Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: dma-mapping: add support for dma_get_sgtable()

This patch adds support for dma_get_sgtable() function which is required
to let drivers to share the buffers allocated by DMA-mapping subsystem.

Generic implementation based on virt_to_page() is not suitable for ARM
dma-mapping subsystem.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Kyungmin Park <kyungmin.park@samsung.com>

+35
+1
arch/arm/common/dmabounce.c
··· 452 452 .alloc = arm_dma_alloc, 453 453 .free = arm_dma_free, 454 454 .mmap = arm_dma_mmap, 455 + .get_sgtable = arm_dma_get_sgtable, 455 456 .map_page = dmabounce_map_page, 456 457 .unmap_page = dmabounce_unmap_page, 457 458 .sync_single_for_cpu = dmabounce_sync_for_cpu,
+3
arch/arm/include/asm/dma-mapping.h
··· 261 261 enum dma_data_direction); 262 262 extern void arm_dma_sync_sg_for_device(struct device *, struct scatterlist *, int, 263 263 enum dma_data_direction); 264 + extern int arm_dma_get_sgtable(struct device *dev, struct sg_table *sgt, 265 + void *cpu_addr, dma_addr_t dma_addr, size_t size, 266 + struct dma_attrs *attrs); 264 267 265 268 #endif /* __KERNEL__ */ 266 269 #endif
+31
arch/arm/mm/dma-mapping.c
··· 125 125 .alloc = arm_dma_alloc, 126 126 .free = arm_dma_free, 127 127 .mmap = arm_dma_mmap, 128 + .get_sgtable = arm_dma_get_sgtable, 128 129 .map_page = arm_dma_map_page, 129 130 .unmap_page = arm_dma_unmap_page, 130 131 .map_sg = arm_dma_map_sg, ··· 662 661 } 663 662 } 664 663 664 + int arm_dma_get_sgtable(struct device *dev, struct sg_table *sgt, 665 + void *cpu_addr, dma_addr_t handle, size_t size, 666 + struct dma_attrs *attrs) 667 + { 668 + struct page *page = pfn_to_page(dma_to_pfn(dev, handle)); 669 + int ret; 670 + 671 + ret = sg_alloc_table(sgt, 1, GFP_KERNEL); 672 + if (unlikely(ret)) 673 + return ret; 674 + 675 + sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0); 676 + return 0; 677 + } 678 + 665 679 static void dma_cache_maint_page(struct page *page, unsigned long offset, 666 680 size_t size, enum dma_data_direction dir, 667 681 void (*op)(const void *, size_t, int)) ··· 1188 1172 __iommu_free_buffer(dev, pages, size); 1189 1173 } 1190 1174 1175 + static int arm_iommu_get_sgtable(struct device *dev, struct sg_table *sgt, 1176 + void *cpu_addr, dma_addr_t dma_addr, 1177 + size_t size, struct dma_attrs *attrs) 1178 + { 1179 + unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; 1180 + struct page **pages = __iommu_get_pages(cpu_addr, attrs); 1181 + 1182 + if (!pages) 1183 + return -ENXIO; 1184 + 1185 + return sg_alloc_table_from_pages(sgt, pages, count, 0, size, 1186 + GFP_KERNEL); 1187 + } 1188 + 1191 1189 /* 1192 1190 * Map a part of the scatter-gather list into contiguous io address space 1193 1191 */ ··· 1461 1431 .alloc = arm_iommu_alloc_attrs, 1462 1432 .free = arm_iommu_free_attrs, 1463 1433 .mmap = arm_iommu_mmap_attrs, 1434 + .get_sgtable = arm_iommu_get_sgtable, 1464 1435 1465 1436 .map_page = arm_iommu_map_page, 1466 1437 .unmap_page = arm_iommu_unmap_page,