From dfd1972c2b464c10fb585c4c60b594e09d181a01 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 1 Dec 2016 11:33:57 -0600 Subject: arm64: PCI: Add local struct device pointers Use a local "struct device *dev" for brevity. No functional change intended. Signed-off-by: Bjorn Helgaas Acked-by: Lorenzo Pieralisi --- arch/arm64/kernel/pci.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index acf38722457b..8183c9803206 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -121,6 +121,7 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) static struct pci_config_window * pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root) { + struct device *dev = &root->device->dev; struct resource *bus_res = &root->secondary; u16 seg = root->segment; struct pci_config_window *cfg; @@ -132,8 +133,7 @@ pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root) root->mcfg_addr = pci_mcfg_lookup(seg, bus_res); if (!root->mcfg_addr) { - dev_err(&root->device->dev, "%04x:%pR ECAM region not found\n", - seg, bus_res); + dev_err(dev, "%04x:%pR ECAM region not found\n", seg, bus_res); return NULL; } @@ -141,11 +141,10 @@ pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root) cfgres.start = root->mcfg_addr + bus_res->start * bsz; cfgres.end = cfgres.start + resource_size(bus_res) * bsz - 1; cfgres.flags = IORESOURCE_MEM; - cfg = pci_ecam_create(&root->device->dev, &cfgres, bus_res, - &pci_generic_ecam_ops); + cfg = pci_ecam_create(dev, &cfgres, bus_res, &pci_generic_ecam_ops); if (IS_ERR(cfg)) { - dev_err(&root->device->dev, "%04x:%pR error %ld mapping ECAM\n", - seg, bus_res, PTR_ERR(cfg)); + dev_err(dev, "%04x:%pR error %ld mapping ECAM\n", seg, bus_res, + PTR_ERR(cfg)); return NULL; } -- cgit v1.2.3 From 08b1c19606b5fc7f895dae4d43d507b4da4a83bf Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 30 Nov 2016 14:48:33 -0600 Subject: arm64: PCI: Search ACPI namespace to ensure ECAM space is reserved The static MCFG table tells us the base of ECAM space, but it does not reserve the space -- the reservation should be done via a device in the ACPI namespace whose _CRS includes the ECAM region. Use acpi_resource_consumer() to check whether the ECAM space is reserved by an ACPI namespace device. If it is, emit a message showing which device reserves it. If not, emit a "[Firmware Bug]" warning. Signed-off-by: Bjorn Helgaas Acked-by: Lorenzo Pieralisi --- arch/arm64/kernel/pci.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index 8183c9803206..216dff6c5877 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -124,8 +124,9 @@ pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root) struct device *dev = &root->device->dev; struct resource *bus_res = &root->secondary; u16 seg = root->segment; - struct pci_config_window *cfg; struct resource cfgres; + struct acpi_device *adev; + struct pci_config_window *cfg; unsigned int bsz; /* Use address from _CBA if present, otherwise lookup MCFG */ @@ -141,6 +142,15 @@ pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root) cfgres.start = root->mcfg_addr + bus_res->start * bsz; cfgres.end = cfgres.start + resource_size(bus_res) * bsz - 1; cfgres.flags = IORESOURCE_MEM; + + adev = acpi_resource_consumer(&cfgres); + if (adev) + dev_info(dev, "ECAM area %pR reserved by %s\n", &cfgres, + dev_name(&adev->dev)); + else + dev_warn(dev, FW_BUG "ECAM area %pR not reserved in ACPI namespace\n", + &cfgres); + cfg = pci_ecam_create(dev, &cfgres, bus_res, &pci_generic_ecam_ops); if (IS_ERR(cfg)) { dev_err(dev, "%04x:%pR error %ld mapping ECAM\n", seg, bus_res, -- cgit v1.2.3 From 093d24a204425f71f4f106b7e62c8df4b456e1cc Mon Sep 17 00:00:00 2001 From: Tomasz Nowicki Date: Thu, 24 Nov 2016 12:05:23 +0100 Subject: arm64: PCI: Manage controller-specific data on per-controller basis Currently we use one shared global acpi_pci_root_ops structure to keep controller-specific ops. We pass its pointer to acpi_pci_root_create() and associate it with a host bridge instance for good. Such a design implies serious drawback. Any potential manipulation on the single system-wide acpi_pci_root_ops leads to kernel crash. The structure content is not really changing even across multiple host bridges creation; thus it was not an issue so far. In preparation for adding ECAM quirks mechanism (where controller-specific PCI ops may be different for each host bridge) allocate new acpi_pci_root_ops and fill in with data for each bridge. Now it is safe to have different controller-specific info. As a consequence free acpi_pci_root_ops when host bridge is released. No functional changes in this patch. Signed-off-by: Tomasz Nowicki Signed-off-by: Bjorn Helgaas Acked-by: Lorenzo Pieralisi --- arch/arm64/kernel/pci.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'arch') diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index 216dff6c5877..ac4509d2668a 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -168,33 +168,36 @@ static void pci_acpi_generic_release_info(struct acpi_pci_root_info *ci) ri = container_of(ci, struct acpi_pci_generic_root_info, common); pci_ecam_free(ri->cfg); + kfree(ci->ops); kfree(ri); } -static struct acpi_pci_root_ops acpi_pci_root_ops = { - .release_info = pci_acpi_generic_release_info, -}; - /* Interface called from ACPI code to setup PCI host controller */ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) { int node = acpi_get_node(root->device->handle); struct acpi_pci_generic_root_info *ri; struct pci_bus *bus, *child; + struct acpi_pci_root_ops *root_ops; ri = kzalloc_node(sizeof(*ri), GFP_KERNEL, node); if (!ri) return NULL; + root_ops = kzalloc_node(sizeof(*root_ops), GFP_KERNEL, node); + if (!root_ops) + return NULL; + ri->cfg = pci_acpi_setup_ecam_mapping(root); if (!ri->cfg) { kfree(ri); + kfree(root_ops); return NULL; } - acpi_pci_root_ops.pci_ops = &ri->cfg->ops->pci_ops; - bus = acpi_pci_root_create(root, &acpi_pci_root_ops, &ri->common, - ri->cfg); + root_ops->release_info = pci_acpi_generic_release_info; + root_ops->pci_ops = &ri->cfg->ops->pci_ops; + bus = acpi_pci_root_create(root, root_ops, &ri->common, ri->cfg); if (!bus) return NULL; -- cgit v1.2.3 From 8fd4391ee717569d60fa283da778f7497630c9b7 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 2 Dec 2016 17:25:54 -0600 Subject: arm64: PCI: Exclude ACPI "consumer" resources from host bridge windows On x86 and ia64, we have treated all ACPI _CRS resources of PNP0A03 host bridge devices as "producers", i.e., as host bridge windows. That's partly because some x86 BIOSes improperly used "consumer" descriptors to describe windows and partly because Linux didn't have good support for handling consumer and producer descriptors differently. One result is that x86 BIOSes describe host bridge "consumer" resources in the _CRS of a PNP0C02 device, not the PNP0A03 device itself. On arm64 we don't have a legacy of firmware that has this consumer/producer confusion, so we can handle PNP0A03 "consumer" descriptors as host bridge registers instead of windows. Exclude non-window ("consumer") resources from the list of host bridge windows. This allows the use of "consumer" PNP0A03 descriptors for bridge register space. Signed-off-by: Bjorn Helgaas --- arch/arm64/kernel/pci.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'arch') diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index ac4509d2668a..266a7b2d4184 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -114,6 +114,19 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) return 0; } +static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci) +{ + struct resource_entry *entry, *tmp; + int status; + + status = acpi_pci_probe_root_resources(ci); + resource_list_for_each_entry_safe(entry, tmp, &ci->resources) { + if (!(entry->res->flags & IORESOURCE_WINDOW)) + resource_list_destroy_entry(entry); + } + return status; +} + /* * Lookup the bus range for the domain in MCFG, and set up config space * mapping. @@ -196,6 +209,7 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) } root_ops->release_info = pci_acpi_generic_release_info; + root_ops->prepare_resources = pci_acpi_root_prepare_resources; root_ops->pci_ops = &ri->cfg->ops->pci_ops; bus = acpi_pci_root_create(root, root_ops, &ri->common, ri->cfg); if (!bus) -- cgit v1.2.3 From 13983eb89d5afaa65acd4479fad151cbd4de5509 Mon Sep 17 00:00:00 2001 From: Tomasz Nowicki Date: Fri, 9 Sep 2016 21:24:03 +0200 Subject: PCI/ACPI: Extend pci_mcfg_lookup() to return ECAM config accessors pci_mcfg_lookup() is the external interface to the generic MCFG code. Previously it merely looked up the ECAM base address for a given domain and bus range. We want a way to add MCFG quirks, some of which may require special config accessors and adjustments to the ECAM address range. Extend pci_mcfg_lookup() so it can return a pointer to a pci_ecam_ops structure and a struct resource for the ECAM address space. For now, it always returns &pci_generic_ecam_ops (the standard accessor) and the resource described by the MCFG. No functional changes intended. [bhelgaas: changelog] Signed-off-by: Tomasz Nowicki Signed-off-by: Bjorn Helgaas --- arch/arm64/kernel/pci.c | 17 +++++------------ drivers/acpi/pci_mcfg.c | 28 +++++++++++++++++++++++++--- include/linux/pci-acpi.h | 4 +++- 3 files changed, 33 insertions(+), 16 deletions(-) (limited to 'arch') diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index 266a7b2d4184..4f0e3ebfea4b 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -137,25 +137,18 @@ pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root) struct device *dev = &root->device->dev; struct resource *bus_res = &root->secondary; u16 seg = root->segment; + struct pci_ecam_ops *ecam_ops; struct resource cfgres; struct acpi_device *adev; struct pci_config_window *cfg; - unsigned int bsz; + int ret; - /* Use address from _CBA if present, otherwise lookup MCFG */ - if (!root->mcfg_addr) - root->mcfg_addr = pci_mcfg_lookup(seg, bus_res); - - if (!root->mcfg_addr) { + ret = pci_mcfg_lookup(root, &cfgres, &ecam_ops); + if (ret) { dev_err(dev, "%04x:%pR ECAM region not found\n", seg, bus_res); return NULL; } - bsz = 1 << pci_generic_ecam_ops.bus_shift; - cfgres.start = root->mcfg_addr + bus_res->start * bsz; - cfgres.end = cfgres.start + resource_size(bus_res) * bsz - 1; - cfgres.flags = IORESOURCE_MEM; - adev = acpi_resource_consumer(&cfgres); if (adev) dev_info(dev, "ECAM area %pR reserved by %s\n", &cfgres, @@ -164,7 +157,7 @@ pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root) dev_warn(dev, FW_BUG "ECAM area %pR not reserved in ACPI namespace\n", &cfgres); - cfg = pci_ecam_create(dev, &cfgres, bus_res, &pci_generic_ecam_ops); + cfg = pci_ecam_create(dev, &cfgres, bus_res, ecam_ops); if (IS_ERR(cfg)) { dev_err(dev, "%04x:%pR error %ld mapping ECAM\n", seg, bus_res, PTR_ERR(cfg)); diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c index b5b376e081f5..ffcc6513e851 100644 --- a/drivers/acpi/pci_mcfg.c +++ b/drivers/acpi/pci_mcfg.c @@ -22,6 +22,7 @@ #include #include #include +#include /* Structure to hold entries from the MCFG table */ struct mcfg_entry { @@ -35,9 +36,18 @@ struct mcfg_entry { /* List to save MCFG entries */ static LIST_HEAD(pci_mcfg_list); -phys_addr_t pci_mcfg_lookup(u16 seg, struct resource *bus_res) +int pci_mcfg_lookup(struct acpi_pci_root *root, struct resource *cfgres, + struct pci_ecam_ops **ecam_ops) { + struct pci_ecam_ops *ops = &pci_generic_ecam_ops; + struct resource *bus_res = &root->secondary; + u16 seg = root->segment; struct mcfg_entry *e; + struct resource res; + + /* Use address from _CBA if present, otherwise lookup MCFG */ + if (root->mcfg_addr) + goto skip_lookup; /* * We expect exact match, unless MCFG entry end bus covers more than @@ -45,10 +55,22 @@ phys_addr_t pci_mcfg_lookup(u16 seg, struct resource *bus_res) */ list_for_each_entry(e, &pci_mcfg_list, list) { if (e->segment == seg && e->bus_start == bus_res->start && - e->bus_end >= bus_res->end) - return e->addr; + e->bus_end >= bus_res->end) { + root->mcfg_addr = e->addr; + } + } + if (!root->mcfg_addr) + return -ENXIO; + +skip_lookup: + memset(&res, 0, sizeof(res)); + res.start = root->mcfg_addr + (bus_res->start << 20); + res.end = res.start + (resource_size(bus_res) << 20) - 1; + res.flags = IORESOURCE_MEM; + *cfgres = res; + *ecam_ops = ops; return 0; } diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h index 7d63a66e8ed4..7a4e83a8c89c 100644 --- a/include/linux/pci-acpi.h +++ b/include/linux/pci-acpi.h @@ -24,7 +24,9 @@ static inline acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev) } extern phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle); -extern phys_addr_t pci_mcfg_lookup(u16 domain, struct resource *bus_res); +struct pci_ecam_ops; +extern int pci_mcfg_lookup(struct acpi_pci_root *root, struct resource *cfgres, + struct pci_ecam_ops **ecam_ops); static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev) { -- cgit v1.2.3 From 589a2d3f18be4c3e2169013eada35baae9b25f79 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 25 Nov 2016 11:57:17 +0100 Subject: arm64: tegra: Add PCIe host bridge on Tegra210 Add the PCIe host bridge found on Tegra X1. It implements two root ports that support x4 and x1 configurations, respectively. Signed-off-by: Thierry Reding Signed-off-by: Bjorn Helgaas --- arch/arm64/boot/dts/nvidia/tegra210.dtsi | 63 ++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) (limited to 'arch') diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi index 46045fe719da..2f832df29da8 100644 --- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi @@ -11,6 +11,69 @@ #address-cells = <2>; #size-cells = <2>; + pcie-controller@01003000 { + compatible = "nvidia,tegra210-pcie"; + device_type = "pci"; + reg = <0x0 0x01003000 0x0 0x00000800 /* PADS registers */ + 0x0 0x01003800 0x0 0x00000800 /* AFI registers */ + 0x0 0x02000000 0x0 0x10000000>; /* configuration space */ + reg-names = "pads", "afi", "cs"; + interrupts = , /* controller interrupt */ + ; /* MSI interrupt */ + interrupt-names = "intr", "msi"; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>; + + bus-range = <0x00 0xff>; + #address-cells = <3>; + #size-cells = <2>; + + ranges = <0x82000000 0 0x01000000 0x0 0x01000000 0 0x00001000 /* port 0 configuration space */ + 0x82000000 0 0x01001000 0x0 0x01001000 0 0x00001000 /* port 1 configuration space */ + 0x81000000 0 0x0 0x0 0x12000000 0 0x00010000 /* downstream I/O (64 KiB) */ + 0x82000000 0 0x13000000 0x0 0x13000000 0 0x0d000000 /* non-prefetchable memory (208 MiB) */ + 0xc2000000 0 0x20000000 0x0 0x20000000 0 0x20000000>; /* prefetchable memory (512 MiB) */ + + clocks = <&tegra_car TEGRA210_CLK_PCIE>, + <&tegra_car TEGRA210_CLK_AFI>, + <&tegra_car TEGRA210_CLK_PLL_E>, + <&tegra_car TEGRA210_CLK_CML0>; + clock-names = "pex", "afi", "pll_e", "cml"; + resets = <&tegra_car 70>, + <&tegra_car 72>, + <&tegra_car 74>; + reset-names = "pex", "afi", "pcie_x"; + status = "disabled"; + + pci@1,0 { + device_type = "pci"; + assigned-addresses = <0x82000800 0 0x01000000 0 0x1000>; + reg = <0x000800 0 0 0 0>; + status = "disabled"; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + + nvidia,num-lanes = <4>; + }; + + pci@2,0 { + device_type = "pci"; + assigned-addresses = <0x82001000 0 0x01001000 0 0x1000>; + reg = <0x001000 0 0 0 0>; + status = "disabled"; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + + nvidia,num-lanes = <1>; + }; + }; + host1x@50000000 { compatible = "nvidia,tegra210-host1x", "simple-bus"; reg = <0x0 0x50000000 0x0 0x00034000>; -- cgit v1.2.3 From af099eab35c3aea52534002203f8b9c7ebdc9861 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 25 Nov 2016 11:57:18 +0100 Subject: arm64: tegra: Enable PCIe on Jetson TX1 Enable the x4 PCIe and M.2 Key E slots on Jetson TX1. The Key E slot is currently untested due to lack of hardware. Signed-off-by: Thierry Reding Signed-off-by: Bjorn Helgaas --- arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'arch') diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts index 983775e637a4..4c1ea7a08d43 100644 --- a/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts +++ b/arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts @@ -7,6 +7,32 @@ model = "NVIDIA Jetson TX1 Developer Kit"; compatible = "nvidia,p2371-2180", "nvidia,tegra210"; + pcie-controller@01003000 { + status = "okay"; + + avdd-pll-uerefe-supply = <&avdd_1v05_pll>; + hvddio-pex-supply = <&vdd_1v8>; + dvddio-pex-supply = <&vdd_pex_1v05>; + dvdd-pex-pll-supply = <&vdd_pex_1v05>; + hvdd-pex-pll-e-supply = <&vdd_1v8>; + vddio-pex-ctl-supply = <&vdd_1v8>; + + pci@1,0 { + phys = <&{/padctl@7009f000/pads/pcie/lanes/pcie-0}>, + <&{/padctl@7009f000/pads/pcie/lanes/pcie-1}>, + <&{/padctl@7009f000/pads/pcie/lanes/pcie-2}>, + <&{/padctl@7009f000/pads/pcie/lanes/pcie-3}>; + phy-names = "pcie-0", "pcie-1", "pcie-2", "pcie-3"; + status = "okay"; + }; + + pci@2,0 { + phys = <&{/padctl@7009f000/pads/pcie/lanes/pcie-4}>; + phy-names = "pcie-0"; + status = "okay"; + }; + }; + host1x@50000000 { dsi@54300000 { status = "okay"; -- cgit v1.2.3