diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/dma/Kconfig | 12 | ||||
-rw-r--r-- | kernel/dma/coherent.c | 13 | ||||
-rw-r--r-- | kernel/dma/mapping.c | 105 | ||||
-rw-r--r-- | kernel/dma/remap.c | 51 |
4 files changed, 115 insertions, 66 deletions
diff --git a/kernel/dma/Kconfig b/kernel/dma/Kconfig index 9decbba255fc..73c5c2b8e824 100644 --- a/kernel/dma/Kconfig +++ b/kernel/dma/Kconfig | |||
@@ -20,6 +20,15 @@ config ARCH_HAS_DMA_COHERENCE_H | |||
20 | config ARCH_HAS_DMA_SET_MASK | 20 | config ARCH_HAS_DMA_SET_MASK |
21 | bool | 21 | bool |
22 | 22 | ||
23 | # | ||
24 | # Select this option if the architecture needs special handling for | ||
25 | # DMA_ATTR_WRITE_COMBINE. Normally the "uncached" mapping should be what | ||
26 | # people thing of when saying write combine, so very few platforms should | ||
27 | # need to enable this. | ||
28 | # | ||
29 | config ARCH_HAS_DMA_WRITE_COMBINE | ||
30 | bool | ||
31 | |||
23 | config DMA_DECLARE_COHERENT | 32 | config DMA_DECLARE_COHERENT |
24 | bool | 33 | bool |
25 | 34 | ||
@@ -45,9 +54,6 @@ config ARCH_HAS_DMA_PREP_COHERENT | |||
45 | config ARCH_HAS_DMA_COHERENT_TO_PFN | 54 | config ARCH_HAS_DMA_COHERENT_TO_PFN |
46 | bool | 55 | bool |
47 | 56 | ||
48 | config ARCH_HAS_DMA_MMAP_PGPROT | ||
49 | bool | ||
50 | |||
51 | config ARCH_HAS_FORCE_DMA_UNENCRYPTED | 57 | config ARCH_HAS_FORCE_DMA_UNENCRYPTED |
52 | bool | 58 | bool |
53 | 59 | ||
diff --git a/kernel/dma/coherent.c b/kernel/dma/coherent.c index 29fd6590dc1e..545e3869b0e3 100644 --- a/kernel/dma/coherent.c +++ b/kernel/dma/coherent.c | |||
@@ -122,18 +122,6 @@ int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, | |||
122 | dma_release_coherent_memory(mem); | 122 | dma_release_coherent_memory(mem); |
123 | return ret; | 123 | return ret; |
124 | } | 124 | } |
125 | EXPORT_SYMBOL(dma_declare_coherent_memory); | ||
126 | |||
127 | void dma_release_declared_memory(struct device *dev) | ||
128 | { | ||
129 | struct dma_coherent_mem *mem = dev->dma_mem; | ||
130 | |||
131 | if (!mem) | ||
132 | return; | ||
133 | dma_release_coherent_memory(mem); | ||
134 | dev->dma_mem = NULL; | ||
135 | } | ||
136 | EXPORT_SYMBOL(dma_release_declared_memory); | ||
137 | 125 | ||
138 | static void *__dma_alloc_from_coherent(struct dma_coherent_mem *mem, | 126 | static void *__dma_alloc_from_coherent(struct dma_coherent_mem *mem, |
139 | ssize_t size, dma_addr_t *dma_handle) | 127 | ssize_t size, dma_addr_t *dma_handle) |
@@ -288,7 +276,6 @@ int dma_mmap_from_dev_coherent(struct device *dev, struct vm_area_struct *vma, | |||
288 | 276 | ||
289 | return __dma_mmap_from_coherent(mem, vma, vaddr, size, ret); | 277 | return __dma_mmap_from_coherent(mem, vma, vaddr, size, ret); |
290 | } | 278 | } |
291 | EXPORT_SYMBOL(dma_mmap_from_dev_coherent); | ||
292 | 279 | ||
293 | int dma_mmap_from_global_coherent(struct vm_area_struct *vma, void *vaddr, | 280 | int dma_mmap_from_global_coherent(struct vm_area_struct *vma, void *vaddr, |
294 | size_t size, int *ret) | 281 | size_t size, int *ret) |
diff --git a/kernel/dma/mapping.c b/kernel/dma/mapping.c index b0038ca3aa92..64a3d294f4b4 100644 --- a/kernel/dma/mapping.c +++ b/kernel/dma/mapping.c | |||
@@ -136,17 +136,29 @@ int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, | |||
136 | return ret; | 136 | return ret; |
137 | } | 137 | } |
138 | 138 | ||
139 | /* | ||
140 | * The whole dma_get_sgtable() idea is fundamentally unsafe - it seems | ||
141 | * that the intention is to allow exporting memory allocated via the | ||
142 | * coherent DMA APIs through the dma_buf API, which only accepts a | ||
143 | * scattertable. This presents a couple of problems: | ||
144 | * 1. Not all memory allocated via the coherent DMA APIs is backed by | ||
145 | * a struct page | ||
146 | * 2. Passing coherent DMA memory into the streaming APIs is not allowed | ||
147 | * as we will try to flush the memory through a different alias to that | ||
148 | * actually being used (and the flushes are redundant.) | ||
149 | */ | ||
139 | int dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt, | 150 | int dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt, |
140 | void *cpu_addr, dma_addr_t dma_addr, size_t size, | 151 | void *cpu_addr, dma_addr_t dma_addr, size_t size, |
141 | unsigned long attrs) | 152 | unsigned long attrs) |
142 | { | 153 | { |
143 | const struct dma_map_ops *ops = get_dma_ops(dev); | 154 | const struct dma_map_ops *ops = get_dma_ops(dev); |
144 | 155 | ||
145 | if (!dma_is_direct(ops) && ops->get_sgtable) | 156 | if (dma_is_direct(ops)) |
146 | return ops->get_sgtable(dev, sgt, cpu_addr, dma_addr, size, | 157 | return dma_common_get_sgtable(dev, sgt, cpu_addr, dma_addr, |
147 | attrs); | 158 | size, attrs); |
148 | return dma_common_get_sgtable(dev, sgt, cpu_addr, dma_addr, size, | 159 | if (!ops->get_sgtable) |
149 | attrs); | 160 | return -ENXIO; |
161 | return ops->get_sgtable(dev, sgt, cpu_addr, dma_addr, size, attrs); | ||
150 | } | 162 | } |
151 | EXPORT_SYMBOL(dma_get_sgtable_attrs); | 163 | EXPORT_SYMBOL(dma_get_sgtable_attrs); |
152 | 164 | ||
@@ -161,9 +173,11 @@ pgprot_t dma_pgprot(struct device *dev, pgprot_t prot, unsigned long attrs) | |||
161 | (IS_ENABLED(CONFIG_DMA_NONCOHERENT_CACHE_SYNC) && | 173 | (IS_ENABLED(CONFIG_DMA_NONCOHERENT_CACHE_SYNC) && |
162 | (attrs & DMA_ATTR_NON_CONSISTENT))) | 174 | (attrs & DMA_ATTR_NON_CONSISTENT))) |
163 | return prot; | 175 | return prot; |
164 | if (IS_ENABLED(CONFIG_ARCH_HAS_DMA_MMAP_PGPROT)) | 176 | #ifdef CONFIG_ARCH_HAS_DMA_WRITE_COMBINE |
165 | return arch_dma_mmap_pgprot(dev, prot, attrs); | 177 | if (attrs & DMA_ATTR_WRITE_COMBINE) |
166 | return pgprot_noncached(prot); | 178 | return pgprot_writecombine(prot); |
179 | #endif | ||
180 | return pgprot_dmacoherent(prot); | ||
167 | } | 181 | } |
168 | #endif /* CONFIG_MMU */ | 182 | #endif /* CONFIG_MMU */ |
169 | 183 | ||
@@ -174,7 +188,7 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, | |||
174 | void *cpu_addr, dma_addr_t dma_addr, size_t size, | 188 | void *cpu_addr, dma_addr_t dma_addr, size_t size, |
175 | unsigned long attrs) | 189 | unsigned long attrs) |
176 | { | 190 | { |
177 | #ifndef CONFIG_ARCH_NO_COHERENT_DMA_MMAP | 191 | #ifdef CONFIG_MMU |
178 | unsigned long user_count = vma_pages(vma); | 192 | unsigned long user_count = vma_pages(vma); |
179 | unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; | 193 | unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; |
180 | unsigned long off = vma->vm_pgoff; | 194 | unsigned long off = vma->vm_pgoff; |
@@ -205,8 +219,29 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, | |||
205 | user_count << PAGE_SHIFT, vma->vm_page_prot); | 219 | user_count << PAGE_SHIFT, vma->vm_page_prot); |
206 | #else | 220 | #else |
207 | return -ENXIO; | 221 | return -ENXIO; |
208 | #endif /* !CONFIG_ARCH_NO_COHERENT_DMA_MMAP */ | 222 | #endif /* CONFIG_MMU */ |
223 | } | ||
224 | |||
225 | /** | ||
226 | * dma_can_mmap - check if a given device supports dma_mmap_* | ||
227 | * @dev: device to check | ||
228 | * | ||
229 | * Returns %true if @dev supports dma_mmap_coherent() and dma_mmap_attrs() to | ||
230 | * map DMA allocations to userspace. | ||
231 | */ | ||
232 | bool dma_can_mmap(struct device *dev) | ||
233 | { | ||
234 | const struct dma_map_ops *ops = get_dma_ops(dev); | ||
235 | |||
236 | if (dma_is_direct(ops)) { | ||
237 | return IS_ENABLED(CONFIG_MMU) && | ||
238 | (dev_is_dma_coherent(dev) || | ||
239 | IS_ENABLED(CONFIG_ARCH_HAS_DMA_COHERENT_TO_PFN)); | ||
240 | } | ||
241 | |||
242 | return ops->mmap != NULL; | ||
209 | } | 243 | } |
244 | EXPORT_SYMBOL_GPL(dma_can_mmap); | ||
210 | 245 | ||
211 | /** | 246 | /** |
212 | * dma_mmap_attrs - map a coherent DMA allocation into user space | 247 | * dma_mmap_attrs - map a coherent DMA allocation into user space |
@@ -227,31 +262,15 @@ int dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, | |||
227 | { | 262 | { |
228 | const struct dma_map_ops *ops = get_dma_ops(dev); | 263 | const struct dma_map_ops *ops = get_dma_ops(dev); |
229 | 264 | ||
230 | if (!dma_is_direct(ops) && ops->mmap) | 265 | if (dma_is_direct(ops)) |
231 | return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs); | 266 | return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size, |
232 | return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size, attrs); | 267 | attrs); |
268 | if (!ops->mmap) | ||
269 | return -ENXIO; | ||
270 | return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs); | ||
233 | } | 271 | } |
234 | EXPORT_SYMBOL(dma_mmap_attrs); | 272 | EXPORT_SYMBOL(dma_mmap_attrs); |
235 | 273 | ||
236 | static u64 dma_default_get_required_mask(struct device *dev) | ||
237 | { | ||
238 | u32 low_totalram = ((max_pfn - 1) << PAGE_SHIFT); | ||
239 | u32 high_totalram = ((max_pfn - 1) >> (32 - PAGE_SHIFT)); | ||
240 | u64 mask; | ||
241 | |||
242 | if (!high_totalram) { | ||
243 | /* convert to mask just covering totalram */ | ||
244 | low_totalram = (1 << (fls(low_totalram) - 1)); | ||
245 | low_totalram += low_totalram - 1; | ||
246 | mask = low_totalram; | ||
247 | } else { | ||
248 | high_totalram = (1 << (fls(high_totalram) - 1)); | ||
249 | high_totalram += high_totalram - 1; | ||
250 | mask = (((u64)high_totalram) << 32) + 0xffffffff; | ||
251 | } | ||
252 | return mask; | ||
253 | } | ||
254 | |||
255 | u64 dma_get_required_mask(struct device *dev) | 274 | u64 dma_get_required_mask(struct device *dev) |
256 | { | 275 | { |
257 | const struct dma_map_ops *ops = get_dma_ops(dev); | 276 | const struct dma_map_ops *ops = get_dma_ops(dev); |
@@ -260,7 +279,16 @@ u64 dma_get_required_mask(struct device *dev) | |||
260 | return dma_direct_get_required_mask(dev); | 279 | return dma_direct_get_required_mask(dev); |
261 | if (ops->get_required_mask) | 280 | if (ops->get_required_mask) |
262 | return ops->get_required_mask(dev); | 281 | return ops->get_required_mask(dev); |
263 | return dma_default_get_required_mask(dev); | 282 | |
283 | /* | ||
284 | * We require every DMA ops implementation to at least support a 32-bit | ||
285 | * DMA mask (and use bounce buffering if that isn't supported in | ||
286 | * hardware). As the direct mapping code has its own routine to | ||
287 | * actually report an optimal mask we default to 32-bit here as that | ||
288 | * is the right thing for most IOMMUs, and at least not actively | ||
289 | * harmful in general. | ||
290 | */ | ||
291 | return DMA_BIT_MASK(32); | ||
264 | } | 292 | } |
265 | EXPORT_SYMBOL_GPL(dma_get_required_mask); | 293 | EXPORT_SYMBOL_GPL(dma_get_required_mask); |
266 | 294 | ||
@@ -405,3 +433,14 @@ size_t dma_max_mapping_size(struct device *dev) | |||
405 | return size; | 433 | return size; |
406 | } | 434 | } |
407 | EXPORT_SYMBOL_GPL(dma_max_mapping_size); | 435 | EXPORT_SYMBOL_GPL(dma_max_mapping_size); |
436 | |||
437 | unsigned long dma_get_merge_boundary(struct device *dev) | ||
438 | { | ||
439 | const struct dma_map_ops *ops = get_dma_ops(dev); | ||
440 | |||
441 | if (!ops || !ops->get_merge_boundary) | ||
442 | return 0; /* can't merge */ | ||
443 | |||
444 | return ops->get_merge_boundary(dev); | ||
445 | } | ||
446 | EXPORT_SYMBOL_GPL(dma_get_merge_boundary); | ||
diff --git a/kernel/dma/remap.c b/kernel/dma/remap.c index ffe78f0b2fe4..ca4e5d44b571 100644 --- a/kernel/dma/remap.c +++ b/kernel/dma/remap.c | |||
@@ -11,13 +11,21 @@ | |||
11 | #include <linux/slab.h> | 11 | #include <linux/slab.h> |
12 | #include <linux/vmalloc.h> | 12 | #include <linux/vmalloc.h> |
13 | 13 | ||
14 | struct page **dma_common_find_pages(void *cpu_addr) | ||
15 | { | ||
16 | struct vm_struct *area = find_vm_area(cpu_addr); | ||
17 | |||
18 | if (!area || area->flags != VM_DMA_COHERENT) | ||
19 | return NULL; | ||
20 | return area->pages; | ||
21 | } | ||
22 | |||
14 | static struct vm_struct *__dma_common_pages_remap(struct page **pages, | 23 | static struct vm_struct *__dma_common_pages_remap(struct page **pages, |
15 | size_t size, unsigned long vm_flags, pgprot_t prot, | 24 | size_t size, pgprot_t prot, const void *caller) |
16 | const void *caller) | ||
17 | { | 25 | { |
18 | struct vm_struct *area; | 26 | struct vm_struct *area; |
19 | 27 | ||
20 | area = get_vm_area_caller(size, vm_flags, caller); | 28 | area = get_vm_area_caller(size, VM_DMA_COHERENT, caller); |
21 | if (!area) | 29 | if (!area) |
22 | return NULL; | 30 | return NULL; |
23 | 31 | ||
@@ -34,12 +42,11 @@ static struct vm_struct *__dma_common_pages_remap(struct page **pages, | |||
34 | * Cannot be used in non-sleeping contexts | 42 | * Cannot be used in non-sleeping contexts |
35 | */ | 43 | */ |
36 | void *dma_common_pages_remap(struct page **pages, size_t size, | 44 | void *dma_common_pages_remap(struct page **pages, size_t size, |
37 | unsigned long vm_flags, pgprot_t prot, | 45 | pgprot_t prot, const void *caller) |
38 | const void *caller) | ||
39 | { | 46 | { |
40 | struct vm_struct *area; | 47 | struct vm_struct *area; |
41 | 48 | ||
42 | area = __dma_common_pages_remap(pages, size, vm_flags, prot, caller); | 49 | area = __dma_common_pages_remap(pages, size, prot, caller); |
43 | if (!area) | 50 | if (!area) |
44 | return NULL; | 51 | return NULL; |
45 | 52 | ||
@@ -53,7 +60,6 @@ void *dma_common_pages_remap(struct page **pages, size_t size, | |||
53 | * Cannot be used in non-sleeping contexts | 60 | * Cannot be used in non-sleeping contexts |
54 | */ | 61 | */ |
55 | void *dma_common_contiguous_remap(struct page *page, size_t size, | 62 | void *dma_common_contiguous_remap(struct page *page, size_t size, |
56 | unsigned long vm_flags, | ||
57 | pgprot_t prot, const void *caller) | 63 | pgprot_t prot, const void *caller) |
58 | { | 64 | { |
59 | int i; | 65 | int i; |
@@ -67,7 +73,7 @@ void *dma_common_contiguous_remap(struct page *page, size_t size, | |||
67 | for (i = 0; i < (size >> PAGE_SHIFT); i++) | 73 | for (i = 0; i < (size >> PAGE_SHIFT); i++) |
68 | pages[i] = nth_page(page, i); | 74 | pages[i] = nth_page(page, i); |
69 | 75 | ||
70 | area = __dma_common_pages_remap(pages, size, vm_flags, prot, caller); | 76 | area = __dma_common_pages_remap(pages, size, prot, caller); |
71 | 77 | ||
72 | kfree(pages); | 78 | kfree(pages); |
73 | 79 | ||
@@ -79,11 +85,11 @@ void *dma_common_contiguous_remap(struct page *page, size_t size, | |||
79 | /* | 85 | /* |
80 | * Unmaps a range previously mapped by dma_common_*_remap | 86 | * Unmaps a range previously mapped by dma_common_*_remap |
81 | */ | 87 | */ |
82 | void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags) | 88 | void dma_common_free_remap(void *cpu_addr, size_t size) |
83 | { | 89 | { |
84 | struct vm_struct *area = find_vm_area(cpu_addr); | 90 | struct page **pages = dma_common_find_pages(cpu_addr); |
85 | 91 | ||
86 | if (!area || (area->flags & vm_flags) != vm_flags) { | 92 | if (!pages) { |
87 | WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr); | 93 | WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr); |
88 | return; | 94 | return; |
89 | } | 95 | } |
@@ -105,7 +111,16 @@ static int __init early_coherent_pool(char *p) | |||
105 | } | 111 | } |
106 | early_param("coherent_pool", early_coherent_pool); | 112 | early_param("coherent_pool", early_coherent_pool); |
107 | 113 | ||
108 | int __init dma_atomic_pool_init(gfp_t gfp, pgprot_t prot) | 114 | static gfp_t dma_atomic_pool_gfp(void) |
115 | { | ||
116 | if (IS_ENABLED(CONFIG_ZONE_DMA)) | ||
117 | return GFP_DMA; | ||
118 | if (IS_ENABLED(CONFIG_ZONE_DMA32)) | ||
119 | return GFP_DMA32; | ||
120 | return GFP_KERNEL; | ||
121 | } | ||
122 | |||
123 | static int __init dma_atomic_pool_init(void) | ||
109 | { | 124 | { |
110 | unsigned int pool_size_order = get_order(atomic_pool_size); | 125 | unsigned int pool_size_order = get_order(atomic_pool_size); |
111 | unsigned long nr_pages = atomic_pool_size >> PAGE_SHIFT; | 126 | unsigned long nr_pages = atomic_pool_size >> PAGE_SHIFT; |
@@ -117,7 +132,7 @@ int __init dma_atomic_pool_init(gfp_t gfp, pgprot_t prot) | |||
117 | page = dma_alloc_from_contiguous(NULL, nr_pages, | 132 | page = dma_alloc_from_contiguous(NULL, nr_pages, |
118 | pool_size_order, false); | 133 | pool_size_order, false); |
119 | else | 134 | else |
120 | page = alloc_pages(gfp, pool_size_order); | 135 | page = alloc_pages(dma_atomic_pool_gfp(), pool_size_order); |
121 | if (!page) | 136 | if (!page) |
122 | goto out; | 137 | goto out; |
123 | 138 | ||
@@ -127,8 +142,9 @@ int __init dma_atomic_pool_init(gfp_t gfp, pgprot_t prot) | |||
127 | if (!atomic_pool) | 142 | if (!atomic_pool) |
128 | goto free_page; | 143 | goto free_page; |
129 | 144 | ||
130 | addr = dma_common_contiguous_remap(page, atomic_pool_size, VM_USERMAP, | 145 | addr = dma_common_contiguous_remap(page, atomic_pool_size, |
131 | prot, __builtin_return_address(0)); | 146 | pgprot_dmacoherent(PAGE_KERNEL), |
147 | __builtin_return_address(0)); | ||
132 | if (!addr) | 148 | if (!addr) |
133 | goto destroy_genpool; | 149 | goto destroy_genpool; |
134 | 150 | ||
@@ -143,7 +159,7 @@ int __init dma_atomic_pool_init(gfp_t gfp, pgprot_t prot) | |||
143 | return 0; | 159 | return 0; |
144 | 160 | ||
145 | remove_mapping: | 161 | remove_mapping: |
146 | dma_common_free_remap(addr, atomic_pool_size, VM_USERMAP); | 162 | dma_common_free_remap(addr, atomic_pool_size); |
147 | destroy_genpool: | 163 | destroy_genpool: |
148 | gen_pool_destroy(atomic_pool); | 164 | gen_pool_destroy(atomic_pool); |
149 | atomic_pool = NULL; | 165 | atomic_pool = NULL; |
@@ -155,6 +171,7 @@ out: | |||
155 | atomic_pool_size / 1024); | 171 | atomic_pool_size / 1024); |
156 | return -ENOMEM; | 172 | return -ENOMEM; |
157 | } | 173 | } |
174 | postcore_initcall(dma_atomic_pool_init); | ||
158 | 175 | ||
159 | bool dma_in_atomic_pool(void *start, size_t size) | 176 | bool dma_in_atomic_pool(void *start, size_t size) |
160 | { | 177 | { |
@@ -217,7 +234,7 @@ void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, | |||
217 | arch_dma_prep_coherent(page, size); | 234 | arch_dma_prep_coherent(page, size); |
218 | 235 | ||
219 | /* create a coherent mapping */ | 236 | /* create a coherent mapping */ |
220 | ret = dma_common_contiguous_remap(page, size, VM_USERMAP, | 237 | ret = dma_common_contiguous_remap(page, size, |
221 | dma_pgprot(dev, PAGE_KERNEL, attrs), | 238 | dma_pgprot(dev, PAGE_KERNEL, attrs), |
222 | __builtin_return_address(0)); | 239 | __builtin_return_address(0)); |
223 | if (!ret) { | 240 | if (!ret) { |