Re: [PATCH] iommu/dma: Explicitly sort PCI DMA windows

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Mar 22, 2022 at 12:27 PM Robin Murphy <robin.murphy@xxxxxxx> wrote:
>
> 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 <robin.murphy@xxxxxxx>
> ---
>
> Looking at this area off the back of the XGene thread[1] made me realise
> that we need to do it anyway, regardless of whether it might also happen
> to restore the previous XGene behaviour or not. Presumably nobody's
> tried to use pcie-cadence-host behind an IOMMU yet...
>
> Boot-tested on Juno to make sure I hadn't got the sort comparison
> backwards.
>
> Robin.
>
> [1] https://lore.kernel.org/linux-pci/20220321104843.949645-1-maz@xxxxxxxxxx/
>
>  drivers/iommu/dma-iommu.c | 13 ++++++++++++-
>  drivers/pci/of.c          |  7 +------
>  2 files changed, 13 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
> index b22034975301..91d134c0c9b1 100644
> --- a/drivers/iommu/dma-iommu.c
> +++ b/drivers/iommu/dma-iommu.c
> @@ -20,6 +20,7 @@
>  #include <linux/iommu.h>
>  #include <linux/iova.h>
>  #include <linux/irq.h>
> +#include <linux/list_sort.h>
>  #include <linux/mm.h>
>  #include <linux/mutex.h>
>  #include <linux/pci.h>
> @@ -414,6 +415,15 @@ static int cookie_init_hw_msi_region(struct iommu_dma_cookie *cookie,
>         return 0;
>  }
>
> +static int iommu_dma_ranges_sort(void *priv, const struct list_head *a,
> +               const struct list_head *b)
> +{
> +       struct resource_entry *res_a = list_entry(a, typeof(*res_a), node);
> +       struct resource_entry *res_b = list_entry(b, typeof(*res_b), node);
> +
> +       return res_a->res->start > res_b->res->start;
> +}
> +
>  static int iova_reserve_pci_windows(struct pci_dev *dev,
>                 struct iova_domain *iovad)
>  {
> @@ -432,6 +442,7 @@ static int iova_reserve_pci_windows(struct pci_dev *dev,
>         }
>
>         /* Get reserved DMA windows from host bridge */
> +       list_sort(NULL, &bridge->dma_ranges, iommu_dma_ranges_sort);
>         resource_list_for_each_entry(window, &bridge->dma_ranges) {
>                 end = window->res->start - window->offset;
>  resv_iova:
> @@ -440,7 +451,7 @@ static int iova_reserve_pci_windows(struct pci_dev *dev,
>                         hi = iova_pfn(iovad, end);
>                         reserve_iova(iovad, lo, hi);
>                 } else if (end < start) {
> -                       /* dma_ranges list should be sorted */
> +                       /* DMA ranges should be non-overlapping */
>                         dev_err(&dev->dev,
>                                 "Failed to reserve IOVA [%pa-%pa]\n",
>                                 &start, &end);
> diff --git a/drivers/pci/of.c b/drivers/pci/of.c
> index cb2e8351c2cc..d176b4bc6193 100644
> --- a/drivers/pci/of.c
> +++ b/drivers/pci/of.c
> @@ -393,12 +393,7 @@ static int devm_of_pci_get_host_bridge_resources(struct device *dev,
>                         goto failed;
>                 }
>
> -               /* Keep the resource list sorted */
> -               resource_list_for_each_entry(entry, ib_resources)
> -                       if (entry->res->start > res->start)
> -                               break;
> -
> -               pci_add_resource_offset(&entry->node, res,

entry is now unused and causes a warning.

> +               pci_add_resource_offset(ib_resources, res,
>                                         res->start - range.pci_addr);
>         }
>
> --
> 2.28.0.dirty
>



[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux