diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2019-05-13 18:34:45 -0500 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2019-05-13 18:34:45 -0500 |
commit | f2e94683162565ff02d8d7386fadee175ab55e40 (patch) | |
tree | fb9752bf2288737623456872d93791b40c30582f /drivers/pci | |
parent | ee6df38da8485b143cc5eccee569ae3e238be10a (diff) | |
parent | 90199c951bd2a6248e55a8db3368a2568e3b3edc (diff) | |
download | linux-f2e94683162565ff02d8d7386fadee175ab55e40.tar.gz linux-f2e94683162565ff02d8d7386fadee175ab55e40.tar.bz2 linux-f2e94683162565ff02d8d7386fadee175ab55e40.zip |
Merge branch 'pci/iova-dma-ranges'
- Add list of legal DMA address ranges to PCI host bridge (Srinath
Mannam)
- Reserve inaccessible DMA ranges so IOMMU doesn't allocate them (Srinath
Mannam)
- Parse iProc DT dma-ranges to learn what PCI devices can reach via DMA
(Srinath Mannam)
* pci/iova-dma-ranges:
PCI: iproc: Add sorted dma ranges resource entries to host bridge
iommu/dma: Reserve IOVA for PCIe inaccessible DMA address
PCI: Add dma_ranges window list
# Conflicts:
# drivers/pci/probe.c
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/controller/pcie-iproc.c | 44 | ||||
-rw-r--r-- | drivers/pci/probe.c | 2 |
2 files changed, 45 insertions, 1 deletions
diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c index aa4768a2c0ca..e3ca46497470 100644 --- a/drivers/pci/controller/pcie-iproc.c +++ b/drivers/pci/controller/pcie-iproc.c @@ -1182,11 +1182,43 @@ err_ib: return ret; } +static int iproc_pcie_add_dma_range(struct device *dev, + struct list_head *resources, + struct of_pci_range *range) +{ + struct resource *res; + struct resource_entry *entry, *tmp; + struct list_head *head = resources; + + res = devm_kzalloc(dev, sizeof(struct resource), GFP_KERNEL); + if (!res) + return -ENOMEM; + + resource_list_for_each_entry(tmp, resources) { + if (tmp->res->start < range->cpu_addr) + head = &tmp->node; + } + + res->start = range->cpu_addr; + res->end = res->start + range->size - 1; + + entry = resource_list_create_entry(res, 0); + if (!entry) + return -ENOMEM; + + entry->offset = res->start - range->cpu_addr; + resource_list_add(entry, head); + + return 0; +} + static int iproc_pcie_map_dma_ranges(struct iproc_pcie *pcie) { + struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); struct of_pci_range range; struct of_pci_range_parser parser; int ret; + LIST_HEAD(resources); /* Get the dma-ranges from DT */ ret = of_pci_dma_range_parser_init(&parser, pcie->dev->of_node); @@ -1194,13 +1226,23 @@ static int iproc_pcie_map_dma_ranges(struct iproc_pcie *pcie) return ret; for_each_of_pci_range(&parser, &range) { + ret = iproc_pcie_add_dma_range(pcie->dev, + &resources, + &range); + if (ret) + goto out; /* Each range entry corresponds to an inbound mapping region */ ret = iproc_pcie_setup_ib(pcie, &range, IPROC_PCIE_IB_MAP_MEM); if (ret) - return ret; + goto out; } + list_splice_init(&resources, &host->dma_ranges); + return 0; +out: + pci_free_resource_list(&resources); + return ret; } static int iproce_pcie_get_msi(struct iproc_pcie *pcie, diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 50cd9c17c08f..0dc42f0eb66d 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -589,6 +589,7 @@ static void pci_release_host_bridge_dev(struct device *dev) static void pci_init_host_bridge(struct pci_host_bridge *bridge) { INIT_LIST_HEAD(&bridge->windows); + INIT_LIST_HEAD(&bridge->dma_ranges); /* * We assume we can manage these PCIe features. Some systems may @@ -637,6 +638,7 @@ EXPORT_SYMBOL(devm_pci_alloc_host_bridge); void pci_free_host_bridge(struct pci_host_bridge *bridge) { pci_free_resource_list(&bridge->windows); + pci_free_resource_list(&bridge->dma_ranges); kfree(bridge); } |