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 <[email protected]> --- 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
