Coverage Report

Created: 2017-10-25 09:10

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