Просмотр исходного кода

drm/i915: unload: fix unpin_work related races

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>
Daniel Vetter 15 лет назад
Родитель
Сommit
67e77c5ae8
2 измененных файлов с 17 добавлено и 0 удалено
  1. 3 0
      drivers/gpu/drm/i915/i915_dma.c
  2. 14 0
      drivers/gpu/drm/i915/intel_display.c

+ 3 - 0
drivers/gpu/drm/i915/i915_dma.c

@@ -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);

+ 14 - 0
drivers/gpu/drm/i915/intel_display.c

@@ -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);
 }