@@ -2185,14 +2185,9 @@ void i915_gem_track_fb(struct drm_i915_gem_object *old,
* initial reference taken using kref_init
*/
struct drm_i915_gem_request {
- /**
- * Underlying object for implementing the signal/wait stuff.
- * NB: Never return this fence object to user land! It is unsafe to
- * let anything outside of the i915 driver get hold of the fence
- * object as the clean up when decrementing the reference count
- * requires holding the driver mutex lock.
- */
+ /** Underlying object for implementing the signal/wait stuff. */
struct fence fence;
+ struct list_head delayed_free_link;
/** On Which ring this request was generated */
struct drm_i915_private *i915;
@@ -2305,21 +2300,10 @@ i915_gem_request_reference(struct drm_i915_gem_request *req)
static inline void
i915_gem_request_unreference(struct drm_i915_gem_request *req)
{
- WARN_ON(!mutex_is_locked(&req->ring->dev->struct_mutex));
- fence_put(&req->fence);
-}
-
-static inline void
-i915_gem_request_unreference__unlocked(struct drm_i915_gem_request *req)
-{
- struct drm_device *dev;
-
if (!req)
return;
- dev = req->ring->dev;
- if (kref_put_mutex(&req->fence.refcount, fence_release, &dev->struct_mutex))
- mutex_unlock(&dev->struct_mutex);
+ fence_put(&req->fence);
}
static inline void i915_gem_request_assign(struct drm_i915_gem_request **pdst,
@@ -2617,10 +2617,26 @@ static void i915_set_reset_status(struct drm_i915_private *dev_priv,
}
}
-static void i915_gem_request_free(struct fence *req_fence)
+static void i915_gem_request_release(struct fence *req_fence)
{
struct drm_i915_gem_request *req = container_of(req_fence,
typeof(*req), fence);
+ struct intel_engine_cs *ring = req->ring;
+ struct drm_i915_private *dev_priv = to_i915(ring->dev);
+
+ /*
+ * Need to add the request to a deferred dereference list to be
+ * processed at a mutex lock safe time.
+ */
+ spin_lock(&ring->delayed_free_lock);
+ list_add_tail(&req->delayed_free_link, &ring->delayed_free_list);
+ spin_unlock(&ring->delayed_free_lock);
+
+ queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0);
+}
+
+static void i915_gem_request_free(struct drm_i915_gem_request *req)
+{
struct intel_context *ctx = req->ctx;
WARN_ON(!mutex_is_locked(&req->ring->dev->struct_mutex));
@@ -2697,7 +2713,7 @@ static const struct fence_ops i915_gem_request_fops = {
.enable_signaling = i915_gem_request_enable_signaling,
.signaled = i915_gem_request_is_completed,
.wait = fence_default_wait,
- .release = i915_gem_request_free,
+ .release = i915_gem_request_release,
.get_driver_name = i915_gem_request_get_driver_name,
.get_timeline_name = i915_gem_request_get_timeline_name,
.fence_value_str = i915_gem_request_fence_value_str,
@@ -2951,6 +2967,9 @@ void i915_gem_reset(struct drm_device *dev)
void
i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
{
+ struct drm_i915_gem_request *req, *req_next;
+ LIST_HEAD(list_head);
+
WARN_ON(i915_verify_lists(ring->dev));
/* Retire requests first as we use it above for the early return.
@@ -2994,6 +3013,15 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
i915_gem_request_assign(&ring->trace_irq_req, NULL);
}
+ /* Really free any requests that were recently unreferenced */
+ spin_lock(&ring->delayed_free_lock);
+ list_splice_init(&ring->delayed_free_list, &list_head);
+ spin_unlock(&ring->delayed_free_lock);
+ list_for_each_entry_safe(req, req_next, &list_head, delayed_free_link) {
+ list_del(&req->delayed_free_link);
+ i915_gem_request_free(req);
+ }
+
WARN_ON(i915_verify_lists(ring->dev));
}
@@ -3184,7 +3212,7 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
ret = __i915_wait_request(req[i], reset_counter, true,
args->timeout_ns > 0 ? &args->timeout_ns : NULL,
file->driver_priv);
- i915_gem_request_unreference__unlocked(req[i]);
+ i915_gem_request_unreference(req[i]);
}
return ret;
@@ -4179,7 +4207,7 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
if (ret == 0)
queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0);
- i915_gem_request_unreference__unlocked(target);
+ i915_gem_request_unreference(target);
return ret;
}
@@ -5036,6 +5064,7 @@ init_ring_lists(struct intel_engine_cs *ring)
{
INIT_LIST_HEAD(&ring->active_list);
INIT_LIST_HEAD(&ring->request_list);
+ INIT_LIST_HEAD(&ring->delayed_free_list);
}
void
@@ -11256,7 +11256,7 @@ static void intel_mmio_flip_work_func(struct work_struct *work)
mmio_flip->crtc->reset_counter,
false, NULL,
&mmio_flip->i915->rps.mmioflips));
- i915_gem_request_unreference__unlocked(mmio_flip->req);
+ i915_gem_request_unreference(mmio_flip->req);
}
intel_do_mmio_flip(mmio_flip);
@@ -1920,7 +1920,9 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin
ring->dev = dev;
INIT_LIST_HEAD(&ring->active_list);
INIT_LIST_HEAD(&ring->request_list);
+ INIT_LIST_HEAD(&ring->delayed_free_list);
spin_lock_init(&ring->fence_lock);
+ spin_lock_init(&ring->delayed_free_lock);
i915_gem_batch_pool_init(dev, &ring->batch_pool);
init_waitqueue_head(&ring->irq_queue);
@@ -7174,7 +7174,7 @@ static void __intel_rps_boost_work(struct work_struct *work)
gen6_rps_boost(to_i915(req->ring->dev), NULL,
req->emitted_jiffies);
- i915_gem_request_unreference__unlocked(req);
+ i915_gem_request_unreference(req);
kfree(boost);
}
@@ -2158,7 +2158,9 @@ static int intel_init_ring_buffer(struct drm_device *dev,
INIT_LIST_HEAD(&ring->request_list);
INIT_LIST_HEAD(&ring->execlist_queue);
INIT_LIST_HEAD(&ring->buffers);
+ INIT_LIST_HEAD(&ring->delayed_free_list);
spin_lock_init(&ring->fence_lock);
+ spin_lock_init(&ring->delayed_free_lock);
i915_gem_batch_pool_init(dev, &ring->batch_pool);
memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno));
@@ -301,6 +301,10 @@ struct intel_engine_cs {
*/
u32 last_submitted_seqno;
+ /* deferred free list to allow unreferencing requests outside the driver */
+ struct list_head delayed_free_list;
+ spinlock_t delayed_free_lock;
+
bool gpu_caches_dirty;
wait_queue_head_t irq_queue;