1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Helpers for DMA ops implementations. These generally rely on the fact that 4 * the allocated memory contains normal pages in the direct kernel mapping. 5 */ 6 #include <linux/dma-noncoherent.h> 7 8 /* 9 * Create scatter-list for the already allocated DMA buffer. 10 */ 11 int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, 12 void *cpu_addr, dma_addr_t dma_addr, size_t size, 13 unsigned long attrs) 14 { 15 struct page *page = virt_to_page(cpu_addr); 16 int ret; 17 18 ret = sg_alloc_table(sgt, 1, GFP_KERNEL); 19 if (!ret) 20 sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0); 21 return ret; 22 } 23 24 /* 25 * Create userspace mapping for the DMA-coherent memory. 26 */ 27 int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, 28 void *cpu_addr, dma_addr_t dma_addr, size_t size, 29 unsigned long attrs) 30 { 31 #ifdef CONFIG_MMU 32 unsigned long user_count = vma_pages(vma); 33 unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; 34 unsigned long off = vma->vm_pgoff; 35 int ret = -ENXIO; 36 37 vma->vm_page_prot = dma_pgprot(dev, vma->vm_page_prot, attrs); 38 39 if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret)) 40 return ret; 41 42 if (off >= count || user_count > count - off) 43 return -ENXIO; 44 45 return remap_pfn_range(vma, vma->vm_start, 46 page_to_pfn(virt_to_page(cpu_addr)) + vma->vm_pgoff, 47 user_count << PAGE_SHIFT, vma->vm_page_prot); 48 #else 49 return -ENXIO; 50 #endif /* CONFIG_MMU */ 51 } 52