1 /*
2  *  acpi_mmconfig.c - Architecture-Specific Low-Level ACPI Boot Support
3  *
4  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
5  *  Copyright (C) 2001 Jun Nakajima <jun.nakajima@intel.com>
6  *
7  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; If not, see <http://www.gnu.org/licenses/>.
21  *
22  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23  *
24  * copied from Linux
25  */
26 
27 #include <xen/errno.h>
28 #include <xen/init.h>
29 #include <xen/acpi.h>
30 #include <xen/irq.h>
31 #include <xen/dmi.h>
32 #include <asm/fixmap.h>
33 #include <asm/page.h>
34 #include <asm/apic.h>
35 #include <asm/io_apic.h>
36 #include <asm/apic.h>
37 #include <asm/io.h>
38 #include <asm/mpspec.h>
39 #include <asm/processor.h>
40 #include <mach_apic.h>
41 #include <mach_mpparse.h>
42 
43 #include "mmconfig.h"
44 
45 /* The physical address of the MMCONFIG aperture.  Set from ACPI tables. */
46 struct acpi_mcfg_allocation *pci_mmcfg_config;
47 int pci_mmcfg_config_num;
48 
acpi_mcfg_check_entry(struct acpi_table_mcfg * mcfg,struct acpi_mcfg_allocation * cfg)49 static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
50                                         struct acpi_mcfg_allocation *cfg)
51 {
52     int year;
53 
54     if (cfg->address < 0xFFFFFFFF)
55         return 0;
56 
57     if (!strncmp(mcfg->header.oem_id, "SGI", 3))
58         return 0;
59 
60     if (mcfg->header.revision >= 1 &&
61         dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) &&
62         year >= 2010)
63             return 0;
64 
65     printk(KERN_ERR "MCFG region for %04x:%02x-%02x at %#"PRIx64
66                     " (above 4GB) ignored\n",
67            cfg->pci_segment, cfg->start_bus_number, cfg->end_bus_number,
68            cfg->address);
69     return -EINVAL;
70 }
71 
acpi_parse_mcfg(struct acpi_table_header * header)72 int __init acpi_parse_mcfg(struct acpi_table_header *header)
73 {
74     struct acpi_table_mcfg *mcfg;
75     unsigned long i;
76 
77     if (!header)
78         return -EINVAL;
79 
80     mcfg = (struct acpi_table_mcfg *)header;
81 
82     /* how many config structures do we have */
83     pci_mmcfg_config_num = 0;
84     i = header->length - sizeof(struct acpi_table_mcfg);
85     while (i >= sizeof(struct acpi_mcfg_allocation)) {
86         ++pci_mmcfg_config_num;
87         i -= sizeof(struct acpi_mcfg_allocation);
88     };
89     if (pci_mmcfg_config_num == 0) {
90         printk(KERN_ERR PREFIX "MMCONFIG has no entries\n");
91         return -ENODEV;
92     }
93 
94     pci_mmcfg_config = xmalloc_array(struct acpi_mcfg_allocation,
95                                      pci_mmcfg_config_num);
96     if (!pci_mmcfg_config) {
97         printk(KERN_WARNING PREFIX
98                "No memory for MCFG config tables\n");
99         pci_mmcfg_config_num = 0;
100         return -ENOMEM;
101     }
102 
103     memcpy(pci_mmcfg_config, &mcfg[1],
104            pci_mmcfg_config_num * sizeof(*pci_mmcfg_config));
105 
106     for (i = 0; i < pci_mmcfg_config_num; ++i) {
107         if (acpi_mcfg_check_entry(mcfg, &pci_mmcfg_config[i])) {
108             xfree(pci_mmcfg_config);
109             pci_mmcfg_config_num = 0;
110             return -ENODEV;
111         }
112         pci_add_segment(pci_mmcfg_config[i].pci_segment);
113     }
114 
115     return 0;
116 }
117