PCI: Add MCFG quirks for Cavium ThunderX pass2.x host controller
authorTomasz Nowicki <tn@semihalf.com>
Thu, 1 Dec 2016 06:07:56 +0000 (00:07 -0600)
committerBjorn Helgaas <helgaas@kernel.org>
Tue, 6 Dec 2016 19:45:49 +0000 (13:45 -0600)
ThunderX PCIe controller to off-chip devices (so-called PEM) is not fully
compliant with ECAM standard. It uses non-standard configuration space
accessors (see thunder_pem_ecam_ops) and custom configuration space
granulation (see bus_shift = 24). In order to access configuration space
and probe PEM as ACPI-based PCI host controller we need to add MCFG quirk
infrastructure. This involves:
1. A new thunder_pem_acpi_init() init function to locate PEM-specific
   register ranges using ACPI.
2. Export PEM thunder_pem_ecam_ops structure so it is visible to MCFG quirk
   code.
3. New quirk entries for each PEM segment. Each contains platform IDs,
   mentioned thunder_pem_ecam_ops and CFG resources.

Quirk is considered for ThunderX silicon pass2.x only which is identified
via MCFG revision 1.

ThunderX pass 2.x requires the following accessors:

  NUMA Node 0 PCI segments  0- 3: pci_generic_ecam_ops (ECAM-compliant)
  NUMA Node 0 PCI segments  4- 9: thunder_pem_ecam_ops (MCFG quirk)
  NUMA Node 1 PCI segments 10-13: pci_generic_ecam_ops (ECAM-compliant)
  NUMA Node 1 PCI segments 14-19: thunder_pem_ecam_ops (MCFG quirk)

[bhelgaas: adapt to use acpi_get_rc_resources(), update Makefile/ifdefs so
quirk doesn't depend on CONFIG_PCI_HOST_THUNDER_PEM]
Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
drivers/acpi/pci_mcfg.c
drivers/pci/host/Kconfig
drivers/pci/host/Makefile
drivers/pci/host/pci-thunder-pem.c
include/linux/pci-ecam.h

index dd162248c3ee71a8a484c220f2f64e7f31bb193c..17cbb07ce16c5eef2587271b892f61b2a5e753eb 100644 (file)
@@ -74,6 +74,25 @@ static struct mcfg_fixup mcfg_quirks[] = {
        HISI_QUAD_DOM("HIP07   ",  4, &hisi_pcie_ops),
        HISI_QUAD_DOM("HIP07   ",  8, &hisi_pcie_ops),
        HISI_QUAD_DOM("HIP07   ", 12, &hisi_pcie_ops),
+
+#define THUNDER_PEM_RES(addr, node) \
+       DEFINE_RES_MEM((addr) + ((u64) (node) << 44), 0x39 * SZ_16M)
+#define THUNDER_PEM_QUIRK(rev, node) \
+       { "CAVIUM", "THUNDERX", rev, 4 + (10 * (node)), MCFG_BUS_ANY,       \
+         &thunder_pem_ecam_ops, THUNDER_PEM_RES(0x88001f000000UL, node) },  \
+       { "CAVIUM", "THUNDERX", rev, 5 + (10 * (node)), MCFG_BUS_ANY,       \
+         &thunder_pem_ecam_ops, THUNDER_PEM_RES(0x884057000000UL, node) },  \
+       { "CAVIUM", "THUNDERX", rev, 6 + (10 * (node)), MCFG_BUS_ANY,       \
+         &thunder_pem_ecam_ops, THUNDER_PEM_RES(0x88808f000000UL, node) },  \
+       { "CAVIUM", "THUNDERX", rev, 7 + (10 * (node)), MCFG_BUS_ANY,       \
+         &thunder_pem_ecam_ops, THUNDER_PEM_RES(0x89001f000000UL, node) },  \
+       { "CAVIUM", "THUNDERX", rev, 8 + (10 * (node)), MCFG_BUS_ANY,       \
+         &thunder_pem_ecam_ops, THUNDER_PEM_RES(0x894057000000UL, node) },  \
+       { "CAVIUM", "THUNDERX", rev, 9 + (10 * (node)), MCFG_BUS_ANY,       \
+         &thunder_pem_ecam_ops, THUNDER_PEM_RES(0x89808f000000UL, node) }
+       /* SoC pass2.x */
+       THUNDER_PEM_QUIRK(1, 0),
+       THUNDER_PEM_QUIRK(1, 1),
 };
 
 static char mcfg_oem_id[ACPI_OEM_ID_SIZE];
index d7e7c0a827c3526dec77709298fc56a40ee5954e..1239a8e63368dc2d7a9cf9b20f9685cae4d11b8c 100644 (file)
@@ -240,7 +240,8 @@ config PCIE_QCOM
 
 config PCI_HOST_THUNDER_PEM
        bool "Cavium Thunder PCIe controller to off-chip devices"
-       depends on OF && ARM64
+       depends on ARM64
+       depends on OF || (ACPI && PCI_QUIRKS)
        select PCI_HOST_COMMON
        help
          Say Y here if you want PCIe support for CN88XX Cavium Thunder SoCs.
index 64845f0d61387dfbc7a41efb994c6fde6a4ef0da..97e6bfc557725583c8db7509060d37b8496f6e4c 100644 (file)
@@ -28,7 +28,7 @@ obj-$(CONFIG_PCIE_ALTERA_MSI) += pcie-altera-msi.o
 obj-$(CONFIG_ARM64) += pcie-hisi.o
 obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o
 obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o
-obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o
+obj-$(CONFIG_ARM64) += pci-thunder-pem.o
 obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o
 obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o
 obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o
index c3276eede82a3ec2751b92bb1c01af0ab0df94b3..af722eb0ca753312a8588d3291ceecd591312626 100644 (file)
 #include <linux/init.h>
 #include <linux/of_address.h>
 #include <linux/of_pci.h>
+#include <linux/pci-acpi.h>
 #include <linux/pci-ecam.h>
 #include <linux/platform_device.h>
+#include "../pci.h"
+
+#if defined(CONFIG_PCI_HOST_THUNDER_PEM) || (defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS))
 
 #define PEM_CFG_WR 0x28
 #define PEM_CFG_RD 0x30
@@ -313,6 +317,43 @@ static int thunder_pem_init(struct device *dev, struct pci_config_window *cfg,
        return 0;
 }
 
+#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
+
+static int thunder_pem_acpi_init(struct pci_config_window *cfg)
+{
+       struct device *dev = cfg->parent;
+       struct acpi_device *adev = to_acpi_device(dev);
+       struct acpi_pci_root *root = acpi_driver_data(adev);
+       struct resource *res_pem;
+       int ret;
+
+       res_pem = devm_kzalloc(&adev->dev, sizeof(*res_pem), GFP_KERNEL);
+       if (!res_pem)
+               return -ENOMEM;
+
+       ret = acpi_get_rc_resources(dev, "THRX0002", root->segment, res_pem);
+       if (ret) {
+               dev_err(dev, "can't get rc base address\n");
+               return ret;
+       }
+
+       return thunder_pem_init(dev, cfg, res_pem);
+}
+
+struct pci_ecam_ops thunder_pem_ecam_ops = {
+       .bus_shift      = 24,
+       .init           = thunder_pem_acpi_init,
+       .pci_ops        = {
+               .map_bus        = pci_ecam_map_bus,
+               .read           = thunder_pem_config_read,
+               .write          = thunder_pem_config_write,
+       }
+};
+
+#endif
+
+#ifdef CONFIG_PCI_HOST_THUNDER_PEM
+
 static int thunder_pem_platform_init(struct pci_config_window *cfg)
 {
        struct device *dev = cfg->parent;
@@ -364,3 +405,6 @@ static struct platform_driver thunder_pem_driver = {
        .probe = thunder_pem_probe,
 };
 builtin_platform_driver(thunder_pem_driver);
+
+#endif
+#endif
index bdacbc883a22b210dd1b312e3df7685df7aa95c3..e88d7db7420096e1df45942caa7a60ee06fbfefd 100644 (file)
@@ -62,6 +62,7 @@ extern struct pci_ecam_ops pci_generic_ecam_ops;
 #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
 extern struct pci_ecam_ops pci_32b_ops;                /* 32-bit accesses only */
 extern struct pci_ecam_ops hisi_pcie_ops;      /* HiSilicon */
+extern struct pci_ecam_ops thunder_pem_ecam_ops; /* Cavium ThunderX 2.x */
 #endif
 
 #ifdef CONFIG_PCI_HOST_GENERIC