summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSrinath Mannam <srinath.mannam@broadcom.com>2019-05-03 10:05:34 -0400
committerBjorn Helgaas <bhelgaas@google.com>2019-05-06 17:03:50 -0400
commit90199c951bd2a6248e55a8db3368a2568e3b3edc (patch)
treece4de577f8cc36a800d231ec01a792f77fa7c219
parentaadad097cd46f783b75c235cffa5c21fcffbf189 (diff)
PCI: iproc: Add sorted dma ranges resource entries to host bridge
The iProc host controller allows only a subset of physical address space as target of inbound PCI memory transaction addresses. PCI device memory transactions targeting memory regions that are not allowed for inbound transactions in the host controller are rejected by the host controller and cannot reach the upstream buses. The firmware device tree description defines the DMA ranges that are addressable by devices DMA transactions; parse the device tree dma-ranges property and add its ranges to the PCI host bridge dma_ranges list; the iova_reserve_pci_windows() call executed at iommu_dma_init_domain() will reserve the IOVA address ranges that are not addressable (ie memory holes in the dma-ranges set) so that they are not allocated to PCI devices for DMA transfers. All allowed address ranges are listed in the dma-ranges DT parameter. For example: dma-ranges = < \ 0x43000000 0x00 0x80000000 0x00 0x80000000 0x00 0x80000000 \ 0x43000000 0x08 0x00000000 0x08 0x00000000 0x08 0x00000000 \ 0x43000000 0x80 0x00000000 0x80 0x00000000 0x40 0x00000000> In the above example of dma-ranges, memory address from 0x0 - 0x80000000, 0x100000000 - 0x800000000, 0x1000000000 - 0x8000000000 and 0x10000000000 - 0xffffffffffffffff. are not allowed to be used as inbound addresses. Based-on-a-patch-by: Oza Pawandeep <oza.oza@broadcom.com> Signed-off-by: Srinath Mannam <srinath.mannam@broadcom.com> [lorenzo.pieralisi@arm.com: updated commit log] Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> [bhelgaas: fix function prototype style] Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Oza Pawandeep <poza@codeaurora.org> Reviewed-by: Eric Auger <eric.auger@redhat.com>
-rw-r--r--drivers/pci/controller/pcie-iproc.c44
1 files changed, 43 insertions, 1 deletions
diff --git a/drivers/pci/controller/pcie-iproc.c b/drivers/pci/controller/pcie-iproc.c
index c20fd6bd68fd..f76a75bb7ae4 100644
--- a/drivers/pci/controller/pcie-iproc.c
+++ b/drivers/pci/controller/pcie-iproc.c
@@ -1146,11 +1146,43 @@ err_ib:
1146 return ret; 1146 return ret;
1147} 1147}
1148 1148
1149static int iproc_pcie_add_dma_range(struct device *dev,
1150 struct list_head *resources,
1151 struct of_pci_range *range)
1152{
1153 struct resource *res;
1154 struct resource_entry *entry, *tmp;
1155 struct list_head *head = resources;
1156
1157 res = devm_kzalloc(dev, sizeof(struct resource), GFP_KERNEL);
1158 if (!res)
1159 return -ENOMEM;
1160
1161 resource_list_for_each_entry(tmp, resources) {
1162 if (tmp->res->start < range->cpu_addr)
1163 head = &tmp->node;
1164 }
1165
1166 res->start = range->cpu_addr;
1167 res->end = res->start + range->size - 1;
1168
1169 entry = resource_list_create_entry(res, 0);
1170 if (!entry)
1171 return -ENOMEM;
1172
1173 entry->offset = res->start - range->cpu_addr;
1174 resource_list_add(entry, head);
1175
1176 return 0;
1177}
1178
1149static int iproc_pcie_map_dma_ranges(struct iproc_pcie *pcie) 1179static int iproc_pcie_map_dma_ranges(struct iproc_pcie *pcie)
1150{ 1180{
1181 struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
1151 struct of_pci_range range; 1182 struct of_pci_range range;
1152 struct of_pci_range_parser parser; 1183 struct of_pci_range_parser parser;
1153 int ret; 1184 int ret;
1185 LIST_HEAD(resources);
1154 1186
1155 /* Get the dma-ranges from DT */ 1187 /* Get the dma-ranges from DT */
1156 ret = of_pci_dma_range_parser_init(&parser, pcie->dev->of_node); 1188 ret = of_pci_dma_range_parser_init(&parser, pcie->dev->of_node);
@@ -1158,13 +1190,23 @@ static int iproc_pcie_map_dma_ranges(struct iproc_pcie *pcie)
1158 return ret; 1190 return ret;
1159 1191
1160 for_each_of_pci_range(&parser, &range) { 1192 for_each_of_pci_range(&parser, &range) {
1193 ret = iproc_pcie_add_dma_range(pcie->dev,
1194 &resources,
1195 &range);
1196 if (ret)
1197 goto out;
1161 /* Each range entry corresponds to an inbound mapping region */ 1198 /* Each range entry corresponds to an inbound mapping region */
1162 ret = iproc_pcie_setup_ib(pcie, &range, IPROC_PCIE_IB_MAP_MEM); 1199 ret = iproc_pcie_setup_ib(pcie, &range, IPROC_PCIE_IB_MAP_MEM);
1163 if (ret) 1200 if (ret)
1164 return ret; 1201 goto out;
1165 } 1202 }
1166 1203
1204 list_splice_init(&resources, &host->dma_ranges);
1205
1167 return 0; 1206 return 0;
1207out:
1208 pci_free_resource_list(&resources);
1209 return ret;
1168} 1210}
1169 1211
1170static int iproce_pcie_get_msi(struct iproc_pcie *pcie, 1212static int iproce_pcie_get_msi(struct iproc_pcie *pcie,