Loading arch/arm/common/dmabounce.c +83 −110 Original line number Diff line number Diff line Loading @@ -79,6 +79,8 @@ struct dmabounce_device_info { struct dmabounce_pool large; rwlock_t lock; int (*needs_bounce)(struct device *, dma_addr_t, size_t); }; #ifdef STATS Loading Loading @@ -210,90 +212,71 @@ static struct safe_buffer *find_safe_buffer_dev(struct device *dev, if (!dev || !dev->archdata.dmabounce) return NULL; if (dma_mapping_error(dev, dma_addr)) { if (dev) dev_err(dev, "Trying to %s invalid mapping\n", where); else pr_err("unknown device: Trying to %s invalid mapping\n", where); return NULL; } return find_safe_buffer(dev->archdata.dmabounce, dma_addr); } static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size, enum dma_data_direction dir) static int needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) { struct dmabounce_device_info *device_info = dev->archdata.dmabounce; dma_addr_t dma_addr; int needs_bounce = 0; if (device_info) DO_STATS ( device_info->map_op_count++ ); dma_addr = virt_to_dma(dev, ptr); if (!dev || !dev->archdata.dmabounce) return 0; if (dev->dma_mask) { unsigned long mask = *dev->dma_mask; unsigned long limit; unsigned long limit, mask = *dev->dma_mask; limit = (mask + 1) & ~mask; if (limit && size > limit) { dev_err(dev, "DMA mapping too big (requested %#x " "mask %#Lx)\n", size, *dev->dma_mask); return ~0; return -E2BIG; } /* * Figure out if we need to bounce from the DMA mask. */ needs_bounce = (dma_addr | (dma_addr + size - 1)) & ~mask; /* Figure out if we need to bounce from the DMA mask. */ if ((dma_addr | (dma_addr + size - 1)) & ~mask) return 1; } return !!dev->archdata.dmabounce->needs_bounce(dev, dma_addr, size); } if (device_info && (needs_bounce || dma_needs_bounce(dev, dma_addr, size))) { static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size, enum dma_data_direction dir) { struct dmabounce_device_info *device_info = dev->archdata.dmabounce; struct safe_buffer *buf; if (device_info) DO_STATS ( device_info->map_op_count++ ); buf = alloc_safe_buffer(device_info, ptr, size, dir); if (buf == 0) { if (buf == NULL) { dev_err(dev, "%s: unable to map unsafe buffer %p!\n", __func__, ptr); return ~0; } dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", __func__, buf->ptr, virt_to_dma(dev, buf->ptr), buf->safe, buf->safe_dma_addr); if ((dir == DMA_TO_DEVICE) || (dir == DMA_BIDIRECTIONAL)) { if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) { dev_dbg(dev, "%s: copy unsafe %p to safe %p, size %d\n", __func__, ptr, buf->safe, size); memcpy(buf->safe, ptr, size); } ptr = buf->safe; dma_addr = buf->safe_dma_addr; } else { /* * We don't need to sync the DMA buffer since * it was allocated via the coherent allocators. */ __dma_single_cpu_to_dev(ptr, size, dir); } return dma_addr; return buf->safe_dma_addr; } static inline void unmap_single(struct device *dev, dma_addr_t dma_addr, static inline void unmap_single(struct device *dev, struct safe_buffer *buf, size_t size, enum dma_data_direction dir) { struct safe_buffer *buf = find_safe_buffer_dev(dev, dma_addr, "unmap"); if (buf) { BUG_ON(buf->size != size); BUG_ON(buf->direction != dir); dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", __func__, buf->ptr, virt_to_dma(dev, buf->ptr), buf->safe, buf->safe_dma_addr); Loading @@ -302,8 +285,7 @@ static inline void unmap_single(struct device *dev, dma_addr_t dma_addr, if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) { void *ptr = buf->ptr; dev_dbg(dev, "%s: copy back safe %p to unsafe %p size %d\n", dev_dbg(dev, "%s: copy back safe %p to unsafe %p size %d\n", __func__, buf->safe, ptr, size); memcpy(ptr, buf->safe, size); Loading @@ -315,9 +297,6 @@ static inline void unmap_single(struct device *dev, dma_addr_t dma_addr, __cpuc_flush_dcache_area(ptr, size); } free_safe_buffer(dev->archdata.dmabounce, buf); } else { __dma_single_dev_to_cpu(dma_to_virt(dev, dma_addr), size, dir); } } /* ************************************************** */ Loading @@ -328,45 +307,28 @@ static inline void unmap_single(struct device *dev, dma_addr_t dma_addr, * substitute the safe buffer for the unsafe one. * (basically move the buffer from an unsafe area to a safe one) */ dma_addr_t __dma_map_single(struct device *dev, void *ptr, size_t size, enum dma_data_direction dir) { dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", __func__, ptr, size, dir); BUG_ON(!valid_dma_direction(dir)); return map_single(dev, ptr, size, dir); } EXPORT_SYMBOL(__dma_map_single); /* * see if a mapped address was really a "safe" buffer and if so, copy * the data from the safe buffer back to the unsafe buffer and free up * the safe buffer. (basically return things back to the way they * should be) */ void __dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction dir) { dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", __func__, (void *) dma_addr, size, dir); unmap_single(dev, dma_addr, size, dir); } EXPORT_SYMBOL(__dma_unmap_single); dma_addr_t __dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction dir) { dma_addr_t dma_addr; int ret; dev_dbg(dev, "%s(page=%p,off=%#lx,size=%zx,dir=%x)\n", __func__, page, offset, size, dir); BUG_ON(!valid_dma_direction(dir)); dma_addr = pfn_to_dma(dev, page_to_pfn(page)) + offset; ret = needs_bounce(dev, dma_addr, size); if (ret < 0) return ~0; if (ret == 0) { __dma_page_cpu_to_dev(page, offset, size, dir); return dma_addr; } if (PageHighMem(page)) { dev_err(dev, "DMA buffer bouncing of HIGHMEM pages " "is not supported\n"); dev_err(dev, "DMA buffer bouncing of HIGHMEM pages is not supported\n"); return ~0; } Loading @@ -383,10 +345,19 @@ EXPORT_SYMBOL(__dma_map_page); void __dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction dir) { dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", __func__, (void *) dma_addr, size, dir); struct safe_buffer *buf; dev_dbg(dev, "%s(dma=%#x,size=%d,dir=%x)\n", __func__, dma_addr, size, dir); buf = find_safe_buffer_dev(dev, dma_addr, __func__); if (!buf) { __dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, dma_addr)), dma_addr & ~PAGE_MASK, size, dir); return; } unmap_single(dev, dma_addr, size, dir); unmap_single(dev, buf, size, dir); } EXPORT_SYMBOL(__dma_unmap_page); Loading Loading @@ -461,7 +432,8 @@ static int dmabounce_init_pool(struct dmabounce_pool *pool, struct device *dev, } int dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, unsigned long large_buffer_size) unsigned long large_buffer_size, int (*needs_bounce_fn)(struct device *, dma_addr_t, size_t)) { struct dmabounce_device_info *device_info; int ret; Loading Loading @@ -497,6 +469,7 @@ int dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, device_info->dev = dev; INIT_LIST_HEAD(&device_info->safe_buffers); rwlock_init(&device_info->lock); device_info->needs_bounce = needs_bounce_fn; #ifdef STATS device_info->total_allocs = 0; Loading arch/arm/common/it8152.c +7 −9 Original line number Diff line number Diff line Loading @@ -243,6 +243,12 @@ static struct resource it8152_mem = { * ITE8152 chip can address up to 64MByte, so all the devices * connected to ITE8152 (PCI and USB) should have limited DMA window */ static int it8152_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) { dev_dbg(dev, "%s: dma_addr %08x, size %08x\n", __func__, dma_addr, size); return (dma_addr + size - PHYS_OFFSET) >= SZ_64M; } /* * Setup DMA mask to 64MB on devices connected to ITE8152. Ignore all Loading @@ -254,7 +260,7 @@ static int it8152_pci_platform_notify(struct device *dev) if (dev->dma_mask) *dev->dma_mask = (SZ_64M - 1) | PHYS_OFFSET; dev->coherent_dma_mask = (SZ_64M - 1) | PHYS_OFFSET; dmabounce_register_dev(dev, 2048, 4096); dmabounce_register_dev(dev, 2048, 4096, it8152_needs_bounce); } return 0; } Loading @@ -267,14 +273,6 @@ static int it8152_pci_platform_notify_remove(struct device *dev) return 0; } int dma_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) { dev_dbg(dev, "%s: dma_addr %08x, size %08x\n", __func__, dma_addr, size); return (dev->bus == &pci_bus_type) && ((dma_addr + size - PHYS_OFFSET) >= SZ_64M); } int dma_set_coherent_mask(struct device *dev, u64 mask) { if (mask >= PHYS_OFFSET + SZ_64M - 1) Loading arch/arm/common/sa1111.c +31 −29 Original line number Diff line number Diff line Loading @@ -579,7 +579,36 @@ sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac, sachip->dev->coherent_dma_mask &= sa1111_dma_mask[drac >> 2]; } #endif #ifdef CONFIG_DMABOUNCE /* * According to the "Intel StrongARM SA-1111 Microprocessor Companion * Chip Specification Update" (June 2000), erratum #7, there is a * significant bug in the SA1111 SDRAM shared memory controller. If * an access to a region of memory above 1MB relative to the bank base, * it is important that address bit 10 _NOT_ be asserted. Depending * on the configuration of the RAM, bit 10 may correspond to one * of several different (processor-relative) address bits. * * This routine only identifies whether or not a given DMA address * is susceptible to the bug. * * This should only get called for sa1111_device types due to the * way we configure our device dma_masks. */ static int sa1111_needs_bounce(struct device *dev, dma_addr_t addr, size_t size) { /* * Section 4.6 of the "Intel StrongARM SA-1111 Development Module * User's Guide" mentions that jumpers R51 and R52 control the * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or * SDRAM bank 1 on Neponset). The default configuration selects * Assabet, so any address in bank 1 is necessarily invalid. */ return (machine_is_assabet() || machine_is_pfs168()) && (addr >= 0xc8000000 || (addr + size) >= 0xc8000000); } #endif static void sa1111_dev_release(struct device *_dev) Loading Loading @@ -644,7 +673,8 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, dev->dev.dma_mask = &dev->dma_mask; if (dev->dma_mask != 0xffffffffUL) { ret = dmabounce_register_dev(&dev->dev, 1024, 4096); ret = dmabounce_register_dev(&dev->dev, 1024, 4096, sa1111_needs_bounce); if (ret) { dev_err(&dev->dev, "SA1111: Failed to register" " with dmabounce\n"); Loading Loading @@ -818,34 +848,6 @@ static void __sa1111_remove(struct sa1111 *sachip) kfree(sachip); } /* * According to the "Intel StrongARM SA-1111 Microprocessor Companion * Chip Specification Update" (June 2000), erratum #7, there is a * significant bug in the SA1111 SDRAM shared memory controller. If * an access to a region of memory above 1MB relative to the bank base, * it is important that address bit 10 _NOT_ be asserted. Depending * on the configuration of the RAM, bit 10 may correspond to one * of several different (processor-relative) address bits. * * This routine only identifies whether or not a given DMA address * is susceptible to the bug. * * This should only get called for sa1111_device types due to the * way we configure our device dma_masks. */ int dma_needs_bounce(struct device *dev, dma_addr_t addr, size_t size) { /* * Section 4.6 of the "Intel StrongARM SA-1111 Development Module * User's Guide" mentions that jumpers R51 and R52 control the * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or * SDRAM bank 1 on Neponset). The default configuration selects * Assabet, so any address in bank 1 is necessarily invalid. */ return ((machine_is_assabet() || machine_is_pfs168()) && (addr >= 0xc8000000 || (addr + size) >= 0xc8000000)); } struct sa1111_save_data { unsigned int skcr; unsigned int skpcr; Loading arch/arm/include/asm/dma-mapping.h +13 −75 Original line number Diff line number Diff line Loading @@ -115,39 +115,8 @@ static inline void __dma_page_dev_to_cpu(struct page *page, unsigned long off, ___dma_page_dev_to_cpu(page, off, size, dir); } /* * Return whether the given device DMA address mask can be supported * properly. For example, if your device can only drive the low 24-bits * during bus mastering, then you would pass 0x00ffffff as the mask * to this function. * * FIXME: This should really be a platform specific issue - we should * return false if GFP_DMA allocations may not satisfy the supplied 'mask'. */ static inline int dma_supported(struct device *dev, u64 mask) { if (mask < ISA_DMA_THRESHOLD) return 0; return 1; } static inline int dma_set_mask(struct device *dev, u64 dma_mask) { #ifdef CONFIG_DMABOUNCE if (dev->archdata.dmabounce) { if (dma_mask >= ISA_DMA_THRESHOLD) return 0; else return -EIO; } #endif if (!dev->dma_mask || !dma_supported(dev, dma_mask)) return -EIO; *dev->dma_mask = dma_mask; return 0; } extern int dma_supported(struct device *, u64); extern int dma_set_mask(struct device *, u64); /* * DMA errors are defined by all-bits-set in the DMA address. Loading Loading @@ -256,14 +225,14 @@ int dma_mmap_writecombine(struct device *, struct vm_area_struct *, * @dev: valid struct device pointer * @small_buf_size: size of buffers to use with small buffer pool * @large_buf_size: size of buffers to use with large buffer pool (can be 0) * @needs_bounce_fn: called to determine whether buffer needs bouncing * * This function should be called by low-level platform code to register * a device as requireing DMA buffer bouncing. The function will allocate * appropriate DMA pools for the device. * */ extern int dmabounce_register_dev(struct device *, unsigned long, unsigned long); unsigned long, int (*)(struct device *, dma_addr_t, size_t)); /** * dmabounce_unregister_dev Loading @@ -277,31 +246,9 @@ extern int dmabounce_register_dev(struct device *, unsigned long, */ extern void dmabounce_unregister_dev(struct device *); /** * dma_needs_bounce * * @dev: valid struct device pointer * @dma_handle: dma_handle of unbounced buffer * @size: size of region being mapped * * Platforms that utilize the dmabounce mechanism must implement * this function. * * The dmabounce routines call this function whenever a dma-mapping * is requested to determine whether a given buffer needs to be bounced * or not. The function must return 0 if the buffer is OK for * DMA access and 1 if the buffer needs to be bounced. * */ extern int dma_needs_bounce(struct device*, dma_addr_t, size_t); /* * The DMA API, implemented by dmabounce.c. See below for descriptions. */ extern dma_addr_t __dma_map_single(struct device *, void *, size_t, enum dma_data_direction); extern void __dma_unmap_single(struct device *, dma_addr_t, size_t, enum dma_data_direction); extern dma_addr_t __dma_map_page(struct device *, struct page *, unsigned long, size_t, enum dma_data_direction); extern void __dma_unmap_page(struct device *, dma_addr_t, size_t, Loading @@ -328,13 +275,6 @@ static inline int dmabounce_sync_for_device(struct device *d, dma_addr_t addr, } static inline dma_addr_t __dma_map_single(struct device *dev, void *cpu_addr, size_t size, enum dma_data_direction dir) { __dma_single_cpu_to_dev(cpu_addr, size, dir); return virt_to_dma(dev, cpu_addr); } static inline dma_addr_t __dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction dir) { Loading @@ -342,12 +282,6 @@ static inline dma_addr_t __dma_map_page(struct device *dev, struct page *page, return pfn_to_dma(dev, page_to_pfn(page)) + offset; } static inline void __dma_unmap_single(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir) { __dma_single_dev_to_cpu(dma_to_virt(dev, handle), size, dir); } static inline void __dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir) { Loading @@ -373,14 +307,18 @@ static inline void __dma_unmap_page(struct device *dev, dma_addr_t handle, static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size, enum dma_data_direction dir) { unsigned long offset; struct page *page; dma_addr_t addr; BUG_ON(!virt_addr_valid(cpu_addr)); BUG_ON(!virt_addr_valid(cpu_addr + size - 1)); BUG_ON(!valid_dma_direction(dir)); addr = __dma_map_single(dev, cpu_addr, size, dir); debug_dma_map_page(dev, virt_to_page(cpu_addr), (unsigned long)cpu_addr & ~PAGE_MASK, size, dir, addr, true); page = virt_to_page(cpu_addr); offset = (unsigned long)cpu_addr & ~PAGE_MASK; addr = __dma_map_page(dev, page, offset, size, dir); debug_dma_map_page(dev, page, offset, size, dir, addr, true); return addr; } Loading Loading @@ -430,7 +368,7 @@ static inline void dma_unmap_single(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir) { debug_dma_unmap_page(dev, handle, size, dir, true); __dma_unmap_single(dev, handle, size, dir); __dma_unmap_page(dev, handle, size, dir); } /** Loading arch/arm/include/asm/dma.h +6 −5 Original line number Diff line number Diff line #ifndef __ASM_ARM_DMA_H #define __ASM_ARM_DMA_H #include <asm/memory.h> /* * This is the maximum virtual address which can be DMA'd from. */ #ifndef ARM_DMA_ZONE_SIZE #define MAX_DMA_ADDRESS 0xffffffff #ifndef CONFIG_ZONE_DMA #define MAX_DMA_ADDRESS 0xffffffffUL #else #define MAX_DMA_ADDRESS (PAGE_OFFSET + ARM_DMA_ZONE_SIZE) #define MAX_DMA_ADDRESS ({ \ extern unsigned long arm_dma_zone_size; \ arm_dma_zone_size ? \ (PAGE_OFFSET + arm_dma_zone_size) : 0xffffffffUL; }) #endif #ifdef CONFIG_ISA_DMA_API Loading Loading
arch/arm/common/dmabounce.c +83 −110 Original line number Diff line number Diff line Loading @@ -79,6 +79,8 @@ struct dmabounce_device_info { struct dmabounce_pool large; rwlock_t lock; int (*needs_bounce)(struct device *, dma_addr_t, size_t); }; #ifdef STATS Loading Loading @@ -210,90 +212,71 @@ static struct safe_buffer *find_safe_buffer_dev(struct device *dev, if (!dev || !dev->archdata.dmabounce) return NULL; if (dma_mapping_error(dev, dma_addr)) { if (dev) dev_err(dev, "Trying to %s invalid mapping\n", where); else pr_err("unknown device: Trying to %s invalid mapping\n", where); return NULL; } return find_safe_buffer(dev->archdata.dmabounce, dma_addr); } static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size, enum dma_data_direction dir) static int needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) { struct dmabounce_device_info *device_info = dev->archdata.dmabounce; dma_addr_t dma_addr; int needs_bounce = 0; if (device_info) DO_STATS ( device_info->map_op_count++ ); dma_addr = virt_to_dma(dev, ptr); if (!dev || !dev->archdata.dmabounce) return 0; if (dev->dma_mask) { unsigned long mask = *dev->dma_mask; unsigned long limit; unsigned long limit, mask = *dev->dma_mask; limit = (mask + 1) & ~mask; if (limit && size > limit) { dev_err(dev, "DMA mapping too big (requested %#x " "mask %#Lx)\n", size, *dev->dma_mask); return ~0; return -E2BIG; } /* * Figure out if we need to bounce from the DMA mask. */ needs_bounce = (dma_addr | (dma_addr + size - 1)) & ~mask; /* Figure out if we need to bounce from the DMA mask. */ if ((dma_addr | (dma_addr + size - 1)) & ~mask) return 1; } return !!dev->archdata.dmabounce->needs_bounce(dev, dma_addr, size); } if (device_info && (needs_bounce || dma_needs_bounce(dev, dma_addr, size))) { static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size, enum dma_data_direction dir) { struct dmabounce_device_info *device_info = dev->archdata.dmabounce; struct safe_buffer *buf; if (device_info) DO_STATS ( device_info->map_op_count++ ); buf = alloc_safe_buffer(device_info, ptr, size, dir); if (buf == 0) { if (buf == NULL) { dev_err(dev, "%s: unable to map unsafe buffer %p!\n", __func__, ptr); return ~0; } dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", __func__, buf->ptr, virt_to_dma(dev, buf->ptr), buf->safe, buf->safe_dma_addr); if ((dir == DMA_TO_DEVICE) || (dir == DMA_BIDIRECTIONAL)) { if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) { dev_dbg(dev, "%s: copy unsafe %p to safe %p, size %d\n", __func__, ptr, buf->safe, size); memcpy(buf->safe, ptr, size); } ptr = buf->safe; dma_addr = buf->safe_dma_addr; } else { /* * We don't need to sync the DMA buffer since * it was allocated via the coherent allocators. */ __dma_single_cpu_to_dev(ptr, size, dir); } return dma_addr; return buf->safe_dma_addr; } static inline void unmap_single(struct device *dev, dma_addr_t dma_addr, static inline void unmap_single(struct device *dev, struct safe_buffer *buf, size_t size, enum dma_data_direction dir) { struct safe_buffer *buf = find_safe_buffer_dev(dev, dma_addr, "unmap"); if (buf) { BUG_ON(buf->size != size); BUG_ON(buf->direction != dir); dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", __func__, buf->ptr, virt_to_dma(dev, buf->ptr), buf->safe, buf->safe_dma_addr); Loading @@ -302,8 +285,7 @@ static inline void unmap_single(struct device *dev, dma_addr_t dma_addr, if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) { void *ptr = buf->ptr; dev_dbg(dev, "%s: copy back safe %p to unsafe %p size %d\n", dev_dbg(dev, "%s: copy back safe %p to unsafe %p size %d\n", __func__, buf->safe, ptr, size); memcpy(ptr, buf->safe, size); Loading @@ -315,9 +297,6 @@ static inline void unmap_single(struct device *dev, dma_addr_t dma_addr, __cpuc_flush_dcache_area(ptr, size); } free_safe_buffer(dev->archdata.dmabounce, buf); } else { __dma_single_dev_to_cpu(dma_to_virt(dev, dma_addr), size, dir); } } /* ************************************************** */ Loading @@ -328,45 +307,28 @@ static inline void unmap_single(struct device *dev, dma_addr_t dma_addr, * substitute the safe buffer for the unsafe one. * (basically move the buffer from an unsafe area to a safe one) */ dma_addr_t __dma_map_single(struct device *dev, void *ptr, size_t size, enum dma_data_direction dir) { dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", __func__, ptr, size, dir); BUG_ON(!valid_dma_direction(dir)); return map_single(dev, ptr, size, dir); } EXPORT_SYMBOL(__dma_map_single); /* * see if a mapped address was really a "safe" buffer and if so, copy * the data from the safe buffer back to the unsafe buffer and free up * the safe buffer. (basically return things back to the way they * should be) */ void __dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction dir) { dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", __func__, (void *) dma_addr, size, dir); unmap_single(dev, dma_addr, size, dir); } EXPORT_SYMBOL(__dma_unmap_single); dma_addr_t __dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction dir) { dma_addr_t dma_addr; int ret; dev_dbg(dev, "%s(page=%p,off=%#lx,size=%zx,dir=%x)\n", __func__, page, offset, size, dir); BUG_ON(!valid_dma_direction(dir)); dma_addr = pfn_to_dma(dev, page_to_pfn(page)) + offset; ret = needs_bounce(dev, dma_addr, size); if (ret < 0) return ~0; if (ret == 0) { __dma_page_cpu_to_dev(page, offset, size, dir); return dma_addr; } if (PageHighMem(page)) { dev_err(dev, "DMA buffer bouncing of HIGHMEM pages " "is not supported\n"); dev_err(dev, "DMA buffer bouncing of HIGHMEM pages is not supported\n"); return ~0; } Loading @@ -383,10 +345,19 @@ EXPORT_SYMBOL(__dma_map_page); void __dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction dir) { dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", __func__, (void *) dma_addr, size, dir); struct safe_buffer *buf; dev_dbg(dev, "%s(dma=%#x,size=%d,dir=%x)\n", __func__, dma_addr, size, dir); buf = find_safe_buffer_dev(dev, dma_addr, __func__); if (!buf) { __dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, dma_addr)), dma_addr & ~PAGE_MASK, size, dir); return; } unmap_single(dev, dma_addr, size, dir); unmap_single(dev, buf, size, dir); } EXPORT_SYMBOL(__dma_unmap_page); Loading Loading @@ -461,7 +432,8 @@ static int dmabounce_init_pool(struct dmabounce_pool *pool, struct device *dev, } int dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, unsigned long large_buffer_size) unsigned long large_buffer_size, int (*needs_bounce_fn)(struct device *, dma_addr_t, size_t)) { struct dmabounce_device_info *device_info; int ret; Loading Loading @@ -497,6 +469,7 @@ int dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, device_info->dev = dev; INIT_LIST_HEAD(&device_info->safe_buffers); rwlock_init(&device_info->lock); device_info->needs_bounce = needs_bounce_fn; #ifdef STATS device_info->total_allocs = 0; Loading
arch/arm/common/it8152.c +7 −9 Original line number Diff line number Diff line Loading @@ -243,6 +243,12 @@ static struct resource it8152_mem = { * ITE8152 chip can address up to 64MByte, so all the devices * connected to ITE8152 (PCI and USB) should have limited DMA window */ static int it8152_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) { dev_dbg(dev, "%s: dma_addr %08x, size %08x\n", __func__, dma_addr, size); return (dma_addr + size - PHYS_OFFSET) >= SZ_64M; } /* * Setup DMA mask to 64MB on devices connected to ITE8152. Ignore all Loading @@ -254,7 +260,7 @@ static int it8152_pci_platform_notify(struct device *dev) if (dev->dma_mask) *dev->dma_mask = (SZ_64M - 1) | PHYS_OFFSET; dev->coherent_dma_mask = (SZ_64M - 1) | PHYS_OFFSET; dmabounce_register_dev(dev, 2048, 4096); dmabounce_register_dev(dev, 2048, 4096, it8152_needs_bounce); } return 0; } Loading @@ -267,14 +273,6 @@ static int it8152_pci_platform_notify_remove(struct device *dev) return 0; } int dma_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) { dev_dbg(dev, "%s: dma_addr %08x, size %08x\n", __func__, dma_addr, size); return (dev->bus == &pci_bus_type) && ((dma_addr + size - PHYS_OFFSET) >= SZ_64M); } int dma_set_coherent_mask(struct device *dev, u64 mask) { if (mask >= PHYS_OFFSET + SZ_64M - 1) Loading
arch/arm/common/sa1111.c +31 −29 Original line number Diff line number Diff line Loading @@ -579,7 +579,36 @@ sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac, sachip->dev->coherent_dma_mask &= sa1111_dma_mask[drac >> 2]; } #endif #ifdef CONFIG_DMABOUNCE /* * According to the "Intel StrongARM SA-1111 Microprocessor Companion * Chip Specification Update" (June 2000), erratum #7, there is a * significant bug in the SA1111 SDRAM shared memory controller. If * an access to a region of memory above 1MB relative to the bank base, * it is important that address bit 10 _NOT_ be asserted. Depending * on the configuration of the RAM, bit 10 may correspond to one * of several different (processor-relative) address bits. * * This routine only identifies whether or not a given DMA address * is susceptible to the bug. * * This should only get called for sa1111_device types due to the * way we configure our device dma_masks. */ static int sa1111_needs_bounce(struct device *dev, dma_addr_t addr, size_t size) { /* * Section 4.6 of the "Intel StrongARM SA-1111 Development Module * User's Guide" mentions that jumpers R51 and R52 control the * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or * SDRAM bank 1 on Neponset). The default configuration selects * Assabet, so any address in bank 1 is necessarily invalid. */ return (machine_is_assabet() || machine_is_pfs168()) && (addr >= 0xc8000000 || (addr + size) >= 0xc8000000); } #endif static void sa1111_dev_release(struct device *_dev) Loading Loading @@ -644,7 +673,8 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, dev->dev.dma_mask = &dev->dma_mask; if (dev->dma_mask != 0xffffffffUL) { ret = dmabounce_register_dev(&dev->dev, 1024, 4096); ret = dmabounce_register_dev(&dev->dev, 1024, 4096, sa1111_needs_bounce); if (ret) { dev_err(&dev->dev, "SA1111: Failed to register" " with dmabounce\n"); Loading Loading @@ -818,34 +848,6 @@ static void __sa1111_remove(struct sa1111 *sachip) kfree(sachip); } /* * According to the "Intel StrongARM SA-1111 Microprocessor Companion * Chip Specification Update" (June 2000), erratum #7, there is a * significant bug in the SA1111 SDRAM shared memory controller. If * an access to a region of memory above 1MB relative to the bank base, * it is important that address bit 10 _NOT_ be asserted. Depending * on the configuration of the RAM, bit 10 may correspond to one * of several different (processor-relative) address bits. * * This routine only identifies whether or not a given DMA address * is susceptible to the bug. * * This should only get called for sa1111_device types due to the * way we configure our device dma_masks. */ int dma_needs_bounce(struct device *dev, dma_addr_t addr, size_t size) { /* * Section 4.6 of the "Intel StrongARM SA-1111 Development Module * User's Guide" mentions that jumpers R51 and R52 control the * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or * SDRAM bank 1 on Neponset). The default configuration selects * Assabet, so any address in bank 1 is necessarily invalid. */ return ((machine_is_assabet() || machine_is_pfs168()) && (addr >= 0xc8000000 || (addr + size) >= 0xc8000000)); } struct sa1111_save_data { unsigned int skcr; unsigned int skpcr; Loading
arch/arm/include/asm/dma-mapping.h +13 −75 Original line number Diff line number Diff line Loading @@ -115,39 +115,8 @@ static inline void __dma_page_dev_to_cpu(struct page *page, unsigned long off, ___dma_page_dev_to_cpu(page, off, size, dir); } /* * Return whether the given device DMA address mask can be supported * properly. For example, if your device can only drive the low 24-bits * during bus mastering, then you would pass 0x00ffffff as the mask * to this function. * * FIXME: This should really be a platform specific issue - we should * return false if GFP_DMA allocations may not satisfy the supplied 'mask'. */ static inline int dma_supported(struct device *dev, u64 mask) { if (mask < ISA_DMA_THRESHOLD) return 0; return 1; } static inline int dma_set_mask(struct device *dev, u64 dma_mask) { #ifdef CONFIG_DMABOUNCE if (dev->archdata.dmabounce) { if (dma_mask >= ISA_DMA_THRESHOLD) return 0; else return -EIO; } #endif if (!dev->dma_mask || !dma_supported(dev, dma_mask)) return -EIO; *dev->dma_mask = dma_mask; return 0; } extern int dma_supported(struct device *, u64); extern int dma_set_mask(struct device *, u64); /* * DMA errors are defined by all-bits-set in the DMA address. Loading Loading @@ -256,14 +225,14 @@ int dma_mmap_writecombine(struct device *, struct vm_area_struct *, * @dev: valid struct device pointer * @small_buf_size: size of buffers to use with small buffer pool * @large_buf_size: size of buffers to use with large buffer pool (can be 0) * @needs_bounce_fn: called to determine whether buffer needs bouncing * * This function should be called by low-level platform code to register * a device as requireing DMA buffer bouncing. The function will allocate * appropriate DMA pools for the device. * */ extern int dmabounce_register_dev(struct device *, unsigned long, unsigned long); unsigned long, int (*)(struct device *, dma_addr_t, size_t)); /** * dmabounce_unregister_dev Loading @@ -277,31 +246,9 @@ extern int dmabounce_register_dev(struct device *, unsigned long, */ extern void dmabounce_unregister_dev(struct device *); /** * dma_needs_bounce * * @dev: valid struct device pointer * @dma_handle: dma_handle of unbounced buffer * @size: size of region being mapped * * Platforms that utilize the dmabounce mechanism must implement * this function. * * The dmabounce routines call this function whenever a dma-mapping * is requested to determine whether a given buffer needs to be bounced * or not. The function must return 0 if the buffer is OK for * DMA access and 1 if the buffer needs to be bounced. * */ extern int dma_needs_bounce(struct device*, dma_addr_t, size_t); /* * The DMA API, implemented by dmabounce.c. See below for descriptions. */ extern dma_addr_t __dma_map_single(struct device *, void *, size_t, enum dma_data_direction); extern void __dma_unmap_single(struct device *, dma_addr_t, size_t, enum dma_data_direction); extern dma_addr_t __dma_map_page(struct device *, struct page *, unsigned long, size_t, enum dma_data_direction); extern void __dma_unmap_page(struct device *, dma_addr_t, size_t, Loading @@ -328,13 +275,6 @@ static inline int dmabounce_sync_for_device(struct device *d, dma_addr_t addr, } static inline dma_addr_t __dma_map_single(struct device *dev, void *cpu_addr, size_t size, enum dma_data_direction dir) { __dma_single_cpu_to_dev(cpu_addr, size, dir); return virt_to_dma(dev, cpu_addr); } static inline dma_addr_t __dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction dir) { Loading @@ -342,12 +282,6 @@ static inline dma_addr_t __dma_map_page(struct device *dev, struct page *page, return pfn_to_dma(dev, page_to_pfn(page)) + offset; } static inline void __dma_unmap_single(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir) { __dma_single_dev_to_cpu(dma_to_virt(dev, handle), size, dir); } static inline void __dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir) { Loading @@ -373,14 +307,18 @@ static inline void __dma_unmap_page(struct device *dev, dma_addr_t handle, static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size, enum dma_data_direction dir) { unsigned long offset; struct page *page; dma_addr_t addr; BUG_ON(!virt_addr_valid(cpu_addr)); BUG_ON(!virt_addr_valid(cpu_addr + size - 1)); BUG_ON(!valid_dma_direction(dir)); addr = __dma_map_single(dev, cpu_addr, size, dir); debug_dma_map_page(dev, virt_to_page(cpu_addr), (unsigned long)cpu_addr & ~PAGE_MASK, size, dir, addr, true); page = virt_to_page(cpu_addr); offset = (unsigned long)cpu_addr & ~PAGE_MASK; addr = __dma_map_page(dev, page, offset, size, dir); debug_dma_map_page(dev, page, offset, size, dir, addr, true); return addr; } Loading Loading @@ -430,7 +368,7 @@ static inline void dma_unmap_single(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir) { debug_dma_unmap_page(dev, handle, size, dir, true); __dma_unmap_single(dev, handle, size, dir); __dma_unmap_page(dev, handle, size, dir); } /** Loading
arch/arm/include/asm/dma.h +6 −5 Original line number Diff line number Diff line #ifndef __ASM_ARM_DMA_H #define __ASM_ARM_DMA_H #include <asm/memory.h> /* * This is the maximum virtual address which can be DMA'd from. */ #ifndef ARM_DMA_ZONE_SIZE #define MAX_DMA_ADDRESS 0xffffffff #ifndef CONFIG_ZONE_DMA #define MAX_DMA_ADDRESS 0xffffffffUL #else #define MAX_DMA_ADDRESS (PAGE_OFFSET + ARM_DMA_ZONE_SIZE) #define MAX_DMA_ADDRESS ({ \ extern unsigned long arm_dma_zone_size; \ arm_dma_zone_size ? \ (PAGE_OFFSET + arm_dma_zone_size) : 0xffffffffUL; }) #endif #ifdef CONFIG_ISA_DMA_API Loading