1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
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
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
44
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
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}
93