提交 6c132d1b 编写于 作者: D David Woodhouse 提交者: Joerg Roedel

dma-debug: print stacktrace of mapping path on unmap error

Impact: saves stacktrace of a dma mapping and prints it if there is an  error
Signed-off-by: NDavid Woodhouse <dwmw2@infradead.org>
Signed-off-by: NJoerg Roedel <joerg.roedel@amd.com>
上级 187f9c3f
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/stacktrace.h>
#include <linux/dma-debug.h> #include <linux/dma-debug.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
...@@ -39,6 +40,8 @@ enum { ...@@ -39,6 +40,8 @@ enum {
dma_debug_coherent, dma_debug_coherent,
}; };
#define DMA_DEBUG_STACKTRACE_ENTRIES 5
struct dma_debug_entry { struct dma_debug_entry {
struct list_head list; struct list_head list;
struct device *dev; struct device *dev;
...@@ -49,6 +52,10 @@ struct dma_debug_entry { ...@@ -49,6 +52,10 @@ struct dma_debug_entry {
int direction; int direction;
int sg_call_ents; int sg_call_ents;
int sg_mapped_ents; int sg_mapped_ents;
#ifdef CONFIG_STACKTRACE
struct stack_trace stacktrace;
unsigned long st_entries[DMA_DEBUG_STACKTRACE_ENTRIES];
#endif
}; };
struct hash_bucket { struct hash_bucket {
...@@ -108,12 +115,23 @@ static const char *dir2name[4] = { "DMA_BIDIRECTIONAL", "DMA_TO_DEVICE", ...@@ -108,12 +115,23 @@ static const char *dir2name[4] = { "DMA_BIDIRECTIONAL", "DMA_TO_DEVICE",
* system log than the user configured. This variable is * system log than the user configured. This variable is
* writeable via debugfs. * writeable via debugfs.
*/ */
#define err_printk(dev, format, arg...) do { \ static inline void dump_entry_trace(struct dma_debug_entry *entry)
{
#ifdef CONFIG_STACKTRACE
if (entry) {
printk(KERN_WARNING "Mapped at:\n");
print_stack_trace(&entry->stacktrace, 0);
}
#endif
}
#define err_printk(dev, entry, format, arg...) do { \
error_count += 1; \ error_count += 1; \
if (show_all_errors || show_num_errors > 0) { \ if (show_all_errors || show_num_errors > 0) { \
WARN(1, "%s %s: " format, \ WARN(1, "%s %s: " format, \
dev_driver_string(dev), \ dev_driver_string(dev), \
dev_name(dev) , ## arg); \ dev_name(dev) , ## arg); \
dump_entry_trace(entry); \
} \ } \
if (!show_all_errors && show_num_errors > 0) \ if (!show_all_errors && show_num_errors > 0) \
show_num_errors -= 1; \ show_num_errors -= 1; \
...@@ -260,6 +278,12 @@ static struct dma_debug_entry *dma_entry_alloc(void) ...@@ -260,6 +278,12 @@ static struct dma_debug_entry *dma_entry_alloc(void)
list_del(&entry->list); list_del(&entry->list);
memset(entry, 0, sizeof(*entry)); memset(entry, 0, sizeof(*entry));
#ifdef CONFIG_STACKTRACE
entry->stacktrace.max_entries = DMA_DEBUG_STACKTRACE_ENTRIES;
entry->stacktrace.entries = entry->st_entries;
entry->stacktrace.skip = 2;
save_stack_trace(&entry->stacktrace);
#endif
num_free_entries -= 1; num_free_entries -= 1;
if (num_free_entries < min_free_entries) if (num_free_entries < min_free_entries)
min_free_entries = num_free_entries; min_free_entries = num_free_entries;
...@@ -457,7 +481,7 @@ static void check_unmap(struct dma_debug_entry *ref) ...@@ -457,7 +481,7 @@ static void check_unmap(struct dma_debug_entry *ref)
entry = hash_bucket_find(bucket, ref); entry = hash_bucket_find(bucket, ref);
if (!entry) { if (!entry) {
err_printk(ref->dev, "DMA-API: device driver tries " err_printk(ref->dev, NULL, "DMA-API: device driver tries "
"to free DMA memory it has not allocated " "to free DMA memory it has not allocated "
"[device address=0x%016llx] [size=%llu bytes]\n", "[device address=0x%016llx] [size=%llu bytes]\n",
ref->dev_addr, ref->size); ref->dev_addr, ref->size);
...@@ -465,7 +489,7 @@ static void check_unmap(struct dma_debug_entry *ref) ...@@ -465,7 +489,7 @@ static void check_unmap(struct dma_debug_entry *ref)
} }
if (ref->size != entry->size) { if (ref->size != entry->size) {
err_printk(ref->dev, "DMA-API: device driver frees " err_printk(ref->dev, entry, "DMA-API: device driver frees "
"DMA memory with different size " "DMA memory with different size "
"[device address=0x%016llx] [map size=%llu bytes] " "[device address=0x%016llx] [map size=%llu bytes] "
"[unmap size=%llu bytes]\n", "[unmap size=%llu bytes]\n",
...@@ -473,7 +497,7 @@ static void check_unmap(struct dma_debug_entry *ref) ...@@ -473,7 +497,7 @@ static void check_unmap(struct dma_debug_entry *ref)
} }
if (ref->type != entry->type) { if (ref->type != entry->type) {
err_printk(ref->dev, "DMA-API: device driver frees " err_printk(ref->dev, entry, "DMA-API: device driver frees "
"DMA memory with wrong function " "DMA memory with wrong function "
"[device address=0x%016llx] [size=%llu bytes] " "[device address=0x%016llx] [size=%llu bytes] "
"[mapped as %s] [unmapped as %s]\n", "[mapped as %s] [unmapped as %s]\n",
...@@ -481,7 +505,7 @@ static void check_unmap(struct dma_debug_entry *ref) ...@@ -481,7 +505,7 @@ static void check_unmap(struct dma_debug_entry *ref)
type2name[entry->type], type2name[ref->type]); type2name[entry->type], type2name[ref->type]);
} else if ((entry->type == dma_debug_coherent) && } else if ((entry->type == dma_debug_coherent) &&
(ref->paddr != entry->paddr)) { (ref->paddr != entry->paddr)) {
err_printk(ref->dev, "DMA-API: device driver frees " err_printk(ref->dev, entry, "DMA-API: device driver frees "
"DMA memory with different CPU address " "DMA memory with different CPU address "
"[device address=0x%016llx] [size=%llu bytes] " "[device address=0x%016llx] [size=%llu bytes] "
"[cpu alloc address=%p] [cpu free address=%p]", "[cpu alloc address=%p] [cpu free address=%p]",
...@@ -491,7 +515,7 @@ static void check_unmap(struct dma_debug_entry *ref) ...@@ -491,7 +515,7 @@ static void check_unmap(struct dma_debug_entry *ref)
if (ref->sg_call_ents && ref->type == dma_debug_sg && if (ref->sg_call_ents && ref->type == dma_debug_sg &&
ref->sg_call_ents != entry->sg_call_ents) { ref->sg_call_ents != entry->sg_call_ents) {
err_printk(ref->dev, "DMA-API: device driver frees " err_printk(ref->dev, entry, "DMA-API: device driver frees "
"DMA sg list with different entry count " "DMA sg list with different entry count "
"[map count=%d] [unmap count=%d]\n", "[map count=%d] [unmap count=%d]\n",
entry->sg_call_ents, ref->sg_call_ents); entry->sg_call_ents, ref->sg_call_ents);
...@@ -502,7 +526,7 @@ static void check_unmap(struct dma_debug_entry *ref) ...@@ -502,7 +526,7 @@ static void check_unmap(struct dma_debug_entry *ref)
* DMA API don't handle this properly, so check for it here * DMA API don't handle this properly, so check for it here
*/ */
if (ref->direction != entry->direction) { if (ref->direction != entry->direction) {
err_printk(ref->dev, "DMA-API: device driver frees " err_printk(ref->dev, entry, "DMA-API: device driver frees "
"DMA memory with different direction " "DMA memory with different direction "
"[device address=0x%016llx] [size=%llu bytes] " "[device address=0x%016llx] [size=%llu bytes] "
"[mapped with %s] [unmapped with %s]\n", "[mapped with %s] [unmapped with %s]\n",
...@@ -521,8 +545,8 @@ static void check_unmap(struct dma_debug_entry *ref) ...@@ -521,8 +545,8 @@ static void check_unmap(struct dma_debug_entry *ref)
static void check_for_stack(struct device *dev, void *addr) static void check_for_stack(struct device *dev, void *addr)
{ {
if (object_is_on_stack(addr)) if (object_is_on_stack(addr))
err_printk(dev, "DMA-API: device driver maps memory from stack" err_printk(dev, NULL, "DMA-API: device driver maps memory from"
" [addr=%p]\n", addr); "stack [addr=%p]\n", addr);
} }
static void check_sync(struct device *dev, dma_addr_t addr, static void check_sync(struct device *dev, dma_addr_t addr,
...@@ -543,7 +567,7 @@ static void check_sync(struct device *dev, dma_addr_t addr, ...@@ -543,7 +567,7 @@ static void check_sync(struct device *dev, dma_addr_t addr,
entry = hash_bucket_find(bucket, &ref); entry = hash_bucket_find(bucket, &ref);
if (!entry) { if (!entry) {
err_printk(dev, "DMA-API: device driver tries " err_printk(dev, NULL, "DMA-API: device driver tries "
"to sync DMA memory it has not allocated " "to sync DMA memory it has not allocated "
"[device address=0x%016llx] [size=%llu bytes]\n", "[device address=0x%016llx] [size=%llu bytes]\n",
addr, size); addr, size);
...@@ -551,7 +575,7 @@ static void check_sync(struct device *dev, dma_addr_t addr, ...@@ -551,7 +575,7 @@ static void check_sync(struct device *dev, dma_addr_t addr,
} }
if ((offset + size) > entry->size) { if ((offset + size) > entry->size) {
err_printk(dev, "DMA-API: device driver syncs" err_printk(dev, entry, "DMA-API: device driver syncs"
" DMA memory outside allocated range " " DMA memory outside allocated range "
"[device address=0x%016llx] " "[device address=0x%016llx] "
"[allocation size=%llu bytes] [sync offset=%llu] " "[allocation size=%llu bytes] [sync offset=%llu] "
...@@ -560,7 +584,7 @@ static void check_sync(struct device *dev, dma_addr_t addr, ...@@ -560,7 +584,7 @@ static void check_sync(struct device *dev, dma_addr_t addr,
} }
if (direction != entry->direction) { if (direction != entry->direction) {
err_printk(dev, "DMA-API: device driver syncs " err_printk(dev, entry, "DMA-API: device driver syncs "
"DMA memory with different direction " "DMA memory with different direction "
"[device address=0x%016llx] [size=%llu bytes] " "[device address=0x%016llx] [size=%llu bytes] "
"[mapped with %s] [synced with %s]\n", "[mapped with %s] [synced with %s]\n",
...@@ -574,7 +598,7 @@ static void check_sync(struct device *dev, dma_addr_t addr, ...@@ -574,7 +598,7 @@ static void check_sync(struct device *dev, dma_addr_t addr,
if (to_cpu && !(entry->direction == DMA_FROM_DEVICE) && if (to_cpu && !(entry->direction == DMA_FROM_DEVICE) &&
!(direction == DMA_TO_DEVICE)) !(direction == DMA_TO_DEVICE))
err_printk(dev, "DMA-API: device driver syncs " err_printk(dev, entry, "DMA-API: device driver syncs "
"device read-only DMA memory for cpu " "device read-only DMA memory for cpu "
"[device address=0x%016llx] [size=%llu bytes] " "[device address=0x%016llx] [size=%llu bytes] "
"[mapped with %s] [synced with %s]\n", "[mapped with %s] [synced with %s]\n",
...@@ -584,7 +608,7 @@ static void check_sync(struct device *dev, dma_addr_t addr, ...@@ -584,7 +608,7 @@ static void check_sync(struct device *dev, dma_addr_t addr,
if (!to_cpu && !(entry->direction == DMA_TO_DEVICE) && if (!to_cpu && !(entry->direction == DMA_TO_DEVICE) &&
!(direction == DMA_FROM_DEVICE)) !(direction == DMA_FROM_DEVICE))
err_printk(dev, "DMA-API: device driver syncs " err_printk(dev, entry, "DMA-API: device driver syncs "
"device write-only DMA memory to device " "device write-only DMA memory to device "
"[device address=0x%016llx] [size=%llu bytes] " "[device address=0x%016llx] [size=%llu bytes] "
"[mapped with %s] [synced with %s]\n", "[mapped with %s] [synced with %s]\n",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册