diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 0cbe154e517d3987811ff388e4483c578b2c1311..05b41045b8f9d11118a34f445f8263561e3970a2 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -4079,10 +4079,8 @@ i915_drop_caches_set(void *data, u64 val) if (val & DROP_IDLE) drain_delayed_work(&dev_priv->gt.idle_work); - if (val & DROP_FREED) { - synchronize_rcu(); + if (val & DROP_FREED) i915_gem_drain_freed_objects(dev_priv); - } return ret; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3a222f1165af641548a886b599e6849d0c7f32b5..0d8cb74e7d02cef56ebbc6f80669b98b66eec086 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1095,6 +1095,11 @@ struct i915_gem_mm { struct llist_head free_list; struct work_struct free_work; spinlock_t free_lock; + /** + * Count of objects pending destructions. Used to skip needlessly + * waiting on an RCU barrier if no objects are waiting to be freed. + */ + atomic_t free_count; /** * Small stash of WC pages @@ -3134,6 +3139,9 @@ void i915_gem_free_object(struct drm_gem_object *obj); static inline void i915_gem_drain_freed_objects(struct drm_i915_private *i915) { + if (!atomic_read(&i915->mm.free_count)) + return; + /* A single pass should suffice to release all the freed objects (along * most call paths) , but be a little more paranoid in that freeing * the objects does take a little amount of time, during which the rcu diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f530cd2477249f72284b9e924b26e2d07763a2f9..631a2db2bb6e2af1f12b139bf7c1730286dd9311 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4758,6 +4758,9 @@ static void __i915_gem_free_objects(struct drm_i915_private *i915, kfree(obj->bit_17); i915_gem_object_free(obj); + GEM_BUG_ON(!atomic_read(&i915->mm.free_count)); + atomic_dec(&i915->mm.free_count); + if (on) cond_resched(); } @@ -4846,6 +4849,7 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj) * i915_gem_busy_ioctl(). For the corresponding synchronized * lookup see i915_gem_object_lookup_rcu(). */ + atomic_inc(&to_i915(obj->base.dev)->mm.free_count); call_rcu(&obj->rcu, __i915_gem_free_object_rcu); } @@ -5546,7 +5550,8 @@ i915_gem_load_init(struct drm_i915_private *dev_priv) void i915_gem_load_cleanup(struct drm_i915_private *dev_priv) { i915_gem_drain_freed_objects(dev_priv); - WARN_ON(!llist_empty(&dev_priv->mm.free_list)); + GEM_BUG_ON(!llist_empty(&dev_priv->mm.free_list)); + GEM_BUG_ON(atomic_read(&dev_priv->mm.free_count)); WARN_ON(dev_priv->mm.object_count); mutex_lock(&dev_priv->drm.struct_mutex);