diff mbox

[U-Boot] dm: core: Ensure DMA regions start up with the cache clean

Message ID 20170404190019.30369-1-sjg@chromium.org
State Accepted
Commit 5a8a8045a928702d9b3fb6f73a4e9717040e09a9
Delegated to: Simon Glass
Headers show

Commit Message

Simon Glass April 4, 2017, 7 p.m. UTC
There is a strange interaction with drivers which use DMA if the cache
starts off in a dirty state. Buffer space which the driver reads (but has
not previously written) can contain zero bytes from alloc_priv(). This can
cause corruption of the memory used by DMA for incoming data.

Fix this and add a comment to explain the problem.

This allows the dwc2 driver to work correctly with driver model, for
example.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/core/device.c | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

Comments

Simon Glass April 13, 2017, 9:16 p.m. UTC | #1
On 4 April 2017 at 13:00, Simon Glass <sjg@chromium.org> wrote:
> There is a strange interaction with drivers which use DMA if the cache
> starts off in a dirty state. Buffer space which the driver reads (but has
> not previously written) can contain zero bytes from alloc_priv(). This can
> cause corruption of the memory used by DMA for incoming data.
>
> Fix this and add a comment to explain the problem.
>
> This allows the dwc2 driver to work correctly with driver model, for
> example.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
>
>  drivers/core/device.c | 30 +++++++++++++++++++++++++++++-
>  1 file changed, 29 insertions(+), 1 deletion(-)

Applied to u-boot-dm
diff mbox

Patch

diff --git a/drivers/core/device.c b/drivers/core/device.c
index 70fcfc23e0..8c9f5293d0 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -255,8 +255,36 @@  static void *alloc_priv(int size, uint flags)
 
 	if (flags & DM_FLAG_ALLOC_PRIV_DMA) {
 		priv = memalign(ARCH_DMA_MINALIGN, size);
-		if (priv)
+		if (priv) {
 			memset(priv, '\0', size);
+
+			/*
+			 * Ensure that the zero bytes are flushed to memory.
+			 * This prevents problems if the driver uses this as
+			 * both an input and an output buffer:
+			 *
+			 * 1. Zeroes written to buffer (here) and sit in the
+			 *	cache
+			 * 2. Driver issues a read command to DMA
+			 * 3. CPU runs out of cache space and evicts some cache
+			 *	data in the buffer, writing zeroes to RAM from
+			 *	the memset() above
+			 * 4. DMA completes
+			 * 5. Buffer now has some DMA data and some zeroes
+			 * 6. Data being read is now incorrect
+			 *
+			 * To prevent this, ensure that the cache is clean
+			 * within this range at the start. The driver can then
+			 * use normal flush-after-write, invalidate-before-read
+			 * procedures.
+			 *
+			 * TODO(sjg@chromium.org): Drop this microblaze
+			 * exception.
+			 */
+#ifndef CONFIG_MICROBLAZE
+			flush_dcache_range((ulong)priv, (ulong)priv + size);
+#endif
+		}
 	} else {
 		priv = calloc(1, size);
 	}