[PATCH v3 06/10] ARM: dma-mapping: Bound IOVA allocation by device DMA limits

Mikko Perttunen mperttunen at nvidia.com
Mon Oct 26 02:19:31 PDT 2026


The legacy unmanaged DMA domain path sets up the IOVA bookkeeping based
on the dma_range_map of the device. This property however is not
necessarily available during the time we create the bookkeeping with
core-owned default domains, and doesn't take into account the device's
DMA mask.

Resolve this by passing the device's DMA limit to __alloc_iova and
refusing allocations that would go above that limit. Allocation logic is
unchanged except for the check.

Signed-off-by: Mikko Perttunen <mperttunen at nvidia.com>
---
 arch/arm/mm/dma-mapping.c | 36 ++++++++++++++++++++----------------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index b82cf58f8bc7..3703f9e2c9a2 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -752,7 +752,7 @@ static int __dma_info_to_prot(enum dma_data_direction dir, unsigned long attrs)
 static int extend_iommu_mapping(struct dma_iommu_mapping *mapping);
 
 static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping,
-				      size_t size)
+				      size_t size, u64 dma_limit)
 {
 	unsigned int order = get_order(size);
 	unsigned int align = 0;
@@ -776,7 +776,6 @@ static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping,
 		if (start >= mapping->bits)
 			continue;
 
-		bitmap_set(mapping->bitmaps[i], start, count);
 		break;
 	}
 
@@ -786,27 +785,28 @@ static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping,
 	 * address range of size bytes.
 	 */
 	if (i == mapping->nr_bitmaps) {
-		if (extend_iommu_mapping(mapping)) {
-			spin_unlock_irqrestore(&mapping->lock, flags);
-			return DMA_MAPPING_ERROR;
-		}
+		if (extend_iommu_mapping(mapping))
+			goto fail;
 
 		start = bitmap_find_next_zero_area(mapping->bitmaps[i],
 				mapping->bits, 0, count, align);
 
-		if (start >= mapping->bits) {
-			spin_unlock_irqrestore(&mapping->lock, flags);
-			return DMA_MAPPING_ERROR;
-		}
-
-		bitmap_set(mapping->bitmaps[i], start, count);
+		if (start >= mapping->bits)
+			goto fail;
 	}
-	spin_unlock_irqrestore(&mapping->lock, flags);
 
 	iova = mapping->base + (mapping_size * i);
 	iova += start << PAGE_SHIFT;
+	if ((u64)iova + PAGE_ALIGN(size) - 1 > dma_limit)
+		goto fail;
 
+	bitmap_set(mapping->bitmaps[i], start, count);
+	spin_unlock_irqrestore(&mapping->lock, flags);
 	return iova;
+
+fail:
+	spin_unlock_irqrestore(&mapping->lock, flags);
+	return DMA_MAPPING_ERROR;
 }
 
 static inline void __free_iova(struct dma_iommu_mapping *mapping,
@@ -965,7 +965,8 @@ __iommu_create_mapping(struct device *dev, struct page **pages, size_t size,
 	dma_addr_t dma_addr, iova;
 	int i;
 
-	dma_addr = __alloc_iova(mapping, size);
+	dma_addr = __alloc_iova(mapping, size,
+				min_not_zero(dev->coherent_dma_mask, dev->bus_dma_limit));
 	if (dma_addr == DMA_MAPPING_ERROR)
 		return dma_addr;
 
@@ -1194,7 +1195,9 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
 	size = PAGE_ALIGN(size);
 	*handle = DMA_MAPPING_ERROR;
 
-	iova_base = iova = __alloc_iova(mapping, size);
+	iova = __alloc_iova(mapping, size,
+			    min_not_zero(dma_get_mask(dev), dev->bus_dma_limit));
+	iova_base = iova;
 	if (iova == DMA_MAPPING_ERROR)
 		return -ENOMEM;
 
@@ -1375,7 +1378,8 @@ static dma_addr_t arm_iommu_map_phys(struct device *dev, phys_addr_t phys,
 	    !(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO)))
 		arch_sync_dma_for_device(phys, size, dir);
 
-	dma_addr = __alloc_iova(mapping, len);
+	dma_addr = __alloc_iova(mapping, len,
+				min_not_zero(dma_get_mask(dev), dev->bus_dma_limit));
 	if (dma_addr == DMA_MAPPING_ERROR)
 		return dma_addr;
 

-- 
2.55.0




More information about the linux-arm-kernel mailing list