1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * DMA operations that map to virtual addresses without flushing memory.
4  */
5 #include <linux/export.h>
6 #include <linux/mm.h>
7 #include <linux/dma-mapping.h>
8 #include <linux/scatterlist.h>
9 
dma_virt_alloc(struct device * dev,size_t size,dma_addr_t * dma_handle,gfp_t gfp,unsigned long attrs)10 static void *dma_virt_alloc(struct device *dev, size_t size,
11 			    dma_addr_t *dma_handle, gfp_t gfp,
12 			    unsigned long attrs)
13 {
14 	void *ret;
15 
16 	ret = (void *)__get_free_pages(gfp | __GFP_ZERO, get_order(size));
17 	if (ret)
18 		*dma_handle = (uintptr_t)ret;
19 	return ret;
20 }
21 
dma_virt_free(struct device * dev,size_t size,void * cpu_addr,dma_addr_t dma_addr,unsigned long attrs)22 static void dma_virt_free(struct device *dev, size_t size,
23 			  void *cpu_addr, dma_addr_t dma_addr,
24 			  unsigned long attrs)
25 {
26 	free_pages((unsigned long)cpu_addr, get_order(size));
27 }
28 
dma_virt_map_page(struct device * dev,struct page * page,unsigned long offset,size_t size,enum dma_data_direction dir,unsigned long attrs)29 static dma_addr_t dma_virt_map_page(struct device *dev, struct page *page,
30 				    unsigned long offset, size_t size,
31 				    enum dma_data_direction dir,
32 				    unsigned long attrs)
33 {
34 	return (uintptr_t)(page_address(page) + offset);
35 }
36 
dma_virt_map_sg(struct device * dev,struct scatterlist * sgl,int nents,enum dma_data_direction dir,unsigned long attrs)37 static int dma_virt_map_sg(struct device *dev, struct scatterlist *sgl,
38 			   int nents, enum dma_data_direction dir,
39 			   unsigned long attrs)
40 {
41 	int i;
42 	struct scatterlist *sg;
43 
44 	for_each_sg(sgl, sg, nents, i) {
45 		BUG_ON(!sg_page(sg));
46 		sg_dma_address(sg) = (uintptr_t)sg_virt(sg);
47 		sg_dma_len(sg) = sg->length;
48 	}
49 
50 	return nents;
51 }
52 
53 const struct dma_map_ops dma_virt_ops = {
54 	.alloc			= dma_virt_alloc,
55 	.free			= dma_virt_free,
56 	.map_page		= dma_virt_map_page,
57 	.map_sg			= dma_virt_map_sg,
58 };
59 EXPORT_SYMBOL(dma_virt_ops);
60