diff options
Diffstat (limited to 'arm64-pcie-quirks.patch')
-rw-r--r-- | arm64-pcie-quirks.patch | 977 |
1 files changed, 0 insertions, 977 deletions
diff --git a/arm64-pcie-quirks.patch b/arm64-pcie-quirks.patch deleted file mode 100644 index 36e8d3724..000000000 --- a/arm64-pcie-quirks.patch +++ /dev/null @@ -1,977 +0,0 @@ -From 5c4f8b5b68451e5d208a5aefb195fdd108629da4 Mon Sep 17 00:00:00 2001 -From: Tomasz Nowicki <tn@semihalf.com> -Date: Fri, 9 Sep 2016 21:24:03 +0200 -Subject: [PATCH 1/6] PCI/ACPI: Extend pci_mcfg_lookup() responsibilities - -In preparation for adding MCFG platform specific quirk handling move -CFG resource calculation and ECAM ops assignment to pci_mcfg_lookup(). -It becomes the gate for further ops and CFG resource manipulation -in arch-agnostic code (drivers/acpi/pci_mcfg.c). - -No functionality changes in this patch. - -Signed-off-by: Tomasz Nowicki <tn@semihalf.com> ---- - 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(-) - -diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c -index acf3872..fb439c7 100644 ---- a/arch/arm64/kernel/pci.c -+++ b/arch/arm64/kernel/pci.c -@@ -125,24 +125,17 @@ pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root) - u16 seg = root->segment; - struct pci_config_window *cfg; - struct resource cfgres; -- unsigned int bsz; -+ struct pci_ecam_ops *ecam_ops; -+ 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(&root->device->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; -- cfg = pci_ecam_create(&root->device->dev, &cfgres, bus_res, -- &pci_generic_ecam_ops); -+ cfg = pci_ecam_create(&root->device->dev, &cfgres, bus_res, ecam_ops); - if (IS_ERR(cfg)) { - dev_err(&root->device->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 b5b376e..ffcc651 100644 ---- a/drivers/acpi/pci_mcfg.c -+++ b/drivers/acpi/pci_mcfg.c -@@ -22,6 +22,7 @@ - #include <linux/kernel.h> - #include <linux/pci.h> - #include <linux/pci-acpi.h> -+#include <linux/pci-ecam.h> - - /* 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 7d63a66..7a4e83a 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) - { --- -2.9.3 - -From 16c02d9cc0e67b48c343aecc4b5566e729a97683 Mon Sep 17 00:00:00 2001 -From: Tomasz Nowicki <tn@semihalf.com> -Date: Fri, 9 Sep 2016 21:24:04 +0200 -Subject: [PATCH 2/6] PCI/ACPI: Check platform specific ECAM quirks - -Some platforms may not be fully compliant with generic set of PCI config -accessors. For these cases we implement the way to overwrite CFG accessors -set and configuration space range. - -In first place pci_mcfg_parse() saves machine's IDs and revision number -(these come from MCFG header) in order to match against known quirk entries. -Then the algorithm traverses available quirk list (static array), -matches against <oem_id, oem_table_id, rev, domain, bus number range> and -returns custom PCI config ops and/or CFG resource structure. - -When adding new quirk there are two possibilities: -1. Override default pci_generic_ecam_ops ops but CFG resource comes from MCFG -{ "OEM_ID", "OEM_TABLE_ID", <REV>, <DOMAIN>, <BUS_NR>, &foo_ops, MCFG_RES_EMPTY }, -2. Override default pci_generic_ecam_ops ops and CFG resource. For this case -it is also allowed get CFG resource from quirk entry w/o having it in MCFG. -{ "OEM_ID", "OEM_TABLE_ID", <REV>, <DOMAIN>, <BUS_NR>, &boo_ops, - DEFINE_RES_MEM(START, SIZE) }, - -pci_generic_ecam_ops and MCFG entries will be used for platforms -free from quirks. - -Signed-off-by: Tomasz Nowicki <tn@semihalf.com> -Signed-off-by: Dongdong Liu <liudongdong3@huawei.com> -Signed-off-by: Christopher Covington <cov@codeaurora.org> ---- - drivers/acpi/pci_mcfg.c | 80 +++++++++++++++++++++++++++++++++++++++++++++---- - 1 file changed, 74 insertions(+), 6 deletions(-) - -diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c -index ffcc651..2b8acc7 100644 ---- a/drivers/acpi/pci_mcfg.c -+++ b/drivers/acpi/pci_mcfg.c -@@ -32,6 +32,59 @@ struct mcfg_entry { - u8 bus_start; - u8 bus_end; - }; -+struct mcfg_fixup { -+ char oem_id[ACPI_OEM_ID_SIZE + 1]; -+ char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1]; -+ u32 oem_revision; -+ u16 seg; -+ struct resource bus_range; -+ struct pci_ecam_ops *ops; -+ struct resource cfgres; -+}; -+ -+#define MCFG_DOM_ANY (-1) -+#define MCFG_BUS_RANGE(start, end) DEFINE_RES_NAMED((start), \ -+ ((end) - (start) + 1), \ -+ NULL, IORESOURCE_BUS) -+#define MCFG_BUS_ANY MCFG_BUS_RANGE(0x0, 0xff) -+#define MCFG_RES_EMPTY DEFINE_RES_NAMED(0, 0, NULL, 0) -+ -+static struct mcfg_fixup mcfg_quirks[] = { -+/* { OEM_ID, OEM_TABLE_ID, REV, DOMAIN, BUS_RANGE, cfgres, ops }, */ -+}; -+ -+static char mcfg_oem_id[ACPI_OEM_ID_SIZE]; -+static char mcfg_oem_table_id[ACPI_OEM_TABLE_ID_SIZE]; -+static u32 mcfg_oem_revision; -+ -+static void pci_mcfg_match_quirks(struct acpi_pci_root *root, -+ struct resource *cfgres, -+ struct pci_ecam_ops **ecam_ops) -+{ -+ struct mcfg_fixup *f; -+ int i; -+ -+ /* -+ * First match against PCI topology <domain:bus> then use OEM ID, OEM -+ * table ID, and OEM revision from MCFG table standard header. -+ */ -+ for (i = 0, f = mcfg_quirks; i < ARRAY_SIZE(mcfg_quirks); i++, f++) { -+ if (f->seg == root->segment && -+ resource_contains(&f->bus_range, &root->secondary) && -+ !memcmp(f->oem_id, mcfg_oem_id, ACPI_OEM_ID_SIZE) && -+ !memcmp(f->oem_table_id, mcfg_oem_table_id, -+ ACPI_OEM_TABLE_ID_SIZE) && -+ f->oem_revision == mcfg_oem_revision) { -+ if (f->cfgres.start) -+ *cfgres = f->cfgres; -+ if (f->ops) -+ *ecam_ops = f->ops; -+ dev_info(&root->device->dev, "Applying PCI MCFG quirks for %s %s rev: %d\n", -+ f->oem_id, f->oem_table_id, f->oem_revision); -+ return; -+ } -+ } -+} - - /* List to save MCFG entries */ - static LIST_HEAD(pci_mcfg_list); -@@ -61,14 +114,24 @@ int pci_mcfg_lookup(struct acpi_pci_root *root, struct resource *cfgres, - - } - -- 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; -+ if (root->mcfg_addr) { -+ res.start = root->mcfg_addr + (bus_res->start << 20); -+ res.end = res.start + (resource_size(bus_res) << 20) - 1; -+ res.flags = IORESOURCE_MEM; -+ } -+ -+ /* -+ * Let to override default ECAM ops and CFG resource range. -+ * Also, this might even retrieve CFG resource range in case MCFG -+ * does not have it. Invalid CFG start address means MCFG firmware bug -+ * or we need another quirk in array. -+ */ -+ pci_mcfg_match_quirks(root, &res, &ops); -+ if (!res.start) -+ return -ENXIO; -+ - *cfgres = res; - *ecam_ops = ops; - return 0; -@@ -101,6 +164,11 @@ static __init int pci_mcfg_parse(struct acpi_table_header *header) - list_add(&e->list, &pci_mcfg_list); - } - -+ /* Save MCFG IDs and revision for quirks matching */ -+ memcpy(mcfg_oem_id, header->oem_id, ACPI_OEM_ID_SIZE); -+ memcpy(mcfg_oem_table_id, header->oem_table_id, ACPI_OEM_TABLE_ID_SIZE); -+ mcfg_oem_revision = header->revision; -+ - pr_info("MCFG table detected, %d entries\n", n); - return 0; - } --- -2.9.3 - -From 2243ab64c12a873e47b72c8e636b40ed09c5f0d4 Mon Sep 17 00:00:00 2001 -From: Tomasz Nowicki <tn@semihalf.com> -Date: Fri, 9 Sep 2016 21:24:05 +0200 -Subject: [PATCH 3/6] PCI: thunder-pem: Allow to probe PEM-specific register - range for ACPI case - -thunder-pem driver stands for being ACPI based PCI host controller. -However, there is no standard way to describe its PEM-specific register -ranges in ACPI tables. Thus we add thunder_pem_init() ACPI extension -to obtain hardcoded addresses from static resource array. -Although it is not pretty, it prevents from creating standard mechanism to -handle similar cases in future. - -Signed-off-by: Tomasz Nowicki <tn@semihalf.com> ---- - drivers/pci/host/pci-thunder-pem.c | 61 ++++++++++++++++++++++++++++++-------- - 1 file changed, 48 insertions(+), 13 deletions(-) - -diff --git a/drivers/pci/host/pci-thunder-pem.c b/drivers/pci/host/pci-thunder-pem.c -index 6abaf80..b048761 100644 ---- a/drivers/pci/host/pci-thunder-pem.c -+++ b/drivers/pci/host/pci-thunder-pem.c -@@ -18,6 +18,7 @@ - #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> - -@@ -284,6 +285,40 @@ static int thunder_pem_config_write(struct pci_bus *bus, unsigned int devfn, - return pci_generic_config_write(bus, devfn, where, size, val); - } - -+#ifdef CONFIG_ACPI -+static struct resource thunder_pem_reg_res[] = { -+ [4] = DEFINE_RES_MEM(0x87e0c0000000UL, SZ_16M), -+ [5] = DEFINE_RES_MEM(0x87e0c1000000UL, SZ_16M), -+ [6] = DEFINE_RES_MEM(0x87e0c2000000UL, SZ_16M), -+ [7] = DEFINE_RES_MEM(0x87e0c3000000UL, SZ_16M), -+ [8] = DEFINE_RES_MEM(0x87e0c4000000UL, SZ_16M), -+ [9] = DEFINE_RES_MEM(0x87e0c5000000UL, SZ_16M), -+ [14] = DEFINE_RES_MEM(0x97e0c0000000UL, SZ_16M), -+ [15] = DEFINE_RES_MEM(0x97e0c1000000UL, SZ_16M), -+ [16] = DEFINE_RES_MEM(0x97e0c2000000UL, SZ_16M), -+ [17] = DEFINE_RES_MEM(0x97e0c3000000UL, SZ_16M), -+ [18] = DEFINE_RES_MEM(0x97e0c4000000UL, SZ_16M), -+ [19] = DEFINE_RES_MEM(0x97e0c5000000UL, SZ_16M), -+}; -+ -+static struct resource *thunder_pem_acpi_res(struct pci_config_window *cfg) -+{ -+ struct acpi_device *adev = to_acpi_device(cfg->parent); -+ struct acpi_pci_root *root = acpi_driver_data(adev); -+ -+ if ((root->segment >= 4 && root->segment <= 9) || -+ (root->segment >= 14 && root->segment <= 19)) -+ return &thunder_pem_reg_res[root->segment]; -+ -+ return NULL; -+} -+#else -+static struct resource *thunder_pem_acpi_res(struct pci_config_window *cfg) -+{ -+ return NULL; -+} -+#endif -+ - static int thunder_pem_init(struct pci_config_window *cfg) - { - struct device *dev = cfg->parent; -@@ -292,24 +327,24 @@ static int thunder_pem_init(struct pci_config_window *cfg) - struct thunder_pem_pci *pem_pci; - struct platform_device *pdev; - -- /* Only OF support for now */ -- if (!dev->of_node) -- return -EINVAL; -- - pem_pci = devm_kzalloc(dev, sizeof(*pem_pci), GFP_KERNEL); - if (!pem_pci) - return -ENOMEM; - -- pdev = to_platform_device(dev); -- -- /* -- * The second register range is the PEM bridge to the PCIe -- * bus. It has a different config access method than those -- * devices behind the bridge. -- */ -- res_pem = platform_get_resource(pdev, IORESOURCE_MEM, 1); -+ if (acpi_disabled) { -+ pdev = to_platform_device(dev); -+ -+ /* -+ * The second register range is the PEM bridge to the PCIe -+ * bus. It has a different config access method than those -+ * devices behind the bridge. -+ */ -+ res_pem = platform_get_resource(pdev, IORESOURCE_MEM, 1); -+ } else { -+ res_pem = thunder_pem_acpi_res(cfg); -+ } - if (!res_pem) { -- dev_err(dev, "missing \"reg[1]\"property\n"); -+ dev_err(dev, "missing configuration region\n"); - return -EINVAL; - } - --- -2.9.3 - -From 443d85d47ee00b3f0b6f39d470a11e7eb116817d Mon Sep 17 00:00:00 2001 -From: Tomasz Nowicki <tn@semihalf.com> -Date: Fri, 9 Sep 2016 21:24:06 +0200 -Subject: [PATCH 4/6] PCI: thunder: Enable ACPI PCI controller for ThunderX - pass2.x silicon version - -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 pci_thunder_pem_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. Export PEM pci_thunder_pem_ops structure so it is visible to MCFG quirk - code. -2. New quirk entries for each PEM segment. Each contains platform IDs, - mentioned pci_thunder_pem_ops and CFG resources. - -Quirk is considered for ThunderX silicon pass2.x only which is identified -via MCFG revision 1. - -Signed-off-by: Tomasz Nowicki <tn@semihalf.com> ---- - drivers/acpi/pci_mcfg.c | 27 +++++++++++++++++++++++++++ - drivers/pci/host/pci-thunder-pem.c | 2 +- - include/linux/pci-ecam.h | 4 ++++ - 3 files changed, 32 insertions(+), 1 deletion(-) - -diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c -index 2b8acc7..1f73d7b 100644 ---- a/drivers/acpi/pci_mcfg.c -+++ b/drivers/acpi/pci_mcfg.c -@@ -51,6 +51,33 @@ struct mcfg_fixup { - - static struct mcfg_fixup mcfg_quirks[] = { - /* { OEM_ID, OEM_TABLE_ID, REV, DOMAIN, BUS_RANGE, cfgres, ops }, */ -+#ifdef CONFIG_PCI_HOST_THUNDER_PEM -+ /* SoC pass2.x */ -+ { "CAVIUM", "THUNDERX", 1, 4, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x88001f000000UL, 0x39 * SZ_16M) }, -+ { "CAVIUM", "THUNDERX", 1, 5, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x884057000000UL, 0x39 * SZ_16M) }, -+ { "CAVIUM", "THUNDERX", 1, 6, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x88808f000000UL, 0x39 * SZ_16M) }, -+ { "CAVIUM", "THUNDERX", 1, 7, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x89001f000000UL, 0x39 * SZ_16M) }, -+ { "CAVIUM", "THUNDERX", 1, 8, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x894057000000UL, 0x39 * SZ_16M) }, -+ { "CAVIUM", "THUNDERX", 1, 9, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x89808f000000UL, 0x39 * SZ_16M) }, -+ { "CAVIUM", "THUNDERX", 1, 14, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x98001f000000UL, 0x39 * SZ_16M) }, -+ { "CAVIUM", "THUNDERX", 1, 15, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x984057000000UL, 0x39 * SZ_16M) }, -+ { "CAVIUM", "THUNDERX", 1, 16, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x98808f000000UL, 0x39 * SZ_16M) }, -+ { "CAVIUM", "THUNDERX", 1, 17, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x99001f000000UL, 0x39 * SZ_16M) }, -+ { "CAVIUM", "THUNDERX", 1, 18, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x994057000000UL, 0x39 * SZ_16M) }, -+ { "CAVIUM", "THUNDERX", 1, 19, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x99808f000000UL, 0x39 * SZ_16M) }, -+#endif - }; - - static char mcfg_oem_id[ACPI_OEM_ID_SIZE]; -diff --git a/drivers/pci/host/pci-thunder-pem.c b/drivers/pci/host/pci-thunder-pem.c -index b048761..d7c10cc 100644 ---- a/drivers/pci/host/pci-thunder-pem.c -+++ b/drivers/pci/host/pci-thunder-pem.c -@@ -367,7 +367,7 @@ static int thunder_pem_init(struct pci_config_window *cfg) - return 0; - } - --static struct pci_ecam_ops pci_thunder_pem_ops = { -+struct pci_ecam_ops pci_thunder_pem_ops = { - .bus_shift = 24, - .init = thunder_pem_init, - .pci_ops = { -diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h -index 7adad20..65505ea 100644 ---- a/include/linux/pci-ecam.h -+++ b/include/linux/pci-ecam.h -@@ -58,6 +58,10 @@ void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn, - int where); - /* default ECAM ops */ - extern struct pci_ecam_ops pci_generic_ecam_ops; -+/* ECAM ops for known quirks */ -+#ifdef CONFIG_PCI_HOST_THUNDER_PEM -+extern struct pci_ecam_ops pci_thunder_pem_ops; -+#endif - - #ifdef CONFIG_PCI_HOST_GENERIC - /* for DT-based PCI controllers that support ECAM */ --- -2.9.3 - -From 6eca99cc392a11bb07b9ef88bca71a85f8bbe273 Mon Sep 17 00:00:00 2001 -From: Tomasz Nowicki <tn@semihalf.com> -Date: Fri, 9 Sep 2016 21:24:07 +0200 -Subject: [PATCH 5/6] PCI: thunder: Enable ACPI PCI controller for ThunderX - pass1.x silicon version - -ThunderX pass1.x requires to emulate the EA headers for on-chip devices -hence it has to use custom pci_thunder_ecam_ops for accessing PCI config -space (pci-thuner-ecam.c). Add new entries to MCFG quirk array where they -can be applied while probing ACPI based PCI host controller. - -ThunderX pass1.x is using the same way for accessing off-chip devices -(so-called PEM) as silicon pass-2.x so we need to add PEM quirk -entries too. - -Quirk is considered for ThunderX silicon pass1.x only which is identified -via MCFG revision 2. - -Signed-off-by: Tomasz Nowicki <tn@semihalf.com> ---- - drivers/acpi/pci_mcfg.c | 45 +++++++++++++++++++++++++++++++++++++ - drivers/pci/host/pci-thunder-ecam.c | 2 +- - include/linux/pci-ecam.h | 3 +++ - 3 files changed, 49 insertions(+), 1 deletion(-) - -diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c -index 1f73d7b..eb14f74 100644 ---- a/drivers/acpi/pci_mcfg.c -+++ b/drivers/acpi/pci_mcfg.c -@@ -77,6 +77,51 @@ static struct mcfg_fixup mcfg_quirks[] = { - DEFINE_RES_MEM(0x994057000000UL, 0x39 * SZ_16M) }, - { "CAVIUM", "THUNDERX", 1, 19, MCFG_BUS_ANY, &pci_thunder_pem_ops, - DEFINE_RES_MEM(0x99808f000000UL, 0x39 * SZ_16M) }, -+ -+ /* SoC pass1.x */ -+ { "CAVIUM", "THUNDERX", 2, 4, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x88001f000000UL, 0x39 * SZ_16M) }, -+ { "CAVIUM", "THUNDERX", 2, 5, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x884057000000UL, 0x39 * SZ_16M) }, -+ { "CAVIUM", "THUNDERX", 2, 6, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x88808f000000UL, 0x39 * SZ_16M) }, -+ { "CAVIUM", "THUNDERX", 2, 7, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x89001f000000UL, 0x39 * SZ_16M) }, -+ { "CAVIUM", "THUNDERX", 2, 8, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x894057000000UL, 0x39 * SZ_16M) }, -+ { "CAVIUM", "THUNDERX", 2, 9, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x89808f000000UL, 0x39 * SZ_16M) }, -+ { "CAVIUM", "THUNDERX", 2, 14, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x98001f000000UL, 0x39 * SZ_16M) }, -+ { "CAVIUM", "THUNDERX", 2, 15, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x984057000000UL, 0x39 * SZ_16M) }, -+ { "CAVIUM", "THUNDERX", 2, 16, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x98808f000000UL, 0x39 * SZ_16M) }, -+ { "CAVIUM", "THUNDERX", 2, 17, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x99001f000000UL, 0x39 * SZ_16M) }, -+ { "CAVIUM", "THUNDERX", 2, 18, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x994057000000UL, 0x39 * SZ_16M) }, -+ { "CAVIUM", "THUNDERX", 2, 19, MCFG_BUS_ANY, &pci_thunder_pem_ops, -+ DEFINE_RES_MEM(0x99808f000000UL, 0x39 * SZ_16M) }, -+#endif -+#ifdef CONFIG_PCI_HOST_THUNDER_ECAM -+ /* SoC pass1.x */ -+ { "CAVIUM", "THUNDERX", 2, 0, MCFG_BUS_ANY, &pci_thunder_ecam_ops, -+ MCFG_RES_EMPTY}, -+ { "CAVIUM", "THUNDERX", 2, 1, MCFG_BUS_ANY, &pci_thunder_ecam_ops, -+ MCFG_RES_EMPTY}, -+ { "CAVIUM", "THUNDERX", 2, 2, MCFG_BUS_ANY, &pci_thunder_ecam_ops, -+ MCFG_RES_EMPTY}, -+ { "CAVIUM", "THUNDERX", 2, 3, MCFG_BUS_ANY, &pci_thunder_ecam_ops, -+ MCFG_RES_EMPTY}, -+ { "CAVIUM", "THUNDERX", 2, 10, MCFG_BUS_ANY, &pci_thunder_ecam_ops, -+ MCFG_RES_EMPTY}, -+ { "CAVIUM", "THUNDERX", 2, 11, MCFG_BUS_ANY, &pci_thunder_ecam_ops, -+ MCFG_RES_EMPTY}, -+ { "CAVIUM", "THUNDERX", 2, 12, MCFG_BUS_ANY, &pci_thunder_ecam_ops, -+ MCFG_RES_EMPTY}, -+ { "CAVIUM", "THUNDERX", 2, 13, MCFG_BUS_ANY, &pci_thunder_ecam_ops, -+ MCFG_RES_EMPTY}, - #endif - }; - -diff --git a/drivers/pci/host/pci-thunder-ecam.c b/drivers/pci/host/pci-thunder-ecam.c -index d50a3dc..b6c17e2 100644 ---- a/drivers/pci/host/pci-thunder-ecam.c -+++ b/drivers/pci/host/pci-thunder-ecam.c -@@ -346,7 +346,7 @@ static int thunder_ecam_config_write(struct pci_bus *bus, unsigned int devfn, - return pci_generic_config_write(bus, devfn, where, size, val); - } - --static struct pci_ecam_ops pci_thunder_ecam_ops = { -+struct pci_ecam_ops pci_thunder_ecam_ops = { - .bus_shift = 20, - .pci_ops = { - .map_bus = pci_ecam_map_bus, -diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h -index 65505ea..35f0e81 100644 ---- a/include/linux/pci-ecam.h -+++ b/include/linux/pci-ecam.h -@@ -62,6 +62,9 @@ extern struct pci_ecam_ops pci_generic_ecam_ops; - #ifdef CONFIG_PCI_HOST_THUNDER_PEM - extern struct pci_ecam_ops pci_thunder_pem_ops; - #endif -+#ifdef CONFIG_PCI_HOST_THUNDER_ECAM -+extern struct pci_ecam_ops pci_thunder_ecam_ops; -+#endif - - #ifdef CONFIG_PCI_HOST_GENERIC - /* for DT-based PCI controllers that support ECAM */ --- -2.9.3 - -From 3080ac5bb527155ccdf8490ce221b1c6ad01f502 Mon Sep 17 00:00:00 2001 -From: Duc Dang <dhdang@apm.com> -Date: Sat, 17 Sep 2016 07:24:38 -0700 -Subject: [PATCH 6/6] PCI/ACPI: xgene: Add ECAM quirk for X-Gene PCIe - controller - -PCIe controller in X-Gene SoCs is not ECAM compliant: software -needs to configure additional concontroller register to address -device at bus:dev:function. - -This patch depends on "ECAM quirks handling for ARM64 platforms" -series (http://www.spinics.net/lists/arm-kernel/msg530692.html) -to address the limitation above for X-Gene PCIe controller. - -The quirk will only be applied for X-Gene PCIe MCFG table with -OEM revison 1, 2, 3 or 4 (PCIe controller v1 and v2 on X-Gene SoCs). - -Signed-off-by: Duc Dang <dhdang@apm.com> ---- - drivers/acpi/pci_mcfg.c | 32 +++++ - drivers/pci/host/Makefile | 2 +- - drivers/pci/host/pci-xgene-ecam.c | 280 ++++++++++++++++++++++++++++++++++++++ - include/linux/pci-ecam.h | 5 + - 4 files changed, 318 insertions(+), 1 deletion(-) - create mode 100644 drivers/pci/host/pci-xgene-ecam.c - -diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c -index eb14f74..635ab24 100644 ---- a/drivers/acpi/pci_mcfg.c -+++ b/drivers/acpi/pci_mcfg.c -@@ -123,6 +123,38 @@ static struct mcfg_fixup mcfg_quirks[] = { - { "CAVIUM", "THUNDERX", 2, 13, MCFG_BUS_ANY, &pci_thunder_ecam_ops, - MCFG_RES_EMPTY}, - #endif -+#ifdef CONFIG_PCI_XGENE -+ {"APM ", "XGENE ", 1, 0, MCFG_BUS_ANY, -+ &xgene_v1_pcie_ecam_ops, MCFG_RES_EMPTY}, -+ {"APM ", "XGENE ", 1, 1, MCFG_BUS_ANY, -+ &xgene_v1_pcie_ecam_ops, MCFG_RES_EMPTY}, -+ {"APM ", "XGENE ", 1, 2, MCFG_BUS_ANY, -+ &xgene_v1_pcie_ecam_ops, MCFG_RES_EMPTY}, -+ {"APM ", "XGENE ", 1, 3, MCFG_BUS_ANY, -+ &xgene_v1_pcie_ecam_ops, MCFG_RES_EMPTY}, -+ {"APM ", "XGENE ", 1, 4, MCFG_BUS_ANY, -+ &xgene_v1_pcie_ecam_ops, MCFG_RES_EMPTY}, -+ {"APM ", "XGENE ", 2, 0, MCFG_BUS_ANY, -+ &xgene_v1_pcie_ecam_ops, MCFG_RES_EMPTY}, -+ {"APM ", "XGENE ", 2, 1, MCFG_BUS_ANY, -+ &xgene_v1_pcie_ecam_ops, MCFG_RES_EMPTY}, -+ {"APM ", "XGENE ", 2, 2, MCFG_BUS_ANY, -+ &xgene_v1_pcie_ecam_ops, MCFG_RES_EMPTY}, -+ {"APM ", "XGENE ", 2, 3, MCFG_BUS_ANY, -+ &xgene_v1_pcie_ecam_ops, MCFG_RES_EMPTY}, -+ {"APM ", "XGENE ", 2, 4, MCFG_BUS_ANY, -+ &xgene_v1_pcie_ecam_ops, MCFG_RES_EMPTY}, -+ {"APM ", "XGENE ", 3, 0, MCFG_BUS_ANY, -+ &xgene_v2_1_pcie_ecam_ops, MCFG_RES_EMPTY}, -+ {"APM ", "XGENE ", 3, 1, MCFG_BUS_ANY, -+ &xgene_v2_1_pcie_ecam_ops, MCFG_RES_EMPTY}, -+ {"APM ", "XGENE ", 4, 0, MCFG_BUS_ANY, -+ &xgene_v2_2_pcie_ecam_ops, MCFG_RES_EMPTY}, -+ {"APM ", "XGENE ", 4, 1, MCFG_BUS_ANY, -+ &xgene_v2_2_pcie_ecam_ops, MCFG_RES_EMPTY}, -+ {"APM ", "XGENE ", 4, 2, MCFG_BUS_ANY, -+ &xgene_v2_2_pcie_ecam_ops, MCFG_RES_EMPTY}, -+#endif - }; - - static char mcfg_oem_id[ACPI_OEM_ID_SIZE]; -diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile -index 8843410..af4f505 100644 ---- a/drivers/pci/host/Makefile -+++ b/drivers/pci/host/Makefile -@@ -15,7 +15,7 @@ obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o - obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o - obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o - obj-$(CONFIG_PCIE_XILINX_NWL) += pcie-xilinx-nwl.o --obj-$(CONFIG_PCI_XGENE) += pci-xgene.o -+obj-$(CONFIG_PCI_XGENE) += pci-xgene.o pci-xgene-ecam.o - obj-$(CONFIG_PCI_XGENE_MSI) += pci-xgene-msi.o - obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o - obj-$(CONFIG_PCI_VERSATILE) += pci-versatile.o -diff --git a/drivers/pci/host/pci-xgene-ecam.c b/drivers/pci/host/pci-xgene-ecam.c -new file mode 100644 -index 0000000..b66a04f ---- /dev/null -+++ b/drivers/pci/host/pci-xgene-ecam.c -@@ -0,0 +1,280 @@ -+/* -+ * APM X-Gene PCIe ECAM fixup driver -+ * -+ * Copyright (c) 2016, Applied Micro Circuits Corporation -+ * Author: -+ * Duc Dang <dhdang@apm.com> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program. If not, see <http://www.gnu.org/licenses/>. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/of_address.h> -+#include <linux/of_pci.h> -+#include <linux/pci-acpi.h> -+#include <linux/platform_device.h> -+#include <linux/pci-ecam.h> -+ -+#ifdef CONFIG_ACPI -+#define RTDID 0x160 -+#define ROOT_CAP_AND_CTRL 0x5C -+ -+/* PCIe IP version */ -+#define XGENE_PCIE_IP_VER_UNKN 0 -+#define XGENE_PCIE_IP_VER_1 1 -+#define XGENE_PCIE_IP_VER_2 2 -+ -+#define XGENE_CSR_LENGTH 0x10000 -+ -+struct xgene_pcie_acpi_root { -+ void __iomem *csr_base; -+ u32 version; -+}; -+ -+static int xgene_v1_pcie_ecam_init(struct pci_config_window *cfg) -+{ -+ struct xgene_pcie_acpi_root *xgene_root; -+ struct device *dev = cfg->parent; -+ u32 csr_base; -+ -+ xgene_root = devm_kzalloc(dev, sizeof(*xgene_root), GFP_KERNEL); -+ if (!xgene_root) -+ return -ENOMEM; -+ -+ switch (cfg->res.start) { -+ case 0xE0D0000000ULL: -+ csr_base = 0x1F2B0000; -+ break; -+ case 0xD0D0000000ULL: -+ csr_base = 0x1F2C0000; -+ break; -+ case 0x90D0000000ULL: -+ csr_base = 0x1F2D0000; -+ break; -+ case 0xA0D0000000ULL: -+ csr_base = 0x1F500000; -+ break; -+ case 0xC0D0000000ULL: -+ csr_base = 0x1F510000; -+ break; -+ default: -+ return -ENODEV; -+ } -+ -+ xgene_root->csr_base = ioremap(csr_base, XGENE_CSR_LENGTH); -+ if (!xgene_root->csr_base) { -+ kfree(xgene_root); -+ return -ENODEV; -+ } -+ -+ xgene_root->version = XGENE_PCIE_IP_VER_1; -+ -+ cfg->priv = xgene_root; -+ -+ return 0; -+} -+ -+static int xgene_v2_1_pcie_ecam_init(struct pci_config_window *cfg) -+{ -+ struct xgene_pcie_acpi_root *xgene_root; -+ struct device *dev = cfg->parent; -+ resource_size_t csr_base; -+ -+ xgene_root = devm_kzalloc(dev, sizeof(*xgene_root), GFP_KERNEL); -+ if (!xgene_root) -+ return -ENOMEM; -+ -+ switch (cfg->res.start) { -+ case 0xC0D0000000ULL: -+ csr_base = 0x1F2B0000; -+ break; -+ case 0xA0D0000000ULL: -+ csr_base = 0x1F2C0000; -+ break; -+ default: -+ return -ENODEV; -+ } -+ -+ xgene_root->csr_base = ioremap(csr_base, XGENE_CSR_LENGTH); -+ if (!xgene_root->csr_base) { -+ kfree(xgene_root); -+ return -ENODEV; -+ } -+ -+ xgene_root->version = XGENE_PCIE_IP_VER_2; -+ -+ cfg->priv = xgene_root; -+ -+ return 0; -+} -+ -+static int xgene_v2_2_pcie_ecam_init(struct pci_config_window *cfg) -+{ -+ struct xgene_pcie_acpi_root *xgene_root; -+ struct device *dev = cfg->parent; -+ resource_size_t csr_base; -+ -+ xgene_root = devm_kzalloc(dev, sizeof(*xgene_root), GFP_KERNEL); -+ if (!xgene_root) -+ return -ENOMEM; -+ -+ switch (cfg->res.start) { -+ case 0xE0D0000000ULL: -+ csr_base = 0x1F2B0000; -+ break; -+ case 0xA0D0000000ULL: -+ csr_base = 0x1F500000; -+ break; -+ case 0x90D0000000ULL: -+ csr_base = 0x1F2D0000; -+ break; -+ default: -+ return -ENODEV; -+ } -+ -+ xgene_root->csr_base = ioremap(csr_base, XGENE_CSR_LENGTH); -+ if (!xgene_root->csr_base) { -+ kfree(xgene_root); -+ return -ENODEV; -+ } -+ -+ xgene_root->version = XGENE_PCIE_IP_VER_2; -+ -+ cfg->priv = xgene_root; -+ -+ return 0; -+} -+/* -+ * For Configuration request, RTDID register is used as Bus Number, -+ * Device Number and Function number of the header fields. -+ */ -+static void xgene_pcie_set_rtdid_reg(struct pci_bus *bus, uint devfn) -+{ -+ struct pci_config_window *cfg = bus->sysdata; -+ struct xgene_pcie_acpi_root *port = cfg->priv; -+ unsigned int b, d, f; -+ u32 rtdid_val = 0; -+ -+ b = bus->number; -+ d = PCI_SLOT(devfn); -+ f = PCI_FUNC(devfn); -+ -+ if (!pci_is_root_bus(bus)) -+ rtdid_val = (b << 8) | (d << 3) | f; -+ -+ writel(rtdid_val, port->csr_base + RTDID); -+ /* read the register back to ensure flush */ -+ readl(port->csr_base + RTDID); -+} -+ -+/* -+ * X-Gene PCIe port uses BAR0-BAR1 of RC's configuration space as -+ * the translation from PCI bus to native BUS. Entire DDR region -+ * is mapped into PCIe space using these registers, so it can be -+ * reached by DMA from EP devices. The BAR0/1 of bridge should be -+ * hidden during enumeration to avoid the sizing and resource allocation -+ * by PCIe core. -+ */ -+static bool xgene_pcie_hide_rc_bars(struct pci_bus *bus, int offset) -+{ -+ if (pci_is_root_bus(bus) && ((offset == PCI_BASE_ADDRESS_0) || -+ (offset == PCI_BASE_ADDRESS_1))) -+ return true; -+ -+ return false; -+} -+ -+void __iomem *xgene_pcie_ecam_map_bus(struct pci_bus *bus, -+ unsigned int devfn, int where) -+{ -+ struct pci_config_window *cfg = bus->sysdata; -+ unsigned int busn = bus->number; -+ void __iomem *base; -+ -+ if (busn < cfg->busr.start || busn > cfg->busr.end) -+ return NULL; -+ -+ if ((pci_is_root_bus(bus) && devfn != 0) || -+ xgene_pcie_hide_rc_bars(bus, where)) -+ return NULL; -+ -+ xgene_pcie_set_rtdid_reg(bus, devfn); -+ -+ if (busn > cfg->busr.start) -+ base = cfg->win + (1 << cfg->ops->bus_shift); -+ else -+ base = cfg->win; -+ -+ return base + where; -+} -+ -+static int xgene_pcie_config_read32(struct pci_bus *bus, unsigned int devfn, -+ int where, int size, u32 *val) -+{ -+ struct pci_config_window *cfg = bus->sysdata; -+ struct xgene_pcie_acpi_root *port = cfg->priv; -+ -+ if (pci_generic_config_read32(bus, devfn, where & ~0x3, 4, val) != -+ PCIBIOS_SUCCESSFUL) -+ return PCIBIOS_DEVICE_NOT_FOUND; -+ -+ /* -+ * The v1 controller has a bug in its Configuration Request -+ * Retry Status (CRS) logic: when CRS is enabled and we read the -+ * Vendor and Device ID of a non-existent device, the controller -+ * fabricates return data of 0xFFFF0001 ("device exists but is not -+ * ready") instead of 0xFFFFFFFF ("device does not exist"). This -+ * causes the PCI core to retry the read until it times out. -+ * Avoid this by not claiming to support CRS. -+ */ -+ if (pci_is_root_bus(bus) && (port->version == XGENE_PCIE_IP_VER_1) && -+ ((where & ~0x3) == ROOT_CAP_AND_CTRL)) -+ *val &= ~(PCI_EXP_RTCAP_CRSVIS << 16); -+ -+ if (size <= 2) -+ *val = (*val >> (8 * (where & 3))) & ((1 << (size * 8)) - 1); -+ -+ return PCIBIOS_SUCCESSFUL; -+} -+ -+struct pci_ecam_ops xgene_v1_pcie_ecam_ops = { -+ .bus_shift = 16, -+ .init = xgene_v1_pcie_ecam_init, -+ .pci_ops = { -+ .map_bus = xgene_pcie_ecam_map_bus, -+ .read = xgene_pcie_config_read32, -+ .write = pci_generic_config_write, -+ } -+}; -+ -+struct pci_ecam_ops xgene_v2_1_pcie_ecam_ops = { -+ .bus_shift = 16, -+ .init = xgene_v2_1_pcie_ecam_init, -+ .pci_ops = { -+ .map_bus = xgene_pcie_ecam_map_bus, -+ .read = xgene_pcie_config_read32, -+ .write = pci_generic_config_write, -+ } -+}; -+ -+struct pci_ecam_ops xgene_v2_2_pcie_ecam_ops = { -+ .bus_shift = 16, -+ .init = xgene_v2_2_pcie_ecam_init, -+ .pci_ops = { -+ .map_bus = xgene_pcie_ecam_map_bus, -+ .read = xgene_pcie_config_read32, -+ .write = pci_generic_config_write, -+ } -+}; -+#endif -diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h -index 35f0e81..40da3e7 100644 ---- a/include/linux/pci-ecam.h -+++ b/include/linux/pci-ecam.h -@@ -65,6 +65,11 @@ extern struct pci_ecam_ops pci_thunder_pem_ops; - #ifdef CONFIG_PCI_HOST_THUNDER_ECAM - extern struct pci_ecam_ops pci_thunder_ecam_ops; - #endif -+#ifdef CONFIG_PCI_XGENE -+extern struct pci_ecam_ops xgene_v1_pcie_ecam_ops; -+extern struct pci_ecam_ops xgene_v2_1_pcie_ecam_ops; -+extern struct pci_ecam_ops xgene_v2_2_pcie_ecam_ops; -+#endif - - #ifdef CONFIG_PCI_HOST_GENERIC - /* for DT-based PCI controllers that support ECAM */ --- -2.9.3 - |