Preparation to .map_page and .unmap_page removal
Subsystems (4)
v4 cover Preparation to .map_page and .unmap_page removal
Changelog:
v4:
* Added Jason's ROB tags
* Added "xen: swiotlb ..." patch to the list of patches which had .map_resource
* Added extra patch "ARM: dma-mapping: Reduce ..." to remove struct page as much as possible.
* Added call to .map_phys/.unmap_phys to dma_common_*_pages() functions.
v3: https://lore.kernel.org/all/[email protected]
* Rewrote the series to allow combination of .map_resource and
* .map_page
to one flow.
* Added two new patches to convert and remove .map_resource.
v2: https://lore.kernel.org/all/[email protected]/
* Added default "else" section without map_phys and map_page callbacks (impossible).
v1: https://lore.kernel.org/all/[email protected]
* Changed "else if" instead of "if".
v0: https://lore.kernel.org/all/[email protected]
---------------------------------------------------------------------
This is followup to "dma-mapping: migrate to physical address-based API" series
https://lore.kernel.org/all/[email protected]
Thanks
Leon Romanovsky (6):
dma-mapping: prepare dma_map_ops to conversion to physical address
dma-mapping: convert dummy ops to physical address mapping
ARM: dma-mapping: Reduce struct page exposure in arch_sync_dma*()
ARM: dma-mapping: Switch to physical address mapping callbacks
xen: swiotlb: Switch to physical address mapping callbacks
dma-mapping: remove unused mapping resource callbacks
arch/arm/mm/dma-mapping.c | 180 +++++++++++------------------------- drivers/xen/swiotlb-xen.c | 63 ++++++------- include/linux/dma-map-ops.h | 13 +-- kernel/dma/dummy.c | 13 ++- kernel/dma/mapping.c | 20 ++-- kernel/dma/ops_helpers.c | 12 ++- 6 files changed, 113 insertions(+), 188 deletions(-)
Signature · 1 line
2.51.0
PATCH v4 2/6 dma-mapping: convert dummy ops to physical address mapping
From: Leon Romanovsky <[email protected]>
Change dma_dummy_map_page and dma_dummy_unmap_page routines to accept physical address and rename them.
--- kernel/dma/dummy.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-)
kernel/dma/dummy.c +6 -7
@@ -11,17 +11,16 @@ static int dma_dummy_mmap(struct device *dev, struct vm_area_struct *vma,return -ENXIO ; } -static dma_addr_t dma_dummy_map_page (struct device *dev,struct page *page, -unsigned long offset,size_t size,enum dma_data_direction dir, -unsigned long attrs) +static dma_addr_t dma_dummy_map_phys (struct device *dev,phys_addr_t phys, +size_t size,enum dma_data_direction dir,unsigned long attrs) {return DMA_MAPPING_ERROR ; } -static void dma_dummy_unmap_page (struct device *dev,dma_addr_t dma_handle, +static void dma_dummy_unmap_phys (struct device *dev,dma_addr_t dma_handle,size_t size,enum dma_data_direction dir,unsigned long attrs) {/* -* Dummy ops doesn't support map_page, so unmap_page should never be +* Dummy ops doesn't support map_phys, so unmap_page should never be * called. */ WARN_ON_ONCE (true);
@@ -51,8 +50,8 @@ static int dma_dummy_supported(struct device *hwdev, u64 mask)const struct dma_map_ops dma_dummy_ops = { .mmap = dma_dummy_mmap, - .map_page = dma_dummy_map_page, - .unmap_page = dma_dummy_unmap_page, + .map_phys = dma_dummy_map_phys, + .unmap_phys = dma_dummy_unmap_phys, .map_sg = dma_dummy_map_sg, .unmap_sg = dma_dummy_unmap_sg, .dma_supported = dma_dummy_supported,
Signature · 1 line
2.51.0
PATCH v4 3/6 ARM: dma-mapping: Reduce struct page exposure in arch_sync_dma*()
In reply to Leon RomanovskyFrom: Leon Romanovsky <[email protected]>
As a preparation to changing from .map_page to use .map_phys DMA callbacks, convert arch_sync_dma*() functions to use physical addresses instead of struct page.
--- arch/arm/mm/dma-mapping.c | 82 +++++++++++++++------------------------ 1 file changed, 31 insertions(+), 51 deletions(-)
arch/arm/mm/dma-mapping.c +31 -51
@@ -624,16 +624,14 @@ static void __arm_dma_free(struct device *dev, size_t size, void *cpu_addr,kfree (buf); } -static void dma_cache_maint_page (struct page *page,unsigned long offset, -size_t size,enum dma_data_direction dir, +static void dma_cache_maint_page (phys_addr_t phys,size_t size, +enum dma_data_direction dir,void (*op)(const void *,size_t ,int )) { -unsigned long pfn; +unsigned long offset =offset_in_page (phys); +unsigned long pfn =__phys_to_pfn (phys);size_t left = size; - pfn =page_to_pfn (page) + offset /PAGE_SIZE ; - offset %=PAGE_SIZE ; -/* * A single sg entry may refer to multiple physically contiguous * pages. But we still need to process highmem pages individually.
@@ -644,17 +642,18 @@ static void dma_cache_maint_page(struct page *page, unsigned long offset,size_t len = left;void *vaddr; - page =pfn_to_page (pfn); - -if (PageHighMem (page)) { + phys =__pfn_to_phys (pfn); +if (PhysHighMem (phys)) {if (len + offset >PAGE_SIZE ) len =PAGE_SIZE - offset;if (cache_is_vipt_nonaliasing ()) { - vaddr =kmap_atomic (page); + vaddr =kmap_atomic_pfn (pfn);op (vaddr + offset, len, dir);kunmap_atomic (vaddr); }else { +struct page *page =phys_to_page (phys); + vaddr =kmap_high_get (page);if (vaddr) {op (vaddr + offset, len, dir);
@@ -662,7 +661,8 @@ static void dma_cache_maint_page(struct page *page, unsigned long offset, } } }else { - vaddr =page_address (page) + offset; + phys += offset; + vaddr =phys_to_virt (phys);op (vaddr, len, dir); } offset =0 ;
@@ -676,14 +676,11 @@ static void dma_cache_maint_page(struct page *page, unsigned long offset,* Note: Drivers should NOT use this function directly. * Use the driver DMA support - see dma-mapping.h (dma_sync_*) */ -static void __dma_page_cpu_to_dev (struct page *page,unsigned long off, -size_t size,enum dma_data_direction dir) +void arch_sync_dma_for_device (phys_addr_t paddr,size_t size, +enum dma_data_direction dir) { -phys_addr_t paddr; - -dma_cache_maint_page (page, off, size, dir, dmac_map_area); +dma_cache_maint_page (paddr, size, dir, dmac_map_area); - paddr =page_to_phys (page) + off;if (dir ==DMA_FROM_DEVICE ) {outer_inv_range (paddr, paddr + size); }else {
@@ -692,17 +689,15 @@ static void __dma_page_cpu_to_dev(struct page *page, unsigned long off,/* FIXME: non-speculating: flush on bidirectional mappings? */ } -static void __dma_page_dev_to_cpu (struct page *page,unsigned long off, -size_t size,enum dma_data_direction dir) +void arch_sync_dma_for_cpu (phys_addr_t paddr,size_t size, +enum dma_data_direction dir) { -phys_addr_t paddr =page_to_phys (page) + off; -/* FIXME: non-speculating: not required */ /* in any case, don't bother invalidating if DMA to device */ if (dir !=DMA_TO_DEVICE ) {outer_inv_range (paddr, paddr + size); -dma_cache_maint_page (page, off, size, dir, dmac_unmap_area); +dma_cache_maint_page (paddr, size, dir, dmac_unmap_area); }/*
@@ -1205,7 +1200,7 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,unsigned int len =PAGE_ALIGN (s->offset + s->length);if (!dev->dma_coherent && !(attrs &DMA_ATTR_SKIP_CPU_SYNC )) -__dma_page_cpu_to_dev (sg_page (s), s->offset, s->length, dir); +arch_sync_dma_for_device (sg_phys (s), s->length, dir); prot =__dma_info_to_prot (dir, attrs);
@@ -1307,8 +1302,7 @@ static void arm_iommu_unmap_sg(struct device *dev,__iommu_remove_mapping (dev,sg_dma_address (s),sg_dma_len (s));if (!dev->dma_coherent && !(attrs &DMA_ATTR_SKIP_CPU_SYNC )) -__dma_page_dev_to_cpu (sg_page (s), s->offset, - s->length, dir); +arch_sync_dma_for_cpu (sg_phys (s), s->length, dir); } }
@@ -1330,7 +1324,7 @@ static void arm_iommu_sync_sg_for_cpu(struct device *dev,return ;for_each_sg (sg, s, nents, i) -__dma_page_dev_to_cpu (sg_page (s), s->offset, s->length, dir); +arch_sync_dma_for_cpu (sg_phys (s), s->length, dir); }
@@ -1352,7 +1346,7 @@ static void arm_iommu_sync_sg_for_device(struct device *dev,return ;for_each_sg (sg, s, nents, i) -__dma_page_cpu_to_dev (sg_page (s), s->offset, s->length, dir); +arch_sync_dma_for_device (sg_phys (s), s->length, dir); }/**
@@ -1374,7 +1368,7 @@ static dma_addr_t arm_iommu_map_page(struct device *dev, struct page *page,int ret, prot, len =PAGE_ALIGN (size + offset);if (!dev->dma_coherent && !(attrs &DMA_ATTR_SKIP_CPU_SYNC )) -__dma_page_cpu_to_dev (page, offset, size, dir); +arch_sync_dma_for_device (page_to_phys (page), offset, size, dir); dma_addr =__alloc_iova (mapping, len);if (dma_addr ==DMA_MAPPING_ERROR )
@@ -1407,7 +1401,6 @@ static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle, {struct dma_iommu_mapping *mapping =to_dma_iommu_mapping (dev);dma_addr_t iova = handle &PAGE_MASK ; -struct page *page;int offset = handle & ~PAGE_MASK ;int len =PAGE_ALIGN (size + offset);
@@ -1415,8 +1408,9 @@ static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle,return ;if (!dev->dma_coherent && !(attrs &DMA_ATTR_SKIP_CPU_SYNC )) { - page =phys_to_page (iommu_iova_to_phys (mapping->domain, iova)); -__dma_page_dev_to_cpu (page, offset, size, dir); +phys_addr_t phys =iommu_iova_to_phys (mapping->domain, iova); + +arch_sync_dma_for_cpu (phys + offset, size, dir); }iommu_unmap (mapping->domain, iova, len);
@@ -1485,14 +1479,14 @@ static void arm_iommu_sync_single_for_cpu(struct device *dev, {struct dma_iommu_mapping *mapping =to_dma_iommu_mapping (dev);dma_addr_t iova = handle &PAGE_MASK ; -struct page *page;unsigned int offset = handle & ~PAGE_MASK ; +phys_addr_t phys;if (dev->dma_coherent || !iova)return ; - page =phys_to_page (iommu_iova_to_phys (mapping->domain, iova)); -__dma_page_dev_to_cpu (page, offset, size, dir); + phys =iommu_iova_to_phys (mapping->domain, iova); +arch_sync_dma_for_cpu (phys + offset, size, dir); } static void arm_iommu_sync_single_for_device(struct device *dev,
@@ -1500,14 +1494,14 @@ static void arm_iommu_sync_single_for_device(struct device *dev, {struct dma_iommu_mapping *mapping =to_dma_iommu_mapping (dev);dma_addr_t iova = handle &PAGE_MASK ; -struct page *page;unsigned int offset = handle & ~PAGE_MASK ; +phys_addr_t phys;if (dev->dma_coherent || !iova)return ; - page =phys_to_page (iommu_iova_to_phys (mapping->domain, iova)); -__dma_page_cpu_to_dev (page, offset, size, dir); + phys =iommu_iova_to_phys (mapping->domain, iova); +arch_sync_dma_for_device (phys + offset, size, dir); }static const struct dma_map_ops iommu_ops = {
@@ -1794,20 +1788,6 @@ void arch_teardown_dma_ops(struct device *dev)set_dma_ops (dev,NULL ); } -void arch_sync_dma_for_device (phys_addr_t paddr,size_t size, -enum dma_data_direction dir) -{ -__dma_page_cpu_to_dev (phys_to_page (paddr), paddr & (PAGE_SIZE -1 ), - size, dir); -} - -void arch_sync_dma_for_cpu (phys_addr_t paddr,size_t size, -enum dma_data_direction dir) -{ -__dma_page_dev_to_cpu (phys_to_page (paddr), paddr & (PAGE_SIZE -1 ), - size, dir); -} -void *arch_dma_alloc (struct device *dev,size_t size,dma_addr_t *dma_handle,gfp_t gfp,unsigned long attrs) {
Signature · 1 line
2.51.0
PATCH v4 1/6 dma-mapping: prepare dma_map_ops to conversion to physical address
In reply to Leon RomanovskyFrom: Leon Romanovsky <[email protected]>
Add new .map_phys() and .unmap_phys() callbacks to dma_map_ops as a preparation to replace .map_page() and .unmap_page() respectively.
--- include/linux/dma-map-ops.h | 7 +++++++ kernel/dma/mapping.c | 4 ++++ kernel/dma/ops_helpers.c | 12 ++++++++++-- 3 files changed, 21 insertions(+), 2 deletions(-)
include/linux/dma-map-ops.h +7 -0
@@ -37,6 +37,13 @@ struct dma_map_ops {void (*unmap_page)(struct device *dev,dma_addr_t dma_handle,size_t size,enum dma_data_direction dir,unsigned long attrs); + +dma_addr_t (*map_phys)(struct device *dev,phys_addr_t phys, +size_t size,enum dma_data_direction dir, +unsigned long attrs); +void (*unmap_phys)(struct device *dev,dma_addr_t dma_handle, +size_t size,enum dma_data_direction dir, +unsigned long attrs);/* * map_sg should return a negative error code on error. See * dma_map_sgtable() for a list of appropriate error codes
kernel/dma/mapping.c +4 -0
@@ -169,6 +169,8 @@ dma_addr_t dma_map_phys(struct device *dev, phys_addr_t phys, size_t size, addr =dma_direct_map_phys (dev, phys, size, dir, attrs); else if (use_dma_iommu(dev)) addr =iommu_dma_map_phys (dev, phys, size, dir, attrs); + else if (ops->map_phys) + addr = ops->map_phys (dev, phys, size, dir, attrs); else if (is_mmio) {if (!ops->map_resource)return DMA_MAPPING_ERROR ;
@@ -223,6 +225,8 @@ void dma_unmap_phys(struct device *dev, dma_addr_t addr, size_t size,dma_direct_unmap_phys (dev, addr, size, dir, attrs); else if (use_dma_iommu(dev)) iommu_dma_unmap_phys(dev, addr, size, dir, attrs); + else if (ops->unmap_phys) + ops->unmap_phys(dev, addr, size, dir, attrs); else if (is_mmio) {if (ops->unmap_resource) ops->unmap_resource (dev, addr, size, dir, attrs);
kernel/dma/ops_helpers.c +10 -2
@@ -64,6 +64,7 @@ struct page *dma_common_alloc_pages(struct device *dev, size_t size, {const struct dma_map_ops *ops =get_dma_ops (dev);struct page *page; +phys_addr_t phys; page =dma_alloc_contiguous (dev, size, gfp);if (!page)
@@ -71,9 +72,13 @@ struct page *dma_common_alloc_pages(struct device *dev, size_t size,if (!page)return NULL ; + phys =page_to_phys (page);if (use_dma_iommu (dev)) - *dma_handle =iommu_dma_map_phys (dev,page_to_phys (page), size, - dir,DMA_ATTR_SKIP_CPU_SYNC ); + *dma_handle =iommu_dma_map_phys (dev, phys, size, dir, +DMA_ATTR_SKIP_CPU_SYNC ); +else if (ops->map_phys) + *dma_handle = ops->map_phys (dev, phys, size, dir, +DMA_ATTR_SKIP_CPU_SYNC );else *dma_handle = ops->map_page (dev, page,0 , size, dir,DMA_ATTR_SKIP_CPU_SYNC );
@@ -94,6 +99,9 @@ void dma_common_free_pages(struct device *dev, size_t size, struct page *page,if (use_dma_iommu (dev))iommu_dma_unmap_phys (dev, dma_handle, size, dir,DMA_ATTR_SKIP_CPU_SYNC ); +else if (ops->unmap_phys) + ops->unmap_phys (dev, dma_handle, size, dir, +DMA_ATTR_SKIP_CPU_SYNC );else if (ops->unmap_page) ops->unmap_page (dev, dma_handle, size, dir,DMA_ATTR_SKIP_CPU_SYNC );
Signature · 1 line
2.51.0
PATCH v4 5/6 xen: swiotlb: Switch to physical address mapping callbacks
In reply to Leon RomanovskyFrom: Leon Romanovsky <[email protected]>
Combine resource and page mappings routines to one function and remove .map_resource/.unmap_resource callbacks completely.
--- drivers/xen/swiotlb-xen.c | 63 ++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 34 deletions(-)
drivers/xen/swiotlb-xen.c +29 -34
@@ -200,17 +200,32 @@ xen_swiotlb_free_coherent(struct device *dev, size_t size, void *vaddr,* physical address to use is returned. * * Once the device is given the dma address, the device owns this memory until -* either xen_swiotlb_unmap_page or xen_swiotlb_dma_sync_single is performed. +* either xen_swiotlb_unmap_phys or xen_swiotlb_dma_sync_single is performed. */ -static dma_addr_t xen_swiotlb_map_page (struct device *dev,struct page *page, -unsigned long offset,size_t size, -enum dma_data_direction dir, +static dma_addr_t xen_swiotlb_map_phys (struct device *dev,phys_addr_t phys, +size_t size,enum dma_data_direction dir,unsigned long attrs) { -phys_addr_t map, phys =page_to_phys (page) + offset; -dma_addr_t dev_addr =xen_phys_to_dma (dev, phys); +dma_addr_t dev_addr; +phys_addr_t map;BUG_ON (dir ==DMA_NONE ); + +if (attrs &DMA_ATTR_MMIO ) { +if (unlikely (!dma_capable (dev, phys, size, false))) { +dev_err_once ( + dev, +"DMA addr %pad+%zu overflow (mask %llx, bus limit %llx).\n" , + &dma_addr, size, *dev->dma_mask, + dev->bus_dma_limit); +WARN_ON_ONCE (1 ); +return DMA_MAPPING_ERROR ; + } +return phys; + } + + dev_addr =xen_phys_to_dma (dev, phys); +/* * If the address happens to be in the device's DMA window, * we can safely return the device addr and not worry about bounce
@@ -257,13 +272,13 @@ static dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,/* * Unmap a single streaming mode DMA translation. The dma_addr and size must -* match what was provided for in a previous xen_swiotlb_map_page call. All +* match what was provided for in a previous xen_swiotlb_map_phys call. All * other usages are undefined. * * After this call, reads by the cpu to the buffer are guaranteed to see * whatever the device wrote there. */ -static void xen_swiotlb_unmap_page (struct device *hwdev,dma_addr_t dev_addr, +static void xen_swiotlb_unmap_phys (struct device *hwdev,dma_addr_t dev_addr,size_t size,enum dma_data_direction dir,unsigned long attrs) {phys_addr_t paddr =xen_dma_to_phys (hwdev, dev_addr);
@@ -325,7 +340,7 @@ xen_swiotlb_sync_single_for_device(struct device *dev, dma_addr_t dma_addr,/* * Unmap a set of streaming mode DMA translations. Again, cpu read rules -* concerning calls here are the same as for swiotlb_unmap_page() above. +* concerning calls here are the same as for swiotlb_unmap_phys() above. */ static void xen_swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sgl, int nelems,
@@ -337,7 +352,7 @@ xen_swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sgl, int nelems,BUG_ON (dir ==DMA_NONE );for_each_sg (sgl, sg, nelems, i) -xen_swiotlb_unmap_page (hwdev, sg->dma_address,sg_dma_len (sg), +xen_swiotlb_unmap_phys (hwdev, sg->dma_address,sg_dma_len (sg), dir, attrs); }
@@ -352,8 +367,8 @@ xen_swiotlb_map_sg(struct device *dev, struct scatterlist *sgl, int nelems,BUG_ON (dir ==DMA_NONE );for_each_sg (sgl, sg, nelems, i) { - sg->dma_address =xen_swiotlb_map_page (dev,sg_page (sg), - sg->offset, sg->length, dir, attrs); + sg->dma_address =xen_swiotlb_map_phys (dev,sg_phys (sg), + sg->length, dir, attrs);if (sg->dma_address ==DMA_MAPPING_ERROR ) goto out_unmap;sg_dma_len (sg) = sg->length;
@@ -392,25 +407,6 @@ xen_swiotlb_sync_sg_for_device(struct device *dev, struct scatterlist *sgl, } } -static dma_addr_t xen_swiotlb_direct_map_resource (struct device *dev, -phys_addr_t paddr, -size_t size, -enum dma_data_direction dir, -unsigned long attrs) -{ -dma_addr_t dma_addr = paddr; - -if (unlikely (!dma_capable (dev, dma_addr, size, false))) { -dev_err_once (dev, -"DMA addr %pad+%zu overflow (mask %llx, bus limit %llx).\n" , - &dma_addr, size, *dev->dma_mask, dev->bus_dma_limit); -WARN_ON_ONCE (1 ); -return DMA_MAPPING_ERROR ; - } - -return dma_addr; -} -/* * Return whether the given device DMA address mask can be supported * properly. For example, if your device can only drive the low 24-bits
@@ -437,13 +433,12 @@ const struct dma_map_ops xen_swiotlb_dma_ops = { .sync_sg_for_device = xen_swiotlb_sync_sg_for_device, .map_sg = xen_swiotlb_map_sg, .unmap_sg = xen_swiotlb_unmap_sg, - .map_page = xen_swiotlb_map_page, - .unmap_page = xen_swiotlb_unmap_page, + .map_phys = xen_swiotlb_map_phys, + .unmap_phys = xen_swiotlb_unmap_phys, .dma_supported = xen_swiotlb_dma_supported, .mmap = dma_common_mmap, .get_sgtable = dma_common_get_sgtable, .alloc_pages_op = dma_common_alloc_pages, .free_pages = dma_common_free_pages, .max_mapping_size = swiotlb_max_mapping_size, - .map_resource = xen_swiotlb_direct_map_resource, };
Signature · 1 line
2.51.0
PATCH v4 6/6 dma-mapping: remove unused mapping resource callbacks
In reply to Leon RomanovskyFrom: Leon Romanovsky <[email protected]>
After ARM and XEN conversions to use physical addresses for the mapping, there are no in-kernel users for map_resource/unmap_resource callbacks, so remove them.
--- include/linux/dma-map-ops.h | 6 ------ kernel/dma/mapping.c | 16 ++++------------ 2 files changed, 4 insertions(+), 18 deletions(-)
include/linux/dma-map-ops.h +0 -6
@@ -53,12 +53,6 @@ struct dma_map_ops { enum dma_data_direction dir, unsigned long attrs);void (*unmap_sg)(struct device *dev,struct scatterlist *sg,int nents,enum dma_data_direction dir,unsigned long attrs); -dma_addr_t (*map_resource)(struct device *dev,phys_addr_t phys_addr, -size_t size,enum dma_data_direction dir, -unsigned long attrs); -void (*unmap_resource)(struct device *dev,dma_addr_t dma_handle, -size_t size,enum dma_data_direction dir, -unsigned long attrs);void (*sync_single_for_cpu)(struct device *dev,dma_addr_t dma_handle,size_t size,enum dma_data_direction dir); void (*sync_single_for_device)(struct device *dev,
kernel/dma/mapping.c +4 -12
@@ -157,7 +157,7 @@ dma_addr_t dma_map_phys(struct device *dev, phys_addr_t phys, size_t size, {const struct dma_map_ops *ops =get_dma_ops (dev);bool is_mmio = attrs &DMA_ATTR_MMIO ; -dma_addr_t addr; +dma_addr_t addr =DMA_MAPPING_ERROR ;BUG_ON (!valid_dma_direction (dir));
@@ -171,18 +171,13 @@ dma_addr_t dma_map_phys(struct device *dev, phys_addr_t phys, size_t size, addr =iommu_dma_map_phys (dev, phys, size, dir, attrs); else if (ops->map_phys) addr = ops->map_phys (dev, phys, size, dir, attrs); - else if (is_mmio) { -if (!ops->map_resource) -return DMA_MAPPING_ERROR ; - - addr = ops->map_resource (dev, phys, size, dir, attrs); - } else { + else if (!is_mmio && ops->map_page) {struct page *page =phys_to_page (phys);size_t offset =offset_in_page (phys);/* * The dma_ops API contract for ops->map_page() requires -* kmappable memory, while ops->map_resource() does not. +* kmappable memory. */ addr = ops->map_page (dev, page, offset, size, dir, attrs); }
@@ -227,10 +222,7 @@ void dma_unmap_phys(struct device *dev, dma_addr_t addr, size_t size,iommu_dma_unmap_phys (dev, addr, size, dir, attrs); else if (ops->unmap_phys) ops->unmap_phys(dev, addr, size, dir, attrs); - else if (is_mmio) { -if (ops->unmap_resource) - ops->unmap_resource (dev, addr, size, dir, attrs); - } else + else ops->unmap_page(dev, addr, size, dir, attrs);trace_dma_unmap_phys (dev, addr, size, dir, attrs);debug_dma_unmap_phys (dev, addr, size, dir);
Signature · 1 line
2.51.0
PATCH v4 4/6 ARM: dma-mapping: Switch to physical address mapping callbacks
In reply to Leon RomanovskyFrom: Leon Romanovsky <[email protected]>
Combine resource and page mappings routines to one function, which handles both these flows at the same manner. This conversion allows us to remove .map_resource/.unmap_resource callbacks completely.
--- arch/arm/mm/dma-mapping.c | 100 +++++++++----------------------------- 1 file changed, 23 insertions(+), 77 deletions(-)
arch/arm/mm/dma-mapping.c +23 -77
@@ -732,6 +732,9 @@ static int __dma_info_to_prot(enum dma_data_direction dir, unsigned long attrs)if (attrs &DMA_ATTR_PRIVILEGED ) prot |=IOMMU_PRIV ; +if (attrs &DMA_ATTR_MMIO ) + prot |=IOMMU_MMIO ; +switch (dir) {case DMA_BIDIRECTIONAL :return prot |IOMMU_READ |IOMMU_WRITE ;
@@ -1350,25 +1353,27 @@ static void arm_iommu_sync_sg_for_device(struct device *dev, }/** -* arm_iommu_map_page +* arm_iommu_map_phys * @dev: valid struct device pointer -* @page: page that buffer resides in -* @offset: offset into page for start of buffer +* @phys: physical address that buffer resides in * @size: size of buffer to map * @dir: DMA transfer direction +* @attrs: DMA mapping attributes * * IOMMU aware version of arm_dma_map_page() */ -static dma_addr_t arm_iommu_map_page (struct device *dev,struct page *page, -unsigned long offset,size_t size,enum dma_data_direction dir, -unsigned long attrs) +static dma_addr_t arm_iommu_map_phys (struct device *dev,phys_addr_t phys, +size_t size,enum dma_data_direction dir,unsigned long attrs) {struct dma_iommu_mapping *mapping =to_dma_iommu_mapping (dev); +int len =PAGE_ALIGN (size +offset_in_page (phys)); +phys_addr_t addr = phys &PAGE_MASK ;dma_addr_t dma_addr; -int ret, prot, len =PAGE_ALIGN (size + offset); +int ret, prot; -if (!dev->dma_coherent && !(attrs &DMA_ATTR_SKIP_CPU_SYNC )) -arch_sync_dma_for_device (page_to_phys (page), offset, size, dir); +if (!dev->dma_coherent && + !(attrs & (DMA_ATTR_SKIP_CPU_SYNC |DMA_ATTR_MMIO ))) +arch_sync_dma_for_device (phys, size, dir); dma_addr =__alloc_iova (mapping, len);if (dma_addr ==DMA_MAPPING_ERROR )
@@ -1376,12 +1381,11 @@ static dma_addr_t arm_iommu_map_page(struct device *dev, struct page *page, prot =__dma_info_to_prot (dir, attrs); - ret =iommu_map (mapping->domain, dma_addr,page_to_phys (page), len, - prot,GFP_KERNEL ); + ret =iommu_map (mapping->domain, dma_addr, addr, len, prot,GFP_KERNEL );if (ret <0 ) goto fail; -return dma_addr + offset; +return dma_addr +offset_in_page (phys); fail:__free_iova (mapping, dma_addr, len);return DMA_MAPPING_ERROR ;
@@ -1393,10 +1397,11 @@ static dma_addr_t arm_iommu_map_page(struct device *dev, struct page *page,* @handle: DMA address of buffer * @size: size of buffer (same as passed to dma_map_page) * @dir: DMA transfer direction (same as passed to dma_map_page) +* @attrs: DMA mapping attributes * -* IOMMU aware version of arm_dma_unmap_page() +* IOMMU aware version of arm_dma_unmap_phys() */ -static void arm_iommu_unmap_page (struct device *dev,dma_addr_t handle, +static void arm_iommu_unmap_phys (struct device *dev,dma_addr_t handle,size_t size,enum dma_data_direction dir,unsigned long attrs) {struct dma_iommu_mapping *mapping =to_dma_iommu_mapping (dev);
@@ -1407,7 +1412,8 @@ static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle,if (!iova)return ; -if (!dev->dma_coherent && !(attrs &DMA_ATTR_SKIP_CPU_SYNC )) { +if (!dev->dma_coherent && + !(attrs & (DMA_ATTR_SKIP_CPU_SYNC |DMA_ATTR_MMIO ))) {phys_addr_t phys =iommu_iova_to_phys (mapping->domain, iova);arch_sync_dma_for_cpu (phys + offset, size, dir);
@@ -1417,63 +1423,6 @@ static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle,__free_iova (mapping, iova, len); } -/** -* arm_iommu_map_resource - map a device resource for DMA -* @dev: valid struct device pointer -* @phys_addr: physical address of resource -* @size: size of resource to map -* @dir: DMA transfer direction -*/ -static dma_addr_t arm_iommu_map_resource (struct device *dev, -phys_addr_t phys_addr,size_t size, -enum dma_data_direction dir,unsigned long attrs) -{ -struct dma_iommu_mapping *mapping =to_dma_iommu_mapping (dev); -dma_addr_t dma_addr; -int ret, prot; -phys_addr_t addr = phys_addr &PAGE_MASK ; -unsigned int offset = phys_addr & ~PAGE_MASK ; -size_t len =PAGE_ALIGN (size + offset); - - dma_addr =__alloc_iova (mapping, len); -if (dma_addr ==DMA_MAPPING_ERROR ) -return dma_addr; - - prot =__dma_info_to_prot (dir, attrs) |IOMMU_MMIO ; - - ret =iommu_map (mapping->domain, dma_addr, addr, len, prot,GFP_KERNEL ); -if (ret <0 ) - goto fail; - -return dma_addr + offset; -fail: -__free_iova (mapping, dma_addr, len); -return DMA_MAPPING_ERROR ; -} - -/** -* arm_iommu_unmap_resource - unmap a device DMA resource -* @dev: valid struct device pointer -* @dma_handle: DMA address to resource -* @size: size of resource to map -* @dir: DMA transfer direction -*/ -static void arm_iommu_unmap_resource (struct device *dev,dma_addr_t dma_handle, -size_t size,enum dma_data_direction dir, -unsigned long attrs) -{ -struct dma_iommu_mapping *mapping =to_dma_iommu_mapping (dev); -dma_addr_t iova = dma_handle &PAGE_MASK ; -unsigned int offset = dma_handle & ~PAGE_MASK ; -size_t len =PAGE_ALIGN (size + offset); - -if (!iova) -return ; - -iommu_unmap (mapping->domain, iova, len); -__free_iova (mapping, iova, len); -} -static void arm_iommu_sync_single_for_cpu (struct device *dev,dma_addr_t handle,size_t size,enum dma_data_direction dir) {
@@ -1510,8 +1459,8 @@ static const struct dma_map_ops iommu_ops = { .mmap = arm_iommu_mmap_attrs, .get_sgtable = arm_iommu_get_sgtable, - .map_page = arm_iommu_map_page, - .unmap_page = arm_iommu_unmap_page, + .map_phys = arm_iommu_map_phys, + .unmap_phys = arm_iommu_unmap_phys, .sync_single_for_cpu = arm_iommu_sync_single_for_cpu, .sync_single_for_device = arm_iommu_sync_single_for_device,
@@ -1519,9 +1468,6 @@ static const struct dma_map_ops iommu_ops = { .unmap_sg = arm_iommu_unmap_sg, .sync_sg_for_cpu = arm_iommu_sync_sg_for_cpu, .sync_sg_for_device = arm_iommu_sync_sg_for_device, - - .map_resource = arm_iommu_map_resource, - .unmap_resource = arm_iommu_unmap_resource, };/**
Signature · 1 line
2.51.0
Re: [PATCH v4 5/6] xen: swiotlb: Switch to physical address mapping callbacks
In reply to Leon RomanovskyQuoted 9 lines · Leon Romanovsky
From: Leon Romanovsky <[email protected]>
Combine resource and page mappings routines to one function and remove .map_resource/.unmap_resource callbacks completely.
Signed-off-by Leon Romanovsky <[email protected]>--- drivers/xen/swiotlb-xen.c | 63 ++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 34 deletions(-)
<...>
Review
Quoted 12 lines
(quoted diff) +12
-0+ if (attrs & DMA_ATTR_MMIO) { + if (unlikely(!dma_capable(dev, phys, size, false))) { + dev_err_once( + dev, + "DMA addr %pad+%zu overflow (mask %llx, bus limit %llx).\n", + &dma_addr, size, *dev->dma_mask, + dev->bus_dma_limit); + WARN_ON_ONCE(1); + return DMA_MAPPING_ERROR; + } + return phys; + }
This need to be fixed by the following change (dma_addr->phys):
drivers/xen/swiotlb-xen.c +2 -2
@@ -215,8 +215,8 @@ static dma_addr_t xen_swiotlb_map_phys(struct device *dev, phys_addr_t phys,if (unlikely (!dma_capable (dev, phys, size, false))) {dev_err_once ( dev, -"DMA addr %pad+%zu overflow (mask %llx, bus limit %llx).\n" , - &dma_addr, size, *dev->dma_mask, +"DMA addr %pa+%zu overflow (mask %llx, bus limit %llx).\n" , + &phys, size, *dev->dma_mask, dev->bus_dma_limit);WARN_ON_ONCE (1 );return DMA_MAPPING_ERROR ;
Thanks
Re: [PATCH v4 3/6] ARM: dma-mapping: Reduce struct page exposure in arch_sync_dma*()
In reply to Leon RomanovskyQuoted 10 lines · Leon Romanovsky
From: Leon Romanovsky <[email protected]>
As a preparation to changing from .map_page to use .map_phys DMA callbacks, convert arch_sync_dma*() functions to use physical addresses instead of struct page.
Signed-off-by Leon Romanovsky <[email protected]>--- arch/arm/mm/dma-mapping.c | 82 +++++++++++++++------------------------ 1 file changed, 31 insertions(+), 51 deletions(-)
Jason
Re: [PATCH v4 5/6] xen: swiotlb: Switch to physical address mapping callbacks
In reply to Leon RomanovskyQuoted 9 lines · Leon Romanovsky
From: Leon Romanovsky <[email protected]>
Combine resource and page mappings routines to one function and remove .map_resource/.unmap_resource callbacks completely.
Signed-off-by Leon Romanovsky <[email protected]>--- drivers/xen/swiotlb-xen.c | 63 ++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 34 deletions(-)
Jason