Blob Blame History Raw
From: Russell King <rmk+kernel@armlinux.org.uk>
Date: Fri, 7 Jul 2017 15:56:24 +0100
Subject: drm/armada: wait and cancel any pending frame work at disable
Git-commit: 65724a19438ce50a7cf85bc2d3172ea237ab05de
Patch-mainline: v4.16-rc1
References: FATE#326289 FATE#326079 FATE#326049 FATE#322398 FATE#326166

Wait for a second, and if we time out, cancel any pending work when
disabling the primary plane.  This ensures that any pending work is
completed or cleaned up prior to the disable taking effect.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
 drivers/gpu/drm/armada/armada_crtc.c    |   28 ++++++++++++++++++++++------
 drivers/gpu/drm/armada/armada_overlay.c |    2 --
 2 files changed, 22 insertions(+), 8 deletions(-)

--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -273,18 +273,15 @@ void armada_drm_plane_work_cancel(struct
 		armada_drm_plane_work_call(dcrtc, work, work->cancel);
 }
 
-static void armada_drm_crtc_complete_frame_work(struct armada_crtc *dcrtc,
+static void armada_drm_crtc_finish_frame_work(struct armada_crtc *dcrtc,
 	struct armada_plane_work *work)
 {
 	struct armada_frame_work *fwork = container_of(work, struct armada_frame_work, work);
-	struct drm_device *dev = dcrtc->crtc.dev;
 	unsigned long flags;
 
-	spin_lock_irqsave(&dcrtc->irq_lock, flags);
-	armada_drm_crtc_update_regs(dcrtc, fwork->regs);
-	spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
-
 	if (fwork->event) {
+		struct drm_device *dev = dcrtc->crtc.dev;
+
 		spin_lock_irqsave(&dev->event_lock, flags);
 		drm_crtc_send_vblank_event(&dcrtc->crtc, fwork->event);
 		spin_unlock_irqrestore(&dev->event_lock, flags);
@@ -295,6 +292,19 @@ static void armada_drm_crtc_complete_fra
 	kfree(fwork);
 }
 
+static void armada_drm_crtc_complete_frame_work(struct armada_crtc *dcrtc,
+	struct armada_plane_work *work)
+{
+	struct armada_frame_work *fwork = container_of(work, struct armada_frame_work, work);
+	unsigned long flags;
+
+	spin_lock_irqsave(&dcrtc->irq_lock, flags);
+	armada_drm_crtc_update_regs(dcrtc, fwork->regs);
+	spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
+
+	armada_drm_crtc_finish_frame_work(dcrtc, work);
+}
+
 static struct armada_frame_work *
 armada_drm_crtc_alloc_frame_work(struct drm_plane *plane)
 {
@@ -307,6 +317,7 @@ armada_drm_crtc_alloc_frame_work(struct
 
 	work->work.plane = plane;
 	work->work.fn = armada_drm_crtc_complete_frame_work;
+	work->work.cancel = armada_drm_crtc_finish_frame_work;
 	armada_reg_queue_end(work->regs, i);
 
 	return work;
@@ -752,6 +763,7 @@ static int armada_drm_crtc_mode_set_base
 void armada_drm_crtc_plane_disable(struct armada_crtc *dcrtc,
 	struct drm_plane *plane)
 {
+	struct armada_plane *dplane = drm_to_armada_plane(plane);
 	u32 sram_para1, dma_ctrl0_mask;
 
 	/*
@@ -775,6 +787,10 @@ void armada_drm_crtc_plane_disable(struc
 		dma_ctrl0_mask = CFG_DMA_ENA;
 	}
 
+	/* Wait for any preceding work to complete, but don't wedge */
+	if (WARN_ON(!armada_drm_plane_work_wait(dplane, HZ)))
+		armada_drm_plane_work_cancel(dcrtc, dplane);
+
 	spin_lock_irq(&dcrtc->irq_lock);
 	armada_updatel(0, dma_ctrl0_mask, dcrtc->base + LCD_SPU_DMA_CTRL0);
 	spin_unlock_irq(&dcrtc->irq_lock);
--- a/drivers/gpu/drm/armada/armada_overlay.c
+++ b/drivers/gpu/drm/armada/armada_overlay.c
@@ -270,8 +270,6 @@ static int armada_ovl_plane_disable(stru
 		return 0;
 
 	dcrtc = drm_to_armada_crtc(dplane->base.base.crtc);
-
-	armada_drm_plane_work_cancel(dcrtc, &dplane->base);
 	armada_drm_crtc_plane_disable(dcrtc, plane);
 
 	dcrtc->plane = NULL;