Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Srinath Mannam and committed by
Bjorn Helgaas
90199c95 aadad097

+43 -1
+43 -1
drivers/pci/controller/pcie-iproc.c
··· 1146 1146 return ret; 1147 1147 } 1148 1148 1149 + static 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 + 1149 1179 static 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 1182 struct of_pci_range range; 1152 1183 struct of_pci_range_parser parser; 1153 1184 int ret; 1185 + LIST_HEAD(resources); 1154 1186 1155 1187 /* Get the dma-ranges from DT */ 1156 1188 ret = of_pci_dma_range_parser_init(&parser, pcie->dev->of_node); ··· 1190 1158 return ret; 1191 1159 1192 1160 for_each_of_pci_range(&parser, &range) { 1161 + ret = iproc_pcie_add_dma_range(pcie->dev, 1162 + &resources, 1163 + &range); 1164 + if (ret) 1165 + goto out; 1193 1166 /* Each range entry corresponds to an inbound mapping region */ 1194 1167 ret = iproc_pcie_setup_ib(pcie, &range, IPROC_PCIE_IB_MAP_MEM); 1195 1168 if (ret) 1196 - return ret; 1169 + goto out; 1197 1170 } 1198 1171 1172 + list_splice_init(&resources, &host->dma_ranges); 1173 + 1199 1174 return 0; 1175 + out: 1176 + pci_free_resource_list(&resources); 1177 + return ret; 1200 1178 } 1201 1179 1202 1180 static int iproce_pcie_get_msi(struct iproc_pcie *pcie,