mpparse_64.c 20.0 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 *	Intel Multiprocessor Specification 1.1 and 1.4
 *	compliant MP-table parsing routines.
 *
 *	(c) 1995 Alan Cox, Building #3 <alan@redhat.com>
 *	(c) 1998, 1999, 2000 Ingo Molnar <mingo@redhat.com>
 *
 *	Fixes
 *		Erich Boleyn	:	MP v1.4 and additional changes.
 *		Alan Cox	:	Added EBDA scanning
 *		Ingo Molnar	:	various cleanups and rewrites
 *		Maciej W. Rozycki:	Bits for default MP configurations
 *		Paul Diefenbaugh:	Added full ACPI support
 */

#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/acpi.h>
23
#include <linux/module.h>
L
Linus Torvalds 已提交
24 25 26 27 28 29 30

#include <asm/smp.h>
#include <asm/mtrr.h>
#include <asm/mpspec.h>
#include <asm/pgalloc.h>
#include <asm/io_apic.h>
#include <asm/proto.h>
31
#include <asm/acpi.h>
32
#include <asm/bios_ebda.h>
L
Linus Torvalds 已提交
33

34 35
#include <mach_apic.h>

L
Linus Torvalds 已提交
36 37 38 39 40 41 42
/* Have we found an MP table */
int smp_found_config;

/*
 * Various Linux-internal data structures created from the
 * MP-table.
 */
43
DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES);
A
Alexey Starikovskiy 已提交
44
int mp_bus_id_to_pci_bus[MAX_MP_BUSSES] = {[0 ... MAX_MP_BUSSES - 1] = -1 };
L
Linus Torvalds 已提交
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65

static int mp_current_pci_id = 0;

/*
 * Intel MP BIOS table parsing routines:
 */

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

66 67
static void __cpuinit MP_processor_info(struct mpc_config_processor *m)
{
68
	int apicid;
69 70 71 72 73 74
	char *bootup_cpu = "";

	if (!(m->mpc_cpuflag & CPU_ENABLED)) {
		disabled_cpus++;
		return;
	}
75 76 77 78 79
#ifdef CONFIG_X86_NUMAQ
	apicid = mpc_apic_id(m, translation_table[mpc_record]);
#else
	apicid = m->mpc_apicid;
#endif
80 81 82 83 84 85
	if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
		bootup_cpu = " (Bootup-CPU)";
		boot_cpu_physical_apicid = m->mpc_apicid;
	}

	printk(KERN_INFO "Processor #%d%s\n", m->mpc_apicid, bootup_cpu);
86
	generic_processor_info(apicid, m->mpc_apicver);
87 88
}

A
Alexey Starikovskiy 已提交
89
static void __init MP_bus_info(struct mpc_config_bus *m)
L
Linus Torvalds 已提交
90 91 92 93 94 95 96 97
{
	char str[7];

	memcpy(str, m->mpc_bustype, 6);
	str[6] = 0;
	Dprintk("Bus #%d is %s\n", m->mpc_busid, str);

	if (strncmp(str, "ISA", 3) == 0) {
98
		set_bit(m->mpc_busid, mp_bus_not_pci);
L
Linus Torvalds 已提交
99
	} else if (strncmp(str, "PCI", 3) == 0) {
100
		clear_bit(m->mpc_busid, mp_bus_not_pci);
L
Linus Torvalds 已提交
101 102 103 104 105 106 107
		mp_bus_id_to_pci_bus[m->mpc_busid] = mp_current_pci_id;
		mp_current_pci_id++;
	} else {
		printk(KERN_ERR "Unknown bustype %s\n", str);
	}
}

108 109 110 111
static int bad_ioapic(unsigned long address)
{
	if (nr_ioapics >= MAX_IO_APICS) {
		printk(KERN_ERR "ERROR: Max # of I/O APICs (%d) exceeded "
A
Alexey Starikovskiy 已提交
112
		       "(found %d)\n", MAX_IO_APICS, nr_ioapics);
113 114 115 116
		panic("Recompile kernel with bigger MAX_IO_APICS!\n");
	}
	if (!address) {
		printk(KERN_ERR "WARNING: Bogus (zero) I/O APIC address"
A
Alexey Starikovskiy 已提交
117
		       " found in table, skipping!\n");
118 119 120 121 122
		return 1;
	}
	return 0;
}

A
Alexey Starikovskiy 已提交
123
static void __init MP_ioapic_info(struct mpc_config_ioapic *m)
L
Linus Torvalds 已提交
124 125 126 127
{
	if (!(m->mpc_flags & MPC_APIC_USABLE))
		return;

A
Alexey Starikovskiy 已提交
128 129
	printk(KERN_INFO "I/O APIC #%d at 0x%X.\n", m->mpc_apicid,
	       m->mpc_apicaddr);
130 131

	if (bad_ioapic(m->mpc_apicaddr))
L
Linus Torvalds 已提交
132
		return;
133

L
Linus Torvalds 已提交
134 135 136 137
	mp_ioapics[nr_ioapics] = *m;
	nr_ioapics++;
}

A
Alexey Starikovskiy 已提交
138
static void __init MP_intsrc_info(struct mpc_config_intsrc *m)
L
Linus Torvalds 已提交
139
{
A
Alexey Starikovskiy 已提交
140
	mp_irqs[mp_irq_entries] = *m;
L
Linus Torvalds 已提交
141 142
	Dprintk("Int: type %d, pol %d, trig %d, bus %d,"
		" IRQ %02x, APIC ID %x, APIC INT %02x\n",
A
Alexey Starikovskiy 已提交
143 144 145
		m->mpc_irqtype, m->mpc_irqflag & 3,
		(m->mpc_irqflag >> 2) & 3, m->mpc_srcbus,
		m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq);
146
	if (++mp_irq_entries >= MAX_IRQ_SOURCES)
L
Linus Torvalds 已提交
147 148 149
		panic("Max # of irq sources exceeded!!\n");
}

A
Alexey Starikovskiy 已提交
150
static void __init MP_lintsrc_info(struct mpc_config_lintsrc *m)
L
Linus Torvalds 已提交
151 152 153
{
	Dprintk("Lint: type %d, pol %d, trig %d, bus %d,"
		" IRQ %02x, APIC ID %x, APIC LINT %02x\n",
A
Alexey Starikovskiy 已提交
154 155 156
		m->mpc_irqtype, m->mpc_irqflag & 3,
		(m->mpc_irqflag >> 2) & 3, m->mpc_srcbusid,
		m->mpc_srcbusirq, m->mpc_destapic, m->mpc_destapiclint);
L
Linus Torvalds 已提交
157 158 159 160 161
}

/*
 * Read/parse the MPC
 */
162
static int __init smp_read_mpc(struct mp_config_table *mpc, unsigned early)
L
Linus Torvalds 已提交
163 164
{
	char str[16];
A
Alexey Starikovskiy 已提交
165 166 167 168 169 170 171 172
	int count = sizeof(*mpc);
	unsigned char *mpt = ((unsigned char *)mpc) + count;

	if (memcmp(mpc->mpc_signature, MPC_SIGNATURE, 4)) {
		printk(KERN_ERR "MPTABLE: bad signature [%c%c%c%c]!\n",
		       mpc->mpc_signature[0],
		       mpc->mpc_signature[1],
		       mpc->mpc_signature[2], mpc->mpc_signature[3]);
L
Linus Torvalds 已提交
173 174
		return 0;
	}
A
Alexey Starikovskiy 已提交
175 176
	if (mpf_checksum((unsigned char *)mpc, mpc->mpc_length)) {
		printk(KERN_ERR "MPTABLE: checksum error!\n");
L
Linus Torvalds 已提交
177 178
		return 0;
	}
A
Alexey Starikovskiy 已提交
179
	if (mpc->mpc_spec != 0x01 && mpc->mpc_spec != 0x04) {
180
		printk(KERN_ERR "MPTABLE: bad table version (%d)!!\n",
A
Alexey Starikovskiy 已提交
181
		       mpc->mpc_spec);
L
Linus Torvalds 已提交
182 183 184
		return 0;
	}
	if (!mpc->mpc_lapic) {
185
		printk(KERN_ERR "MPTABLE: null local APIC address!\n");
L
Linus Torvalds 已提交
186 187
		return 0;
	}
A
Alexey Starikovskiy 已提交
188
	memcpy(str, mpc->mpc_oem, 8);
189
	str[8] = 0;
A
Alexey Starikovskiy 已提交
190
	printk(KERN_INFO "MPTABLE: OEM ID: %s ", str);
L
Linus Torvalds 已提交
191

A
Alexey Starikovskiy 已提交
192
	memcpy(str, mpc->mpc_productid, 12);
193
	str[12] = 0;
A
Alexey Starikovskiy 已提交
194
	printk(KERN_INFO "MPTABLE: Product ID: %s ", str);
L
Linus Torvalds 已提交
195

A
Alexey Starikovskiy 已提交
196
	printk(KERN_INFO "MPTABLE: APIC at: 0x%X\n", mpc->mpc_lapic);
L
Linus Torvalds 已提交
197 198 199

	/* save the local APIC address, it might be non-default */
	if (!acpi_lapic)
200
		mp_lapic_addr = mpc->mpc_lapic;
L
Linus Torvalds 已提交
201

202 203 204
	if (early)
		return 1;

L
Linus Torvalds 已提交
205
	/*
A
Alexey Starikovskiy 已提交
206
	 *      Now process the configuration blocks.
L
Linus Torvalds 已提交
207 208
	 */
	while (count < mpc->mpc_length) {
A
Alexey Starikovskiy 已提交
209 210
		switch (*mpt) {
		case MP_PROCESSOR:
L
Linus Torvalds 已提交
211
			{
A
Alexey Starikovskiy 已提交
212 213
				struct mpc_config_processor *m =
				    (struct mpc_config_processor *)mpt;
L
Linus Torvalds 已提交
214
				if (!acpi_lapic)
215
					MP_processor_info(m);
L
Linus Torvalds 已提交
216 217 218 219
				mpt += sizeof(*m);
				count += sizeof(*m);
				break;
			}
A
Alexey Starikovskiy 已提交
220
		case MP_BUS:
L
Linus Torvalds 已提交
221
			{
A
Alexey Starikovskiy 已提交
222 223
				struct mpc_config_bus *m =
				    (struct mpc_config_bus *)mpt;
L
Linus Torvalds 已提交
224 225 226 227 228
				MP_bus_info(m);
				mpt += sizeof(*m);
				count += sizeof(*m);
				break;
			}
A
Alexey Starikovskiy 已提交
229
		case MP_IOAPIC:
L
Linus Torvalds 已提交
230
			{
A
Alexey Starikovskiy 已提交
231 232
				struct mpc_config_ioapic *m =
				    (struct mpc_config_ioapic *)mpt;
L
Linus Torvalds 已提交
233
				MP_ioapic_info(m);
234 235
				mpt += sizeof(*m);
				count += sizeof(*m);
L
Linus Torvalds 已提交
236 237
				break;
			}
A
Alexey Starikovskiy 已提交
238
		case MP_INTSRC:
L
Linus Torvalds 已提交
239
			{
A
Alexey Starikovskiy 已提交
240 241
				struct mpc_config_intsrc *m =
				    (struct mpc_config_intsrc *)mpt;
L
Linus Torvalds 已提交
242 243

				MP_intsrc_info(m);
244 245
				mpt += sizeof(*m);
				count += sizeof(*m);
L
Linus Torvalds 已提交
246 247
				break;
			}
A
Alexey Starikovskiy 已提交
248
		case MP_LINTSRC:
L
Linus Torvalds 已提交
249
			{
A
Alexey Starikovskiy 已提交
250 251
				struct mpc_config_lintsrc *m =
				    (struct mpc_config_lintsrc *)mpt;
L
Linus Torvalds 已提交
252
				MP_lintsrc_info(m);
253 254
				mpt += sizeof(*m);
				count += sizeof(*m);
L
Linus Torvalds 已提交
255 256 257 258
				break;
			}
		}
	}
259
	setup_apic_routing();
L
Linus Torvalds 已提交
260
	if (!num_processors)
261
		printk(KERN_ERR "MPTABLE: no processors registered!\n");
L
Linus Torvalds 已提交
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
	return num_processors;
}

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)
{
	struct mpc_config_intsrc intsrc;
	int i;
	int ELCR_fallback = 0;

	intsrc.mpc_type = MP_INTSRC;
A
Alexey Starikovskiy 已提交
280
	intsrc.mpc_irqflag = 0;	/* conforming */
L
Linus Torvalds 已提交
281 282 283 284 285 286 287 288 289 290 291 292 293 294
	intsrc.mpc_srcbus = 0;
	intsrc.mpc_dstapic = mp_ioapics[0].mpc_apicid;

	intsrc.mpc_irqtype = mp_INT;

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

A
Alexey Starikovskiy 已提交
298 299 300 301
		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 已提交
302
		else {
A
Alexey Starikovskiy 已提交
303 304
			printk(KERN_INFO
			       "Using ELCR to identify PCI interrupts\n");
L
Linus Torvalds 已提交
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
			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))
				intsrc.mpc_irqflag = 13;
			else
				intsrc.mpc_irqflag = 0;
		}

		intsrc.mpc_srcbusirq = i;
A
Alexey Starikovskiy 已提交
333
		intsrc.mpc_dstirq = i ? i : 2;	/* IRQ0 to INTIN2 */
L
Linus Torvalds 已提交
334 335 336 337 338
		MP_intsrc_info(&intsrc);
	}

	intsrc.mpc_irqtype = mp_ExtINT;
	intsrc.mpc_srcbusirq = 0;
A
Alexey Starikovskiy 已提交
339
	intsrc.mpc_dstirq = 0;	/* 8259A to INTIN0 */
L
Linus Torvalds 已提交
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
	MP_intsrc_info(&intsrc);
}

static inline void __init construct_default_ISA_mptable(int mpc_default_type)
{
	struct mpc_config_processor processor;
	struct mpc_config_bus bus;
	struct mpc_config_ioapic ioapic;
	struct mpc_config_lintsrc lintsrc;
	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.
	 */
	processor.mpc_type = MP_PROCESSOR;
361
	processor.mpc_apicver = 0;
L
Linus Torvalds 已提交
362
	processor.mpc_cpuflag = CPU_ENABLED;
363 364
	processor.mpc_cpufeature = 0;
	processor.mpc_featureflag = 0;
L
Linus Torvalds 已提交
365 366 367 368 369 370 371 372 373 374
	processor.mpc_reserved[0] = 0;
	processor.mpc_reserved[1] = 0;
	for (i = 0; i < 2; i++) {
		processor.mpc_apicid = i;
		MP_processor_info(&processor);
	}

	bus.mpc_type = MP_BUS;
	bus.mpc_busid = 0;
	switch (mpc_default_type) {
A
Alexey Starikovskiy 已提交
375 376 377 378 379 380 381 382
	default:
		printk(KERN_ERR "???\nUnknown standard configuration %d\n",
		       mpc_default_type);
		/* fall through */
	case 1:
	case 5:
		memcpy(bus.mpc_bustype, "ISA   ", 6);
		break;
L
Linus Torvalds 已提交
383 384 385 386 387 388 389 390 391 392
	}
	MP_bus_info(&bus);
	if (mpc_default_type > 4) {
		bus.mpc_busid = 1;
		memcpy(bus.mpc_bustype, "PCI   ", 6);
		MP_bus_info(&bus);
	}

	ioapic.mpc_type = MP_IOAPIC;
	ioapic.mpc_apicid = 2;
393
	ioapic.mpc_apicver = 0;
L
Linus Torvalds 已提交
394 395 396 397 398 399 400 401 402 403
	ioapic.mpc_flags = MPC_APIC_USABLE;
	ioapic.mpc_apicaddr = 0xFEC00000;
	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);

	lintsrc.mpc_type = MP_LINTSRC;
A
Alexey Starikovskiy 已提交
404
	lintsrc.mpc_irqflag = 0;	/* conforming */
L
Linus Torvalds 已提交
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
	lintsrc.mpc_srcbusid = 0;
	lintsrc.mpc_srcbusirq = 0;
	lintsrc.mpc_destapic = MP_APIC_ALL;
	for (i = 0; i < 2; i++) {
		lintsrc.mpc_irqtype = linttypes[i];
		lintsrc.mpc_destapiclint = i;
		MP_lintsrc_info(&lintsrc);
	}
}

static struct intel_mp_floating *mpf_found;

/*
 * Scan the memory blocks for an SMP configuration block.
 */
420
static void __init __get_smp_config(unsigned early)
L
Linus Torvalds 已提交
421 422 423
{
	struct intel_mp_floating *mpf = mpf_found;

424 425
	if (acpi_lapic && early)
		return;
L
Linus Torvalds 已提交
426
	/*
427 428 429 430 431
	 * ACPI supports both logical (e.g. Hyper-Threading) and physical
	 * processors, where MPS only supports physical.
	 */
	if (acpi_lapic && acpi_ioapic) {
		printk(KERN_INFO "Using ACPI (MADT) for SMP configuration "
A
Alexey Starikovskiy 已提交
432
		       "information\n");
433 434 435
		return;
	} else if (acpi_lapic)
		printk(KERN_INFO "Using ACPI for processor (LAPIC) "
A
Alexey Starikovskiy 已提交
436
		       "configuration information\n");
L
Linus Torvalds 已提交
437

438
	printk(KERN_INFO "Intel MultiProcessor Specification v1.%d\n",
A
Alexey Starikovskiy 已提交
439
	       mpf->mpf_specification);
L
Linus Torvalds 已提交
440 441 442 443 444

	/*
	 * Now see if we need to read further.
	 */
	if (mpf->mpf_feature1 != 0) {
445 446 447 448 449 450 451
		if (early) {
			/*
			 * local APIC has default address
			 */
			mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
			return;
		}
L
Linus Torvalds 已提交
452

A
Alexey Starikovskiy 已提交
453 454
		printk(KERN_INFO "Default MP configuration #%d\n",
		       mpf->mpf_feature1);
L
Linus Torvalds 已提交
455 456 457 458 459 460 461 462
		construct_default_ISA_mptable(mpf->mpf_feature1);

	} else if (mpf->mpf_physptr) {

		/*
		 * Read the physical hardware table.  Anything here will
		 * override the defaults.
		 */
463
		if (!smp_read_mpc(phys_to_virt(mpf->mpf_physptr), early)) {
L
Linus Torvalds 已提交
464
			smp_found_config = 0;
A
Alexey Starikovskiy 已提交
465 466 467 468
			printk(KERN_ERR
			       "BIOS bug, MP table errors detected!...\n");
			printk(KERN_ERR "... disabling SMP support. "
			       "(tell your hw vendor)\n");
L
Linus Torvalds 已提交
469 470
			return;
		}
471 472 473

		if (early)
			return;
L
Linus Torvalds 已提交
474 475 476 477 478 479 480 481
		/*
		 * 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_config_bus bus;

A
Alexey Starikovskiy 已提交
482 483 484
			printk(KERN_ERR "BIOS bug, no explicit IRQ entries, "
			       "using default mptable. "
			       "(tell your hw vendor)\n");
L
Linus Torvalds 已提交
485 486 487 488 489 490 491 492 493 494 495 496

			bus.mpc_type = MP_BUS;
			bus.mpc_busid = 0;
			memcpy(bus.mpc_bustype, "ISA   ", 6);
			MP_bus_info(&bus);

			construct_default_ioirq_mptable(0);
		}

	} else
		BUG();

497 498
	if (!early)
		printk(KERN_INFO "Processors: %d\n", num_processors);
L
Linus Torvalds 已提交
499 500 501 502 503
	/*
	 * Only use the first configuration found.
	 */
}

504 505 506 507 508 509 510 511 512 513 514 515
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 已提交
516
{
A
Alexey Starikovskiy 已提交
517
	extern void __bad_mpf_size(void);
L
Linus Torvalds 已提交
518 519 520
	unsigned int *bp = phys_to_virt(base);
	struct intel_mp_floating *mpf;

A
Alexey Starikovskiy 已提交
521
	Dprintk("Scan SMP from %p for %ld bytes.\n", bp, length);
L
Linus Torvalds 已提交
522 523 524 525 526 527
	if (sizeof(*mpf) != 16)
		__bad_mpf_size();

	while (length > 0) {
		mpf = (struct intel_mp_floating *)bp;
		if ((*bp == SMP_MAGIC_IDENT) &&
A
Alexey Starikovskiy 已提交
528 529 530 531
		    (mpf->mpf_length == 1) &&
		    !mpf_checksum((unsigned char *)bp, 16) &&
		    ((mpf->mpf_specification == 1)
		     || (mpf->mpf_specification == 4))) {
L
Linus Torvalds 已提交
532 533

			smp_found_config = 1;
534 535 536 537 538
			mpf_found = mpf;

			if (!reserve)
				return 1;

L
Linus Torvalds 已提交
539 540
			reserve_bootmem_generic(virt_to_phys(mpf), PAGE_SIZE);
			if (mpf->mpf_physptr)
541 542
				reserve_bootmem_generic(mpf->mpf_physptr,
							PAGE_SIZE);
L
Linus Torvalds 已提交
543 544 545 546 547 548 549 550
			return 1;
		}
		bp += 4;
		length -= 16;
	}
	return 0;
}

551
static void __init __find_smp_config(unsigned reserve)
L
Linus Torvalds 已提交
552 553 554 555 556 557 558 559 560 561 562
{
	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
	 */
563
	if (smp_scan_config(0x0, 0x400, reserve) ||
A
Alexey Starikovskiy 已提交
564 565
	    smp_scan_config(639 * 0x400, 0x400, reserve) ||
	    smp_scan_config(0xF0000, 0x10000, reserve))
L
Linus Torvalds 已提交
566 567
		return;
	/*
568
	 * If it is an SMP machine we should know now.
L
Linus Torvalds 已提交
569 570 571 572 573 574 575 576 577
	 *
	 * 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.
578 579
	 *
	 * MP1.4 SPEC states to only scan first 1K of 4K EBDA.
L
Linus Torvalds 已提交
580 581
	 */

582 583
	address = get_bios_ebda();
	if (address)
584
		smp_scan_config(address, 0x400, reserve);
L
Linus Torvalds 已提交
585 586
}

587 588 589 590 591 592 593 594 595 596
void __init early_find_smp_config(void)
{
	__find_smp_config(0);
}

void __init find_smp_config(void)
{
	__find_smp_config(1);
}

L
Linus Torvalds 已提交
597 598 599 600
/* --------------------------------------------------------------------------
                            ACPI-based MP Configuration
   -------------------------------------------------------------------------- */

L
Len Brown 已提交
601
#ifdef CONFIG_ACPI
L
Linus Torvalds 已提交
602 603 604 605

#define MP_ISA_BUS		0
#define MP_MAX_IOAPIC_PIN	127

606
extern struct mp_ioapic_routing mp_ioapic_routing[MAX_IO_APICS];
L
Linus Torvalds 已提交
607

608
static int mp_find_ioapic(int gsi)
L
Linus Torvalds 已提交
609
{
610
	int i = 0;
L
Linus Torvalds 已提交
611 612 613

	/* Find the IOAPIC that manages this GSI. */
	for (i = 0; i < nr_ioapics; i++) {
614
		if ((gsi >= mp_ioapic_routing[i].gsi_base)
A
Alexey Starikovskiy 已提交
615
		    && (gsi <= mp_ioapic_routing[i].gsi_end))
L
Linus Torvalds 已提交
616 617 618 619 620 621 622
			return i;
	}

	printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi);
	return -1;
}

623 624 625 626 627 628 629 630 631 632 633 634 635 636
static u8 uniq_ioapic_id(u8 id)
{
	int i;
	DECLARE_BITMAP(used, 256);
	bitmap_zero(used, 256);
	for (i = 0; i < nr_ioapics; i++) {
		struct mpc_config_ioapic *ia = &mp_ioapics[i];
		__set_bit(ia->mpc_apicid, used);
	}
	if (!test_bit(id, used))
		return id;
	return find_first_zero_bit(used, 256);
}

J
Jack Steiner 已提交
637
void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)
L
Linus Torvalds 已提交
638
{
639
	int idx = 0;
L
Linus Torvalds 已提交
640

641
	if (bad_ioapic(address))
L
Linus Torvalds 已提交
642 643
		return;

644
	idx = nr_ioapics;
L
Linus Torvalds 已提交
645 646 647 648 649 650

	mp_ioapics[idx].mpc_type = MP_IOAPIC;
	mp_ioapics[idx].mpc_flags = MPC_APIC_USABLE;
	mp_ioapics[idx].mpc_apicaddr = address;

	set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
651
	mp_ioapics[idx].mpc_apicid = uniq_ioapic_id(id);
652
	mp_ioapics[idx].mpc_apicver = 0;
A
Alexey Starikovskiy 已提交
653

L
Linus Torvalds 已提交
654 655 656 657 658
	/* 
	 * Build basic IRQ lookup table to facilitate gsi->io_apic lookups
	 * and to prevent reprogramming of IOAPIC pins (PCI IRQs).
	 */
	mp_ioapic_routing[idx].apic_id = mp_ioapics[idx].mpc_apicid;
659
	mp_ioapic_routing[idx].gsi_base = gsi_base;
A
Alexey Starikovskiy 已提交
660 661
	mp_ioapic_routing[idx].gsi_end = gsi_base +
	    io_apic_get_redir_entries(idx);
L
Linus Torvalds 已提交
662

663
	printk(KERN_INFO "IOAPIC[%d]: apic_id %d, address 0x%x, "
A
Alexey Starikovskiy 已提交
664 665
	       "GSI %d-%d\n", idx, mp_ioapics[idx].mpc_apicid,
	       mp_ioapics[idx].mpc_apicaddr,
666
	       mp_ioapic_routing[idx].gsi_base,
A
Alexey Starikovskiy 已提交
667
	       mp_ioapic_routing[idx].gsi_end);
668 669

	nr_ioapics++;
L
Linus Torvalds 已提交
670 671
}

A
Alexey Starikovskiy 已提交
672
void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi)
L
Linus Torvalds 已提交
673 674
{
	struct mpc_config_intsrc intsrc;
A
Alexey Starikovskiy 已提交
675 676
	int ioapic = -1;
	int pin = -1;
L
Linus Torvalds 已提交
677 678 679 680 681 682 683

	/* 
	 * Convert 'gsi' to 'ioapic.pin'.
	 */
	ioapic = mp_find_ioapic(gsi);
	if (ioapic < 0)
		return;
684
	pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
L
Linus Torvalds 已提交
685 686 687 688 689 690 691 692 693 694 695 696 697

	/*
	 * TBD: This check is for faulty timer entries, where the override
	 *      erroneously sets the trigger to level, resulting in a HUGE 
	 *      increase of timer interrupts!
	 */
	if ((bus_irq == 0) && (trigger == 3))
		trigger = 1;

	intsrc.mpc_type = MP_INTSRC;
	intsrc.mpc_irqtype = mp_INT;
	intsrc.mpc_irqflag = (trigger << 2) | polarity;
	intsrc.mpc_srcbus = MP_ISA_BUS;
A
Alexey Starikovskiy 已提交
698 699 700
	intsrc.mpc_srcbusirq = bus_irq;	/* IRQ */
	intsrc.mpc_dstapic = mp_ioapics[ioapic].mpc_apicid;	/* APIC ID */
	intsrc.mpc_dstirq = pin;	/* INTIN# */
L
Linus Torvalds 已提交
701

A
Alexey Starikovskiy 已提交
702 703 704
	Dprintk("Int: type %d, pol %d, trig %d, bus %d, irq %d, %d-%d\n",
		intsrc.mpc_irqtype, intsrc.mpc_irqflag & 3,
		(intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus,
L
Linus Torvalds 已提交
705 706 707 708 709 710 711
		intsrc.mpc_srcbusirq, intsrc.mpc_dstapic, intsrc.mpc_dstirq);

	mp_irqs[mp_irq_entries] = intsrc;
	if (++mp_irq_entries == MAX_IRQ_SOURCES)
		panic("Max # of irq sources exceeded!\n");
}

712
void __init mp_config_acpi_legacy_irqs(void)
L
Linus Torvalds 已提交
713 714
{
	struct mpc_config_intsrc intsrc;
715 716
	int i = 0;
	int ioapic = -1;
L
Linus Torvalds 已提交
717 718 719 720

	/* 
	 * Fabricate the legacy ISA bus (bus #31).
	 */
721
	set_bit(MP_ISA_BUS, mp_bus_not_pci);
L
Linus Torvalds 已提交
722 723 724 725 726 727 728 729 730

	/* 
	 * Locate the IOAPIC that manages the ISA IRQs (0-15). 
	 */
	ioapic = mp_find_ioapic(0);
	if (ioapic < 0)
		return;

	intsrc.mpc_type = MP_INTSRC;
A
Alexey Starikovskiy 已提交
731
	intsrc.mpc_irqflag = 0;	/* Conforming */
L
Linus Torvalds 已提交
732 733 734 735 736 737 738 739 740 741 742 743 744 745
	intsrc.mpc_srcbus = MP_ISA_BUS;
	intsrc.mpc_dstapic = mp_ioapics[ioapic].mpc_apicid;

	/* 
	 * Use the default configuration for the IRQs 0-15.  Unless
	 * overridden by (MADT) interrupt source override entries.
	 */
	for (i = 0; i < 16; i++) {
		int idx;

		for (idx = 0; idx < mp_irq_entries; idx++) {
			struct mpc_config_intsrc *irq = mp_irqs + idx;

			/* Do we already have a mapping for this ISA IRQ? */
A
Alexey Starikovskiy 已提交
746 747
			if (irq->mpc_srcbus == MP_ISA_BUS
			    && irq->mpc_srcbusirq == i)
L
Linus Torvalds 已提交
748 749 750 751
				break;

			/* Do we already have a mapping for this IOAPIC pin */
			if ((irq->mpc_dstapic == intsrc.mpc_dstapic) &&
A
Alexey Starikovskiy 已提交
752
			    (irq->mpc_dstirq == i))
L
Linus Torvalds 已提交
753 754 755 756 757
				break;
		}

		if (idx != mp_irq_entries) {
			printk(KERN_DEBUG "ACPI: IRQ%d used by override.\n", i);
A
Alexey Starikovskiy 已提交
758
			continue;	/* IRQ already used */
L
Linus Torvalds 已提交
759 760 761
		}

		intsrc.mpc_irqtype = mp_INT;
A
Alexey Starikovskiy 已提交
762
		intsrc.mpc_srcbusirq = i;	/* Identity mapped */
L
Linus Torvalds 已提交
763 764 765
		intsrc.mpc_dstirq = i;

		Dprintk("Int: type %d, pol %d, trig %d, bus %d, irq %d, "
A
Alexey Starikovskiy 已提交
766 767 768
			"%d-%d\n", intsrc.mpc_irqtype, intsrc.mpc_irqflag & 3,
			(intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus,
			intsrc.mpc_srcbusirq, intsrc.mpc_dstapic,
L
Linus Torvalds 已提交
769 770 771 772 773 774 775 776
			intsrc.mpc_dstirq);

		mp_irqs[mp_irq_entries] = intsrc;
		if (++mp_irq_entries == MAX_IRQ_SOURCES)
			panic("Max # of irq sources exceeded!\n");
	}
}

B
Bob Moore 已提交
777
int mp_register_gsi(u32 gsi, int triggering, int polarity)
L
Linus Torvalds 已提交
778
{
779 780 781
	int ioapic = -1;
	int ioapic_pin = 0;
	int idx, bit = 0;
L
Linus Torvalds 已提交
782 783 784 785 786

	if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
		return gsi;

	/* Don't set up the ACPI SCI because it's already set up */
787
	if (acpi_gbl_FADT.sci_interrupt == gsi)
L
Linus Torvalds 已提交
788 789 790 791 792 793 794 795
		return gsi;

	ioapic = mp_find_ioapic(gsi);
	if (ioapic < 0) {
		printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi);
		return gsi;
	}

796
	ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
L
Linus Torvalds 已提交
797 798 799 800 801 802 803 804 805 806

	/* 
	 * Avoid pin reprogramming.  PRTs typically include entries  
	 * with redundant pin->gsi mappings (but unique PCI devices);
	 * we only program the IOAPIC on the first.
	 */
	bit = ioapic_pin % 32;
	idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32);
	if (idx > 3) {
		printk(KERN_ERR "Invalid reference to IOAPIC pin "
A
Alexey Starikovskiy 已提交
807 808
		       "%d-%d\n", mp_ioapic_routing[ioapic].apic_id,
		       ioapic_pin);
L
Linus Torvalds 已提交
809 810
		return gsi;
	}
A
Alexey Starikovskiy 已提交
811
	if ((1 << bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
L
Linus Torvalds 已提交
812 813
		Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
			mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
814
		return gsi;
L
Linus Torvalds 已提交
815 816
	}

A
Alexey Starikovskiy 已提交
817
	mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1 << bit);
L
Linus Torvalds 已提交
818 819

	io_apic_set_pci_routing(ioapic, ioapic_pin, gsi,
A
Alexey Starikovskiy 已提交
820 821
				triggering == ACPI_EDGE_SENSITIVE ? 0 : 1,
				polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
L
Linus Torvalds 已提交
822 823
	return gsi;
}
A
Alexey Starikovskiy 已提交
824
#endif /* CONFIG_ACPI */