Skip to content

Commit 51b30ec

Browse files
willdeaconChristoph Hellwig
authored and
Christoph Hellwig
committed
swiotlb: Fix alignment checks when both allocation and DMA masks are present
Nicolin reports that swiotlb buffer allocations fail for an NVME device behind an IOMMU using 64KiB pages. This is because we end up with a minimum allocation alignment of 64KiB (for the IOMMU to map the buffer safely) but a minimum DMA alignment mask corresponding to a 4KiB NVME page (i.e. preserving the 4KiB page offset from the original allocation). If the original address is not 4KiB-aligned, the allocation will fail because swiotlb_search_pool_area() erroneously compares these unmasked bits with the 64KiB-aligned candidate allocation. Tweak swiotlb_search_pool_area() so that the DMA alignment mask is reduced based on the required alignment of the allocation. Fixes: 82612d6 ("iommu: Allow the dma-iommu api to use bounce buffers") Link: https://lore.kernel.org/r/[email protected] Reported-by: Nicolin Chen <[email protected]> Signed-off-by: Will Deacon <[email protected]> Reviewed-by: Michael Kelley <[email protected]> Tested-by: Nicolin Chen <[email protected]> Tested-by: Michael Kelley <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent cbf5307 commit 51b30ec

File tree

1 file changed

+9
-2
lines changed

1 file changed

+9
-2
lines changed

kernel/dma/swiotlb.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,8 +1003,7 @@ static int swiotlb_search_pool_area(struct device *dev, struct io_tlb_pool *pool
10031003
dma_addr_t tbl_dma_addr =
10041004
phys_to_dma_unencrypted(dev, pool->start) & boundary_mask;
10051005
unsigned long max_slots = get_max_slots(boundary_mask);
1006-
unsigned int iotlb_align_mask =
1007-
dma_get_min_align_mask(dev) & ~(IO_TLB_SIZE - 1);
1006+
unsigned int iotlb_align_mask = dma_get_min_align_mask(dev);
10081007
unsigned int nslots = nr_slots(alloc_size), stride;
10091008
unsigned int offset = swiotlb_align_offset(dev, orig_addr);
10101009
unsigned int index, slots_checked, count = 0, i;
@@ -1015,6 +1014,14 @@ static int swiotlb_search_pool_area(struct device *dev, struct io_tlb_pool *pool
10151014
BUG_ON(!nslots);
10161015
BUG_ON(area_index >= pool->nareas);
10171016

1017+
/*
1018+
* Ensure that the allocation is at least slot-aligned and update
1019+
* 'iotlb_align_mask' to ignore bits that will be preserved when
1020+
* offsetting into the allocation.
1021+
*/
1022+
alloc_align_mask |= (IO_TLB_SIZE - 1);
1023+
iotlb_align_mask &= ~alloc_align_mask;
1024+
10181025
/*
10191026
* For mappings with an alignment requirement don't bother looping to
10201027
* unaligned slots once we found an aligned one.

0 commit comments

Comments
 (0)