[Intel-gfx] [PATCH 2/6] drm/i915: Preserve ring buffers objects across resume
Mateo Lozano, Oscar
oscar.mateo at intel.com
Tue Apr 22 14:56:35 CEST 2014
> Subject: [Intel-gfx] [PATCH 2/6] drm/i915: Preserve ring buffers objects across
> resume
>
> Tearing down the ring buffers across resume is overkill, risks unnecessary
> failure and increases fragmentation.
>
> After failure, since the device is still active we may end up trying to write into
> the dangling iomapping and trigger an oops.
>
> v2: stop_ringbuffers() was meant to call stop(ring) not
> cleanup(ring) during resume!
>
> Reported-by: Jae-hyeon Park <jhyeon at gmail.com>
> Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=72351
> References: https://bugs.freedesktop.org/show_bug.cgi?id=76554
> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
> ---
> drivers/gpu/drm/i915/i915_gem.c | 20 +++-
> drivers/gpu/drm/i915/intel_ringbuffer.c | 168 +++++++++++++++++--------------
> -
> drivers/gpu/drm/i915/intel_ringbuffer.h | 1 +
> 3 files changed, 105 insertions(+), 84 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_gem.c
> b/drivers/gpu/drm/i915/i915_gem.c index 6370a761d137..89e736c00ddc
> 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -2383,6 +2383,11 @@ static void i915_gem_reset_ring_cleanup(struct
> drm_i915_private *dev_priv,
>
> i915_gem_free_request(request);
> }
> +
> + /* These may not have been flush before the reset, do so now */
> + kfree(ring->preallocated_lazy_request);
> + ring->preallocated_lazy_request = NULL;
> + ring->outstanding_lazy_seqno = 0;
> }
>
> void i915_gem_restore_fences(struct drm_device *dev) @@ -2423,8 +2428,6
> @@ void i915_gem_reset(struct drm_device *dev)
> for_each_ring(ring, dev_priv, i)
> i915_gem_reset_ring_cleanup(dev_priv, ring);
>
> - i915_gem_cleanup_ringbuffer(dev);
> -
> i915_gem_context_reset(dev);
>
> i915_gem_restore_fences(dev);
> @@ -4232,6 +4235,17 @@ void i915_gem_vma_destroy(struct i915_vma
> *vma)
> kfree(vma);
> }
>
> +static void
> +i915_gem_stop_ringbuffers(struct drm_device *dev) {
> + struct drm_i915_private *dev_priv = dev->dev_private;
> + struct intel_ring_buffer *ring;
> + int i;
> +
> + for_each_ring(ring, dev_priv, i)
> + intel_stop_ring_buffer(ring);
> +}
> +
> int
> i915_gem_suspend(struct drm_device *dev) { @@ -4253,7 +4267,7 @@
> i915_gem_suspend(struct drm_device *dev)
> i915_gem_evict_everything(dev);
>
> i915_kernel_lost_context(dev);
> - i915_gem_cleanup_ringbuffer(dev);
> + i915_gem_stop_ringbuffers(dev);
>
> /* Hack! Don't let anybody do execbuf while we don't control the chip.
> * We need to replace this with a semaphore, or something.
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c
> b/drivers/gpu/drm/i915/intel_ringbuffer.c
> index 9bed8764a62a..cce09f5a4426 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> @@ -1301,45 +1301,39 @@ static void cleanup_status_page(struct
> intel_ring_buffer *ring)
>
> static int init_status_page(struct intel_ring_buffer *ring) {
> - struct drm_device *dev = ring->dev;
> struct drm_i915_gem_object *obj;
> - int ret;
>
> - obj = i915_gem_alloc_object(dev, 4096);
> - if (obj == NULL) {
> - DRM_ERROR("Failed to allocate status page\n");
> - ret = -ENOMEM;
> - goto err;
> - }
> + if ((obj = ring->status_page.obj) == NULL) {
> + int ret;
>
> - ret = i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
> - if (ret)
> - goto err_unref;
> + obj = i915_gem_alloc_object(ring->dev, 4096);
> + if (obj == NULL) {
> + DRM_ERROR("Failed to allocate status page\n");
> + return -ENOMEM;
> + }
>
> - ret = i915_gem_obj_ggtt_pin(obj, 4096, 0);
> - if (ret)
> - goto err_unref;
> + ret = i915_gem_object_set_cache_level(obj,
> I915_CACHE_LLC);
> + if (ret)
> + goto err_unref;
> +
> + ret = i915_gem_obj_ggtt_pin(obj, 4096, 0);
> + if (ret) {
> +err_unref:
> + drm_gem_object_unreference(&obj->base);
> + return ret;
> + }
> +
> + ring->status_page.obj = obj;
> + }
>
> ring->status_page.gfx_addr = i915_gem_obj_ggtt_offset(obj);
> ring->status_page.page_addr = kmap(sg_page(obj->pages->sgl));
> - if (ring->status_page.page_addr == NULL) {
> - ret = -ENOMEM;
> - goto err_unpin;
> - }
> - ring->status_page.obj = obj;
> memset(ring->status_page.page_addr, 0, PAGE_SIZE);
>
> DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n",
> ring->name, ring->status_page.gfx_addr);
>
> return 0;
> -
> -err_unpin:
> - i915_gem_object_ggtt_unpin(obj);
> -err_unref:
> - drm_gem_object_unreference(&obj->base);
> -err:
> - return ret;
> }
>
> static int init_phys_status_page(struct intel_ring_buffer *ring) @@ -1359,44
> +1353,23 @@ static int init_phys_status_page(struct intel_ring_buffer *ring)
> return 0;
> }
>
> -static int intel_init_ring_buffer(struct drm_device *dev,
> - struct intel_ring_buffer *ring)
> +static int allocate_ring_buffer(struct intel_ring_buffer *ring)
> {
> + struct drm_device *dev = ring->dev;
> + struct drm_i915_private *dev_priv = to_i915(dev);
> struct drm_i915_gem_object *obj;
> - struct drm_i915_private *dev_priv = dev->dev_private;
> int ret;
>
> - ring->dev = dev;
> - INIT_LIST_HEAD(&ring->active_list);
> - INIT_LIST_HEAD(&ring->request_list);
> - ring->size = 32 * PAGE_SIZE;
> - memset(ring->sync_seqno, 0, sizeof(ring->sync_seqno));
> -
> - init_waitqueue_head(&ring->irq_queue);
> -
> - if (I915_NEED_GFX_HWS(dev)) {
> - ret = init_status_page(ring);
> - if (ret)
> - return ret;
> - } else {
> - BUG_ON(ring->id != RCS);
> - ret = init_phys_status_page(ring);
> - if (ret)
> - return ret;
> - }
> + if (ring->obj)
> + return 0;
>
> obj = NULL;
> if (!HAS_LLC(dev))
> obj = i915_gem_object_create_stolen(dev, ring->size);
> if (obj == NULL)
> obj = i915_gem_alloc_object(dev, ring->size);
> - if (obj == NULL) {
> - DRM_ERROR("Failed to allocate ringbuffer\n");
> - ret = -ENOMEM;
> - goto err_hws;
> - }
> -
> - ring->obj = obj;
> + if (obj == NULL)
> + return -ENOMEM;
>
> ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, PIN_MAPPABLE);
> if (ret)
> @@ -1410,55 +1383,72 @@ static int intel_init_ring_buffer(struct drm_device
> *dev,
> ioremap_wc(dev_priv->gtt.mappable_base +
> i915_gem_obj_ggtt_offset(obj),
> ring->size);
> if (ring->virtual_start == NULL) {
> - DRM_ERROR("Failed to map ringbuffer.\n");
> ret = -EINVAL;
> goto err_unpin;
> }
>
> - ret = ring->init(ring);
> - if (ret)
> - goto err_unmap;
> + ring->obj = obj;
> + return 0;
> +
> +err_unpin:
> + i915_gem_object_ggtt_unpin(obj);
> +err_unref:
> + drm_gem_object_unreference(&obj->base);
> + return ret;
> +}
> +
> +static int intel_init_ring_buffer(struct drm_device *dev,
> + struct intel_ring_buffer *ring)
> +{
> + int ret;
> +
> + ring->dev = dev;
> + INIT_LIST_HEAD(&ring->active_list);
> + INIT_LIST_HEAD(&ring->request_list);
> + ring->size = 32 * PAGE_SIZE;
> + memset(ring->sync_seqno, 0, sizeof(ring->sync_seqno));
> +
> + init_waitqueue_head(&ring->irq_queue);
> +
> + if (I915_NEED_GFX_HWS(dev)) {
> + ret = init_status_page(ring);
> + if (ret)
> + return ret;
> + } else {
> + BUG_ON(ring->id != RCS);
> + ret = init_phys_status_page(ring);
> + if (ret)
> + return ret;
> + }
> +
> + ret = allocate_ring_buffer(ring);
> + if (ret) {
> + DRM_ERROR("Failed to allocate ringbuffer %s: %d\n", ring-
> >name, ret);
> + return ret;
> + }
>
> /* Workaround an erratum on the i830 which causes a hang if
> * the TAIL pointer points to within the last 2 cachelines
> * of the buffer.
> */
> ring->effective_size = ring->size;
> - if (IS_I830(ring->dev) || IS_845G(ring->dev))
> + if (IS_I830(dev) || IS_845G(dev))
> ring->effective_size -= 2 * CACHELINE_BYTES;
>
> i915_cmd_parser_init_ring(ring);
>
> - return 0;
> -
> -err_unmap:
> - iounmap(ring->virtual_start);
> -err_unpin:
> - i915_gem_object_ggtt_unpin(obj);
> -err_unref:
> - drm_gem_object_unreference(&obj->base);
> - ring->obj = NULL;
> -err_hws:
> - cleanup_status_page(ring);
> - return ret;
> + return ring->init(ring);
> }
>
> void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring) {
> - struct drm_i915_private *dev_priv;
> - int ret;
> + struct drm_i915_private *dev_priv = to_i915(ring->dev);
>
> if (ring->obj == NULL)
> return;
>
> - /* Disable the ring buffer. The ring must be idle at this point */
> - dev_priv = ring->dev->dev_private;
> - ret = intel_ring_idle(ring);
> - if (ret && !i915_reset_in_progress(&dev_priv->gpu_error))
> - DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n",
> - ring->name, ret);
> -
> - I915_WRITE_CTL(ring, 0);
> + intel_stop_ring_buffer(ring);
> + WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0);
>
> iounmap(ring->virtual_start);
>
> @@ -2248,3 +2238,19 @@ intel_ring_invalidate_all_caches(struct
> intel_ring_buffer *ring)
> ring->gpu_caches_dirty = false;
> return 0;
> }
> +
> +void
> +intel_stop_ring_buffer(struct intel_ring_buffer *ring) {
> + int ret;
> +
> + if (ring->obj == NULL)
> + return;
It´s probably a good idea to use the intel_ring_initialized() macro.
Other than that:
Reviewed-by: Oscar Mateo <oscar.mateo at intel.com>
> +
> + ret = intel_ring_idle(ring);
> + if (ret && !i915_reset_in_progress(&to_i915(ring->dev)->gpu_error))
> + DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n",
> + ring->name, ret);
> +
> + stop_ring(ring);
> +}
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h
> b/drivers/gpu/drm/i915/intel_ringbuffer.h
> index 413cdc74ed53..54839165eb6d 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.h
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
> @@ -263,6 +263,7 @@ intel_write_status_page(struct intel_ring_buffer *ring,
> #define I915_GEM_HWS_SCRATCH_INDEX 0x30
> #define I915_GEM_HWS_SCRATCH_ADDR (I915_GEM_HWS_SCRATCH_INDEX
> << MI_STORE_DWORD_INDEX_SHIFT)
>
> +void intel_stop_ring_buffer(struct intel_ring_buffer *ring);
> void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring);
>
> int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n);
> --
> 1.9.1
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
More information about the Intel-gfx
mailing list