ia64/xen-unstable

view xen/arch/x86/x86_64/mmconfig-shared.c @ 19697:42fe00c6f8b4

Enable pci mmcfg and ATS for x86_64

This patch enables PCI MMCONFIG in xen and turns on hooks for ATS.

Signed-off-by: Allen Kay <allen.m.kay@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Jun 02 11:49:34 2009 +0100 (2009-06-02)
parents
children
line source
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 */
15 #include <xen/mm.h>
16 #include <xen/acpi.h>
17 #include <xen/xmalloc.h>
18 #include <xen/pci.h>
19 #include <xen/pci_regs.h>
20 #include <asm/e820.h>
21 #include <asm/msr.h>
22 #include <asm/msr-index.h>
24 #include "mmconfig.h"
26 static int __initdata known_bridge;
27 unsigned int pci_probe = PCI_PROBE_CONF1 | PCI_PROBE_MMCONF;
29 static const char __init *pci_mmcfg_e7520(void)
30 {
31 u32 win;
32 win = pci_conf_read16(0, 0, 0, 0xce);
34 win = win & 0xf000;
35 if(win == 0x0000 || win == 0xf000)
36 pci_mmcfg_config_num = 0;
37 else {
38 pci_mmcfg_config_num = 1;
39 pci_mmcfg_config = xmalloc_bytes(sizeof(pci_mmcfg_config[0]));
40 if (!pci_mmcfg_config)
41 return NULL;
42 memset(pci_mmcfg_config, 0, sizeof(pci_mmcfg_config[0]));
43 pci_mmcfg_config[0].address = win << 16;
44 pci_mmcfg_config[0].pci_segment = 0;
45 pci_mmcfg_config[0].start_bus_number = 0;
46 pci_mmcfg_config[0].end_bus_number = 255;
47 }
49 return "Intel Corporation E7520 Memory Controller Hub";
50 }
52 static const char __init *pci_mmcfg_intel_945(void)
53 {
54 u32 pciexbar, mask = 0, len = 0;
56 pci_mmcfg_config_num = 1;
58 pciexbar = pci_conf_read32(0, 0, 0, 0x48);
60 /* Enable bit */
61 if (!(pciexbar & 1))
62 pci_mmcfg_config_num = 0;
64 /* Size bits */
65 switch ((pciexbar >> 1) & 3) {
66 case 0:
67 mask = 0xf0000000U;
68 len = 0x10000000U;
69 break;
70 case 1:
71 mask = 0xf8000000U;
72 len = 0x08000000U;
73 break;
74 case 2:
75 mask = 0xfc000000U;
76 len = 0x04000000U;
77 break;
78 default:
79 pci_mmcfg_config_num = 0;
80 }
82 /* Errata #2, things break when not aligned on a 256Mb boundary */
83 /* Can only happen in 64M/128M mode */
85 if ((pciexbar & mask) & 0x0fffffffU)
86 pci_mmcfg_config_num = 0;
88 /* Don't hit the APIC registers and their friends */
89 if ((pciexbar & mask) >= 0xf0000000U)
90 pci_mmcfg_config_num = 0;
92 if (pci_mmcfg_config_num) {
93 pci_mmcfg_config = xmalloc_bytes(sizeof(pci_mmcfg_config[0]));
94 if (!pci_mmcfg_config)
95 return NULL;
96 memset(pci_mmcfg_config, 0, sizeof(pci_mmcfg_config[0]));
97 pci_mmcfg_config[0].address = pciexbar & mask;
98 pci_mmcfg_config[0].pci_segment = 0;
99 pci_mmcfg_config[0].start_bus_number = 0;
100 pci_mmcfg_config[0].end_bus_number = (len >> 20) - 1;
101 }
103 return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub";
104 }
106 static const char __init *pci_mmcfg_amd_fam10h(void)
107 {
108 u32 low, high, address;
109 u64 base, msr;
110 int i;
111 unsigned segnbits = 0, busnbits;
113 if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF))
114 return NULL;
116 address = MSR_FAM10H_MMIO_CONF_BASE;
117 if (rdmsr_safe(address, low, high))
118 return NULL;
120 msr = high;
121 msr <<= 32;
122 msr |= low;
124 /* mmconfig is not enable */
125 if (!(msr & FAM10H_MMIO_CONF_ENABLE))
126 return NULL;
128 base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT);
130 busnbits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
131 FAM10H_MMIO_CONF_BUSRANGE_MASK;
133 /*
134 * only handle bus 0 ?
135 * need to skip it
136 */
137 if (!busnbits)
138 return NULL;
140 if (busnbits > 8) {
141 segnbits = busnbits - 8;
142 busnbits = 8;
143 }
145 pci_mmcfg_config_num = (1 << segnbits);
146 pci_mmcfg_config = xmalloc_bytes(sizeof(pci_mmcfg_config[0]) *
147 pci_mmcfg_config_num);
148 if (!pci_mmcfg_config)
149 return NULL;
151 for (i = 0; i < (1 << segnbits); i++) {
152 pci_mmcfg_config[i].address = base + (1<<28) * i;
153 pci_mmcfg_config[i].pci_segment = i;
154 pci_mmcfg_config[i].start_bus_number = 0;
155 pci_mmcfg_config[i].end_bus_number = (1 << busnbits) - 1;
156 }
158 return "AMD Family 10h NB";
159 }
161 struct pci_mmcfg_hostbridge_probe {
162 u32 bus;
163 u32 devfn;
164 u32 vendor;
165 u32 device;
166 const char *(*probe)(void);
167 };
169 static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = {
170 { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL,
171 PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 },
172 { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL,
173 PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 },
174 { 0, PCI_DEVFN(0x18, 0), PCI_VENDOR_ID_AMD,
175 0x1200, pci_mmcfg_amd_fam10h },
176 { 0xff, PCI_DEVFN(0, 0), PCI_VENDOR_ID_AMD,
177 0x1200, pci_mmcfg_amd_fam10h },
178 };
180 static int __init pci_mmcfg_check_hostbridge(void)
181 {
182 u32 l;
183 u32 bus, devfn;
184 u16 vendor, device;
185 int i;
186 const char *name;
188 pci_mmcfg_config_num = 0;
189 pci_mmcfg_config = NULL;
190 name = NULL;
192 for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) {
193 bus = pci_mmcfg_probes[i].bus;
194 devfn = pci_mmcfg_probes[i].devfn;
195 l = pci_conf_read32(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), 0);
196 vendor = l & 0xffff;
197 device = (l >> 16) & 0xffff;
199 if (pci_mmcfg_probes[i].vendor == vendor &&
200 pci_mmcfg_probes[i].device == device)
201 name = pci_mmcfg_probes[i].probe();
202 }
204 if (name) {
205 printk(KERN_INFO "PCI: Found %s %s MMCONFIG support.\n",
206 name, pci_mmcfg_config_num ? "with" : "without");
207 }
209 return name != NULL;
210 }
212 typedef int (*check_reserved_t)(u64 start, u64 end, unsigned type);
214 static int __init is_mmconf_reserved(
215 check_reserved_t is_reserved,
216 u64 addr, u64 size, int i,
217 typeof(pci_mmcfg_config[0]) *cfg, int with_e820)
218 {
219 u64 old_size = size;
220 int valid = 0;
222 while (!is_reserved(addr, addr + size - 1, E820_RESERVED)) {
223 size >>= 1;
224 if (size < (16UL<<20))
225 break;
226 }
228 if (size >= (16UL<<20) || size == old_size) {
229 printk(KERN_NOTICE
230 "PCI: MCFG area at %lx reserved in %s\n",
231 addr, with_e820?"E820":"ACPI motherboard resources");
232 valid = 1;
234 if (old_size != size) {
235 /* update end_bus_number */
236 cfg->end_bus_number = cfg->start_bus_number + ((size>>20) - 1);
237 printk(KERN_NOTICE "PCI: updated MCFG configuration %d: base %lx "
238 "segment %hu buses %u - %u\n",
239 i, (unsigned long)cfg->address, cfg->pci_segment,
240 (unsigned int)cfg->start_bus_number,
241 (unsigned int)cfg->end_bus_number);
242 }
243 }
245 return valid;
246 }
248 static void __init pci_mmcfg_reject_broken(int early)
249 {
250 typeof(pci_mmcfg_config[0]) *cfg;
251 int i;
253 if ((pci_mmcfg_config_num == 0) ||
254 (pci_mmcfg_config == NULL) ||
255 (pci_mmcfg_config[0].address == 0))
256 return;
258 cfg = &pci_mmcfg_config[0];
260 for (i = 0; i < pci_mmcfg_config_num; i++) {
261 int valid = 0;
262 u64 addr, size;
264 cfg = &pci_mmcfg_config[i];
265 addr = cfg->start_bus_number;
266 addr <<= 20;
267 addr += cfg->address;
268 size = cfg->end_bus_number + 1 - cfg->start_bus_number;
269 size <<= 20;
270 printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx "
271 "segment %hu buses %u - %u\n",
272 i, (unsigned long)cfg->address, cfg->pci_segment,
273 (unsigned int)cfg->start_bus_number,
274 (unsigned int)cfg->end_bus_number);
276 if (valid)
277 continue;
279 if (!early)
280 printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %lx is not"
281 " reserved in ACPI motherboard resources\n",
282 cfg->address);
284 valid = is_mmconf_reserved(e820_all_mapped, addr, size, i, cfg, 1);
286 if (!valid)
287 goto reject;
288 }
290 return;
292 reject:
293 printk(KERN_INFO "PCI: Not using MMCONFIG.\n");
294 pci_mmcfg_arch_free();
295 xfree(pci_mmcfg_config);
296 pci_mmcfg_config = NULL;
297 pci_mmcfg_config_num = 0;
298 }
300 void __init __pci_mmcfg_init(int early)
301 {
302 /* MMCONFIG disabled */
303 if ((pci_probe & PCI_PROBE_MMCONF) == 0)
304 return;
306 /* MMCONFIG already enabled */
307 if (!early && !(pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF))
308 return;
310 /* for late to exit */
311 if (known_bridge)
312 return;
314 if (early) {
315 if (pci_mmcfg_check_hostbridge())
316 known_bridge = 1;
317 }
319 if (!known_bridge) {
320 acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
321 pci_mmcfg_reject_broken(early);
322 }
324 if ((pci_mmcfg_config_num == 0) ||
325 (pci_mmcfg_config == NULL) ||
326 (pci_mmcfg_config[0].address == 0))
327 return;
329 if (pci_mmcfg_arch_init()) {
330 pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
331 }
332 }
334 void acpi_mmcfg_init(void)
335 {
336 __pci_mmcfg_init(1);
337 }
339 /**
340 * pci_find_ext_capability - Find an extended capability
341 * @dev: PCI device to query
342 * @cap: capability code
343 *
344 * Returns the address of the requested extended capability structure
345 * within the device's PCI configuration space or 0 if the device does
346 * not support it. Possible values for @cap:
347 *
348 * %PCI_EXT_CAP_ID_ERR Advanced Error Reporting
349 * %PCI_EXT_CAP_ID_VC Virtual Channel
350 * %PCI_EXT_CAP_ID_DSN Device Serial Number
351 * %PCI_EXT_CAP_ID_PWR Power Budgeting
352 */
353 int pci_find_ext_capability(int seg, int bus, int devfn, int cap)
354 {
355 u32 header;
356 int ttl = 480; /* 3840 bytes, minimum 8 bytes per capability */
357 int pos = 0x100;
359 header = pci_conf_read32(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos);
361 /*
362 * If we have no capabilities, this is indicated by cap ID,
363 * cap version and next pointer all being 0.
364 */
365 if ( (header == 0) || (header == -1) )
366 {
367 dprintk(XENLOG_INFO VTDPREFIX,
368 "next cap:%x:%x.%x: no extended config\n",
369 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
370 return 0;
371 }
373 while ( ttl-- > 0 ) {
374 if ( PCI_EXT_CAP_ID(header) == cap )
375 return pos;
376 pos = PCI_EXT_CAP_NEXT(header);
377 if ( pos < 0x100 )
378 break;
379 header = pci_conf_read32(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos);
380 }
381 return 0;
382 }