0001
0002
0003
0004
0005
0006
0007
0008
0009 #define pr_fmt(fmt) "ACPI: " fmt
0010
0011 #include <linux/kernel.h>
0012 #include <linux/pci.h>
0013 #include <linux/pci-acpi.h>
0014 #include <linux/pci-ecam.h>
0015
0016
0017 struct mcfg_entry {
0018 struct list_head list;
0019 phys_addr_t addr;
0020 u16 segment;
0021 u8 bus_start;
0022 u8 bus_end;
0023 };
0024
0025 #ifdef CONFIG_PCI_QUIRKS
0026 struct mcfg_fixup {
0027 char oem_id[ACPI_OEM_ID_SIZE + 1];
0028 char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1];
0029 u32 oem_revision;
0030 u16 segment;
0031 struct resource bus_range;
0032 const struct pci_ecam_ops *ops;
0033 struct resource cfgres;
0034 };
0035
0036 #define MCFG_BUS_RANGE(start, end) DEFINE_RES_NAMED((start), \
0037 ((end) - (start) + 1), \
0038 NULL, IORESOURCE_BUS)
0039 #define MCFG_BUS_ANY MCFG_BUS_RANGE(0x0, 0xff)
0040
0041 static struct mcfg_fixup mcfg_quirks[] = {
0042
0043
0044 #ifdef CONFIG_ARM64
0045
0046 #define AL_ECAM(table_id, rev, seg, ops) \
0047 { "AMAZON", table_id, rev, seg, MCFG_BUS_ANY, ops }
0048
0049 AL_ECAM("GRAVITON", 0, 0, &al_pcie_ops),
0050 AL_ECAM("GRAVITON", 0, 1, &al_pcie_ops),
0051 AL_ECAM("GRAVITON", 0, 2, &al_pcie_ops),
0052 AL_ECAM("GRAVITON", 0, 3, &al_pcie_ops),
0053 AL_ECAM("GRAVITON", 0, 4, &al_pcie_ops),
0054 AL_ECAM("GRAVITON", 0, 5, &al_pcie_ops),
0055 AL_ECAM("GRAVITON", 0, 6, &al_pcie_ops),
0056 AL_ECAM("GRAVITON", 0, 7, &al_pcie_ops),
0057
0058 #define QCOM_ECAM32(seg) \
0059 { "QCOM ", "QDF2432 ", 1, seg, MCFG_BUS_ANY, &pci_32b_ops }
0060
0061 QCOM_ECAM32(0),
0062 QCOM_ECAM32(1),
0063 QCOM_ECAM32(2),
0064 QCOM_ECAM32(3),
0065 QCOM_ECAM32(4),
0066 QCOM_ECAM32(5),
0067 QCOM_ECAM32(6),
0068 QCOM_ECAM32(7),
0069
0070 #define HISI_QUAD_DOM(table_id, seg, ops) \
0071 { "HISI ", table_id, 0, (seg) + 0, MCFG_BUS_ANY, ops }, \
0072 { "HISI ", table_id, 0, (seg) + 1, MCFG_BUS_ANY, ops }, \
0073 { "HISI ", table_id, 0, (seg) + 2, MCFG_BUS_ANY, ops }, \
0074 { "HISI ", table_id, 0, (seg) + 3, MCFG_BUS_ANY, ops }
0075
0076 HISI_QUAD_DOM("HIP05 ", 0, &hisi_pcie_ops),
0077 HISI_QUAD_DOM("HIP06 ", 0, &hisi_pcie_ops),
0078 HISI_QUAD_DOM("HIP07 ", 0, &hisi_pcie_ops),
0079 HISI_QUAD_DOM("HIP07 ", 4, &hisi_pcie_ops),
0080 HISI_QUAD_DOM("HIP07 ", 8, &hisi_pcie_ops),
0081 HISI_QUAD_DOM("HIP07 ", 12, &hisi_pcie_ops),
0082
0083 #define THUNDER_PEM_RES(addr, node) \
0084 DEFINE_RES_MEM((addr) + ((u64) (node) << 44), 0x39 * SZ_16M)
0085
0086 #define THUNDER_PEM_QUIRK(rev, node) \
0087 { "CAVIUM", "THUNDERX", rev, 4 + (10 * (node)), MCFG_BUS_ANY, \
0088 &thunder_pem_ecam_ops, THUNDER_PEM_RES(0x88001f000000UL, node) }, \
0089 { "CAVIUM", "THUNDERX", rev, 5 + (10 * (node)), MCFG_BUS_ANY, \
0090 &thunder_pem_ecam_ops, THUNDER_PEM_RES(0x884057000000UL, node) }, \
0091 { "CAVIUM", "THUNDERX", rev, 6 + (10 * (node)), MCFG_BUS_ANY, \
0092 &thunder_pem_ecam_ops, THUNDER_PEM_RES(0x88808f000000UL, node) }, \
0093 { "CAVIUM", "THUNDERX", rev, 7 + (10 * (node)), MCFG_BUS_ANY, \
0094 &thunder_pem_ecam_ops, THUNDER_PEM_RES(0x89001f000000UL, node) }, \
0095 { "CAVIUM", "THUNDERX", rev, 8 + (10 * (node)), MCFG_BUS_ANY, \
0096 &thunder_pem_ecam_ops, THUNDER_PEM_RES(0x894057000000UL, node) }, \
0097 { "CAVIUM", "THUNDERX", rev, 9 + (10 * (node)), MCFG_BUS_ANY, \
0098 &thunder_pem_ecam_ops, THUNDER_PEM_RES(0x89808f000000UL, node) }
0099
0100 #define THUNDER_ECAM_QUIRK(rev, seg) \
0101 { "CAVIUM", "THUNDERX", rev, seg, MCFG_BUS_ANY, \
0102 &pci_thunder_ecam_ops }
0103
0104
0105 THUNDER_PEM_QUIRK(1, 0),
0106 THUNDER_PEM_QUIRK(1, 1),
0107 THUNDER_ECAM_QUIRK(1, 10),
0108
0109
0110 THUNDER_PEM_QUIRK(2, 0),
0111 THUNDER_PEM_QUIRK(2, 1),
0112 THUNDER_ECAM_QUIRK(2, 0),
0113 THUNDER_ECAM_QUIRK(2, 1),
0114 THUNDER_ECAM_QUIRK(2, 2),
0115 THUNDER_ECAM_QUIRK(2, 3),
0116 THUNDER_ECAM_QUIRK(2, 10),
0117 THUNDER_ECAM_QUIRK(2, 11),
0118 THUNDER_ECAM_QUIRK(2, 12),
0119 THUNDER_ECAM_QUIRK(2, 13),
0120
0121 { "NVIDIA", "TEGRA194", 1, 0, MCFG_BUS_ANY, &tegra194_pcie_ops},
0122 { "NVIDIA", "TEGRA194", 1, 1, MCFG_BUS_ANY, &tegra194_pcie_ops},
0123 { "NVIDIA", "TEGRA194", 1, 2, MCFG_BUS_ANY, &tegra194_pcie_ops},
0124 { "NVIDIA", "TEGRA194", 1, 3, MCFG_BUS_ANY, &tegra194_pcie_ops},
0125 { "NVIDIA", "TEGRA194", 1, 4, MCFG_BUS_ANY, &tegra194_pcie_ops},
0126 { "NVIDIA", "TEGRA194", 1, 5, MCFG_BUS_ANY, &tegra194_pcie_ops},
0127
0128 #define XGENE_V1_ECAM_MCFG(rev, seg) \
0129 {"APM ", "XGENE ", rev, seg, MCFG_BUS_ANY, \
0130 &xgene_v1_pcie_ecam_ops }
0131
0132 #define XGENE_V2_ECAM_MCFG(rev, seg) \
0133 {"APM ", "XGENE ", rev, seg, MCFG_BUS_ANY, \
0134 &xgene_v2_pcie_ecam_ops }
0135
0136
0137 XGENE_V1_ECAM_MCFG(1, 0),
0138 XGENE_V1_ECAM_MCFG(1, 1),
0139 XGENE_V1_ECAM_MCFG(1, 2),
0140 XGENE_V1_ECAM_MCFG(1, 3),
0141 XGENE_V1_ECAM_MCFG(1, 4),
0142 XGENE_V1_ECAM_MCFG(2, 0),
0143 XGENE_V1_ECAM_MCFG(2, 1),
0144 XGENE_V1_ECAM_MCFG(2, 2),
0145 XGENE_V1_ECAM_MCFG(2, 3),
0146 XGENE_V1_ECAM_MCFG(2, 4),
0147
0148 XGENE_V2_ECAM_MCFG(3, 0),
0149 XGENE_V2_ECAM_MCFG(3, 1),
0150
0151 XGENE_V2_ECAM_MCFG(4, 0),
0152 XGENE_V2_ECAM_MCFG(4, 1),
0153 XGENE_V2_ECAM_MCFG(4, 2),
0154
0155 #define ALTRA_ECAM_QUIRK(rev, seg) \
0156 { "Ampere", "Altra ", rev, seg, MCFG_BUS_ANY, &pci_32b_read_ops }
0157
0158 ALTRA_ECAM_QUIRK(1, 0),
0159 ALTRA_ECAM_QUIRK(1, 1),
0160 ALTRA_ECAM_QUIRK(1, 2),
0161 ALTRA_ECAM_QUIRK(1, 3),
0162 ALTRA_ECAM_QUIRK(1, 4),
0163 ALTRA_ECAM_QUIRK(1, 5),
0164 ALTRA_ECAM_QUIRK(1, 6),
0165 ALTRA_ECAM_QUIRK(1, 7),
0166 ALTRA_ECAM_QUIRK(1, 8),
0167 ALTRA_ECAM_QUIRK(1, 9),
0168 ALTRA_ECAM_QUIRK(1, 10),
0169 ALTRA_ECAM_QUIRK(1, 11),
0170 ALTRA_ECAM_QUIRK(1, 12),
0171 ALTRA_ECAM_QUIRK(1, 13),
0172 ALTRA_ECAM_QUIRK(1, 14),
0173 ALTRA_ECAM_QUIRK(1, 15),
0174 #endif
0175
0176 #ifdef CONFIG_LOONGARCH
0177 #define LOONGSON_ECAM_MCFG(table_id, seg) \
0178 { "LOONGS", table_id, 1, seg, MCFG_BUS_ANY, &loongson_pci_ecam_ops }
0179
0180 LOONGSON_ECAM_MCFG("\0", 0),
0181 LOONGSON_ECAM_MCFG("LOONGSON", 0),
0182 LOONGSON_ECAM_MCFG("\0", 1),
0183 LOONGSON_ECAM_MCFG("LOONGSON", 1),
0184 #endif
0185 };
0186
0187 static char mcfg_oem_id[ACPI_OEM_ID_SIZE];
0188 static char mcfg_oem_table_id[ACPI_OEM_TABLE_ID_SIZE];
0189 static u32 mcfg_oem_revision;
0190
0191 static int pci_mcfg_quirk_matches(struct mcfg_fixup *f, u16 segment,
0192 struct resource *bus_range)
0193 {
0194 if (!memcmp(f->oem_id, mcfg_oem_id, ACPI_OEM_ID_SIZE) &&
0195 !memcmp(f->oem_table_id, mcfg_oem_table_id,
0196 ACPI_OEM_TABLE_ID_SIZE) &&
0197 f->oem_revision == mcfg_oem_revision &&
0198 f->segment == segment &&
0199 resource_contains(&f->bus_range, bus_range))
0200 return 1;
0201
0202 return 0;
0203 }
0204 #endif
0205
0206 static void pci_mcfg_apply_quirks(struct acpi_pci_root *root,
0207 struct resource *cfgres,
0208 const struct pci_ecam_ops **ecam_ops)
0209 {
0210 #ifdef CONFIG_PCI_QUIRKS
0211 u16 segment = root->segment;
0212 struct resource *bus_range = &root->secondary;
0213 struct mcfg_fixup *f;
0214 int i;
0215
0216 for (i = 0, f = mcfg_quirks; i < ARRAY_SIZE(mcfg_quirks); i++, f++) {
0217 if (pci_mcfg_quirk_matches(f, segment, bus_range)) {
0218 if (f->cfgres.start)
0219 *cfgres = f->cfgres;
0220 if (f->ops)
0221 *ecam_ops = f->ops;
0222 dev_info(&root->device->dev, "MCFG quirk: ECAM at %pR for %pR with %ps\n",
0223 cfgres, bus_range, *ecam_ops);
0224 return;
0225 }
0226 }
0227 #endif
0228 }
0229
0230
0231 static LIST_HEAD(pci_mcfg_list);
0232
0233 int pci_mcfg_lookup(struct acpi_pci_root *root, struct resource *cfgres,
0234 const struct pci_ecam_ops **ecam_ops)
0235 {
0236 const struct pci_ecam_ops *ops = &pci_generic_ecam_ops;
0237 struct resource *bus_res = &root->secondary;
0238 u16 seg = root->segment;
0239 struct mcfg_entry *e;
0240 struct resource res;
0241
0242
0243 if (root->mcfg_addr)
0244 goto skip_lookup;
0245
0246
0247
0248
0249 list_for_each_entry(e, &pci_mcfg_list, list) {
0250 if (e->segment == seg && e->bus_start <= bus_res->start &&
0251 e->bus_end >= bus_res->end) {
0252 root->mcfg_addr = e->addr;
0253 }
0254
0255 }
0256
0257 skip_lookup:
0258 memset(&res, 0, sizeof(res));
0259 if (root->mcfg_addr) {
0260 res.start = root->mcfg_addr + (bus_res->start << 20);
0261 res.end = res.start + (resource_size(bus_res) << 20) - 1;
0262 res.flags = IORESOURCE_MEM;
0263 }
0264
0265
0266
0267
0268
0269
0270
0271 pci_mcfg_apply_quirks(root, &res, &ops);
0272 if (!res.start)
0273 return -ENXIO;
0274
0275 *cfgres = res;
0276 *ecam_ops = ops;
0277 return 0;
0278 }
0279
0280 static __init int pci_mcfg_parse(struct acpi_table_header *header)
0281 {
0282 struct acpi_table_mcfg *mcfg;
0283 struct acpi_mcfg_allocation *mptr;
0284 struct mcfg_entry *e, *arr;
0285 int i, n;
0286
0287 if (header->length < sizeof(struct acpi_table_mcfg))
0288 return -EINVAL;
0289
0290 n = (header->length - sizeof(struct acpi_table_mcfg)) /
0291 sizeof(struct acpi_mcfg_allocation);
0292 mcfg = (struct acpi_table_mcfg *)header;
0293 mptr = (struct acpi_mcfg_allocation *) &mcfg[1];
0294
0295 arr = kcalloc(n, sizeof(*arr), GFP_KERNEL);
0296 if (!arr)
0297 return -ENOMEM;
0298
0299 for (i = 0, e = arr; i < n; i++, mptr++, e++) {
0300 e->segment = mptr->pci_segment;
0301 e->addr = mptr->address;
0302 e->bus_start = mptr->start_bus_number;
0303 e->bus_end = mptr->end_bus_number;
0304 list_add(&e->list, &pci_mcfg_list);
0305 }
0306
0307 #ifdef CONFIG_PCI_QUIRKS
0308
0309 memcpy(mcfg_oem_id, header->oem_id, ACPI_OEM_ID_SIZE);
0310 memcpy(mcfg_oem_table_id, header->oem_table_id, ACPI_OEM_TABLE_ID_SIZE);
0311 mcfg_oem_revision = header->oem_revision;
0312 #endif
0313
0314 pr_info("MCFG table detected, %d entries\n", n);
0315 return 0;
0316 }
0317
0318
0319 void __init pci_mmcfg_late_init(void)
0320 {
0321 int err = acpi_table_parse(ACPI_SIG_MCFG, pci_mcfg_parse);
0322 if (err)
0323 pr_debug("Failed to parse MCFG (%d)\n", err);
0324 }