aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Fainelli <f.fainelli@gmail.com>2014-12-10 18:41:25 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-12-10 20:41:02 -0500
commit2ce8e7ed006a6e86eecf59188da8652b8a3bc4f0 (patch)
tree86909497f906374db58b65f4af2219eb290d059d
parent01ce18b31153427bcdccc9c9fd170fd28c03e6e8 (diff)
dma-debug: prevent early callers from crashing
dma_debug_init() is called by architecture specific code at different levels, but typically as a fs_initcall due to the debugfs initialization. Some platforms may have early callers of the DMA-API, running prior to the fs_initcall() level, which is not much of an issue unless CONFIG_DMA_API_DEBUG is set. When the DMA-API debugging facilities are turned on a caller will go through: debug_dma_map_{single,page} -> dma_mapping_error (inline function usually) -> debug_dma_mapping_error -> get_hash_bucket Calling get_hash_bucket() returns a valid hash value since we hash on high bits of the dma_addr cookie, but we will grab an unitialized spinlock, which typically won't crash but produce a warning, the real crash will however happen during the bucket list traversal because the list has not been initialized yet. An obvious solution is of course to move some of the offenders to run after the fs_initcall level, but since this might not always be an option, we add a flag "dma_debug_initialized" which is set to false by default, and set to true once dma_debug_init() has had a chance to run. The dma_debug_disabled() helper function previously introduced just needs to check for dma_debug_initialized to allow the caller to proceed or not. Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Cc: Dan Williams <dan.j.williams@intel.com> Cc: Jiri Kosina <jkosina@suse.cz> Cc: Horia Geanta <horia.geanta@freescale.com> Cc: Brian Norris <computersforpeace@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--lib/dma-debug.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/lib/dma-debug.c b/lib/dma-debug.c
index 1ac35dbaf8e0..9722bd2dbc9b 100644
--- a/lib/dma-debug.c
+++ b/lib/dma-debug.c
@@ -102,9 +102,12 @@ static DEFINE_SPINLOCK(free_entries_lock);
102/* Global disable flag - will be set in case of an error */ 102/* Global disable flag - will be set in case of an error */
103static u32 global_disable __read_mostly; 103static u32 global_disable __read_mostly;
104 104
105/* Early initialization disable flag, set at the end of dma_debug_init */
106static bool dma_debug_initialized __read_mostly;
107
105static inline bool dma_debug_disabled(void) 108static inline bool dma_debug_disabled(void)
106{ 109{
107 return global_disable; 110 return global_disable || !dma_debug_initialized;
108} 111}
109 112
110/* Global error count */ 113/* Global error count */
@@ -999,7 +1002,10 @@ void dma_debug_init(u32 num_entries)
999{ 1002{
1000 int i; 1003 int i;
1001 1004
1002 if (dma_debug_disabled()) 1005 /* Do not use dma_debug_initialized here, since we really want to be
1006 * called to set dma_debug_initialized
1007 */
1008 if (global_disable)
1003 return; 1009 return;
1004 1010
1005 for (i = 0; i < HASH_SIZE; ++i) { 1011 for (i = 0; i < HASH_SIZE; ++i) {
@@ -1026,6 +1032,8 @@ void dma_debug_init(u32 num_entries)
1026 1032
1027 nr_total_entries = num_free_entries; 1033 nr_total_entries = num_free_entries;
1028 1034
1035 dma_debug_initialized = true;
1036
1029 pr_info("DMA-API: debugging enabled by kernel config\n"); 1037 pr_info("DMA-API: debugging enabled by kernel config\n");
1030} 1038}
1031 1039