]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
dma-debug: allow poisoning nonzero allocations
authorRobin Murphy <robin.murphy@arm.com>
Wed, 21 Oct 2015 22:04:01 +0000 (09:04 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Wed, 21 Oct 2015 22:04:01 +0000 (09:04 +1100)
Since some dma_alloc_coherent implementations return a zeroed buffer
regardless of whether __GFP_ZERO is passed, there exist drivers which are
implicitly dependent on this and pass otherwise uninitialised buffers to
hardware.  This can lead to subtle and awkward-to-debug issues using those
drivers on different platforms, where nonzero uninitialised junk may for
instance occasionally look like a valid command which causes the hardware
to start misbehaving.  To help with debugging such issues, add the option
to make uninitialised buffers much more obvious.

Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Cc: Sumit Semwal <sumit.semwal@linaro.org>
Cc: Sakari Ailus <sakari.ailus@iki.fi>
Cc: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
include/asm-generic/dma-mapping-common.h
include/linux/dma-debug.h
include/linux/poison.h
lib/Kconfig.debug
lib/dma-debug.c

index b1bc954eccf37438213d6744fe69ff1bc4d71365..0f3e16b1ea64b454f500d949cf192ea20eeba732 100644 (file)
@@ -260,7 +260,7 @@ static inline void *dma_alloc_attrs(struct device *dev, size_t size,
                return NULL;
 
        cpu_addr = ops->alloc(dev, size, dma_handle, flag, attrs);
-       debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr);
+       debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr, flag);
        return cpu_addr;
 }
 
index fe8cb610deac70f3027edb7923d4bd99f525b7c6..e5f539dd56bfa3dfbd21836e80d7b32188502593 100644 (file)
@@ -51,7 +51,8 @@ extern void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
                               int nelems, int dir);
 
 extern void debug_dma_alloc_coherent(struct device *dev, size_t size,
-                                    dma_addr_t dma_addr, void *virt);
+                                    dma_addr_t dma_addr, void *virt,
+                                    gfp_t flags);
 
 extern void debug_dma_free_coherent(struct device *dev, size_t size,
                                    void *virt, dma_addr_t addr);
@@ -132,7 +133,8 @@ static inline void debug_dma_unmap_sg(struct device *dev,
 }
 
 static inline void debug_dma_alloc_coherent(struct device *dev, size_t size,
-                                           dma_addr_t dma_addr, void *virt)
+                                           dma_addr_t dma_addr, void *virt,
+                                           gfp_t flags)
 {
 }
 
index 4a27153574e2839546fb40ee8e8afea483e33cef..deabe23b426d90c65bb0cdd10b69e69c66a05ba9 100644 (file)
@@ -77,6 +77,9 @@
 #define MUTEX_DEBUG_INIT       0x11
 #define MUTEX_DEBUG_FREE       0x22
 
+/********** lib/dma_debug.c **********/
+#define DMA_ALLOC_POISON       0xee
+
 /********** lib/flex_array.c **********/
 #define FLEX_ARRAY_FREE        0x6c    /* for use-after-free poisoning */
 
index c8ab20934691e187e1e0a6d95a9e66ddd7c8b844..4d1b97b03b2f8ee27a000f66c4ab8c6cb5cae94d 100644 (file)
@@ -1764,6 +1764,16 @@ config DMA_API_DEBUG
 
          If unsure, say N.
 
+config DMA_API_DEBUG_POISON
+       bool "Poison coherent DMA buffers"
+       depends on DMA_API_DEBUG && EXPERT
+       help
+         Poison DMA buffers returned by dma_alloc_coherent unless __GFP_ZERO
+         is explicitly specified, to catch drivers depending on zeroed buffers
+         without passing the correct flags.
+
+         Only say Y if you're prepared for almost everything to break.
+
 config TEST_LKM
        tristate "Test module loading with 'hello world' module"
        default n
index 908fb353f0d2c72a69d00789dc0d1dd081fee24c..40514eddb67053562978de2c06a8f12451175a98 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/sched.h>
 #include <linux/ctype.h>
 #include <linux/list.h>
+#include <linux/poison.h>
 #include <linux/slab.h>
 
 #include <asm/sections.h>
@@ -1447,7 +1448,7 @@ void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
 EXPORT_SYMBOL(debug_dma_unmap_sg);
 
 void debug_dma_alloc_coherent(struct device *dev, size_t size,
-                             dma_addr_t dma_addr, void *virt)
+                             dma_addr_t dma_addr, void *virt, gfp_t flags)
 {
        struct dma_debug_entry *entry;
 
@@ -1457,6 +1458,9 @@ void debug_dma_alloc_coherent(struct device *dev, size_t size,
        if (unlikely(virt == NULL))
                return;
 
+       if (IS_ENABLED(CONFIG_DMA_API_DEBUG_POISON) && !(flags & __GFP_ZERO))
+               memset(virt, DMA_ALLOC_POISON, size);
+
        entry = dma_entry_alloc();
        if (!entry)
                return;