diff options
Diffstat (limited to 'kernel/dma/mapping.c')
| -rw-r--r-- | kernel/dma/mapping.c | 71 |
1 files changed, 37 insertions, 34 deletions
diff --git a/kernel/dma/mapping.c b/kernel/dma/mapping.c index d2a92ddaac4d..58dec7a92b7b 100644 --- a/kernel/dma/mapping.c +++ b/kernel/dma/mapping.c | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include <linux/acpi.h> | 9 | #include <linux/acpi.h> |
| 10 | #include <linux/dma-mapping.h> | 10 | #include <linux/dma-noncoherent.h> |
| 11 | #include <linux/export.h> | 11 | #include <linux/export.h> |
| 12 | #include <linux/gfp.h> | 12 | #include <linux/gfp.h> |
| 13 | #include <linux/of_device.h> | 13 | #include <linux/of_device.h> |
| @@ -202,17 +202,26 @@ EXPORT_SYMBOL(dmam_release_declared_memory); | |||
| 202 | * Create scatter-list for the already allocated DMA buffer. | 202 | * Create scatter-list for the already allocated DMA buffer. |
| 203 | */ | 203 | */ |
| 204 | int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, | 204 | int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, |
| 205 | void *cpu_addr, dma_addr_t handle, size_t size) | 205 | void *cpu_addr, dma_addr_t dma_addr, size_t size, |
| 206 | unsigned long attrs) | ||
| 206 | { | 207 | { |
| 207 | struct page *page = virt_to_page(cpu_addr); | 208 | struct page *page; |
| 208 | int ret; | 209 | int ret; |
| 209 | 210 | ||
| 210 | ret = sg_alloc_table(sgt, 1, GFP_KERNEL); | 211 | if (!dev_is_dma_coherent(dev)) { |
| 211 | if (unlikely(ret)) | 212 | if (!IS_ENABLED(CONFIG_ARCH_HAS_DMA_COHERENT_TO_PFN)) |
| 212 | return ret; | 213 | return -ENXIO; |
| 213 | 214 | ||
| 214 | sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0); | 215 | page = pfn_to_page(arch_dma_coherent_to_pfn(dev, cpu_addr, |
| 215 | return 0; | 216 | dma_addr)); |
| 217 | } else { | ||
| 218 | page = virt_to_page(cpu_addr); | ||
| 219 | } | ||
| 220 | |||
| 221 | ret = sg_alloc_table(sgt, 1, GFP_KERNEL); | ||
| 222 | if (!ret) | ||
| 223 | sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0); | ||
| 224 | return ret; | ||
| 216 | } | 225 | } |
| 217 | EXPORT_SYMBOL(dma_common_get_sgtable); | 226 | EXPORT_SYMBOL(dma_common_get_sgtable); |
| 218 | 227 | ||
| @@ -220,27 +229,37 @@ EXPORT_SYMBOL(dma_common_get_sgtable); | |||
| 220 | * Create userspace mapping for the DMA-coherent memory. | 229 | * Create userspace mapping for the DMA-coherent memory. |
| 221 | */ | 230 | */ |
| 222 | int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, | 231 | int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, |
| 223 | void *cpu_addr, dma_addr_t dma_addr, size_t size) | 232 | void *cpu_addr, dma_addr_t dma_addr, size_t size, |
| 233 | unsigned long attrs) | ||
| 224 | { | 234 | { |
| 225 | int ret = -ENXIO; | ||
| 226 | #ifndef CONFIG_ARCH_NO_COHERENT_DMA_MMAP | 235 | #ifndef CONFIG_ARCH_NO_COHERENT_DMA_MMAP |
| 227 | unsigned long user_count = vma_pages(vma); | 236 | unsigned long user_count = vma_pages(vma); |
| 228 | unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; | 237 | unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; |
| 229 | unsigned long off = vma->vm_pgoff; | 238 | unsigned long off = vma->vm_pgoff; |
| 239 | unsigned long pfn; | ||
| 240 | int ret = -ENXIO; | ||
| 230 | 241 | ||
| 231 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | 242 | vma->vm_page_prot = arch_dma_mmap_pgprot(dev, vma->vm_page_prot, attrs); |
| 232 | 243 | ||
| 233 | if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret)) | 244 | if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret)) |
| 234 | return ret; | 245 | return ret; |
| 235 | 246 | ||
| 236 | if (off < count && user_count <= (count - off)) | 247 | if (off >= count || user_count > count - off) |
| 237 | ret = remap_pfn_range(vma, vma->vm_start, | 248 | return -ENXIO; |
| 238 | page_to_pfn(virt_to_page(cpu_addr)) + off, | ||
| 239 | user_count << PAGE_SHIFT, | ||
| 240 | vma->vm_page_prot); | ||
| 241 | #endif /* !CONFIG_ARCH_NO_COHERENT_DMA_MMAP */ | ||
| 242 | 249 | ||
| 243 | return ret; | 250 | if (!dev_is_dma_coherent(dev)) { |
| 251 | if (!IS_ENABLED(CONFIG_ARCH_HAS_DMA_COHERENT_TO_PFN)) | ||
| 252 | return -ENXIO; | ||
| 253 | pfn = arch_dma_coherent_to_pfn(dev, cpu_addr, dma_addr); | ||
| 254 | } else { | ||
| 255 | pfn = page_to_pfn(virt_to_page(cpu_addr)); | ||
| 256 | } | ||
| 257 | |||
| 258 | return remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff, | ||
| 259 | user_count << PAGE_SHIFT, vma->vm_page_prot); | ||
| 260 | #else | ||
| 261 | return -ENXIO; | ||
| 262 | #endif /* !CONFIG_ARCH_NO_COHERENT_DMA_MMAP */ | ||
| 244 | } | 263 | } |
| 245 | EXPORT_SYMBOL(dma_common_mmap); | 264 | EXPORT_SYMBOL(dma_common_mmap); |
| 246 | 265 | ||
| @@ -327,19 +346,3 @@ void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags) | |||
| 327 | vunmap(cpu_addr); | 346 | vunmap(cpu_addr); |
| 328 | } | 347 | } |
| 329 | #endif | 348 | #endif |
| 330 | |||
| 331 | /* | ||
| 332 | * enables DMA API use for a device | ||
| 333 | */ | ||
| 334 | int dma_configure(struct device *dev) | ||
| 335 | { | ||
| 336 | if (dev->bus->dma_configure) | ||
| 337 | return dev->bus->dma_configure(dev); | ||
| 338 | return 0; | ||
| 339 | } | ||
| 340 | |||
| 341 | void dma_deconfigure(struct device *dev) | ||
| 342 | { | ||
| 343 | of_dma_deconfigure(dev); | ||
| 344 | acpi_dma_deconfigure(dev); | ||
| 345 | } | ||
