summaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2019-05-13 18:34:45 -0500
committerBjorn Helgaas <bhelgaas@google.com>2019-05-13 18:34:45 -0500
commitf2e94683162565ff02d8d7386fadee175ab55e40 (patch)
treefb9752bf2288737623456872d93791b40c30582f /drivers/pci
parentee6df38da8485b143cc5eccee569ae3e238be10a (diff)
parent90199c951bd2a6248e55a8db3368a2568e3b3edc (diff)
downloadlinux-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.c44
-rw-r--r--drivers/pci/probe.c2
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);
}