Skip to content

Commit 6c9c6d6

Browse files
Shuah KhanJoerg Roedel
Shuah Khan
authored and
Joerg Roedel
committed
dma-debug: New interfaces to debug dma mapping errors
Add dma-debug interface debug_dma_mapping_error() to debug drivers that fail to check dma mapping errors on addresses returned by dma_map_single() and dma_map_page() interfaces. This interface clears a flag set by debug_dma_map_page() to indicate that dma_mapping_error() has been called by the driver. When driver does unmap, debug_dma_unmap() checks the flag and if this flag is still set, prints warning message that includes call trace that leads up to the unmap. This interface can be called from dma_mapping_error() routines to enable dma mapping error check debugging. Tested: Intel iommu and swiotlb (iommu=soft) on x86-64 with CONFIG_DMA_API_DEBUG enabled and disabled. Signed-off-by: Shuah Khan <[email protected]> Reviewed-by: Konrad Rzeszutek Wilk <[email protected]> Signed-off-by: Joerg Roedel <[email protected]>
1 parent 6f0c058 commit 6c9c6d6

File tree

4 files changed

+87
-4
lines changed

4 files changed

+87
-4
lines changed

Documentation/DMA-API.txt

+12
Original file line numberDiff line numberDiff line change
@@ -678,3 +678,15 @@ out of dma_debug_entries. These entries are preallocated at boot. The number
678678
of preallocated entries is defined per architecture. If it is too low for you
679679
boot with 'dma_debug_entries=<your_desired_number>' to overwrite the
680680
architectural default.
681+
682+
void debug_dmap_mapping_error(struct device *dev, dma_addr_t dma_addr);
683+
684+
dma-debug interface debug_dma_mapping_error() to debug drivers that fail
685+
to check dma mapping errors on addresses returned by dma_map_single() and
686+
dma_map_page() interfaces. This interface clears a flag set by
687+
debug_dma_map_page() to indicate that dma_mapping_error() has been called by
688+
the driver. When driver does unmap, debug_dma_unmap() checks the flag and if
689+
this flag is still set, prints warning message that includes call trace that
690+
leads up to the unmap. This interface can be called from dma_mapping_error()
691+
routines to enable dma mapping error check debugging.
692+

arch/x86/include/asm/dma-mapping.h

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
4747
static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
4848
{
4949
struct dma_map_ops *ops = get_dma_ops(dev);
50+
debug_dma_mapping_error(dev, dma_addr);
5051
if (ops->mapping_error)
5152
return ops->mapping_error(dev, dma_addr);
5253

include/linux/dma-debug.h

+7
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ extern void debug_dma_map_page(struct device *dev, struct page *page,
3939
int direction, dma_addr_t dma_addr,
4040
bool map_single);
4141

42+
extern void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr);
43+
4244
extern void debug_dma_unmap_page(struct device *dev, dma_addr_t addr,
4345
size_t size, int direction, bool map_single);
4446

@@ -105,6 +107,11 @@ static inline void debug_dma_map_page(struct device *dev, struct page *page,
105107
{
106108
}
107109

110+
static inline void debug_dma_mapping_error(struct device *dev,
111+
dma_addr_t dma_addr)
112+
{
113+
}
114+
108115
static inline void debug_dma_unmap_page(struct device *dev, dma_addr_t addr,
109116
size_t size, int direction,
110117
bool map_single)

lib/dma-debug.c

+67-4
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ enum {
4545
dma_debug_coherent,
4646
};
4747

48+
enum map_err_types {
49+
MAP_ERR_CHECK_NOT_APPLICABLE,
50+
MAP_ERR_NOT_CHECKED,
51+
MAP_ERR_CHECKED,
52+
};
53+
4854
#define DMA_DEBUG_STACKTRACE_ENTRIES 5
4955

5056
struct dma_debug_entry {
@@ -57,6 +63,7 @@ struct dma_debug_entry {
5763
int direction;
5864
int sg_call_ents;
5965
int sg_mapped_ents;
66+
enum map_err_types map_err_type;
6067
#ifdef CONFIG_STACKTRACE
6168
struct stack_trace stacktrace;
6269
unsigned long st_entries[DMA_DEBUG_STACKTRACE_ENTRIES];
@@ -114,6 +121,12 @@ static struct device_driver *current_driver __read_mostly;
114121

115122
static DEFINE_RWLOCK(driver_name_lock);
116123

124+
static const char *const maperr2str[] = {
125+
[MAP_ERR_CHECK_NOT_APPLICABLE] = "dma map error check not applicable",
126+
[MAP_ERR_NOT_CHECKED] = "dma map error not checked",
127+
[MAP_ERR_CHECKED] = "dma map error checked",
128+
};
129+
117130
static const char *type2name[4] = { "single", "page",
118131
"scather-gather", "coherent" };
119132

@@ -376,11 +389,12 @@ void debug_dma_dump_mappings(struct device *dev)
376389
list_for_each_entry(entry, &bucket->list, list) {
377390
if (!dev || dev == entry->dev) {
378391
dev_info(entry->dev,
379-
"%s idx %d P=%Lx D=%Lx L=%Lx %s\n",
392+
"%s idx %d P=%Lx D=%Lx L=%Lx %s %s\n",
380393
type2name[entry->type], idx,
381394
(unsigned long long)entry->paddr,
382395
entry->dev_addr, entry->size,
383-
dir2name[entry->direction]);
396+
dir2name[entry->direction],
397+
maperr2str[entry->map_err_type]);
384398
}
385399
}
386400

@@ -838,13 +852,28 @@ static __init int dma_debug_entries_cmdline(char *str)
838852
__setup("dma_debug=", dma_debug_cmdline);
839853
__setup("dma_debug_entries=", dma_debug_entries_cmdline);
840854

855+
/* Calling dma_mapping_error() from dma-debug api will result in calling
856+
debug_dma_mapping_error() - need internal mapping error routine to
857+
avoid debug checks */
858+
#ifndef DMA_ERROR_CODE
859+
#define DMA_ERROR_CODE 0
860+
#endif
861+
static inline int has_mapping_error(struct device *dev, dma_addr_t dma_addr)
862+
{
863+
const struct dma_map_ops *ops = get_dma_ops(dev);
864+
if (ops->mapping_error)
865+
return ops->mapping_error(dev, dma_addr);
866+
867+
return (dma_addr == DMA_ERROR_CODE);
868+
}
869+
841870
static void check_unmap(struct dma_debug_entry *ref)
842871
{
843872
struct dma_debug_entry *entry;
844873
struct hash_bucket *bucket;
845874
unsigned long flags;
846875

847-
if (dma_mapping_error(ref->dev, ref->dev_addr)) {
876+
if (unlikely(has_mapping_error(ref->dev, ref->dev_addr))) {
848877
err_printk(ref->dev, NULL, "DMA-API: device driver tries "
849878
"to free an invalid DMA memory address\n");
850879
return;
@@ -910,6 +939,15 @@ static void check_unmap(struct dma_debug_entry *ref)
910939
dir2name[ref->direction]);
911940
}
912941

942+
if (entry->map_err_type == MAP_ERR_NOT_CHECKED) {
943+
err_printk(ref->dev, entry,
944+
"DMA-API: device driver failed to check map error"
945+
"[device address=0x%016llx] [size=%llu bytes] "
946+
"[mapped as %s]",
947+
ref->dev_addr, ref->size,
948+
type2name[entry->type]);
949+
}
950+
913951
hash_bucket_del(entry);
914952
dma_entry_free(entry);
915953

@@ -1017,7 +1055,7 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
10171055
if (unlikely(global_disable))
10181056
return;
10191057

1020-
if (unlikely(dma_mapping_error(dev, dma_addr)))
1058+
if (unlikely(has_mapping_error(dev, dma_addr)))
10211059
return;
10221060

10231061
entry = dma_entry_alloc();
@@ -1030,6 +1068,7 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
10301068
entry->dev_addr = dma_addr;
10311069
entry->size = size;
10321070
entry->direction = direction;
1071+
entry->map_err_type = MAP_ERR_NOT_CHECKED;
10331072

10341073
if (map_single)
10351074
entry->type = dma_debug_single;
@@ -1045,6 +1084,30 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
10451084
}
10461085
EXPORT_SYMBOL(debug_dma_map_page);
10471086

1087+
void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
1088+
{
1089+
struct dma_debug_entry ref;
1090+
struct dma_debug_entry *entry;
1091+
struct hash_bucket *bucket;
1092+
unsigned long flags;
1093+
1094+
if (unlikely(global_disable))
1095+
return;
1096+
1097+
ref.dev = dev;
1098+
ref.dev_addr = dma_addr;
1099+
bucket = get_hash_bucket(&ref, &flags);
1100+
entry = bucket_find_exact(bucket, &ref);
1101+
1102+
if (!entry)
1103+
goto out;
1104+
1105+
entry->map_err_type = MAP_ERR_CHECKED;
1106+
out:
1107+
put_hash_bucket(bucket, &flags);
1108+
}
1109+
EXPORT_SYMBOL(debug_dma_mapping_error);
1110+
10481111
void debug_dma_unmap_page(struct device *dev, dma_addr_t addr,
10491112
size_t size, int direction, bool map_single)
10501113
{

0 commit comments

Comments
 (0)