aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomasz Nowicki <tn@semihalf.com>2016-06-10 15:55:13 -0400
committerBjorn Helgaas <bhelgaas@google.com>2016-06-10 19:27:59 -0400
commit935c760ec8101413248da23b6df45f0a7a643c62 (patch)
treeeb8e54c07bbc7fecebcb7584ba01d9ebf27058cd
parent0a70abb3806295e039f9b2df5321cc3f7c87f4d6 (diff)
PCI/ACPI: Add generic MCFG table handling
On ACPI systems that support memory-mapped config space access, i.e., ECAM, the PCI Firmware Specification says the OS can learn where the ECAM space is from either: - the static MCFG table (for non-hotpluggable bridges), or - the _CBA method (for hotpluggable bridges) The current MCFG table handling code cannot be easily generalized owing to x86-specific quirks, which makes it hard to reuse on other architectures. Implement generic MCFG handling from scratch, including: - Simple MCFG table parsing (via pci_mmcfg_late_init() as in current x86) - MCFG region lookup for a (domain, bus_start, bus_end) tuple [bhelgaas: changelog] Signed-off-by: Tomasz Nowicki <tn@semihalf.com> Signed-off-by: Jayachandran C <jchandra@broadcom.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
-rw-r--r--drivers/acpi/Kconfig3
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/pci_mcfg.c92
-rw-r--r--include/linux/pci-acpi.h2
-rw-r--r--include/linux/pci.h2
5 files changed, 99 insertions, 1 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index b7e2e776397d..f98c3287256e 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -217,6 +217,9 @@ config ACPI_PROCESSOR_IDLE
217 bool 217 bool
218 select CPU_IDLE 218 select CPU_IDLE
219 219
220config ACPI_MCFG
221 bool
222
220config ACPI_CPPC_LIB 223config ACPI_CPPC_LIB
221 bool 224 bool
222 depends on ACPI_PROCESSOR 225 depends on ACPI_PROCESSOR
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 251ce85a66fb..632e81feef69 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -40,6 +40,7 @@ acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o
40acpi-y += ec.o 40acpi-y += ec.o
41acpi-$(CONFIG_ACPI_DOCK) += dock.o 41acpi-$(CONFIG_ACPI_DOCK) += dock.o
42acpi-y += pci_root.o pci_link.o pci_irq.o 42acpi-y += pci_root.o pci_link.o pci_irq.o
43obj-$(CONFIG_ACPI_MCFG) += pci_mcfg.o
43acpi-y += acpi_lpss.o acpi_apd.o 44acpi-y += acpi_lpss.o acpi_apd.o
44acpi-y += acpi_platform.o 45acpi-y += acpi_platform.o
45acpi-y += acpi_pnp.o 46acpi-y += acpi_pnp.o
diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
new file mode 100644
index 000000000000..b5b376e081f5
--- /dev/null
+++ b/drivers/acpi/pci_mcfg.c
@@ -0,0 +1,92 @@
1/*
2 * Copyright (C) 2016 Broadcom
3 * Author: Jayachandran C <jchandra@broadcom.com>
4 * Copyright (C) 2016 Semihalf
5 * Author: Tomasz Nowicki <tn@semihalf.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License, version 2, as
9 * published by the Free Software Foundation (the "GPL").
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License version 2 (GPLv2) for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * version 2 (GPLv2) along with this source code.
18 */
19
20#define pr_fmt(fmt) "ACPI: " fmt
21
22#include <linux/kernel.h>
23#include <linux/pci.h>
24#include <linux/pci-acpi.h>
25
26/* Structure to hold entries from the MCFG table */
27struct mcfg_entry {
28 struct list_head list;
29 phys_addr_t addr;
30 u16 segment;
31 u8 bus_start;
32 u8 bus_end;
33};
34
35/* List to save MCFG entries */
36static LIST_HEAD(pci_mcfg_list);
37
38phys_addr_t pci_mcfg_lookup(u16 seg, struct resource *bus_res)
39{
40 struct mcfg_entry *e;
41
42 /*
43 * We expect exact match, unless MCFG entry end bus covers more than
44 * specified by caller.
45 */
46 list_for_each_entry(e, &pci_mcfg_list, list) {
47 if (e->segment == seg && e->bus_start == bus_res->start &&
48 e->bus_end >= bus_res->end)
49 return e->addr;
50 }
51
52 return 0;
53}
54
55static __init int pci_mcfg_parse(struct acpi_table_header *header)
56{
57 struct acpi_table_mcfg *mcfg;
58 struct acpi_mcfg_allocation *mptr;
59 struct mcfg_entry *e, *arr;
60 int i, n;
61
62 if (header->length < sizeof(struct acpi_table_mcfg))
63 return -EINVAL;
64
65 n = (header->length - sizeof(struct acpi_table_mcfg)) /
66 sizeof(struct acpi_mcfg_allocation);
67 mcfg = (struct acpi_table_mcfg *)header;
68 mptr = (struct acpi_mcfg_allocation *) &mcfg[1];
69
70 arr = kcalloc(n, sizeof(*arr), GFP_KERNEL);
71 if (!arr)
72 return -ENOMEM;
73
74 for (i = 0, e = arr; i < n; i++, mptr++, e++) {
75 e->segment = mptr->pci_segment;
76 e->addr = mptr->address;
77 e->bus_start = mptr->start_bus_number;
78 e->bus_end = mptr->end_bus_number;
79 list_add(&e->list, &pci_mcfg_list);
80 }
81
82 pr_info("MCFG table detected, %d entries\n", n);
83 return 0;
84}
85
86/* Interface called by ACPI - parse and save MCFG table */
87void __init pci_mmcfg_late_init(void)
88{
89 int err = acpi_table_parse(ACPI_SIG_MCFG, pci_mcfg_parse);
90 if (err)
91 pr_err("Failed to parse MCFG (%d)\n", err);
92}
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index 89ab0572dbc6..7d63a66e8ed4 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -24,6 +24,8 @@ static inline acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev)
24} 24}
25extern phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle); 25extern phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle);
26 26
27extern phys_addr_t pci_mcfg_lookup(u16 domain, struct resource *bus_res);
28
27static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev) 29static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
28{ 30{
29 struct pci_bus *pbus = pdev->bus; 31 struct pci_bus *pbus = pdev->bus;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 12349deb688c..ce03d650279b 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1723,7 +1723,7 @@ void pcibios_free_irq(struct pci_dev *dev);
1723extern struct dev_pm_ops pcibios_pm_ops; 1723extern struct dev_pm_ops pcibios_pm_ops;
1724#endif 1724#endif
1725 1725
1726#ifdef CONFIG_PCI_MMCONFIG 1726#if defined(CONFIG_PCI_MMCONFIG) || defined(CONFIG_ACPI_MCFG)
1727void __init pci_mmcfg_early_init(void); 1727void __init pci_mmcfg_early_init(void);
1728void __init pci_mmcfg_late_init(void); 1728void __init pci_mmcfg_late_init(void);
1729#else 1729#else