diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-20 13:07:25 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-20 13:07:25 -0500 |
commit | 787314c35fbb97e02823a1b8eb8cfa58f366cd49 (patch) | |
tree | 3fe5a484c1846c80361217a726997484533e8344 /lib | |
parent | 6491d4d02893d9787ba67279595990217177b351 (diff) | |
parent | 9c6ecf6a3ade2dc4b03a239af68058b22897af41 (diff) |
Merge tag 'iommu-updates-v3.8' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu
Pull IOMMU updates from Joerg Roedel:
"A few new features this merge-window. The most important one is
probably, that dma-debug now warns if a dma-handle is not checked with
dma_mapping_error by the device driver. This requires minor changes
to some architectures which make use of dma-debug. Most of these
changes have the respective Acks by the Arch-Maintainers.
Besides that there are updates to the AMD IOMMU driver for refactor
the IOMMU-Groups support and to make sure it does not trigger a
hardware erratum.
The OMAP changes (for which I pulled in a branch from Tony Lindgren's
tree) have a conflict in linux-next with the arm-soc tree. The
conflict is in the file arch/arm/mach-omap2/clock44xx_data.c which is
deleted in the arm-soc tree. It is safe to delete the file too so
solve the conflict. Similar changes are done in the arm-soc tree in
the common clock framework migration. A missing hunk from the patch
in the IOMMU tree will be submitted as a seperate patch when the
merge-window is closed."
* tag 'iommu-updates-v3.8' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu: (29 commits)
ARM: dma-mapping: support debug_dma_mapping_error
ARM: OMAP4: hwmod data: ipu and dsp to use parent clocks instead of leaf clocks
iommu/omap: Adapt to runtime pm
iommu/omap: Migrate to hwmod framework
iommu/omap: Keep mmu enabled when requested
iommu/omap: Remove redundant clock handling on ISR
iommu/amd: Remove obsolete comment
iommu/amd: Don't use 512GB pages
iommu/tegra: smmu: Move bus_set_iommu after probe for multi arch
iommu/tegra: gart: Move bus_set_iommu after probe for multi arch
iommu/tegra: smmu: Remove unnecessary PTC/TLB flush all
tile: dma_debug: add debug_dma_mapping_error support
sh: dma_debug: add debug_dma_mapping_error support
powerpc: dma_debug: add debug_dma_mapping_error support
mips: dma_debug: add debug_dma_mapping_error support
microblaze: dma-mapping: support debug_dma_mapping_error
ia64: dma_debug: add debug_dma_mapping_error support
c6x: dma_debug: add debug_dma_mapping_error support
ARM64: dma_debug: add debug_dma_mapping_error support
intel-iommu: Prevent devices with RMRRs from being placed into SI Domain
...
Diffstat (limited to 'lib')
-rw-r--r-- | lib/dma-debug.c | 66 |
1 files changed, 57 insertions, 9 deletions
diff --git a/lib/dma-debug.c b/lib/dma-debug.c index d84beb994f3..5e396accd3d 100644 --- a/lib/dma-debug.c +++ b/lib/dma-debug.c | |||
@@ -45,6 +45,12 @@ enum { | |||
45 | dma_debug_coherent, | 45 | dma_debug_coherent, |
46 | }; | 46 | }; |
47 | 47 | ||
48 | enum map_err_types { | ||
49 | MAP_ERR_CHECK_NOT_APPLICABLE, | ||
50 | MAP_ERR_NOT_CHECKED, | ||
51 | MAP_ERR_CHECKED, | ||
52 | }; | ||
53 | |||
48 | #define DMA_DEBUG_STACKTRACE_ENTRIES 5 | 54 | #define DMA_DEBUG_STACKTRACE_ENTRIES 5 |
49 | 55 | ||
50 | struct dma_debug_entry { | 56 | struct dma_debug_entry { |
@@ -57,6 +63,7 @@ struct dma_debug_entry { | |||
57 | int direction; | 63 | int direction; |
58 | int sg_call_ents; | 64 | int sg_call_ents; |
59 | int sg_mapped_ents; | 65 | int sg_mapped_ents; |
66 | enum map_err_types map_err_type; | ||
60 | #ifdef CONFIG_STACKTRACE | 67 | #ifdef CONFIG_STACKTRACE |
61 | struct stack_trace stacktrace; | 68 | struct stack_trace stacktrace; |
62 | unsigned long st_entries[DMA_DEBUG_STACKTRACE_ENTRIES]; | 69 | unsigned long st_entries[DMA_DEBUG_STACKTRACE_ENTRIES]; |
@@ -114,6 +121,12 @@ static struct device_driver *current_driver __read_mostly; | |||
114 | 121 | ||
115 | static DEFINE_RWLOCK(driver_name_lock); | 122 | static DEFINE_RWLOCK(driver_name_lock); |
116 | 123 | ||
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 | |||
117 | static const char *type2name[4] = { "single", "page", | 130 | static const char *type2name[4] = { "single", "page", |
118 | "scather-gather", "coherent" }; | 131 | "scather-gather", "coherent" }; |
119 | 132 | ||
@@ -376,11 +389,12 @@ void debug_dma_dump_mappings(struct device *dev) | |||
376 | list_for_each_entry(entry, &bucket->list, list) { | 389 | list_for_each_entry(entry, &bucket->list, list) { |
377 | if (!dev || dev == entry->dev) { | 390 | if (!dev || dev == entry->dev) { |
378 | dev_info(entry->dev, | 391 | 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", |
380 | type2name[entry->type], idx, | 393 | type2name[entry->type], idx, |
381 | (unsigned long long)entry->paddr, | 394 | (unsigned long long)entry->paddr, |
382 | entry->dev_addr, entry->size, | 395 | entry->dev_addr, entry->size, |
383 | dir2name[entry->direction]); | 396 | dir2name[entry->direction], |
397 | maperr2str[entry->map_err_type]); | ||
384 | } | 398 | } |
385 | } | 399 | } |
386 | 400 | ||
@@ -844,16 +858,16 @@ static void check_unmap(struct dma_debug_entry *ref) | |||
844 | struct hash_bucket *bucket; | 858 | struct hash_bucket *bucket; |
845 | unsigned long flags; | 859 | unsigned long flags; |
846 | 860 | ||
847 | if (dma_mapping_error(ref->dev, ref->dev_addr)) { | ||
848 | err_printk(ref->dev, NULL, "DMA-API: device driver tries " | ||
849 | "to free an invalid DMA memory address\n"); | ||
850 | return; | ||
851 | } | ||
852 | |||
853 | bucket = get_hash_bucket(ref, &flags); | 861 | bucket = get_hash_bucket(ref, &flags); |
854 | entry = bucket_find_exact(bucket, ref); | 862 | entry = bucket_find_exact(bucket, ref); |
855 | 863 | ||
856 | if (!entry) { | 864 | if (!entry) { |
865 | if (dma_mapping_error(ref->dev, ref->dev_addr)) { | ||
866 | err_printk(ref->dev, NULL, | ||
867 | "DMA-API: device driver tries " | ||
868 | "to free an invalid DMA memory address\n"); | ||
869 | return; | ||
870 | } | ||
857 | err_printk(ref->dev, NULL, "DMA-API: device driver tries " | 871 | err_printk(ref->dev, NULL, "DMA-API: device driver tries " |
858 | "to free DMA memory it has not allocated " | 872 | "to free DMA memory it has not allocated " |
859 | "[device address=0x%016llx] [size=%llu bytes]\n", | 873 | "[device address=0x%016llx] [size=%llu bytes]\n", |
@@ -910,6 +924,15 @@ static void check_unmap(struct dma_debug_entry *ref) | |||
910 | dir2name[ref->direction]); | 924 | dir2name[ref->direction]); |
911 | } | 925 | } |
912 | 926 | ||
927 | if (entry->map_err_type == MAP_ERR_NOT_CHECKED) { | ||
928 | err_printk(ref->dev, entry, | ||
929 | "DMA-API: device driver failed to check map error" | ||
930 | "[device address=0x%016llx] [size=%llu bytes] " | ||
931 | "[mapped as %s]", | ||
932 | ref->dev_addr, ref->size, | ||
933 | type2name[entry->type]); | ||
934 | } | ||
935 | |||
913 | hash_bucket_del(entry); | 936 | hash_bucket_del(entry); |
914 | dma_entry_free(entry); | 937 | dma_entry_free(entry); |
915 | 938 | ||
@@ -1017,7 +1040,7 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset, | |||
1017 | if (unlikely(global_disable)) | 1040 | if (unlikely(global_disable)) |
1018 | return; | 1041 | return; |
1019 | 1042 | ||
1020 | if (unlikely(dma_mapping_error(dev, dma_addr))) | 1043 | if (dma_mapping_error(dev, dma_addr)) |
1021 | return; | 1044 | return; |
1022 | 1045 | ||
1023 | entry = dma_entry_alloc(); | 1046 | entry = dma_entry_alloc(); |
@@ -1030,6 +1053,7 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset, | |||
1030 | entry->dev_addr = dma_addr; | 1053 | entry->dev_addr = dma_addr; |
1031 | entry->size = size; | 1054 | entry->size = size; |
1032 | entry->direction = direction; | 1055 | entry->direction = direction; |
1056 | entry->map_err_type = MAP_ERR_NOT_CHECKED; | ||
1033 | 1057 | ||
1034 | if (map_single) | 1058 | if (map_single) |
1035 | entry->type = dma_debug_single; | 1059 | entry->type = dma_debug_single; |
@@ -1045,6 +1069,30 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset, | |||
1045 | } | 1069 | } |
1046 | EXPORT_SYMBOL(debug_dma_map_page); | 1070 | EXPORT_SYMBOL(debug_dma_map_page); |
1047 | 1071 | ||
1072 | void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr) | ||
1073 | { | ||
1074 | struct dma_debug_entry ref; | ||
1075 | struct dma_debug_entry *entry; | ||
1076 | struct hash_bucket *bucket; | ||
1077 | unsigned long flags; | ||
1078 | |||
1079 | if (unlikely(global_disable)) | ||
1080 | return; | ||
1081 | |||
1082 | ref.dev = dev; | ||
1083 | ref.dev_addr = dma_addr; | ||
1084 | bucket = get_hash_bucket(&ref, &flags); | ||
1085 | entry = bucket_find_exact(bucket, &ref); | ||
1086 | |||
1087 | if (!entry) | ||
1088 | goto out; | ||
1089 | |||
1090 | entry->map_err_type = MAP_ERR_CHECKED; | ||
1091 | out: | ||
1092 | put_hash_bucket(bucket, &flags); | ||
1093 | } | ||
1094 | EXPORT_SYMBOL(debug_dma_mapping_error); | ||
1095 | |||
1048 | void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, | 1096 | void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, |
1049 | size_t size, int direction, bool map_single) | 1097 | size_t size, int direction, bool map_single) |
1050 | { | 1098 | { |