diff options
| -rw-r--r-- | arch/arm/Kconfig | 1 | ||||
| -rw-r--r-- | arch/arm/mm/consistent.c | 8 | ||||
| -rw-r--r-- | arch/cris/arch-v32/drivers/Kconfig | 1 | ||||
| -rw-r--r-- | arch/cris/arch-v32/drivers/pci/dma.c | 106 | ||||
| -rw-r--r-- | arch/sh/Kconfig | 1 | ||||
| -rw-r--r-- | arch/sh/mm/consistent.c | 98 | ||||
| -rw-r--r-- | arch/x86/Kconfig | 1 | ||||
| -rw-r--r-- | arch/x86/kernel/pci-dma.c | 122 | ||||
| -rw-r--r-- | include/asm-arm/dma-mapping.h | 2 | ||||
| -rw-r--r-- | include/asm-cris/dma-mapping.h | 2 | ||||
| -rw-r--r-- | include/asm-generic/dma-coherent.h | 32 | ||||
| -rw-r--r-- | include/asm-sh/dma-mapping.h | 1 | ||||
| -rw-r--r-- | include/asm-x86/dma-mapping.h | 22 | ||||
| -rw-r--r-- | init/Kconfig | 4 | ||||
| -rw-r--r-- | kernel/Makefile | 1 | ||||
| -rw-r--r-- | kernel/dma-coherent.c | 154 |
16 files changed, 217 insertions, 339 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c8f528284a94..652cd32a09c5 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
| @@ -17,6 +17,7 @@ config ARM | |||
| 17 | select HAVE_KRETPROBES if (HAVE_KPROBES) | 17 | select HAVE_KRETPROBES if (HAVE_KPROBES) |
| 18 | select HAVE_FTRACE if (!XIP_KERNEL) | 18 | select HAVE_FTRACE if (!XIP_KERNEL) |
| 19 | select HAVE_DYNAMIC_FTRACE if (HAVE_FTRACE) | 19 | select HAVE_DYNAMIC_FTRACE if (HAVE_FTRACE) |
| 20 | select HAVE_GENERIC_DMA_COHERENT | ||
| 20 | help | 21 | help |
| 21 | The ARM series is a line of low-power-consumption RISC chip designs | 22 | The ARM series is a line of low-power-consumption RISC chip designs |
| 22 | licensed by ARM Ltd and targeted at embedded applications and | 23 | licensed by ARM Ltd and targeted at embedded applications and |
diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c index 333a82a3717e..db7b3e38ef1d 100644 --- a/arch/arm/mm/consistent.c +++ b/arch/arm/mm/consistent.c | |||
| @@ -274,6 +274,11 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp, | |||
| 274 | void * | 274 | void * |
| 275 | dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp) | 275 | dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp) |
| 276 | { | 276 | { |
| 277 | void *memory; | ||
| 278 | |||
| 279 | if (dma_alloc_from_coherent(dev, size, handle, &memory)) | ||
| 280 | return memory; | ||
| 281 | |||
| 277 | if (arch_is_coherent()) { | 282 | if (arch_is_coherent()) { |
| 278 | void *virt; | 283 | void *virt; |
| 279 | 284 | ||
| @@ -362,6 +367,9 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr | |||
| 362 | 367 | ||
| 363 | WARN_ON(irqs_disabled()); | 368 | WARN_ON(irqs_disabled()); |
| 364 | 369 | ||
| 370 | if (dma_release_from_coherent(dev, get_order(size), cpu_addr)) | ||
| 371 | return; | ||
| 372 | |||
| 365 | if (arch_is_coherent()) { | 373 | if (arch_is_coherent()) { |
| 366 | kfree(cpu_addr); | 374 | kfree(cpu_addr); |
| 367 | return; | 375 | return; |
diff --git a/arch/cris/arch-v32/drivers/Kconfig b/arch/cris/arch-v32/drivers/Kconfig index 2a92cb1886ca..7a64fcef9d07 100644 --- a/arch/cris/arch-v32/drivers/Kconfig +++ b/arch/cris/arch-v32/drivers/Kconfig | |||
| @@ -641,6 +641,7 @@ config PCI | |||
| 641 | bool | 641 | bool |
| 642 | depends on ETRAX_CARDBUS | 642 | depends on ETRAX_CARDBUS |
| 643 | default y | 643 | default y |
| 644 | select HAVE_GENERIC_DMA_COHERENT | ||
| 644 | 645 | ||
| 645 | config ETRAX_IOP_FW_LOAD | 646 | config ETRAX_IOP_FW_LOAD |
| 646 | tristate "IO-processor hotplug firmware loading support" | 647 | tristate "IO-processor hotplug firmware loading support" |
diff --git a/arch/cris/arch-v32/drivers/pci/dma.c b/arch/cris/arch-v32/drivers/pci/dma.c index e0364654fc44..fbe65954ee6c 100644 --- a/arch/cris/arch-v32/drivers/pci/dma.c +++ b/arch/cris/arch-v32/drivers/pci/dma.c | |||
| @@ -15,35 +15,16 @@ | |||
| 15 | #include <linux/pci.h> | 15 | #include <linux/pci.h> |
| 16 | #include <asm/io.h> | 16 | #include <asm/io.h> |
| 17 | 17 | ||
| 18 | struct dma_coherent_mem { | ||
| 19 | void *virt_base; | ||
| 20 | u32 device_base; | ||
| 21 | int size; | ||
| 22 | int flags; | ||
| 23 | unsigned long *bitmap; | ||
| 24 | }; | ||
| 25 | |||
| 26 | void *dma_alloc_coherent(struct device *dev, size_t size, | 18 | void *dma_alloc_coherent(struct device *dev, size_t size, |
| 27 | dma_addr_t *dma_handle, gfp_t gfp) | 19 | dma_addr_t *dma_handle, gfp_t gfp) |
| 28 | { | 20 | { |
| 29 | void *ret; | 21 | void *ret; |
| 30 | struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; | ||
| 31 | int order = get_order(size); | 22 | int order = get_order(size); |
| 32 | /* ignore region specifiers */ | 23 | /* ignore region specifiers */ |
| 33 | gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); | 24 | gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); |
| 34 | 25 | ||
| 35 | if (mem) { | 26 | if (dma_alloc_from_coherent(dev, size, dma_handle, &ret)) |
| 36 | int page = bitmap_find_free_region(mem->bitmap, mem->size, | 27 | return ret; |
| 37 | order); | ||
| 38 | if (page >= 0) { | ||
| 39 | *dma_handle = mem->device_base + (page << PAGE_SHIFT); | ||
| 40 | ret = mem->virt_base + (page << PAGE_SHIFT); | ||
| 41 | memset(ret, 0, size); | ||
| 42 | return ret; | ||
| 43 | } | ||
| 44 | if (mem->flags & DMA_MEMORY_EXCLUSIVE) | ||
| 45 | return NULL; | ||
| 46 | } | ||
| 47 | 28 | ||
| 48 | if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) | 29 | if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) |
| 49 | gfp |= GFP_DMA; | 30 | gfp |= GFP_DMA; |
| @@ -60,90 +41,9 @@ void *dma_alloc_coherent(struct device *dev, size_t size, | |||
| 60 | void dma_free_coherent(struct device *dev, size_t size, | 41 | void dma_free_coherent(struct device *dev, size_t size, |
| 61 | void *vaddr, dma_addr_t dma_handle) | 42 | void *vaddr, dma_addr_t dma_handle) |
| 62 | { | 43 | { |
| 63 | struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; | ||
| 64 | int order = get_order(size); | 44 | int order = get_order(size); |
| 65 | 45 | ||
| 66 | if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) { | 46 | if (!dma_release_from_coherent(dev, order, vaddr)) |
| 67 | int page = (vaddr - mem->virt_base) >> PAGE_SHIFT; | ||
| 68 | |||
| 69 | bitmap_release_region(mem->bitmap, page, order); | ||
| 70 | } else | ||
| 71 | free_pages((unsigned long)vaddr, order); | 47 | free_pages((unsigned long)vaddr, order); |
| 72 | } | 48 | } |
| 73 | 49 | ||
| 74 | int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, | ||
| 75 | dma_addr_t device_addr, size_t size, int flags) | ||
| 76 | { | ||
| 77 | void __iomem *mem_base; | ||
| 78 | int pages = size >> PAGE_SHIFT; | ||
| 79 | int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); | ||
| 80 | |||
| 81 | if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0) | ||
| 82 | goto out; | ||
| 83 | if (!size) | ||
| 84 | goto out; | ||
| 85 | if (dev->dma_mem) | ||
| 86 | goto out; | ||
| 87 | |||
| 88 | /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ | ||
| 89 | |||
| 90 | mem_base = ioremap(bus_addr, size); | ||
| 91 | if (!mem_base) | ||
| 92 | goto out; | ||
| 93 | |||
| 94 | dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); | ||
| 95 | if (!dev->dma_mem) | ||
| 96 | goto iounmap_out; | ||
| 97 | dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL); | ||
| 98 | if (!dev->dma_mem->bitmap) | ||
| 99 | goto free1_out; | ||
| 100 | |||
| 101 | dev->dma_mem->virt_base = mem_base; | ||
| 102 | dev->dma_mem->device_base = device_addr; | ||
| 103 | dev->dma_mem->size = pages; | ||
| 104 | dev->dma_mem->flags = flags; | ||
| 105 | |||
| 106 | if (flags & DMA_MEMORY_MAP) | ||
| 107 | return DMA_MEMORY_MAP; | ||
| 108 | |||
| 109 | return DMA_MEMORY_IO; | ||
| 110 | |||
| 111 | free1_out: | ||
| 112 | kfree(dev->dma_mem); | ||
| 113 | iounmap_out: | ||
| 114 | iounmap(mem_base); | ||
| 115 | out: | ||
| 116 | return 0; | ||
| 117 | } | ||
| 118 | EXPORT_SYMBOL(dma_declare_coherent_memory); | ||
| 119 | |||
| 120 | void dma_release_declared_memory(struct device *dev) | ||
| 121 | { | ||
| 122 | struct dma_coherent_mem *mem = dev->dma_mem; | ||
| 123 | |||
| 124 | if(!mem) | ||
| 125 | return; | ||
| 126 | dev->dma_mem = NULL; | ||
| 127 | iounmap(mem->virt_base); | ||
| 128 | kfree(mem->bitmap); | ||
| 129 | kfree(mem); | ||
| 130 | } | ||
| 131 | EXPORT_SYMBOL(dma_release_declared_memory); | ||
| 132 | |||
| 133 | void *dma_mark_declared_memory_occupied(struct device *dev, | ||
| 134 | dma_addr_t device_addr, size_t size) | ||
| 135 | { | ||
| 136 | struct dma_coherent_mem *mem = dev->dma_mem; | ||
| 137 | int pages = (size + (device_addr & ~PAGE_MASK) + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
| 138 | int pos, err; | ||
| 139 | |||
| 140 | if (!mem) | ||
| 141 | return ERR_PTR(-EINVAL); | ||
| 142 | |||
| 143 | pos = (device_addr - mem->device_base) >> PAGE_SHIFT; | ||
| 144 | err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages)); | ||
| 145 | if (err != 0) | ||
| 146 | return ERR_PTR(err); | ||
| 147 | return mem->virt_base + (pos << PAGE_SHIFT); | ||
| 148 | } | ||
| 149 | EXPORT_SYMBOL(dma_mark_declared_memory_occupied); | ||
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 7bfb0d219d67..0b88dc462d73 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig | |||
| @@ -11,6 +11,7 @@ config SUPERH | |||
| 11 | select HAVE_CLK | 11 | select HAVE_CLK |
| 12 | select HAVE_IDE | 12 | select HAVE_IDE |
| 13 | select HAVE_OPROFILE | 13 | select HAVE_OPROFILE |
| 14 | select HAVE_GENERIC_DMA_COHERENT | ||
| 14 | help | 15 | help |
| 15 | The SuperH is a RISC processor targeted for use in embedded systems | 16 | The SuperH is a RISC processor targeted for use in embedded systems |
| 16 | and consumer electronics; it was also used in the Sega Dreamcast | 17 | and consumer electronics; it was also used in the Sega Dreamcast |
diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c index 8277982d0938..b2ce014401b5 100644 --- a/arch/sh/mm/consistent.c +++ b/arch/sh/mm/consistent.c | |||
| @@ -28,21 +28,10 @@ void *dma_alloc_coherent(struct device *dev, size_t size, | |||
| 28 | dma_addr_t *dma_handle, gfp_t gfp) | 28 | dma_addr_t *dma_handle, gfp_t gfp) |
| 29 | { | 29 | { |
| 30 | void *ret, *ret_nocache; | 30 | void *ret, *ret_nocache; |
| 31 | struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; | ||
| 32 | int order = get_order(size); | 31 | int order = get_order(size); |
| 33 | 32 | ||
| 34 | if (mem) { | 33 | if (dma_alloc_from_coherent(dev, size, dma_handle, &ret)) |
| 35 | int page = bitmap_find_free_region(mem->bitmap, mem->size, | 34 | return ret; |
| 36 | order); | ||
| 37 | if (page >= 0) { | ||
| 38 | *dma_handle = mem->device_base + (page << PAGE_SHIFT); | ||
| 39 | ret = mem->virt_base + (page << PAGE_SHIFT); | ||
| 40 | memset(ret, 0, size); | ||
| 41 | return ret; | ||
| 42 | } | ||
| 43 | if (mem->flags & DMA_MEMORY_EXCLUSIVE) | ||
| 44 | return NULL; | ||
| 45 | } | ||
| 46 | 35 | ||
| 47 | ret = (void *)__get_free_pages(gfp, order); | 36 | ret = (void *)__get_free_pages(gfp, order); |
| 48 | if (!ret) | 37 | if (!ret) |
| @@ -72,11 +61,7 @@ void dma_free_coherent(struct device *dev, size_t size, | |||
| 72 | struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; | 61 | struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; |
| 73 | int order = get_order(size); | 62 | int order = get_order(size); |
| 74 | 63 | ||
| 75 | if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) { | 64 | if (!dma_release_from_coherent(dev, order, vaddr)) { |
| 76 | int page = (vaddr - mem->virt_base) >> PAGE_SHIFT; | ||
| 77 | |||
| 78 | bitmap_release_region(mem->bitmap, page, order); | ||
| 79 | } else { | ||
| 80 | WARN_ON(irqs_disabled()); /* for portability */ | 65 | WARN_ON(irqs_disabled()); /* for portability */ |
| 81 | BUG_ON(mem && mem->flags & DMA_MEMORY_EXCLUSIVE); | 66 | BUG_ON(mem && mem->flags & DMA_MEMORY_EXCLUSIVE); |
| 82 | free_pages((unsigned long)phys_to_virt(dma_handle), order); | 67 | free_pages((unsigned long)phys_to_virt(dma_handle), order); |
| @@ -85,83 +70,6 @@ void dma_free_coherent(struct device *dev, size_t size, | |||
| 85 | } | 70 | } |
| 86 | EXPORT_SYMBOL(dma_free_coherent); | 71 | EXPORT_SYMBOL(dma_free_coherent); |
| 87 | 72 | ||
| 88 | int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, | ||
| 89 | dma_addr_t device_addr, size_t size, int flags) | ||
| 90 | { | ||
| 91 | void __iomem *mem_base = NULL; | ||
| 92 | int pages = size >> PAGE_SHIFT; | ||
| 93 | int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); | ||
| 94 | |||
| 95 | if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0) | ||
| 96 | goto out; | ||
| 97 | if (!size) | ||
| 98 | goto out; | ||
| 99 | if (dev->dma_mem) | ||
| 100 | goto out; | ||
| 101 | |||
| 102 | /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ | ||
| 103 | |||
| 104 | mem_base = ioremap_nocache(bus_addr, size); | ||
| 105 | if (!mem_base) | ||
| 106 | goto out; | ||
| 107 | |||
| 108 | dev->dma_mem = kmalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); | ||
| 109 | if (!dev->dma_mem) | ||
| 110 | goto out; | ||
| 111 | dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL); | ||
| 112 | if (!dev->dma_mem->bitmap) | ||
| 113 | goto free1_out; | ||
| 114 | |||
| 115 | dev->dma_mem->virt_base = mem_base; | ||
| 116 | dev->dma_mem->device_base = device_addr; | ||
| 117 | dev->dma_mem->size = pages; | ||
| 118 | dev->dma_mem->flags = flags; | ||
| 119 | |||
| 120 | if (flags & DMA_MEMORY_MAP) | ||
| 121 | return DMA_MEMORY_MAP; | ||
| 122 | |||
| 123 | return DMA_MEMORY_IO; | ||
| 124 | |||
| 125 | free1_out: | ||
| 126 | kfree(dev->dma_mem); | ||
| 127 | out: | ||
| 128 | if (mem_base) | ||
| 129 | iounmap(mem_base); | ||
| 130 | return 0; | ||
| 131 | } | ||
| 132 | EXPORT_SYMBOL(dma_declare_coherent_memory); | ||
| 133 | |||
| 134 | void dma_release_declared_memory(struct device *dev) | ||
| 135 | { | ||
| 136 | struct dma_coherent_mem *mem = dev->dma_mem; | ||
| 137 | |||
| 138 | if (!mem) | ||
| 139 | return; | ||
| 140 | dev->dma_mem = NULL; | ||
| 141 | iounmap(mem->virt_base); | ||
| 142 | kfree(mem->bitmap); | ||
| 143 | kfree(mem); | ||
| 144 | } | ||
| 145 | EXPORT_SYMBOL(dma_release_declared_memory); | ||
| 146 | |||
| 147 | void *dma_mark_declared_memory_occupied(struct device *dev, | ||
| 148 | dma_addr_t device_addr, size_t size) | ||
| 149 | { | ||
| 150 | struct dma_coherent_mem *mem = dev->dma_mem; | ||
| 151 | int pages = (size + (device_addr & ~PAGE_MASK) + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
| 152 | int pos, err; | ||
| 153 | |||
| 154 | if (!mem) | ||
| 155 | return ERR_PTR(-EINVAL); | ||
| 156 | |||
| 157 | pos = (device_addr - mem->device_base) >> PAGE_SHIFT; | ||
| 158 | err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages)); | ||
| 159 | if (err != 0) | ||
| 160 | return ERR_PTR(err); | ||
| 161 | return mem->virt_base + (pos << PAGE_SHIFT); | ||
| 162 | } | ||
| 163 | EXPORT_SYMBOL(dma_mark_declared_memory_occupied); | ||
| 164 | |||
| 165 | void dma_cache_sync(struct device *dev, void *vaddr, size_t size, | 73 | void dma_cache_sync(struct device *dev, void *vaddr, size_t size, |
| 166 | enum dma_data_direction direction) | 74 | enum dma_data_direction direction) |
| 167 | { | 75 | { |
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index b6fa2877b173..3d0f2b6a5a16 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
| @@ -30,6 +30,7 @@ config X86 | |||
| 30 | select HAVE_FTRACE | 30 | select HAVE_FTRACE |
| 31 | select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64) | 31 | select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64) |
| 32 | select HAVE_ARCH_KGDB if !X86_VOYAGER | 32 | select HAVE_ARCH_KGDB if !X86_VOYAGER |
| 33 | select HAVE_GENERIC_DMA_COHERENT if X86_32 | ||
| 33 | select HAVE_EFFICIENT_UNALIGNED_ACCESS | 34 | select HAVE_EFFICIENT_UNALIGNED_ACCESS |
| 34 | 35 | ||
| 35 | config ARCH_DEFCONFIG | 36 | config ARCH_DEFCONFIG |
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index 37544123896d..8dbffb846de9 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c | |||
| @@ -192,124 +192,6 @@ static __init int iommu_setup(char *p) | |||
| 192 | } | 192 | } |
| 193 | early_param("iommu", iommu_setup); | 193 | early_param("iommu", iommu_setup); |
| 194 | 194 | ||
| 195 | #ifdef CONFIG_X86_32 | ||
| 196 | int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, | ||
| 197 | dma_addr_t device_addr, size_t size, int flags) | ||
| 198 | { | ||
| 199 | void __iomem *mem_base = NULL; | ||
| 200 | int pages = size >> PAGE_SHIFT; | ||
| 201 | int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); | ||
| 202 | |||
| 203 | if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0) | ||
| 204 | goto out; | ||
| 205 | if (!size) | ||
| 206 | goto out; | ||
| 207 | if (dev->dma_mem) | ||
| 208 | goto out; | ||
| 209 | |||
| 210 | /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ | ||
| 211 | |||
| 212 | mem_base = ioremap(bus_addr, size); | ||
| 213 | if (!mem_base) | ||
| 214 | goto out; | ||
| 215 | |||
| 216 | dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); | ||
| 217 | if (!dev->dma_mem) | ||
| 218 | goto out; | ||
| 219 | dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL); | ||
| 220 | if (!dev->dma_mem->bitmap) | ||
| 221 | goto free1_out; | ||
| 222 | |||
| 223 | dev->dma_mem->virt_base = mem_base; | ||
| 224 | dev->dma_mem->device_base = device_addr; | ||
| 225 | dev->dma_mem->size = pages; | ||
| 226 | dev->dma_mem->flags = flags; | ||
| 227 | |||
| 228 | if (flags & DMA_MEMORY_MAP) | ||
| 229 | return DMA_MEMORY_MAP; | ||
| 230 | |||
| 231 | return DMA_MEMORY_IO; | ||
| 232 | |||
| 233 | free1_out: | ||
| 234 | kfree(dev->dma_mem); | ||
| 235 | out: | ||
| 236 | if (mem_base) | ||
| 237 | iounmap(mem_base); | ||
| 238 | return 0; | ||
| 239 | } | ||
| 240 | EXPORT_SYMBOL(dma_declare_coherent_memory); | ||
| 241 | |||
| 242 | void dma_release_declared_memory(struct device *dev) | ||
| 243 | { | ||
| 244 | struct dma_coherent_mem *mem = dev->dma_mem; | ||
| 245 | |||
| 246 | if (!mem) | ||
| 247 | return; | ||
| 248 | dev->dma_mem = NULL; | ||
| 249 | iounmap(mem->virt_base); | ||
| 250 | kfree(mem->bitmap); | ||
| 251 | kfree(mem); | ||
| 252 | } | ||
| 253 | EXPORT_SYMBOL(dma_release_declared_memory); | ||
| 254 | |||
| 255 | void *dma_mark_declared_memory_occupied(struct device *dev, | ||
| 256 | dma_addr_t device_addr, size_t size) | ||
| 257 | { | ||
| 258 | struct dma_coherent_mem *mem = dev->dma_mem; | ||
| 259 | int pos, err; | ||
| 260 | int pages = (size + (device_addr & ~PAGE_MASK) + PAGE_SIZE - 1); | ||
| 261 | |||
| 262 | pages >>= PAGE_SHIFT; | ||
| 263 | |||
| 264 | if (!mem) | ||
| 265 | return ERR_PTR(-EINVAL); | ||
| 266 | |||
| 267 | pos = (device_addr - mem->device_base) >> PAGE_SHIFT; | ||
| 268 | err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages)); | ||
| 269 | if (err != 0) | ||
| 270 | return ERR_PTR(err); | ||
| 271 | return mem->virt_base + (pos << PAGE_SHIFT); | ||
| 272 | } | ||
| 273 | EXPORT_SYMBOL(dma_mark_declared_memory_occupied); | ||
| 274 | |||
| 275 | static int dma_alloc_from_coherent_mem(struct device *dev, ssize_t size, | ||
| 276 | dma_addr_t *dma_handle, void **ret) | ||
| 277 | { | ||
| 278 | struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; | ||
| 279 | int order = get_order(size); | ||
| 280 | |||
| 281 | if (mem) { | ||
| 282 | int page = bitmap_find_free_region(mem->bitmap, mem->size, | ||
| 283 | order); | ||
| 284 | if (page >= 0) { | ||
| 285 | *dma_handle = mem->device_base + (page << PAGE_SHIFT); | ||
| 286 | *ret = mem->virt_base + (page << PAGE_SHIFT); | ||
| 287 | memset(*ret, 0, size); | ||
| 288 | } | ||
| 289 | if (mem->flags & DMA_MEMORY_EXCLUSIVE) | ||
| 290 | *ret = NULL; | ||
| 291 | } | ||
| 292 | return (mem != NULL); | ||
| 293 | } | ||
| 294 | |||
| 295 | static int dma_release_coherent(struct device *dev, int order, void *vaddr) | ||
| 296 | { | ||
| 297 | struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; | ||
| 298 | |||
| 299 | if (mem && vaddr >= mem->virt_base && vaddr < | ||
| 300 | (mem->virt_base + (mem->size << PAGE_SHIFT))) { | ||
| 301 | int page = (vaddr - mem->virt_base) >> PAGE_SHIFT; | ||
| 302 | |||
| 303 | bitmap_release_region(mem->bitmap, page, order); | ||
| 304 | return 1; | ||
| 305 | } | ||
| 306 | return 0; | ||
| 307 | } | ||
| 308 | #else | ||
| 309 | #define dma_alloc_from_coherent_mem(dev, size, handle, ret) (0) | ||
| 310 | #define dma_release_coherent(dev, order, vaddr) (0) | ||
| 311 | #endif /* CONFIG_X86_32 */ | ||
| 312 | |||
| 313 | int dma_supported(struct device *dev, u64 mask) | 195 | int dma_supported(struct device *dev, u64 mask) |
| 314 | { | 196 | { |
| 315 | struct dma_mapping_ops *ops = get_dma_ops(dev); | 197 | struct dma_mapping_ops *ops = get_dma_ops(dev); |
| @@ -379,7 +261,7 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, | |||
| 379 | /* ignore region specifiers */ | 261 | /* ignore region specifiers */ |
| 380 | gfp &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32); | 262 | gfp &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32); |
| 381 | 263 | ||
| 382 | if (dma_alloc_from_coherent_mem(dev, size, dma_handle, &memory)) | 264 | if (dma_alloc_from_coherent(dev, size, dma_handle, &memory)) |
| 383 | return memory; | 265 | return memory; |
| 384 | 266 | ||
| 385 | if (!dev) { | 267 | if (!dev) { |
| @@ -484,7 +366,7 @@ void dma_free_coherent(struct device *dev, size_t size, | |||
| 484 | 366 | ||
| 485 | int order = get_order(size); | 367 | int order = get_order(size); |
| 486 | WARN_ON(irqs_disabled()); /* for portability */ | 368 | WARN_ON(irqs_disabled()); /* for portability */ |
| 487 | if (dma_release_coherent(dev, order, vaddr)) | 369 | if (dma_release_from_coherent(dev, order, vaddr)) |
| 488 | return; | 370 | return; |
| 489 | if (ops->unmap_single) | 371 | if (ops->unmap_single) |
| 490 | ops->unmap_single(dev, bus, size, 0); | 372 | ops->unmap_single(dev, bus, size, 0); |
diff --git a/include/asm-arm/dma-mapping.h b/include/asm-arm/dma-mapping.h index f41335ba6337..45329fca1b64 100644 --- a/include/asm-arm/dma-mapping.h +++ b/include/asm-arm/dma-mapping.h | |||
| @@ -7,6 +7,8 @@ | |||
| 7 | 7 | ||
| 8 | #include <linux/scatterlist.h> | 8 | #include <linux/scatterlist.h> |
| 9 | 9 | ||
| 10 | #include <asm-generic/dma-coherent.h> | ||
| 11 | |||
| 10 | /* | 12 | /* |
| 11 | * DMA-consistent mapping functions. These allocate/free a region of | 13 | * DMA-consistent mapping functions. These allocate/free a region of |
| 12 | * uncached, unwrite-buffered mapped memory space for use with DMA | 14 | * uncached, unwrite-buffered mapped memory space for use with DMA |
diff --git a/include/asm-cris/dma-mapping.h b/include/asm-cris/dma-mapping.h index cb2fb25ff8d9..da8ef8e8f842 100644 --- a/include/asm-cris/dma-mapping.h +++ b/include/asm-cris/dma-mapping.h | |||
| @@ -14,6 +14,8 @@ | |||
| 14 | #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) | 14 | #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) |
| 15 | 15 | ||
| 16 | #ifdef CONFIG_PCI | 16 | #ifdef CONFIG_PCI |
| 17 | #include <asm-generic/dma-coherent.h> | ||
| 18 | |||
| 17 | void *dma_alloc_coherent(struct device *dev, size_t size, | 19 | void *dma_alloc_coherent(struct device *dev, size_t size, |
| 18 | dma_addr_t *dma_handle, gfp_t flag); | 20 | dma_addr_t *dma_handle, gfp_t flag); |
| 19 | 21 | ||
diff --git a/include/asm-generic/dma-coherent.h b/include/asm-generic/dma-coherent.h new file mode 100644 index 000000000000..85a3ffaa0242 --- /dev/null +++ b/include/asm-generic/dma-coherent.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | #ifndef DMA_COHERENT_H | ||
| 2 | #define DMA_COHERENT_H | ||
| 3 | |||
| 4 | #ifdef CONFIG_HAVE_GENERIC_DMA_COHERENT | ||
| 5 | /* | ||
| 6 | * These two functions are only for dma allocator. | ||
| 7 | * Don't use them in device drivers. | ||
| 8 | */ | ||
| 9 | int dma_alloc_from_coherent(struct device *dev, ssize_t size, | ||
| 10 | dma_addr_t *dma_handle, void **ret); | ||
| 11 | int dma_release_from_coherent(struct device *dev, int order, void *vaddr); | ||
| 12 | |||
| 13 | /* | ||
| 14 | * Standard interface | ||
| 15 | */ | ||
| 16 | #define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY | ||
| 17 | extern int | ||
| 18 | dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, | ||
| 19 | dma_addr_t device_addr, size_t size, int flags); | ||
| 20 | |||
| 21 | extern void | ||
| 22 | dma_release_declared_memory(struct device *dev); | ||
| 23 | |||
| 24 | extern void * | ||
| 25 | dma_mark_declared_memory_occupied(struct device *dev, | ||
| 26 | dma_addr_t device_addr, size_t size); | ||
| 27 | #else | ||
| 28 | #define dma_alloc_from_coherent(dev, size, handle, ret) (0) | ||
| 29 | #define dma_release_from_coherent(dev, order, vaddr) (0) | ||
| 30 | #endif | ||
| 31 | |||
| 32 | #endif | ||
diff --git a/include/asm-sh/dma-mapping.h b/include/asm-sh/dma-mapping.h index 6c0b8a2de143..627315ecdb52 100644 --- a/include/asm-sh/dma-mapping.h +++ b/include/asm-sh/dma-mapping.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <linux/scatterlist.h> | 5 | #include <linux/scatterlist.h> |
| 6 | #include <asm/cacheflush.h> | 6 | #include <asm/cacheflush.h> |
| 7 | #include <asm/io.h> | 7 | #include <asm/io.h> |
| 8 | #include <asm-generic/dma-coherent.h> | ||
| 8 | 9 | ||
| 9 | extern struct bus_type pci_bus_type; | 10 | extern struct bus_type pci_bus_type; |
| 10 | 11 | ||
diff --git a/include/asm-x86/dma-mapping.h b/include/asm-x86/dma-mapping.h index 0eaa9bf6011f..ad9cd6d49bfc 100644 --- a/include/asm-x86/dma-mapping.h +++ b/include/asm-x86/dma-mapping.h | |||
| @@ -249,25 +249,5 @@ static inline int dma_get_cache_alignment(void) | |||
| 249 | 249 | ||
| 250 | #define dma_is_consistent(d, h) (1) | 250 | #define dma_is_consistent(d, h) (1) |
| 251 | 251 | ||
| 252 | #ifdef CONFIG_X86_32 | 252 | #include <asm-generic/dma-coherent.h> |
| 253 | # define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY | ||
| 254 | struct dma_coherent_mem { | ||
| 255 | void *virt_base; | ||
| 256 | u32 device_base; | ||
| 257 | int size; | ||
| 258 | int flags; | ||
| 259 | unsigned long *bitmap; | ||
| 260 | }; | ||
| 261 | |||
| 262 | extern int | ||
| 263 | dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, | ||
| 264 | dma_addr_t device_addr, size_t size, int flags); | ||
| 265 | |||
| 266 | extern void | ||
| 267 | dma_release_declared_memory(struct device *dev); | ||
| 268 | |||
| 269 | extern void * | ||
| 270 | dma_mark_declared_memory_occupied(struct device *dev, | ||
| 271 | dma_addr_t device_addr, size_t size); | ||
| 272 | #endif /* CONFIG_X86_32 */ | ||
| 273 | #endif | 253 | #endif |
diff --git a/init/Kconfig b/init/Kconfig index 43d6989c275f..250e02c8f8f9 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
| @@ -802,6 +802,10 @@ config PROC_PAGE_MONITOR | |||
| 802 | 802 | ||
| 803 | endmenu # General setup | 803 | endmenu # General setup |
| 804 | 804 | ||
| 805 | config HAVE_GENERIC_DMA_COHERENT | ||
| 806 | bool | ||
| 807 | default n | ||
| 808 | |||
| 805 | config SLABINFO | 809 | config SLABINFO |
| 806 | bool | 810 | bool |
| 807 | depends on PROC_FS | 811 | depends on PROC_FS |
diff --git a/kernel/Makefile b/kernel/Makefile index 54f69837d35a..4e1d7df7c3e2 100644 --- a/kernel/Makefile +++ b/kernel/Makefile | |||
| @@ -84,6 +84,7 @@ obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o | |||
| 84 | obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o | 84 | obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o |
| 85 | obj-$(CONFIG_MARKERS) += marker.o | 85 | obj-$(CONFIG_MARKERS) += marker.o |
| 86 | obj-$(CONFIG_LATENCYTOP) += latencytop.o | 86 | obj-$(CONFIG_LATENCYTOP) += latencytop.o |
| 87 | obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o | ||
| 87 | obj-$(CONFIG_FTRACE) += trace/ | 88 | obj-$(CONFIG_FTRACE) += trace/ |
| 88 | obj-$(CONFIG_TRACING) += trace/ | 89 | obj-$(CONFIG_TRACING) += trace/ |
| 89 | obj-$(CONFIG_SMP) += sched_cpupri.o | 90 | obj-$(CONFIG_SMP) += sched_cpupri.o |
diff --git a/kernel/dma-coherent.c b/kernel/dma-coherent.c new file mode 100644 index 000000000000..7517115a8cce --- /dev/null +++ b/kernel/dma-coherent.c | |||
| @@ -0,0 +1,154 @@ | |||
| 1 | /* | ||
| 2 | * Coherent per-device memory handling. | ||
| 3 | * Borrowed from i386 | ||
| 4 | */ | ||
| 5 | #include <linux/kernel.h> | ||
| 6 | #include <linux/dma-mapping.h> | ||
| 7 | |||
| 8 | struct dma_coherent_mem { | ||
| 9 | void *virt_base; | ||
| 10 | u32 device_base; | ||
| 11 | int size; | ||
| 12 | int flags; | ||
| 13 | unsigned long *bitmap; | ||
| 14 | }; | ||
| 15 | |||
| 16 | int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, | ||
| 17 | dma_addr_t device_addr, size_t size, int flags) | ||
| 18 | { | ||
| 19 | void __iomem *mem_base = NULL; | ||
| 20 | int pages = size >> PAGE_SHIFT; | ||
| 21 | int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); | ||
| 22 | |||
| 23 | if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0) | ||
| 24 | goto out; | ||
| 25 | if (!size) | ||
| 26 | goto out; | ||
| 27 | if (dev->dma_mem) | ||
| 28 | goto out; | ||
| 29 | |||
| 30 | /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ | ||
| 31 | |||
| 32 | mem_base = ioremap(bus_addr, size); | ||
| 33 | if (!mem_base) | ||
| 34 | goto out; | ||
| 35 | |||
| 36 | dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); | ||
| 37 | if (!dev->dma_mem) | ||
| 38 | goto out; | ||
| 39 | dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL); | ||
| 40 | if (!dev->dma_mem->bitmap) | ||
| 41 | goto free1_out; | ||
| 42 | |||
| 43 | dev->dma_mem->virt_base = mem_base; | ||
| 44 | dev->dma_mem->device_base = device_addr; | ||
| 45 | dev->dma_mem->size = pages; | ||
| 46 | dev->dma_mem->flags = flags; | ||
| 47 | |||
| 48 | if (flags & DMA_MEMORY_MAP) | ||
| 49 | return DMA_MEMORY_MAP; | ||
| 50 | |||
| 51 | return DMA_MEMORY_IO; | ||
| 52 | |||
| 53 | free1_out: | ||
| 54 | kfree(dev->dma_mem); | ||
| 55 | out: | ||
| 56 | if (mem_base) | ||
| 57 | iounmap(mem_base); | ||
| 58 | return 0; | ||
| 59 | } | ||
| 60 | EXPORT_SYMBOL(dma_declare_coherent_memory); | ||
| 61 | |||
| 62 | void dma_release_declared_memory(struct device *dev) | ||
| 63 | { | ||
| 64 | struct dma_coherent_mem *mem = dev->dma_mem; | ||
| 65 | |||
| 66 | if (!mem) | ||
| 67 | return; | ||
| 68 | dev->dma_mem = NULL; | ||
| 69 | iounmap(mem->virt_base); | ||
| 70 | kfree(mem->bitmap); | ||
| 71 | kfree(mem); | ||
| 72 | } | ||
| 73 | EXPORT_SYMBOL(dma_release_declared_memory); | ||
| 74 | |||
| 75 | void *dma_mark_declared_memory_occupied(struct device *dev, | ||
| 76 | dma_addr_t device_addr, size_t size) | ||
| 77 | { | ||
| 78 | struct dma_coherent_mem *mem = dev->dma_mem; | ||
| 79 | int pos, err; | ||
| 80 | int pages = (size + (device_addr & ~PAGE_MASK) + PAGE_SIZE - 1); | ||
| 81 | |||
| 82 | pages >>= PAGE_SHIFT; | ||
| 83 | |||
| 84 | if (!mem) | ||
| 85 | return ERR_PTR(-EINVAL); | ||
| 86 | |||
| 87 | pos = (device_addr - mem->device_base) >> PAGE_SHIFT; | ||
| 88 | err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages)); | ||
| 89 | if (err != 0) | ||
| 90 | return ERR_PTR(err); | ||
| 91 | return mem->virt_base + (pos << PAGE_SHIFT); | ||
| 92 | } | ||
| 93 | EXPORT_SYMBOL(dma_mark_declared_memory_occupied); | ||
| 94 | |||
| 95 | /** | ||
| 96 | * Try to allocate memory from the per-device coherent area. | ||
| 97 | * | ||
| 98 | * @dev: device from which we allocate memory | ||
| 99 | * @size: size of requested memory area | ||
| 100 | * @dma_handle: This will be filled with the correct dma handle | ||
| 101 | * @ret: This pointer will be filled with the virtual address | ||
| 102 | * to allocated area. | ||
| 103 | * | ||
| 104 | * This function should be only called from per-arch %dma_alloc_coherent() | ||
| 105 | * to support allocation from per-device coherent memory pools. | ||
| 106 | * | ||
| 107 | * Returns 0 if dma_alloc_coherent should continue with allocating from | ||
| 108 | * generic memory areas, or !0 if dma_alloc_coherent should return %ret. | ||
| 109 | */ | ||
| 110 | int dma_alloc_from_coherent(struct device *dev, ssize_t size, | ||
| 111 | dma_addr_t *dma_handle, void **ret) | ||
| 112 | { | ||
| 113 | struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; | ||
| 114 | int order = get_order(size); | ||
| 115 | |||
| 116 | if (mem) { | ||
| 117 | int page = bitmap_find_free_region(mem->bitmap, mem->size, | ||
| 118 | order); | ||
| 119 | if (page >= 0) { | ||
| 120 | *dma_handle = mem->device_base + (page << PAGE_SHIFT); | ||
| 121 | *ret = mem->virt_base + (page << PAGE_SHIFT); | ||
| 122 | memset(*ret, 0, size); | ||
| 123 | } else if (mem->flags & DMA_MEMORY_EXCLUSIVE) | ||
| 124 | *ret = NULL; | ||
| 125 | } | ||
| 126 | return (mem != NULL); | ||
| 127 | } | ||
| 128 | |||
| 129 | /** | ||
| 130 | * Try to free the memory allocated from per-device coherent memory pool. | ||
| 131 | * @dev: device from which the memory was allocated | ||
| 132 | * @order: the order of pages allocated | ||
| 133 | * @vaddr: virtual address of allocated pages | ||
| 134 | * | ||
| 135 | * This checks whether the memory was allocated from the per-device | ||
| 136 | * coherent memory pool and if so, releases that memory. | ||
| 137 | * | ||
| 138 | * Returns 1 if we correctly released the memory, or 0 if | ||
| 139 | * %dma_release_coherent() should proceed with releasing memory from | ||
| 140 | * generic pools. | ||
| 141 | */ | ||
| 142 | int dma_release_from_coherent(struct device *dev, int order, void *vaddr) | ||
| 143 | { | ||
| 144 | struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; | ||
| 145 | |||
| 146 | if (mem && vaddr >= mem->virt_base && vaddr < | ||
| 147 | (mem->virt_base + (mem->size << PAGE_SHIFT))) { | ||
| 148 | int page = (vaddr - mem->virt_base) >> PAGE_SHIFT; | ||
| 149 | |||
| 150 | bitmap_release_region(mem->bitmap, page, order); | ||
| 151 | return 1; | ||
| 152 | } | ||
| 153 | return 0; | ||
| 154 | } | ||
