}
seq_printf(m, "Inactive Objects:\n");
- msm_gem_describe_objects(&priv->inactive_list, m);
+ msm_gem_describe_objects(&priv->inactive_dontneed, m);
+ msm_gem_describe_objects(&priv->inactive_willneed, m);
mutex_unlock(&priv->mm_lock);
priv->wq = alloc_ordered_workqueue("msm", 0);
- INIT_LIST_HEAD(&priv->inactive_list);
+ INIT_LIST_HEAD(&priv->inactive_willneed);
+ INIT_LIST_HEAD(&priv->inactive_dontneed);
mutex_init(&priv->mm_lock);
/* Teach lockdep about lock ordering wrt. shrinker: */
struct msm_perf_state *perf;
/*
- * List of inactive GEM objects. Every bo is either in the inactive_list
- * or gpu->active_list (for the gpu it is active on[1])
+ * Lists of inactive GEM objects. Every bo is either in one of the
+ * inactive lists (depending on whether or not it is shrinkable) or
+ * gpu->active_list (for the gpu it is active on[1])
*
* These lists are protected by mm_lock. If struct_mutex is involved, it
* should be aquired prior to mm_lock. One should *not* hold mm_lock in
* [1] if someone ever added support for the old 2d cores, there could be
* more than one gpu object
*/
- struct list_head inactive_list;
+ struct list_head inactive_willneed; /* inactive + !shrinkable */
+ struct list_head inactive_dontneed; /* inactive + shrinkable */
struct mutex mm_lock;
struct workqueue_struct *wq;
#include "msm_gpu.h"
#include "msm_mmu.h"
+static void update_inactive(struct msm_gem_object *msm_obj);
static dma_addr_t physaddr(struct drm_gem_object *obj)
{
madv = msm_obj->madv;
+ /* If the obj is inactive, we might need to move it
+ * between inactive lists
+ */
+ if (msm_obj->active_count == 0)
+ update_inactive(msm_obj);
+
msm_gem_unlock(obj);
return (madv != __MSM_MADV_PURGED);
void msm_gem_active_put(struct drm_gem_object *obj)
{
struct msm_gem_object *msm_obj = to_msm_bo(obj);
- struct msm_drm_private *priv = obj->dev->dev_private;
might_sleep();
WARN_ON(!msm_gem_is_locked(obj));
if (--msm_obj->active_count == 0) {
- mutex_lock(&priv->mm_lock);
- list_del_init(&msm_obj->mm_list);
- list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
- mutex_unlock(&priv->mm_lock);
+ update_inactive(msm_obj);
}
}
+static void update_inactive(struct msm_gem_object *msm_obj)
+{
+ struct msm_drm_private *priv = msm_obj->base.dev->dev_private;
+
+ mutex_lock(&priv->mm_lock);
+ WARN_ON(msm_obj->active_count != 0);
+
+ list_del_init(&msm_obj->mm_list);
+ if (msm_obj->madv == MSM_MADV_WILLNEED)
+ list_add_tail(&msm_obj->mm_list, &priv->inactive_willneed);
+ else
+ list_add_tail(&msm_obj->mm_list, &priv->inactive_dontneed);
+
+ mutex_unlock(&priv->mm_lock);
+}
+
int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout)
{
bool write = !!(op & MSM_PREP_WRITE);
}
mutex_lock(&priv->mm_lock);
- list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
+ /* Initially obj is idle, obj->madv == WILLNEED: */
+ list_add_tail(&msm_obj->mm_list, &priv->inactive_willneed);
mutex_unlock(&priv->mm_lock);
return obj;
msm_gem_unlock(obj);
mutex_lock(&priv->mm_lock);
- list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
+ list_add_tail(&msm_obj->mm_list, &priv->inactive_willneed);
mutex_unlock(&priv->mm_lock);
return obj;
mutex_lock(&priv->mm_lock);
- list_for_each_entry(msm_obj, &priv->inactive_list, mm_list) {
+ list_for_each_entry(msm_obj, &priv->inactive_dontneed, mm_list) {
if (!msm_gem_trylock(&msm_obj->base))
continue;
if (is_purgeable(msm_obj))
mutex_lock(&priv->mm_lock);
- list_for_each_entry(msm_obj, &priv->inactive_list, mm_list) {
+ list_for_each_entry(msm_obj, &priv->inactive_dontneed, mm_list) {
if (freed >= sc->nr_to_scan)
break;
if (!msm_gem_trylock(&msm_obj->base))
struct msm_drm_private *priv =
container_of(nb, struct msm_drm_private, vmap_notifier);
struct list_head *mm_lists[] = {
- &priv->inactive_list,
+ &priv->inactive_dontneed,
+ &priv->inactive_willneed,
priv->gpu ? &priv->gpu->active_list : NULL,
NULL,
};