Blame view
drivers/base/dma-coherent.c
4.46 KB
ee7e5516b generic: per-devi... |
1 2 3 4 |
/* * Coherent per-device memory handling. * Borrowed from i386 */ |
5a0e3ad6a include cleanup: ... |
5 |
#include <linux/slab.h> |
ee7e5516b generic: per-devi... |
6 |
#include <linux/kernel.h> |
08a999ce6 drivers/base: dma... |
7 |
#include <linux/module.h> |
ee7e5516b generic: per-devi... |
8 9 10 11 |
#include <linux/dma-mapping.h> struct dma_coherent_mem { void *virt_base; |
ed1d218c9 Driver core: inte... |
12 |
dma_addr_t device_base; |
ee7e5516b generic: per-devi... |
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
int size; int flags; unsigned long *bitmap; }; int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, dma_addr_t device_addr, size_t size, int flags) { void __iomem *mem_base = NULL; int pages = size >> PAGE_SHIFT; int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0) goto out; if (!size) goto out; if (dev->dma_mem) goto out; /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ mem_base = ioremap(bus_addr, size); if (!mem_base) goto out; dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); if (!dev->dma_mem) goto out; dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL); if (!dev->dma_mem->bitmap) goto free1_out; dev->dma_mem->virt_base = mem_base; dev->dma_mem->device_base = device_addr; dev->dma_mem->size = pages; dev->dma_mem->flags = flags; if (flags & DMA_MEMORY_MAP) return DMA_MEMORY_MAP; return DMA_MEMORY_IO; free1_out: kfree(dev->dma_mem); out: if (mem_base) iounmap(mem_base); return 0; } EXPORT_SYMBOL(dma_declare_coherent_memory); void dma_release_declared_memory(struct device *dev) { struct dma_coherent_mem *mem = dev->dma_mem; if (!mem) return; dev->dma_mem = NULL; iounmap(mem->virt_base); kfree(mem->bitmap); kfree(mem); } EXPORT_SYMBOL(dma_release_declared_memory); void *dma_mark_declared_memory_occupied(struct device *dev, dma_addr_t device_addr, size_t size) { struct dma_coherent_mem *mem = dev->dma_mem; int pos, err; |
ee7e5516b generic: per-devi... |
82 |
|
d2dc1f4ad dma: fix order ca... |
83 |
size += device_addr & ~PAGE_MASK; |
ee7e5516b generic: per-devi... |
84 85 86 87 88 |
if (!mem) return ERR_PTR(-EINVAL); pos = (device_addr - mem->device_base) >> PAGE_SHIFT; |
d2dc1f4ad dma: fix order ca... |
89 |
err = bitmap_allocate_region(mem->bitmap, pos, get_order(size)); |
ee7e5516b generic: per-devi... |
90 91 92 93 94 |
if (err != 0) return ERR_PTR(err); return mem->virt_base + (pos << PAGE_SHIFT); } EXPORT_SYMBOL(dma_mark_declared_memory_occupied); |
b6d4f7e3e dma-coherent: add... |
95 |
/** |
cb3952bf7 DMA: make dma-coh... |
96 |
* dma_alloc_from_coherent() - try to allocate memory from the per-device coherent area |
b6d4f7e3e dma-coherent: add... |
97 98 99 100 101 |
* * @dev: device from which we allocate memory * @size: size of requested memory area * @dma_handle: This will be filled with the correct dma handle * @ret: This pointer will be filled with the virtual address |
0609697ea dma-coherent: Res... |
102 |
* to allocated area. |
b6d4f7e3e dma-coherent: add... |
103 |
* |
cb3952bf7 DMA: make dma-coh... |
104 |
* This function should be only called from per-arch dma_alloc_coherent() |
b6d4f7e3e dma-coherent: add... |
105 106 107 |
* to support allocation from per-device coherent memory pools. * * Returns 0 if dma_alloc_coherent should continue with allocating from |
cb3952bf7 DMA: make dma-coh... |
108 |
* generic memory areas, or !0 if dma_alloc_coherent should return @ret. |
b6d4f7e3e dma-coherent: add... |
109 |
*/ |
ee7e5516b generic: per-devi... |
110 111 112 |
int dma_alloc_from_coherent(struct device *dev, ssize_t size, dma_addr_t *dma_handle, void **ret) { |
eccd83e11 dma_alloc_coheren... |
113 |
struct dma_coherent_mem *mem; |
ee7e5516b generic: per-devi... |
114 |
int order = get_order(size); |
eccd83e11 dma_alloc_coheren... |
115 |
int pageno; |
ee7e5516b generic: per-devi... |
116 |
|
eccd83e11 dma_alloc_coheren... |
117 118 119 120 121 |
if (!dev) return 0; mem = dev->dma_mem; if (!mem) return 0; |
0609697ea dma-coherent: Res... |
122 123 |
*ret = NULL; |
cdf57cab2 dma-coherent: per... |
124 |
if (unlikely(size > (mem->size << PAGE_SHIFT))) |
0609697ea dma-coherent: Res... |
125 |
goto err; |
eccd83e11 dma_alloc_coheren... |
126 127 |
pageno = bitmap_find_free_region(mem->bitmap, mem->size, order); |
0609697ea dma-coherent: Res... |
128 129 130 131 132 133 134 135 136 |
if (unlikely(pageno < 0)) goto err; /* * Memory was found in the per-device area. */ *dma_handle = mem->device_base + (pageno << PAGE_SHIFT); *ret = mem->virt_base + (pageno << PAGE_SHIFT); memset(*ret, 0, size); |
eccd83e11 dma_alloc_coheren... |
137 |
return 1; |
0609697ea dma-coherent: Res... |
138 139 140 141 142 143 144 145 |
err: /* * In the case where the allocation can not be satisfied from the * per-device area, try to fall back to generic memory if the * constraints allow it. */ return mem->flags & DMA_MEMORY_EXCLUSIVE; |
ee7e5516b generic: per-devi... |
146 |
} |
a38409fbb dma-coherent: exp... |
147 |
EXPORT_SYMBOL(dma_alloc_from_coherent); |
ee7e5516b generic: per-devi... |
148 |
|
b6d4f7e3e dma-coherent: add... |
149 |
/** |
cb3952bf7 DMA: make dma-coh... |
150 |
* dma_release_from_coherent() - try to free the memory allocated from per-device coherent memory pool |
b6d4f7e3e dma-coherent: add... |
151 152 153 154 155 156 157 158 |
* @dev: device from which the memory was allocated * @order: the order of pages allocated * @vaddr: virtual address of allocated pages * * This checks whether the memory was allocated from the per-device * coherent memory pool and if so, releases that memory. * * Returns 1 if we correctly released the memory, or 0 if |
cb3952bf7 DMA: make dma-coh... |
159 |
* dma_release_coherent() should proceed with releasing memory from |
b6d4f7e3e dma-coherent: add... |
160 161 |
* generic pools. */ |
ee7e5516b generic: per-devi... |
162 163 164 165 166 167 168 169 170 171 172 173 174 |
int dma_release_from_coherent(struct device *dev, int order, void *vaddr) { struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) { int page = (vaddr - mem->virt_base) >> PAGE_SHIFT; bitmap_release_region(mem->bitmap, page, order); return 1; } return 0; } |
a38409fbb dma-coherent: exp... |
175 |
EXPORT_SYMBOL(dma_release_from_coherent); |