1 /*
2  * mmconfig-shared.c - Low-level direct PCI config space access via
3  *                     MMCONFIG - common code between i386 and x86-64.
4  *
5  * This code does:
6  * - known chipset handling
7  * - ACPI decoding and validation
8  *
9  * Per-architecture code takes care of the mappings and accesses
10  * themselves.
11  *
12  * Author: Allen Kay <allen.m.kay@intel.com> -  adapted to xen from Linux
13  */
14 
15 #include <xen/init.h>
16 #include <xen/mm.h>
17 #include <xen/param.h>
18 #include <xen/acpi.h>
19 #include <xen/xmalloc.h>
20 #include <xen/pci.h>
21 #include <xen/pci_regs.h>
22 #include <xen/pci_ids.h>
23 #include <asm/e820.h>
24 #include <asm/msr.h>
25 #include <asm/msr-index.h>
26 #include <public/physdev.h>
27 
28 #include "mmconfig.h"
29 
30 unsigned int pci_probe = PCI_PROBE_CONF1 | PCI_PROBE_MMCONF;
31 
parse_mmcfg(const char * s)32 static int __init parse_mmcfg(const char *s)
33 {
34     const char *ss;
35     int rc = 0;
36 
37     do {
38         ss = strchr(s, ',');
39         if ( !ss )
40             ss = strchr(s, '\0');
41 
42         switch ( parse_bool(s, ss) )
43         {
44         case 0:
45             pci_probe &= ~PCI_PROBE_MMCONF;
46             break;
47         case 1:
48             break;
49         default:
50             if ( !cmdline_strcmp(s, "amd_fam10") ||
51                  !cmdline_strcmp(s, "amd-fam10") )
52                 pci_probe |= PCI_CHECK_ENABLE_AMD_MMCONF;
53             else
54                 rc = -EINVAL;
55             break;
56         }
57 
58         s = ss + 1;
59     } while ( *ss );
60 
61     return rc;
62 }
63 custom_param("mmcfg", parse_mmcfg);
64 
pci_mmcfg_e7520(void)65 static const char __init *pci_mmcfg_e7520(void)
66 {
67     u32 win;
68     win = pci_conf_read16(PCI_SBDF(0, 0, 0, 0), 0xce);
69 
70     win = win & 0xf000;
71     if(win == 0x0000 || win == 0xf000)
72         pci_mmcfg_config_num = 0;
73     else {
74         pci_mmcfg_config_num = 1;
75         pci_mmcfg_config = xzalloc(struct acpi_mcfg_allocation);
76         if (!pci_mmcfg_config)
77             return NULL;
78         pci_mmcfg_config[0].address = win << 16;
79         pci_mmcfg_config[0].pci_segment = 0;
80         pci_mmcfg_config[0].start_bus_number = 0;
81         pci_mmcfg_config[0].end_bus_number = 255;
82     }
83 
84     return "Intel Corporation E7520 Memory Controller Hub";
85 }
86 
pci_mmcfg_intel_945(void)87 static const char __init *pci_mmcfg_intel_945(void)
88 {
89     u32 pciexbar, mask = 0, len = 0;
90 
91     pci_mmcfg_config_num = 1;
92 
93     pciexbar = pci_conf_read32(PCI_SBDF(0, 0, 0, 0), 0x48);
94 
95     /* Enable bit */
96     if (!(pciexbar & 1))
97         pci_mmcfg_config_num = 0;
98 
99     /* Size bits */
100     switch ((pciexbar >> 1) & 3) {
101     case 0:
102         mask = 0xf0000000U;
103         len  = 0x10000000U;
104         break;
105     case 1:
106         mask = 0xf8000000U;
107         len  = 0x08000000U;
108         break;
109     case 2:
110         mask = 0xfc000000U;
111         len  = 0x04000000U;
112         break;
113     default:
114         pci_mmcfg_config_num = 0;
115     }
116 
117     /* Errata #2, things break when not aligned on a 256Mb boundary */
118     /* Can only happen in 64M/128M mode */
119 
120     if ((pciexbar & mask) & 0x0fffffffU)
121         pci_mmcfg_config_num = 0;
122 
123     /* Don't hit the APIC registers and their friends */
124     if ((pciexbar & mask) >= 0xf0000000U)
125         pci_mmcfg_config_num = 0;
126 
127     if (pci_mmcfg_config_num) {
128         pci_mmcfg_config = xzalloc(struct acpi_mcfg_allocation);
129         if (!pci_mmcfg_config)
130             return NULL;
131         pci_mmcfg_config[0].address = pciexbar & mask;
132         pci_mmcfg_config[0].pci_segment = 0;
133         pci_mmcfg_config[0].start_bus_number = 0;
134         pci_mmcfg_config[0].end_bus_number = (len >> 20) - 1;
135     }
136 
137     return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub";
138 }
139 
pci_mmcfg_amd_fam10h(void)140 static const char __init *pci_mmcfg_amd_fam10h(void)
141 {
142     uint32_t address;
143     uint64_t base, msr_content;
144     int i;
145     unsigned segnbits = 0, busnbits;
146 
147     if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF))
148         return NULL;
149 
150     address = MSR_FAM10H_MMIO_CONF_BASE;
151     if (rdmsr_safe(address, msr_content))
152         return NULL;
153 
154     /* mmconfig is not enable */
155     if (!(msr_content & FAM10H_MMIO_CONF_ENABLE))
156         return NULL;
157 
158     base = msr_content &
159         (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT);
160 
161     busnbits = (msr_content >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
162                 FAM10H_MMIO_CONF_BUSRANGE_MASK;
163 
164     /*
165      * only handle bus 0 ?
166      * need to skip it
167      */
168     if (!busnbits)
169         return NULL;
170 
171     if (busnbits > 8) {
172         segnbits = busnbits - 8;
173         busnbits = 8;
174     }
175 
176     pci_mmcfg_config_num = (1 << segnbits);
177     pci_mmcfg_config = xmalloc_array(struct acpi_mcfg_allocation,
178                                      pci_mmcfg_config_num);
179     if (!pci_mmcfg_config)
180         return NULL;
181 
182     for (i = 0; i < (1 << segnbits); i++) {
183         pci_mmcfg_config[i].address = base + ((unsigned long)i << 28);
184         pci_mmcfg_config[i].pci_segment = i;
185         pci_mmcfg_config[i].start_bus_number = 0;
186         pci_mmcfg_config[i].end_bus_number = (1 << busnbits) - 1;
187         pci_add_segment(i);
188     }
189 
190     return "AMD Family 10h NB";
191 }
192 
pci_mmcfg_nvidia_mcp55(void)193 static const char __init *pci_mmcfg_nvidia_mcp55(void)
194 {
195     static bool_t __initdata mcp55_checked;
196     int bus, i;
197 
198     static const u32 extcfg_regnum      = 0x90;
199     static const u32 extcfg_enable_mask = 1u << 31;
200     static const u32 extcfg_start_mask  = 0xffu << 16;
201     static const int extcfg_start_shift = 16;
202     static const u32 extcfg_size_mask   = 3u << 28;
203     static const int extcfg_size_shift  = 28;
204     static const int extcfg_sizebus[]   = {0xff, 0x7f, 0x3f, 0x1f};
205     static const u32 extcfg_base_mask[] = {0x7ff8, 0x7ffc, 0x7ffe, 0x7fff};
206     static const int extcfg_base_lshift = 25;
207 
208     /* check if amd fam10h already took over */
209     if (!acpi_disabled || pci_mmcfg_config_num || mcp55_checked)
210         return NULL;
211 
212     mcp55_checked = 1;
213     for (i = bus = 0; bus < 256; bus++) {
214         u32 l, extcfg;
215         u16 vendor, device;
216 
217         l = pci_conf_read32(PCI_SBDF(0, bus, 0, 0), 0);
218         vendor = l & 0xffff;
219         device = (l >> 16) & 0xffff;
220 
221         if (PCI_VENDOR_ID_NVIDIA != vendor || 0x0369 != device)
222             continue;
223 
224         extcfg = pci_conf_read32(PCI_SBDF(0, bus, 0, 0), extcfg_regnum);
225 
226         if (extcfg & extcfg_enable_mask)
227             i++;
228     }
229 
230     if (!i)
231         return NULL;
232 
233     pci_mmcfg_config_num = i;
234     pci_mmcfg_config = xmalloc_array(struct acpi_mcfg_allocation,
235                                      pci_mmcfg_config_num);
236 
237     for (i = bus = 0; bus < 256; bus++) {
238         u64 base;
239         u32 l, extcfg;
240         u16 vendor, device;
241         int size_index;
242 
243         l = pci_conf_read32(PCI_SBDF(0, bus, 0, 0), 0);
244         vendor = l & 0xffff;
245         device = (l >> 16) & 0xffff;
246 
247         if (PCI_VENDOR_ID_NVIDIA != vendor || 0x0369 != device)
248             continue;
249 
250         extcfg = pci_conf_read32(PCI_SBDF(0, bus, 0, 0), extcfg_regnum);
251 
252         if (!(extcfg & extcfg_enable_mask))
253             continue;
254 
255         if (i >= pci_mmcfg_config_num)
256             break;
257 
258         size_index = (extcfg & extcfg_size_mask) >> extcfg_size_shift;
259         base = extcfg & extcfg_base_mask[size_index];
260         /* base could be > 4G */
261         pci_mmcfg_config[i].address = base << extcfg_base_lshift;
262         pci_mmcfg_config[i].pci_segment = 0;
263         pci_mmcfg_config[i].start_bus_number =
264             (extcfg & extcfg_start_mask) >> extcfg_start_shift;
265         pci_mmcfg_config[i].end_bus_number =
266             pci_mmcfg_config[i].start_bus_number + extcfg_sizebus[size_index];
267         i++;
268     }
269 
270     if (bus == 256)
271         return "nVidia MCP55";
272 
273     pci_mmcfg_config_num = 0;
274     xfree(pci_mmcfg_config);
275     pci_mmcfg_config = NULL;
276 
277     return NULL;
278 }
279 
280 struct pci_mmcfg_hostbridge_probe {
281     u32 bus;
282     u32 devfn;
283     u32 vendor;
284     u32 device;
285     const char *(*probe)(void);
286 };
287 
288 static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = {
289     { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL,
290       PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 },
291     { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL,
292       PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 },
293     { 0, PCI_DEVFN(0x18, 0), PCI_VENDOR_ID_AMD,
294       0x1200, pci_mmcfg_amd_fam10h },
295     { 0xff, PCI_DEVFN(0, 0), PCI_VENDOR_ID_AMD,
296       0x1200, pci_mmcfg_amd_fam10h },
297     { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_NVIDIA,
298       0x0369, pci_mmcfg_nvidia_mcp55 },
299 };
300 
pci_mmcfg_check_hostbridge(void)301 static int __init pci_mmcfg_check_hostbridge(void)
302 {
303     u32 l;
304     u32 bus, devfn;
305     u16 vendor, device;
306     int i;
307     const char *name;
308 
309     pci_mmcfg_config_num = 0;
310     pci_mmcfg_config = NULL;
311     name = NULL;
312 
313     for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) {
314         bus =  pci_mmcfg_probes[i].bus;
315         devfn = pci_mmcfg_probes[i].devfn;
316         l = pci_conf_read32(PCI_SBDF3(0, bus, devfn), 0);
317         vendor = l & 0xffff;
318         device = (l >> 16) & 0xffff;
319 
320         if (pci_mmcfg_probes[i].vendor == vendor &&
321             pci_mmcfg_probes[i].device == device)
322             name = pci_mmcfg_probes[i].probe();
323     }
324 
325     if (name) {
326         printk(KERN_INFO "PCI: Found %s %s MMCONFIG support.\n",
327             name, pci_mmcfg_config_num ? "with" : "without");
328     }
329 
330     return name != NULL;
331 }
332 
is_mmconf_reserved(u64 addr,u64 size,int i,typeof (pci_mmcfg_config[0])* cfg)333 static int __init is_mmconf_reserved(
334     u64 addr, u64 size, int i,
335     typeof(pci_mmcfg_config[0]) *cfg)
336 {
337     u64 old_size = size;
338     int valid = 0;
339 
340     while (!e820_all_mapped(addr, addr + size, E820_RESERVED)) {
341         size >>= 1;
342         if (size < (16UL<<20))
343             break;
344     }
345 
346     if (size >= (16UL<<20) || size == old_size) {
347         printk(KERN_NOTICE "PCI: MCFG area at %lx reserved in E820\n", addr);
348         valid = 1;
349 
350         if (old_size != size) {
351             /* update end_bus_number */
352             cfg->end_bus_number = cfg->start_bus_number + ((size>>20) - 1);
353             printk(KERN_NOTICE "PCI: updated MCFG configuration %d: base %lx "
354                    "segment %hu buses %u - %u\n",
355                    i, (unsigned long)cfg->address, cfg->pci_segment,
356                    (unsigned int)cfg->start_bus_number,
357                    (unsigned int)cfg->end_bus_number);
358         }
359     }
360 
361     return valid;
362 }
363 
pci_mmcfg_reject_broken(void)364 static bool_t __init pci_mmcfg_reject_broken(void)
365 {
366     typeof(pci_mmcfg_config[0]) *cfg;
367     int i;
368     bool_t valid = 1;
369 
370     if ((pci_mmcfg_config_num == 0) ||
371         (pci_mmcfg_config == NULL) ||
372         (pci_mmcfg_config[0].address == 0))
373         return 0;
374 
375     for (i = 0; i < pci_mmcfg_config_num; i++) {
376         u64 addr, size;
377 
378         cfg = &pci_mmcfg_config[i];
379         addr = cfg->start_bus_number;
380         addr <<= 20;
381         addr += cfg->address;
382         size = cfg->end_bus_number + 1 - cfg->start_bus_number;
383         size <<= 20;
384         printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx "
385                "segment %04x buses %02x - %02x\n",
386                i, (unsigned long)cfg->address, cfg->pci_segment,
387                (unsigned int)cfg->start_bus_number,
388                (unsigned int)cfg->end_bus_number);
389 
390         if (!is_mmconf_reserved(addr, size, i, cfg) ||
391             pci_mmcfg_arch_enable(i)) {
392             pci_mmcfg_arch_disable(i);
393             valid = 0;
394         }
395     }
396 
397     return valid;
398 }
399 
acpi_mmcfg_init(void)400 void __init acpi_mmcfg_init(void)
401 {
402     bool_t valid = 1;
403 
404     pci_segments_init();
405 
406     /* MMCONFIG disabled */
407     if ((pci_probe & PCI_PROBE_MMCONF) == 0)
408         return;
409 
410     /* MMCONFIG already enabled */
411     if (!(pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF))
412         return;
413 
414     if (pci_mmcfg_check_hostbridge()) {
415         unsigned int i;
416 
417         pci_mmcfg_arch_init();
418         for (i = 0; i < pci_mmcfg_config_num; ++i)
419             if (pci_mmcfg_arch_enable(i))
420                 valid = 0;
421     } else {
422         acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
423         pci_mmcfg_arch_init();
424         valid = pci_mmcfg_reject_broken();
425     }
426 
427     if ((pci_mmcfg_config_num == 0) ||
428         (pci_mmcfg_config == NULL) ||
429         (pci_mmcfg_config[0].address == 0))
430         return;
431 
432     if (valid)
433         pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
434 }
435 
pci_mmcfg_reserved(uint64_t address,unsigned int segment,unsigned int start_bus,unsigned int end_bus,unsigned int flags)436 int pci_mmcfg_reserved(uint64_t address, unsigned int segment,
437                        unsigned int start_bus, unsigned int end_bus,
438                        unsigned int flags)
439 {
440     unsigned int i;
441 
442     if (flags & ~XEN_PCI_MMCFG_RESERVED)
443         return -EINVAL;
444 
445     for (i = 0; i < pci_mmcfg_config_num; ++i) {
446         const typeof(pci_mmcfg_config[0]) *cfg = &pci_mmcfg_config[i];
447 
448         if (cfg->pci_segment == segment &&
449             cfg->start_bus_number == start_bus &&
450             cfg->end_bus_number == end_bus) {
451             if (cfg->address != address) {
452                 printk(KERN_WARNING
453                        "Base address presented for segment %04x bus %02x-%02x"
454                        " (%08" PRIx64 ") does not match previously obtained"
455                        " one (%08" PRIx64 ")\n",
456                        segment, start_bus, end_bus, address, cfg->address);
457                 return -EIO;
458             }
459             if (flags & XEN_PCI_MMCFG_RESERVED)
460                 return pci_mmcfg_arch_enable(i);
461             pci_mmcfg_arch_disable(i);
462             return 0;
463         }
464     }
465 
466     return -ENODEV;
467 }
468