Skip to content

Commit b8397a8

Browse files
rmurphy-armjoergroedel
authored andcommitted
iommu/dma: Explicitly sort PCI DMA windows
Originally, creating the dma_ranges resource list in pre-sorted fashion was the simplest and most efficient way to enforce the order required by iova_reserve_pci_windows(). However since then at least one PCI host driver is now re-sorting the list for its own probe-time processing, which doesn't seem entirely unreasonable, so that basic assumption no longer holds. Make iommu-dma robust and get the sort order it needs by explicitly sorting, which means we can also save the effort at creation time and just build the list in whatever natural order the DT had. Signed-off-by: Robin Murphy <[email protected]> Reviewed-by: Rob Herring <[email protected]> Link: https://lore.kernel.org/r/35661036a7e4160850895f9b37f35408b6a29f2f.1652091160.git.robin.murphy@arm.com Signed-off-by: Joerg Roedel <[email protected]>
1 parent a388477 commit b8397a8

File tree

2 files changed

+13
-8
lines changed

2 files changed

+13
-8
lines changed

drivers/iommu/dma-iommu.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/iommu.h>
2121
#include <linux/iova.h>
2222
#include <linux/irq.h>
23+
#include <linux/list_sort.h>
2324
#include <linux/mm.h>
2425
#include <linux/mutex.h>
2526
#include <linux/pci.h>
@@ -414,6 +415,15 @@ static int cookie_init_hw_msi_region(struct iommu_dma_cookie *cookie,
414415
return 0;
415416
}
416417

418+
static int iommu_dma_ranges_sort(void *priv, const struct list_head *a,
419+
const struct list_head *b)
420+
{
421+
struct resource_entry *res_a = list_entry(a, typeof(*res_a), node);
422+
struct resource_entry *res_b = list_entry(b, typeof(*res_b), node);
423+
424+
return res_a->res->start > res_b->res->start;
425+
}
426+
417427
static int iova_reserve_pci_windows(struct pci_dev *dev,
418428
struct iova_domain *iovad)
419429
{
@@ -432,6 +442,7 @@ static int iova_reserve_pci_windows(struct pci_dev *dev,
432442
}
433443

434444
/* Get reserved DMA windows from host bridge */
445+
list_sort(NULL, &bridge->dma_ranges, iommu_dma_ranges_sort);
435446
resource_list_for_each_entry(window, &bridge->dma_ranges) {
436447
end = window->res->start - window->offset;
437448
resv_iova:
@@ -440,7 +451,7 @@ static int iova_reserve_pci_windows(struct pci_dev *dev,
440451
hi = iova_pfn(iovad, end);
441452
reserve_iova(iovad, lo, hi);
442453
} else if (end < start) {
443-
/* dma_ranges list should be sorted */
454+
/* DMA ranges should be non-overlapping */
444455
dev_err(&dev->dev,
445456
"Failed to reserve IOVA [%pa-%pa]\n",
446457
&start, &end);

drivers/pci/of.c

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,6 @@ static int devm_of_pci_get_host_bridge_resources(struct device *dev,
369369

370370
dev_dbg(dev, "Parsing dma-ranges property...\n");
371371
for_each_of_pci_range(&parser, &range) {
372-
struct resource_entry *entry;
373372
/*
374373
* If we failed translation or got a zero-sized region
375374
* then skip this range
@@ -393,12 +392,7 @@ static int devm_of_pci_get_host_bridge_resources(struct device *dev,
393392
goto failed;
394393
}
395394

396-
/* Keep the resource list sorted */
397-
resource_list_for_each_entry(entry, ib_resources)
398-
if (entry->res->start > res->start)
399-
break;
400-
401-
pci_add_resource_offset(&entry->node, res,
395+
pci_add_resource_offset(ib_resources, res,
402396
res->start - range.pci_addr);
403397
}
404398

0 commit comments

Comments
 (0)