mpparse.c 25.1 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>
L
Linus Torvalds 已提交
30 31

#include <mach_apic.h>
32
#ifdef CONFIG_X86_32
33
#include <mach_apicdef.h>
L
Linus Torvalds 已提交
34
#include <mach_mpparse.h>
35
#endif
L
Linus Torvalds 已提交
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50

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

51
static void __init MP_processor_info(struct mpc_cpu *m)
52 53
{
	int apicid;
54
	char *bootup_cpu = "";
55

56
	if (!(m->cpuflag & CPU_ENABLED)) {
G
Glauber Costa 已提交
57
		disabled_cpus++;
L
Linus Torvalds 已提交
58
		return;
G
Glauber Costa 已提交
59
	}
60 61 62

	if (x86_quirks->mpc_apic_id)
		apicid = x86_quirks->mpc_apic_id(m);
63
	else
64
		apicid = m->apicid;
65

66
	if (m->cpuflag & CPU_BOOTPROCESSOR) {
67
		bootup_cpu = " (Bootup-CPU)";
68
		boot_cpu_physical_apicid = m->apicid;
L
Linus Torvalds 已提交
69 70
	}

71 72
	printk(KERN_INFO "Processor #%d%s\n", m->apicid, bootup_cpu);
	generic_processor_info(apicid, m->apicver);
L
Linus Torvalds 已提交
73 74
}

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

82 83 84
	if (x86_quirks->mpc_oem_bus_info)
		x86_quirks->mpc_oem_bus_info(m, str);
	else
85
		apic_printk(APIC_VERBOSE, "Bus #%d is %s\n", m->busid, str);
L
Linus Torvalds 已提交
86

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

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

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

118 119
#ifdef CONFIG_X86_IO_APIC

120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
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;
}

135
static void __init MP_ioapic_info(struct mpc_ioapic *m)
L
Linus Torvalds 已提交
136
{
137
	if (!(m->flags & MPC_APIC_USABLE))
L
Linus Torvalds 已提交
138 139
		return;

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

143
	if (bad_ioapic(m->apicaddr))
L
Linus Torvalds 已提交
144
		return;
145

146 147 148 149 150
	mp_ioapics[nr_ioapics].mp_apicaddr = m->apicaddr;
	mp_ioapics[nr_ioapics].mp_apicid = m->apicid;
	mp_ioapics[nr_ioapics].mp_type = m->type;
	mp_ioapics[nr_ioapics].mp_apicver = m->apicver;
	mp_ioapics[nr_ioapics].mp_flags = m->flags;
L
Linus Torvalds 已提交
151 152 153
	nr_ioapics++;
}

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

static void __init print_mp_irq_info(struct mp_config_intsrc *mp_irq)
{
164
	apic_printk(APIC_VERBOSE, "Int: type %d, pol %d, trig %d, bus %02x,"
Y
Yinghai Lu 已提交
165 166 167 168 169 170
		" IRQ %02x, APIC ID %x, APIC INT %02x\n",
		mp_irq->mp_irqtype, mp_irq->mp_irqflag & 3,
		(mp_irq->mp_irqflag >> 2) & 3, mp_irq->mp_srcbus,
		mp_irq->mp_srcbusirq, mp_irq->mp_dstapic, mp_irq->mp_dstirq);
}

171
static void __init assign_to_mp_irq(struct mpc_intsrc *m,
Y
Yinghai Lu 已提交
172 173
				    struct mp_config_intsrc *mp_irq)
{
174 175 176 177 178 179 180
	mp_irq->mp_dstapic = m->dstapic;
	mp_irq->mp_type = m->type;
	mp_irq->mp_irqtype = m->irqtype;
	mp_irq->mp_irqflag = m->irqflag;
	mp_irq->mp_srcbus = m->srcbus;
	mp_irq->mp_srcbusirq = m->srcbusirq;
	mp_irq->mp_dstirq = m->dstirq;
Y
Yinghai Lu 已提交
181 182 183
}

static void __init assign_to_mpc_intsrc(struct mp_config_intsrc *mp_irq,
184
					struct mpc_intsrc *m)
Y
Yinghai Lu 已提交
185
{
186 187 188 189 190 191 192
	m->dstapic = mp_irq->mp_dstapic;
	m->type = mp_irq->mp_type;
	m->irqtype = mp_irq->mp_irqtype;
	m->irqflag = mp_irq->mp_irqflag;
	m->srcbus = mp_irq->mp_srcbus;
	m->srcbusirq = mp_irq->mp_srcbusirq;
	m->dstirq = mp_irq->mp_dstirq;
Y
Yinghai Lu 已提交
193 194
}

195
static int __init mp_irq_mpc_intsrc_cmp(struct mp_config_intsrc *mp_irq,
196
					struct mpc_intsrc *m)
Y
Yinghai Lu 已提交
197
{
198
	if (mp_irq->mp_dstapic != m->dstapic)
Y
Yinghai Lu 已提交
199
		return 1;
200
	if (mp_irq->mp_type != m->type)
Y
Yinghai Lu 已提交
201
		return 2;
202
	if (mp_irq->mp_irqtype != m->irqtype)
Y
Yinghai Lu 已提交
203
		return 3;
204
	if (mp_irq->mp_irqflag != m->irqflag)
Y
Yinghai Lu 已提交
205
		return 4;
206
	if (mp_irq->mp_srcbus != m->srcbus)
Y
Yinghai Lu 已提交
207
		return 5;
208
	if (mp_irq->mp_srcbusirq != m->srcbusirq)
Y
Yinghai Lu 已提交
209
		return 6;
210
	if (mp_irq->mp_dstirq != m->dstirq)
Y
Yinghai Lu 已提交
211 212 213 214 215
		return 7;

	return 0;
}

216
static void __init MP_intsrc_info(struct mpc_intsrc *m)
Y
Yinghai Lu 已提交
217 218 219 220 221
{
	int i;

	print_MP_intsrc_info(m);

222 223 224 225
	for (i = 0; i < mp_irq_entries; i++) {
		if (!mp_irq_mpc_intsrc_cmp(&mp_irqs[i], m))
			return;
	}
Y
Yinghai Lu 已提交
226 227

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

232 233
#endif

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

/*
 * Read/parse the MPC
 */

246
static int __init smp_check_mpc(struct mpc_table *mpc, char *oem, char *str)
L
Linus Torvalds 已提交
247 248
{

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

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

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

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

Y
Yinghai Lu 已提交
279 280 281
	return 1;
}

282
static int __init smp_read_mpc(struct mpc_table *mpc, unsigned early)
Y
Yinghai Lu 已提交
283 284 285 286 287 288 289 290 291 292 293
{
	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
294 295 296 297 298 299 300 301 302 303
	/*
	 * need to make sure summit and es7000's mps_oem_check is safe to be
	 * called early via genericarch 's mps_oem_check
	 */
	if (early) {
#ifdef CONFIG_X86_NUMAQ
		numaq_mps_oem_check(mpc, oem, str);
#endif
	} else
		mps_oem_check(mpc, oem, str);
Y
Yinghai Lu 已提交
304
#endif
A
Alexey Starikovskiy 已提交
305
	/* save the local APIC address, it might be non-default */
L
Linus Torvalds 已提交
306
	if (!acpi_lapic)
307
		mp_lapic_addr = mpc->lapic;
L
Linus Torvalds 已提交
308

309 310 311
	if (early)
		return 1;

312 313 314
	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);
315 316
	}

L
Linus Torvalds 已提交
317
	/*
A
Alexey Starikovskiy 已提交
318
	 *      Now process the configuration blocks.
L
Linus Torvalds 已提交
319
	 */
320 321 322
	if (x86_quirks->mpc_record)
		*x86_quirks->mpc_record = 0;

323
	while (count < mpc->length) {
A
Alexey Starikovskiy 已提交
324 325
		switch (*mpt) {
		case MP_PROCESSOR:
L
Linus Torvalds 已提交
326
			{
327
				struct mpc_cpu *m = (struct mpc_cpu *)mpt;
L
Linus Torvalds 已提交
328 329 330 331 332 333 334
				/* ACPI may have already provided this data */
				if (!acpi_lapic)
					MP_processor_info(m);
				mpt += sizeof(*m);
				count += sizeof(*m);
				break;
			}
A
Alexey Starikovskiy 已提交
335
		case MP_BUS:
L
Linus Torvalds 已提交
336
			{
337
				struct mpc_bus *m = (struct mpc_bus *)mpt;
T
Thomas Gleixner 已提交
338
#ifdef CONFIG_X86_IO_APIC
L
Linus Torvalds 已提交
339
				MP_bus_info(m);
T
Thomas Gleixner 已提交
340
#endif
L
Linus Torvalds 已提交
341 342 343 344
				mpt += sizeof(*m);
				count += sizeof(*m);
				break;
			}
A
Alexey Starikovskiy 已提交
345
		case MP_IOAPIC:
L
Linus Torvalds 已提交
346
			{
347
#ifdef CONFIG_X86_IO_APIC
348
				struct mpc_ioapic *m = (struct mpc_ioapic *)mpt;
L
Linus Torvalds 已提交
349
				MP_ioapic_info(m);
350
#endif
351 352
				mpt += sizeof(struct mpc_ioapic);
				count += sizeof(struct mpc_ioapic);
L
Linus Torvalds 已提交
353 354
				break;
			}
A
Alexey Starikovskiy 已提交
355
		case MP_INTSRC:
L
Linus Torvalds 已提交
356
			{
357
#ifdef CONFIG_X86_IO_APIC
358
				struct mpc_intsrc *m = (struct mpc_intsrc *)mpt;
L
Linus Torvalds 已提交
359 360

				MP_intsrc_info(m);
361
#endif
362 363
				mpt += sizeof(struct mpc_intsrc);
				count += sizeof(struct mpc_intsrc);
L
Linus Torvalds 已提交
364 365
				break;
			}
A
Alexey Starikovskiy 已提交
366
		case MP_LINTSRC:
L
Linus Torvalds 已提交
367
			{
368 369
				struct mpc_lintsrc *m =
				    (struct mpc_lintsrc *)mpt;
L
Linus Torvalds 已提交
370
				MP_lintsrc_info(m);
A
Alexey Starikovskiy 已提交
371 372
				mpt += sizeof(*m);
				count += sizeof(*m);
L
Linus Torvalds 已提交
373 374
				break;
			}
A
Alexey Starikovskiy 已提交
375
		default:
Y
Yinghai Lu 已提交
376 377 378 379
			/* 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,
380 381
					1, mpc, mpc->length, 1);
			count = mpc->length;
Y
Yinghai Lu 已提交
382
			break;
L
Linus Torvalds 已提交
383
		}
384 385
		if (x86_quirks->mpc_record)
			(*x86_quirks->mpc_record)++;
L
Linus Torvalds 已提交
386
	}
387 388 389 390 391

#ifdef CONFIG_X86_GENERICARCH
       generic_bigsmp_probe();
#endif

392
#ifdef CONFIG_X86_32
393
	setup_apic_routing();
394
#endif
L
Linus Torvalds 已提交
395
	if (!num_processors)
A
Alexey Starikovskiy 已提交
396
		printk(KERN_ERR "MPTABLE: no processors registered!\n");
L
Linus Torvalds 已提交
397 398 399
	return num_processors;
}

400 401
#ifdef CONFIG_X86_IO_APIC

L
Linus Torvalds 已提交
402 403 404 405 406 407 408 409 410 411
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)
{
412
	struct mpc_intsrc intsrc;
L
Linus Torvalds 已提交
413 414 415
	int i;
	int ELCR_fallback = 0;

416 417 418 419
	intsrc.type = MP_INTSRC;
	intsrc.irqflag = 0;	/* conforming */
	intsrc.srcbus = 0;
	intsrc.dstapic = mp_ioapics[0].mp_apicid;
L
Linus Torvalds 已提交
420

421
	intsrc.irqtype = mp_INT;
L
Linus Torvalds 已提交
422 423 424 425 426 427 428 429 430 431

	/*
	 *  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) {
432 433
		printk(KERN_INFO "ISA/PCI bus type with no IRQ information... "
		       "falling back to ELCR\n");
L
Linus Torvalds 已提交
434

435 436 437 438
		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 已提交
439
		else {
A
Alexey Starikovskiy 已提交
440 441
			printk(KERN_INFO
			       "Using ELCR to identify PCI interrupts\n");
L
Linus Torvalds 已提交
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
			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))
464
				intsrc.irqflag = 13;
L
Linus Torvalds 已提交
465
			else
466
				intsrc.irqflag = 0;
L
Linus Torvalds 已提交
467 468
		}

469 470
		intsrc.srcbusirq = i;
		intsrc.dstirq = i ? i : 2;	/* IRQ0 to INTIN2 */
L
Linus Torvalds 已提交
471 472 473
		MP_intsrc_info(&intsrc);
	}

474 475 476
	intsrc.irqtype = mp_ExtINT;
	intsrc.srcbusirq = 0;
	intsrc.dstirq = 0;	/* 8259A to INTIN0 */
L
Linus Torvalds 已提交
477 478 479
	MP_intsrc_info(&intsrc);
}

480

481
static void __init construct_ioapic_table(int mpc_default_type)
L
Linus Torvalds 已提交
482
{
483
	struct mpc_ioapic ioapic;
484
	struct mpc_bus bus;
L
Linus Torvalds 已提交
485

486 487
	bus.type = MP_BUS;
	bus.busid = 0;
L
Linus Torvalds 已提交
488
	switch (mpc_default_type) {
A
Alexey Starikovskiy 已提交
489
	default:
490
		printk(KERN_ERR "???\nUnknown standard configuration %d\n",
A
Alexey Starikovskiy 已提交
491 492 493 494
		       mpc_default_type);
		/* fall through */
	case 1:
	case 5:
495
		memcpy(bus.bustype, "ISA   ", 6);
A
Alexey Starikovskiy 已提交
496 497 498 499
		break;
	case 2:
	case 6:
	case 3:
500
		memcpy(bus.bustype, "EISA  ", 6);
A
Alexey Starikovskiy 已提交
501 502 503
		break;
	case 4:
	case 7:
504
		memcpy(bus.bustype, "MCA   ", 6);
L
Linus Torvalds 已提交
505 506 507
	}
	MP_bus_info(&bus);
	if (mpc_default_type > 4) {
508 509
		bus.busid = 1;
		memcpy(bus.bustype, "PCI   ", 6);
L
Linus Torvalds 已提交
510 511 512
		MP_bus_info(&bus);
	}

513 514 515 516 517
	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 已提交
518 519 520 521 522 523
	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 已提交
524 525
}
#else
526
static inline void __init construct_ioapic_table(int mpc_default_type) { }
527
#endif
T
Thomas Gleixner 已提交
528 529 530

static inline void __init construct_default_ISA_mptable(int mpc_default_type)
{
531
	struct mpc_cpu processor;
532
	struct mpc_lintsrc lintsrc;
T
Thomas Gleixner 已提交
533 534 535 536 537 538 539 540 541 542 543
	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.
	 */
544
	processor.type = MP_PROCESSOR;
T
Thomas Gleixner 已提交
545
	/* Either an integrated APIC or a discrete 82489DX. */
546 547 548
	processor.apicver = mpc_default_type > 4 ? 0x10 : 0x01;
	processor.cpuflag = CPU_ENABLED;
	processor.cpufeature = (boot_cpu_data.x86 << 8) |
T
Thomas Gleixner 已提交
549
	    (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_mask;
550 551 552
	processor.featureflag = boot_cpu_data.x86_capability[0];
	processor.reserved[0] = 0;
	processor.reserved[1] = 0;
T
Thomas Gleixner 已提交
553
	for (i = 0; i < 2; i++) {
554
		processor.apicid = i;
T
Thomas Gleixner 已提交
555 556 557 558 559
		MP_processor_info(&processor);
	}

	construct_ioapic_table(mpc_default_type);

560 561 562 563 564
	lintsrc.type = MP_LINTSRC;
	lintsrc.irqflag = 0;		/* conforming */
	lintsrc.srcbusid = 0;
	lintsrc.srcbusirq = 0;
	lintsrc.destapic = MP_APIC_ALL;
L
Linus Torvalds 已提交
565
	for (i = 0; i < 2; i++) {
566 567
		lintsrc.irqtype = linttypes[i];
		lintsrc.destapiclint = i;
L
Linus Torvalds 已提交
568 569 570 571
		MP_lintsrc_info(&lintsrc);
	}
}

572
static struct mpf_intel *mpf_found;
L
Linus Torvalds 已提交
573 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) {
L
Linus Torvalds 已提交
627 628 629 630 631

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

643 644
		if (early)
			return;
645
#ifdef CONFIG_X86_IO_APIC
L
Linus Torvalds 已提交
646 647 648 649 650 651
		/*
		 * 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) {
652
			struct mpc_bus bus;
L
Linus Torvalds 已提交
653

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

658 659 660
			bus.type = MP_BUS;
			bus.busid = 0;
			memcpy(bus.bustype, "ISA   ", 6);
L
Linus Torvalds 已提交
661 662 663 664
			MP_bus_info(&bus);

			construct_default_ioirq_mptable(0);
		}
665
#endif
L
Linus Torvalds 已提交
666 667 668
	} else
		BUG();

669 670
	if (!early)
		printk(KERN_INFO "Processors: %d\n", num_processors);
L
Linus Torvalds 已提交
671 672 673 674 675
	/*
	 * Only use the first configuration found.
	 */
}

676 677 678 679 680 681 682 683 684 685 686 687
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 已提交
688
{
A
Alexey Starikovskiy 已提交
689
	unsigned int *bp = phys_to_virt(base);
690
	struct mpf_intel *mpf;
L
Linus Torvalds 已提交
691

692 693
	apic_printk(APIC_VERBOSE, "Scan SMP from %p for %ld bytes.\n",
			bp, length);
694
	BUILD_BUG_ON(sizeof(*mpf) != 16);
L
Linus Torvalds 已提交
695 696

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

708
			printk(KERN_INFO "found SMP MP-table at [%p] %08lx\n",
A
Alexey Starikovskiy 已提交
709
			       mpf, virt_to_phys(mpf));
710 711 712

			if (!reserve)
				return 1;
713
			reserve_bootmem_generic(virt_to_phys(mpf), PAGE_SIZE,
714
					BOOTMEM_DEFAULT);
715
			if (mpf->physptr) {
716 717
				unsigned long size = PAGE_SIZE;
#ifdef CONFIG_X86_32
L
Linus Torvalds 已提交
718 719 720 721 722 723
				/*
				 * 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
724
				 * PAGE_SIZE from mpf->physptr yields BUG()
L
Linus Torvalds 已提交
725 726 727
				 * in reserve_bootmem.
				 */
				unsigned long end = max_low_pfn * PAGE_SIZE;
728 729
				if (mpf->physptr + size > end)
					size = end - mpf->physptr;
730
#endif
731
				reserve_bootmem_generic(mpf->physptr, size,
732
						BOOTMEM_DEFAULT);
L
Linus Torvalds 已提交
733 734
			}

735
			return 1;
L
Linus Torvalds 已提交
736 737 738 739 740 741 742
		}
		bp += 4;
		length -= 16;
	}
	return 0;
}

I
Ingo Molnar 已提交
743
static void __init __find_smp_config(unsigned int reserve)
L
Linus Torvalds 已提交
744 745 746
{
	unsigned int address;

Y
Yinghai Lu 已提交
747 748
	if (x86_quirks->mach_find_smp_config) {
		if (x86_quirks->mach_find_smp_config(reserve))
I
Ingo Molnar 已提交
749 750
			return;
	}
L
Linus Torvalds 已提交
751 752 753 754 755 756 757 758
	/*
	 * 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
	 */
759 760 761
	if (smp_scan_config(0x0, 0x400, reserve) ||
	    smp_scan_config(639 * 0x400, 0x400, reserve) ||
	    smp_scan_config(0xF0000, 0x10000, reserve))
L
Linus Torvalds 已提交
762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781
		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)
782 783 784 785 786 787 788 789 790 791 792
		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 已提交
793
}
Y
Yinghai Lu 已提交
794 795 796 797

#ifdef CONFIG_X86_IO_APIC
static u8 __initdata irq_used[MAX_IRQ_SOURCES];

798
static int  __init get_MP_intsrc_index(struct mpc_intsrc *m)
Y
Yinghai Lu 已提交
799 800 801
{
	int i;

802
	if (m->irqtype != mp_INT)
Y
Yinghai Lu 已提交
803 804
		return 0;

805
	if (m->irqflag != 0x0f)
Y
Yinghai Lu 已提交
806 807 808 809 810 811 812 813 814 815 816
		return 0;

	/* not legacy */

	for (i = 0; i < mp_irq_entries; i++) {
		if (mp_irqs[i].mp_irqtype != mp_INT)
			continue;

		if (mp_irqs[i].mp_irqflag != 0x0f)
			continue;

817
		if (mp_irqs[i].mp_srcbus != m->srcbus)
Y
Yinghai Lu 已提交
818
			continue;
819
		if (mp_irqs[i].mp_srcbusirq != m->srcbusirq)
Y
Yinghai Lu 已提交
820 821 822 823 824 825 826 827 828 829 830 831 832 833 834
			continue;
		if (irq_used[i]) {
			/* already claimed */
			return -2;
		}
		irq_used[i] = 1;
		return i;
	}

	/* not found */
	return -1;
}

#define SPARE_SLOT_NUM 20

835
static struct mpc_intsrc __initdata *m_spare[SPARE_SLOT_NUM];
Y
Yinghai Lu 已提交
836 837
#endif

838
static int  __init replace_intsrc_all(struct mpc_table *mpc,
Y
Yinghai Lu 已提交
839 840 841 842 843 844 845 846 847 848 849
					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;

850 851
	printk(KERN_INFO "mpc_length %x\n", mpc->length);
	while (count < mpc->length) {
Y
Yinghai Lu 已提交
852 853 854
		switch (*mpt) {
		case MP_PROCESSOR:
			{
855
				struct mpc_cpu *m = (struct mpc_cpu *)mpt;
Y
Yinghai Lu 已提交
856 857 858 859 860 861
				mpt += sizeof(*m);
				count += sizeof(*m);
				break;
			}
		case MP_BUS:
			{
862
				struct mpc_bus *m = (struct mpc_bus *)mpt;
Y
Yinghai Lu 已提交
863 864 865 866 867 868
				mpt += sizeof(*m);
				count += sizeof(*m);
				break;
			}
		case MP_IOAPIC:
			{
869 870
				mpt += sizeof(struct mpc_ioapic);
				count += sizeof(struct mpc_ioapic);
Y
Yinghai Lu 已提交
871 872 873 874 875
				break;
			}
		case MP_INTSRC:
			{
#ifdef CONFIG_X86_IO_APIC
876
				struct mpc_intsrc *m = (struct mpc_intsrc *)mpt;
Y
Yinghai Lu 已提交
877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896

				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
897 898
				mpt += sizeof(struct mpc_intsrc);
				count += sizeof(struct mpc_intsrc);
Y
Yinghai Lu 已提交
899 900 901 902
				break;
			}
		case MP_LINTSRC:
			{
903 904
				struct mpc_lintsrc *m =
				    (struct mpc_lintsrc *)mpt;
Y
Yinghai Lu 已提交
905 906 907 908 909 910 911 912 913
				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,
914
					1, mpc, mpc->length, 1);
Y
Yinghai Lu 已提交
915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935
			goto out;
		}
	}

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

		if (mp_irqs[i].mp_irqtype != mp_INT)
			continue;

		if (mp_irqs[i].mp_irqflag != 0x0f)
			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 {
936 937
			struct mpc_intsrc *m = (struct mpc_intsrc *)mpt;
			count += sizeof(struct mpc_intsrc);
Y
Yinghai Lu 已提交
938 939 940 941 942 943 944 945 946 947 948
			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);
949
			mpc->length = count;
950
			mpt += sizeof(struct mpc_intsrc);
Y
Yinghai Lu 已提交
951 952 953 954 955 956
		}
		print_mp_irq_info(&mp_irqs[i]);
	}
#endif
out:
	/* update checksum */
957 958
	mpc->checksum = 0;
	mpc->checksum -= mpf_checksum((unsigned char *)mpc, mpc->length);
Y
Yinghai Lu 已提交
959 960 961 962

	return 0;
}

963 964
static int __initdata enable_update_mptable;

Y
Yinghai Lu 已提交
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 990 991 992 993 994 995 996 997 998 999 1000 1001 1002
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];
1003
	struct mpf_intel *mpf;
1004
	struct mpc_table *mpc, *mpc_new;
Y
Yinghai Lu 已提交
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015

	if (!enable_update_mptable)
		return 0;

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

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

1019
	if (!mpf->physptr)
Y
Yinghai Lu 已提交
1020 1021
		return 0;

1022
	mpc = phys_to_virt(mpf->physptr);
Y
Yinghai Lu 已提交
1023 1024 1025 1026 1027

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

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

1030
	if (mpc_new_phys && mpc->length > mpc_new_length) {
Y
Yinghai Lu 已提交
1031 1032 1033 1034 1035 1036 1037 1038
		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 */
1039 1040 1041 1042
		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 已提交
1043 1044 1045 1046 1047 1048
		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 {
1049
		mpf->physptr = mpc_new_phys;
Y
Yinghai Lu 已提交
1050
		mpc_new = phys_to_virt(mpc_new_phys);
1051
		memcpy(mpc_new, mpc, mpc->length);
Y
Yinghai Lu 已提交
1052 1053
		mpc = mpc_new;
		/* check if we can modify that */
1054
		if (mpc_new_phys - mpf->physptr) {
1055
			struct mpf_intel *mpf_new;
Y
Yinghai Lu 已提交
1056 1057 1058 1059 1060
			/* 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;
1061
			mpf->physptr = mpc_new_phys;
Y
Yinghai Lu 已提交
1062
		}
1063 1064 1065
		mpf->checksum = 0;
		mpf->checksum -= mpf_checksum((unsigned char *)mpf, 16);
		printk(KERN_INFO "physptr new: %x\n", mpf->physptr);
Y
Yinghai Lu 已提交
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079
	}

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