Petr Tesarik 373f2b
From 538f66ba204944470a653a4cccc5f8befdf97c22 Mon Sep 17 00:00:00 2001
Petr Tesarik 373f2b
From: Tomi Valkeinen <tomi.valkeinen@ti.com>
Petr Tesarik 373f2b
Date: Wed, 26 Sep 2018 12:11:27 +0300
Petr Tesarik 373f2b
Subject: [PATCH] drm/omap: fix memory barrier bug in DMM driver
Petr Tesarik 373f2b
Git-commit: 538f66ba204944470a653a4cccc5f8befdf97c22
Petr Tesarik 373f2b
Patch-mainline: v4.20-rc1
Petr Tesarik 373f2b
References: bsc#1051510
Petr Tesarik 373f2b
Petr Tesarik 373f2b
A DMM timeout "timed out waiting for done" has been observed on DRA7
Petr Tesarik 373f2b
devices. The timeout happens rarely, and only when the system is under
Petr Tesarik 373f2b
heavy load.
Petr Tesarik 373f2b
Petr Tesarik 373f2b
Debugging showed that the timeout can be made to happen much more
Petr Tesarik 373f2b
frequently by optimizing the DMM driver, so that there's almost no code
Petr Tesarik 373f2b
between writing the last DMM descriptors to RAM, and writing to DMM
Petr Tesarik 373f2b
register which starts the DMM transaction.
Petr Tesarik 373f2b
Petr Tesarik 373f2b
The current theory is that a wmb() does not properly ensure that the
Petr Tesarik 373f2b
data written to RAM is observable by all the components in the system.
Petr Tesarik 373f2b
Petr Tesarik 373f2b
This DMM timeout has caused interesting (and rare) bugs as the error
Petr Tesarik 373f2b
handling was not functioning properly (the error handling has been fixed
Petr Tesarik 373f2b
in previous commits):
Petr Tesarik 373f2b
Petr Tesarik 373f2b
 * If a DMM timeout happened when a GEM buffer was being pinned for
Petr Tesarik 373f2b
   display on the screen, a timeout error would be shown, but the driver
Petr Tesarik 373f2b
   would continue programming DSS HW with broken buffer, leading to
Petr Tesarik 373f2b
   SYNCLOST floods and possible crashes.
Petr Tesarik 373f2b
Petr Tesarik 373f2b
 * If a DMM timeout happened when other user (say, video decoder) was
Petr Tesarik 373f2b
   pinning a GEM buffer, a timeout would be shown but if the user
Petr Tesarik 373f2b
   handled the error properly, no other issues followed.
Petr Tesarik 373f2b
Petr Tesarik 373f2b
 * If a DMM timeout happened when a GEM buffer was being released, the
Petr Tesarik 373f2b
   driver does not even notice the error, leading to crashes or hang
Petr Tesarik 373f2b
   later.
Petr Tesarik 373f2b
Petr Tesarik 373f2b
This patch adds wmb() and readl() calls after the last bit is written to
Petr Tesarik 373f2b
RAM, which should ensure that the execution proceeds only after the data
Petr Tesarik 373f2b
is actually in RAM, and thus observable by DMM.
Petr Tesarik 373f2b
Petr Tesarik 373f2b
The read-back should not be needed. Further study is required to understand
Petr Tesarik 373f2b
if DMM is somehow special case and read-back is ok, or if DRA7's memory
Petr Tesarik 373f2b
barriers do not work correctly.
Petr Tesarik 373f2b
Petr Tesarik 373f2b
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Petr Tesarik 373f2b
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
Petr Tesarik 373f2b
Acked-by: Takashi Iwai <tiwai@suse.de>
Petr Tesarik 373f2b
Petr Tesarik 373f2b
---
Petr Tesarik 373f2b
 drivers/gpu/drm/omapdrm/omap_dmm_tiler.c |   11 +++++++++++
Petr Tesarik 373f2b
 1 file changed, 11 insertions(+)
Petr Tesarik 373f2b
Petr Tesarik 373f2b
--- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
Petr Tesarik 373f2b
+++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
Petr Tesarik 373f2b
@@ -285,6 +285,17 @@ static int dmm_txn_commit(struct dmm_txn
Petr Tesarik 373f2b
 	}
Petr Tesarik 373f2b
 
Petr Tesarik 373f2b
 	txn->last_pat->next_pa = 0;
Petr Tesarik 373f2b
+	/* ensure that the written descriptors are visible to DMM */
Petr Tesarik 373f2b
+	wmb();
Petr Tesarik 373f2b
+
Petr Tesarik 373f2b
+	/*
Petr Tesarik 373f2b
+	 * NOTE: the wmb() above should be enough, but there seems to be a bug
Petr Tesarik 373f2b
+	 * in OMAP's memory barrier implementation, which in some rare cases may
Petr Tesarik 373f2b
+	 * cause the writes not to be observable after wmb().
Petr Tesarik 373f2b
+	 */
Petr Tesarik 373f2b
+
Petr Tesarik 373f2b
+	/* read back to ensure the data is in RAM */
Petr Tesarik 373f2b
+	readl(&txn->last_pat->next_pa);
Petr Tesarik 373f2b
 
Petr Tesarik 373f2b
 	/* write to PAT_DESCR to clear out any pending transaction */
Petr Tesarik 373f2b
 	dmm_write(dmm, 0x0, reg[PAT_DESCR][engine->id]);