drm/i915: Recover all available ringbuffer space following reset
authorChris Wilson <chris@chris-wilson.co.uk>
Thu, 3 Sep 2015 12:01:40 +0000 (13:01 +0100)
committerTvrtko Ursulin <tvrtko.ursulin@intel.com>
Wed, 28 Oct 2015 17:10:31 +0000 (17:10 +0000)
Having flushed all requests from all queues, we know that all
ringbuffers must now be empty. However, since we do not reclaim
all space when retiring the request (to prevent HEADs colliding
with rapid ringbuffer wraparound) the amount of available space
on each ringbuffer upon reset is less than when we start. Do one
more pass over all the ringbuffers to reset the available space

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com>
Cc: Arun Siluvery <arun.siluvery@linux.intel.com>
Cc: Mika Kuoppala <mika.kuoppala@intel.com>
Cc: Dave Gordon <david.s.gordon@intel.com>
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/intel_lrc.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_ringbuffer.h

index 9b2048c7077d1cbd2f545e2d46b34b8874ce395f..4b03dce9385960694bc628122989071bda30f797 100644 (file)
@@ -2738,6 +2738,8 @@ static void i915_gem_reset_ring_status(struct drm_i915_private *dev_priv,
 static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
                                        struct intel_engine_cs *ring)
 {
+       struct intel_ringbuffer *buffer;
+
        while (!list_empty(&ring->active_list)) {
                struct drm_i915_gem_object *obj;
 
@@ -2788,6 +2790,18 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
 
                i915_gem_request_retire(request);
        }
+
+       /* Having flushed all requests from all queues, we know that all
+        * ringbuffers must now be empty. However, since we do not reclaim
+        * all space when retiring the request (to prevent HEADs colliding
+        * with rapid ringbuffer wraparound) the amount of available space
+        * upon reset is less than when we start. Do one more pass over
+        * all the ringbuffers to reset last_retired_head.
+        */
+       list_for_each_entry(buffer, &ring->buffers, link) {
+               buffer->last_retired_head = buffer->tail;
+               intel_ring_update_space(buffer);
+       }
 }
 
 void i915_gem_reset(struct drm_device *dev)
index 14bdb36deb94ac0a6c6cb06354a91efcbe37d1cd..fd7b8c9fdfb490cc518486521e7635d0ef19ad19 100644 (file)
@@ -1897,6 +1897,7 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin
        i915_gem_batch_pool_init(dev, &ring->batch_pool);
        init_waitqueue_head(&ring->irq_queue);
 
+       INIT_LIST_HEAD(&ring->buffers);
        INIT_LIST_HEAD(&ring->execlist_queue);
        INIT_LIST_HEAD(&ring->execlist_retired_req_list);
        spin_lock_init(&ring->execlist_lock);
index 69286c9f2fd33ab942691e6b8673496b73cf9a3a..8d6d2de19dca860c0c32adad8d9507c5668dcbf6 100644 (file)
@@ -2102,10 +2102,14 @@ intel_engine_create_ringbuffer(struct intel_engine_cs *engine, int size)
        int ret;
 
        ring = kzalloc(sizeof(*ring), GFP_KERNEL);
-       if (ring == NULL)
+       if (ring == NULL) {
+               DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s\n",
+                                engine->name);
                return ERR_PTR(-ENOMEM);
+       }
 
        ring->ring = engine;
+       list_add(&ring->link, &engine->buffers);
 
        ring->size = size;
        /* Workaround an erratum on the i830 which causes a hang if
@@ -2121,8 +2125,9 @@ intel_engine_create_ringbuffer(struct intel_engine_cs *engine, int size)
 
        ret = intel_alloc_ringbuffer_obj(engine->dev, ring);
        if (ret) {
-               DRM_ERROR("Failed to allocate ringbuffer %s: %d\n",
-                         engine->name, ret);
+               DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s: %d\n",
+                                engine->name, ret);
+               list_del(&ring->link);
                kfree(ring);
                return ERR_PTR(ret);
        }
@@ -2134,6 +2139,7 @@ void
 intel_ringbuffer_free(struct intel_ringbuffer *ring)
 {
        intel_destroy_ringbuffer_obj(ring);
+       list_del(&ring->link);
        kfree(ring);
 }
 
@@ -2149,6 +2155,7 @@ static int intel_init_ring_buffer(struct drm_device *dev,
        INIT_LIST_HEAD(&ring->active_list);
        INIT_LIST_HEAD(&ring->request_list);
        INIT_LIST_HEAD(&ring->execlist_queue);
+       INIT_LIST_HEAD(&ring->buffers);
        i915_gem_batch_pool_init(dev, &ring->batch_pool);
        memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno));
 
index 49fa41dc0eb66af4ee7ba10c15f6948ad84bb079..58b1976a7d0ae86054a2b2ae6821a63f867bc2f5 100644 (file)
@@ -100,6 +100,7 @@ struct intel_ringbuffer {
        void __iomem *virtual_start;
 
        struct intel_engine_cs *ring;
+       struct list_head link;
 
        u32 head;
        u32 tail;
@@ -157,6 +158,7 @@ struct  intel_engine_cs {
        u32             mmio_base;
        struct          drm_device *dev;
        struct intel_ringbuffer *buffer;
+       struct list_head buffers;
 
        /*
         * A pool of objects to use as shadow copies of client batch buffers