summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h22
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c39
-rw-r--r--drivers/gpu/drm/i915/intel_display.c2
-rw-r--r--drivers/gpu/drm/i915/intel_lrc.c2
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c2
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c2
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.h7
7 files changed, 51 insertions, 25 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 707bf0f742f7..81324ba2ebf7 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2253,14 +2253,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;
@@ -2383,21 +2378,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->engine->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->engine->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,
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 26891a8d237b..67eeefbefa7d 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2726,10 +2726,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 *engine = req->engine;
+ struct drm_i915_private *dev_priv = to_i915(engine->dev);
+
+ /*
+ * Need to add the request to a deferred dereference list to be
+ * processed at a mutex lock safe time.
+ */
+ spin_lock(&engine->delayed_free_lock);
+ list_add_tail(&req->delayed_free_link, &engine->delayed_free_list);
+ spin_unlock(&engine->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->engine->dev->struct_mutex));
@@ -2810,7 +2826,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,
@@ -3087,6 +3103,9 @@ void i915_gem_reset(struct drm_device *dev)
void
i915_gem_retire_requests_ring(struct intel_engine_cs *engine)
{
+ struct drm_i915_gem_request *req, *req_next;
+ LIST_HEAD(list_head);
+
WARN_ON(i915_verify_lists(engine->dev));
/* Retire requests first as we use it above for the early return.
@@ -3130,6 +3149,17 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *engine)
i915_gem_request_assign(&engine->trace_irq_req, NULL);
}
+ /* Really free any requests that were recently unreferenced */
+ if (!list_empty(&engine->delayed_free_list)) {
+ spin_lock(&engine->delayed_free_lock);
+ list_splice_init(&engine->delayed_free_list, &list_head);
+ spin_unlock(&engine->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(engine->dev));
}
@@ -3317,7 +3347,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,
to_rps_client(file));
- i915_gem_request_unreference__unlocked(req[i]);
+ i915_gem_request_unreference(req[i]);
}
return ret;
@@ -4339,7 +4369,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;
}
@@ -5201,6 +5231,7 @@ init_engine_lists(struct intel_engine_cs *engine)
{
INIT_LIST_HEAD(&engine->active_list);
INIT_LIST_HEAD(&engine->request_list);
+ INIT_LIST_HEAD(&engine->delayed_free_list);
}
void
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 90a45fe35b6e..276bbd34fcd0 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -11367,7 +11367,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);
}
/* For framebuffer backed by dmabuf, wait for fence */
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index db74cc142f44..8eb0c5ed5f12 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -2133,7 +2133,9 @@ logical_ring_init(struct drm_device *dev, struct intel_engine_cs *engine)
engine->dev = dev;
INIT_LIST_HEAD(&engine->active_list);
INIT_LIST_HEAD(&engine->request_list);
+ INIT_LIST_HEAD(&engine->delayed_free_list);
spin_lock_init(&engine->fence_lock);
+ spin_lock_init(&engine->delayed_free_lock);
i915_gem_batch_pool_init(dev, &engine->batch_pool);
init_waitqueue_head(&engine->irq_queue);
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 781d601dbdca..568c2fa0899e 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -7363,7 +7363,7 @@ static void __intel_rps_boost_work(struct work_struct *work)
gen6_rps_boost(to_i915(req->engine->dev), NULL,
req->emitted_jiffies);
- i915_gem_request_unreference__unlocked(req);
+ i915_gem_request_unreference(req);
kfree(boost);
}
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index a52b81c4d66f..ac922a53e6b7 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -2229,7 +2229,9 @@ static int intel_init_ring_buffer(struct drm_device *dev,
INIT_LIST_HEAD(&engine->request_list);
INIT_LIST_HEAD(&engine->execlist_queue);
INIT_LIST_HEAD(&engine->buffers);
+ INIT_LIST_HEAD(&engine->delayed_free_list);
spin_lock_init(&engine->fence_lock);
+ spin_lock_init(&engine->delayed_free_lock);
i915_gem_batch_pool_init(dev, &engine->batch_pool);
memset(engine->semaphore.sync_seqno, 0,
sizeof(engine->semaphore.sync_seqno));
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 23e1d94d2b38..fa07ea9afe6c 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -309,6 +309,13 @@ struct intel_engine_cs {
u32 last_submitted_seqno;
unsigned user_interrupts;
+ /*
+ * Deferred free list to allow unreferencing requests from interrupt
+ * contexts and from outside of the i915 driver.
+ */
+ struct list_head delayed_free_list;
+ spinlock_t delayed_free_lock;
+
bool gpu_caches_dirty;
wait_queue_head_t irq_queue;