mpparse.c 22.3 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
Linus Torvalds's avatar
Linus Torvalds committed
2
/*
3
 *	Intel Multiprocessor Specification 1.1 and 1.4
Linus Torvalds's avatar
Linus Torvalds committed
4 5
 *	compliant MP-table parsing routines.
 *
6
 *	(c) 1995 Alan Cox, Building #3 <alan@lxorguk.ukuu.org.uk>
Ingo Molnar's avatar
Ingo Molnar committed
7
 *	(c) 1998, 1999, 2000, 2009 Ingo Molnar <mingo@redhat.com>
8
 *      (c) 2008 Alexey Starikovskiy <astarikovskiy@suse.de>
Linus Torvalds's avatar
Linus Torvalds committed
9 10 11 12 13
 */

#include <linux/mm.h>
#include <linux/init.h>
#include <linux/delay.h>
14
#include <linux/memblock.h>
Linus Torvalds's avatar
Linus Torvalds committed
15 16 17
#include <linux/kernel_stat.h>
#include <linux/mc146818rtc.h>
#include <linux/bitops.h>
18
#include <linux/acpi.h>
19
#include <linux/smp.h>
20
#include <linux/pci.h>
Linus Torvalds's avatar
Linus Torvalds committed
21

22
#include <asm/irqdomain.h>
Linus Torvalds's avatar
Linus Torvalds committed
23 24
#include <asm/mtrr.h>
#include <asm/mpspec.h>
25
#include <asm/pgalloc.h>
Linus Torvalds's avatar
Linus Torvalds committed
26
#include <asm/io_apic.h>
27
#include <asm/proto.h>
28
#include <asm/bios_ebda.h>
29
#include <asm/e820/api.h>
Yinghai Lu's avatar
Yinghai Lu committed
30
#include <asm/setup.h>
31
#include <asm/smp.h>
Linus Torvalds's avatar
Linus Torvalds committed
32

Ingo Molnar's avatar
Ingo Molnar committed
33
#include <asm/apic.h>
Linus Torvalds's avatar
Linus Torvalds committed
34 35 36 37 38 39 40 41 42 43 44 45 46 47
/*
 * 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;
}

48 49 50 51 52
int __init default_mpc_apic_id(struct mpc_cpu *m)
{
	return m->apicid;
}

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

58
	if (!(m->cpuflag & CPU_ENABLED)) {
59
		disabled_cpus++;
Linus Torvalds's avatar
Linus Torvalds committed
60
		return;
61
	}
62

63
	apicid = x86_init.mpparse.mpc_apic_id(m);
64

65
	if (m->cpuflag & CPU_BOOTPROCESSOR) {
66
		bootup_cpu = " (Bootup-CPU)";
67
		boot_cpu_physical_apicid = m->apicid;
Linus Torvalds's avatar
Linus Torvalds committed
68 69
	}

70
	pr_info("Processor #%d%s\n", m->apicid, bootup_cpu);
71
	generic_processor_info(apicid, m->apicver);
Linus Torvalds's avatar
Linus Torvalds committed
72 73
}

Thomas Gleixner's avatar
Thomas Gleixner committed
74
#ifdef CONFIG_X86_IO_APIC
75
void __init default_mpc_oem_bus_info(struct mpc_bus *m, char *str)
Linus Torvalds's avatar
Linus Torvalds committed
76
{
77
	memcpy(str, m->bustype, 6);
Linus Torvalds's avatar
Linus Torvalds committed
78
	str[6] = 0;
79 80
	apic_printk(APIC_VERBOSE, "Bus #%d is %s\n", m->busid, str);
}
Linus Torvalds's avatar
Linus Torvalds committed
81

82 83 84
static void __init MP_bus_info(struct mpc_bus *m)
{
	char str[7];
Linus Torvalds's avatar
Linus Torvalds committed
85

86
	x86_init.mpparse.mpc_oem_bus_info(m, str);
Linus Torvalds's avatar
Linus Torvalds committed
87

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

96
	set_bit(m->busid, mp_bus_not_pci);
Alexey Starikovskiy's avatar
Alexey Starikovskiy committed
97
	if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA) - 1) == 0) {
98
#ifdef CONFIG_EISA
99
		mp_bus_id_to_type[m->busid] = MP_BUS_ISA;
Alexey Starikovskiy's avatar
Alexey Starikovskiy committed
100 101
#endif
	} else if (strncmp(str, BUSTYPE_PCI, sizeof(BUSTYPE_PCI) - 1) == 0) {
102 103
		if (x86_init.mpparse.mpc_oem_pci_bus)
			x86_init.mpparse.mpc_oem_pci_bus(m);
104

105
		clear_bit(m->busid, mp_bus_not_pci);
106
#ifdef CONFIG_EISA
107
		mp_bus_id_to_type[m->busid] = MP_BUS_PCI;
108
	} else if (strncmp(str, BUSTYPE_EISA, sizeof(BUSTYPE_EISA) - 1) == 0) {
109
		mp_bus_id_to_type[m->busid] = MP_BUS_EISA;
110
#endif
Alexey Starikovskiy's avatar
Alexey Starikovskiy committed
111
	} else
112
		pr_warn("Unknown bustype %s - ignoring\n", str);
Linus Torvalds's avatar
Linus Torvalds committed
113
}
114

115
static void __init MP_ioapic_info(struct mpc_ioapic *m)
Linus Torvalds's avatar
Linus Torvalds committed
116
{
117 118 119 120 121
	struct ioapic_domain_cfg cfg = {
		.type = IOAPIC_DOMAIN_LEGACY,
		.ops = &mp_ioapic_irqdomain_ops,
	};

122
	if (m->flags & MPC_APIC_USABLE)
123
		mp_register_ioapic(m->apicid, m->apicaddr, gsi_top, &cfg);
Yinghai Lu's avatar
Yinghai Lu committed
124 125
}

126
static void __init print_mp_irq_info(struct mpc_intsrc *mp_irq)
Yinghai Lu's avatar
Yinghai Lu committed
127
{
128 129
	apic_printk(APIC_VERBOSE,
		"Int: type %d, pol %d, trig %d, bus %02x, IRQ %02x, APIC ID %x, APIC INT %02x\n",
130 131 132
		mp_irq->irqtype, mp_irq->irqflag & 3,
		(mp_irq->irqflag >> 2) & 3, mp_irq->srcbus,
		mp_irq->srcbusirq, mp_irq->dstapic, mp_irq->dstirq);
Yinghai Lu's avatar
Yinghai Lu committed
133 134
}

135 136 137 138
#else /* CONFIG_X86_IO_APIC */
static inline void __init MP_bus_info(struct mpc_bus *m) {}
static inline void __init MP_ioapic_info(struct mpc_ioapic *m) {}
#endif /* CONFIG_X86_IO_APIC */
Linus Torvalds's avatar
Linus Torvalds committed
139

140
static void __init MP_lintsrc_info(struct mpc_lintsrc *m)
Linus Torvalds's avatar
Linus Torvalds committed
141
{
142 143
	apic_printk(APIC_VERBOSE,
		"Lint: type %d, pol %d, trig %d, bus %02x, IRQ %02x, APIC ID %x, APIC LINT %02x\n",
144 145
		m->irqtype, m->irqflag & 3, (m->irqflag >> 2) & 3, m->srcbusid,
		m->srcbusirq, m->destapic, m->destapiclint);
Linus Torvalds's avatar
Linus Torvalds committed
146 147 148 149 150
}

/*
 * Read/parse the MPC
 */
151
static int __init smp_check_mpc(struct mpc_table *mpc, char *oem, char *str)
Linus Torvalds's avatar
Linus Torvalds committed
152 153
{

154
	if (memcmp(mpc->signature, MPC_SIGNATURE, 4)) {
155
		pr_err("MPTABLE: bad signature [%c%c%c%c]!\n",
156 157
		       mpc->signature[0], mpc->signature[1],
		       mpc->signature[2], mpc->signature[3]);
Linus Torvalds's avatar
Linus Torvalds committed
158 159
		return 0;
	}
160
	if (mpf_checksum((unsigned char *)mpc, mpc->length)) {
161
		pr_err("MPTABLE: checksum error!\n");
Linus Torvalds's avatar
Linus Torvalds committed
162 163
		return 0;
	}
164
	if (mpc->spec != 0x01 && mpc->spec != 0x04) {
165
		pr_err("MPTABLE: bad table version (%d)!!\n", mpc->spec);
Linus Torvalds's avatar
Linus Torvalds committed
166 167
		return 0;
	}
168
	if (!mpc->lapic) {
169
		pr_err("MPTABLE: null local APIC address!\n");
Linus Torvalds's avatar
Linus Torvalds committed
170 171
		return 0;
	}
172
	memcpy(oem, mpc->oem, 8);
173
	oem[8] = 0;
174
	pr_info("MPTABLE: OEM ID: %s\n", oem);
Linus Torvalds's avatar
Linus Torvalds committed
175

176
	memcpy(str, mpc->productid, 12);
177
	str[12] = 0;
Linus Torvalds's avatar
Linus Torvalds committed
178

179
	pr_info("MPTABLE: Product ID: %s\n", str);
Linus Torvalds's avatar
Linus Torvalds committed
180

181
	pr_info("MPTABLE: APIC at: 0x%X\n", mpc->lapic);
Linus Torvalds's avatar
Linus Torvalds committed
182

Yinghai Lu's avatar
Yinghai Lu committed
183 184 185
	return 1;
}

186 187 188 189 190 191
static void skip_entry(unsigned char **ptr, int *count, int size)
{
	*ptr += size;
	*count += size;
}

192 193
static void __init smp_dump_mptable(struct mpc_table *mpc, unsigned char *mpt)
{
194 195
	pr_err("Your mptable is wrong, contact your HW vendor!\n");
	pr_cont("type %x\n", *mpt);
196 197 198 199
	print_hex_dump(KERN_ERR, "  ", DUMP_PREFIX_ADDRESS, 16,
			1, mpc, mpc->length, 1);
}

200 201
void __init default_smp_read_mpc_oem(struct mpc_table *mpc) { }

202
static int __init smp_read_mpc(struct mpc_table *mpc, unsigned early)
Yinghai Lu's avatar
Yinghai Lu committed
203 204 205 206 207 208 209 210 211 212
{
	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;

213
	/* Initialize the lapic mapping */
Linus Torvalds's avatar
Linus Torvalds committed
214
	if (!acpi_lapic)
215
		register_lapic_address(mpc->lapic);
Linus Torvalds's avatar
Linus Torvalds committed
216

217 218 219
	if (early)
		return 1;

220 221
	if (mpc->oemptr)
		x86_init.mpparse.smp_read_mpc_oem(mpc);
222

Linus Torvalds's avatar
Linus Torvalds committed
223
	/*
224
	 *      Now process the configuration blocks.
Linus Torvalds's avatar
Linus Torvalds committed
225
	 */
226
	x86_init.mpparse.mpc_record(0);
227

228
	while (count < mpc->length) {
229 230
		switch (*mpt) {
		case MP_PROCESSOR:
231 232
			/* ACPI may have already provided this data */
			if (!acpi_lapic)
233
				MP_processor_info((struct mpc_cpu *)mpt);
234 235
			skip_entry(&mpt, &count, sizeof(struct mpc_cpu));
			break;
236
		case MP_BUS:
237
			MP_bus_info((struct mpc_bus *)mpt);
238 239
			skip_entry(&mpt, &count, sizeof(struct mpc_bus));
			break;
240
		case MP_IOAPIC:
241
			MP_ioapic_info((struct mpc_ioapic *)mpt);
242 243
			skip_entry(&mpt, &count, sizeof(struct mpc_ioapic));
			break;
244
		case MP_INTSRC:
245
			mp_save_irq((struct mpc_intsrc *)mpt);
246 247
			skip_entry(&mpt, &count, sizeof(struct mpc_intsrc));
			break;
248
		case MP_LINTSRC:
249
			MP_lintsrc_info((struct mpc_lintsrc *)mpt);
250 251
			skip_entry(&mpt, &count, sizeof(struct mpc_lintsrc));
			break;
252
		default:
Yinghai Lu's avatar
Yinghai Lu committed
253
			/* wrong mptable */
254
			smp_dump_mptable(mpc, mpt);
255
			count = mpc->length;
Yinghai Lu's avatar
Yinghai Lu committed
256
			break;
Linus Torvalds's avatar
Linus Torvalds committed
257
		}
258
		x86_init.mpparse.mpc_record(1);
Linus Torvalds's avatar
Linus Torvalds committed
259
	}
260

Linus Torvalds's avatar
Linus Torvalds committed
261
	if (!num_processors)
262
		pr_err("MPTABLE: no processors registered!\n");
Linus Torvalds's avatar
Linus Torvalds committed
263 264 265
	return num_processors;
}

266 267
#ifdef CONFIG_X86_IO_APIC

Linus Torvalds's avatar
Linus Torvalds committed
268 269 270 271 272 273 274 275 276 277
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)
{
278
	struct mpc_intsrc intsrc;
Linus Torvalds's avatar
Linus Torvalds committed
279 280 281
	int i;
	int ELCR_fallback = 0;

282
	intsrc.type = MP_INTSRC;
283
	intsrc.irqflag = MP_IRQTRIG_DEFAULT | MP_IRQPOL_DEFAULT;
284
	intsrc.srcbus = 0;
285
	intsrc.dstapic = mpc_ioapic_id(0);
Linus Torvalds's avatar
Linus Torvalds committed
286

287
	intsrc.irqtype = mp_INT;
Linus Torvalds's avatar
Linus Torvalds committed
288 289 290 291 292 293 294 295 296 297

	/*
	 *  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) {
298
		pr_info("ISA/PCI bus type with no IRQ information... falling back to ELCR\n");
Linus Torvalds's avatar
Linus Torvalds committed
299

300 301
		if (ELCR_trigger(0) || ELCR_trigger(1) || ELCR_trigger(2) ||
		    ELCR_trigger(13))
302
			pr_err("ELCR contains invalid data... not using ELCR\n");
Linus Torvalds's avatar
Linus Torvalds committed
303
		else {
304
			pr_info("Using ELCR to identify PCI interrupts\n");
Linus Torvalds's avatar
Linus Torvalds committed
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
			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).
			 */
326 327 328 329 330 331 332
			if (ELCR_trigger(i)) {
				intsrc.irqflag = MP_IRQTRIG_LEVEL |
						 MP_IRQPOL_ACTIVE_HIGH;
			} else {
				intsrc.irqflag = MP_IRQTRIG_DEFAULT |
						 MP_IRQPOL_DEFAULT;
			}
Linus Torvalds's avatar
Linus Torvalds committed
333 334
		}

335 336
		intsrc.srcbusirq = i;
		intsrc.dstirq = i ? i : 2;	/* IRQ0 to INTIN2 */
337
		mp_save_irq(&intsrc);
Linus Torvalds's avatar
Linus Torvalds committed
338 339
	}

340 341 342
	intsrc.irqtype = mp_ExtINT;
	intsrc.srcbusirq = 0;
	intsrc.dstirq = 0;	/* 8259A to INTIN0 */
343
	mp_save_irq(&intsrc);
Linus Torvalds's avatar
Linus Torvalds committed
344 345
}

346

347
static void __init construct_ioapic_table(int mpc_default_type)
Linus Torvalds's avatar
Linus Torvalds committed
348
{
349
	struct mpc_ioapic ioapic;
350
	struct mpc_bus bus;
Linus Torvalds's avatar
Linus Torvalds committed
351

352 353
	bus.type = MP_BUS;
	bus.busid = 0;
Linus Torvalds's avatar
Linus Torvalds committed
354
	switch (mpc_default_type) {
355
	default:
356
		pr_err("???\nUnknown standard configuration %d\n",
357 358 359 360
		       mpc_default_type);
		/* fall through */
	case 1:
	case 5:
361
		memcpy(bus.bustype, "ISA   ", 6);
362 363 364 365
		break;
	case 2:
	case 6:
	case 3:
366
		memcpy(bus.bustype, "EISA  ", 6);
367
		break;
Linus Torvalds's avatar
Linus Torvalds committed
368 369 370
	}
	MP_bus_info(&bus);
	if (mpc_default_type > 4) {
371 372
		bus.busid = 1;
		memcpy(bus.bustype, "PCI   ", 6);
Linus Torvalds's avatar
Linus Torvalds committed
373 374 375
		MP_bus_info(&bus);
	}

376 377 378 379 380
	ioapic.type	= MP_IOAPIC;
	ioapic.apicid	= 2;
	ioapic.apicver	= mpc_default_type > 4 ? 0x10 : 0x01;
	ioapic.flags	= MPC_APIC_USABLE;
	ioapic.apicaddr	= IO_APIC_DEFAULT_PHYS_BASE;
Linus Torvalds's avatar
Linus Torvalds committed
381 382 383 384 385 386
	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);
Thomas Gleixner's avatar
Thomas Gleixner committed
387 388
}
#else
389
static inline void __init construct_ioapic_table(int mpc_default_type) { }
390
#endif
Thomas Gleixner's avatar
Thomas Gleixner committed
391 392 393

static inline void __init construct_default_ISA_mptable(int mpc_default_type)
{
394
	struct mpc_cpu processor;
395
	struct mpc_lintsrc lintsrc;
Thomas Gleixner's avatar
Thomas Gleixner committed
396 397 398 399 400 401 402 403 404 405 406
	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.
	 */
407
	processor.type = MP_PROCESSOR;
Thomas Gleixner's avatar
Thomas Gleixner committed
408
	/* Either an integrated APIC or a discrete 82489DX. */
409 410 411
	processor.apicver = mpc_default_type > 4 ? 0x10 : 0x01;
	processor.cpuflag = CPU_ENABLED;
	processor.cpufeature = (boot_cpu_data.x86 << 8) |
412
	    (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_stepping;
413
	processor.featureflag = boot_cpu_data.x86_capability[CPUID_1_EDX];
414 415
	processor.reserved[0] = 0;
	processor.reserved[1] = 0;
Thomas Gleixner's avatar
Thomas Gleixner committed
416
	for (i = 0; i < 2; i++) {
417
		processor.apicid = i;
Thomas Gleixner's avatar
Thomas Gleixner committed
418 419 420 421 422
		MP_processor_info(&processor);
	}

	construct_ioapic_table(mpc_default_type);

423
	lintsrc.type = MP_LINTSRC;
424
	lintsrc.irqflag = MP_IRQTRIG_DEFAULT | MP_IRQPOL_DEFAULT;
425 426 427
	lintsrc.srcbusid = 0;
	lintsrc.srcbusirq = 0;
	lintsrc.destapic = MP_APIC_ALL;
Linus Torvalds's avatar
Linus Torvalds committed
428
	for (i = 0; i < 2; i++) {
429 430
		lintsrc.irqtype = linttypes[i];
		lintsrc.destapiclint = i;
Linus Torvalds's avatar
Linus Torvalds committed
431 432 433 434
		MP_lintsrc_info(&lintsrc);
	}
}

435
static unsigned long mpf_base;
436
static bool mpf_found;
Linus Torvalds's avatar
Linus Torvalds committed
437

Yinghai Lu's avatar
Yinghai Lu committed
438 439 440 441 442
static unsigned long __init get_mpc_size(unsigned long physptr)
{
	struct mpc_table *mpc;
	unsigned long size;

443
	mpc = early_memremap(physptr, PAGE_SIZE);
Yinghai Lu's avatar
Yinghai Lu committed
444
	size = mpc->length;
445
	early_memunmap(mpc, PAGE_SIZE);
Yinghai Lu's avatar
Yinghai Lu committed
446 447 448 449 450
	apic_printk(APIC_VERBOSE, "  mpc: %lx-%lx\n", physptr, physptr + size);

	return size;
}

451 452 453 454 455 456
static int __init check_physptr(struct mpf_intel *mpf, unsigned int early)
{
	struct mpc_table *mpc;
	unsigned long size;

	size = get_mpc_size(mpf->physptr);
457
	mpc = early_memremap(mpf->physptr, size);
458

459 460 461 462 463 464 465 466
	/*
	 * Read the physical hardware table.  Anything here will
	 * override the defaults.
	 */
	if (!smp_read_mpc(mpc, early)) {
#ifdef CONFIG_X86_LOCAL_APIC
		smp_found_config = 0;
#endif
467 468
		pr_err("BIOS bug, MP table errors detected!...\n");
		pr_cont("... disabling SMP support. (tell your hw vendor)\n");
469
		early_memunmap(mpc, size);
470 471
		return -1;
	}
472
	early_memunmap(mpc, size);
473 474 475 476 477 478 479 480 481 482 483 484 485

	if (early)
		return -1;

#ifdef CONFIG_X86_IO_APIC
	/*
	 * 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) {
		struct mpc_bus bus;

486
		pr_err("BIOS bug, no explicit IRQ entries, using default mptable. (tell your hw vendor)\n");
487 488 489 490 491 492 493 494 495 496 497 498 499

		bus.type = MP_BUS;
		bus.busid = 0;
		memcpy(bus.bustype, "ISA   ", 6);
		MP_bus_info(&bus);

		construct_default_ioirq_mptable(0);
	}
#endif

	return 0;
}

Linus Torvalds's avatar
Linus Torvalds committed
500 501 502
/*
 * Scan the memory blocks for an SMP configuration block.
 */
503
void __init default_get_smp_config(unsigned int early)
Linus Torvalds's avatar
Linus Torvalds committed
504
{
505
	struct mpf_intel *mpf;
Linus Torvalds's avatar
Linus Torvalds committed
506

507 508 509
	if (!smp_found_config)
		return;

510
	if (!mpf_found)
Yinghai Lu's avatar
Yinghai Lu committed
511 512
		return;

513 514
	if (acpi_lapic && early)
		return;
Yinghai Lu's avatar
Yinghai Lu committed
515

Linus Torvalds's avatar
Linus Torvalds committed
516
	/*
Yinghai Lu's avatar
Yinghai Lu committed
517 518
	 * MPS doesn't support hyperthreading, aka only have
	 * thread 0 apic id in MPS table
Linus Torvalds's avatar
Linus Torvalds committed
519
	 */
Yinghai Lu's avatar
Yinghai Lu committed
520
	if (acpi_lapic && acpi_ioapic)
Linus Torvalds's avatar
Linus Torvalds committed
521 522
		return;

523 524 525 526 527 528
	mpf = early_memremap(mpf_base, sizeof(*mpf));
	if (!mpf) {
		pr_err("MPTABLE: error mapping MP table\n");
		return;
	}

529 530
	pr_info("Intel MultiProcessor Specification v1.%d\n",
		mpf->specification);
531
#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_32)
532
	if (mpf->feature2 & (1 << 7)) {
533
		pr_info("    IMCR and PIC compatibility mode.\n");
Linus Torvalds's avatar
Linus Torvalds committed
534 535
		pic_mode = 1;
	} else {
536
		pr_info("    Virtual Wire compatibility mode.\n");
Linus Torvalds's avatar
Linus Torvalds committed
537 538
		pic_mode = 0;
	}
539
#endif
Linus Torvalds's avatar
Linus Torvalds committed
540 541 542
	/*
	 * Now see if we need to read further.
	 */
543
	if (mpf->feature1) {
544 545 546 547 548
		if (early) {
			/*
			 * local APIC has default address
			 */
			mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
549
			goto out;
550
		}
Linus Torvalds's avatar
Linus Torvalds committed
551

552
		pr_info("Default MP configuration #%d\n", mpf->feature1);
553
		construct_default_ISA_mptable(mpf->feature1);
Linus Torvalds's avatar
Linus Torvalds committed
554

555
	} else if (mpf->physptr) {
556 557
		if (check_physptr(mpf, early))
			goto out;
Linus Torvalds's avatar
Linus Torvalds committed
558 559 560
	} else
		BUG();

561
	if (!early)
562
		pr_info("Processors: %d\n", num_processors);
Linus Torvalds's avatar
Linus Torvalds committed
563 564 565
	/*
	 * Only use the first configuration found.
	 */
566
out:
567
	early_memunmap(mpf, sizeof(*mpf));
Linus Torvalds's avatar
Linus Torvalds committed
568 569
}

570
static void __init smp_reserve_memory(struct mpf_intel *mpf)
571
{
572
	memblock_reserve(mpf->physptr, get_mpc_size(mpf->physptr));
573 574
}

575
static int __init smp_scan_config(unsigned long base, unsigned long length)
Linus Torvalds's avatar
Linus Torvalds committed
576
{
577
	unsigned int *bp;
578
	struct mpf_intel *mpf;
579
	int ret = 0;
Linus Torvalds's avatar
Linus Torvalds committed
580

581 582
	apic_printk(APIC_VERBOSE, "Scan for SMP in [mem %#010lx-%#010lx]\n",
		    base, base + length - 1);
583
	BUILD_BUG_ON(sizeof(*mpf) != 16);
Linus Torvalds's avatar
Linus Torvalds committed
584 585

	while (length > 0) {
586
		bp = early_memremap(base, length);
587
		mpf = (struct mpf_intel *)bp;
Linus Torvalds's avatar
Linus Torvalds committed
588
		if ((*bp == SMP_MAGIC_IDENT) &&
589
		    (mpf->length == 1) &&
590
		    !mpf_checksum((unsigned char *)bp, 16) &&
591 592
		    ((mpf->specification == 1)
		     || (mpf->specification == 4))) {
593
#ifdef CONFIG_X86_LOCAL_APIC
Linus Torvalds's avatar
Linus Torvalds committed
594
			smp_found_config = 1;
595
#endif
596
			mpf_base = base;
597
			mpf_found = true;
598

599 600
			pr_info("found SMP MP-table at [mem %#010lx-%#010lx]\n",
				base, base + sizeof(*mpf) - 1);
601

602
			memblock_reserve(base, sizeof(*mpf));
603
			if (mpf->physptr)
604
				smp_reserve_memory(mpf);
Linus Torvalds's avatar
Linus Torvalds committed
605

606
			ret = 1;
Linus Torvalds's avatar
Linus Torvalds committed
607
		}
608 609 610 611 612 613
		early_memunmap(bp, length);

		if (ret)
			break;

		base += 16;
Linus Torvalds's avatar
Linus Torvalds committed
614 615
		length -= 16;
	}
616
	return ret;
Linus Torvalds's avatar
Linus Torvalds committed
617 618
}

619
void __init default_find_smp_config(void)
Linus Torvalds's avatar
Linus Torvalds committed
620 621 622 623 624 625 626 627 628 629 630
{
	unsigned int address;

	/*
	 * 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
	 */
631 632 633
	if (smp_scan_config(0x0, 0x400) ||
	    smp_scan_config(639 * 0x400, 0x400) ||
	    smp_scan_config(0xF0000, 0x10000))
Linus Torvalds's avatar
Linus Torvalds committed
634 635 636
		return;
	/*
	 * If it is an SMP machine we should know now, unless the
637
	 * configuration is in an EISA bus machine with an
Linus Torvalds's avatar
Linus Torvalds committed
638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
	 * 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)
654
		smp_scan_config(address, 0x400);
655 656
}

Yinghai Lu's avatar
Yinghai Lu committed
657 658 659
#ifdef CONFIG_X86_IO_APIC
static u8 __initdata irq_used[MAX_IRQ_SOURCES];

660
static int  __init get_MP_intsrc_index(struct mpc_intsrc *m)
Yinghai Lu's avatar
Yinghai Lu committed
661 662 663
{
	int i;

664
	if (m->irqtype != mp_INT)
Yinghai Lu's avatar
Yinghai Lu committed
665 666
		return 0;

667
	if (m->irqflag != (MP_IRQTRIG_LEVEL | MP_IRQPOL_ACTIVE_LOW))
Yinghai Lu's avatar
Yinghai Lu committed
668 669 670 671 672
		return 0;

	/* not legacy */

	for (i = 0; i < mp_irq_entries; i++) {
673
		if (mp_irqs[i].irqtype != mp_INT)
Yinghai Lu's avatar
Yinghai Lu committed
674 675
			continue;

676 677
		if (mp_irqs[i].irqflag != (MP_IRQTRIG_LEVEL |
					   MP_IRQPOL_ACTIVE_LOW))
Yinghai Lu's avatar
Yinghai Lu committed
678 679
			continue;

680
		if (mp_irqs[i].srcbus != m->srcbus)
Yinghai Lu's avatar
Yinghai Lu committed
681
			continue;
682
		if (mp_irqs[i].srcbusirq != m->srcbusirq)
Yinghai Lu's avatar
Yinghai Lu committed
683 684 685 686 687 688 689 690 691 692 693 694 695 696 697
			continue;
		if (irq_used[i]) {
			/* already claimed */
			return -2;
		}
		irq_used[i] = 1;
		return i;
	}

	/* not found */
	return -1;
}

#define SPARE_SLOT_NUM 20

698
static struct mpc_intsrc __initdata *m_spare[SPARE_SLOT_NUM];
699

700
static void __init check_irq_src(struct mpc_intsrc *m, int *nr_m_spare)
701 702 703 704
{
	int i;

	apic_printk(APIC_VERBOSE, "OLD ");
705
	print_mp_irq_info(m);
706 707 708

	i = get_MP_intsrc_index(m);
	if (i > 0) {
709
		memcpy(m, &mp_irqs[i], sizeof(*m));
710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
		apic_printk(APIC_VERBOSE, "NEW ");
		print_mp_irq_info(&mp_irqs[i]);
		return;
	}
	if (!i) {
		/* legacy, do nothing */
		return;
	}
	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 += 1;
	}
}

728
static int __init
Yinghai Lu's avatar
Yinghai Lu committed
729
check_slot(unsigned long mpc_new_phys, unsigned long mpc_new_length, int count)
730
{
Yinghai Lu's avatar
Yinghai Lu committed
731 732 733
	if (!mpc_new_phys || count <= mpc_new_length) {
		WARN(1, "update_mptable: No spare slots (length: %x)\n", count);
		return -1;
734 735
	}

736
	return 0;
737
}
738 739 740 741
#else /* CONFIG_X86_IO_APIC */
static
inline void __init check_irq_src(struct mpc_intsrc *m, int *nr_m_spare) {}
#endif /* CONFIG_X86_IO_APIC */
Yinghai Lu's avatar
Yinghai Lu committed
742

743
static int  __init replace_intsrc_all(struct mpc_table *mpc,
Yinghai Lu's avatar
Yinghai Lu committed
744 745 746 747 748 749 750
					unsigned long mpc_new_phys,
					unsigned long mpc_new_length)
{
#ifdef CONFIG_X86_IO_APIC
	int i;
#endif
	int count = sizeof(*mpc);
751
	int nr_m_spare = 0;
Yinghai Lu's avatar
Yinghai Lu committed
752 753
	unsigned char *mpt = ((unsigned char *)mpc) + count;

754
	pr_info("mpc_length %x\n", mpc->length);
755
	while (count < mpc->length) {
Yinghai Lu's avatar
Yinghai Lu committed
756 757
		switch (*mpt) {
		case MP_PROCESSOR:
758 759
			skip_entry(&mpt, &count, sizeof(struct mpc_cpu));
			break;
Yinghai Lu's avatar
Yinghai Lu committed
760
		case MP_BUS:
761 762
			skip_entry(&mpt, &count, sizeof(struct mpc_bus));
			break;
Yinghai Lu's avatar
Yinghai Lu committed
763
		case MP_IOAPIC:
764 765
			skip_entry(&mpt, &count, sizeof(struct mpc_ioapic));
			break;
Yinghai Lu's avatar
Yinghai Lu committed
766
		case MP_INTSRC:
767
			check_irq_src((struct mpc_intsrc *)mpt, &nr_m_spare);
768 769
			skip_entry(&mpt, &count, sizeof(struct mpc_intsrc));
			break;
Yinghai Lu's avatar
Yinghai Lu committed
770
		case MP_LINTSRC:
771 772
			skip_entry(&mpt, &count, sizeof(struct mpc_lintsrc));
			break;
Yinghai Lu's avatar
Yinghai Lu committed
773 774
		default:
			/* wrong mptable */
775
			smp_dump_mptable(mpc, mpt);
Yinghai Lu's avatar
Yinghai Lu committed
776 777 778 779 780 781 782 783 784
			goto out;
		}
	}

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

785
		if (mp_irqs[i].irqtype != mp_INT)
Yinghai Lu's avatar
Yinghai Lu committed
786 787
			continue;

788 789
		if (mp_irqs[i].irqflag != (MP_IRQTRIG_LEVEL |
					   MP_IRQPOL_ACTIVE_LOW))
Yinghai Lu's avatar
Yinghai Lu committed
790 791 792
			continue;

		if (nr_m_spare > 0) {
793
			apic_printk(APIC_VERBOSE, "*NEW* found\n");
Yinghai Lu's avatar
Yinghai Lu committed
794
			nr_m_spare--;
795
			memcpy(m_spare[nr_m_spare], &mp_irqs[i], sizeof(mp_irqs[i]));
Yinghai Lu's avatar
Yinghai Lu committed
796 797
			m_spare[nr_m_spare] = NULL;
		} else {
798 799
			struct mpc_intsrc *m = (struct mpc_intsrc *)mpt;
			count += sizeof(struct mpc_intsrc);
Yinghai Lu's avatar
Yinghai Lu committed
800
			if (check_slot(mpc_new_phys, mpc_new_length, count) < 0)
801
				goto out;
802
			memcpy(m, &mp_irqs[i], sizeof(*m));
803
			mpc->length = count;
804
			mpt += sizeof(struct mpc_intsrc);
Yinghai Lu's avatar
Yinghai Lu committed
805 806 807 808 809 810
		}
		print_mp_irq_info(&mp_irqs[i]);
	}
#endif
out:
	/* update checksum */
811 812
	mpc->checksum = 0;
	mpc->checksum -= mpf_checksum((unsigned char *)mpc, mpc->length);
Yinghai Lu's avatar
Yinghai Lu committed
813 814 815 816

	return 0;
}

817
int enable_update_mptable;
818

Yinghai Lu's avatar
Yinghai Lu committed
819 820 821
static int __init update_mptable_setup(char *str)
{
	enable_update_mptable = 1;
822 823 824
#ifdef CONFIG_PCI
	pci_routeirq = 1;
#endif
Yinghai Lu's avatar
Yinghai Lu committed
825 826 827 828 829 830 831 832 833 834 835 836
	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;
837 838 839
#ifdef CONFIG_PCI
	pci_routeirq = 1;
#endif
Yinghai Lu's avatar
Yinghai Lu committed
840 841 842 843 844 845 846 847
	alloc_mptable = 1;
	if (!p)
		return 0;
	mpc_new_length = memparse(p, &p);
	return 0;
}
early_param("alloc_mptable", parse_alloc_mptable_opt);

848
void __init e820__memblock_alloc_reserved_mpc_new(void)
Yinghai Lu's avatar
Yinghai Lu committed
849
{
850
	if (enable_update_mptable && alloc_mptable)
851
		mpc_new_phys = e820__memblock_alloc_reserved(mpc_new_length, 4);
Yinghai Lu's avatar
Yinghai Lu committed
852 853 854 855 856 857
}

static int __init update_mp_table(void)
{
	char str[16];
	char oem[10];
858
	struct mpf_intel *mpf;
859
	struct mpc_table *mpc, *mpc_new;
860
	unsigned long size;
Yinghai Lu's avatar
Yinghai Lu committed
861 862 863 864

	if (!enable_update_mptable)
		return 0;

865
	if (!mpf_found)
866 867 868 869 870
		return 0;

	mpf = early_memremap(mpf_base, sizeof(*mpf));
	if (!mpf) {
		pr_err("MPTABLE: mpf early_memremap() failed\n");
Yinghai Lu's avatar
Yinghai Lu committed
871
		return 0;
872
	}
Yinghai Lu's avatar
Yinghai Lu committed
873 874 875 876

	/*
	 * Now see if we need to go further.
	 */
877 878
	if (mpf->feature1)
		goto do_unmap_mpf;
Yinghai Lu's avatar
Yinghai Lu committed
879

880
	if (!mpf->physptr)
881
		goto do_unmap_mpf;
Yinghai Lu's avatar
Yinghai Lu committed
882

883 884 885 886 887 888
	size = get_mpc_size(mpf->physptr);
	mpc = early_memremap(mpf->physptr, size);
	if (!mpc) {
		pr_err("MPTABLE: mpc early_memremap() failed\n");
		goto do_unmap_mpf;
	}
Yinghai Lu's avatar
Yinghai Lu committed
889 890

	if (!smp_check_mpc(mpc, oem, str))
891
		goto do_unmap_mpc;
Yinghai Lu's avatar
Yinghai Lu committed
892

893
	pr_info("mpf: %llx\n", (u64)mpf_base);
894
	pr_info("physptr: %x\n", mpf->physptr);
Yinghai Lu's avatar
Yinghai Lu committed
895

896
	if (mpc_new_phys && mpc->length > mpc_new_length) {
Yinghai Lu's avatar
Yinghai Lu committed
897
		mpc_new_phys = 0;
898 899
		pr_info("mpc_new_length is %ld, please use alloc_mptable=8k\n",
			mpc_new_length);
Yinghai Lu's avatar
Yinghai Lu committed
900 901 902 903
	}

	if (!mpc_new_phys) {
		unsigned char old, new;
904
		/* check if we can change the position */
905 906 907 908
		mpc->checksum = 0;
		old = mpf_checksum((unsigned char *)mpc, mpc->length);
		mpc->checksum = 0xff;
		new = mpf_checksum((unsigned char *)mpc, mpc->length);
Yinghai Lu's avatar
Yinghai Lu committed
909
		if (old == new) {
910
			pr_info("mpc is readonly, please try alloc_mptable instead\n");
911
			goto do_unmap_mpc;
Yinghai Lu's avatar
Yinghai Lu committed
912
		}
913
		pr_info("use in-position replacing\n");
Yinghai Lu's avatar
Yinghai Lu committed
914
	} else {
915 916 917 918 919
		mpc_new = early_memremap(mpc_new_phys, mpc_new_length);
		if (!mpc_new) {
			pr_err("MPTABLE: new mpc early_memremap() failed\n");
			goto do_unmap_mpc;
		}
920
		mpf->physptr = mpc_new_phys;
921
		memcpy(mpc_new, mpc, mpc->length);
922
		early_memunmap(mpc, size);
Yinghai Lu's avatar
Yinghai Lu committed
923
		mpc = mpc_new;
924
		size = mpc_new_length;
Yinghai Lu's avatar
Yinghai Lu committed
925
		/* check if we can modify that */
926
		if (mpc_new_phys - mpf->physptr) {
927
			struct mpf_intel *mpf_new;
Yinghai Lu's avatar
Yinghai Lu committed
928
			/* steal 16 bytes from [0, 1k) */
929 930 931 932 933
			mpf_new = early_memremap(0x400 - 16, sizeof(*mpf_new));
			if (!mpf_new) {
				pr_err("MPTABLE: new mpf early_memremap() failed\n");
				goto do_unmap_mpc;
			}
934
			pr_info("mpf new: %x\n", 0x400 - 16);
Yinghai Lu's avatar
Yinghai Lu committed
935
			memcpy(mpf_new, mpf, 16);
936
			early_memunmap(mpf, sizeof(*mpf));
Yinghai Lu's avatar
Yinghai Lu committed
937
			mpf = mpf_new;
938
			mpf->physptr = mpc_new_phys;
Yinghai Lu's avatar
Yinghai Lu committed
939
		}
940 941
		mpf->checksum = 0;
		mpf->checksum -= mpf_checksum((unsigned char *)mpf, 16);
942
		pr_info("physptr new: %x\n", mpf->physptr);
Yinghai Lu's avatar
Yinghai Lu committed
943 944 945 946 947 948 949 950 951 952
	}

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

953 954 955 956 957 958
do_unmap_mpc:
	early_memunmap(mpc, size);

do_unmap_mpf:
	early_memunmap(mpf, sizeof(*mpf));

Yinghai Lu's avatar
Yinghai Lu committed
959 960 961 962
	return 0;
}

late_initcall(update_mp_table);