summaryrefslogtreecommitdiffstats
path: root/kernel/dma/ops_helpers.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2020-09-01 13:34:33 +0200
committerChristoph Hellwig <hch@lst.de>2020-09-25 06:20:47 +0200
commitefa70f2fdc842e63a0a13223e0e83cedcc2117f1 (patch)
treeef21550627a0a50be9edf10c53542f9c59a61896 /kernel/dma/ops_helpers.c
parent5a84292271402cffe0717bc58e2ad9a0c7977272 (diff)
downloadlinux-stable-efa70f2fdc842e63a0a13223e0e83cedcc2117f1.tar.gz
linux-stable-efa70f2fdc842e63a0a13223e0e83cedcc2117f1.tar.bz2
linux-stable-efa70f2fdc842e63a0a13223e0e83cedcc2117f1.zip
dma-mapping: add a new dma_alloc_pages API
This API is the equivalent of alloc_pages, except that the returned memory is guaranteed to be DMA addressable by the passed in device. The implementation will also be used to provide a more sensible replacement for DMA_ATTR_NON_CONSISTENT flag. Additionally dma_alloc_noncoherent is switched over to use dma_alloc_pages as its backend. Signed-off-by: Christoph Hellwig <hch@lst.de> Acked-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de> (MIPS part)
Diffstat (limited to 'kernel/dma/ops_helpers.c')
-rw-r--r--kernel/dma/ops_helpers.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/kernel/dma/ops_helpers.c b/kernel/dma/ops_helpers.c
index e443c69be429..5828e5e01b79 100644
--- a/kernel/dma/ops_helpers.c
+++ b/kernel/dma/ops_helpers.c
@@ -3,6 +3,7 @@
* Helpers for DMA ops implementations. These generally rely on the fact that
* the allocated memory contains normal pages in the direct kernel mapping.
*/
+#include <linux/dma-contiguous.h>
#include <linux/dma-noncoherent.h>
/*
@@ -49,3 +50,37 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
return -ENXIO;
#endif /* CONFIG_MMU */
}
+
+struct page *dma_common_alloc_pages(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, enum dma_data_direction dir, gfp_t gfp)
+{
+ const struct dma_map_ops *ops = get_dma_ops(dev);
+ struct page *page;
+
+ page = dma_alloc_contiguous(dev, size, gfp);
+ if (!page)
+ page = alloc_pages_node(dev_to_node(dev), gfp, get_order(size));
+ if (!page)
+ return NULL;
+
+ *dma_handle = ops->map_page(dev, page, 0, size, dir,
+ DMA_ATTR_SKIP_CPU_SYNC);
+ if (*dma_handle == DMA_MAPPING_ERROR) {
+ dma_free_contiguous(dev, page, size);
+ return NULL;
+ }
+
+ memset(page_address(page), 0, size);
+ return page;
+}
+
+void dma_common_free_pages(struct device *dev, size_t size, struct page *page,
+ dma_addr_t dma_handle, enum dma_data_direction dir)
+{
+ const struct dma_map_ops *ops = get_dma_ops(dev);
+
+ if (ops->unmap_page)
+ ops->unmap_page(dev, dma_handle, size, dir,
+ DMA_ATTR_SKIP_CPU_SYNC);
+ dma_free_contiguous(dev, page, size);
+}