diff --git a/[refs] b/[refs] index c058ada54cea..58dac4b904a6 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: a0157573041403e7507a6f3f32279fc14ff5c02e +refs/heads/master: eb9c95271eafb62f7024547016ad00636c1425c1 diff --git a/trunk/Documentation/DMA-API-HOWTO.txt b/trunk/Documentation/DMA-API-HOWTO.txt index 4a4fb295ceef..a0b6250add79 100644 --- a/trunk/Documentation/DMA-API-HOWTO.txt +++ b/trunk/Documentation/DMA-API-HOWTO.txt @@ -468,46 +468,11 @@ To map a single region, you do: size_t size = buffer->len; dma_handle = dma_map_single(dev, addr, size, direction); - if (dma_mapping_error(dma_handle)) { - /* - * reduce current DMA mapping usage, - * delay and try again later or - * reset driver. - */ - goto map_error_handling; - } and to unmap it: dma_unmap_single(dev, dma_handle, size, direction); -You should call dma_mapping_error() as dma_map_single() could fail and return -error. Not all dma implementations support dma_mapping_error() interface. -However, it is a good practice to call dma_mapping_error() interface, which -will invoke the generic mapping error check interface. Doing so will ensure -that the mapping code will work correctly on all dma implementations without -any dependency on the specifics of the underlying implementation. Using the -returned address without checking for errors could result in failures ranging -from panics to silent data corruption. Couple of example of incorrect ways to -check for errors that make assumptions about the underlying dma implementation -are as follows and these are applicable to dma_map_page() as well. - -Incorrect example 1: - dma_addr_t dma_handle; - - dma_handle = dma_map_single(dev, addr, size, direction); - if ((dma_handle & 0xffff != 0) || (dma_handle >= 0x1000000)) { - goto map_error; - } - -Incorrect example 2: - dma_addr_t dma_handle; - - dma_handle = dma_map_single(dev, addr, size, direction); - if (dma_handle == DMA_ERROR_CODE) { - goto map_error; - } - You should call dma_unmap_single when the DMA activity is finished, e.g. from the interrupt which told you that the DMA transfer is done. @@ -524,14 +489,6 @@ Specifically: size_t size = buffer->len; dma_handle = dma_map_page(dev, page, offset, size, direction); - if (dma_mapping_error(dma_handle)) { - /* - * reduce current DMA mapping usage, - * delay and try again later or - * reset driver. - */ - goto map_error_handling; - } ... @@ -539,12 +496,6 @@ Specifically: Here, "offset" means byte offset within the given page. -You should call dma_mapping_error() as dma_map_page() could fail and return -error as outlined under the dma_map_single() discussion. - -You should call dma_unmap_page when the DMA activity is finished, e.g. -from the interrupt which told you that the DMA transfer is done. - With scatterlists, you map a region gathered from several regions by: int i, count = dma_map_sg(dev, sglist, nents, direction); @@ -627,14 +578,6 @@ to use the dma_sync_*() interfaces. dma_addr_t mapping; mapping = dma_map_single(cp->dev, buffer, len, DMA_FROM_DEVICE); - if (dma_mapping_error(dma_handle)) { - /* - * reduce current DMA mapping usage, - * delay and try again later or - * reset driver. - */ - goto map_error_handling; - } cp->rx_buf = buffer; cp->rx_len = len; @@ -715,75 +658,6 @@ failure can be determined by: * delay and try again later or * reset driver. */ - goto map_error_handling; - } - -- unmap pages that are already mapped, when mapping error occurs in the middle - of a multiple page mapping attempt. These example are applicable to - dma_map_page() as well. - -Example 1: - dma_addr_t dma_handle1; - dma_addr_t dma_handle2; - - dma_handle1 = dma_map_single(dev, addr, size, direction); - if (dma_mapping_error(dev, dma_handle1)) { - /* - * reduce current DMA mapping usage, - * delay and try again later or - * reset driver. - */ - goto map_error_handling1; - } - dma_handle2 = dma_map_single(dev, addr, size, direction); - if (dma_mapping_error(dev, dma_handle2)) { - /* - * reduce current DMA mapping usage, - * delay and try again later or - * reset driver. - */ - goto map_error_handling2; - } - - ... - - map_error_handling2: - dma_unmap_single(dma_handle1); - map_error_handling1: - -Example 2: (if buffers are allocated a loop, unmap all mapped buffers when - mapping error is detected in the middle) - - dma_addr_t dma_addr; - dma_addr_t array[DMA_BUFFERS]; - int save_index = 0; - - for (i = 0; i < DMA_BUFFERS; i++) { - - ... - - dma_addr = dma_map_single(dev, addr, size, direction); - if (dma_mapping_error(dev, dma_addr)) { - /* - * reduce current DMA mapping usage, - * delay and try again later or - * reset driver. - */ - goto map_error_handling; - } - array[i].dma_addr = dma_addr; - save_index++; - } - - ... - - map_error_handling: - - for (i = 0; i < save_index; i++) { - - ... - - dma_unmap_single(array[i].dma_addr); } Networking drivers must call dev_kfree_skb to free the socket buffer diff --git a/trunk/Documentation/DMA-API.txt b/trunk/Documentation/DMA-API.txt index 78a6c569d204..66bd97a95f10 100644 --- a/trunk/Documentation/DMA-API.txt +++ b/trunk/Documentation/DMA-API.txt @@ -678,15 +678,3 @@ out of dma_debug_entries. These entries are preallocated at boot. The number of preallocated entries is defined per architecture. If it is too low for you boot with 'dma_debug_entries=' to overwrite the architectural default. - -void debug_dmap_mapping_error(struct device *dev, dma_addr_t dma_addr); - -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. - diff --git a/trunk/arch/arm/include/asm/dma-mapping.h b/trunk/arch/arm/include/asm/dma-mapping.h index 78d8e9b5544f..23004847bb05 100644 --- a/trunk/arch/arm/include/asm/dma-mapping.h +++ b/trunk/arch/arm/include/asm/dma-mapping.h @@ -91,7 +91,6 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr) */ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { - debug_dma_mapping_error(dev, dma_addr); return dma_addr == DMA_ERROR_CODE; } diff --git a/trunk/arch/arm64/include/asm/dma-mapping.h b/trunk/arch/arm64/include/asm/dma-mapping.h index 994776894198..538f4b44db5d 100644 --- a/trunk/arch/arm64/include/asm/dma-mapping.h +++ b/trunk/arch/arm64/include/asm/dma-mapping.h @@ -50,7 +50,6 @@ static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr) static inline int dma_mapping_error(struct device *dev, dma_addr_t dev_addr) { struct dma_map_ops *ops = get_dma_ops(dev); - debug_dma_mapping_error(dev, dev_addr); return ops->mapping_error(dev, dev_addr); } diff --git a/trunk/arch/c6x/include/asm/dma-mapping.h b/trunk/arch/c6x/include/asm/dma-mapping.h index 3c694065030f..03579fd99dba 100644 --- a/trunk/arch/c6x/include/asm/dma-mapping.h +++ b/trunk/arch/c6x/include/asm/dma-mapping.h @@ -32,7 +32,6 @@ static inline int dma_set_mask(struct device *dev, u64 dma_mask) */ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { - debug_dma_mapping_error(dev, dma_addr); return dma_addr == ~0; } diff --git a/trunk/arch/ia64/include/asm/dma-mapping.h b/trunk/arch/ia64/include/asm/dma-mapping.h index cf3ab7e784b5..4f5e8148440d 100644 --- a/trunk/arch/ia64/include/asm/dma-mapping.h +++ b/trunk/arch/ia64/include/asm/dma-mapping.h @@ -58,7 +58,6 @@ static inline void dma_free_attrs(struct device *dev, size_t size, static inline int dma_mapping_error(struct device *dev, dma_addr_t daddr) { struct dma_map_ops *ops = platform_dma_get_ops(dev); - debug_dma_mapping_error(dev, daddr); return ops->mapping_error(dev, daddr); } diff --git a/trunk/arch/microblaze/include/asm/dma-mapping.h b/trunk/arch/microblaze/include/asm/dma-mapping.h index 46460f1c49c4..01d228286cb0 100644 --- a/trunk/arch/microblaze/include/asm/dma-mapping.h +++ b/trunk/arch/microblaze/include/asm/dma-mapping.h @@ -114,8 +114,6 @@ static inline void __dma_sync(unsigned long paddr, static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { struct dma_map_ops *ops = get_dma_ops(dev); - - debug_dma_mapping_error(dev, dma_addr); if (ops->mapping_error) return ops->mapping_error(dev, dma_addr); diff --git a/trunk/arch/mips/include/asm/dma-mapping.h b/trunk/arch/mips/include/asm/dma-mapping.h index 006b43e38a9c..be39a12901c6 100644 --- a/trunk/arch/mips/include/asm/dma-mapping.h +++ b/trunk/arch/mips/include/asm/dma-mapping.h @@ -40,8 +40,6 @@ static inline int dma_supported(struct device *dev, u64 mask) static inline int dma_mapping_error(struct device *dev, u64 mask) { struct dma_map_ops *ops = get_dma_ops(dev); - - debug_dma_mapping_error(dev, mask); return ops->mapping_error(dev, mask); } diff --git a/trunk/arch/powerpc/include/asm/dma-mapping.h b/trunk/arch/powerpc/include/asm/dma-mapping.h index e27e9ad6818e..78160874809a 100644 --- a/trunk/arch/powerpc/include/asm/dma-mapping.h +++ b/trunk/arch/powerpc/include/asm/dma-mapping.h @@ -172,7 +172,6 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { struct dma_map_ops *dma_ops = get_dma_ops(dev); - debug_dma_mapping_error(dev, dma_addr); if (dma_ops->mapping_error) return dma_ops->mapping_error(dev, dma_addr); diff --git a/trunk/arch/sh/include/asm/dma-mapping.h b/trunk/arch/sh/include/asm/dma-mapping.h index b437f2c780b8..8bd965e00a15 100644 --- a/trunk/arch/sh/include/asm/dma-mapping.h +++ b/trunk/arch/sh/include/asm/dma-mapping.h @@ -46,7 +46,6 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { struct dma_map_ops *ops = get_dma_ops(dev); - debug_dma_mapping_error(dev, dma_addr); if (ops->mapping_error) return ops->mapping_error(dev, dma_addr); diff --git a/trunk/arch/sparc/include/asm/dma-mapping.h b/trunk/arch/sparc/include/asm/dma-mapping.h index 05fe53f5346e..8493fd3c7ba5 100644 --- a/trunk/arch/sparc/include/asm/dma-mapping.h +++ b/trunk/arch/sparc/include/asm/dma-mapping.h @@ -59,7 +59,6 @@ static inline void dma_free_attrs(struct device *dev, size_t size, static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { - debug_dma_mapping_error(dev, dma_addr); return (dma_addr == DMA_ERROR_CODE); } diff --git a/trunk/arch/tile/include/asm/dma-mapping.h b/trunk/arch/tile/include/asm/dma-mapping.h index f2ff191376b4..4b6247d1a315 100644 --- a/trunk/arch/tile/include/asm/dma-mapping.h +++ b/trunk/arch/tile/include/asm/dma-mapping.h @@ -72,7 +72,6 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { - debug_dma_mapping_error(dev, dma_addr); return get_dma_ops(dev)->mapping_error(dev, dma_addr); } diff --git a/trunk/arch/x86/include/asm/dma-mapping.h b/trunk/arch/x86/include/asm/dma-mapping.h index 808dae63eeea..f7b4c7903e7e 100644 --- a/trunk/arch/x86/include/asm/dma-mapping.h +++ b/trunk/arch/x86/include/asm/dma-mapping.h @@ -47,7 +47,6 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { struct dma_map_ops *ops = get_dma_ops(dev); - debug_dma_mapping_error(dev, dma_addr); if (ops->mapping_error) return ops->mapping_error(dev, dma_addr); diff --git a/trunk/drivers/iommu/amd_iommu.c b/trunk/drivers/iommu/amd_iommu.c index 55074cba20eb..b65b377815ac 100644 --- a/trunk/drivers/iommu/amd_iommu.c +++ b/trunk/drivers/iommu/amd_iommu.c @@ -276,39 +276,32 @@ static void swap_pci_ref(struct pci_dev **from, struct pci_dev *to) #define REQ_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF) -static int iommu_init_device(struct device *dev) +static int init_iommu_group(struct device *dev) { - struct pci_dev *dma_pdev = NULL, *pdev = to_pci_dev(dev); struct iommu_dev_data *dev_data; struct iommu_group *group; - u16 alias; + struct pci_dev *dma_pdev = NULL; int ret; - if (dev->archdata.iommu) + group = iommu_group_get(dev); + if (group) { + iommu_group_put(group); return 0; + } dev_data = find_dev_data(get_device_id(dev)); if (!dev_data) return -ENOMEM; - alias = amd_iommu_alias_table[dev_data->devid]; - if (alias != dev_data->devid) { - struct iommu_dev_data *alias_data; - - alias_data = find_dev_data(alias); - if (alias_data == NULL) { - pr_err("AMD-Vi: Warning: Unhandled device %s\n", - dev_name(dev)); - free_dev_data(dev_data); - return -ENOTSUPP; - } - dev_data->alias_data = alias_data; + if (dev_data->alias_data) { + u16 alias; + alias = amd_iommu_alias_table[dev_data->devid]; dma_pdev = pci_get_bus_and_slot(alias >> 8, alias & 0xff); } - if (dma_pdev == NULL) - dma_pdev = pci_dev_get(pdev); + if (!dma_pdev) + dma_pdev = pci_dev_get(to_pci_dev(dev)); /* Account for quirked devices */ swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev)); @@ -358,6 +351,38 @@ static int iommu_init_device(struct device *dev) iommu_group_put(group); + return ret; +} + +static int iommu_init_device(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct iommu_dev_data *dev_data; + u16 alias; + int ret; + + if (dev->archdata.iommu) + return 0; + + dev_data = find_dev_data(get_device_id(dev)); + if (!dev_data) + return -ENOMEM; + + alias = amd_iommu_alias_table[dev_data->devid]; + if (alias != dev_data->devid) { + struct iommu_dev_data *alias_data; + + alias_data = find_dev_data(alias); + if (alias_data == NULL) { + pr_err("AMD-Vi: Warning: Unhandled device %s\n", + dev_name(dev)); + free_dev_data(dev_data); + return -ENOTSUPP; + } + dev_data->alias_data = alias_data; + } + + ret = init_iommu_group(dev); if (ret) return ret; diff --git a/trunk/include/linux/dma-debug.h b/trunk/include/linux/dma-debug.h index fc0e34ce038f..171ad8aedc83 100644 --- a/trunk/include/linux/dma-debug.h +++ b/trunk/include/linux/dma-debug.h @@ -39,8 +39,6 @@ extern void debug_dma_map_page(struct device *dev, struct page *page, int direction, dma_addr_t dma_addr, bool map_single); -extern void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr); - extern void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, size_t size, int direction, bool map_single); @@ -107,11 +105,6 @@ static inline void debug_dma_map_page(struct device *dev, struct page *page, { } -static inline void debug_dma_mapping_error(struct device *dev, - dma_addr_t dma_addr) -{ -} - static inline void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, size_t size, int direction, bool map_single) diff --git a/trunk/lib/dma-debug.c b/trunk/lib/dma-debug.c index 5e396accd3d0..d84beb994f36 100644 --- a/trunk/lib/dma-debug.c +++ b/trunk/lib/dma-debug.c @@ -45,12 +45,6 @@ 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 { @@ -63,7 +57,6 @@ 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]; @@ -121,12 +114,6 @@ 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" }; @@ -389,12 +376,11 @@ 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 %s\n", + "%s idx %d P=%Lx D=%Lx L=%Lx %s\n", type2name[entry->type], idx, (unsigned long long)entry->paddr, entry->dev_addr, entry->size, - dir2name[entry->direction], - maperr2str[entry->map_err_type]); + dir2name[entry->direction]); } } @@ -858,16 +844,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", @@ -924,15 +910,6 @@ 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); @@ -1040,7 +1017,7 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset, if (unlikely(global_disable)) return; - if (dma_mapping_error(dev, dma_addr)) + if (unlikely(dma_mapping_error(dev, dma_addr))) return; entry = dma_entry_alloc(); @@ -1053,7 +1030,6 @@ 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; @@ -1069,30 +1045,6 @@ 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) {