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