[Intel-gfx] [PATCH] Avoid i915 flip unpin/HPD event handler deadlock.

Chris Wilson chris at chris-wilson.co.uk
Sat Aug 31 11:15:25 CEST 2013


On Fri, Aug 30, 2013 at 06:30:55PM -0700, Stuart Abercrombie wrote:
> Both of these were taking the mode_config mutex but executed from the
> same work queue.  If intel_crtc_page_flip happened to flush a work queue
> containing an HPD event handler work item, deadlock resulted, since the
> mutex required by the HPD handler was taken before the flush.  Instead
> use a separate work queue for the flip unpin work.
> 
> Signed-off-by: sabercrombie at chromium.org
> Reviewed-by: marcheu at chromium.org

It would be possible to rearrange the flip to drop the lock around the
flush (which is a regression from the kernel/workqueue.c refacting...).
However, this looks much simpler. In the long run being strict on
calling flush_workqueue() unlocked is likely to be safer though.

Reviewed-by; Chris Wilson <chris at chris-wilson.co.uk>

> ---
>  drivers/gpu/drm/i915/i915_dma.c      | 21 ++++++++++++++++++++-
>  drivers/gpu/drm/i915/i915_drv.h      |  1 +
>  drivers/gpu/drm/i915/intel_display.c |  4 ++--
>  3 files changed, 23 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
> index 4f129bb..9215360 100644
> --- a/drivers/gpu/drm/i915/i915_dma.c
> +++ b/drivers/gpu/drm/i915/i915_dma.c
> @@ -1558,6 +1558,22 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
>  		goto out_mtrrfree;
>  	}
>  
> +	/* intel_crtc_page_flip runs with the mode_config mutex having been
> +	 * taken in the DRM layer.  It synchronously waits for pending unpin
> +	 * work items while holding this mutex.  Therefore this queue cannot
> +	 * contain work items that take this mutex, such as HPD event
> +	 * handling, or we deadlock.  There is also no reason for flipping to
> +	 * wait on such events.  Therefore put flip unpinning in its own
> +	 * work queue.
> +	 */
> +	dev_priv->flip_unpin_wq = alloc_ordered_workqueue("i915", 0);
> +	if (dev_priv->flip_unpin_wq == NULL) {
> +		DRM_ERROR("Failed to create flip unpin workqueue.\n");
> +		destroy_workqueue(dev_priv->wq);
> +		ret = -ENOMEM;
> +		goto out_mtrrfree;
> +	}
> +
>  	/* This must be called before any calls to HAS_PCH_* */
>  	intel_detect_pch(dev);
>  
> @@ -1628,6 +1644,7 @@ out_gem_unload:
>  	intel_teardown_gmbus(dev);
>  	intel_teardown_mchbar(dev);
>  	destroy_workqueue(dev_priv->wq);
> +	destroy_workqueue(dev_priv->flip_unpin_wq);

To be consistent, flip_wq then wq. In case we get ordering issues later.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre



More information about the Intel-gfx mailing list