[PATCH v11 07/11] device-mapping: Introduce DMA range map, supplanting dma_pfn_offset

Christoph Hellwig hch at lst.de
Tue Sep 8 07:29:35 UTC 2020


FYI, this is what I'd do relative to the patch on the dma-ranges
branch.  In fact realizing this makes me want to refactor things a bit
so that the new code can entirely live in the dma-direct code, but please
test this first:


diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index c21893f683b585..072fc42349874d 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -35,21 +35,16 @@ static inline const struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus)
 #ifndef __arch_pfn_to_dma
 static inline dma_addr_t pfn_to_dma(struct device *dev, unsigned long pfn)
 {
-	if (dev) {
-		phys_addr_t paddr = PFN_PHYS(pfn);
-
-		pfn -= PFN_DOWN(dma_offset_from_phys_addr(dev, paddr));
-	}
-	return (dma_addr_t)__pfn_to_bus(pfn);
+	if (!dev)
+		return (dma_addr_t)__pfn_to_bus(pfn);
+	return translate_phys_to_dma(dev, PFN_PHYS(pfn));
 }
 
 static inline unsigned long dma_to_pfn(struct device *dev, dma_addr_t addr)
 {
-	unsigned long pfn = __bus_to_pfn(addr);
-
-	if (dev)
-		pfn += PFN_DOWN(dma_offset_from_dma_addr(dev, addr));
-	return pfn;
+	if (!dev)
+		return __bus_to_pfn(addr);
+	return PFN_DOWN(translate_dma_to_phys(dev, addr));
 }
 
 static inline void *dma_to_virt(struct device *dev, dma_addr_t addr)
diff --git a/include/linux/dma-direct.h b/include/linux/dma-direct.h
index 7831ca5b1b5dd6..e624171c4962ad 100644
--- a/include/linux/dma-direct.h
+++ b/include/linux/dma-direct.h
@@ -19,12 +19,16 @@ extern unsigned int zone_dma_bits;
 #else
 static inline dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr)
 {
-	return (dma_addr_t)paddr - dma_offset_from_phys_addr(dev, paddr);
+	if (dev->dma_range_map)
+		return (dma_addr_t)paddr - translate_phys_to_dma(dev, paddr);
+	return (dma_addr_t)paddr;
 }
 
-static inline phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t dev_addr)
+static inline phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t dma_addr)
 {
-	return (phys_addr_t)dev_addr + dma_offset_from_dma_addr(dev, dev_addr);
+	if (dev->dma_range_map)
+		return translate_dma_to_phys(dev, dma_addr);
+	return (phys_addr_t)dma_addr;
 }
 #endif /* !CONFIG_ARCH_HAS_PHYS_TO_DMA */
 
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 4c4646761afee4..3b1ceebb6f2ad5 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -199,29 +199,28 @@ struct bus_dma_region {
 };
 
 #ifdef CONFIG_HAS_DMA
-static inline u64 dma_offset_from_dma_addr(struct device *dev,
-		dma_addr_t dma_addr)
+static inline dma_addr_t translate_phys_to_dma(struct device *dev,
+		phys_addr_t paddr)
 {
-	const struct bus_dma_region *m = dev->dma_range_map;
+	const struct bus_dma_region *m;
 
-	if (m)
-		for (; m->size; m++)
-			if (dma_addr >= m->dma_start &&
-			    dma_addr - m->dma_start < m->size)
-				return m->offset;
-	return 0;
+	for (m = dev->dma_range_map; m->size; m++)
+		if (paddr >= m->cpu_start && paddr - m->cpu_start < m->size)
+			return (dma_addr_t)paddr - m->offset;
+
+	/* make sure dma_capable fails when no translation is available */
+	return DMA_MAPPING_ERROR; 
 }
 
-static inline u64 dma_offset_from_phys_addr(struct device *dev,
-		phys_addr_t paddr)
+static inline phys_addr_t translate_dma_to_phys(struct device *dev,
+		dma_addr_t dma_addr)
 {
-	const struct bus_dma_region *m = dev->dma_range_map;
+	const struct bus_dma_region *m;
+
+	for (m = dev->dma_range_map; m->size; m++)
+		if (dma_addr >= m->dma_start && dma_addr - m->dma_start < m->size)
+			return (phys_addr_t)dma_addr + m->offset;
 
-	if (m)
-		for (; m->size; m++)
-			if (paddr >= m->cpu_start &&
-			    paddr - m->cpu_start < m->size)
-				return m->offset;
 	return 0;
 }
 


More information about the devel mailing list