aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/controller/dwc/pcie-designware-host.c
diff options
context:
space:
mode:
authorRob Herring <robh@kernel.org>2020-10-26 13:16:52 -0500
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2020-11-18 16:01:53 +0000
commit9f9e59a4809563f24e3d1377aa804a4b7386a418 (patch)
tree6e5b5ac2e082be6a85adc75ec769c3974a3663a5 /drivers/pci/controller/dwc/pcie-designware-host.c
parentLinux 5.10-rc3 (diff)
downloadlinux-dev-9f9e59a4809563f24e3d1377aa804a4b7386a418.tar.xz
linux-dev-9f9e59a4809563f24e3d1377aa804a4b7386a418.zip
PCI: dwc: Support multiple ATU memory regions
The current ATU setup only supports a single memory resource which isn't sufficient if there are also prefetchable memory regions. In order to support multiple memory regions, we need to move away from fixed ATU slots and rework the assignment. As there's always an ATU entry for config space, let's assign index 0 to config space. Then we assign memory resources to index 1 and up. Finally, if we have an I/O region and slots remaining, we assign the I/O region last. If there aren't remaining slots, we keep the same config and I/O space sharing. Link: https://lore.kernel.org/r/20201026181652.418729-1-robh@kernel.org Tested-by: Vidya Sagar <vidyas@nvidia.com> Signed-off-by: Rob Herring <robh@kernel.org> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Reviewed-by: Vidya Sagar <vidyas@nvidia.com> Acked-by: Jingoo Han <jingoohan1@gmail.com> Cc: Vidya Sagar <vidyas@nvidia.com> Cc: Jingoo Han <jingoohan1@gmail.com> Cc: Gustavo Pimentel <gustavo.pimentel@synopsys.com> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Cc: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/pci/controller/dwc/pcie-designware-host.c')
-rw-r--r--drivers/pci/controller/dwc/pcie-designware-host.c54
1 files changed, 32 insertions, 22 deletions
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 44c2a6572199..a6ffab9b537e 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -464,9 +464,7 @@ static void __iomem *dw_pcie_other_conf_map_bus(struct pci_bus *bus,
type = PCIE_ATU_TYPE_CFG1;
- dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
- type, pp->cfg0_base,
- busdev, pp->cfg0_size);
+ dw_pcie_prog_outbound_atu(pci, 0, type, pp->cfg0_base, busdev, pp->cfg0_size);
return pp->va_cfg0_base + where;
}
@@ -480,9 +478,8 @@ static int dw_pcie_rd_other_conf(struct pci_bus *bus, unsigned int devfn,
ret = pci_generic_config_read(bus, devfn, where, size, val);
- if (!ret && pci->num_viewport <= 2)
- dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
- PCIE_ATU_TYPE_IO, pp->io_base,
+ if (!ret && pci->io_cfg_atu_shared)
+ dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, pp->io_base,
pp->io_bus_addr, pp->io_size);
return ret;
@@ -497,9 +494,8 @@ static int dw_pcie_wr_other_conf(struct pci_bus *bus, unsigned int devfn,
ret = pci_generic_config_write(bus, devfn, where, size, val);
- if (!ret && pci->num_viewport <= 2)
- dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
- PCIE_ATU_TYPE_IO, pp->io_base,
+ if (!ret && pci->io_cfg_atu_shared)
+ dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, pp->io_base,
pp->io_bus_addr, pp->io_size);
return ret;
@@ -586,21 +582,35 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
* ATU, so we should not program the ATU here.
*/
if (pp->bridge->child_ops == &dw_child_pcie_ops) {
- struct resource_entry *tmp, *entry = NULL;
+ int atu_idx = 0;
+ struct resource_entry *entry;
/* Get last memory resource entry */
- resource_list_for_each_entry(tmp, &pp->bridge->windows)
- if (resource_type(tmp->res) == IORESOURCE_MEM)
- entry = tmp;
-
- dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
- PCIE_ATU_TYPE_MEM, entry->res->start,
- entry->res->start - entry->offset,
- resource_size(entry->res));
- if (pci->num_viewport > 2)
- dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX2,
- PCIE_ATU_TYPE_IO, pp->io_base,
- pp->io_bus_addr, pp->io_size);
+ resource_list_for_each_entry(entry, &pp->bridge->windows) {
+ if (resource_type(entry->res) != IORESOURCE_MEM)
+ continue;
+
+ if (pci->num_viewport <= ++atu_idx)
+ break;
+
+ dw_pcie_prog_outbound_atu(pci, atu_idx,
+ PCIE_ATU_TYPE_MEM, entry->res->start,
+ entry->res->start - entry->offset,
+ resource_size(entry->res));
+ }
+
+ if (pp->io_size) {
+ if (pci->num_viewport > ++atu_idx)
+ dw_pcie_prog_outbound_atu(pci, atu_idx,
+ PCIE_ATU_TYPE_IO, pp->io_base,
+ pp->io_bus_addr, pp->io_size);
+ else
+ pci->io_cfg_atu_shared = true;
+ }
+
+ if (pci->num_viewport <= atu_idx)
+ dev_warn(pci->dev, "Resources exceed number of ATU entries (%d)",
+ pci->num_viewport);
}
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);