Skip to contentSkip to conversation

Remove DMA .map_page and .unmap_page callbacks

PATCH In review Leon Romanovsky 7 participants 34 messages Sep 28, 2025 – Oct 6, 2025

Subsystems (10)
x86 PowerPC MIPS virtio core +6 more subsystems
lore
Share & tools
lore
#0 lore raw

cover Remove DMA .map_page and .unmap_page callbacks

Changelog:
v1:
* Fixed wrong offset in alpha conversion patch.
v0: https://lore.kernel.org/all/[email protected]

Hi,

This series continues following two series:
1. "dma-mapping: migrate to physical address-based API"
https://lore.kernel.org/all/[email protected]
2. "Preparation to .map_page and .unmap_page removal" Preparation to .map_page and .unmap_page removal

In this series, the DMA .map_page/.unmap_page callbacks are converted to newly introduced .map_phys/.unmap_phys interfaces. This conversion allows us to reduce or eliminate (for certain ARCHs) use of struct pages in DMA path.

Thanks

Leon Romanovsky (9):
alpha: Convert mapping routine to rely on physical address MIPS/jazzdma: Provide physical address directly
parisc: Convert DMA map_page to map_phys interface
powerpc: Convert to physical address DMA mapping
sparc64: Use physical address DMA mapping
x86: Use physical address for DMA mapping
vdpa: Convert to physical address DMA mapping
xen: swiotlb: Convert mapping routine to rely on physical address
dma-mapping: remove unused map_page callback

 arch/alpha/kernel/pci_iommu.c            | 48 +++++++++++-------------
 arch/mips/jazz/jazzdma.c                 | 20 ++++++----
 arch/powerpc/include/asm/iommu.h         |  8 ++--
 arch/powerpc/kernel/dma-iommu.c          | 22 +++++------
 arch/powerpc/kernel/iommu.c              | 14 +++----
 arch/powerpc/platforms/ps3/system-bus.c  | 33 +++++++++-------
 arch/powerpc/platforms/pseries/ibmebus.c | 15 ++++----
 arch/powerpc/platforms/pseries/vio.c     | 21 ++++++-----
 arch/sparc/kernel/iommu.c                | 16 ++++----
 arch/sparc/kernel/pci_sun4v.c            | 16 ++++----
 arch/sparc/mm/io-unit.c                  | 13 +++----
 arch/sparc/mm/iommu.c                    | 46 ++++++++++++-----------
 arch/x86/kernel/amd_gart_64.c            | 19 +++++-----
 drivers/parisc/ccio-dma.c                | 25 ++++++------
 drivers/parisc/sba_iommu.c               | 23 ++++++------
 drivers/vdpa/vdpa_user/iova_domain.c     | 11 +++---
 drivers/vdpa/vdpa_user/iova_domain.h     |  8 ++--
 drivers/vdpa/vdpa_user/vduse_dev.c       | 18 +++++----
 drivers/xen/grant-dma-ops.c              | 20 ++++++----
 include/linux/dma-map-ops.h              |  7 ----
 kernel/dma/mapping.c                     | 12 ------
 kernel/dma/ops_helpers.c                 |  8 +---
 22 files changed, 209 insertions(+), 214 deletions(-)
Signature · 1 line
2.51.0
#1 lore raw

PATCH 1/9 alpha: Convert mapping routine to rely on physical address

From: Leon Romanovsky <[email protected]>

Alpha doesn't need struct *page and can perform mapping based on physical addresses. So convert it to implement new .map_phys callback.

As part of this change, remove useless BUG_ON() as DMA mapping layer ensures that right direction is provided.

---
 arch/alpha/kernel/pci_iommu.c | 48 +++++++++++++++--------------------
 1 file changed, 21 insertions(+), 27 deletions(-)
arch/alpha/kernel/pci_iommu.c +21 -27
index dc91de50f906..3e4f631a1f27 100644
@@ -224,28 +224,26 @@ static int pci_dac_dma_supported(struct pci_dev *dev, u64 mask)
    until either pci_unmap_single or pci_dma_sync_single is performed.  */
 
 static dma_addr_t
-pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size,
+pci_map_single_1(struct pci_dev *pdev, phys_addr_t paddr, size_t size,
 		 int dac_allowed)
 {
 	struct pci_controller *hose = pdev ? pdev->sysdata : pci_isa_hose;
 	dma_addr_t max_dma = pdev ? pdev->dma_mask : ISA_DMA_MASK;
+	unsigned long offset = offset_in_page(paddr);
 	struct pci_iommu_arena *arena;
 	long npages, dma_ofs, i;
-	unsigned long paddr;
 	dma_addr_t ret;
 	unsigned int align = 0;
 	struct device *dev = pdev ? &pdev->dev : NULL;
 
-	paddr = __pa(cpu_addr);
-
 #if !DEBUG_NODIRECT
 	/* First check to see if we can use the direct map window.  */
 	if (paddr + size + __direct_map_base - 1 <= max_dma
 	    && paddr + size <= __direct_map_size) {
 		ret = paddr + __direct_map_base;
 
-		DBGA2("pci_map_single: [%p,%zx] -> direct %llx from %ps\n",
-		      cpu_addr, size, ret, __builtin_return_address(0));
+		DBGA2("pci_map_single: [%pa,%zx] -> direct %llx from %ps\n",
+		      &paddr, size, ret, __builtin_return_address(0));
 
 		return ret;
 	}
@@ -255,8 +253,8 @@ pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size,
 	if (dac_allowed) {
 		ret = paddr + alpha_mv.pci_dac_offset;
 
-		DBGA2("pci_map_single: [%p,%zx] -> DAC %llx from %ps\n",
-		      cpu_addr, size, ret, __builtin_return_address(0));
+		DBGA2("pci_map_single: [%pa,%zx] -> DAC %llx from %ps\n",
+		      &paddr, size, ret, __builtin_return_address(0));
 
 		return ret;
 	}
@@ -290,10 +288,10 @@ pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size,
 		arena->ptes[i + dma_ofs] = mk_iommu_pte(paddr);
 
 	ret = arena->dma_base + dma_ofs * PAGE_SIZE;
-	ret += (unsigned long)cpu_addr & ~PAGE_MASK;
+	ret += offset;
 
-	DBGA2("pci_map_single: [%p,%zx] np %ld -> sg %llx from %ps\n",
-	      cpu_addr, size, npages, ret, __builtin_return_address(0));
+	DBGA2("pci_map_single: [%pa,%zx] np %ld -> sg %llx from %ps\n",
+	      &paddr, size, npages, ret, __builtin_return_address(0));
 
 	return ret;
 }
@@ -322,19 +320,18 @@ static struct pci_dev *alpha_gendev_to_pci(struct device *dev)
 	return NULL;
 }
 
-static dma_addr_t alpha_pci_map_page(struct device *dev, struct page *page,
-				     unsigned long offset, size_t size,
-				     enum dma_data_direction dir,
+static dma_addr_t alpha_pci_map_phys(struct device *dev, phys_addr_t phys,
+				     size_t size, enum dma_data_direction dir,
 				     unsigned long attrs)
 {
 	struct pci_dev *pdev = alpha_gendev_to_pci(dev);
 	int dac_allowed;
 
-	BUG_ON(dir == DMA_NONE);
+	if (attrs & DMA_ATTR_MMIO)
+		return DMA_MAPPING_ERROR;
 
-	dac_allowed = pdev ? pci_dac_dma_supported(pdev, pdev->dma_mask) : 0; 
-	return pci_map_single_1(pdev, (char *)page_address(page) + offset, 
-				size, dac_allowed);
+	dac_allowed = pdev ? pci_dac_dma_supported(pdev, pdev->dma_mask) : 0;
+	return pci_map_single_1(pdev, phys, size, dac_allowed);
 }
 
 /* Unmap a single streaming mode DMA translation.  The DMA_ADDR and
@@ -343,7 +340,7 @@ static dma_addr_t alpha_pci_map_page(struct device *dev, struct page *page,
    the cpu to the buffer are guaranteed to see whatever the device
    wrote there.  */
 
-static void alpha_pci_unmap_page(struct device *dev, dma_addr_t dma_addr,
+static void alpha_pci_unmap_phys(struct device *dev, dma_addr_t dma_addr,
 				 size_t size, enum dma_data_direction dir,
 				 unsigned long attrs)
 {
@@ -353,8 +350,6 @@ static void alpha_pci_unmap_page(struct device *dev, dma_addr_t dma_addr,
 	struct pci_iommu_arena *arena;
 	long dma_ofs, npages;
 
-	BUG_ON(dir == DMA_NONE);
-
 	if (dma_addr >= __direct_map_base
 	    && dma_addr < __direct_map_base + __direct_map_size) {
 		/* Nothing to do.  */
@@ -429,7 +424,7 @@ static void *alpha_pci_alloc_coherent(struct device *dev, size_t size,
 	}
 	memset(cpu_addr, 0, size);
 
-	*dma_addrp = pci_map_single_1(pdev, cpu_addr, size, 0);
+	*dma_addrp = pci_map_single_1(pdev, virt_to_phys(cpu_addr), size, 0);
 	if (*dma_addrp == DMA_MAPPING_ERROR) {
 		free_pages((unsigned long)cpu_addr, order);
 		if (alpha_mv.mv_pci_tbi || (gfp & GFP_DMA))
@@ -643,9 +638,8 @@ static int alpha_pci_map_sg(struct device *dev, struct scatterlist *sg,
 	/* Fast path single entry scatterlists.  */
 	if (nents == 1) {
 		sg->dma_length = sg->length;
-		sg->dma_address
-		  = pci_map_single_1(pdev, SG_ENT_VIRT_ADDRESS(sg),
-				     sg->length, dac_allowed);
+		sg->dma_address = pci_map_single_1(pdev, sg_phys(sg),
+						   sg->length, dac_allowed);
 		if (sg->dma_address == DMA_MAPPING_ERROR)
 			return -EIO;
 		return 1;
@@ -917,8 +911,8 @@ iommu_unbind(struct pci_iommu_arena *arena, long pg_start, long pg_count)
 const struct dma_map_ops alpha_pci_ops = {
 	.alloc			= alpha_pci_alloc_coherent,
 	.free			= alpha_pci_free_coherent,
-	.map_page		= alpha_pci_map_page,
-	.unmap_page		= alpha_pci_unmap_page,
+	.map_phys		= alpha_pci_map_phys,
+	.unmap_phys		= alpha_pci_unmap_phys,
 	.map_sg			= alpha_pci_map_sg,
 	.unmap_sg		= alpha_pci_unmap_sg,
 	.dma_supported		= alpha_pci_supported,
Signature · 1 line
2.51.0
maintainer Tested-by on v1 1/9
#2 lore raw

Re: [PATCH v1 1/9] alpha: Convert mapping routine to rely on physical address

Quoted 8 lines · Leon Romanovsky

From: Leon Romanovsky <[email protected]>

Alpha doesn't need struct *page and can perform mapping based on physical addresses. So convert it to implement new .map_phys callback.

As part of this change, remove useless BUG_ON() as DMA mapping layer ensures that right direction is provided.

After the changes in v1 this runs fine on Alpha. I've tested this on an ES40 Alphaserver during load (build kernel and unpack tar files). The v1 patch fixes the errors seen in the first revision of this patch.

Reviewed-by on v1 1/9
#3 lore raw

Re: [PATCH v1 1/9] alpha: Convert mapping routine to rely on physical address

In reply to Leon Romanovsky
Quoted 5 lines · Leon Romanovsky

From: Leon Romanovsky <[email protected]>

Alpha doesn't need struct *page and can perform mapping based on physical addresses. So convert it to implement new .map_phys callback.

Quoted 7 lines

As part of this change, remove useless BUG_ON() as DMA mapping layer ensures that right direction is provided.

---
 arch/alpha/kernel/pci_iommu.c | 48 +++++++++++++++--------------------
 1 file changed, 21 insertions(+), 27 deletions(-)

Jason

#4 lore raw

PATCH 2/9 MIPS/jazzdma: Provide physical address directly

In reply to Leon Romanovsky

From: Leon Romanovsky <[email protected]>

MIPS jazz uses physical addresses for mapping pages, so convert it to get them directly from DMA mapping routine.

---
 arch/mips/jazz/jazzdma.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)
arch/mips/jazz/jazzdma.c +13 -7
index c97b089b9902..45fe71aa454b 100644
@@ -521,18 +521,24 @@ static void jazz_dma_free(struct device *dev, size_t size, void *vaddr,
 	__free_pages(virt_to_page(vaddr), get_order(size));
 }
 
-static dma_addr_t jazz_dma_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 jazz_dma_map_phys(struct device *dev, phys_addr_t phys,
+		size_t size, enum dma_data_direction dir, unsigned long attrs)
 {
-	phys_addr_t phys = page_to_phys(page) + offset;
+	if (attrs & DMA_ATTR_MMIO)
+		/*
+		 * This check is included because older versions of the code lacked
+		 * MMIO path support, and my ability to test this path is limited.
+		 * However, from a software technical standpoint, there is no restriction,
+		 * as the following code operates solely on physical addresses.
+		 */
+		return DMA_MAPPING_ERROR;
 
 	if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
 		arch_sync_dma_for_device(phys, size, dir);
 	return vdma_alloc(phys, size);
 }
 
-static void jazz_dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
+static void jazz_dma_unmap_phys(struct device *dev, dma_addr_t dma_addr,
 		size_t size, enum dma_data_direction dir, unsigned long attrs)
 {
 	if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
@@ -607,8 +613,8 @@ static void jazz_dma_sync_sg_for_cpu(struct device *dev,
 const struct dma_map_ops jazz_dma_ops = {
 	.alloc			= jazz_dma_alloc,
 	.free			= jazz_dma_free,
-	.map_page		= jazz_dma_map_page,
-	.unmap_page		= jazz_dma_unmap_page,
+	.map_phys		= jazz_dma_map_phys,
+	.unmap_phys		= jazz_dma_unmap_phys,
 	.map_sg			= jazz_dma_map_sg,
 	.unmap_sg		= jazz_dma_unmap_sg,
 	.sync_single_for_cpu	= jazz_dma_sync_single_for_cpu,
Signature · 1 line
2.51.0
Reviewed-by on v1 2/9
#5 lore raw

Re: [PATCH v1 2/9] MIPS/jazzdma: Provide physical address directly

Quoted 9 lines · Leon Romanovsky

From: Leon Romanovsky <[email protected]>

MIPS jazz uses physical addresses for mapping pages, so convert it to get them directly from DMA mapping routine.

---
 arch/mips/jazz/jazzdma.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

arch/mips/jazz/jazzdma.c static void jazz_dma_free(struct device *dev, size_t size, void *vaddr, · line 527

Quoted 1 line
arch/mips/jazz/jazzdma.c +1 -0
+	if (attrs & DMA_ATTR_MMIO)

If this has to be respun I'd put an unlikely() here and the {}

Jason

#6 lore raw

PATCH 3/9 parisc: Convert DMA map_page to map_phys interface

In reply to Leon Romanovsky

From: Leon Romanovsky <[email protected]>

Perform mechanical conversion from .map_page to .map_phys callback.

---
 drivers/parisc/ccio-dma.c  | 25 +++++++++++++------------
 drivers/parisc/sba_iommu.c | 23 ++++++++++++-----------
 2 files changed, 25 insertions(+), 23 deletions(-)
drivers/parisc/ccio-dma.c +13 -12
index feef537257d0..d45f3634f827 100644
@@ -773,17 +773,18 @@ ccio_map_single(struct device *dev, void *addr, size_t size,
 
 
 static dma_addr_t
-ccio_map_page(struct device *dev, struct page *page, unsigned long offset,
-		size_t size, enum dma_data_direction direction,
-		unsigned long attrs)
+ccio_map_phys(struct device *dev, phys_addr_t phys, size_t size,
+	      enum dma_data_direction direction, unsigned long attrs)
 {
-	return ccio_map_single(dev, page_address(page) + offset, size,
-			direction);
+	if (attrs & DMA_ATTR_MMIO)
+		return DMA_MAPPING_ERROR;
+
+	return ccio_map_single(dev, phys_to_virt(phys), size, direction);
 }
 
 
 /**
- * ccio_unmap_page - Unmap an address range from the IOMMU.
+ * ccio_unmap_phys - Unmap an address range from the IOMMU.
  * @dev: The PCI device.
  * @iova: The start address of the DMA region.
  * @size: The length of the DMA region.
@@ -791,7 +792,7 @@ ccio_map_page(struct device *dev, struct page *page, unsigned long offset,
  * @attrs: attributes
  */
 static void 
-ccio_unmap_page(struct device *dev, dma_addr_t iova, size_t size,
+ccio_unmap_phys(struct device *dev, dma_addr_t iova, size_t size,
 		enum dma_data_direction direction, unsigned long attrs)
 {
 	struct ioc *ioc;
@@ -873,7 +874,7 @@ static void
 ccio_free(struct device *dev, size_t size, void *cpu_addr,
 		dma_addr_t dma_handle, unsigned long attrs)
 {
-	ccio_unmap_page(dev, dma_handle, size, 0, 0);
+	ccio_unmap_phys(dev, dma_handle, size, 0, 0);
 	free_pages((unsigned long)cpu_addr, get_order(size));
 }
 
@@ -1004,7 +1005,7 @@ ccio_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
 #ifdef CCIO_COLLECT_STATS
 		ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT;
 #endif
-		ccio_unmap_page(dev, sg_dma_address(sglist),
+		ccio_unmap_phys(dev, sg_dma_address(sglist),
 				  sg_dma_len(sglist), direction, 0);
 		++sglist;
 		nents--;
@@ -1017,8 +1018,8 @@ static const struct dma_map_ops ccio_ops = {
 	.dma_supported =	ccio_dma_supported,
 	.alloc =		ccio_alloc,
 	.free =			ccio_free,
-	.map_page =		ccio_map_page,
-	.unmap_page =		ccio_unmap_page,
+	.map_phys =		ccio_map_phys,
+	.unmap_phys =		ccio_unmap_phys,
 	.map_sg =		ccio_map_sg,
 	.unmap_sg =		ccio_unmap_sg,
 	.get_sgtable =		dma_common_get_sgtable,
@@ -1072,7 +1073,7 @@ static int ccio_proc_info(struct seq_file *m, void *p)
 			   ioc->msingle_calls, ioc->msingle_pages,
 			   (int)((ioc->msingle_pages * 1000)/ioc->msingle_calls));
 
-		/* KLUGE - unmap_sg calls unmap_page for each mapped page */
+		/* KLUGE - unmap_sg calls unmap_phys for each mapped page */
 		min = ioc->usingle_calls - ioc->usg_calls;
 		max = ioc->usingle_pages - ioc->usg_pages;
 		seq_printf(m, "pci_unmap_single: %8ld calls  %8ld pages (avg %d/1000)\n",
drivers/parisc/sba_iommu.c +12 -11
index fc3863c09f83..8040aa4e6ff4 100644
@@ -778,17 +778,18 @@ sba_map_single(struct device *dev, void *addr, size_t size,
 
 
 static dma_addr_t
-sba_map_page(struct device *dev, struct page *page, unsigned long offset,
-		size_t size, enum dma_data_direction direction,
-		unsigned long attrs)
+sba_map_phys(struct device *dev, phys_addr_t phys, size_t size,
+		enum dma_data_direction direction, unsigned long attrs)
 {
-	return sba_map_single(dev, page_address(page) + offset, size,
-			direction);
+	if (attrs & DMA_ATTR_MMIO)
+		return DMA_MAPPING_ERROR;
+
+	return sba_map_single(dev, phys_to_virt(phys), size, direction);
 }
 
 
 /**
- * sba_unmap_page - unmap one IOVA and free resources
+ * sba_unmap_phys - unmap one IOVA and free resources
  * @dev: instance of PCI owned by the driver that's asking.
  * @iova:  IOVA of driver buffer previously mapped.
  * @size:  number of bytes mapped in driver buffer.
@@ -798,7 +799,7 @@ sba_map_page(struct device *dev, struct page *page, unsigned long offset,
  * See Documentation/core-api/dma-api-howto.rst
  */
 static void
-sba_unmap_page(struct device *dev, dma_addr_t iova, size_t size,
+sba_unmap_phys(struct device *dev, dma_addr_t iova, size_t size,
 		enum dma_data_direction direction, unsigned long attrs)
 {
 	struct ioc *ioc;
@@ -914,7 +915,7 @@ static void
 sba_free(struct device *hwdev, size_t size, void *vaddr,
 		    dma_addr_t dma_handle, unsigned long attrs)
 {
-	sba_unmap_page(hwdev, dma_handle, size, 0, 0);
+	sba_unmap_phys(hwdev, dma_handle, size, 0, 0);
 	free_pages((unsigned long) vaddr, get_order(size));
 }
 
@@ -1061,7 +1062,7 @@ sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
 
 	while (nents && sg_dma_len(sglist)) {
 
-		sba_unmap_page(dev, sg_dma_address(sglist), sg_dma_len(sglist),
+		sba_unmap_phys(dev, sg_dma_address(sglist), sg_dma_len(sglist),
 				direction, 0);
 #ifdef SBA_COLLECT_STATS
 		ioc->usg_pages += ((sg_dma_address(sglist) & ~IOVP_MASK) + sg_dma_len(sglist) + IOVP_SIZE - 1) >> PAGE_SHIFT;
@@ -1085,8 +1086,8 @@ static const struct dma_map_ops sba_ops = {
 	.dma_supported =	sba_dma_supported,
 	.alloc =		sba_alloc,
 	.free =			sba_free,
-	.map_page =		sba_map_page,
-	.unmap_page =		sba_unmap_page,
+	.map_phys =		sba_map_phys,
+	.unmap_phys =		sba_unmap_phys,
 	.map_sg =		sba_map_sg,
 	.unmap_sg =		sba_unmap_sg,
 	.get_sgtable =		dma_common_get_sgtable,
Signature · 1 line
2.51.0
Reviewed-by on v1 3/9
#7 lore raw

Re: [PATCH v1 3/9] parisc: Convert DMA map_page to map_phys interface

drivers/parisc/ccio-dma.c ccio_map_single(struct device *dev, void *addr, size_t size, · line 782

Quoted 9 lines · Leon Romanovsky
drivers/parisc/ccio-dma.c +6 -2
+ccio_map_phys(struct device *dev, phys_addr_t phys, size_t size,
+	      enum dma_data_direction direction, unsigned long attrs)
 {
-	return ccio_map_single(dev, page_address(page) + offset, size,
-			direction);
+	if (attrs & DMA_ATTR_MMIO)
+		return DMA_MAPPING_ERROR;
+
+	return ccio_map_single(dev, phys_to_virt(phys), size, direction);

This doesn't actually use the virt at all:

	offset = ((unsigned long) addr) & ~IOVP_MASK;
	if((size % L1_CACHE_BYTES) || ((unsigned long)addr % L1_CACHE_BYTES))
		ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long)addr, hint);

And ccio_io_pdir_entry():

	pa = lpa(vba);

Is a special instruction that uses virt but AI tells me that special LPA instruction is returning phys. Not sure if that is a different value than virt_to_phys()..

IDK, I'm not feeling brave enough to drop the LPA but maybe include this note in the commit message.

Jason

#8 lore raw

Re: [PATCH v1 3/9] parisc: Convert DMA map_page to map_phys interface

Quoted 6 lines · Jason Gunthorpe

This doesn't actually use the virt at all:

	offset = ((unsigned long) addr) & ~IOVP_MASK;
	if((size % L1_CACHE_BYTES) || ((unsigned long)addr % L1_CACHE_BYTES))
		ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long)addr, hint);
Quoted 6 lines

And ccio_io_pdir_entry():

	pa = lpa(vba);

Is a special instruction that uses virt but AI tells me that special LPA instruction is returning phys. Not sure if that is a different value than virt_to_phys()..

ccio_io_pdir_entry currently only supports KERNEL_SPACE. For KERNEL_SPACE, lpa() and virt_to_phys() are equivalent if page is mapped. lpa() returns 0 if a non-access data TLB fault occurs (i.e., page isn't mapped). Not sure if that matters.

Quoted 3 lines

IDK, I'm not feeling brave enough to drop the LPA but maybe include this note in the commit message.

Signature · 1 line
John David Anglin  [email protected]
#9 lore raw

Re: [PATCH v1 3/9] parisc: Convert DMA map_page to map_phys interface

Quoted 10 lines · John David Anglin
Quoted 9 lines · Jason Gunthorpe

This doesn't actually use the virt at all:

	offset = ((unsigned long) addr) & ~IOVP_MASK;
	if((size % L1_CACHE_BYTES) || ((unsigned long)addr % L1_CACHE_BYTES))
		ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long)addr, hint);

And ccio_io_pdir_entry():

	pa = lpa(vba);
Quoted 8 lines
Quoted 3 lines

Is a special instruction that uses virt but AI tells me that special LPA instruction is returning phys. Not sure if that is a different value than virt_to_phys()..

ccio_io_pdir_entry currently only supports KERNEL_SPACE. For KERNEL_SPACE, lpa() and virt_to_phys() are equivalent if page is mapped. lpa() returns 0 if a non-access data TLB fault occurs (i.e., page isn't mapped). Not sure if that
matters.

After unfolding everything the expression is

lpa(phys_to_virt(pa))

So if that is always equal to pa then lets just drop it.

phys_to_virt() always returns something kernel mapped, and it can't be unmapped.

Jason

#10 lore raw

Re: [PATCH v1 3/9] parisc: Convert DMA map_page to map_phys interface

Quoted 20 lines · Jason Gunthorpe
Quoted 10 lines · John David Anglin
Quoted 9 lines · Jason Gunthorpe

This doesn't actually use the virt at all:

	offset = ((unsigned long) addr) & ~IOVP_MASK;
	if((size % L1_CACHE_BYTES) || ((unsigned long)addr % L1_CACHE_BYTES))
		ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long)addr, hint);

And ccio_io_pdir_entry():

	pa = lpa(vba);
Quoted 8 lines
Quoted 3 lines

Is a special instruction that uses virt but AI tells me that special LPA instruction is returning phys. Not sure if that is a different value than virt_to_phys()..

ccio_io_pdir_entry currently only supports KERNEL_SPACE. For KERNEL_SPACE, lpa() and virt_to_phys() are equivalent if page is mapped. lpa() returns 0 if a non-access data TLB fault occurs (i.e., page isn't mapped). Not sure if that
matters.

Quoted 5 lines

After unfolding everything the expression is

lpa(phys_to_virt(pa))

So if that is always equal to pa then lets just drop it.

If lpa() was replaced by virt_to_phys(), the result would always be equal to pa. So, I think it can be dropped.

Dave

Signature · 1 line
John David Anglin  [email protected]
maintainer
#11 lore raw

Re: [PATCH v1 3/9] parisc: Convert DMA map_page to map_phys interface

In reply to John David Anglin
Quoted 9 lines · John David Anglin
Quoted 8 lines · Jason Gunthorpe

This doesn't actually use the virt at all:

	offset = ((unsigned long) addr) & ~IOVP_MASK;
	if((size % L1_CACHE_BYTES) || ((unsigned long)addr %

L1_CACHE_BYTES))
ccio_io_pdir_entry(pdir_start, KERNEL_SPACE,
(unsigned long)addr, hint);

Quoted 8 lines
Quoted 6 lines

And ccio_io_pdir_entry():

	pa = lpa(vba);

Is a special instruction that uses virt but AI tells me that special LPA instruction is returning phys. Not sure if that is a different value than virt_to_phys()..

ccio_io_pdir_entry currently only supports KERNEL_SPACE.

Actually there's a bit more nuance to it than that. Obviously DMA has to support user pages otherwise I/O wouldn't work. The way it does is that all physical pages are mapped in the kernel and we try to make sure all user mappings are on cache stride (4MB) boundaries so the coherence index of the kernel virtual address and the user virtual address are the same, so we can solely use the kernel virtual address to calculate the coherence index for the IOMMU. If that's not true, we flush the user virtual address range in gup and the kernel virtual address range before sending the I/O completion.

Regards,

James

#12 lore raw

Re: [PATCH v1 3/9] parisc: Convert DMA map_page to map_phys interface

In reply to Jason Gunthorpe
Quoted 18 lines · Jason Gunthorpe

Review

Quoted 9 lines · Leon Romanovsky
(quoted diff) +6 -2
+ccio_map_phys(struct device *dev, phys_addr_t phys, size_t size,
+	      enum dma_data_direction direction, unsigned long attrs)
 {
-	return ccio_map_single(dev, page_address(page) + offset, size,
-			direction);
+	if (attrs & DMA_ATTR_MMIO)
+		return DMA_MAPPING_ERROR;
+
+	return ccio_map_single(dev, phys_to_virt(phys), size, direction);

This doesn't actually use the virt at all:

	offset = ((unsigned long) addr) & ~IOVP_MASK;
	if((size % L1_CACHE_BYTES) || ((unsigned long)addr % L1_CACHE_BYTES))
		ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long)addr, hint);

And ccio_io_pdir_entry():

Quoted 9 lines
	pa = lpa(vba);

Is a special instruction that uses virt but AI tells me that special LPA instruction is returning phys. Not sure if that is a different value than virt_to_phys()..

IDK, I'm not feeling brave enough to drop the LPA but maybe include this note in the commit message.

It looks like I was chosen as a volunteer to do so. WDYT?

drivers/parisc/ccio-dma.c +16 -15
index b00f6fc49063..4d73e67fbd54 100644
@@ -517,10 +517,10 @@ static u32 hint_lookup[] = {
  * ccio_io_pdir_entry - Initialize an I/O Pdir.
  * @pdir_ptr: A pointer into I/O Pdir.
  * @sid: The Space Identifier.
- * @vba: The virtual address.
+ * @pba: The physical address.
  * @hints: The DMA Hint.
  *
- * Given a virtual address (vba, arg2) and space id, (sid, arg1),
+ * Given a physical address (pba, arg2) and space id, (sid, arg1),
  * load the I/O PDIR entry pointed to by pdir_ptr (arg0). Each IO Pdir
  * entry consists of 8 bytes as shown below (MSB == bit 0):
  *
@@ -543,7 +543,7 @@ static u32 hint_lookup[] = {
  * index are bits 12:19 of the value returned by LCI.
  */
 static void
-ccio_io_pdir_entry(__le64 *pdir_ptr, space_t sid, unsigned long vba,
+ccio_io_pdir_entry(__le64 *pdir_ptr, space_t sid, phys_addr_t pba,
                   unsigned long hints)
 {
        register unsigned long pa;
@@ -557,7 +557,7 @@ ccio_io_pdir_entry(__le64 *pdir_ptr, space_t sid, unsigned long vba,
        ** "hints" parm includes the VALID bit!
        ** "dep" clobbers the physical address offset bits as well.
        */
-       pa = lpa(vba);
+       pa = pba;
        asm volatile("depw  %1,31,12,%0" : "+r" (pa) : "r" (hints));
        ((u32 *)pdir_ptr)[1] = (u32) pa;
 
@@ -582,7 +582,7 @@ ccio_io_pdir_entry(__le64 *pdir_ptr, space_t sid, unsigned long vba,
        ** Grab virtual index [0:11]
        ** Deposit virt_idx bits into I/O PDIR word
        */
-       asm volatile ("lci %%r0(%1), %0" : "=r" (ci) : "r" (vba));
+       asm volatile ("lci %%r0(%1), %0" : "=r" (ci) : "r" (pba));
        asm volatile ("extru %1,19,12,%0" : "+r" (ci) : "r" (ci));
        asm volatile ("depw  %1,15,12,%0" : "+r" (pa) : "r" (ci));
 
@@ -704,14 +704,14 @@ ccio_dma_supported(struct device *dev, u64 mask)
 /**
  * ccio_map_single - Map an address range into the IOMMU.
  * @dev: The PCI device.
- * @addr: The start address of the DMA region.
+ * @addr: The physical address of the DMA region.
  * @size: The length of the DMA region.
  * @direction: The direction of the DMA transaction (to/from device).
  *
  * This function implements the pci_map_single function.
  */
 static dma_addr_t 
-ccio_map_single(struct device *dev, void *addr, size_t size,
+ccio_map_single(struct device *dev, phys_addr_t addr, size_t size,
                enum dma_data_direction direction)
 {
        int idx;
@@ -730,7 +730,7 @@ ccio_map_single(struct device *dev, void *addr, size_t size,
        BUG_ON(size <= 0);
 
        /* save offset bits */
-       offset = ((unsigned long) addr) & ~IOVP_MASK;
+       offset = offset_in_page(addr);
 
        /* round up to nearest IOVP_SIZE */
        size = ALIGN(size + offset, IOVP_SIZE);
@@ -746,15 +746,15 @@ ccio_map_single(struct device *dev, void *addr, size_t size,
 
        pdir_start = &(ioc->pdir_base[idx]);
 
-       DBG_RUN("%s() %px -> %#lx size: %zu\n",
-               __func__, addr, (long)(iovp | offset), size);
+       DBG_RUN("%s() %pa -> %#lx size: %zu\n",
+               __func__, &addr, (long)(iovp | offset), size);
 
        /* If not cacheline aligned, force SAFE_DMA on the whole mess */
-       if((size % L1_CACHE_BYTES) || ((unsigned long)addr % L1_CACHE_BYTES))
+       if((size % L1_CACHE_BYTES) || (addr % L1_CACHE_BYTES))
                hint |= HINT_SAFE_DMA;
 
        while(size > 0) {
-               ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long)addr, hint);
+               ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, addr, hint);
 
                DBG_RUN(" pdir %p %08x%08x\n",
                        pdir_start,
@@ -779,7 +779,7 @@ ccio_map_phys(struct device *dev, phys_addr_t phys, size_t size,
        if (unlikely(attrs & DMA_ATTR_MMIO))
                return DMA_MAPPING_ERROR;
 
-       return ccio_map_single(dev, phys_to_virt(phys), size, direction);
+       return ccio_map_single(dev, phys, size, direction);
 }
 
 
@@ -854,7 +854,8 @@ ccio_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag,
 
        if (ret) {
                memset(ret, 0, size);
-               *dma_handle = ccio_map_single(dev, ret, size, DMA_BIDIRECTIONAL);
+               *dma_handle = ccio_map_single(dev, virt_to_phys(ret), size,
+                                             DMA_BIDIRECTIONAL);
        }
 
        return ret;
@@ -921,7 +922,7 @@ ccio_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
        /* Fast path single entry scatterlists. */
        if (nents == 1) {
                sg_dma_address(sglist) = ccio_map_single(dev,
-                               sg_virt(sglist), sglist->length,
+                               sg_phys(sglist), sglist->length,
                                direction);
                sg_dma_len(sglist) = sglist->length;
                return 1;
Quoted 3 lines

Jason

#13 lore raw

Re: [PATCH v1 3/9] parisc: Convert DMA map_page to map_phys interface

drivers/parisc/ccio-dma.c ccio_io_pdir_entry(__le64 *pdir_ptr, space_t sid, unsigned long vba, · line 585

Quoted 6 lines · Leon Romanovsky
drivers/parisc/ccio-dma.c +1 -1
@@ -582,7 +582,7 @@ ccio_io_pdir_entry(__le64 *pdir_ptr, space_t sid, unsigned long vba,
        ** Grab virtual index [0:11]
        ** Deposit virt_idx bits into I/O PDIR word
        */
-       asm volatile ("lci %%r0(%1), %0" : "=r" (ci) : "r" (vba));
+       asm volatile ("lci %%r0(%1), %0" : "=r" (ci) : "r" (pba));

Don't know how I missed this, but this is the virtual address for the cache invalidate James mentioned

So the optimal is to drop the lpa() and to use phys_to_virt() to get vba for this instruction.

Jason

#14 lore raw

Re: [PATCH v1 3/9] parisc: Convert DMA map_page to map_phys interface

Quoted 11 lines · Jason Gunthorpe

drivers/parisc/ccio-dma.c ccio_io_pdir_entry(__le64 *pdir_ptr, space_t sid, unsigned long vba, · line 585

Quoted 6 lines · Leon Romanovsky
drivers/parisc/ccio-dma.c +1 -1
@@ -582,7 +582,7 @@ ccio_io_pdir_entry(__le64 *pdir_ptr, space_t sid, unsigned long vba,
        ** Grab virtual index [0:11]
        ** Deposit virt_idx bits into I/O PDIR word
        */
-       asm volatile ("lci %%r0(%1), %0" : "=r" (ci) : "r" (vba));
+       asm volatile ("lci %%r0(%1), %0" : "=r" (ci) : "r" (pba));

Don't know how I missed this, but this is the virtual address for the cache invalidate James mentioned

Quoted 2 lines

So the optimal is to drop the lpa() and to use phys_to_virt() to get vba for this instruction.

The optimal is to keep parisc arch code as I did in v1 and don't change it too much.

Quoted 2 lines

Jason

maintainer
#15 lore raw

Re: [PATCH v1 3/9] parisc: Convert DMA map_page to map_phys interface

In reply to Jason Gunthorpe
Quoted 16 lines · Jason Gunthorpe
Quoted 11 lines · Leon Romanovsky
(quoted diff) +2 -0
+ccio_map_phys(struct device *dev, phys_addr_t phys, size_t size,
+	      enum dma_data_direction direction, unsigned long

attrs)
 {

(quoted diff) +0 -1
-	return ccio_map_single(dev, page_address(page) + offset,

size,

drivers/parisc/ccio-dma.c +4 -1
-			direction);
+	if (attrs & DMA_ATTR_MMIO)
+		return DMA_MAPPING_ERROR;
+
+	return ccio_map_single(dev, phys_to_virt(phys), size,
Quoted 1 line

direction);

This doesn't actually use the virt at all:

Quoted 5 lines
	offset = ((unsigned long) addr) & ~IOVP_MASK;
	if((size % L1_CACHE_BYTES) || ((unsigned long)addr %

L1_CACHE_BYTES))
ccio_io_pdir_entry(pdir_start, KERNEL_SPACE,
(unsigned long)addr, hint);

Actually, it does: it has to; parisc caches are VIPT. The iommu needs to know both the physical address and the virtual tag (also called the coherence index) to instruct the CPU to flush its cache. The sole use of the vba is in ccio_io_pdir_entry() which programs the IOMMU page table. The coherence index is pretty small because the largest VIPT cache stride parisc has is 4MB and obviously the lower 12 bits (page offset) are the same for both physical and virtual, so it's only the 10 bits between 4k and 4M that the iommu needs (the entry is 12 bits because architecturally there were chips with a 16M stride planned for but never produced).

Quoted 7 lines

And ccio_io_pdir_entry():

	pa = lpa(vba);

Is a special instruction that uses virt but AI tells me that special LPA instruction is returning phys. Not sure if that is a different value than virt_to_phys()..

That's right, so if you want to pass both phys and virt addresses to the function, this could be dropped.

Regards,

James

#16 lore raw

PATCH 4/9 powerpc: Convert to physical address DMA mapping

In reply to Leon Romanovsky

From: Leon Romanovsky <[email protected]>

Adapt PowerPC DMA to use physical addresses in order to prepare code to removal .map_page and .unmap_page.

---
 arch/powerpc/include/asm/iommu.h         |  8 +++---
 arch/powerpc/kernel/dma-iommu.c          | 22 +++++++---------
 arch/powerpc/kernel/iommu.c              | 14 +++++-----
 arch/powerpc/platforms/ps3/system-bus.c  | 33 ++++++++++++++----------
 arch/powerpc/platforms/pseries/ibmebus.c | 15 ++++++-----
 arch/powerpc/platforms/pseries/vio.c     | 21 ++++++++-------
 6 files changed, 60 insertions(+), 53 deletions(-)
arch/powerpc/include/asm/iommu.h +4 -4
index b410021ad4c6..eafdd63cd6c4 100644
@@ -274,12 +274,12 @@ extern void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl,
 				  unsigned long mask, gfp_t flag, int node);
 extern void iommu_free_coherent(struct iommu_table *tbl, size_t size,
 				void *vaddr, dma_addr_t dma_handle);
-extern dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl,
-				 struct page *page, unsigned long offset,
-				 size_t size, unsigned long mask,
+extern dma_addr_t iommu_map_phys(struct device *dev, struct iommu_table *tbl,
+				 phys_addr_t phys, size_t size,
+				 unsigned long mask,
 				 enum dma_data_direction direction,
 				 unsigned long attrs);
-extern void iommu_unmap_page(struct iommu_table *tbl, dma_addr_t dma_handle,
+extern void iommu_unmap_phys(struct iommu_table *tbl, dma_addr_t dma_handle,
 			     size_t size, enum dma_data_direction direction,
 			     unsigned long attrs);
 
arch/powerpc/kernel/dma-iommu.c +10 -12
index 0359ab72cd3b..aa3689d61917 100644
@@ -93,28 +93,26 @@ static void dma_iommu_free_coherent(struct device *dev, size_t size,
 
 /* Creates TCEs for a user provided buffer.  The user buffer must be
  * contiguous real kernel storage (not vmalloc).  The address passed here
- * comprises a page address and offset into that page. The dma_addr_t
- * returned will point to the same byte within the page as was passed in.
+ * is a physical address to that page. The dma_addr_t returned will point
+ * to the same byte within the page as was passed in.
  */
-static dma_addr_t dma_iommu_map_page(struct device *dev, struct page *page,
-				     unsigned long offset, size_t size,
+static dma_addr_t dma_iommu_map_phys(struct device *dev, phys_addr_t phys,
+				     size_t size,
 				     enum dma_data_direction direction,
 				     unsigned long attrs)
 {
-	return iommu_map_page(dev, get_iommu_table_base(dev), page, offset,
-			      size, dma_get_mask(dev), direction, attrs);
+	return iommu_map_phys(dev, get_iommu_table_base(dev), phys, size,
+			      dma_get_mask(dev), direction, attrs);
 }
 
-
-static void dma_iommu_unmap_page(struct device *dev, dma_addr_t dma_handle,
+static void dma_iommu_unmap_phys(struct device *dev, dma_addr_t dma_handle,
 				 size_t size, enum dma_data_direction direction,
 				 unsigned long attrs)
 {
-	iommu_unmap_page(get_iommu_table_base(dev), dma_handle, size, direction,
+	iommu_unmap_phys(get_iommu_table_base(dev), dma_handle, size, direction,
 			 attrs);
 }
 
-
 static int dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist,
 			    int nelems, enum dma_data_direction direction,
 			    unsigned long attrs)
@@ -211,8 +209,8 @@ const struct dma_map_ops dma_iommu_ops = {
 	.map_sg			= dma_iommu_map_sg,
 	.unmap_sg		= dma_iommu_unmap_sg,
 	.dma_supported		= dma_iommu_dma_supported,
-	.map_page		= dma_iommu_map_page,
-	.unmap_page		= dma_iommu_unmap_page,
+	.map_phys		= dma_iommu_map_phys,
+	.unmap_phys		= dma_iommu_unmap_phys,
 	.get_required_mask	= dma_iommu_get_required_mask,
 	.mmap			= dma_common_mmap,
 	.get_sgtable		= dma_common_get_sgtable,
arch/powerpc/kernel/iommu.c +7 -7
index 244eb4857e7f..6b5f4b72ce97 100644
@@ -848,12 +848,12 @@ EXPORT_SYMBOL_GPL(iommu_tce_table_put);
 
 /* Creates TCEs for a user provided buffer.  The user buffer must be
  * contiguous real kernel storage (not vmalloc).  The address passed here
- * comprises a page address and offset into that page. The dma_addr_t
- * returned will point to the same byte within the page as was passed in.
+ * is physical address into that page. The dma_addr_t returned will point
+ * to the same byte within the page as was passed in.
  */
-dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl,
-			  struct page *page, unsigned long offset, size_t size,
-			  unsigned long mask, enum dma_data_direction direction,
+dma_addr_t iommu_map_phys(struct device *dev, struct iommu_table *tbl,
+			  phys_addr_t phys, size_t size, unsigned long mask,
+			  enum dma_data_direction direction,
 			  unsigned long attrs)
 {
 	dma_addr_t dma_handle = DMA_MAPPING_ERROR;
@@ -863,7 +863,7 @@ dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl,
 
 	BUG_ON(direction == DMA_NONE);
 
-	vaddr = page_address(page) + offset;
+	vaddr = phys_to_virt(phys);
 	uaddr = (unsigned long)vaddr;
 
 	if (tbl) {
@@ -890,7 +890,7 @@ dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl,
 	return dma_handle;
 }
 
-void iommu_unmap_page(struct iommu_table *tbl, dma_addr_t dma_handle,
+void iommu_unmap_phys(struct iommu_table *tbl, dma_addr_t dma_handle,
 		      size_t size, enum dma_data_direction direction,
 		      unsigned long attrs)
 {
arch/powerpc/platforms/ps3/system-bus.c +19 -14
index afbaabf182d0..a223ba777148 100644
@@ -551,18 +551,20 @@ static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr,
 
 /* Creates TCEs for a user provided buffer.  The user buffer must be
  * contiguous real kernel storage (not vmalloc).  The address passed here
- * comprises a page address and offset into that page. The dma_addr_t
- * returned will point to the same byte within the page as was passed in.
+ * is physical address to that hat page. The dma_addr_t returned will point
+ * to the same byte within the page as was passed in.
  */
 
-static dma_addr_t ps3_sb_map_page(struct device *_dev, struct page *page,
-	unsigned long offset, size_t size, enum dma_data_direction direction,
-	unsigned long attrs)
+static dma_addr_t ps3_sb_map_phys(struct device *_dev, phys_addr_t phys,
+	size_t size, enum dma_data_direction direction, unsigned long attrs)
 {
 	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
 	int result;
 	dma_addr_t bus_addr;
-	void *ptr = page_address(page) + offset;
+	void *ptr = phys_to_virt(phys);
+
+	if (attrs & DMA_ATTR_MMIO)
+		return DMA_MAPPING_ERROR;
 
 	result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size,
 			     &bus_addr,
@@ -577,8 +579,8 @@ static dma_addr_t ps3_sb_map_page(struct device *_dev, struct page *page,
 	return bus_addr;
 }
 
-static dma_addr_t ps3_ioc0_map_page(struct device *_dev, struct page *page,
-				    unsigned long offset, size_t size,
+static dma_addr_t ps3_ioc0_map_phys(struct device *_dev, phys_addr_t phys,
+				    size_t size,
 				    enum dma_data_direction direction,
 				    unsigned long attrs)
 {
@@ -586,7 +588,10 @@ static dma_addr_t ps3_ioc0_map_page(struct device *_dev, struct page *page,
 	int result;
 	dma_addr_t bus_addr;
 	u64 iopte_flag;
-	void *ptr = page_address(page) + offset;
+	void *ptr = phys_to_virt(phys);
+
+	if (attrs & DMA_ATTR_MMIO)
+		return DMA_MAPPING_ERROR;
 
 	iopte_flag = CBE_IOPTE_M;
 	switch (direction) {
@@ -613,7 +618,7 @@ static dma_addr_t ps3_ioc0_map_page(struct device *_dev, struct page *page,
 	return bus_addr;
 }
 
-static void ps3_unmap_page(struct device *_dev, dma_addr_t dma_addr,
+static void ps3_unmap_phys(struct device *_dev, dma_addr_t dma_addr,
 	size_t size, enum dma_data_direction direction, unsigned long attrs)
 {
 	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
@@ -690,8 +695,8 @@ static const struct dma_map_ops ps3_sb_dma_ops = {
 	.map_sg = ps3_sb_map_sg,
 	.unmap_sg = ps3_sb_unmap_sg,
 	.dma_supported = ps3_dma_supported,
-	.map_page = ps3_sb_map_page,
-	.unmap_page = ps3_unmap_page,
+	.map_phys = ps3_sb_map_phys,
+	.unmap_phys = ps3_unmap_phys,
 	.mmap = dma_common_mmap,
 	.get_sgtable = dma_common_get_sgtable,
 	.alloc_pages_op = dma_common_alloc_pages,
@@ -704,8 +709,8 @@ static const struct dma_map_ops ps3_ioc0_dma_ops = {
 	.map_sg = ps3_ioc0_map_sg,
 	.unmap_sg = ps3_ioc0_unmap_sg,
 	.dma_supported = ps3_dma_supported,
-	.map_page = ps3_ioc0_map_page,
-	.unmap_page = ps3_unmap_page,
+	.map_phys = ps3_ioc0_map_phys,
+	.unmap_phys = ps3_unmap_phys,
 	.mmap = dma_common_mmap,
 	.get_sgtable = dma_common_get_sgtable,
 	.alloc_pages_op = dma_common_alloc_pages,
arch/powerpc/platforms/pseries/ibmebus.c +8 -7
index 3436b0af795e..cad2deb7e70d 100644
@@ -86,17 +86,18 @@ static void ibmebus_free_coherent(struct device *dev,
 	kfree(vaddr);
 }
 
-static dma_addr_t ibmebus_map_page(struct device *dev,
-				   struct page *page,
-				   unsigned long offset,
+static dma_addr_t ibmebus_map_phys(struct device *dev, phys_addr_t phys,
 				   size_t size,
 				   enum dma_data_direction direction,
 				   unsigned long attrs)
 {
-	return (dma_addr_t)(page_address(page) + offset);
+	if (attrs & DMA_ATTR_MMIO)
+		return DMA_MAPPING_ERROR;
+
+	return (dma_addr_t)(phys_to_virt(phys));
 }
 
-static void ibmebus_unmap_page(struct device *dev,
+static void ibmebus_unmap_phys(struct device *dev,
 			       dma_addr_t dma_addr,
 			       size_t size,
 			       enum dma_data_direction direction,
@@ -146,8 +147,8 @@ static const struct dma_map_ops ibmebus_dma_ops = {
 	.unmap_sg           = ibmebus_unmap_sg,
 	.dma_supported      = ibmebus_dma_supported,
 	.get_required_mask  = ibmebus_dma_get_required_mask,
-	.map_page           = ibmebus_map_page,
-	.unmap_page         = ibmebus_unmap_page,
+	.map_phys           = ibmebus_map_phys,
+	.unmap_phys         = ibmebus_unmap_phys,
 };
 
 static int ibmebus_match_path(struct device *dev, const void *data)
arch/powerpc/platforms/pseries/vio.c +12 -9
index ac1d2d2c9a88..838e29d47378 100644
@@ -512,18 +512,21 @@ static void vio_dma_iommu_free_coherent(struct device *dev, size_t size,
 	vio_cmo_dealloc(viodev, roundup(size, PAGE_SIZE));
 }
 
-static dma_addr_t vio_dma_iommu_map_page(struct device *dev, struct page *page,
-                                         unsigned long offset, size_t size,
-                                         enum dma_data_direction direction,
-                                         unsigned long attrs)
+static dma_addr_t vio_dma_iommu_map_phys(struct device *dev, phys_addr_t phys,
+					 size_t size,
+					 enum dma_data_direction direction,
+					 unsigned long attrs)
 {
 	struct vio_dev *viodev = to_vio_dev(dev);
 	struct iommu_table *tbl = get_iommu_table_base(dev);
 	dma_addr_t ret = DMA_MAPPING_ERROR;
 
+	if (attrs & DMA_ATTR_MMIO)
+		return ret;
+
 	if (vio_cmo_alloc(viodev, roundup(size, IOMMU_PAGE_SIZE(tbl))))
 		goto out_fail;
-	ret = iommu_map_page(dev, tbl, page, offset, size, dma_get_mask(dev),
+	ret = iommu_map_phys(dev, tbl, phys, size, dma_get_mask(dev),
 			direction, attrs);
 	if (unlikely(ret == DMA_MAPPING_ERROR))
 		goto out_deallocate;
@@ -536,7 +539,7 @@ static dma_addr_t vio_dma_iommu_map_page(struct device *dev, struct page *page,
 	return DMA_MAPPING_ERROR;
 }
 
-static void vio_dma_iommu_unmap_page(struct device *dev, dma_addr_t dma_handle,
+static void vio_dma_iommu_unmap_phys(struct device *dev, dma_addr_t dma_handle,
 				     size_t size,
 				     enum dma_data_direction direction,
 				     unsigned long attrs)
@@ -544,7 +547,7 @@ static void vio_dma_iommu_unmap_page(struct device *dev, dma_addr_t dma_handle,
 	struct vio_dev *viodev = to_vio_dev(dev);
 	struct iommu_table *tbl = get_iommu_table_base(dev);
 
-	iommu_unmap_page(tbl, dma_handle, size, direction, attrs);
+	iommu_unmap_phys(tbl, dma_handle, size, direction, attrs);
 	vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE(tbl)));
 }
 
@@ -605,8 +608,8 @@ static const struct dma_map_ops vio_dma_mapping_ops = {
 	.free              = vio_dma_iommu_free_coherent,
 	.map_sg            = vio_dma_iommu_map_sg,
 	.unmap_sg          = vio_dma_iommu_unmap_sg,
-	.map_page          = vio_dma_iommu_map_page,
-	.unmap_page        = vio_dma_iommu_unmap_page,
+	.map_phys          = vio_dma_iommu_map_phys,
+	.unmap_phys        = vio_dma_iommu_unmap_phys,
 	.dma_supported     = dma_iommu_dma_supported,
 	.get_required_mask = dma_iommu_get_required_mask,
 	.mmap		   = dma_common_mmap,
Signature · 1 line
2.51.0
Reviewed-by on v1 4/9
#17 lore raw

Re: [PATCH v1 4/9] powerpc: Convert to physical address DMA mapping

Quoted 6 lines · Leon Romanovsky

From: Leon Romanovsky <[email protected]>

Adapt PowerPC DMA to use physical addresses in order to prepare code to removal .map_page and .unmap_page.

Quoted 8 lines
---
 arch/powerpc/include/asm/iommu.h         |  8 +++---
 arch/powerpc/kernel/dma-iommu.c          | 22 +++++++---------
 arch/powerpc/kernel/iommu.c              | 14 +++++-----
 arch/powerpc/platforms/ps3/system-bus.c  | 33 ++++++++++++++----------
 arch/powerpc/platforms/pseries/ibmebus.c | 15 ++++++-----
 arch/powerpc/platforms/pseries/vio.c     | 21 ++++++++-------
 6 files changed, 60 insertions(+), 53 deletions(-)

I think this is good enough for PPC anything more looks quite hard

Jason

#18 lore raw

Re: [PATCH v1 4/9] powerpc: Convert to physical address DMA mapping

Le 03/10/2025 à 18:35, Jason Gunthorpe a écrit :

Quoted 16 lines · Leon Romanovsky
Quoted 6 lines

From: Leon Romanovsky <[email protected]>

Adapt PowerPC DMA to use physical addresses in order to prepare code to removal .map_page and .unmap_page.

Quoted 8 lines
---
  arch/powerpc/include/asm/iommu.h         |  8 +++---
  arch/powerpc/kernel/dma-iommu.c          | 22 +++++++---------
  arch/powerpc/kernel/iommu.c              | 14 +++++-----
  arch/powerpc/platforms/ps3/system-bus.c  | 33 ++++++++++++++----------
  arch/powerpc/platforms/pseries/ibmebus.c | 15 ++++++-----
  arch/powerpc/platforms/pseries/vio.c     | 21 ++++++++-------
  6 files changed, 60 insertions(+), 53 deletions(-)
Quoted 1 line

I think this is good enough for PPC anything more looks quite hard

Can you tell what you have in mind ? What more would be interesting to do but looks hard ? Maybe it can be a follow-up change ?

Christophe

Quoted 5 lines

Jason

#19 lore raw

Re: [PATCH v1 4/9] powerpc: Convert to physical address DMA mapping

Quoted 19 lines · Christophe Leroy

Le 03/10/2025 à 18:35, Jason Gunthorpe a écrit :

Quoted 16 lines · Leon Romanovsky
Quoted 14 lines

From: Leon Romanovsky <[email protected]>

Adapt PowerPC DMA to use physical addresses in order to prepare code to removal .map_page and .unmap_page.

---
  arch/powerpc/include/asm/iommu.h         |  8 +++---
  arch/powerpc/kernel/dma-iommu.c          | 22 +++++++---------
  arch/powerpc/kernel/iommu.c              | 14 +++++-----
  arch/powerpc/platforms/ps3/system-bus.c  | 33 ++++++++++++++----------
  arch/powerpc/platforms/pseries/ibmebus.c | 15 ++++++-----
  arch/powerpc/platforms/pseries/vio.c     | 21 ++++++++-------
  6 files changed, 60 insertions(+), 53 deletions(-)
Quoted 4 lines
Quoted 1 line

I think this is good enough for PPC anything more looks quite hard

Can you tell what you have in mind ? What more would be interesting to do but looks hard ? Maybe it can be a follow-up change ?

The phys_addr_t should be pushed down through the ops function pointer and only the implementations that need the vaddr should call virt_to_phys()

Ie try to avoid doing phys -> virt -> phys as it is not efficient.

Jason

#20 lore raw

PATCH 5/9 sparc64: Use physical address DMA mapping

In reply to Leon Romanovsky

From: Leon Romanovsky <[email protected]>

Convert sparc architecture DMA code to use .map_phys callback.

---
 arch/sparc/kernel/iommu.c     | 16 ++++++------
 arch/sparc/kernel/pci_sun4v.c | 16 ++++++------
 arch/sparc/mm/io-unit.c       | 13 +++++-----
 arch/sparc/mm/iommu.c         | 46 ++++++++++++++++++-----------------
 4 files changed, 48 insertions(+), 43 deletions(-)
arch/sparc/kernel/iommu.c +9 -7
index da0363692528..288301d2398a 100644
@@ -260,9 +260,8 @@ static void dma_4u_free_coherent(struct device *dev, size_t size,
 		free_pages((unsigned long)cpu, order);
 }
 
-static dma_addr_t dma_4u_map_page(struct device *dev, struct page *page,
-				  unsigned long offset, size_t sz,
-				  enum dma_data_direction direction,
+static dma_addr_t dma_4u_map_phys(struct device *dev, phys_addr_t phys,
+				  size_t sz, enum dma_data_direction direction,
 				  unsigned long attrs)
 {
 	struct iommu *iommu;
@@ -273,13 +272,16 @@ static dma_addr_t dma_4u_map_page(struct device *dev, struct page *page,
 	u32 bus_addr, ret;
 	unsigned long iopte_protection;
 
+	if (attrs & DMA_ATTR_MMIO)
+		goto bad_no_ctx;
+
 	iommu = dev->archdata.iommu;
 	strbuf = dev->archdata.stc;
 
 	if (unlikely(direction == DMA_NONE))
 		goto bad_no_ctx;
 
-	oaddr = (unsigned long)(page_address(page) + offset);
+	oaddr = (unsigned long)(phys_to_virt(phys));
 	npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK);
 	npages >>= IO_PAGE_SHIFT;
 
@@ -383,7 +385,7 @@ static void strbuf_flush(struct strbuf *strbuf, struct iommu *iommu,
 		       vaddr, ctx, npages);
 }
 
-static void dma_4u_unmap_page(struct device *dev, dma_addr_t bus_addr,
+static void dma_4u_unmap_phys(struct device *dev, dma_addr_t bus_addr,
 			      size_t sz, enum dma_data_direction direction,
 			      unsigned long attrs)
 {
@@ -753,8 +755,8 @@ static int dma_4u_supported(struct device *dev, u64 device_mask)
 static const struct dma_map_ops sun4u_dma_ops = {
 	.alloc			= dma_4u_alloc_coherent,
 	.free			= dma_4u_free_coherent,
-	.map_page		= dma_4u_map_page,
-	.unmap_page		= dma_4u_unmap_page,
+	.map_phys		= dma_4u_map_phys,
+	.unmap_phys		= dma_4u_unmap_phys,
 	.map_sg			= dma_4u_map_sg,
 	.unmap_sg		= dma_4u_unmap_sg,
 	.sync_single_for_cpu	= dma_4u_sync_single_for_cpu,
arch/sparc/kernel/pci_sun4v.c +9 -7
index b720b21ccfbd..d9d2464a948c 100644
@@ -352,9 +352,8 @@ static void dma_4v_free_coherent(struct device *dev, size_t size, void *cpu,
 		free_pages((unsigned long)cpu, order);
 }
 
-static dma_addr_t dma_4v_map_page(struct device *dev, struct page *page,
-				  unsigned long offset, size_t sz,
-				  enum dma_data_direction direction,
+static dma_addr_t dma_4v_map_phys(struct device *dev, phys_addr_t phys,
+				  size_t sz, enum dma_data_direction direction,
 				  unsigned long attrs)
 {
 	struct iommu *iommu;
@@ -367,13 +366,16 @@ static dma_addr_t dma_4v_map_page(struct device *dev, struct page *page,
 	dma_addr_t bus_addr, ret;
 	long entry;
 
+	if (attrs & DMA_ATTR_MMIO)
+		goto bad;
+
 	iommu = dev->archdata.iommu;
 	atu = iommu->atu;
 
 	if (unlikely(direction == DMA_NONE))
 		goto bad;
 
-	oaddr = (unsigned long)(page_address(page) + offset);
+	oaddr = (unsigned long)(phys_to_virt(phys));
 	npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK);
 	npages >>= IO_PAGE_SHIFT;
 
@@ -426,7 +428,7 @@ static dma_addr_t dma_4v_map_page(struct device *dev, struct page *page,
 	return DMA_MAPPING_ERROR;
 }
 
-static void dma_4v_unmap_page(struct device *dev, dma_addr_t bus_addr,
+static void dma_4v_unmap_phys(struct device *dev, dma_addr_t bus_addr,
 			      size_t sz, enum dma_data_direction direction,
 			      unsigned long attrs)
 {
@@ -686,8 +688,8 @@ static int dma_4v_supported(struct device *dev, u64 device_mask)
 static const struct dma_map_ops sun4v_dma_ops = {
 	.alloc				= dma_4v_alloc_coherent,
 	.free				= dma_4v_free_coherent,
-	.map_page			= dma_4v_map_page,
-	.unmap_page			= dma_4v_unmap_page,
+	.map_phys			= dma_4v_map_phys,
+	.unmap_phys			= dma_4v_unmap_phys,
 	.map_sg				= dma_4v_map_sg,
 	.unmap_sg			= dma_4v_unmap_sg,
 	.dma_supported			= dma_4v_supported,
arch/sparc/mm/io-unit.c +6 -7
index d8376f61b4d0..fab303cc3370 100644
@@ -142,11 +142,10 @@ nexti:	scan = find_next_zero_bit(iounit->bmap, limit, scan);
 	return vaddr;
 }
 
-static dma_addr_t iounit_map_page(struct device *dev, struct page *page,
-		unsigned long offset, size_t len, enum dma_data_direction dir,
-		unsigned long attrs)
+static dma_addr_t iounit_map_phys(struct device *dev, phys_addr_t phys,
+		size_t len, enum dma_data_direction dir, unsigned long attrs)
 {
-	void *vaddr = page_address(page) + offset;
+	void *vaddr = phys_to_virt(phys);
 	struct iounit_struct *iounit = dev->archdata.iommu;
 	unsigned long ret, flags;
 	
@@ -178,7 +177,7 @@ static int iounit_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
 	return nents;
 }
 
-static void iounit_unmap_page(struct device *dev, dma_addr_t vaddr, size_t len,
+static void iounit_unmap_phys(struct device *dev, dma_addr_t vaddr, size_t len,
 		enum dma_data_direction dir, unsigned long attrs)
 {
 	struct iounit_struct *iounit = dev->archdata.iommu;
@@ -279,8 +278,8 @@ static const struct dma_map_ops iounit_dma_ops = {
 	.alloc			= iounit_alloc,
 	.free			= iounit_free,
 #endif
-	.map_page		= iounit_map_page,
-	.unmap_page		= iounit_unmap_page,
+	.map_phys		= iounit_map_phys,
+	.unmap_phys		= iounit_unmap_phys,
 	.map_sg			= iounit_map_sg,
 	.unmap_sg		= iounit_unmap_sg,
 };
arch/sparc/mm/iommu.c +24 -22

109 lines not on this page · raw message

Signature · 1 line
2.51.0
#21 lore raw

Re: [PATCH v1 5/9] sparc64: Use physical address DMA mapping

Quoted 7 lines · Leon Romanovsky
arch/sparc/kernel/iommu.c +3 -0
@@ -273,13 +272,16 @@ static dma_addr_t dma_4u_map_page(struct device *dev, struct page *page,
 	u32 bus_addr, ret;
 	unsigned long iopte_protection;
 
+	if (attrs & DMA_ATTR_MMIO)
+		goto bad_no_ctx;
+

arch/sparc/kernel/iommu.c static dma_addr_t dma_4u_map_page(struct device *dev, struct page *page, · line 286

Quoted 10 lines
arch/sparc/kernel/iommu.c +1 -1
 	iommu = dev->archdata.iommu;
 	strbuf = dev->archdata.stc;
 
 	if (unlikely(direction == DMA_NONE))
 		goto bad_no_ctx;
 
-	oaddr = (unsigned long)(page_address(page) + offset);
+	oaddr = (unsigned long)(phys_to_virt(phys));
 	npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK);
 	npages >>= IO_PAGE_SHIFT;

This should be cleaned up some more:

	oaddr = (unsigned long)(page_address(page) + offset);
	ret = bus_addr | (oaddr & ~IO_PAGE_MASK);

	base_paddr = __pa(oaddr & IO_PAGE_MASK);

Makes no sense to phys_to_virt() then __pa() on that result. Drop oaddr.

Then I would copy and paste the comment from mips about DMA_ATTR_MMIO

Quoted 7 lines
arch/sparc/kernel/pci_sun4v.c +3 -0
@@ -367,13 +366,16 @@ static dma_addr_t dma_4v_map_page(struct device *dev, struct page *page,
 	dma_addr_t bus_addr, ret;
 	long entry;
 
+	if (attrs & DMA_ATTR_MMIO)
+		goto bad;
+

arch/sparc/kernel/pci_sun4v.c static dma_addr_t dma_4v_map_page(struct device *dev, struct page *page, · line 380

Quoted 10 lines
arch/sparc/kernel/pci_sun4v.c +1 -1
 	iommu = dev->archdata.iommu;
 	atu = iommu->atu;
 
 	if (unlikely(direction == DMA_NONE))
 		goto bad;
 
-	oaddr = (unsigned long)(page_address(page) + offset);
+	oaddr = (unsigned long)(phys_to_virt(phys));
 	npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK);
 	npages >>= IO_PAGE_SHIFT;

Same remarks here

arch/sparc/mm/io-unit.c nexti: scan = find_next_zero_bit(iounit->bmap, limit, scan); · line 150

Quoted 7 lines
arch/sparc/mm/io-unit.c +3 -1
+static dma_addr_t iounit_map_phys(struct device *dev, phys_addr_t phys,
+		size_t len, enum dma_data_direction dir, unsigned long attrs)
 {
-	void *vaddr = page_address(page) + offset;
+	void *vaddr = phys_to_virt(phys);
 	struct iounit_struct *iounit = dev->archdata.iommu;
 	unsigned long ret, flags;

iounit_get_area() does not seem to need vaddr:

        npages = ((vaddr & ~PAGE_MASK) + size + (PAGE_SIZE-1)) >> PAGE_SHIFT;

~PAGE_MASK is page_offset()

	iopte = MKIOPTE(__pa(vaddr & PAGE_MASK));

__pa(phys_to_virt(pa)) again:
iopte = MKIOPTE(PAGE_ALIGN(pa));

	vaddr = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT) + (vaddr & ~PAGE_MASK);

page_offset, then it replaces vaddr.

So I'd tidy this too.

arch/sparc/mm/iommu.c static dma_addr_t __sbus_iommu_map_page(struct device *dev, struct page *page, · line 207

Quoted 5 lines
arch/sparc/mm/iommu.c +0 -0
@@ -202,10 +204,10 @@ static dma_addr_t __sbus_iommu_map_page(struct device *dev, struct page *page,
 	 * We expect unmapped highmem pages to be not in the cache.
 	 * XXX Is this a good assumption?
 	 * XXX What if someone else unmaps it here and races us?
 	 */

At least ARM32 has code that seems to say these assumptions are not always true.. Oh well.

Jason

#22 lore raw

PATCH 6/9 x86: Use physical address for DMA mapping

In reply to Leon Romanovsky

From: Leon Romanovsky <[email protected]>

Perform mechanical conversion from DMA .map_page to .map_phys.

---
 arch/x86/kernel/amd_gart_64.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)
arch/x86/kernel/amd_gart_64.c +10 -9
index 3485d419c2f5..f1ffdc0e4a3a 100644
@@ -222,13 +222,14 @@ static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem,
 }
 
 /* Map a single area into the IOMMU */
-static dma_addr_t gart_map_page(struct device *dev, struct page *page,
-				unsigned long offset, size_t size,
-				enum dma_data_direction dir,
+static dma_addr_t gart_map_phys(struct device *dev, phys_addr_t paddr,
+				size_t size, enum dma_data_direction dir,
 				unsigned long attrs)
 {
 	unsigned long bus;
-	phys_addr_t paddr = page_to_phys(page) + offset;
+
+	if (attrs & DMA_ATTR_MMIO)
+		return DMA_MAPPING_ERROR;
 
 	if (!need_iommu(dev, paddr, size))
 		return paddr;
@@ -242,7 +243,7 @@ static dma_addr_t gart_map_page(struct device *dev, struct page *page,
 /*
  * Free a DMA mapping.
  */
-static void gart_unmap_page(struct device *dev, dma_addr_t dma_addr,
+static void gart_unmap_phys(struct device *dev, dma_addr_t dma_addr,
 			    size_t size, enum dma_data_direction dir,
 			    unsigned long attrs)
 {
@@ -282,7 +283,7 @@ static void gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
 	for_each_sg(sg, s, nents, i) {
 		if (!s->dma_length || !s->length)
 			break;
-		gart_unmap_page(dev, s->dma_address, s->dma_length, dir, 0);
+		gart_unmap_phys(dev, s->dma_address, s->dma_length, dir, 0);
 	}
 }
 
@@ -487,7 +488,7 @@ static void
 gart_free_coherent(struct device *dev, size_t size, void *vaddr,
 		   dma_addr_t dma_addr, unsigned long attrs)
 {
-	gart_unmap_page(dev, dma_addr, size, DMA_BIDIRECTIONAL, 0);
+	gart_unmap_phys(dev, dma_addr, size, DMA_BIDIRECTIONAL, 0);
 	dma_direct_free(dev, size, vaddr, dma_addr, attrs);
 }
 
@@ -668,8 +669,8 @@ static __init int init_amd_gatt(struct agp_kern_info *info)
 static const struct dma_map_ops gart_dma_ops = {
 	.map_sg				= gart_map_sg,
 	.unmap_sg			= gart_unmap_sg,
-	.map_page			= gart_map_page,
-	.unmap_page			= gart_unmap_page,
+	.map_phys			= gart_map_phys,
+	.unmap_phys			= gart_unmap_phys,
 	.alloc				= gart_alloc_coherent,
 	.free				= gart_free_coherent,
 	.mmap				= dma_common_mmap,
Signature · 1 line
2.51.0
#24 lore raw

PATCH 7/9 vdpa: Convert to physical address DMA mapping

In reply to Leon Romanovsky

From: Leon Romanovsky <[email protected]>

Use physical address directly in DMA mapping flow.

---
 drivers/vdpa/vdpa_user/iova_domain.c | 11 +++++------
 drivers/vdpa/vdpa_user/iova_domain.h |  8 ++++----
 drivers/vdpa/vdpa_user/vduse_dev.c   | 18 ++++++++++--------
 3 files changed, 19 insertions(+), 18 deletions(-)
drivers/vdpa/vdpa_user/iova_domain.c +5 -6
index 58116f89d8da..c0ecf01003cd 100644
@@ -396,17 +396,16 @@ void vduse_domain_sync_single_for_cpu(struct vduse_iova_domain *domain,
 	read_unlock(&domain->bounce_lock);
 }
 
-dma_addr_t vduse_domain_map_page(struct vduse_iova_domain *domain,
-				 struct page *page, unsigned long offset,
-				 size_t size, enum dma_data_direction dir,
+dma_addr_t vduse_domain_map_phys(struct vduse_iova_domain *domain,
+				 phys_addr_t pa, size_t size,
+				 enum dma_data_direction dir,
 				 unsigned long attrs)
 {
 	struct iova_domain *iovad = &domain->stream_iovad;
 	unsigned long limit = domain->bounce_size - 1;
-	phys_addr_t pa = page_to_phys(page) + offset;
 	dma_addr_t iova = vduse_domain_alloc_iova(iovad, size, limit);
 
-	if (!iova)
+	if (!iova || (attrs & DMA_ATTR_MMIO))
 		return DMA_MAPPING_ERROR;
 
 	if (vduse_domain_init_bounce_map(domain))
@@ -430,7 +429,7 @@ dma_addr_t vduse_domain_map_page(struct vduse_iova_domain *domain,
 	return DMA_MAPPING_ERROR;
 }
 
-void vduse_domain_unmap_page(struct vduse_iova_domain *domain,
+void vduse_domain_unmap_phys(struct vduse_iova_domain *domain,
 			     dma_addr_t dma_addr, size_t size,
 			     enum dma_data_direction dir, unsigned long attrs)
 {
drivers/vdpa/vdpa_user/iova_domain.h +4 -4
index 7f3f0928ec78..7c4546fd856a 100644
@@ -53,12 +53,12 @@ void vduse_domain_sync_single_for_cpu(struct vduse_iova_domain *domain,
 				      dma_addr_t dma_addr, size_t size,
 				      enum dma_data_direction dir);
 
-dma_addr_t vduse_domain_map_page(struct vduse_iova_domain *domain,
-				 struct page *page, unsigned long offset,
-				 size_t size, enum dma_data_direction dir,
+dma_addr_t vduse_domain_map_phys(struct vduse_iova_domain *domain,
+				 phys_addr_t phys, size_t size,
+				 enum dma_data_direction dir,
 				 unsigned long attrs);
 
-void vduse_domain_unmap_page(struct vduse_iova_domain *domain,
+void vduse_domain_unmap_phys(struct vduse_iova_domain *domain,
 			     dma_addr_t dma_addr, size_t size,
 			     enum dma_data_direction dir, unsigned long attrs);
 
drivers/vdpa/vdpa_user/vduse_dev.c +10 -8
index 04620bb77203..75aa3c9f83fb 100644
@@ -834,25 +834,27 @@ static void vduse_dev_sync_single_for_cpu(struct device *dev,
 	vduse_domain_sync_single_for_cpu(domain, dma_addr, size, dir);
 }
 
-static dma_addr_t vduse_dev_map_page(struct device *dev, struct page *page,
-				     unsigned long offset, size_t size,
-				     enum dma_data_direction dir,
+static dma_addr_t vduse_dev_map_phys(struct device *dev, phys_addr_t phys,
+				     size_t size, enum dma_data_direction dir,
 				     unsigned long attrs)
 {
 	struct vduse_dev *vdev = dev_to_vduse(dev);
 	struct vduse_iova_domain *domain = vdev->domain;
 
-	return vduse_domain_map_page(domain, page, offset, size, dir, attrs);
+	if (attrs & DMA_ATTR_MMIO)
+		return DMA_MAPPING_ERROR;
+
+	return vduse_domain_map_phys(domain, phys, size, dir, attrs);
 }
 
-static void vduse_dev_unmap_page(struct device *dev, dma_addr_t dma_addr,
+static void vduse_dev_unmap_phys(struct device *dev, dma_addr_t dma_addr,
 				size_t size, enum dma_data_direction dir,
 				unsigned long attrs)
 {
 	struct vduse_dev *vdev = dev_to_vduse(dev);
 	struct vduse_iova_domain *domain = vdev->domain;
 
-	return vduse_domain_unmap_page(domain, dma_addr, size, dir, attrs);
+	return vduse_domain_unmap_phys(domain, dma_addr, size, dir, attrs);
 }
 
 static void *vduse_dev_alloc_coherent(struct device *dev, size_t size,
@@ -896,8 +898,8 @@ static size_t vduse_dev_max_mapping_size(struct device *dev)
 static const struct dma_map_ops vduse_dev_dma_ops = {
 	.sync_single_for_device = vduse_dev_sync_single_for_device,
 	.sync_single_for_cpu = vduse_dev_sync_single_for_cpu,
-	.map_page = vduse_dev_map_page,
-	.unmap_page = vduse_dev_unmap_page,
+	.map_phys = vduse_dev_map_phys,
+	.unmap_phys = vduse_dev_unmap_phys,
 	.alloc = vduse_dev_alloc_coherent,
 	.free = vduse_dev_free_coherent,
 	.max_mapping_size = vduse_dev_max_mapping_size,
Signature · 1 line
2.51.0
Reviewed-by on v1 7/9
#25 lore raw

Re: [PATCH v1 7/9] vdpa: Convert to physical address DMA mapping

Quoted 10 lines · Leon Romanovsky

From: Leon Romanovsky <[email protected]>

Use physical address directly in DMA mapping flow.

---
 drivers/vdpa/vdpa_user/iova_domain.c | 11 +++++------
 drivers/vdpa/vdpa_user/iova_domain.h |  8 ++++----
 drivers/vdpa/vdpa_user/vduse_dev.c   | 18 ++++++++++--------
 3 files changed, 19 insertions(+), 18 deletions(-)

Jason

#26 lore raw

PATCH 8/9 xen: swiotlb: Convert mapping routine to rely on physical address

In reply to Leon Romanovsky

From: Leon Romanovsky <[email protected]>

Switch to .map_phys callback instead of .map_page.

---
 drivers/xen/grant-dma-ops.c | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)
drivers/xen/grant-dma-ops.c +12 -8
index 29257d2639db..7f76e516fe24 100644
@@ -163,18 +163,22 @@ static void xen_grant_dma_free_pages(struct device *dev, size_t size,
 	xen_grant_dma_free(dev, size, page_to_virt(vaddr), dma_handle, 0);
 }
 
-static dma_addr_t xen_grant_dma_map_page(struct device *dev, struct page *page,
-					 unsigned long offset, size_t size,
+static dma_addr_t xen_grant_dma_map_phys(struct device *dev, phys_addr_t phys,
+					 size_t size,
 					 enum dma_data_direction dir,
 					 unsigned long attrs)
 {
 	struct xen_grant_dma_data *data;
+	unsigned long offset = offset_in_page(phys);
 	unsigned long dma_offset = xen_offset_in_page(offset),
 			pfn_offset = XEN_PFN_DOWN(offset);
 	unsigned int i, n_pages = XEN_PFN_UP(dma_offset + size);
 	grant_ref_t grant;
 	dma_addr_t dma_handle;
 
+	if (attrs & DMA_ATTR_MMIO)
+		return DMA_MAPPING_ERROR;
+
 	if (WARN_ON(dir == DMA_NONE))
 		return DMA_MAPPING_ERROR;
 
@@ -190,7 +194,7 @@ static dma_addr_t xen_grant_dma_map_page(struct device *dev, struct page *page,
 
 	for (i = 0; i < n_pages; i++) {
 		gnttab_grant_foreign_access_ref(grant + i, data->backend_domid,
-				pfn_to_gfn(page_to_xen_pfn(page) + i + pfn_offset),
+				pfn_to_gfn(page_to_xen_pfn(phys_to_page(phys)) + i + pfn_offset),
 				dir == DMA_TO_DEVICE);
 	}
 
@@ -199,7 +203,7 @@ static dma_addr_t xen_grant_dma_map_page(struct device *dev, struct page *page,
 	return dma_handle;
 }
 
-static void xen_grant_dma_unmap_page(struct device *dev, dma_addr_t dma_handle,
+static void xen_grant_dma_unmap_phys(struct device *dev, dma_addr_t dma_handle,
 				     size_t size, enum dma_data_direction dir,
 				     unsigned long attrs)
 {
@@ -242,7 +246,7 @@ static void xen_grant_dma_unmap_sg(struct device *dev, struct scatterlist *sg,
 		return;
 
 	for_each_sg(sg, s, nents, i)
-		xen_grant_dma_unmap_page(dev, s->dma_address, sg_dma_len(s), dir,
+		xen_grant_dma_unmap_phys(dev, s->dma_address, sg_dma_len(s), dir,
 				attrs);
 }
 
@@ -257,7 +261,7 @@ static int xen_grant_dma_map_sg(struct device *dev, struct scatterlist *sg,
 		return -EINVAL;
 
 	for_each_sg(sg, s, nents, i) {
-		s->dma_address = xen_grant_dma_map_page(dev, sg_page(s), s->offset,
+		s->dma_address = xen_grant_dma_map_phys(dev, sg_phys(s),
 				s->length, dir, attrs);
 		if (s->dma_address == DMA_MAPPING_ERROR)
 			goto out;
@@ -286,8 +290,8 @@ static const struct dma_map_ops xen_grant_dma_ops = {
 	.free_pages = xen_grant_dma_free_pages,
 	.mmap = dma_common_mmap,
 	.get_sgtable = dma_common_get_sgtable,
-	.map_page = xen_grant_dma_map_page,
-	.unmap_page = xen_grant_dma_unmap_page,
+	.map_phys = xen_grant_dma_map_phys,
+	.unmap_phys = xen_grant_dma_unmap_phys,
 	.map_sg = xen_grant_dma_map_sg,
 	.unmap_sg = xen_grant_dma_unmap_sg,
 	.dma_supported = xen_grant_dma_supported,
Signature · 1 line
2.51.0
#28 lore raw

PATCH 9/9 dma-mapping: remove unused map_page callback

In reply to Leon Romanovsky

From: Leon Romanovsky <[email protected]>

After conversion of arch code to use physical address mapping, there are no users of .map_page() and .unmap_page() callbacks, so let's remove them.

---
 include/linux/dma-map-ops.h |  7 -------
 kernel/dma/mapping.c        | 12 ------------
 kernel/dma/ops_helpers.c    |  8 +-------
 3 files changed, 1 insertion(+), 26 deletions(-)
include/linux/dma-map-ops.h +0 -7
index a2ec1566aa27..e0a78991fa8a 100644
@@ -31,13 +31,6 @@ struct dma_map_ops {
 			void *cpu_addr, dma_addr_t dma_addr, size_t size,
 			unsigned long attrs);
 
-	dma_addr_t (*map_page)(struct device *dev, struct page *page,
-			unsigned long offset, size_t size,
-			enum dma_data_direction dir, unsigned long attrs);
-	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);
kernel/dma/mapping.c +0 -12
index 32a85bfdf873..37163eb49f9f 100644
@@ -171,16 +171,6 @@ 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 && 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.
-		 */
-		addr = ops->map_page(dev, page, offset, size, dir, attrs);
-	}
 
 	if (!is_mmio)
 		kmsan_handle_dma(phys, size, dir);
@@ -222,8 +212,6 @@ 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
-		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);
 }
kernel/dma/ops_helpers.c +1 -7
index 1eccbdbc99c1..20caf9cabf69 100644
@@ -76,11 +76,8 @@ struct page *dma_common_alloc_pages(struct device *dev, size_t size,
 	if (use_dma_iommu(dev))
 		*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_handle = ops->map_phys(dev, phys, size, dir,
 					    DMA_ATTR_SKIP_CPU_SYNC);
 	if (*dma_handle == DMA_MAPPING_ERROR) {
 		dma_free_contiguous(dev, page, size);
@@ -102,8 +99,5 @@ void dma_common_free_pages(struct device *dev, size_t size, struct page *page,
 	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);
 	dma_free_contiguous(dev, page, size);
 }
Signature · 1 line
2.51.0
#29 lore raw

Re: [PATCH v1 9/9] dma-mapping: remove unused map_page callback

Hi Leon.

Quoted 6 lines · Leon Romanovsky

From: Leon Romanovsky <[email protected]>

After conversion of arch code to use physical address mapping, there are no users of .map_page() and .unmap_page() callbacks, so let's remove them.

Quoted 6 lines
---
 include/linux/dma-map-ops.h |  7 -------
 kernel/dma/mapping.c        | 12 ------------
 kernel/dma/ops_helpers.c    |  8 +-------
 3 files changed, 1 insertion(+), 26 deletions(-)

It looks like you missed a few sparc32 bits:
mm/iommu.c:
static const struct dma_map_ops sbus_iommu_dma_gflush_ops = { #ifdef CONFIG_SBUS
.alloc = sbus_iommu_alloc,
.free = sbus_iommu_free,
#endif

        .map_page               = sbus_iommu_map_page_gflush,
        .unmap_page             = sbus_iommu_unmap_page,
        .map_sg                 = sbus_iommu_map_sg_gflush,

mm/io-unit.c:
static const struct dma_map_ops iounit_dma_ops = { #ifdef CONFIG_SBUS
.alloc = iounit_alloc,
.free = iounit_free,
#endif

        .map_page               = iounit_map_page,
        .unmap_page             = iounit_unmap_page,
        .map_sg                 = iounit_map_sg,

I did not compile test, but from a quick look they need to be updated.

Sam

#30 lore raw

Re: [PATCH v1 9/9] dma-mapping: remove unused map_page callback

Hi Leon.

Quoted 9 lines · Sam Ravnborg

Hi Leon.

Quoted 6 lines · Leon Romanovsky

From: Leon Romanovsky <[email protected]>

After conversion of arch code to use physical address mapping, there are no users of .map_page() and .unmap_page() callbacks, so let's remove them.

Quoted 8 lines
Quoted 6 lines
---
 include/linux/dma-map-ops.h |  7 -------
 kernel/dma/mapping.c        | 12 ------------
 kernel/dma/ops_helpers.c    |  8 +-------
 3 files changed, 1 insertion(+), 26 deletions(-)

It looks like you missed a few sparc32 bits:

They were included, but the patch is named sparc64, which is why I missed it.

If you could rename the patch that would be nice.

Sam

#31 lore raw

Re: [PATCH v1 9/9] dma-mapping: remove unused map_page callback

Quoted 19 lines · Sam Ravnborg

Hi Leon.

Quoted 16 lines · Sam Ravnborg

Hi Leon.

Quoted 12 lines · Leon Romanovsky

From: Leon Romanovsky <[email protected]>

After conversion of arch code to use physical address mapping, there are no users of .map_page() and .unmap_page() callbacks, so let's remove them.

---
 include/linux/dma-map-ops.h |  7 -------
 kernel/dma/mapping.c        | 12 ------------
 kernel/dma/ops_helpers.c    |  8 +-------
 3 files changed, 1 insertion(+), 26 deletions(-)
Quoted 6 lines
Quoted 1 line

It looks like you missed a few sparc32 bits:

They were included, but the patch is named sparc64, which is why I missed it.

If you could rename the patch that would be nice.

Let's see if new version is required.

Thanks

Quoted 3 lines

Sam

#32 lore raw

Re: [PATCH v1 9/9] dma-mapping: remove unused map_page callback

In reply to Sam Ravnborg
Quoted 33 lines · Sam Ravnborg

Hi Leon.

Quoted 6 lines · Leon Romanovsky

From: Leon Romanovsky <[email protected]>

After conversion of arch code to use physical address mapping, there are no users of .map_page() and .unmap_page() callbacks, so let's remove them.

Quoted 6 lines
---
 include/linux/dma-map-ops.h |  7 -------
 kernel/dma/mapping.c        | 12 ------------
 kernel/dma/ops_helpers.c    |  8 +-------
 3 files changed, 1 insertion(+), 26 deletions(-)

It looks like you missed a few sparc32 bits:
mm/iommu.c:
static const struct dma_map_ops sbus_iommu_dma_gflush_ops = { #ifdef CONFIG_SBUS
.alloc = sbus_iommu_alloc,
.free = sbus_iommu_free,
#endif

        .map_page               = sbus_iommu_map_page_gflush,
        .unmap_page             = sbus_iommu_unmap_page,
        .map_sg                 = sbus_iommu_map_sg_gflush,

mm/io-unit.c:
static const struct dma_map_ops iounit_dma_ops = { #ifdef CONFIG_SBUS
.alloc = iounit_alloc,
.free = iounit_free,
#endif

Quoted 5 lines
        .map_page               = iounit_map_page,
        .unmap_page             = iounit_unmap_page,
        .map_sg                 = iounit_map_sg,

I did not compile test, but from a quick look they need to be updated.

There were updated, see patch #5.
https://lore.kernel.org/all/bac909dab3c82fc6a7a4f5a31f22bac9a69f7f07.1759071169.git.leon@kernel.org/T/#u

arch/sparc/mm/iommu.c:
426 static const struct dma_map_ops sbus_iommu_dma_gflush_ops = { 427 #ifdef CONFIG_SBUS

  428         .alloc                  = sbus_iommu_alloc,
  429         .free                   = sbus_iommu_free,
  430 #endif
  431         .map_phys               = sbus_iommu_map_phys_gflush,
  432         .unmap_phys             = sbus_iommu_unmap_phys,
  433         .map_sg                 = sbus_iommu_map_sg_gflush,
  434         .unmap_sg               = sbus_iommu_unmap_sg,

435 };

arch/sparc/mm/io-unit.c:
276 static const struct dma_map_ops iounit_dma_ops = { 277 #ifdef CONFIG_SBUS

  278         .alloc                  = iounit_alloc,
  279         .free                   = iounit_free,
  280 #endif
  281         .map_phys               = iounit_map_phys,
  282         .unmap_phys             = iounit_unmap_phys,
  283         .map_sg                 = iounit_map_sg,
  284         .unmap_sg               = iounit_unmap_sg,

285 };

Thanks

Quoted 3 lines

Sam

Reviewed-by on v1 9/9
#33 lore raw

Re: [PATCH v1 9/9] dma-mapping: remove unused map_page callback

In reply to Leon Romanovsky
Quoted 6 lines · Leon Romanovsky

From: Leon Romanovsky <[email protected]>

After conversion of arch code to use physical address mapping, there are no users of .map_page() and .unmap_page() callbacks, so let's remove them.

Quoted 6 lines
---
 include/linux/dma-map-ops.h |  7 -------
 kernel/dma/mapping.c        | 12 ------------
 kernel/dma/ops_helpers.c    |  8 +-------
 3 files changed, 1 insertion(+), 26 deletions(-)

Jason