Blame view
kernel/dma-coherent.c
4.4 KB
ee7e5516b generic: per-devi... |
1 2 3 4 5 6 7 8 9 10 11 12 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 |
/* * Coherent per-device memory handling. * Borrowed from i386 */ #include <linux/kernel.h> #include <linux/dma-mapping.h> struct dma_coherent_mem { void *virt_base; u32 device_base; 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... |
80 |
|
d2dc1f4ad dma: fix order ca... |
81 |
size += device_addr & ~PAGE_MASK; |
ee7e5516b generic: per-devi... |
82 83 84 85 86 |
if (!mem) return ERR_PTR(-EINVAL); pos = (device_addr - mem->device_base) >> PAGE_SHIFT; |
d2dc1f4ad dma: fix order ca... |
87 |
err = bitmap_allocate_region(mem->bitmap, pos, get_order(size)); |
ee7e5516b generic: per-devi... |
88 89 90 91 92 |
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... |
93 |
/** |
cb3952bf7 DMA: make dma-coh... |
94 |
* dma_alloc_from_coherent() - try to allocate memory from the per-device coherent area |
b6d4f7e3e dma-coherent: add... |
95 96 97 98 99 |
* * @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... |
100 |
* to allocated area. |
b6d4f7e3e dma-coherent: add... |
101 |
* |
cb3952bf7 DMA: make dma-coh... |
102 |
* This function should be only called from per-arch dma_alloc_coherent() |
b6d4f7e3e dma-coherent: add... |
103 104 105 |
* 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... |
106 |
* generic memory areas, or !0 if dma_alloc_coherent should return @ret. |
b6d4f7e3e dma-coherent: add... |
107 |
*/ |
ee7e5516b generic: per-devi... |
108 109 110 |
int dma_alloc_from_coherent(struct device *dev, ssize_t size, dma_addr_t *dma_handle, void **ret) { |
eccd83e11 dma_alloc_coheren... |
111 |
struct dma_coherent_mem *mem; |
ee7e5516b generic: per-devi... |
112 |
int order = get_order(size); |
eccd83e11 dma_alloc_coheren... |
113 |
int pageno; |
ee7e5516b generic: per-devi... |
114 |
|
eccd83e11 dma_alloc_coheren... |
115 116 117 118 119 |
if (!dev) return 0; mem = dev->dma_mem; if (!mem) return 0; |
0609697ea dma-coherent: Res... |
120 121 |
*ret = NULL; |
cdf57cab2 dma-coherent: per... |
122 |
if (unlikely(size > (mem->size << PAGE_SHIFT))) |
0609697ea dma-coherent: Res... |
123 |
goto err; |
eccd83e11 dma_alloc_coheren... |
124 125 |
pageno = bitmap_find_free_region(mem->bitmap, mem->size, order); |
0609697ea dma-coherent: Res... |
126 127 128 129 130 131 132 133 134 |
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... |
135 |
return 1; |
0609697ea dma-coherent: Res... |
136 137 138 139 140 141 142 143 |
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... |
144 |
} |
a38409fbb dma-coherent: exp... |
145 |
EXPORT_SYMBOL(dma_alloc_from_coherent); |
ee7e5516b generic: per-devi... |
146 |
|
b6d4f7e3e dma-coherent: add... |
147 |
/** |
cb3952bf7 DMA: make dma-coh... |
148 |
* dma_release_from_coherent() - try to free the memory allocated from per-device coherent memory pool |
b6d4f7e3e dma-coherent: add... |
149 150 151 152 153 154 155 156 |
* @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... |
157 |
* dma_release_coherent() should proceed with releasing memory from |
b6d4f7e3e dma-coherent: add... |
158 159 |
* generic pools. */ |
ee7e5516b generic: per-devi... |
160 161 162 163 164 165 166 167 168 169 170 171 172 |
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... |
173 |
EXPORT_SYMBOL(dma_release_from_coherent); |