PCI: Add MCFG quirks for Cavium ThunderX pass2.x host controller
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>
This commit is contained in:
Родитель
0d414268fb
Коммит
44f22bd91e
|
@ -74,6 +74,25 @@ static struct mcfg_fixup mcfg_quirks[] = {
|
||||||
HISI_QUAD_DOM("HIP07 ", 4, &hisi_pcie_ops),
|
HISI_QUAD_DOM("HIP07 ", 4, &hisi_pcie_ops),
|
||||||
HISI_QUAD_DOM("HIP07 ", 8, &hisi_pcie_ops),
|
HISI_QUAD_DOM("HIP07 ", 8, &hisi_pcie_ops),
|
||||||
HISI_QUAD_DOM("HIP07 ", 12, &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];
|
static char mcfg_oem_id[ACPI_OEM_ID_SIZE];
|
||||||
|
|
|
@ -240,7 +240,8 @@ config PCIE_QCOM
|
||||||
|
|
||||||
config PCI_HOST_THUNDER_PEM
|
config PCI_HOST_THUNDER_PEM
|
||||||
bool "Cavium Thunder PCIe controller to off-chip devices"
|
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
|
select PCI_HOST_COMMON
|
||||||
help
|
help
|
||||||
Say Y here if you want PCIe support for CN88XX Cavium Thunder SoCs.
|
Say Y here if you want PCIe support for CN88XX Cavium Thunder SoCs.
|
||||||
|
|
|
@ -28,7 +28,7 @@ obj-$(CONFIG_PCIE_ALTERA_MSI) += pcie-altera-msi.o
|
||||||
obj-$(CONFIG_ARM64) += pcie-hisi.o
|
obj-$(CONFIG_ARM64) += pcie-hisi.o
|
||||||
obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o
|
obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o
|
||||||
obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.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_ARMADA_8K) += pcie-armada8k.o
|
||||||
obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o
|
obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o
|
||||||
obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o
|
obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o
|
||||||
|
|
|
@ -18,8 +18,12 @@
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
#include <linux/of_pci.h>
|
#include <linux/of_pci.h>
|
||||||
|
#include <linux/pci-acpi.h>
|
||||||
#include <linux/pci-ecam.h>
|
#include <linux/pci-ecam.h>
|
||||||
#include <linux/platform_device.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_WR 0x28
|
||||||
#define PEM_CFG_RD 0x30
|
#define PEM_CFG_RD 0x30
|
||||||
|
@ -313,6 +317,43 @@ static int thunder_pem_init(struct device *dev, struct pci_config_window *cfg,
|
||||||
return 0;
|
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)
|
static int thunder_pem_platform_init(struct pci_config_window *cfg)
|
||||||
{
|
{
|
||||||
struct device *dev = cfg->parent;
|
struct device *dev = cfg->parent;
|
||||||
|
@ -364,3 +405,6 @@ static struct platform_driver thunder_pem_driver = {
|
||||||
.probe = thunder_pem_probe,
|
.probe = thunder_pem_probe,
|
||||||
};
|
};
|
||||||
builtin_platform_driver(thunder_pem_driver);
|
builtin_platform_driver(thunder_pem_driver);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
|
@ -62,6 +62,7 @@ extern struct pci_ecam_ops pci_generic_ecam_ops;
|
||||||
#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
|
#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 pci_32b_ops; /* 32-bit accesses only */
|
||||||
extern struct pci_ecam_ops hisi_pcie_ops; /* HiSilicon */
|
extern struct pci_ecam_ops hisi_pcie_ops; /* HiSilicon */
|
||||||
|
extern struct pci_ecam_ops thunder_pem_ecam_ops; /* Cavium ThunderX 2.x */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_PCI_HOST_GENERIC
|
#ifdef CONFIG_PCI_HOST_GENERIC
|
||||||
|
|
Загрузка…
Ссылка в новой задаче