mpparse.c 25.4 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2
 *	Intel Multiprocessor Specification 1.1 and 1.4
L
Linus Torvalds 已提交
3 4
 *	compliant MP-table parsing routines.
 *
5
 *	(c) 1995 Alan Cox, Building #3 <alan@lxorguk.ukuu.org.uk>
I
Ingo Molnar 已提交
6
 *	(c) 1998, 1999, 2000, 2009 Ingo Molnar <mingo@redhat.com>
7
 *      (c) 2008 Alexey Starikovskiy <astarikovskiy@suse.de>
L
Linus Torvalds 已提交
8 9 10 11 12 13 14 15 16
 */

#include <linux/mm.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/bootmem.h>
#include <linux/kernel_stat.h>
#include <linux/mc146818rtc.h>
#include <linux/bitops.h>
17 18
#include <linux/acpi.h>
#include <linux/module.h>
19
#include <linux/smp.h>
L
Linus Torvalds 已提交
20 21 22

#include <asm/mtrr.h>
#include <asm/mpspec.h>
23
#include <asm/pgalloc.h>
L
Linus Torvalds 已提交
24
#include <asm/io_apic.h>
25
#include <asm/proto.h>
26
#include <asm/bios_ebda.h>
Y
Yinghai Lu 已提交
27 28
#include <asm/e820.h>
#include <asm/trampoline.h>
Y
Yinghai Lu 已提交
29
#include <asm/setup.h>
30
#include <asm/smp.h>
L
Linus Torvalds 已提交
31

I
Ingo Molnar 已提交
32
#include <asm/apic.h>
L
Linus Torvalds 已提交
33 34 35 36 37 38 39 40 41 42 43 44 45 46
/*
 * Checksum an MP configuration block.
 */

static int __init mpf_checksum(unsigned char *mp, int len)
{
	int sum = 0;

	while (len--)
		sum += *mp++;

	return sum & 0xFF;
}

47
static void __init MP_processor_info(struct mpc_cpu *m)
48 49
{
	int apicid;
50
	char *bootup_cpu = "";
51

52
	if (!(m->cpuflag & CPU_ENABLED)) {
G
Glauber Costa 已提交
53
		disabled_cpus++;
L
Linus Torvalds 已提交
54
		return;
G
Glauber Costa 已提交
55
	}
56 57 58

	if (x86_quirks->mpc_apic_id)
		apicid = x86_quirks->mpc_apic_id(m);
59
	else
60
		apicid = m->apicid;
61

62
	if (m->cpuflag & CPU_BOOTPROCESSOR) {
63
		bootup_cpu = " (Bootup-CPU)";
64
		boot_cpu_physical_apicid = m->apicid;
L
Linus Torvalds 已提交
65 66
	}

67 68
	printk(KERN_INFO "Processor #%d%s\n", m->apicid, bootup_cpu);
	generic_processor_info(apicid, m->apicver);
L
Linus Torvalds 已提交
69 70
}

T
Thomas Gleixner 已提交
71
#ifdef CONFIG_X86_IO_APIC
72
static void __init MP_bus_info(struct mpc_bus *m)
L
Linus Torvalds 已提交
73 74
{
	char str[7];
75
	memcpy(str, m->bustype, 6);
L
Linus Torvalds 已提交
76 77
	str[6] = 0;

78 79 80
	if (x86_quirks->mpc_oem_bus_info)
		x86_quirks->mpc_oem_bus_info(m, str);
	else
81
		apic_printk(APIC_VERBOSE, "Bus #%d is %s\n", m->busid, str);
L
Linus Torvalds 已提交
82

83
#if MAX_MP_BUSSES < 256
84
	if (m->busid >= MAX_MP_BUSSES) {
85
		printk(KERN_WARNING "MP table busid value (%d) for bustype %s "
A
Alexey Starikovskiy 已提交
86
		       " is too large, max. supported is %d\n",
87
		       m->busid, str, MAX_MP_BUSSES - 1);
88 89
		return;
	}
90
#endif
91

A
Alexey Starikovskiy 已提交
92
	if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA) - 1) == 0) {
93
		set_bit(m->busid, mp_bus_not_pci);
94
#if defined(CONFIG_EISA) || defined(CONFIG_MCA)
95
		mp_bus_id_to_type[m->busid] = MP_BUS_ISA;
A
Alexey Starikovskiy 已提交
96 97
#endif
	} else if (strncmp(str, BUSTYPE_PCI, sizeof(BUSTYPE_PCI) - 1) == 0) {
98 99 100
		if (x86_quirks->mpc_oem_pci_bus)
			x86_quirks->mpc_oem_pci_bus(m);

101
		clear_bit(m->busid, mp_bus_not_pci);
102
#if defined(CONFIG_EISA) || defined(CONFIG_MCA)
103
		mp_bus_id_to_type[m->busid] = MP_BUS_PCI;
A
Alexey Starikovskiy 已提交
104
	} else if (strncmp(str, BUSTYPE_EISA, sizeof(BUSTYPE_EISA) - 1) == 0) {
105
		mp_bus_id_to_type[m->busid] = MP_BUS_EISA;
A
Alexey Starikovskiy 已提交
106
	} else if (strncmp(str, BUSTYPE_MCA, sizeof(BUSTYPE_MCA) - 1) == 0) {
107
		mp_bus_id_to_type[m->busid] = MP_BUS_MCA;
108
#endif
A
Alexey Starikovskiy 已提交
109 110
	} else
		printk(KERN_WARNING "Unknown bustype %s - ignoring\n", str);
L
Linus Torvalds 已提交
111
}
T
Thomas Gleixner 已提交
112
#endif
L
Linus Torvalds 已提交
113

114 115
#ifdef CONFIG_X86_IO_APIC

116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
static int bad_ioapic(unsigned long address)
{
	if (nr_ioapics >= MAX_IO_APICS) {
		printk(KERN_ERR "ERROR: Max # of I/O APICs (%d) exceeded "
		       "(found %d)\n", MAX_IO_APICS, nr_ioapics);
		panic("Recompile kernel with bigger MAX_IO_APICS!\n");
	}
	if (!address) {
		printk(KERN_ERR "WARNING: Bogus (zero) I/O APIC address"
		       " found in table, skipping!\n");
		return 1;
	}
	return 0;
}

131
static void __init MP_ioapic_info(struct mpc_ioapic *m)
L
Linus Torvalds 已提交
132
{
133
	if (!(m->flags & MPC_APIC_USABLE))
L
Linus Torvalds 已提交
134 135
		return;

T
Thomas Gleixner 已提交
136
	printk(KERN_INFO "I/O APIC #%d Version %d at 0x%X.\n",
137
	       m->apicid, m->apicver, m->apicaddr);
138

139
	if (bad_ioapic(m->apicaddr))
L
Linus Torvalds 已提交
140
		return;
141

142 143 144 145 146
	mp_ioapics[nr_ioapics].apicaddr = m->apicaddr;
	mp_ioapics[nr_ioapics].apicid = m->apicid;
	mp_ioapics[nr_ioapics].type = m->type;
	mp_ioapics[nr_ioapics].apicver = m->apicver;
	mp_ioapics[nr_ioapics].flags = m->flags;
L
Linus Torvalds 已提交
147 148 149
	nr_ioapics++;
}

150
static void print_MP_intsrc_info(struct mpc_intsrc *m)
L
Linus Torvalds 已提交
151
{
152
	apic_printk(APIC_VERBOSE, "Int: type %d, pol %d, trig %d, bus %02x,"
L
Linus Torvalds 已提交
153
		" IRQ %02x, APIC ID %x, APIC INT %02x\n",
154 155
		m->irqtype, m->irqflag & 3, (m->irqflag >> 2) & 3, m->srcbus,
		m->srcbusirq, m->dstapic, m->dstirq);
Y
Yinghai Lu 已提交
156 157
}

158
static void __init print_mp_irq_info(struct mpc_intsrc *mp_irq)
Y
Yinghai Lu 已提交
159
{
160
	apic_printk(APIC_VERBOSE, "Int: type %d, pol %d, trig %d, bus %02x,"
Y
Yinghai Lu 已提交
161
		" IRQ %02x, APIC ID %x, APIC INT %02x\n",
162 163 164
		mp_irq->irqtype, mp_irq->irqflag & 3,
		(mp_irq->irqflag >> 2) & 3, mp_irq->srcbus,
		mp_irq->srcbusirq, mp_irq->dstapic, mp_irq->dstirq);
Y
Yinghai Lu 已提交
165 166
}

167
static void __init assign_to_mp_irq(struct mpc_intsrc *m,
168
				    struct mpc_intsrc *mp_irq)
Y
Yinghai Lu 已提交
169
{
170 171 172 173 174 175 176
	mp_irq->dstapic = m->dstapic;
	mp_irq->type = m->type;
	mp_irq->irqtype = m->irqtype;
	mp_irq->irqflag = m->irqflag;
	mp_irq->srcbus = m->srcbus;
	mp_irq->srcbusirq = m->srcbusirq;
	mp_irq->dstirq = m->dstirq;
Y
Yinghai Lu 已提交
177 178
}

179
static void __init assign_to_mpc_intsrc(struct mpc_intsrc *mp_irq,
180
					struct mpc_intsrc *m)
Y
Yinghai Lu 已提交
181
{
182 183 184 185 186 187 188
	m->dstapic = mp_irq->dstapic;
	m->type = mp_irq->type;
	m->irqtype = mp_irq->irqtype;
	m->irqflag = mp_irq->irqflag;
	m->srcbus = mp_irq->srcbus;
	m->srcbusirq = mp_irq->srcbusirq;
	m->dstirq = mp_irq->dstirq;
Y
Yinghai Lu 已提交
189 190
}

191
static int __init mp_irq_mpc_intsrc_cmp(struct mpc_intsrc *mp_irq,
192
					struct mpc_intsrc *m)
Y
Yinghai Lu 已提交
193
{
194
	if (mp_irq->dstapic != m->dstapic)
Y
Yinghai Lu 已提交
195
		return 1;
196
	if (mp_irq->type != m->type)
Y
Yinghai Lu 已提交
197
		return 2;
198
	if (mp_irq->irqtype != m->irqtype)
Y
Yinghai Lu 已提交
199
		return 3;
200
	if (mp_irq->irqflag != m->irqflag)
Y
Yinghai Lu 已提交
201
		return 4;
202
	if (mp_irq->srcbus != m->srcbus)
Y
Yinghai Lu 已提交
203
		return 5;
204
	if (mp_irq->srcbusirq != m->srcbusirq)
Y
Yinghai Lu 已提交
205
		return 6;
206
	if (mp_irq->dstirq != m->dstirq)
Y
Yinghai Lu 已提交
207 208 209 210 211
		return 7;

	return 0;
}

212
static void __init MP_intsrc_info(struct mpc_intsrc *m)
Y
Yinghai Lu 已提交
213 214 215 216 217
{
	int i;

	print_MP_intsrc_info(m);

218 219 220 221
	for (i = 0; i < mp_irq_entries; i++) {
		if (!mp_irq_mpc_intsrc_cmp(&mp_irqs[i], m))
			return;
	}
Y
Yinghai Lu 已提交
222 223

	assign_to_mp_irq(m, &mp_irqs[mp_irq_entries]);
L
Linus Torvalds 已提交
224 225 226 227
	if (++mp_irq_entries == MAX_IRQ_SOURCES)
		panic("Max # of irq sources exceeded!!\n");
}

228 229
#endif

230
static void __init MP_lintsrc_info(struct mpc_lintsrc *m)
L
Linus Torvalds 已提交
231
{
232
	apic_printk(APIC_VERBOSE, "Lint: type %d, pol %d, trig %d, bus %02x,"
L
Linus Torvalds 已提交
233
		" IRQ %02x, APIC ID %x, APIC LINT %02x\n",
234 235
		m->irqtype, m->irqflag & 3, (m->irqflag >> 2) & 3, m->srcbusid,
		m->srcbusirq, m->destapic, m->destapiclint);
L
Linus Torvalds 已提交
236 237 238 239 240 241
}

/*
 * Read/parse the MPC
 */

242
static int __init smp_check_mpc(struct mpc_table *mpc, char *oem, char *str)
L
Linus Torvalds 已提交
243 244
{

245
	if (memcmp(mpc->signature, MPC_SIGNATURE, 4)) {
A
Alexey Starikovskiy 已提交
246
		printk(KERN_ERR "MPTABLE: bad signature [%c%c%c%c]!\n",
247 248
		       mpc->signature[0], mpc->signature[1],
		       mpc->signature[2], mpc->signature[3]);
L
Linus Torvalds 已提交
249 250
		return 0;
	}
251
	if (mpf_checksum((unsigned char *)mpc, mpc->length)) {
A
Alexey Starikovskiy 已提交
252
		printk(KERN_ERR "MPTABLE: checksum error!\n");
L
Linus Torvalds 已提交
253 254
		return 0;
	}
255
	if (mpc->spec != 0x01 && mpc->spec != 0x04) {
A
Alexey Starikovskiy 已提交
256
		printk(KERN_ERR "MPTABLE: bad table version (%d)!!\n",
257
		       mpc->spec);
L
Linus Torvalds 已提交
258 259
		return 0;
	}
260
	if (!mpc->lapic) {
A
Alexey Starikovskiy 已提交
261
		printk(KERN_ERR "MPTABLE: null local APIC address!\n");
L
Linus Torvalds 已提交
262 263
		return 0;
	}
264
	memcpy(oem, mpc->oem, 8);
A
Alexey Starikovskiy 已提交
265
	oem[8] = 0;
Y
Yinghai Lu 已提交
266
	printk(KERN_INFO "MPTABLE: OEM ID: %s\n", oem);
L
Linus Torvalds 已提交
267

268
	memcpy(str, mpc->productid, 12);
A
Alexey Starikovskiy 已提交
269
	str[12] = 0;
L
Linus Torvalds 已提交
270

Y
Yinghai Lu 已提交
271
	printk(KERN_INFO "MPTABLE: Product ID: %s\n", str);
L
Linus Torvalds 已提交
272

273
	printk(KERN_INFO "MPTABLE: APIC at: 0x%X\n", mpc->lapic);
L
Linus Torvalds 已提交
274

Y
Yinghai Lu 已提交
275 276 277
	return 1;
}

278
static int __init smp_read_mpc(struct mpc_table *mpc, unsigned early)
Y
Yinghai Lu 已提交
279 280 281 282 283 284 285 286 287 288 289
{
	char str[16];
	char oem[10];

	int count = sizeof(*mpc);
	unsigned char *mpt = ((unsigned char *)mpc) + count;

	if (!smp_check_mpc(mpc, oem, str))
		return 0;

#ifdef CONFIG_X86_32
290
	generic_mps_oem_check(mpc, oem, str);
Y
Yinghai Lu 已提交
291
#endif
A
Alexey Starikovskiy 已提交
292
	/* save the local APIC address, it might be non-default */
L
Linus Torvalds 已提交
293
	if (!acpi_lapic)
294
		mp_lapic_addr = mpc->lapic;
L
Linus Torvalds 已提交
295

296 297 298
	if (early)
		return 1;

299 300 301
	if (mpc->oemptr && x86_quirks->smp_read_mpc_oem) {
		struct mpc_oemtable *oem_table = (void *)(long)mpc->oemptr;
		x86_quirks->smp_read_mpc_oem(oem_table, mpc->oemsize);
302 303
	}

L
Linus Torvalds 已提交
304
	/*
A
Alexey Starikovskiy 已提交
305
	 *      Now process the configuration blocks.
L
Linus Torvalds 已提交
306
	 */
307 308 309
	if (x86_quirks->mpc_record)
		*x86_quirks->mpc_record = 0;

310
	while (count < mpc->length) {
A
Alexey Starikovskiy 已提交
311 312
		switch (*mpt) {
		case MP_PROCESSOR:
L
Linus Torvalds 已提交
313
			{
314
				struct mpc_cpu *m = (struct mpc_cpu *)mpt;
L
Linus Torvalds 已提交
315 316 317 318 319 320 321
				/* ACPI may have already provided this data */
				if (!acpi_lapic)
					MP_processor_info(m);
				mpt += sizeof(*m);
				count += sizeof(*m);
				break;
			}
A
Alexey Starikovskiy 已提交
322
		case MP_BUS:
L
Linus Torvalds 已提交
323
			{
324
				struct mpc_bus *m = (struct mpc_bus *)mpt;
T
Thomas Gleixner 已提交
325
#ifdef CONFIG_X86_IO_APIC
L
Linus Torvalds 已提交
326
				MP_bus_info(m);
T
Thomas Gleixner 已提交
327
#endif
L
Linus Torvalds 已提交
328 329 330 331
				mpt += sizeof(*m);
				count += sizeof(*m);
				break;
			}
A
Alexey Starikovskiy 已提交
332
		case MP_IOAPIC:
L
Linus Torvalds 已提交
333
			{
334
#ifdef CONFIG_X86_IO_APIC
335
				struct mpc_ioapic *m = (struct mpc_ioapic *)mpt;
L
Linus Torvalds 已提交
336
				MP_ioapic_info(m);
337
#endif
338 339
				mpt += sizeof(struct mpc_ioapic);
				count += sizeof(struct mpc_ioapic);
L
Linus Torvalds 已提交
340 341
				break;
			}
A
Alexey Starikovskiy 已提交
342
		case MP_INTSRC:
L
Linus Torvalds 已提交
343
			{
344
#ifdef CONFIG_X86_IO_APIC
345
				struct mpc_intsrc *m = (struct mpc_intsrc *)mpt;
L
Linus Torvalds 已提交
346 347

				MP_intsrc_info(m);
348
#endif
349 350
				mpt += sizeof(struct mpc_intsrc);
				count += sizeof(struct mpc_intsrc);
L
Linus Torvalds 已提交
351 352
				break;
			}
A
Alexey Starikovskiy 已提交
353
		case MP_LINTSRC:
L
Linus Torvalds 已提交
354
			{
355 356
				struct mpc_lintsrc *m =
				    (struct mpc_lintsrc *)mpt;
L
Linus Torvalds 已提交
357
				MP_lintsrc_info(m);
A
Alexey Starikovskiy 已提交
358 359
				mpt += sizeof(*m);
				count += sizeof(*m);
L
Linus Torvalds 已提交
360 361
				break;
			}
A
Alexey Starikovskiy 已提交
362
		default:
Y
Yinghai Lu 已提交
363 364 365 366
			/* wrong mptable */
			printk(KERN_ERR "Your mptable is wrong, contact your HW vendor!\n");
			printk(KERN_ERR "type %x\n", *mpt);
			print_hex_dump(KERN_ERR, "  ", DUMP_PREFIX_ADDRESS, 16,
367 368
					1, mpc, mpc->length, 1);
			count = mpc->length;
Y
Yinghai Lu 已提交
369
			break;
L
Linus Torvalds 已提交
370
		}
371 372
		if (x86_quirks->mpc_record)
			(*x86_quirks->mpc_record)++;
L
Linus Torvalds 已提交
373
	}
374

375 376
#ifdef CONFIG_X86_BIGSMP
	generic_bigsmp_probe();
377 378
#endif

379 380 381
	if (apic->setup_apic_routing)
		apic->setup_apic_routing();

L
Linus Torvalds 已提交
382
	if (!num_processors)
A
Alexey Starikovskiy 已提交
383
		printk(KERN_ERR "MPTABLE: no processors registered!\n");
L
Linus Torvalds 已提交
384 385 386
	return num_processors;
}

387 388
#ifdef CONFIG_X86_IO_APIC

L
Linus Torvalds 已提交
389 390 391 392 393 394 395 396 397 398
static int __init ELCR_trigger(unsigned int irq)
{
	unsigned int port;

	port = 0x4d0 + (irq >> 3);
	return (inb(port) >> (irq & 7)) & 1;
}

static void __init construct_default_ioirq_mptable(int mpc_default_type)
{
399
	struct mpc_intsrc intsrc;
L
Linus Torvalds 已提交
400 401 402
	int i;
	int ELCR_fallback = 0;

403 404 405
	intsrc.type = MP_INTSRC;
	intsrc.irqflag = 0;	/* conforming */
	intsrc.srcbus = 0;
406
	intsrc.dstapic = mp_ioapics[0].apicid;
L
Linus Torvalds 已提交
407

408
	intsrc.irqtype = mp_INT;
L
Linus Torvalds 已提交
409 410 411 412 413 414 415 416 417 418

	/*
	 *  If true, we have an ISA/PCI system with no IRQ entries
	 *  in the MP table. To prevent the PCI interrupts from being set up
	 *  incorrectly, we try to use the ELCR. The sanity check to see if
	 *  there is good ELCR data is very simple - IRQ0, 1, 2 and 13 can
	 *  never be level sensitive, so we simply see if the ELCR agrees.
	 *  If it does, we assume it's valid.
	 */
	if (mpc_default_type == 5) {
419 420
		printk(KERN_INFO "ISA/PCI bus type with no IRQ information... "
		       "falling back to ELCR\n");
L
Linus Torvalds 已提交
421

422 423 424 425
		if (ELCR_trigger(0) || ELCR_trigger(1) || ELCR_trigger(2) ||
		    ELCR_trigger(13))
			printk(KERN_ERR "ELCR contains invalid data... "
			       "not using ELCR\n");
L
Linus Torvalds 已提交
426
		else {
A
Alexey Starikovskiy 已提交
427 428
			printk(KERN_INFO
			       "Using ELCR to identify PCI interrupts\n");
L
Linus Torvalds 已提交
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
			ELCR_fallback = 1;
		}
	}

	for (i = 0; i < 16; i++) {
		switch (mpc_default_type) {
		case 2:
			if (i == 0 || i == 13)
				continue;	/* IRQ0 & IRQ13 not connected */
			/* fall through */
		default:
			if (i == 2)
				continue;	/* IRQ2 is never connected */
		}

		if (ELCR_fallback) {
			/*
			 *  If the ELCR indicates a level-sensitive interrupt, we
			 *  copy that information over to the MP table in the
			 *  irqflag field (level sensitive, active high polarity).
			 */
			if (ELCR_trigger(i))
451
				intsrc.irqflag = 13;
L
Linus Torvalds 已提交
452
			else
453
				intsrc.irqflag = 0;
L
Linus Torvalds 已提交
454 455
		}

456 457
		intsrc.srcbusirq = i;
		intsrc.dstirq = i ? i : 2;	/* IRQ0 to INTIN2 */
L
Linus Torvalds 已提交
458 459 460
		MP_intsrc_info(&intsrc);
	}

461 462 463
	intsrc.irqtype = mp_ExtINT;
	intsrc.srcbusirq = 0;
	intsrc.dstirq = 0;	/* 8259A to INTIN0 */
L
Linus Torvalds 已提交
464 465 466
	MP_intsrc_info(&intsrc);
}

467

468
static void __init construct_ioapic_table(int mpc_default_type)
L
Linus Torvalds 已提交
469
{
470
	struct mpc_ioapic ioapic;
471
	struct mpc_bus bus;
L
Linus Torvalds 已提交
472

473 474
	bus.type = MP_BUS;
	bus.busid = 0;
L
Linus Torvalds 已提交
475
	switch (mpc_default_type) {
A
Alexey Starikovskiy 已提交
476
	default:
477
		printk(KERN_ERR "???\nUnknown standard configuration %d\n",
A
Alexey Starikovskiy 已提交
478 479 480 481
		       mpc_default_type);
		/* fall through */
	case 1:
	case 5:
482
		memcpy(bus.bustype, "ISA   ", 6);
A
Alexey Starikovskiy 已提交
483 484 485 486
		break;
	case 2:
	case 6:
	case 3:
487
		memcpy(bus.bustype, "EISA  ", 6);
A
Alexey Starikovskiy 已提交
488 489 490
		break;
	case 4:
	case 7:
491
		memcpy(bus.bustype, "MCA   ", 6);
L
Linus Torvalds 已提交
492 493 494
	}
	MP_bus_info(&bus);
	if (mpc_default_type > 4) {
495 496
		bus.busid = 1;
		memcpy(bus.bustype, "PCI   ", 6);
L
Linus Torvalds 已提交
497 498 499
		MP_bus_info(&bus);
	}

500 501 502 503 504
	ioapic.type = MP_IOAPIC;
	ioapic.apicid = 2;
	ioapic.apicver = mpc_default_type > 4 ? 0x10 : 0x01;
	ioapic.flags = MPC_APIC_USABLE;
	ioapic.apicaddr = 0xFEC00000;
L
Linus Torvalds 已提交
505 506 507 508 509 510
	MP_ioapic_info(&ioapic);

	/*
	 * We set up most of the low 16 IO-APIC pins according to MPS rules.
	 */
	construct_default_ioirq_mptable(mpc_default_type);
T
Thomas Gleixner 已提交
511 512
}
#else
513
static inline void __init construct_ioapic_table(int mpc_default_type) { }
514
#endif
T
Thomas Gleixner 已提交
515 516 517

static inline void __init construct_default_ISA_mptable(int mpc_default_type)
{
518
	struct mpc_cpu processor;
519
	struct mpc_lintsrc lintsrc;
T
Thomas Gleixner 已提交
520 521 522 523 524 525 526 527 528 529 530
	int linttypes[2] = { mp_ExtINT, mp_NMI };
	int i;

	/*
	 * local APIC has default address
	 */
	mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;

	/*
	 * 2 CPUs, numbered 0 & 1.
	 */
531
	processor.type = MP_PROCESSOR;
T
Thomas Gleixner 已提交
532
	/* Either an integrated APIC or a discrete 82489DX. */
533 534 535
	processor.apicver = mpc_default_type > 4 ? 0x10 : 0x01;
	processor.cpuflag = CPU_ENABLED;
	processor.cpufeature = (boot_cpu_data.x86 << 8) |
T
Thomas Gleixner 已提交
536
	    (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_mask;
537 538 539
	processor.featureflag = boot_cpu_data.x86_capability[0];
	processor.reserved[0] = 0;
	processor.reserved[1] = 0;
T
Thomas Gleixner 已提交
540
	for (i = 0; i < 2; i++) {
541
		processor.apicid = i;
T
Thomas Gleixner 已提交
542 543 544 545 546
		MP_processor_info(&processor);
	}

	construct_ioapic_table(mpc_default_type);

547 548 549 550 551
	lintsrc.type = MP_LINTSRC;
	lintsrc.irqflag = 0;		/* conforming */
	lintsrc.srcbusid = 0;
	lintsrc.srcbusirq = 0;
	lintsrc.destapic = MP_APIC_ALL;
L
Linus Torvalds 已提交
552
	for (i = 0; i < 2; i++) {
553 554
		lintsrc.irqtype = linttypes[i];
		lintsrc.destapiclint = i;
L
Linus Torvalds 已提交
555 556 557 558
		MP_lintsrc_info(&lintsrc);
	}
}

559
static struct mpf_intel *mpf_found;
L
Linus Torvalds 已提交
560

Y
Yinghai Lu 已提交
561 562 563 564 565 566 567 568 569 570 571 572 573
static unsigned long __init get_mpc_size(unsigned long physptr)
{
	struct mpc_table *mpc;
	unsigned long size;

	mpc = early_ioremap(physptr, PAGE_SIZE);
	size = mpc->length;
	early_iounmap(mpc, PAGE_SIZE);
	apic_printk(APIC_VERBOSE, "  mpc: %lx-%lx\n", physptr, physptr + size);

	return size;
}

L
Linus Torvalds 已提交
574 575 576
/*
 * Scan the memory blocks for an SMP configuration block.
 */
I
Ingo Molnar 已提交
577
static void __init __get_smp_config(unsigned int early)
L
Linus Torvalds 已提交
578
{
579
	struct mpf_intel *mpf = mpf_found;
L
Linus Torvalds 已提交
580

Y
Yinghai Lu 已提交
581 582 583
	if (!mpf)
		return;

584 585
	if (acpi_lapic && early)
		return;
Y
Yinghai Lu 已提交
586

L
Linus Torvalds 已提交
587
	/*
Y
Yinghai Lu 已提交
588 589
	 * MPS doesn't support hyperthreading, aka only have
	 * thread 0 apic id in MPS table
L
Linus Torvalds 已提交
590
	 */
Y
Yinghai Lu 已提交
591
	if (acpi_lapic && acpi_ioapic)
L
Linus Torvalds 已提交
592 593
		return;

Y
Yinghai Lu 已提交
594 595 596 597
	if (x86_quirks->mach_get_smp_config) {
		if (x86_quirks->mach_get_smp_config(early))
			return;
	}
598

A
Alexey Starikovskiy 已提交
599
	printk(KERN_INFO "Intel MultiProcessor Specification v1.%d\n",
600
	       mpf->specification);
601
#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_32)
602
	if (mpf->feature2 & (1 << 7)) {
L
Linus Torvalds 已提交
603 604 605 606 607 608
		printk(KERN_INFO "    IMCR and PIC compatibility mode.\n");
		pic_mode = 1;
	} else {
		printk(KERN_INFO "    Virtual Wire compatibility mode.\n");
		pic_mode = 0;
	}
A
Alexey Starikovskiy 已提交
609
#endif
L
Linus Torvalds 已提交
610 611 612
	/*
	 * Now see if we need to read further.
	 */
613
	if (mpf->feature1 != 0) {
614 615 616 617 618 619 620
		if (early) {
			/*
			 * local APIC has default address
			 */
			mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
			return;
		}
L
Linus Torvalds 已提交
621

A
Alexey Starikovskiy 已提交
622
		printk(KERN_INFO "Default MP configuration #%d\n",
623 624
		       mpf->feature1);
		construct_default_ISA_mptable(mpf->feature1);
L
Linus Torvalds 已提交
625

626
	} else if (mpf->physptr) {
Y
Yinghai Lu 已提交
627 628
		struct mpc_table *mpc;
		unsigned long size;
L
Linus Torvalds 已提交
629

Y
Yinghai Lu 已提交
630 631
		size = get_mpc_size(mpf->physptr);
		mpc = early_ioremap(mpf->physptr, size);
L
Linus Torvalds 已提交
632 633 634 635
		/*
		 * Read the physical hardware table.  Anything here will
		 * override the defaults.
		 */
Y
Yinghai Lu 已提交
636
		if (!smp_read_mpc(mpc, early)) {
A
Alexey Starikovskiy 已提交
637
#ifdef CONFIG_X86_LOCAL_APIC
L
Linus Torvalds 已提交
638
			smp_found_config = 0;
A
Alexey Starikovskiy 已提交
639
#endif
A
Alexey Starikovskiy 已提交
640 641
			printk(KERN_ERR
			       "BIOS bug, MP table errors detected!...\n");
A
Alexey Starikovskiy 已提交
642 643
			printk(KERN_ERR "... disabling SMP support. "
			       "(tell your hw vendor)\n");
Y
Yinghai Lu 已提交
644
			early_iounmap(mpc, size);
L
Linus Torvalds 已提交
645 646
			return;
		}
Y
Yinghai Lu 已提交
647
		early_iounmap(mpc, size);
648

649 650
		if (early)
			return;
651
#ifdef CONFIG_X86_IO_APIC
L
Linus Torvalds 已提交
652 653 654 655 656 657
		/*
		 * If there are no explicit MP IRQ entries, then we are
		 * broken.  We set up most of the low 16 IO-APIC pins to
		 * ISA defaults and hope it will work.
		 */
		if (!mp_irq_entries) {
658
			struct mpc_bus bus;
L
Linus Torvalds 已提交
659

A
Alexey Starikovskiy 已提交
660 661 662
			printk(KERN_ERR "BIOS bug, no explicit IRQ entries, "
			       "using default mptable. "
			       "(tell your hw vendor)\n");
L
Linus Torvalds 已提交
663

664 665 666
			bus.type = MP_BUS;
			bus.busid = 0;
			memcpy(bus.bustype, "ISA   ", 6);
L
Linus Torvalds 已提交
667 668 669 670
			MP_bus_info(&bus);

			construct_default_ioirq_mptable(0);
		}
671
#endif
L
Linus Torvalds 已提交
672 673 674
	} else
		BUG();

675 676
	if (!early)
		printk(KERN_INFO "Processors: %d\n", num_processors);
L
Linus Torvalds 已提交
677 678 679 680 681
	/*
	 * Only use the first configuration found.
	 */
}

682 683 684 685 686 687 688 689 690 691 692 693
void __init early_get_smp_config(void)
{
	__get_smp_config(1);
}

void __init get_smp_config(void)
{
	__get_smp_config(0);
}

static int __init smp_scan_config(unsigned long base, unsigned long length,
				  unsigned reserve)
L
Linus Torvalds 已提交
694
{
A
Alexey Starikovskiy 已提交
695
	unsigned int *bp = phys_to_virt(base);
696
	struct mpf_intel *mpf;
L
Linus Torvalds 已提交
697

698 699
	apic_printk(APIC_VERBOSE, "Scan SMP from %p for %ld bytes.\n",
			bp, length);
700
	BUILD_BUG_ON(sizeof(*mpf) != 16);
L
Linus Torvalds 已提交
701 702

	while (length > 0) {
703
		mpf = (struct mpf_intel *)bp;
L
Linus Torvalds 已提交
704
		if ((*bp == SMP_MAGIC_IDENT) &&
705
		    (mpf->length == 1) &&
A
Alexey Starikovskiy 已提交
706
		    !mpf_checksum((unsigned char *)bp, 16) &&
707 708
		    ((mpf->specification == 1)
		     || (mpf->specification == 4))) {
A
Alexey Starikovskiy 已提交
709
#ifdef CONFIG_X86_LOCAL_APIC
L
Linus Torvalds 已提交
710
			smp_found_config = 1;
A
Alexey Starikovskiy 已提交
711
#endif
A
Alexey Starikovskiy 已提交
712
			mpf_found = mpf;
713

714 715
			printk(KERN_INFO "found SMP MP-table at [%p] %llx\n",
			       mpf, (u64)virt_to_phys(mpf));
716 717 718

			if (!reserve)
				return 1;
719
			reserve_bootmem_generic(virt_to_phys(mpf), PAGE_SIZE,
720
					BOOTMEM_DEFAULT);
721
			if (mpf->physptr) {
722 723
				unsigned long size = PAGE_SIZE;
#ifdef CONFIG_X86_32
L
Linus Torvalds 已提交
724 725 726 727 728 729
				/*
				 * We cannot access to MPC table to compute
				 * table size yet, as only few megabytes from
				 * the bottom is mapped now.
				 * PC-9800's MPC table places on the very last
				 * of physical memory; so that simply reserving
730
				 * PAGE_SIZE from mpf->physptr yields BUG()
L
Linus Torvalds 已提交
731
				 * in reserve_bootmem.
732 733 734
				 * also need to make sure physptr is below than
				 * max_low_pfn
				 * we don't need reserve the area above max_low_pfn
L
Linus Torvalds 已提交
735 736
				 */
				unsigned long end = max_low_pfn * PAGE_SIZE;
737 738 739 740 741 742 743 744

				if (mpf->physptr < end) {
					if (mpf->physptr + size > end)
						size = end - mpf->physptr;
					reserve_bootmem_generic(mpf->physptr, size,
							BOOTMEM_DEFAULT);
				}
#else
745
				reserve_bootmem_generic(mpf->physptr, size,
746
						BOOTMEM_DEFAULT);
747
#endif
L
Linus Torvalds 已提交
748 749
			}

750
			return 1;
L
Linus Torvalds 已提交
751 752 753 754 755 756 757
		}
		bp += 4;
		length -= 16;
	}
	return 0;
}

I
Ingo Molnar 已提交
758
static void __init __find_smp_config(unsigned int reserve)
L
Linus Torvalds 已提交
759 760 761
{
	unsigned int address;

Y
Yinghai Lu 已提交
762 763
	if (x86_quirks->mach_find_smp_config) {
		if (x86_quirks->mach_find_smp_config(reserve))
I
Ingo Molnar 已提交
764 765
			return;
	}
L
Linus Torvalds 已提交
766 767 768 769 770 771 772 773
	/*
	 * FIXME: Linux assumes you have 640K of base ram..
	 * this continues the error...
	 *
	 * 1) Scan the bottom 1K for a signature
	 * 2) Scan the top 1K of base RAM
	 * 3) Scan the 64K of bios
	 */
774 775 776
	if (smp_scan_config(0x0, 0x400, reserve) ||
	    smp_scan_config(639 * 0x400, 0x400, reserve) ||
	    smp_scan_config(0xF0000, 0x10000, reserve))
L
Linus Torvalds 已提交
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796
		return;
	/*
	 * If it is an SMP machine we should know now, unless the
	 * configuration is in an EISA/MCA bus machine with an
	 * extended bios data area.
	 *
	 * there is a real-mode segmented pointer pointing to the
	 * 4K EBDA area at 0x40E, calculate and scan it here.
	 *
	 * NOTE! There are Linux loaders that will corrupt the EBDA
	 * area, and as such this kind of SMP config may be less
	 * trustworthy, simply because the SMP table may have been
	 * stomped on during early boot. These loaders are buggy and
	 * should be fixed.
	 *
	 * MP1.4 SPEC states to only scan first 1K of 4K EBDA.
	 */

	address = get_bios_ebda();
	if (address)
797 798 799 800 801 802 803 804 805 806 807
		smp_scan_config(address, 0x400, reserve);
}

void __init early_find_smp_config(void)
{
	__find_smp_config(0);
}

void __init find_smp_config(void)
{
	__find_smp_config(1);
L
Linus Torvalds 已提交
808
}
Y
Yinghai Lu 已提交
809 810 811 812

#ifdef CONFIG_X86_IO_APIC
static u8 __initdata irq_used[MAX_IRQ_SOURCES];

813
static int  __init get_MP_intsrc_index(struct mpc_intsrc *m)
Y
Yinghai Lu 已提交
814 815 816
{
	int i;

817
	if (m->irqtype != mp_INT)
Y
Yinghai Lu 已提交
818 819
		return 0;

820
	if (m->irqflag != 0x0f)
Y
Yinghai Lu 已提交
821 822 823 824 825
		return 0;

	/* not legacy */

	for (i = 0; i < mp_irq_entries; i++) {
826
		if (mp_irqs[i].irqtype != mp_INT)
Y
Yinghai Lu 已提交
827 828
			continue;

829
		if (mp_irqs[i].irqflag != 0x0f)
Y
Yinghai Lu 已提交
830 831
			continue;

832
		if (mp_irqs[i].srcbus != m->srcbus)
Y
Yinghai Lu 已提交
833
			continue;
834
		if (mp_irqs[i].srcbusirq != m->srcbusirq)
Y
Yinghai Lu 已提交
835 836 837 838 839 840 841 842 843 844 845 846 847 848 849
			continue;
		if (irq_used[i]) {
			/* already claimed */
			return -2;
		}
		irq_used[i] = 1;
		return i;
	}

	/* not found */
	return -1;
}

#define SPARE_SLOT_NUM 20

850
static struct mpc_intsrc __initdata *m_spare[SPARE_SLOT_NUM];
Y
Yinghai Lu 已提交
851 852
#endif

853
static int  __init replace_intsrc_all(struct mpc_table *mpc,
Y
Yinghai Lu 已提交
854 855 856 857 858 859 860 861 862 863 864
					unsigned long mpc_new_phys,
					unsigned long mpc_new_length)
{
#ifdef CONFIG_X86_IO_APIC
	int i;
	int nr_m_spare = 0;
#endif

	int count = sizeof(*mpc);
	unsigned char *mpt = ((unsigned char *)mpc) + count;

865 866
	printk(KERN_INFO "mpc_length %x\n", mpc->length);
	while (count < mpc->length) {
Y
Yinghai Lu 已提交
867 868 869
		switch (*mpt) {
		case MP_PROCESSOR:
			{
870
				struct mpc_cpu *m = (struct mpc_cpu *)mpt;
Y
Yinghai Lu 已提交
871 872 873 874 875 876
				mpt += sizeof(*m);
				count += sizeof(*m);
				break;
			}
		case MP_BUS:
			{
877
				struct mpc_bus *m = (struct mpc_bus *)mpt;
Y
Yinghai Lu 已提交
878 879 880 881 882 883
				mpt += sizeof(*m);
				count += sizeof(*m);
				break;
			}
		case MP_IOAPIC:
			{
884 885
				mpt += sizeof(struct mpc_ioapic);
				count += sizeof(struct mpc_ioapic);
Y
Yinghai Lu 已提交
886 887 888 889 890
				break;
			}
		case MP_INTSRC:
			{
#ifdef CONFIG_X86_IO_APIC
891
				struct mpc_intsrc *m = (struct mpc_intsrc *)mpt;
Y
Yinghai Lu 已提交
892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911

				printk(KERN_INFO "OLD ");
				print_MP_intsrc_info(m);
				i = get_MP_intsrc_index(m);
				if (i > 0) {
					assign_to_mpc_intsrc(&mp_irqs[i], m);
					printk(KERN_INFO "NEW ");
					print_mp_irq_info(&mp_irqs[i]);
				} else if (!i) {
					/* legacy, do nothing */
				} else if (nr_m_spare < SPARE_SLOT_NUM) {
					/*
					 * not found (-1), or duplicated (-2)
					 * are invalid entries,
					 * we need to use the slot  later
					 */
					m_spare[nr_m_spare] = m;
					nr_m_spare++;
				}
#endif
912 913
				mpt += sizeof(struct mpc_intsrc);
				count += sizeof(struct mpc_intsrc);
Y
Yinghai Lu 已提交
914 915 916 917
				break;
			}
		case MP_LINTSRC:
			{
918 919
				struct mpc_lintsrc *m =
				    (struct mpc_lintsrc *)mpt;
Y
Yinghai Lu 已提交
920 921 922 923 924 925 926 927 928
				mpt += sizeof(*m);
				count += sizeof(*m);
				break;
			}
		default:
			/* wrong mptable */
			printk(KERN_ERR "Your mptable is wrong, contact your HW vendor!\n");
			printk(KERN_ERR "type %x\n", *mpt);
			print_hex_dump(KERN_ERR, "  ", DUMP_PREFIX_ADDRESS, 16,
929
					1, mpc, mpc->length, 1);
Y
Yinghai Lu 已提交
930 931 932 933 934 935 936 937 938
			goto out;
		}
	}

#ifdef CONFIG_X86_IO_APIC
	for (i = 0; i < mp_irq_entries; i++) {
		if (irq_used[i])
			continue;

939
		if (mp_irqs[i].irqtype != mp_INT)
Y
Yinghai Lu 已提交
940 941
			continue;

942
		if (mp_irqs[i].irqflag != 0x0f)
Y
Yinghai Lu 已提交
943 944 945 946 947 948 949 950
			continue;

		if (nr_m_spare > 0) {
			printk(KERN_INFO "*NEW* found ");
			nr_m_spare--;
			assign_to_mpc_intsrc(&mp_irqs[i], m_spare[nr_m_spare]);
			m_spare[nr_m_spare] = NULL;
		} else {
951 952
			struct mpc_intsrc *m = (struct mpc_intsrc *)mpt;
			count += sizeof(struct mpc_intsrc);
Y
Yinghai Lu 已提交
953 954 955 956 957 958 959 960 961 962 963
			if (!mpc_new_phys) {
				printk(KERN_INFO "No spare slots, try to append...take your risk, new mpc_length %x\n", count);
			} else {
				if (count <= mpc_new_length)
					printk(KERN_INFO "No spare slots, try to append..., new mpc_length %x\n", count);
				else {
					printk(KERN_ERR "mpc_new_length %lx is too small\n", mpc_new_length);
					goto out;
				}
			}
			assign_to_mpc_intsrc(&mp_irqs[i], m);
964
			mpc->length = count;
965
			mpt += sizeof(struct mpc_intsrc);
Y
Yinghai Lu 已提交
966 967 968 969 970 971
		}
		print_mp_irq_info(&mp_irqs[i]);
	}
#endif
out:
	/* update checksum */
972 973
	mpc->checksum = 0;
	mpc->checksum -= mpf_checksum((unsigned char *)mpc, mpc->length);
Y
Yinghai Lu 已提交
974 975 976 977

	return 0;
}

978 979
static int __initdata enable_update_mptable;

Y
Yinghai Lu 已提交
980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
static int __init update_mptable_setup(char *str)
{
	enable_update_mptable = 1;
	return 0;
}
early_param("update_mptable", update_mptable_setup);

static unsigned long __initdata mpc_new_phys;
static unsigned long mpc_new_length __initdata = 4096;

/* alloc_mptable or alloc_mptable=4k */
static int __initdata alloc_mptable;
static int __init parse_alloc_mptable_opt(char *p)
{
	enable_update_mptable = 1;
	alloc_mptable = 1;
	if (!p)
		return 0;
	mpc_new_length = memparse(p, &p);
	return 0;
}
early_param("alloc_mptable", parse_alloc_mptable_opt);

void __init early_reserve_e820_mpc_new(void)
{
	if (enable_update_mptable && alloc_mptable) {
		u64 startt = 0;
#ifdef CONFIG_X86_TRAMPOLINE
		startt = TRAMPOLINE_BASE;
#endif
		mpc_new_phys = early_reserve_e820(startt, mpc_new_length, 4);
	}
}

static int __init update_mp_table(void)
{
	char str[16];
	char oem[10];
1018
	struct mpf_intel *mpf;
1019
	struct mpc_table *mpc, *mpc_new;
Y
Yinghai Lu 已提交
1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030

	if (!enable_update_mptable)
		return 0;

	mpf = mpf_found;
	if (!mpf)
		return 0;

	/*
	 * Now see if we need to go further.
	 */
1031
	if (mpf->feature1 != 0)
Y
Yinghai Lu 已提交
1032 1033
		return 0;

1034
	if (!mpf->physptr)
Y
Yinghai Lu 已提交
1035 1036
		return 0;

1037
	mpc = phys_to_virt(mpf->physptr);
Y
Yinghai Lu 已提交
1038 1039 1040 1041

	if (!smp_check_mpc(mpc, oem, str))
		return 0;

1042
	printk(KERN_INFO "mpf: %llx\n", (u64)virt_to_phys(mpf));
1043
	printk(KERN_INFO "physptr: %x\n", mpf->physptr);
Y
Yinghai Lu 已提交
1044

1045
	if (mpc_new_phys && mpc->length > mpc_new_length) {
Y
Yinghai Lu 已提交
1046 1047 1048 1049 1050 1051 1052 1053
		mpc_new_phys = 0;
		printk(KERN_INFO "mpc_new_length is %ld, please use alloc_mptable=8k\n",
			 mpc_new_length);
	}

	if (!mpc_new_phys) {
		unsigned char old, new;
		/* check if we can change the postion */
1054 1055 1056 1057
		mpc->checksum = 0;
		old = mpf_checksum((unsigned char *)mpc, mpc->length);
		mpc->checksum = 0xff;
		new = mpf_checksum((unsigned char *)mpc, mpc->length);
Y
Yinghai Lu 已提交
1058 1059 1060 1061 1062 1063
		if (old == new) {
			printk(KERN_INFO "mpc is readonly, please try alloc_mptable instead\n");
			return 0;
		}
		printk(KERN_INFO "use in-positon replacing\n");
	} else {
1064
		mpf->physptr = mpc_new_phys;
Y
Yinghai Lu 已提交
1065
		mpc_new = phys_to_virt(mpc_new_phys);
1066
		memcpy(mpc_new, mpc, mpc->length);
Y
Yinghai Lu 已提交
1067 1068
		mpc = mpc_new;
		/* check if we can modify that */
1069
		if (mpc_new_phys - mpf->physptr) {
1070
			struct mpf_intel *mpf_new;
Y
Yinghai Lu 已提交
1071 1072 1073 1074 1075
			/* steal 16 bytes from [0, 1k) */
			printk(KERN_INFO "mpf new: %x\n", 0x400 - 16);
			mpf_new = phys_to_virt(0x400 - 16);
			memcpy(mpf_new, mpf, 16);
			mpf = mpf_new;
1076
			mpf->physptr = mpc_new_phys;
Y
Yinghai Lu 已提交
1077
		}
1078 1079 1080
		mpf->checksum = 0;
		mpf->checksum -= mpf_checksum((unsigned char *)mpf, 16);
		printk(KERN_INFO "physptr new: %x\n", mpf->physptr);
Y
Yinghai Lu 已提交
1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
	}

	/*
	 * only replace the one with mp_INT and
	 *	 MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW,
	 * already in mp_irqs , stored by ... and mp_config_acpi_gsi,
	 * may need pci=routeirq for all coverage
	 */
	replace_intsrc_all(mpc, mpc_new_phys, mpc_new_length);

	return 0;
}

late_initcall(update_mp_table);