Commit f2123818 authored by Chris Wilson's avatar Chris Wilson

drm/i915: Move dev_priv->mm.[un]bound_list to its own lock

Remove the struct_mutex requirement around dev_priv->mm.bound_list and
dev_priv->mm.unbound_list by giving it its own spinlock. This reduces
one more requirement for struct_mutex and in the process gives us
slightly more accurate unbound_list tracking, which should improve the
shrinker - but the drawback is that we drop the retirement before
counting so i915_gem_object_is_active() may be stale and lead us to
underestimate the number of objects that may be shrunk (see commit
bed50aea ("drm/i915/shrinker: Flush active on objects before
counting")).

v2: Crosslink the spinlock to the lists it protects, and btw this
changes s/obj->global_link/obj->mm.link/
v3: Fix decoupling of old links in i915_gem_object_attach_phys()
v3.1: Fix the fix, only unlink if it was linked
v3.2: Use a local for to_i915(obj->base.dev)->mm.obj_lock
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: default avatarJoonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20171016114037.5556-1-chris@chris-wilson.co.uk
parent 3d574a6b
...@@ -271,7 +271,9 @@ static int i915_gem_stolen_list_info(struct seq_file *m, void *data) ...@@ -271,7 +271,9 @@ static int i915_gem_stolen_list_info(struct seq_file *m, void *data)
goto out; goto out;
total_obj_size = total_gtt_size = count = 0; total_obj_size = total_gtt_size = count = 0;
list_for_each_entry(obj, &dev_priv->mm.bound_list, global_link) {
spin_lock(&dev_priv->mm.obj_lock);
list_for_each_entry(obj, &dev_priv->mm.bound_list, mm.link) {
if (count == total) if (count == total)
break; break;
...@@ -283,7 +285,7 @@ static int i915_gem_stolen_list_info(struct seq_file *m, void *data) ...@@ -283,7 +285,7 @@ static int i915_gem_stolen_list_info(struct seq_file *m, void *data)
total_gtt_size += i915_gem_obj_total_ggtt_size(obj); total_gtt_size += i915_gem_obj_total_ggtt_size(obj);
} }
list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_link) { list_for_each_entry(obj, &dev_priv->mm.unbound_list, mm.link) {
if (count == total) if (count == total)
break; break;
...@@ -293,6 +295,7 @@ static int i915_gem_stolen_list_info(struct seq_file *m, void *data) ...@@ -293,6 +295,7 @@ static int i915_gem_stolen_list_info(struct seq_file *m, void *data)
objects[count++] = obj; objects[count++] = obj;
total_obj_size += obj->base.size; total_obj_size += obj->base.size;
} }
spin_unlock(&dev_priv->mm.obj_lock);
sort(objects, count, sizeof(*objects), obj_rank_by_stolen, NULL); sort(objects, count, sizeof(*objects), obj_rank_by_stolen, NULL);
...@@ -454,7 +457,9 @@ static int i915_gem_object_info(struct seq_file *m, void *data) ...@@ -454,7 +457,9 @@ static int i915_gem_object_info(struct seq_file *m, void *data)
mapped_size = mapped_count = 0; mapped_size = mapped_count = 0;
purgeable_size = purgeable_count = 0; purgeable_size = purgeable_count = 0;
huge_size = huge_count = 0; huge_size = huge_count = 0;
list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_link) {
spin_lock(&dev_priv->mm.obj_lock);
list_for_each_entry(obj, &dev_priv->mm.unbound_list, mm.link) {
size += obj->base.size; size += obj->base.size;
++count; ++count;
...@@ -477,7 +482,7 @@ static int i915_gem_object_info(struct seq_file *m, void *data) ...@@ -477,7 +482,7 @@ static int i915_gem_object_info(struct seq_file *m, void *data)
seq_printf(m, "%u unbound objects, %llu bytes\n", count, size); seq_printf(m, "%u unbound objects, %llu bytes\n", count, size);
size = count = dpy_size = dpy_count = 0; size = count = dpy_size = dpy_count = 0;
list_for_each_entry(obj, &dev_priv->mm.bound_list, global_link) { list_for_each_entry(obj, &dev_priv->mm.bound_list, mm.link) {
size += obj->base.size; size += obj->base.size;
++count; ++count;
...@@ -502,6 +507,8 @@ static int i915_gem_object_info(struct seq_file *m, void *data) ...@@ -502,6 +507,8 @@ static int i915_gem_object_info(struct seq_file *m, void *data)
page_sizes |= obj->mm.page_sizes.sg; page_sizes |= obj->mm.page_sizes.sg;
} }
} }
spin_unlock(&dev_priv->mm.obj_lock);
seq_printf(m, "%u bound objects, %llu bytes\n", seq_printf(m, "%u bound objects, %llu bytes\n",
count, size); count, size);
seq_printf(m, "%u purgeable objects, %llu bytes\n", seq_printf(m, "%u purgeable objects, %llu bytes\n",
...@@ -568,28 +575,46 @@ static int i915_gem_gtt_info(struct seq_file *m, void *data) ...@@ -568,28 +575,46 @@ static int i915_gem_gtt_info(struct seq_file *m, void *data)
struct drm_info_node *node = m->private; struct drm_info_node *node = m->private;
struct drm_i915_private *dev_priv = node_to_i915(node); struct drm_i915_private *dev_priv = node_to_i915(node);
struct drm_device *dev = &dev_priv->drm; struct drm_device *dev = &dev_priv->drm;
struct drm_i915_gem_object **objects;
struct drm_i915_gem_object *obj; struct drm_i915_gem_object *obj;
u64 total_obj_size, total_gtt_size; u64 total_obj_size, total_gtt_size;
unsigned long nobject, n;
int count, ret; int count, ret;
nobject = READ_ONCE(dev_priv->mm.object_count);
objects = kvmalloc_array(nobject, sizeof(*objects), GFP_KERNEL);
if (!objects)
return -ENOMEM;
ret = mutex_lock_interruptible(&dev->struct_mutex); ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret) if (ret)
return ret; return ret;
total_obj_size = total_gtt_size = count = 0; count = 0;
list_for_each_entry(obj, &dev_priv->mm.bound_list, global_link) { spin_lock(&dev_priv->mm.obj_lock);
list_for_each_entry(obj, &dev_priv->mm.bound_list, mm.link) {
objects[count++] = obj;
if (count == nobject)
break;
}
spin_unlock(&dev_priv->mm.obj_lock);
total_obj_size = total_gtt_size = 0;
for (n = 0; n < count; n++) {
obj = objects[n];
seq_puts(m, " "); seq_puts(m, " ");
describe_obj(m, obj); describe_obj(m, obj);
seq_putc(m, '\n'); seq_putc(m, '\n');
total_obj_size += obj->base.size; total_obj_size += obj->base.size;
total_gtt_size += i915_gem_obj_total_ggtt_size(obj); total_gtt_size += i915_gem_obj_total_ggtt_size(obj);
count++;
} }
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
seq_printf(m, "Total %d objects, %llu bytes, %llu GTT size\n", seq_printf(m, "Total %d objects, %llu bytes, %llu GTT size\n",
count, total_obj_size, total_gtt_size); count, total_obj_size, total_gtt_size);
kvfree(objects);
return 0; return 0;
} }
......
...@@ -1490,6 +1490,9 @@ struct i915_gem_mm { ...@@ -1490,6 +1490,9 @@ struct i915_gem_mm {
* always the inner lock when overlapping with struct_mutex. */ * always the inner lock when overlapping with struct_mutex. */
struct mutex stolen_lock; struct mutex stolen_lock;
/* Protects bound_list/unbound_list and #drm_i915_gem_object.mm.link */
spinlock_t obj_lock;
/** List of all objects in gtt_space. Used to restore gtt /** List of all objects in gtt_space. Used to restore gtt
* mappings on resume */ * mappings on resume */
struct list_head bound_list; struct list_head bound_list;
......
...@@ -1537,6 +1537,8 @@ static void i915_gem_object_bump_inactive_ggtt(struct drm_i915_gem_object *obj) ...@@ -1537,6 +1537,8 @@ static void i915_gem_object_bump_inactive_ggtt(struct drm_i915_gem_object *obj)
struct list_head *list; struct list_head *list;
struct i915_vma *vma; struct i915_vma *vma;
GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
list_for_each_entry(vma, &obj->vma_list, obj_link) { list_for_each_entry(vma, &obj->vma_list, obj_link) {
if (!i915_vma_is_ggtt(vma)) if (!i915_vma_is_ggtt(vma))
break; break;
...@@ -1551,8 +1553,10 @@ static void i915_gem_object_bump_inactive_ggtt(struct drm_i915_gem_object *obj) ...@@ -1551,8 +1553,10 @@ static void i915_gem_object_bump_inactive_ggtt(struct drm_i915_gem_object *obj)
} }
i915 = to_i915(obj->base.dev); i915 = to_i915(obj->base.dev);
spin_lock(&i915->mm.obj_lock);
list = obj->bind_count ? &i915->mm.bound_list : &i915->mm.unbound_list; list = obj->bind_count ? &i915->mm.bound_list : &i915->mm.unbound_list;
list_move_tail(&obj->global_link, list); list_move_tail(&obj->mm.link, list);
spin_unlock(&i915->mm.obj_lock);
} }
/** /**
...@@ -2253,6 +2257,7 @@ static void __i915_gem_object_reset_page_iter(struct drm_i915_gem_object *obj) ...@@ -2253,6 +2257,7 @@ static void __i915_gem_object_reset_page_iter(struct drm_i915_gem_object *obj)
void __i915_gem_object_put_pages(struct drm_i915_gem_object *obj, void __i915_gem_object_put_pages(struct drm_i915_gem_object *obj,
enum i915_mm_subclass subclass) enum i915_mm_subclass subclass)
{ {
struct drm_i915_private *i915 = to_i915(obj->base.dev);
struct sg_table *pages; struct sg_table *pages;
if (i915_gem_object_has_pinned_pages(obj)) if (i915_gem_object_has_pinned_pages(obj))
...@@ -2273,6 +2278,10 @@ void __i915_gem_object_put_pages(struct drm_i915_gem_object *obj, ...@@ -2273,6 +2278,10 @@ void __i915_gem_object_put_pages(struct drm_i915_gem_object *obj,
pages = fetch_and_zero(&obj->mm.pages); pages = fetch_and_zero(&obj->mm.pages);
GEM_BUG_ON(!pages); GEM_BUG_ON(!pages);
spin_lock(&i915->mm.obj_lock);
list_del(&obj->mm.link);
spin_unlock(&i915->mm.obj_lock);
if (obj->mm.mapping) { if (obj->mm.mapping) {
void *ptr; void *ptr;
...@@ -2507,7 +2516,7 @@ void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj, ...@@ -2507,7 +2516,7 @@ void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj,
obj->mm.pages = pages; obj->mm.pages = pages;
if (i915_gem_object_is_tiled(obj) && if (i915_gem_object_is_tiled(obj) &&
to_i915(obj->base.dev)->quirks & QUIRK_PIN_SWIZZLED_PAGES) { i915->quirks & QUIRK_PIN_SWIZZLED_PAGES) {
GEM_BUG_ON(obj->mm.quirked); GEM_BUG_ON(obj->mm.quirked);
__i915_gem_object_pin_pages(obj); __i915_gem_object_pin_pages(obj);
obj->mm.quirked = true; obj->mm.quirked = true;
...@@ -2529,8 +2538,11 @@ void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj, ...@@ -2529,8 +2538,11 @@ void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj,
if (obj->mm.page_sizes.phys & ~0u << i) if (obj->mm.page_sizes.phys & ~0u << i)
obj->mm.page_sizes.sg |= BIT(i); obj->mm.page_sizes.sg |= BIT(i);
} }
GEM_BUG_ON(!HAS_PAGE_SIZES(i915, obj->mm.page_sizes.sg)); GEM_BUG_ON(!HAS_PAGE_SIZES(i915, obj->mm.page_sizes.sg));
spin_lock(&i915->mm.obj_lock);
list_add(&obj->mm.link, &i915->mm.unbound_list);
spin_unlock(&i915->mm.obj_lock);
} }
static int ____i915_gem_object_get_pages(struct drm_i915_gem_object *obj) static int ____i915_gem_object_get_pages(struct drm_i915_gem_object *obj)
...@@ -4324,7 +4336,6 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj, ...@@ -4324,7 +4336,6 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
{ {
mutex_init(&obj->mm.lock); mutex_init(&obj->mm.lock);
INIT_LIST_HEAD(&obj->global_link);
INIT_LIST_HEAD(&obj->vma_list); INIT_LIST_HEAD(&obj->vma_list);
INIT_LIST_HEAD(&obj->lut_list); INIT_LIST_HEAD(&obj->lut_list);
INIT_LIST_HEAD(&obj->batch_pool_link); INIT_LIST_HEAD(&obj->batch_pool_link);
...@@ -4496,7 +4507,18 @@ static void __i915_gem_free_objects(struct drm_i915_private *i915, ...@@ -4496,7 +4507,18 @@ static void __i915_gem_free_objects(struct drm_i915_private *i915,
GEM_BUG_ON(!list_empty(&obj->vma_list)); GEM_BUG_ON(!list_empty(&obj->vma_list));
GEM_BUG_ON(!RB_EMPTY_ROOT(&obj->vma_tree)); GEM_BUG_ON(!RB_EMPTY_ROOT(&obj->vma_tree));
list_del(&obj->global_link); /* This serializes freeing with the shrinker. Since the free
* is delayed, first by RCU then by the workqueue, we want the
* shrinker to be able to free pages of unreferenced objects,
* or else we may oom whilst there are plenty of deferred
* freed objects.
*/
if (i915_gem_object_has_pages(obj)) {
spin_lock(&i915->mm.obj_lock);
list_del_init(&obj->mm.link);
spin_unlock(&i915->mm.obj_lock);
}
} }
intel_runtime_pm_put(i915); intel_runtime_pm_put(i915);
mutex_unlock(&i915->drm.struct_mutex); mutex_unlock(&i915->drm.struct_mutex);
...@@ -5035,11 +5057,14 @@ i915_gem_load_init(struct drm_i915_private *dev_priv) ...@@ -5035,11 +5057,14 @@ i915_gem_load_init(struct drm_i915_private *dev_priv)
goto err_priorities; goto err_priorities;
INIT_WORK(&dev_priv->mm.free_work, __i915_gem_free_work); INIT_WORK(&dev_priv->mm.free_work, __i915_gem_free_work);
spin_lock_init(&dev_priv->mm.obj_lock);
init_llist_head(&dev_priv->mm.free_list); init_llist_head(&dev_priv->mm.free_list);
INIT_LIST_HEAD(&dev_priv->mm.unbound_list); INIT_LIST_HEAD(&dev_priv->mm.unbound_list);
INIT_LIST_HEAD(&dev_priv->mm.bound_list); INIT_LIST_HEAD(&dev_priv->mm.bound_list);
INIT_LIST_HEAD(&dev_priv->mm.fence_list); INIT_LIST_HEAD(&dev_priv->mm.fence_list);
INIT_LIST_HEAD(&dev_priv->mm.userfault_list); INIT_LIST_HEAD(&dev_priv->mm.userfault_list);
INIT_DELAYED_WORK(&dev_priv->gt.retire_work, INIT_DELAYED_WORK(&dev_priv->gt.retire_work,
i915_gem_retire_work_handler); i915_gem_retire_work_handler);
INIT_DELAYED_WORK(&dev_priv->gt.idle_work, INIT_DELAYED_WORK(&dev_priv->gt.idle_work,
...@@ -5133,12 +5158,12 @@ int i915_gem_freeze_late(struct drm_i915_private *dev_priv) ...@@ -5133,12 +5158,12 @@ int i915_gem_freeze_late(struct drm_i915_private *dev_priv)
i915_gem_shrink(dev_priv, -1UL, NULL, I915_SHRINK_UNBOUND); i915_gem_shrink(dev_priv, -1UL, NULL, I915_SHRINK_UNBOUND);
i915_gem_drain_freed_objects(dev_priv); i915_gem_drain_freed_objects(dev_priv);
mutex_lock(&dev_priv->drm.struct_mutex); spin_lock(&dev_priv->mm.obj_lock);
for (p = phases; *p; p++) { for (p = phases; *p; p++) {
list_for_each_entry(obj, *p, global_link) list_for_each_entry(obj, *p, mm.link)
__start_cpu_write(obj); __start_cpu_write(obj);
} }
mutex_unlock(&dev_priv->drm.struct_mutex); spin_unlock(&dev_priv->mm.obj_lock);
return 0; return 0;
} }
...@@ -5457,7 +5482,17 @@ int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj, int align) ...@@ -5457,7 +5482,17 @@ int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj, int align)
goto err_unlock; goto err_unlock;
} }
pages = obj->mm.pages; pages = fetch_and_zero(&obj->mm.pages);
if (pages) {
struct drm_i915_private *i915 = to_i915(obj->base.dev);
__i915_gem_object_reset_page_iter(obj);
spin_lock(&i915->mm.obj_lock);
list_del(&obj->mm.link);
spin_unlock(&i915->mm.obj_lock);
}
obj->ops = &i915_gem_phys_ops; obj->ops = &i915_gem_phys_ops;
err = ____i915_gem_object_get_pages(obj); err = ____i915_gem_object_get_pages(obj);
......
...@@ -3594,8 +3594,7 @@ void i915_gem_restore_gtt_mappings(struct drm_i915_private *dev_priv) ...@@ -3594,8 +3594,7 @@ void i915_gem_restore_gtt_mappings(struct drm_i915_private *dev_priv)
ggtt->base.closed = true; /* skip rewriting PTE on VMA unbind */ ggtt->base.closed = true; /* skip rewriting PTE on VMA unbind */
/* clflush objects bound into the GGTT and rebind them. */ /* clflush objects bound into the GGTT and rebind them. */
list_for_each_entry_safe(obj, on, list_for_each_entry_safe(obj, on, &dev_priv->mm.bound_list, mm.link) {
&dev_priv->mm.bound_list, global_link) {
bool ggtt_bound = false; bool ggtt_bound = false;
struct i915_vma *vma; struct i915_vma *vma;
......
...@@ -114,7 +114,6 @@ struct drm_i915_gem_object { ...@@ -114,7 +114,6 @@ struct drm_i915_gem_object {
/** Stolen memory for this object, instead of being backed by shmem. */ /** Stolen memory for this object, instead of being backed by shmem. */
struct drm_mm_node *stolen; struct drm_mm_node *stolen;
struct list_head global_link;
union { union {
struct rcu_head rcu; struct rcu_head rcu;
struct llist_node freed; struct llist_node freed;
...@@ -208,6 +207,12 @@ struct drm_i915_gem_object { ...@@ -208,6 +207,12 @@ struct drm_i915_gem_object {
struct mutex lock; /* protects this cache */ struct mutex lock; /* protects this cache */
} get_page; } get_page;
/**
* Element within i915->mm.unbound_list or i915->mm.bound_list,
* locked by i915->mm.obj_lock.
*/
struct list_head link;
/** /**
* Advice: are the backing pages purgeable? * Advice: are the backing pages purgeable?
*/ */
......
...@@ -78,9 +78,6 @@ static bool swap_available(void) ...@@ -78,9 +78,6 @@ static bool swap_available(void)
static bool can_release_pages(struct drm_i915_gem_object *obj) static bool can_release_pages(struct drm_i915_gem_object *obj)
{ {
if (!i915_gem_object_has_pages(obj))
return false;
/* Consider only shrinkable ojects. */ /* Consider only shrinkable ojects. */
if (!i915_gem_object_is_shrinkable(obj)) if (!i915_gem_object_is_shrinkable(obj))
return false; return false;
...@@ -102,7 +99,7 @@ static bool can_release_pages(struct drm_i915_gem_object *obj) ...@@ -102,7 +99,7 @@ static bool can_release_pages(struct drm_i915_gem_object *obj)
* To simplify the scan, and to avoid walking the list of vma under the * To simplify the scan, and to avoid walking the list of vma under the
* object, we just check the count of its permanently pinned. * object, we just check the count of its permanently pinned.
*/ */
if (obj->pin_global) if (READ_ONCE(obj->pin_global))
return false; return false;
/* We can only return physical pages to the system if we can either /* We can only return physical pages to the system if we can either
...@@ -204,15 +201,20 @@ i915_gem_shrink(struct drm_i915_private *dev_priv, ...@@ -204,15 +201,20 @@ i915_gem_shrink(struct drm_i915_private *dev_priv,
continue; continue;
INIT_LIST_HEAD(&still_in_list); INIT_LIST_HEAD(&still_in_list);
/*
* We serialize our access to unreferenced objects through
* the use of the struct_mutex. While the objects are not
* yet freed (due to RCU then a workqueue) we still want
* to be able to shrink their pages, so they remain on
* the unbound/bound list until actually freed.
*/
spin_lock(&dev_priv->mm.obj_lock);
while (count < target && while (count < target &&
(obj = list_first_entry_or_null(phase->list, (obj = list_first_entry_or_null(phase->list,
typeof(*obj), typeof(*obj),
global_link))) { mm.link))) {
list_move_tail(&obj->global_link, &still_in_list); list_move_tail(&obj->mm.link, &still_in_list);
if (!obj->mm.pages) {
list_del_init(&obj->global_link);
continue;
}
if (flags & I915_SHRINK_PURGEABLE && if (flags & I915_SHRINK_PURGEABLE &&
obj->mm.madv != I915_MADV_DONTNEED) obj->mm.madv != I915_MADV_DONTNEED)
...@@ -230,20 +232,24 @@ i915_gem_shrink(struct drm_i915_private *dev_priv, ...@@ -230,20 +232,24 @@ i915_gem_shrink(struct drm_i915_private *dev_priv,
if (!can_release_pages(obj)) if (!can_release_pages(obj))
continue; continue;
spin_unlock(&dev_priv->mm.obj_lock);
if (unsafe_drop_pages(obj)) { if (unsafe_drop_pages(obj)) {
/* May arrive from get_pages on another bo */ /* May arrive from get_pages on another bo */
mutex_lock_nested(&obj->mm.lock, mutex_lock_nested(&obj->mm.lock,
I915_MM_SHRINKER); I915_MM_SHRINKER);
if (!i915_gem_object_has_pages(obj)) { if (!i915_gem_object_has_pages(obj)) {
__i915_gem_object_invalidate(obj); __i915_gem_object_invalidate(obj);
list_del_init(&obj->global_link);
count += obj->base.size >> PAGE_SHIFT; count += obj->base.size >> PAGE_SHIFT;
} }
mutex_unlock(&obj->mm.lock); mutex_unlock(&obj->mm.lock);
scanned += obj->base.size >> PAGE_SHIFT; scanned += obj->base.size >> PAGE_SHIFT;
} }
spin_lock(&dev_priv->mm.obj_lock);
} }
list_splice_tail(&still_in_list, phase->list); list_splice_tail(&still_in_list, phase->list);
spin_unlock(&dev_priv->mm.obj_lock);
} }
if (flags & I915_SHRINK_BOUND) if (flags & I915_SHRINK_BOUND)
...@@ -292,25 +298,17 @@ i915_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc) ...@@ -292,25 +298,17 @@ i915_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc)
struct drm_i915_private *dev_priv = struct drm_i915_private *dev_priv =
container_of(shrinker, struct drm_i915_private, mm.shrinker); container_of(shrinker, struct drm_i915_private, mm.shrinker);
struct drm_i915_gem_object *obj; struct drm_i915_gem_object *obj;
unsigned long count; unsigned long count = 0;
bool unlock;
if (!shrinker_lock(dev_priv, &unlock))
return 0;
i915_gem_retire_requests(dev_priv);
count = 0; spin_lock(&dev_priv->mm.obj_lock);
list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_link) list_for_each_entry(obj, &dev_priv->mm.unbound_list, mm.link)
if (can_release_pages(obj)) if (can_release_pages(obj))
count += obj->base.size >> PAGE_SHIFT; count += obj->base.size >> PAGE_SHIFT;
list_for_each_entry(obj, &dev_priv->mm.bound_list, global_link) { list_for_each_entry(obj, &dev_priv->mm.bound_list, mm.link)
if (!i915_gem_object_is_active(obj) && can_release_pages(obj)) if (!i915_gem_object_is_active(obj) && can_release_pages(obj))
count += obj->base.size >> PAGE_SHIFT; count += obj->base.size >> PAGE_SHIFT;
} spin_unlock(&dev_priv->mm.obj_lock);
shrinker_unlock(dev_priv, unlock);
return count; return count;
} }
...@@ -387,10 +385,6 @@ i915_gem_shrinker_oom(struct notifier_block *nb, unsigned long event, void *ptr) ...@@ -387,10 +385,6 @@ i915_gem_shrinker_oom(struct notifier_block *nb, unsigned long event, void *ptr)
container_of(nb, struct drm_i915_private, mm.oom_notifier); container_of(nb, struct drm_i915_private, mm.oom_notifier);
struct drm_i915_gem_object *obj; struct drm_i915_gem_object *obj;
unsigned long unevictable, bound, unbound, freed_pages; unsigned long unevictable, bound, unbound, freed_pages;
bool unlock;
if (!shrinker_lock_uninterruptible(dev_priv, &unlock, 5000))
return NOTIFY_DONE;
freed_pages = i915_gem_shrink_all(dev_priv); freed_pages = i915_gem_shrink_all(dev_priv);
...@@ -399,26 +393,20 @@ i915_gem_shrinker_oom(struct notifier_block *nb, unsigned long event, void *ptr) ...@@ -399,26 +393,20 @@ i915_gem_shrinker_oom(struct notifier_block *nb, unsigned long event, void *ptr)
* being pointed to by hardware. * being pointed to by hardware.
*/ */
unbound = bound = unevictable = 0; unbound = bound = unevictable = 0;
list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_link) { spin_lock(&dev_priv->mm.obj_lock);
if (!i915_gem_object_has_pages(obj)) list_for_each_entry(obj, &dev_priv->mm.unbound_list, mm.link) {
continue;
if (!can_release_pages(obj)) if (!can_release_pages(obj))
unevictable += obj->base.size >> PAGE_SHIFT; unevictable += obj->base.size >> PAGE_SHIFT;
else else
unbound += obj->base.size >> PAGE_SHIFT; unbound += obj->base.size >> PAGE_SHIFT;
} }
list_for_each_entry(obj, &dev_priv->mm.bound_list, global_link) { list_for_each_entry(obj, &dev_priv->mm.bound_list, mm.link) {
if (!i915_gem_object_has_pages(obj))
continue;
if (!can_release_pages(obj)) if (!can_release_pages(obj))
unevictable += obj->base.size >> PAGE_SHIFT; unevictable += obj->base.size >> PAGE_SHIFT;
else else
bound += obj->base.size >> PAGE_SHIFT; bound += obj->base.size >> PAGE_SHIFT;
} }
spin_unlock(&dev_priv->mm.obj_lock);
shrinker_unlock(dev_priv, unlock);
if (freed_pages || unbound || bound) if (freed_pages || unbound || bound)
pr_info("Purging GPU memory, %lu pages freed, " pr_info("Purging GPU memory, %lu pages freed, "
......
...@@ -724,8 +724,11 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_i915_private *dev_priv ...@@ -724,8 +724,11 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_i915_private *dev_priv
vma->flags |= I915_VMA_GLOBAL_BIND; vma->flags |= I915_VMA_GLOBAL_BIND;
__i915_vma_set_map_and_fenceable(vma); __i915_vma_set_map_and_fenceable(vma);
list_move_tail(&vma->vm_link, &ggtt->base.inactive_list); list_move_tail(&vma->vm_link, &ggtt->base.inactive_list);
list_move_tail(&obj->global_link, &dev_priv->mm.bound_list);
spin_lock(&dev_priv->mm.obj_lock);
list_move_tail(&obj->mm.link, &dev_priv->mm.bound_list);
obj->bind_count++; obj->bind_count++;
spin_unlock(&dev_priv->mm.obj_lock);
return obj; return obj;
......
...@@ -58,8 +58,10 @@ i915_vma_retire(struct i915_gem_active *active, ...@@ -58,8 +58,10 @@ i915_vma_retire(struct i915_gem_active *active,
* so that we don't steal from recently used but inactive objects * so that we don't steal from recently used but inactive objects
* (unless we are forced to ofc!) * (unless we are forced to ofc!)
*/ */
spin_lock(&rq->i915->mm.obj_lock);
if (obj->bind_count) if (obj->bind_count)
list_move_tail(&obj->global_link, &rq->i915->mm.bound_list); list_move_tail(&obj->mm.link, &rq->i915->mm.bound_list);
spin_unlock(&rq->i915->mm.obj_lock);
obj->mm.dirty = true; /* be paranoid */ obj->mm.dirty = true; /* be paranoid */
...@@ -563,9 +565,13 @@ i915_vma_insert(struct i915_vma *vma, u64 size, u64 alignment, u64 flags) ...@@ -563,9 +565,13 @@ i915_vma_insert(struct i915_vma *vma, u64 size, u64 alignment, u64 flags)
GEM_BUG_ON(!drm_mm_node_allocated(&vma->node)); GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
GEM_BUG_ON(!i915_gem_valid_gtt_space(vma, obj->cache_level)); GEM_BUG_ON(!i915_gem_valid_gtt_space(vma, obj->cache_level));
list_move_tail(&obj->global_link, &dev_priv->mm.bound_list);
list_move_tail(&vma->vm_link, &vma->vm->inactive_list); list_move_tail(&vma->vm_link, &vma->vm->inactive_list);
spin_lock(&dev_priv->mm.obj_lock);
list_move_tail(&obj->mm.link, &dev_priv->mm.bound_list);
obj->bind_count++; obj->bind_count++;
spin_unlock(&dev_priv->mm.obj_lock);
GEM_BUG_ON(atomic_read(&obj->mm.pages_pin_count) < obj->bind_count); GEM_BUG_ON(atomic_read(&obj->mm.pages_pin_count) < obj->bind_count);
return 0; return 0;
...@@ -580,6 +586,7 @@ i915_vma_insert(struct i915_vma *vma, u64 size, u64 alignment, u64 flags) ...@@ -580,6 +586,7 @@ i915_vma_insert(struct i915_vma *vma, u64 size, u64 alignment, u64 flags)
static void static void
i915_vma_remove(struct i915_vma *vma) i915_vma_remove(struct i915_vma *vma)
{ {
struct drm_i915_private *i915 = vma->vm->i915;
struct drm_i915_gem_object *obj = vma->obj; struct drm_i915_gem_object *obj = vma->obj;
GEM_BUG_ON(!drm_mm_node_allocated(&vma->node)); GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
...@@ -593,9 +600,10 @@ i915_vma_remove(struct i915_vma *vma) ...@@ -593,9 +600,10 @@ i915_vma_remove(struct i915_vma *vma)
/* Since the unbound list is global, only move to that list if /* Since the unbound list is global, only move to that list if
* no more VMAs exist. * no more VMAs exist.
*/ */
spin_lock(&i915->mm.obj_lock);
if (--obj->bind_count == 0) if (--obj->bind_count == 0)
list_move_tail(&obj->global_link, list_move_tail(&obj->mm.link, &i915->mm.unbound_list);
&to_i915(obj->base.dev)->mm.unbound_list); spin_unlock(&i915->mm.obj_lock);
/* And finally now the object is completely decoupled from this vma, /* And finally now the object is completely decoupled from this vma,
* we can drop its hold on the backing storage and allow it to be * we can drop its hold on the backing storage and allow it to be
......
...@@ -417,7 +417,7 @@ static int fake_aliasing_ppgtt_enable(struct drm_i915_private *i915) ...@@ -417,7 +417,7 @@ static int fake_aliasing_ppgtt_enable(struct drm_i915_private *i915)
if (err) if (err)
return err; return err;
list_for_each_entry(obj, &i915->mm.bound_list, global_link) { list_for_each_entry(obj, &i915->mm.bound_list, mm.link) {
struct i915_vma *vma; struct i915_vma *vma;
vma = i915_vma_instance(obj, &i915->ggtt.base, NULL); vma = i915_vma_instance(obj, &i915->ggtt.base, NULL);
......
...@@ -50,7 +50,7 @@ static int populate_ggtt(struct drm_i915_private *i915) ...@@ -50,7 +50,7 @@ static int populate_ggtt(struct drm_i915_private *i915)
if (!list_empty(&i915->mm.unbound_list)) { if (!list_empty(&i915->mm.unbound_list)) {
size = 0; size = 0;
list_for_each_entry(obj, &i915->mm.unbound_list, global_link) list_for_each_entry(obj, &i915->mm.unbound_list, mm.link)
size++; size++;
pr_err("Found %lld objects unbound!\n", size); pr_err("Found %lld objects unbound!\n", size);
...@@ -77,10 +77,10 @@ static void cleanup_objects(struct drm_i915_private *i915) ...@@ -77,10 +77,10 @@ static void cleanup_objects(struct drm_i915_private *i915)
{ {
struct drm_i915_gem_object *obj, *on; struct drm_i915_gem_object *obj, *on;
list_for_each_entry_safe(obj, on, &i915->mm.unbound_list, global_link) list_for_each_entry_safe(obj, on, &i915->mm.unbound_list, mm.link)
i915_gem_object_put(obj); i915_gem_object_put(obj);
list_for_each_entry_safe(obj, on, &i915->mm.bound_list, global_link) list_for_each_entry_safe(obj, on, &i915->mm.bound_list, mm.link)
i915_gem_object_put(obj); i915_gem_object_put(obj);
mutex_unlock(&i915->drm.struct_mutex); mutex_unlock(&i915->drm.struct_mutex);
...@@ -152,8 +152,6 @@ static int igt_overcommit(void *arg) ...@@ -152,8 +152,6 @@ static int igt_overcommit(void *arg)
goto cleanup; goto cleanup;
} }
list_move(&obj->global_link, &i915->mm.unbound_list);
vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0); vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0);
if (!IS_ERR(vma) || PTR_ERR(vma) != -ENOSPC) { if (!IS_ERR(vma) || PTR_ERR(vma) != -ENOSPC) {
pr_err("Failed to evict+insert, i915_gem_object_ggtt_pin returned err=%d\n", (int)PTR_ERR(vma)); pr_err("Failed to evict+insert, i915_gem_object_ggtt_pin returned err=%d\n", (int)PTR_ERR(vma));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment