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 ...
这个提交包含在:
@@ -45,6 +45,12 @@ enum {
|
||||
dma_debug_coherent,
|
||||
};
|
||||
|
||||
enum map_err_types {
|
||||
MAP_ERR_CHECK_NOT_APPLICABLE,
|
||||
MAP_ERR_NOT_CHECKED,
|
||||
MAP_ERR_CHECKED,
|
||||
};
|
||||
|
||||
#define DMA_DEBUG_STACKTRACE_ENTRIES 5
|
||||
|
||||
struct dma_debug_entry {
|
||||
@@ -57,6 +63,7 @@ struct dma_debug_entry {
|
||||
int direction;
|
||||
int sg_call_ents;
|
||||
int sg_mapped_ents;
|
||||
enum map_err_types map_err_type;
|
||||
#ifdef CONFIG_STACKTRACE
|
||||
struct stack_trace stacktrace;
|
||||
unsigned long st_entries[DMA_DEBUG_STACKTRACE_ENTRIES];
|
||||
@@ -114,6 +121,12 @@ static struct device_driver *current_driver __read_mostly;
|
||||
|
||||
static DEFINE_RWLOCK(driver_name_lock);
|
||||
|
||||
static const char *const maperr2str[] = {
|
||||
[MAP_ERR_CHECK_NOT_APPLICABLE] = "dma map error check not applicable",
|
||||
[MAP_ERR_NOT_CHECKED] = "dma map error not checked",
|
||||
[MAP_ERR_CHECKED] = "dma map error checked",
|
||||
};
|
||||
|
||||
static const char *type2name[4] = { "single", "page",
|
||||
"scather-gather", "coherent" };
|
||||
|
||||
@@ -376,11 +389,12 @@ void debug_dma_dump_mappings(struct device *dev)
|
||||
list_for_each_entry(entry, &bucket->list, list) {
|
||||
if (!dev || dev == entry->dev) {
|
||||
dev_info(entry->dev,
|
||||
"%s idx %d P=%Lx D=%Lx L=%Lx %s\n",
|
||||
"%s idx %d P=%Lx D=%Lx L=%Lx %s %s\n",
|
||||
type2name[entry->type], idx,
|
||||
(unsigned long long)entry->paddr,
|
||||
entry->dev_addr, entry->size,
|
||||
dir2name[entry->direction]);
|
||||
dir2name[entry->direction],
|
||||
maperr2str[entry->map_err_type]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -844,16 +858,16 @@ static void check_unmap(struct dma_debug_entry *ref)
|
||||
struct hash_bucket *bucket;
|
||||
unsigned long flags;
|
||||
|
||||
if (dma_mapping_error(ref->dev, ref->dev_addr)) {
|
||||
err_printk(ref->dev, NULL, "DMA-API: device driver tries "
|
||||
"to free an invalid DMA memory address\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bucket = get_hash_bucket(ref, &flags);
|
||||
entry = bucket_find_exact(bucket, ref);
|
||||
|
||||
if (!entry) {
|
||||
if (dma_mapping_error(ref->dev, ref->dev_addr)) {
|
||||
err_printk(ref->dev, NULL,
|
||||
"DMA-API: device driver tries "
|
||||
"to free an invalid DMA memory address\n");
|
||||
return;
|
||||
}
|
||||
err_printk(ref->dev, NULL, "DMA-API: device driver tries "
|
||||
"to free DMA memory it has not allocated "
|
||||
"[device address=0x%016llx] [size=%llu bytes]\n",
|
||||
@@ -910,6 +924,15 @@ static void check_unmap(struct dma_debug_entry *ref)
|
||||
dir2name[ref->direction]);
|
||||
}
|
||||
|
||||
if (entry->map_err_type == MAP_ERR_NOT_CHECKED) {
|
||||
err_printk(ref->dev, entry,
|
||||
"DMA-API: device driver failed to check map error"
|
||||
"[device address=0x%016llx] [size=%llu bytes] "
|
||||
"[mapped as %s]",
|
||||
ref->dev_addr, ref->size,
|
||||
type2name[entry->type]);
|
||||
}
|
||||
|
||||
hash_bucket_del(entry);
|
||||
dma_entry_free(entry);
|
||||
|
||||
@@ -1017,7 +1040,7 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
|
||||
if (unlikely(global_disable))
|
||||
return;
|
||||
|
||||
if (unlikely(dma_mapping_error(dev, dma_addr)))
|
||||
if (dma_mapping_error(dev, dma_addr))
|
||||
return;
|
||||
|
||||
entry = dma_entry_alloc();
|
||||
@@ -1030,6 +1053,7 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
|
||||
entry->dev_addr = dma_addr;
|
||||
entry->size = size;
|
||||
entry->direction = direction;
|
||||
entry->map_err_type = MAP_ERR_NOT_CHECKED;
|
||||
|
||||
if (map_single)
|
||||
entry->type = dma_debug_single;
|
||||
@@ -1045,6 +1069,30 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
|
||||
}
|
||||
EXPORT_SYMBOL(debug_dma_map_page);
|
||||
|
||||
void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
|
||||
{
|
||||
struct dma_debug_entry ref;
|
||||
struct dma_debug_entry *entry;
|
||||
struct hash_bucket *bucket;
|
||||
unsigned long flags;
|
||||
|
||||
if (unlikely(global_disable))
|
||||
return;
|
||||
|
||||
ref.dev = dev;
|
||||
ref.dev_addr = dma_addr;
|
||||
bucket = get_hash_bucket(&ref, &flags);
|
||||
entry = bucket_find_exact(bucket, &ref);
|
||||
|
||||
if (!entry)
|
||||
goto out;
|
||||
|
||||
entry->map_err_type = MAP_ERR_CHECKED;
|
||||
out:
|
||||
put_hash_bucket(bucket, &flags);
|
||||
}
|
||||
EXPORT_SYMBOL(debug_dma_mapping_error);
|
||||
|
||||
void debug_dma_unmap_page(struct device *dev, dma_addr_t addr,
|
||||
size_t size, int direction, bool map_single)
|
||||
{
|
||||
|
在新工单中引用
屏蔽一个用户