drm/i915: unload: fix unpin_work related races
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Fri, 20 Aug 2010 20:26:30 +0000 (22:26 +0200)
committerChris Wilson <chris@chris-wilson.co.uk>
Wed, 8 Sep 2010 09:13:27 +0000 (10:13 +0100)
Kill any outstanding unpin_work when destroying the corresponding
crtc. Then flush the workqueue before the gem teardown, in case
any unpin work is still outstanding.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/intel_display.c

index 970c338..27a826e 100644 (file)
@@ -2292,6 +2292,9 @@ int i915_driver_unload(struct drm_device *dev)
        intel_opregion_free(dev, 0);
 
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               /* Flush any outstanding unpin_work. */
+               flush_workqueue(dev_priv->wq);
+
                i915_gem_free_all_phys_object(dev);
 
                mutex_lock(&dev->struct_mutex);
index ccfc105..794d4ac 100644 (file)
@@ -4850,8 +4850,22 @@ void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj)
 static void intel_crtc_destroy(struct drm_crtc *crtc)
 {
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct intel_unpin_work *work;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+       work = intel_crtc->unpin_work;
+       intel_crtc->unpin_work = NULL;
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+
+       if (work) {
+               cancel_work_sync(&work->work);
+               kfree(work);
+       }
 
        drm_crtc_cleanup(crtc);
+
        kfree(intel_crtc);
 }