Blame view

arch/x86/pci/mmconfig-shared.c 16.1 KB
b78673944   Olivier Galibert   [PATCH] mmconfig:...
1
2
3
4
5
  /*
   * mmconfig-shared.c - Low-level direct PCI config space access via
   *                     MMCONFIG - common code between i386 and x86-64.
   *
   * This code does:
9358c693c   Olivier Galibert   [PATCH] mmconfig:...
6
   * - known chipset handling
b78673944   Olivier Galibert   [PATCH] mmconfig:...
7
8
9
10
11
12
13
14
15
   * - ACPI decoding and validation
   *
   * Per-architecture code takes care of the mappings and accesses
   * themselves.
   */
  
  #include <linux/pci.h>
  #include <linux/init.h>
  #include <linux/acpi.h>
5f0db7a2f   Feng Tang   SFI: Hook PCI MMC...
16
  #include <linux/sfi_acpi.h>
b78673944   Olivier Galibert   [PATCH] mmconfig:...
17
  #include <linux/bitmap.h>
068258bc1   Yinghai Lu   x86/PCI: host mmc...
18
  #include <linux/sort.h>
b78673944   Olivier Galibert   [PATCH] mmconfig:...
19
  #include <asm/e820.h>
824877111   Jaswinder Singh Rajput   x86, pci: move ar...
20
  #include <asm/pci_x86.h>
5f0db7a2f   Feng Tang   SFI: Hook PCI MMC...
21
  #include <asm/acpi.h>
b78673944   Olivier Galibert   [PATCH] mmconfig:...
22

f4a2d5840   Len Brown   ACPI, PCI: Change...
23
  #define PREFIX "PCI: "
a192a9580   Len Brown   ACPI: Move defini...
24

b78673944   Olivier Galibert   [PATCH] mmconfig:...
25
26
27
  /* aperture is up to 256MB but BIOS may reserve less */
  #define MMCONFIG_APER_MIN	(2 * 1024*1024)
  #define MMCONFIG_APER_MAX	(256 * 1024*1024)
a5ba79710   Aaron Durbin   i386: insert uncl...
28
29
  /* Indicate if the mmcfg resources have been placed into the resource table. */
  static int __initdata pci_mmcfg_resources_inserted;
068258bc1   Yinghai Lu   x86/PCI: host mmc...
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
  static __init int extend_mmcfg(int num)
  {
  	struct acpi_mcfg_allocation *new;
  	int new_num = pci_mmcfg_config_num + num;
  
  	new = kzalloc(sizeof(pci_mmcfg_config[0]) * new_num, GFP_KERNEL);
  	if (!new)
  		return -1;
  
  	if (pci_mmcfg_config) {
  		memcpy(new, pci_mmcfg_config,
  			 sizeof(pci_mmcfg_config[0]) * new_num);
  		kfree(pci_mmcfg_config);
  	}
  	pci_mmcfg_config = new;
  
  	return 0;
  }
  
  static __init void fill_one_mmcfg(u64 addr, int segment, int start, int end)
  {
  	int i = pci_mmcfg_config_num;
  
  	pci_mmcfg_config_num++;
  	pci_mmcfg_config[i].address = addr;
  	pci_mmcfg_config[i].pci_segment = segment;
  	pci_mmcfg_config[i].start_bus_number = start;
  	pci_mmcfg_config[i].end_bus_number = end;
  }
429d512e5   OGAWA Hirofumi   [PATCH] mmconfig:...
59
  static const char __init *pci_mmcfg_e7520(void)
9358c693c   Olivier Galibert   [PATCH] mmconfig:...
60
61
  {
  	u32 win;
bb63b4219   Yinghai Lu   x86 pci: remove c...
62
  	raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0xce, 2, &win);
9358c693c   Olivier Galibert   [PATCH] mmconfig:...
63

b5229dbb8   Olivier Galibert   [PATCH] i386: Som...
64
  	win = win & 0xf000;
068258bc1   Yinghai Lu   x86/PCI: host mmc...
65
66
67
68
69
70
71
  	if (win == 0x0000 || win == 0xf000)
  		return NULL;
  
  	if (extend_mmcfg(1) == -1)
  		return NULL;
  
  	fill_one_mmcfg(win << 16, 0, 0, 255);
9358c693c   Olivier Galibert   [PATCH] mmconfig:...
72
73
74
  
  	return "Intel Corporation E7520 Memory Controller Hub";
  }
429d512e5   OGAWA Hirofumi   [PATCH] mmconfig:...
75
  static const char __init *pci_mmcfg_intel_945(void)
9358c693c   Olivier Galibert   [PATCH] mmconfig:...
76
77
  {
  	u32 pciexbar, mask = 0, len = 0;
bb63b4219   Yinghai Lu   x86 pci: remove c...
78
  	raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0x48, 4, &pciexbar);
9358c693c   Olivier Galibert   [PATCH] mmconfig:...
79
80
81
  
  	/* Enable bit */
  	if (!(pciexbar & 1))
068258bc1   Yinghai Lu   x86/PCI: host mmc...
82
  		return NULL;
9358c693c   Olivier Galibert   [PATCH] mmconfig:...
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  
  	/* Size bits */
  	switch ((pciexbar >> 1) & 3) {
  	case 0:
  		mask = 0xf0000000U;
  		len  = 0x10000000U;
  		break;
  	case 1:
  		mask = 0xf8000000U;
  		len  = 0x08000000U;
  		break;
  	case 2:
  		mask = 0xfc000000U;
  		len  = 0x04000000U;
  		break;
  	default:
068258bc1   Yinghai Lu   x86/PCI: host mmc...
99
  		return NULL;
9358c693c   Olivier Galibert   [PATCH] mmconfig:...
100
101
102
103
104
105
  	}
  
  	/* Errata #2, things break when not aligned on a 256Mb boundary */
  	/* Can only happen in 64M/128M mode */
  
  	if ((pciexbar & mask) & 0x0fffffffU)
068258bc1   Yinghai Lu   x86/PCI: host mmc...
106
  		return NULL;
9358c693c   Olivier Galibert   [PATCH] mmconfig:...
107

b5229dbb8   Olivier Galibert   [PATCH] i386: Som...
108
109
  	/* Don't hit the APIC registers and their friends */
  	if ((pciexbar & mask) >= 0xf0000000U)
068258bc1   Yinghai Lu   x86/PCI: host mmc...
110
111
112
113
114
115
  		return NULL;
  
  	if (extend_mmcfg(1) == -1)
  		return NULL;
  
  	fill_one_mmcfg(pciexbar & mask, 0, 0, (len >> 20) - 1);
9358c693c   Olivier Galibert   [PATCH] mmconfig:...
116
117
118
  
  	return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub";
  }
7fd0da408   Yinghai Lu   x86_64: check MSR...
119
120
121
122
123
124
  static const char __init *pci_mmcfg_amd_fam10h(void)
  {
  	u32 low, high, address;
  	u64 base, msr;
  	int i;
  	unsigned segnbits = 0, busnbits;
5f0b2976c   Yinghai Lu   x86: add pci=chec...
125
126
  	if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF))
  		return NULL;
7fd0da408   Yinghai Lu   x86_64: check MSR...
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
  	address = MSR_FAM10H_MMIO_CONF_BASE;
  	if (rdmsr_safe(address, &low, &high))
  		return NULL;
  
  	msr = high;
  	msr <<= 32;
  	msr |= low;
  
  	/* mmconfig is not enable */
  	if (!(msr & FAM10H_MMIO_CONF_ENABLE))
  		return NULL;
  
  	base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT);
  
  	busnbits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
  			 FAM10H_MMIO_CONF_BUSRANGE_MASK;
  
  	/*
  	 * only handle bus 0 ?
  	 * need to skip it
  	 */
  	if (!busnbits)
  		return NULL;
  
  	if (busnbits > 8) {
  		segnbits = busnbits - 8;
  		busnbits = 8;
  	}
068258bc1   Yinghai Lu   x86/PCI: host mmc...
155
  	if (extend_mmcfg(1 << segnbits) == -1)
7fd0da408   Yinghai Lu   x86_64: check MSR...
156
  		return NULL;
068258bc1   Yinghai Lu   x86/PCI: host mmc...
157
158
  	for (i = 0; i < (1 << segnbits); i++)
  		fill_one_mmcfg(base + (1<<28) * i, i, 0, (1 << busnbits) - 1);
7fd0da408   Yinghai Lu   x86_64: check MSR...
159
160
161
  
  	return "AMD Family 10h NB";
  }
5546d6f56   Ed Swierk   x86/PCI: Detect m...
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
  static bool __initdata mcp55_checked;
  static const char __init *pci_mmcfg_nvidia_mcp55(void)
  {
  	int bus;
  	int mcp55_mmconf_found = 0;
  
  	static const u32 extcfg_regnum		= 0x90;
  	static const u32 extcfg_regsize		= 4;
  	static const u32 extcfg_enable_mask	= 1<<31;
  	static const u32 extcfg_start_mask	= 0xff<<16;
  	static const int extcfg_start_shift	= 16;
  	static const u32 extcfg_size_mask	= 0x3<<28;
  	static const int extcfg_size_shift	= 28;
  	static const int extcfg_sizebus[]	= {0x100, 0x80, 0x40, 0x20};
  	static const u32 extcfg_base_mask[]	= {0x7ff8, 0x7ffc, 0x7ffe, 0x7fff};
  	static const int extcfg_base_lshift	= 25;
  
  	/*
  	 * do check if amd fam10h already took over
  	 */
  	if (!acpi_disabled || pci_mmcfg_config_num || mcp55_checked)
  		return NULL;
  
  	mcp55_checked = true;
  	for (bus = 0; bus < 256; bus++) {
  		u64 base;
  		u32 l, extcfg;
  		u16 vendor, device;
  		int start, size_index, end;
  
  		raw_pci_ops->read(0, bus, PCI_DEVFN(0, 0), 0, 4, &l);
  		vendor = l & 0xffff;
  		device = (l >> 16) & 0xffff;
  
  		if (PCI_VENDOR_ID_NVIDIA != vendor || 0x0369 != device)
  			continue;
  
  		raw_pci_ops->read(0, bus, PCI_DEVFN(0, 0), extcfg_regnum,
  				  extcfg_regsize, &extcfg);
  
  		if (!(extcfg & extcfg_enable_mask))
  			continue;
  
  		if (extend_mmcfg(1) == -1)
  			continue;
  
  		size_index = (extcfg & extcfg_size_mask) >> extcfg_size_shift;
  		base = extcfg & extcfg_base_mask[size_index];
  		/* base could > 4G */
  		base <<= extcfg_base_lshift;
  		start = (extcfg & extcfg_start_mask) >> extcfg_start_shift;
  		end = start + extcfg_sizebus[size_index] - 1;
  		fill_one_mmcfg(base, 0, start, end);
  		mcp55_mmconf_found++;
  	}
  
  	if (!mcp55_mmconf_found)
  		return NULL;
  
  	return "nVidia MCP55";
  }
9358c693c   Olivier Galibert   [PATCH] mmconfig:...
223
  struct pci_mmcfg_hostbridge_probe {
7fd0da408   Yinghai Lu   x86_64: check MSR...
224
225
  	u32 bus;
  	u32 devfn;
9358c693c   Olivier Galibert   [PATCH] mmconfig:...
226
227
228
229
  	u32 vendor;
  	u32 device;
  	const char *(*probe)(void);
  };
429d512e5   OGAWA Hirofumi   [PATCH] mmconfig:...
230
  static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = {
7fd0da408   Yinghai Lu   x86_64: check MSR...
231
232
233
234
235
236
237
238
  	{ 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL,
  	  PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 },
  	{ 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL,
  	  PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 },
  	{ 0, PCI_DEVFN(0x18, 0), PCI_VENDOR_ID_AMD,
  	  0x1200, pci_mmcfg_amd_fam10h },
  	{ 0xff, PCI_DEVFN(0, 0), PCI_VENDOR_ID_AMD,
  	  0x1200, pci_mmcfg_amd_fam10h },
5546d6f56   Ed Swierk   x86/PCI: Detect m...
239
240
  	{ 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_NVIDIA,
  	  0x0369, pci_mmcfg_nvidia_mcp55 },
9358c693c   Olivier Galibert   [PATCH] mmconfig:...
241
  };
068258bc1   Yinghai Lu   x86/PCI: host mmc...
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
  static int __init cmp_mmcfg(const void *x1, const void *x2)
  {
  	const typeof(pci_mmcfg_config[0]) *m1 = x1;
  	const typeof(pci_mmcfg_config[0]) *m2 = x2;
  	int start1, start2;
  
  	start1 = m1->start_bus_number;
  	start2 = m2->start_bus_number;
  
  	return start1 - start2;
  }
  
  static void __init pci_mmcfg_check_end_bus_number(void)
  {
  	int i;
  	typeof(pci_mmcfg_config[0]) *cfg, *cfgx;
  
  	/* sort them at first */
  	sort(pci_mmcfg_config, pci_mmcfg_config_num,
  		 sizeof(pci_mmcfg_config[0]), cmp_mmcfg, NULL);
  
  	/* last one*/
  	if (pci_mmcfg_config_num > 0) {
  		i = pci_mmcfg_config_num - 1;
  		cfg = &pci_mmcfg_config[i];
  		if (cfg->end_bus_number < cfg->start_bus_number)
  			cfg->end_bus_number = 255;
  	}
  
  	/* don't overlap please */
  	for (i = 0; i < pci_mmcfg_config_num - 1; i++) {
  		cfg = &pci_mmcfg_config[i];
  		cfgx = &pci_mmcfg_config[i+1];
  
  		if (cfg->end_bus_number < cfg->start_bus_number)
  			cfg->end_bus_number = 255;
  
  		if (cfg->end_bus_number >= cfgx->start_bus_number)
  			cfg->end_bus_number = cfgx->start_bus_number - 1;
  	}
  }
9358c693c   Olivier Galibert   [PATCH] mmconfig:...
283
284
285
  static int __init pci_mmcfg_check_hostbridge(void)
  {
  	u32 l;
7fd0da408   Yinghai Lu   x86_64: check MSR...
286
  	u32 bus, devfn;
9358c693c   Olivier Galibert   [PATCH] mmconfig:...
287
288
289
  	u16 vendor, device;
  	int i;
  	const char *name;
bb63b4219   Yinghai Lu   x86 pci: remove c...
290
291
  	if (!raw_pci_ops)
  		return 0;
9358c693c   Olivier Galibert   [PATCH] mmconfig:...
292
293
  	pci_mmcfg_config_num = 0;
  	pci_mmcfg_config = NULL;
9358c693c   Olivier Galibert   [PATCH] mmconfig:...
294

068258bc1   Yinghai Lu   x86/PCI: host mmc...
295
  	for (i = 0; i < ARRAY_SIZE(pci_mmcfg_probes); i++) {
7fd0da408   Yinghai Lu   x86_64: check MSR...
296
297
  		bus =  pci_mmcfg_probes[i].bus;
  		devfn = pci_mmcfg_probes[i].devfn;
bb63b4219   Yinghai Lu   x86 pci: remove c...
298
  		raw_pci_ops->read(0, bus, devfn, 0, 4, &l);
7fd0da408   Yinghai Lu   x86_64: check MSR...
299
300
  		vendor = l & 0xffff;
  		device = (l >> 16) & 0xffff;
068258bc1   Yinghai Lu   x86/PCI: host mmc...
301
  		name = NULL;
429d512e5   OGAWA Hirofumi   [PATCH] mmconfig:...
302
303
  		if (pci_mmcfg_probes[i].vendor == vendor &&
  		    pci_mmcfg_probes[i].device == device)
9358c693c   Olivier Galibert   [PATCH] mmconfig:...
304
  			name = pci_mmcfg_probes[i].probe();
068258bc1   Yinghai Lu   x86/PCI: host mmc...
305
306
307
308
  		if (name)
  			printk(KERN_INFO "PCI: Found %s with MMCONFIG support.
  ",
  			       name);
9358c693c   Olivier Galibert   [PATCH] mmconfig:...
309
  	}
068258bc1   Yinghai Lu   x86/PCI: host mmc...
310
311
312
313
  	/* some end_bus_number is crazy, fix it */
  	pci_mmcfg_check_end_bus_number();
  
  	return pci_mmcfg_config_num != 0;
9358c693c   Olivier Galibert   [PATCH] mmconfig:...
314
  }
ebd60cd64   Yinghai Lu   x86: unify using ...
315
  static void __init pci_mmcfg_insert_resources(void)
6a0668fc4   Olivier Galibert   [PATCH] mmconfig:...
316
  {
068258bc1   Yinghai Lu   x86/PCI: host mmc...
317
  #define PCI_MMCFG_RESOURCE_NAME_LEN 24
6a0668fc4   Olivier Galibert   [PATCH] mmconfig:...
318
319
320
321
322
323
324
  	int i;
  	struct resource *res;
  	char *names;
  	unsigned num_buses;
  
  	res = kcalloc(PCI_MMCFG_RESOURCE_NAME_LEN + sizeof(*res),
  			pci_mmcfg_config_num, GFP_KERNEL);
6a0668fc4   Olivier Galibert   [PATCH] mmconfig:...
325
326
327
328
329
330
331
332
  	if (!res) {
  		printk(KERN_ERR "PCI: Unable to allocate MMCONFIG resources
  ");
  		return;
  	}
  
  	names = (void *)&res[pci_mmcfg_config_num];
  	for (i = 0; i < pci_mmcfg_config_num; i++, res++) {
429d512e5   OGAWA Hirofumi   [PATCH] mmconfig:...
333
334
  		struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[i];
  		num_buses = cfg->end_bus_number - cfg->start_bus_number + 1;
6a0668fc4   Olivier Galibert   [PATCH] mmconfig:...
335
  		res->name = names;
068258bc1   Yinghai Lu   x86/PCI: host mmc...
336
337
338
339
  		snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN,
  			 "PCI MMCONFIG %u [%02x-%02x]", cfg->pci_segment,
  			 cfg->start_bus_number, cfg->end_bus_number);
  		res->start = cfg->address + (cfg->start_bus_number << 20);
6a0668fc4   Olivier Galibert   [PATCH] mmconfig:...
340
  		res->end = res->start + (num_buses << 20) - 1;
ebd60cd64   Yinghai Lu   x86: unify using ...
341
  		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
6a0668fc4   Olivier Galibert   [PATCH] mmconfig:...
342
343
344
  		insert_resource(&iomem_resource, res);
  		names += PCI_MMCFG_RESOURCE_NAME_LEN;
  	}
a5ba79710   Aaron Durbin   i386: insert uncl...
345
346
347
  
  	/* Mark that the resources have been inserted. */
  	pci_mmcfg_resources_inserted = 1;
6a0668fc4   Olivier Galibert   [PATCH] mmconfig:...
348
  }
7752d5cfe   Robert Hancock   x86: validate aga...
349
350
351
352
353
354
355
356
357
358
359
360
361
  static acpi_status __init check_mcfg_resource(struct acpi_resource *res,
  					      void *data)
  {
  	struct resource *mcfg_res = data;
  	struct acpi_resource_address64 address;
  	acpi_status status;
  
  	if (res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) {
  		struct acpi_resource_fixed_memory32 *fixmem32 =
  			&res->data.fixed_memory32;
  		if (!fixmem32)
  			return AE_OK;
  		if ((mcfg_res->start >= fixmem32->address) &&
75e613cdc   Yinghai Lu   x86/pci: fix mmco...
362
  		    (mcfg_res->end < (fixmem32->address +
7752d5cfe   Robert Hancock   x86: validate aga...
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
  				      fixmem32->address_length))) {
  			mcfg_res->flags = 1;
  			return AE_CTRL_TERMINATE;
  		}
  	}
  	if ((res->type != ACPI_RESOURCE_TYPE_ADDRESS32) &&
  	    (res->type != ACPI_RESOURCE_TYPE_ADDRESS64))
  		return AE_OK;
  
  	status = acpi_resource_to_address64(res, &address);
  	if (ACPI_FAILURE(status) ||
  	   (address.address_length <= 0) ||
  	   (address.resource_type != ACPI_MEMORY_RANGE))
  		return AE_OK;
  
  	if ((mcfg_res->start >= address.minimum) &&
75e613cdc   Yinghai Lu   x86/pci: fix mmco...
379
  	    (mcfg_res->end < (address.minimum + address.address_length))) {
7752d5cfe   Robert Hancock   x86: validate aga...
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
  		mcfg_res->flags = 1;
  		return AE_CTRL_TERMINATE;
  	}
  	return AE_OK;
  }
  
  static acpi_status __init find_mboard_resource(acpi_handle handle, u32 lvl,
  		void *context, void **rv)
  {
  	struct resource *mcfg_res = context;
  
  	acpi_walk_resources(handle, METHOD_NAME__CRS,
  			    check_mcfg_resource, context);
  
  	if (mcfg_res->flags)
  		return AE_CTRL_TERMINATE;
  
  	return AE_OK;
  }
a83fe32fa   Yinghai Lu   x86, pci: detect ...
399
  static int __init is_acpi_reserved(u64 start, u64 end, unsigned not_used)
7752d5cfe   Robert Hancock   x86: validate aga...
400
401
402
403
  {
  	struct resource mcfg_res;
  
  	mcfg_res.start = start;
75e613cdc   Yinghai Lu   x86/pci: fix mmco...
404
  	mcfg_res.end = end - 1;
7752d5cfe   Robert Hancock   x86: validate aga...
405
406
407
408
409
410
411
412
413
414
  	mcfg_res.flags = 0;
  
  	acpi_get_devices("PNP0C01", find_mboard_resource, &mcfg_res, NULL);
  
  	if (!mcfg_res.flags)
  		acpi_get_devices("PNP0C02", find_mboard_resource, &mcfg_res,
  				 NULL);
  
  	return mcfg_res.flags;
  }
a83fe32fa   Yinghai Lu   x86, pci: detect ...
415
416
417
418
419
420
421
422
  typedef int (*check_reserved_t)(u64 start, u64 end, unsigned type);
  
  static int __init is_mmconf_reserved(check_reserved_t is_reserved,
  		u64 addr, u64 size, int i,
  		typeof(pci_mmcfg_config[0]) *cfg, int with_e820)
  {
  	u64 old_size = size;
  	int valid = 0;
044cd8094   Yinghai Lu   x86/PCI: don't ca...
423
  	while (!is_reserved(addr, addr + size, E820_RESERVED)) {
a83fe32fa   Yinghai Lu   x86, pci: detect ...
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
  		size >>= 1;
  		if (size < (16UL<<20))
  			break;
  	}
  
  	if (size >= (16UL<<20) || size == old_size) {
  		printk(KERN_NOTICE
  		       "PCI: MCFG area at %Lx reserved in %s
  ",
  			addr, with_e820?"E820":"ACPI motherboard resources");
  		valid = 1;
  
  		if (old_size != size) {
  			/* update end_bus_number */
  			cfg->end_bus_number = cfg->start_bus_number + ((size>>20) - 1);
  			printk(KERN_NOTICE "PCI: updated MCFG configuration %d: base %lx "
  			       "segment %hu buses %u - %u
  ",
  			       i, (unsigned long)cfg->address, cfg->pci_segment,
  			       (unsigned int)cfg->start_bus_number,
  			       (unsigned int)cfg->end_bus_number);
  		}
  	}
  
  	return valid;
  }
bb63b4219   Yinghai Lu   x86 pci: remove c...
450
  static void __init pci_mmcfg_reject_broken(int early)
44de0203f   OGAWA Hirofumi   [PATCH] mmconfig:...
451
  {
26054ed02   OGAWA Hirofumi   [PATCH] mmconfig:...
452
  	typeof(pci_mmcfg_config[0]) *cfg;
7752d5cfe   Robert Hancock   x86: validate aga...
453
  	int i;
26054ed02   OGAWA Hirofumi   [PATCH] mmconfig:...
454
455
456
457
458
  
  	if ((pci_mmcfg_config_num == 0) ||
  	    (pci_mmcfg_config == NULL) ||
  	    (pci_mmcfg_config[0].address == 0))
  		return;
7752d5cfe   Robert Hancock   x86: validate aga...
459
  	for (i = 0; i < pci_mmcfg_config_num; i++) {
05c58b8ac   Yinghai Lu   x86: mmconf enabl...
460
  		int valid = 0;
a83fe32fa   Yinghai Lu   x86, pci: detect ...
461
  		u64 addr, size;
7752d5cfe   Robert Hancock   x86: validate aga...
462
  		cfg = &pci_mmcfg_config[i];
a83fe32fa   Yinghai Lu   x86, pci: detect ...
463
464
465
466
467
  		addr = cfg->start_bus_number;
  		addr <<= 20;
  		addr += cfg->address;
  		size = cfg->end_bus_number + 1 - cfg->start_bus_number;
  		size <<= 20;
05c58b8ac   Yinghai Lu   x86: mmconf enabl...
468
  		printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx "
7752d5cfe   Robert Hancock   x86: validate aga...
469
470
471
472
473
  		       "segment %hu buses %u - %u
  ",
  		       i, (unsigned long)cfg->address, cfg->pci_segment,
  		       (unsigned int)cfg->start_bus_number,
  		       (unsigned int)cfg->end_bus_number);
05c58b8ac   Yinghai Lu   x86: mmconf enabl...
474

5f0db7a2f   Feng Tang   SFI: Hook PCI MMC...
475
  		if (!early && !acpi_disabled)
a83fe32fa   Yinghai Lu   x86, pci: detect ...
476
  			valid = is_mmconf_reserved(is_acpi_reserved, addr, size, i, cfg, 0);
05c58b8ac   Yinghai Lu   x86: mmconf enabl...
477
478
479
480
481
  
  		if (valid)
  			continue;
  
  		if (!early)
7752d5cfe   Robert Hancock   x86: validate aga...
482
483
484
485
  			printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not"
  			       " reserved in ACPI motherboard resources
  ",
  			       cfg->address);
a83fe32fa   Yinghai Lu   x86, pci: detect ...
486

05c58b8ac   Yinghai Lu   x86: mmconf enabl...
487
  		/* Don't try to do this check unless configuration
bb63b4219   Yinghai Lu   x86 pci: remove c...
488
  		   type 1 is available. how about type 2 ?*/
a83fe32fa   Yinghai Lu   x86, pci: detect ...
489
490
  		if (raw_pci_ops)
  			valid = is_mmconf_reserved(e820_all_mapped, addr, size, i, cfg, 1);
05c58b8ac   Yinghai Lu   x86: mmconf enabl...
491
492
493
  
  		if (!valid)
  			goto reject;
44de0203f   OGAWA Hirofumi   [PATCH] mmconfig:...
494
  	}
7752d5cfe   Robert Hancock   x86: validate aga...
495

26054ed02   OGAWA Hirofumi   [PATCH] mmconfig:...
496
497
498
  	return;
  
  reject:
ef3102374   Dave Jones   x86: silence mmco...
499
500
  	printk(KERN_INFO "PCI: Not using MMCONFIG.
  ");
0b64ad712   Yinghai Lu   x86: clear pci_mm...
501
  	pci_mmcfg_arch_free();
26054ed02   OGAWA Hirofumi   [PATCH] mmconfig:...
502
503
504
  	kfree(pci_mmcfg_config);
  	pci_mmcfg_config = NULL;
  	pci_mmcfg_config_num = 0;
44de0203f   OGAWA Hirofumi   [PATCH] mmconfig:...
505
  }
05c58b8ac   Yinghai Lu   x86: mmconf enabl...
506
  static int __initdata known_bridge;
7752d5cfe   Robert Hancock   x86: validate aga...
507

c4bf2f372   Len Brown   ACPI, PCI, x86: m...
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
  static int acpi_mcfg_64bit_base_addr __initdata = FALSE;
  
  /* The physical address of the MMCONFIG aperture.  Set from ACPI tables. */
  struct acpi_mcfg_allocation *pci_mmcfg_config;
  int pci_mmcfg_config_num;
  
  static int __init acpi_mcfg_oem_check(struct acpi_table_mcfg *mcfg)
  {
  	if (!strcmp(mcfg->header.oem_id, "SGI"))
  		acpi_mcfg_64bit_base_addr = TRUE;
  
  	return 0;
  }
  
  static int __init pci_parse_mcfg(struct acpi_table_header *header)
  {
  	struct acpi_table_mcfg *mcfg;
  	unsigned long i;
  	int config_size;
  
  	if (!header)
  		return -EINVAL;
  
  	mcfg = (struct acpi_table_mcfg *)header;
  
  	/* how many config structures do we have */
  	pci_mmcfg_config_num = 0;
  	i = header->length - sizeof(struct acpi_table_mcfg);
  	while (i >= sizeof(struct acpi_mcfg_allocation)) {
  		++pci_mmcfg_config_num;
  		i -= sizeof(struct acpi_mcfg_allocation);
  	};
  	if (pci_mmcfg_config_num == 0) {
  		printk(KERN_ERR PREFIX "MMCONFIG has no entries
  ");
  		return -ENODEV;
  	}
  
  	config_size = pci_mmcfg_config_num * sizeof(*pci_mmcfg_config);
  	pci_mmcfg_config = kmalloc(config_size, GFP_KERNEL);
  	if (!pci_mmcfg_config) {
  		printk(KERN_WARNING PREFIX
  		       "No memory for MCFG config tables
  ");
  		return -ENOMEM;
  	}
  
  	memcpy(pci_mmcfg_config, &mcfg[1], config_size);
  
  	acpi_mcfg_oem_check(mcfg);
  
  	for (i = 0; i < pci_mmcfg_config_num; ++i) {
  		if ((pci_mmcfg_config[i].address > 0xFFFFFFFF) &&
  		    !acpi_mcfg_64bit_base_addr) {
  			printk(KERN_ERR PREFIX
  			       "MMCONFIG not in low 4GB of memory
  ");
  			kfree(pci_mmcfg_config);
  			pci_mmcfg_config_num = 0;
  			return -ENODEV;
  		}
  	}
  
  	return 0;
  }
968cbfad1   Thomas Gleixner   x86: make __pci_m...
573
  static void __init __pci_mmcfg_init(int early)
b78673944   Olivier Galibert   [PATCH] mmconfig:...
574
  {
7752d5cfe   Robert Hancock   x86: validate aga...
575
  	/* MMCONFIG disabled */
b78673944   Olivier Galibert   [PATCH] mmconfig:...
576
577
  	if ((pci_probe & PCI_PROBE_MMCONF) == 0)
  		return;
7752d5cfe   Robert Hancock   x86: validate aga...
578
  	/* MMCONFIG already enabled */
05c58b8ac   Yinghai Lu   x86: mmconf enabl...
579
  	if (!early && !(pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF))
7752d5cfe   Robert Hancock   x86: validate aga...
580
  		return;
9358c693c   Olivier Galibert   [PATCH] mmconfig:...
581

05c58b8ac   Yinghai Lu   x86: mmconf enabl...
582
583
584
  	/* for late to exit */
  	if (known_bridge)
  		return;
7752d5cfe   Robert Hancock   x86: validate aga...
585

bb63b4219   Yinghai Lu   x86 pci: remove c...
586
  	if (early) {
05c58b8ac   Yinghai Lu   x86: mmconf enabl...
587
588
589
  		if (pci_mmcfg_check_hostbridge())
  			known_bridge = 1;
  	}
068258bc1   Yinghai Lu   x86/PCI: host mmc...
590
  	if (!known_bridge)
5f0db7a2f   Feng Tang   SFI: Hook PCI MMC...
591
  		acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
068258bc1   Yinghai Lu   x86/PCI: host mmc...
592
593
  
  	pci_mmcfg_reject_broken(early);
b78673944   Olivier Galibert   [PATCH] mmconfig:...
594
595
596
597
598
  
  	if ((pci_mmcfg_config_num == 0) ||
  	    (pci_mmcfg_config == NULL) ||
  	    (pci_mmcfg_config[0].address == 0))
  		return;
ebd60cd64   Yinghai Lu   x86: unify using ...
599
  	if (pci_mmcfg_arch_init())
b78673944   Olivier Galibert   [PATCH] mmconfig:...
600
  		pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
ebd60cd64   Yinghai Lu   x86: unify using ...
601
  	else {
a5ba79710   Aaron Durbin   i386: insert uncl...
602
603
604
605
606
  		/*
  		 * Signal not to attempt to insert mmcfg resources because
  		 * the architecture mmcfg setup could not initialize.
  		 */
  		pci_mmcfg_resources_inserted = 1;
b78673944   Olivier Galibert   [PATCH] mmconfig:...
607
608
  	}
  }
a5ba79710   Aaron Durbin   i386: insert uncl...
609

bb63b4219   Yinghai Lu   x86 pci: remove c...
610
  void __init pci_mmcfg_early_init(void)
05c58b8ac   Yinghai Lu   x86: mmconf enabl...
611
  {
bb63b4219   Yinghai Lu   x86 pci: remove c...
612
  	__pci_mmcfg_init(1);
05c58b8ac   Yinghai Lu   x86: mmconf enabl...
613
614
615
616
  }
  
  void __init pci_mmcfg_late_init(void)
  {
bb63b4219   Yinghai Lu   x86 pci: remove c...
617
  	__pci_mmcfg_init(0);
05c58b8ac   Yinghai Lu   x86: mmconf enabl...
618
  }
a5ba79710   Aaron Durbin   i386: insert uncl...
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
  static int __init pci_mmcfg_late_insert_resources(void)
  {
  	/*
  	 * If resources are already inserted or we are not using MMCONFIG,
  	 * don't insert the resources.
  	 */
  	if ((pci_mmcfg_resources_inserted == 1) ||
  	    (pci_probe & PCI_PROBE_MMCONF) == 0 ||
  	    (pci_mmcfg_config_num == 0) ||
  	    (pci_mmcfg_config == NULL) ||
  	    (pci_mmcfg_config[0].address == 0))
  		return 1;
  
  	/*
  	 * Attempt to insert the mmcfg resources but not with the busy flag
  	 * marked so it won't cause request errors when __request_region is
  	 * called.
  	 */
ebd60cd64   Yinghai Lu   x86: unify using ...
637
  	pci_mmcfg_insert_resources();
a5ba79710   Aaron Durbin   i386: insert uncl...
638
639
640
641
642
643
644
645
646
647
  
  	return 0;
  }
  
  /*
   * Perform MMCONFIG resource insertion after PCI initialization to allow for
   * misprogrammed MCFG tables that state larger sizes but actually conflict
   * with other system resources.
   */
  late_initcall(pci_mmcfg_late_insert_resources);