mpparse.c 24.7 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>
L
Linus Torvalds 已提交
6
 *	(c) 1998, 1999, 2000 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/genapic.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 561 562 563

/*
 * Scan the memory blocks for an SMP configuration block.
 */
I
Ingo Molnar 已提交
564
static void __init __get_smp_config(unsigned int early)
L
Linus Torvalds 已提交
565
{
566
	struct mpf_intel *mpf = mpf_found;
L
Linus Torvalds 已提交
567

Y
Yinghai Lu 已提交
568 569 570
	if (!mpf)
		return;

571 572
	if (acpi_lapic && early)
		return;
Y
Yinghai Lu 已提交
573

L
Linus Torvalds 已提交
574
	/*
Y
Yinghai Lu 已提交
575 576
	 * MPS doesn't support hyperthreading, aka only have
	 * thread 0 apic id in MPS table
L
Linus Torvalds 已提交
577
	 */
Y
Yinghai Lu 已提交
578
	if (acpi_lapic && acpi_ioapic)
L
Linus Torvalds 已提交
579 580
		return;

Y
Yinghai Lu 已提交
581 582 583 584
	if (x86_quirks->mach_get_smp_config) {
		if (x86_quirks->mach_get_smp_config(early))
			return;
	}
585

A
Alexey Starikovskiy 已提交
586
	printk(KERN_INFO "Intel MultiProcessor Specification v1.%d\n",
587
	       mpf->specification);
588
#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_32)
589
	if (mpf->feature2 & (1 << 7)) {
L
Linus Torvalds 已提交
590 591 592 593 594 595
		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 已提交
596
#endif
L
Linus Torvalds 已提交
597 598 599
	/*
	 * Now see if we need to read further.
	 */
600
	if (mpf->feature1 != 0) {
601 602 603 604 605 606 607
		if (early) {
			/*
			 * local APIC has default address
			 */
			mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
			return;
		}
L
Linus Torvalds 已提交
608

A
Alexey Starikovskiy 已提交
609
		printk(KERN_INFO "Default MP configuration #%d\n",
610 611
		       mpf->feature1);
		construct_default_ISA_mptable(mpf->feature1);
L
Linus Torvalds 已提交
612

613
	} else if (mpf->physptr) {
L
Linus Torvalds 已提交
614 615 616 617 618

		/*
		 * Read the physical hardware table.  Anything here will
		 * override the defaults.
		 */
619
		if (!smp_read_mpc(phys_to_virt(mpf->physptr), early)) {
A
Alexey Starikovskiy 已提交
620
#ifdef CONFIG_X86_LOCAL_APIC
L
Linus Torvalds 已提交
621
			smp_found_config = 0;
A
Alexey Starikovskiy 已提交
622
#endif
A
Alexey Starikovskiy 已提交
623 624
			printk(KERN_ERR
			       "BIOS bug, MP table errors detected!...\n");
A
Alexey Starikovskiy 已提交
625 626
			printk(KERN_ERR "... disabling SMP support. "
			       "(tell your hw vendor)\n");
L
Linus Torvalds 已提交
627 628
			return;
		}
629

630 631
		if (early)
			return;
632
#ifdef CONFIG_X86_IO_APIC
L
Linus Torvalds 已提交
633 634 635 636 637 638
		/*
		 * 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) {
639
			struct mpc_bus bus;
L
Linus Torvalds 已提交
640

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

645 646 647
			bus.type = MP_BUS;
			bus.busid = 0;
			memcpy(bus.bustype, "ISA   ", 6);
L
Linus Torvalds 已提交
648 649 650 651
			MP_bus_info(&bus);

			construct_default_ioirq_mptable(0);
		}
652
#endif
L
Linus Torvalds 已提交
653 654 655
	} else
		BUG();

656 657
	if (!early)
		printk(KERN_INFO "Processors: %d\n", num_processors);
L
Linus Torvalds 已提交
658 659 660 661 662
	/*
	 * Only use the first configuration found.
	 */
}

663 664 665 666 667 668 669 670 671 672 673 674
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 已提交
675
{
A
Alexey Starikovskiy 已提交
676
	unsigned int *bp = phys_to_virt(base);
677
	struct mpf_intel *mpf;
L
Linus Torvalds 已提交
678

679 680
	apic_printk(APIC_VERBOSE, "Scan SMP from %p for %ld bytes.\n",
			bp, length);
681
	BUILD_BUG_ON(sizeof(*mpf) != 16);
L
Linus Torvalds 已提交
682 683

	while (length > 0) {
684
		mpf = (struct mpf_intel *)bp;
L
Linus Torvalds 已提交
685
		if ((*bp == SMP_MAGIC_IDENT) &&
686
		    (mpf->length == 1) &&
A
Alexey Starikovskiy 已提交
687
		    !mpf_checksum((unsigned char *)bp, 16) &&
688 689
		    ((mpf->specification == 1)
		     || (mpf->specification == 4))) {
A
Alexey Starikovskiy 已提交
690
#ifdef CONFIG_X86_LOCAL_APIC
L
Linus Torvalds 已提交
691
			smp_found_config = 1;
A
Alexey Starikovskiy 已提交
692
#endif
A
Alexey Starikovskiy 已提交
693
			mpf_found = mpf;
694

695
			printk(KERN_INFO "found SMP MP-table at [%p] %08lx\n",
A
Alexey Starikovskiy 已提交
696
			       mpf, virt_to_phys(mpf));
697 698 699

			if (!reserve)
				return 1;
700
			reserve_bootmem_generic(virt_to_phys(mpf), PAGE_SIZE,
701
					BOOTMEM_DEFAULT);
702
			if (mpf->physptr) {
703 704
				unsigned long size = PAGE_SIZE;
#ifdef CONFIG_X86_32
L
Linus Torvalds 已提交
705 706 707 708 709 710
				/*
				 * 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
711
				 * PAGE_SIZE from mpf->physptr yields BUG()
L
Linus Torvalds 已提交
712 713 714
				 * in reserve_bootmem.
				 */
				unsigned long end = max_low_pfn * PAGE_SIZE;
715 716
				if (mpf->physptr + size > end)
					size = end - mpf->physptr;
717
#endif
718
				reserve_bootmem_generic(mpf->physptr, size,
719
						BOOTMEM_DEFAULT);
L
Linus Torvalds 已提交
720 721
			}

722
			return 1;
L
Linus Torvalds 已提交
723 724 725 726 727 728 729
		}
		bp += 4;
		length -= 16;
	}
	return 0;
}

I
Ingo Molnar 已提交
730
static void __init __find_smp_config(unsigned int reserve)
L
Linus Torvalds 已提交
731 732 733
{
	unsigned int address;

Y
Yinghai Lu 已提交
734 735
	if (x86_quirks->mach_find_smp_config) {
		if (x86_quirks->mach_find_smp_config(reserve))
I
Ingo Molnar 已提交
736 737
			return;
	}
L
Linus Torvalds 已提交
738 739 740 741 742 743 744 745
	/*
	 * 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
	 */
746 747 748
	if (smp_scan_config(0x0, 0x400, reserve) ||
	    smp_scan_config(639 * 0x400, 0x400, reserve) ||
	    smp_scan_config(0xF0000, 0x10000, reserve))
L
Linus Torvalds 已提交
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768
		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)
769 770 771 772 773 774 775 776 777 778 779
		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 已提交
780
}
Y
Yinghai Lu 已提交
781 782 783 784

#ifdef CONFIG_X86_IO_APIC
static u8 __initdata irq_used[MAX_IRQ_SOURCES];

785
static int  __init get_MP_intsrc_index(struct mpc_intsrc *m)
Y
Yinghai Lu 已提交
786 787 788
{
	int i;

789
	if (m->irqtype != mp_INT)
Y
Yinghai Lu 已提交
790 791
		return 0;

792
	if (m->irqflag != 0x0f)
Y
Yinghai Lu 已提交
793 794 795 796 797
		return 0;

	/* not legacy */

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

801
		if (mp_irqs[i].irqflag != 0x0f)
Y
Yinghai Lu 已提交
802 803
			continue;

804
		if (mp_irqs[i].srcbus != m->srcbus)
Y
Yinghai Lu 已提交
805
			continue;
806
		if (mp_irqs[i].srcbusirq != m->srcbusirq)
Y
Yinghai Lu 已提交
807 808 809 810 811 812 813 814 815 816 817 818 819 820 821
			continue;
		if (irq_used[i]) {
			/* already claimed */
			return -2;
		}
		irq_used[i] = 1;
		return i;
	}

	/* not found */
	return -1;
}

#define SPARE_SLOT_NUM 20

822
static struct mpc_intsrc __initdata *m_spare[SPARE_SLOT_NUM];
Y
Yinghai Lu 已提交
823 824
#endif

825
static int  __init replace_intsrc_all(struct mpc_table *mpc,
Y
Yinghai Lu 已提交
826 827 828 829 830 831 832 833 834 835 836
					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;

837 838
	printk(KERN_INFO "mpc_length %x\n", mpc->length);
	while (count < mpc->length) {
Y
Yinghai Lu 已提交
839 840 841
		switch (*mpt) {
		case MP_PROCESSOR:
			{
842
				struct mpc_cpu *m = (struct mpc_cpu *)mpt;
Y
Yinghai Lu 已提交
843 844 845 846 847 848
				mpt += sizeof(*m);
				count += sizeof(*m);
				break;
			}
		case MP_BUS:
			{
849
				struct mpc_bus *m = (struct mpc_bus *)mpt;
Y
Yinghai Lu 已提交
850 851 852 853 854 855
				mpt += sizeof(*m);
				count += sizeof(*m);
				break;
			}
		case MP_IOAPIC:
			{
856 857
				mpt += sizeof(struct mpc_ioapic);
				count += sizeof(struct mpc_ioapic);
Y
Yinghai Lu 已提交
858 859 860 861 862
				break;
			}
		case MP_INTSRC:
			{
#ifdef CONFIG_X86_IO_APIC
863
				struct mpc_intsrc *m = (struct mpc_intsrc *)mpt;
Y
Yinghai Lu 已提交
864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883

				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
884 885
				mpt += sizeof(struct mpc_intsrc);
				count += sizeof(struct mpc_intsrc);
Y
Yinghai Lu 已提交
886 887 888 889
				break;
			}
		case MP_LINTSRC:
			{
890 891
				struct mpc_lintsrc *m =
				    (struct mpc_lintsrc *)mpt;
Y
Yinghai Lu 已提交
892 893 894 895 896 897 898 899 900
				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,
901
					1, mpc, mpc->length, 1);
Y
Yinghai Lu 已提交
902 903 904 905 906 907 908 909 910
			goto out;
		}
	}

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

911
		if (mp_irqs[i].irqtype != mp_INT)
Y
Yinghai Lu 已提交
912 913
			continue;

914
		if (mp_irqs[i].irqflag != 0x0f)
Y
Yinghai Lu 已提交
915 916 917 918 919 920 921 922
			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 {
923 924
			struct mpc_intsrc *m = (struct mpc_intsrc *)mpt;
			count += sizeof(struct mpc_intsrc);
Y
Yinghai Lu 已提交
925 926 927 928 929 930 931 932 933 934 935
			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);
936
			mpc->length = count;
937
			mpt += sizeof(struct mpc_intsrc);
Y
Yinghai Lu 已提交
938 939 940 941 942 943
		}
		print_mp_irq_info(&mp_irqs[i]);
	}
#endif
out:
	/* update checksum */
944 945
	mpc->checksum = 0;
	mpc->checksum -= mpf_checksum((unsigned char *)mpc, mpc->length);
Y
Yinghai Lu 已提交
946 947 948 949

	return 0;
}

950 951
static int __initdata enable_update_mptable;

Y
Yinghai Lu 已提交
952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989
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];
990
	struct mpf_intel *mpf;
991
	struct mpc_table *mpc, *mpc_new;
Y
Yinghai Lu 已提交
992 993 994 995 996 997 998 999 1000 1001 1002

	if (!enable_update_mptable)
		return 0;

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

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

1006
	if (!mpf->physptr)
Y
Yinghai Lu 已提交
1007 1008
		return 0;

1009
	mpc = phys_to_virt(mpf->physptr);
Y
Yinghai Lu 已提交
1010 1011 1012 1013 1014

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

	printk(KERN_INFO "mpf: %lx\n", virt_to_phys(mpf));
1015
	printk(KERN_INFO "physptr: %x\n", mpf->physptr);
Y
Yinghai Lu 已提交
1016

1017
	if (mpc_new_phys && mpc->length > mpc_new_length) {
Y
Yinghai Lu 已提交
1018 1019 1020 1021 1022 1023 1024 1025
		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 */
1026 1027 1028 1029
		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 已提交
1030 1031 1032 1033 1034 1035
		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 {
1036
		mpf->physptr = mpc_new_phys;
Y
Yinghai Lu 已提交
1037
		mpc_new = phys_to_virt(mpc_new_phys);
1038
		memcpy(mpc_new, mpc, mpc->length);
Y
Yinghai Lu 已提交
1039 1040
		mpc = mpc_new;
		/* check if we can modify that */
1041
		if (mpc_new_phys - mpf->physptr) {
1042
			struct mpf_intel *mpf_new;
Y
Yinghai Lu 已提交
1043 1044 1045 1046 1047
			/* 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;
1048
			mpf->physptr = mpc_new_phys;
Y
Yinghai Lu 已提交
1049
		}
1050 1051 1052
		mpf->checksum = 0;
		mpf->checksum -= mpf_checksum((unsigned char *)mpf, 16);
		printk(KERN_INFO "physptr new: %x\n", mpf->physptr);
Y
Yinghai Lu 已提交
1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
	}

	/*
	 * 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);