x86/smpboot: Init apic mapping before usage
[cascardo/linux.git] / drivers / acpi / pci_mcfg.c
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 */
27 struct 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 */
36 static LIST_HEAD(pci_mcfg_list);
37
38 phys_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
55 static __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 */
87 void __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 }