[PATCH v3 06/10] ARM: dma-mapping: Bound IOVA allocation by device DMA limits
From: Mikko Perttunen
Date: Mon Oct 26 2026 - 05:25:34 EST
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@xxxxxxxxxx>
---
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