mpparse_32.c 27.1 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/*
 *	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/acpi.h>
#include <linux/delay.h>
#include <linux/bootmem.h>
#include <linux/kernel_stat.h>
#include <linux/mc146818rtc.h>
#include <linux/bitops.h>

#include <asm/smp.h>
#include <asm/acpi.h>
#include <asm/mtrr.h>
#include <asm/mpspec.h>
#include <asm/io_apic.h>
30
#include <asm/bios_ebda.h>
Linus Torvalds's avatar
Linus Torvalds committed
31 32

#include <mach_apic.h>
33
#include <mach_apicdef.h>
Linus Torvalds's avatar
Linus Torvalds committed
34 35 36 37 38 39 40 41 42
#include <mach_mpparse.h>

/* Have we found an MP table */
int smp_found_config;

/*
 * Various Linux-internal data structures created from the
 * MP-table.
 */
43
#if defined (CONFIG_MCA) || defined (CONFIG_EISA)
44
int mp_bus_id_to_type[MAX_MP_BUSSES];
45
#endif
46
DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES);
47
int mp_bus_id_to_pci_bus[MAX_MP_BUSSES] = {[0 ... MAX_MP_BUSSES - 1] = -1 };
Linus Torvalds's avatar
Linus Torvalds committed
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
static int mp_current_pci_id;

int pic_mode;

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

70
#ifdef CONFIG_X86_NUMAQ
Linus Torvalds's avatar
Linus Torvalds committed
71 72 73 74 75 76
/*
 * Have to match translation table entries to main table entries by counter
 * hence the mpc_record variable .... can't see a less disgusting way of
 * doing this ....
 */

77 78 79
static int mpc_record;
static struct mpc_config_translation *translation_table[MAX_MPC_ENTRY]
    __cpuinitdata;
80
#endif
Linus Torvalds's avatar
Linus Torvalds committed
81

82 83 84
static void __cpuinit MP_processor_info(struct mpc_config_processor *m)
{
	int apicid;
85
	char *bootup_cpu = "";
86

87 88
	if (!(m->mpc_cpuflag & CPU_ENABLED)) {
		disabled_cpus++;
Linus Torvalds's avatar
Linus Torvalds committed
89
		return;
90
	}
91
#ifdef CONFIG_X86_NUMAQ
Linus Torvalds's avatar
Linus Torvalds committed
92
	apicid = mpc_apic_id(m, translation_table[mpc_record]);
93 94 95
#else
	apicid = m->mpc_apicid;
#endif
Linus Torvalds's avatar
Linus Torvalds committed
96
	if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
97
		bootup_cpu = " (Bootup-CPU)";
Linus Torvalds's avatar
Linus Torvalds committed
98 99 100
		boot_cpu_physical_apicid = m->mpc_apicid;
	}

101
	printk(KERN_INFO "Processor #%d%s\n", m->mpc_apicid, bootup_cpu);
102
	generic_processor_info(apicid, m->mpc_apicver);
Linus Torvalds's avatar
Linus Torvalds committed
103 104
}

105
static void __init MP_bus_info(struct mpc_config_bus *m)
Linus Torvalds's avatar
Linus Torvalds committed
106 107 108 109 110 111
{
	char str[7];

	memcpy(str, m->mpc_bustype, 6);
	str[6] = 0;

112
#ifdef CONFIG_X86_NUMAQ
Linus Torvalds's avatar
Linus Torvalds committed
113
	mpc_oem_bus_info(m, str, translation_table[mpc_record]);
114 115 116
#else
	Dprintk("Bus #%d is %s\n", m->mpc_busid, str);
#endif
Linus Torvalds's avatar
Linus Torvalds committed
117

118
#if MAX_MP_BUSSES < 256
119 120
	if (m->mpc_busid >= MAX_MP_BUSSES) {
		printk(KERN_WARNING "MP table busid value (%d) for bustype %s "
121 122
		       " is too large, max. supported is %d\n",
		       m->mpc_busid, str, MAX_MP_BUSSES - 1);
123 124
		return;
	}
125
#endif
126

Alexey Starikovskiy's avatar
Alexey Starikovskiy committed
127 128 129 130 131 132
	if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA) - 1) == 0) {
		 set_bit(m->mpc_busid, mp_bus_not_pci);
#if defined(CONFIG_EISA) || defined (CONFIG_MCA)
		mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA;
#endif
	} else if (strncmp(str, BUSTYPE_PCI, sizeof(BUSTYPE_PCI) - 1) == 0) {
133
#ifdef CONFIG_X86_NUMAQ
Linus Torvalds's avatar
Linus Torvalds committed
134
		mpc_oem_pci_bus(m, translation_table[mpc_record]);
135
#endif
136
		clear_bit(m->mpc_busid, mp_bus_not_pci);
Linus Torvalds's avatar
Linus Torvalds committed
137 138
		mp_bus_id_to_pci_bus[m->mpc_busid] = mp_current_pci_id;
		mp_current_pci_id++;
139 140
#if defined(CONFIG_EISA) || defined (CONFIG_MCA)
		mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI;
141
	} else if (strncmp(str, BUSTYPE_EISA, sizeof(BUSTYPE_EISA) - 1) == 0) {
142
		mp_bus_id_to_type[m->mpc_busid] = MP_BUS_EISA;
143
	} else if (strncmp(str, BUSTYPE_MCA, sizeof(BUSTYPE_MCA) - 1) == 0) {
Linus Torvalds's avatar
Linus Torvalds committed
144
		mp_bus_id_to_type[m->mpc_busid] = MP_BUS_MCA;
145
#endif
Alexey Starikovskiy's avatar
Alexey Starikovskiy committed
146 147
	} else
		printk(KERN_WARNING "Unknown bustype %s - ignoring\n", str);
Linus Torvalds's avatar
Linus Torvalds committed
148 149
}

150 151
#ifdef CONFIG_X86_IO_APIC

152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
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;
}

167
static void __init MP_ioapic_info(struct mpc_config_ioapic *m)
Linus Torvalds's avatar
Linus Torvalds committed
168 169 170 171
{
	if (!(m->mpc_flags & MPC_APIC_USABLE))
		return;

172
	printk(KERN_INFO "I/O APIC #%d Version %d at 0x%X.\n",
173
	       m->mpc_apicid, m->mpc_apicver, m->mpc_apicaddr);
174 175

	if (bad_ioapic(m->mpc_apicaddr))
Linus Torvalds's avatar
Linus Torvalds committed
176
		return;
177

Linus Torvalds's avatar
Linus Torvalds committed
178 179 180 181
	mp_ioapics[nr_ioapics] = *m;
	nr_ioapics++;
}

182
static void __init MP_intsrc_info(struct mpc_config_intsrc *m)
Linus Torvalds's avatar
Linus Torvalds committed
183
{
184
	mp_irqs[mp_irq_entries] = *m;
Linus Torvalds's avatar
Linus Torvalds committed
185 186
	Dprintk("Int: type %d, pol %d, trig %d, bus %d,"
		" IRQ %02x, APIC ID %x, APIC INT %02x\n",
187 188 189
		m->mpc_irqtype, m->mpc_irqflag & 3,
		(m->mpc_irqflag >> 2) & 3, m->mpc_srcbus,
		m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq);
Linus Torvalds's avatar
Linus Torvalds committed
190 191 192 193
	if (++mp_irq_entries == MAX_IRQ_SOURCES)
		panic("Max # of irq sources exceeded!!\n");
}

194 195
#endif

196
static void __init MP_lintsrc_info(struct mpc_config_lintsrc *m)
Linus Torvalds's avatar
Linus Torvalds committed
197 198 199
{
	Dprintk("Lint: type %d, pol %d, trig %d, bus %d,"
		" IRQ %02x, APIC ID %x, APIC LINT %02x\n",
200 201 202
		m->mpc_irqtype, m->mpc_irqflag & 3,
		(m->mpc_irqflag >> 2) & 3, m->mpc_srcbusid,
		m->mpc_srcbusirq, m->mpc_destapic, m->mpc_destapiclint);
Linus Torvalds's avatar
Linus Torvalds committed
203 204 205
}

#ifdef CONFIG_X86_NUMAQ
206
static void __init MP_translation_info(struct mpc_config_translation *m)
Linus Torvalds's avatar
Linus Torvalds committed
207
{
208 209 210 211
	printk(KERN_INFO
	       "Translation: record %d, type %d, quad %d, global %d, local %d\n",
	       mpc_record, m->trans_type, m->trans_quad, m->trans_global,
	       m->trans_local);
Linus Torvalds's avatar
Linus Torvalds committed
212

213
	if (mpc_record >= MAX_MPC_ENTRY)
Linus Torvalds's avatar
Linus Torvalds committed
214 215
		printk(KERN_ERR "MAX_MPC_ENTRY exceeded!\n");
	else
216
		translation_table[mpc_record] = m;	/* stash this for later */
Linus Torvalds's avatar
Linus Torvalds committed
217 218 219 220 221 222 223 224
	if (m->trans_quad < MAX_NUMNODES && !node_online(m->trans_quad))
		node_set_online(m->trans_quad);
}

/*
 * Read/parse the MPC oem tables
 */

225 226
static void __init smp_read_mpc_oem(struct mp_config_oemtable *oemtable,
				    unsigned short oemsize)
Linus Torvalds's avatar
Linus Torvalds committed
227
{
228 229 230
	int count = sizeof(*oemtable);	/* the header size */
	unsigned char *oemptr = ((unsigned char *)oemtable) + count;

Linus Torvalds's avatar
Linus Torvalds committed
231
	mpc_record = 0;
232 233 234 235 236 237 238
	printk(KERN_INFO "Found an OEM MPC table at %8p - parsing it ... \n",
	       oemtable);
	if (memcmp(oemtable->oem_signature, MPC_OEM_SIGNATURE, 4)) {
		printk(KERN_WARNING
		       "SMP mpc oemtable: bad signature [%c%c%c%c]!\n",
		       oemtable->oem_signature[0], oemtable->oem_signature[1],
		       oemtable->oem_signature[2], oemtable->oem_signature[3]);
Linus Torvalds's avatar
Linus Torvalds committed
239 240
		return;
	}
241
	if (mpf_checksum((unsigned char *)oemtable, oemtable->oem_length)) {
Linus Torvalds's avatar
Linus Torvalds committed
242 243 244 245 246
		printk(KERN_WARNING "SMP oem mptable: checksum error!\n");
		return;
	}
	while (count < oemtable->oem_length) {
		switch (*oemptr) {
247
		case MP_TRANSLATION:
Linus Torvalds's avatar
Linus Torvalds committed
248
			{
249 250
				struct mpc_config_translation *m =
				    (struct mpc_config_translation *)oemptr;
Linus Torvalds's avatar
Linus Torvalds committed
251 252 253 254 255 256
				MP_translation_info(m);
				oemptr += sizeof(*m);
				count += sizeof(*m);
				++mpc_record;
				break;
			}
257
		default:
Linus Torvalds's avatar
Linus Torvalds committed
258
			{
259 260 261
				printk(KERN_WARNING
				       "Unrecognised OEM table entry type! - %d\n",
				       (int)*oemptr);
Linus Torvalds's avatar
Linus Torvalds committed
262 263 264
				return;
			}
		}
265
	}
Linus Torvalds's avatar
Linus Torvalds committed
266 267 268
}

static inline void mps_oem_check(struct mp_config_table *mpc, char *oem,
269
				 char *productid)
Linus Torvalds's avatar
Linus Torvalds committed
270 271 272 273
{
	if (strncmp(oem, "IBM NUMA", 8))
		printk("Warning!  May not be a NUMA-Q system!\n");
	if (mpc->mpc_oemptr)
274 275
		smp_read_mpc_oem((struct mp_config_oemtable *)mpc->mpc_oemptr,
				 mpc->mpc_oemsize);
Linus Torvalds's avatar
Linus Torvalds committed
276
}
277
#endif /* CONFIG_X86_NUMAQ */
Linus Torvalds's avatar
Linus Torvalds committed
278 279 280 281 282

/*
 * Read/parse the MPC
 */

283
static int __init smp_read_mpc(struct mp_config_table *mpc, unsigned early)
Linus Torvalds's avatar
Linus Torvalds committed
284 285 286
{
	char str[16];
	char oem[10];
287 288
	int count = sizeof(*mpc);
	unsigned char *mpt = ((unsigned char *)mpc) + count;
Linus Torvalds's avatar
Linus Torvalds committed
289

290
	if (memcmp(mpc->mpc_signature, MPC_SIGNATURE, 4)) {
291 292 293
		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]);
Linus Torvalds's avatar
Linus Torvalds committed
294 295
		return 0;
	}
296
	if (mpf_checksum((unsigned char *)mpc, mpc->mpc_length)) {
297
		printk(KERN_ERR "MPTABLE: checksum error!\n");
Linus Torvalds's avatar
Linus Torvalds committed
298 299
		return 0;
	}
300
	if (mpc->mpc_spec != 0x01 && mpc->mpc_spec != 0x04) {
301
		printk(KERN_ERR "MPTABLE: bad table version (%d)!!\n",
302
		       mpc->mpc_spec);
Linus Torvalds's avatar
Linus Torvalds committed
303 304 305
		return 0;
	}
	if (!mpc->mpc_lapic) {
306
		printk(KERN_ERR "MPTABLE: null local APIC address!\n");
Linus Torvalds's avatar
Linus Torvalds committed
307 308
		return 0;
	}
309 310
	memcpy(oem, mpc->mpc_oem, 8);
	oem[8] = 0;
311
	printk(KERN_INFO "MPTABLE: OEM ID: %s ", oem);
Linus Torvalds's avatar
Linus Torvalds committed
312

313 314 315
	memcpy(str, mpc->mpc_productid, 12);
	str[12] = 0;
	printk("Product ID: %s ", str);
Linus Torvalds's avatar
Linus Torvalds committed
316

317
#ifdef CONFIG_X86_32
Linus Torvalds's avatar
Linus Torvalds committed
318
	mps_oem_check(mpc, oem, str);
319 320
#endif
	printk(KERN_INFO "MPTABLE: Product ID: %s ", str);
Linus Torvalds's avatar
Linus Torvalds committed
321

322
	printk(KERN_INFO "MPTABLE: APIC at: 0x%X\n", mpc->mpc_lapic);
Linus Torvalds's avatar
Linus Torvalds committed
323

324
	/* save the local APIC address, it might be non-default */
Linus Torvalds's avatar
Linus Torvalds committed
325 326 327
	if (!acpi_lapic)
		mp_lapic_addr = mpc->mpc_lapic;

328 329 330
	if (early)
		return 1;

Linus Torvalds's avatar
Linus Torvalds committed
331
	/*
332
	 *      Now process the configuration blocks.
Linus Torvalds's avatar
Linus Torvalds committed
333
	 */
334
#ifdef CONFIG_X86_NUMAQ
Linus Torvalds's avatar
Linus Torvalds committed
335
	mpc_record = 0;
336
#endif
Linus Torvalds's avatar
Linus Torvalds committed
337
	while (count < mpc->mpc_length) {
338 339
		switch (*mpt) {
		case MP_PROCESSOR:
Linus Torvalds's avatar
Linus Torvalds committed
340
			{
341 342
				struct mpc_config_processor *m =
				    (struct mpc_config_processor *)mpt;
Linus Torvalds's avatar
Linus Torvalds committed
343 344 345 346 347 348 349
				/* ACPI may have already provided this data */
				if (!acpi_lapic)
					MP_processor_info(m);
				mpt += sizeof(*m);
				count += sizeof(*m);
				break;
			}
350
		case MP_BUS:
Linus Torvalds's avatar
Linus Torvalds committed
351
			{
352 353
				struct mpc_config_bus *m =
				    (struct mpc_config_bus *)mpt;
Linus Torvalds's avatar
Linus Torvalds committed
354 355 356 357 358
				MP_bus_info(m);
				mpt += sizeof(*m);
				count += sizeof(*m);
				break;
			}
359
		case MP_IOAPIC:
Linus Torvalds's avatar
Linus Torvalds committed
360
			{
361
#ifdef CONFIG_X86_IO_APIC
362 363
				struct mpc_config_ioapic *m =
				    (struct mpc_config_ioapic *)mpt;
Linus Torvalds's avatar
Linus Torvalds committed
364
				MP_ioapic_info(m);
365
#endif
366 367
				mpt += sizeof(struct mpc_config_ioapic);
				count += sizeof(struct mpc_config_ioapic);
Linus Torvalds's avatar
Linus Torvalds committed
368 369
				break;
			}
370
		case MP_INTSRC:
Linus Torvalds's avatar
Linus Torvalds committed
371
			{
372
#ifdef CONFIG_X86_IO_APIC
373 374
				struct mpc_config_intsrc *m =
				    (struct mpc_config_intsrc *)mpt;
Linus Torvalds's avatar
Linus Torvalds committed
375 376

				MP_intsrc_info(m);
377
#endif
378 379
				mpt += sizeof(struct mpc_config_intsrc);
				count += sizeof(struct mpc_config_intsrc);
Linus Torvalds's avatar
Linus Torvalds committed
380 381
				break;
			}
382
		case MP_LINTSRC:
Linus Torvalds's avatar
Linus Torvalds committed
383
			{
384 385
				struct mpc_config_lintsrc *m =
				    (struct mpc_config_lintsrc *)mpt;
Linus Torvalds's avatar
Linus Torvalds committed
386
				MP_lintsrc_info(m);
387 388
				mpt += sizeof(*m);
				count += sizeof(*m);
Linus Torvalds's avatar
Linus Torvalds committed
389 390
				break;
			}
391
		default:
Linus Torvalds's avatar
Linus Torvalds committed
392 393 394 395 396
			{
				count = mpc->mpc_length;
				break;
			}
		}
397
#ifdef CONFIG_X86_NUMAQ
Linus Torvalds's avatar
Linus Torvalds committed
398
		++mpc_record;
399
#endif
Linus Torvalds's avatar
Linus Torvalds committed
400
	}
401
	setup_apic_routing();
Linus Torvalds's avatar
Linus Torvalds committed
402
	if (!num_processors)
403
		printk(KERN_ERR "MPTABLE: no processors registered!\n");
Linus Torvalds's avatar
Linus Torvalds committed
404 405 406
	return num_processors;
}

407 408
#ifdef CONFIG_X86_IO_APIC

Linus Torvalds's avatar
Linus Torvalds committed
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
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;
424
	intsrc.mpc_irqflag = 0;	/* conforming */
Linus Torvalds's avatar
Linus Torvalds committed
425 426 427 428 429 430 431 432 433 434 435 436 437 438
	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) {
439 440
		printk(KERN_INFO "ISA/PCI bus type with no IRQ information... "
		       "falling back to ELCR\n");
Linus Torvalds's avatar
Linus Torvalds committed
441

442 443 444 445
		if (ELCR_trigger(0) || ELCR_trigger(1) || ELCR_trigger(2) ||
		    ELCR_trigger(13))
			printk(KERN_ERR "ELCR contains invalid data... "
			       "not using ELCR\n");
Linus Torvalds's avatar
Linus Torvalds committed
446
		else {
447 448
			printk(KERN_INFO
			       "Using ELCR to identify PCI interrupts\n");
Linus Torvalds's avatar
Linus Torvalds committed
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
			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;
477
		intsrc.mpc_dstirq = i ? i : 2;	/* IRQ0 to INTIN2 */
Linus Torvalds's avatar
Linus Torvalds committed
478 479 480 481 482
		MP_intsrc_info(&intsrc);
	}

	intsrc.mpc_irqtype = mp_ExtINT;
	intsrc.mpc_srcbusirq = 0;
483
	intsrc.mpc_dstirq = 0;	/* 8259A to INTIN0 */
Linus Torvalds's avatar
Linus Torvalds committed
484 485 486
	MP_intsrc_info(&intsrc);
}

487 488
#endif

Linus Torvalds's avatar
Linus Torvalds committed
489 490 491 492
static inline void __init construct_default_ISA_mptable(int mpc_default_type)
{
	struct mpc_config_processor processor;
	struct mpc_config_bus bus;
493
#ifdef CONFIG_X86_IO_APIC
Linus Torvalds's avatar
Linus Torvalds committed
494
	struct mpc_config_ioapic ioapic;
495
#endif
Linus Torvalds's avatar
Linus Torvalds committed
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
	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;
	/* Either an integrated APIC or a discrete 82489DX. */
	processor.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01;
	processor.mpc_cpuflag = CPU_ENABLED;
	processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) |
513
	    (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_mask;
Linus Torvalds's avatar
Linus Torvalds committed
514 515 516 517 518 519 520 521 522 523 524
	processor.mpc_featureflag = boot_cpu_data.x86_capability[0];
	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) {
525
	default:
526
		printk(KERN_ERR "???\nUnknown standard configuration %d\n",
527 528 529 530 531 532 533 534 535 536 537 538 539 540
		       mpc_default_type);
		/* fall through */
	case 1:
	case 5:
		memcpy(bus.mpc_bustype, "ISA   ", 6);
		break;
	case 2:
	case 6:
	case 3:
		memcpy(bus.mpc_bustype, "EISA  ", 6);
		break;
	case 4:
	case 7:
		memcpy(bus.mpc_bustype, "MCA   ", 6);
Linus Torvalds's avatar
Linus Torvalds committed
541 542 543 544 545 546 547 548
	}
	MP_bus_info(&bus);
	if (mpc_default_type > 4) {
		bus.mpc_busid = 1;
		memcpy(bus.mpc_bustype, "PCI   ", 6);
		MP_bus_info(&bus);
	}

549
#ifdef CONFIG_X86_IO_APIC
Linus Torvalds's avatar
Linus Torvalds committed
550 551 552 553 554 555 556 557 558 559 560
	ioapic.mpc_type = MP_IOAPIC;
	ioapic.mpc_apicid = 2;
	ioapic.mpc_apicver = mpc_default_type > 4 ? 0x10 : 0x01;
	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);
561
#endif
Linus Torvalds's avatar
Linus Torvalds committed
562
	lintsrc.mpc_type = MP_LINTSRC;
563
	lintsrc.mpc_irqflag = 0;	/* conforming */
Linus Torvalds's avatar
Linus Torvalds committed
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
	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.
 */
579
static void __init __get_smp_config(unsigned early)
Linus Torvalds's avatar
Linus Torvalds committed
580 581 582
{
	struct intel_mp_floating *mpf = mpf_found;

583 584 585
	if (acpi_lapic && early)
		return;

Linus Torvalds's avatar
Linus Torvalds committed
586
	/*
587
	 * ACPI supports both logical (e.g. Hyper-Threading) and physical
Linus Torvalds's avatar
Linus Torvalds committed
588 589 590
	 * processors, where MPS only supports physical.
	 */
	if (acpi_lapic && acpi_ioapic) {
591 592
		printk(KERN_INFO "Using ACPI (MADT) for SMP configuration "
		       "information\n");
Linus Torvalds's avatar
Linus Torvalds committed
593
		return;
594
	} else if (acpi_lapic)
595 596
		printk(KERN_INFO "Using ACPI for processor (LAPIC) "
		       "configuration information\n");
Linus Torvalds's avatar
Linus Torvalds committed
597

598 599
	printk(KERN_INFO "Intel MultiProcessor Specification v1.%d\n",
	       mpf->mpf_specification);
600
#ifdef CONFIG_X86_32
601
	if (mpf->mpf_feature2 & (1 << 7)) {
Linus Torvalds's avatar
Linus Torvalds committed
602 603 604 605 606 607
		printk(KERN_INFO "    IMCR and PIC compatibility mode.\n");
		pic_mode = 1;
	} else {
		printk(KERN_INFO "    Virtual Wire compatibility mode.\n");
		pic_mode = 0;
	}
608
#endif
Linus Torvalds's avatar
Linus Torvalds committed
609 610 611 612
	/*
	 * Now see if we need to read further.
	 */
	if (mpf->mpf_feature1 != 0) {
613 614 615 616 617 618 619
		if (early) {
			/*
			 * local APIC has default address
			 */
			mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
			return;
		}
Linus Torvalds's avatar
Linus Torvalds committed
620

621 622
		printk(KERN_INFO "Default MP configuration #%d\n",
		       mpf->mpf_feature1);
Linus Torvalds's avatar
Linus Torvalds committed
623 624 625 626 627 628 629 630
		construct_default_ISA_mptable(mpf->mpf_feature1);

	} else if (mpf->mpf_physptr) {

		/*
		 * Read the physical hardware table.  Anything here will
		 * override the defaults.
		 */
631
		if (!smp_read_mpc(phys_to_virt(mpf->mpf_physptr), early)) {
Linus Torvalds's avatar
Linus Torvalds committed
632
			smp_found_config = 0;
633 634
			printk(KERN_ERR
			       "BIOS bug, MP table errors detected!...\n");
635 636
			printk(KERN_ERR "... disabling SMP support. "
			       "(tell your hw vendor)\n");
Linus Torvalds's avatar
Linus Torvalds committed
637 638
			return;
		}
639

640 641
		if (early)
			return;
642
#ifdef CONFIG_X86_IO_APIC
Linus Torvalds's avatar
Linus Torvalds committed
643 644 645 646 647 648 649 650
		/*
		 * 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;

651 652 653
			printk(KERN_ERR "BIOS bug, no explicit IRQ entries, "
			       "using default mptable. "
			       "(tell your hw vendor)\n");
Linus Torvalds's avatar
Linus Torvalds committed
654 655 656 657 658 659 660 661

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

			construct_default_ioirq_mptable(0);
		}
662
#endif
Linus Torvalds's avatar
Linus Torvalds committed
663 664 665
	} else
		BUG();

666 667
	if (!early)
		printk(KERN_INFO "Processors: %d\n", num_processors);
Linus Torvalds's avatar
Linus Torvalds committed
668 669 670 671 672
	/*
	 * Only use the first configuration found.
	 */
}

673 674 675 676 677 678 679 680 681 682 683 684
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)
Linus Torvalds's avatar
Linus Torvalds committed
685
{
686 687
	extern void __bad_mpf_size(void);
	unsigned int *bp = phys_to_virt(base);
Linus Torvalds's avatar
Linus Torvalds committed
688 689
	struct intel_mp_floating *mpf;

690
	Dprintk("Scan SMP from %p for %ld bytes.\n", bp, length);
Linus Torvalds's avatar
Linus Torvalds committed
691
	if (sizeof(*mpf) != 16)
692
		__bad_mpf_size();
Linus Torvalds's avatar
Linus Torvalds committed
693 694 695 696

	while (length > 0) {
		mpf = (struct intel_mp_floating *)bp;
		if ((*bp == SMP_MAGIC_IDENT) &&
697 698 699 700
		    (mpf->mpf_length == 1) &&
		    !mpf_checksum((unsigned char *)bp, 16) &&
		    ((mpf->mpf_specification == 1)
		     || (mpf->mpf_specification == 4))) {
Linus Torvalds's avatar
Linus Torvalds committed
701 702

			smp_found_config = 1;
703 704
			mpf_found = mpf;
#ifdef CONFIG_X86_32
705
			printk(KERN_INFO "found SMP MP-table at [%p] %08lx\n",
706
			       mpf, virt_to_phys(mpf));
707 708
			reserve_bootmem(virt_to_phys(mpf), PAGE_SIZE,
					BOOTMEM_DEFAULT);
Linus Torvalds's avatar
Linus Torvalds committed
709 710 711 712 713 714 715 716 717 718 719 720 721 722
			if (mpf->mpf_physptr) {
				/*
				 * 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
				 * PAGE_SIZE from mpg->mpf_physptr yields BUG()
				 * in reserve_bootmem.
				 */
				unsigned long size = PAGE_SIZE;
				unsigned long end = max_low_pfn * PAGE_SIZE;
				if (mpf->mpf_physptr + size > end)
					size = end - mpf->mpf_physptr;
723 724
				reserve_bootmem(mpf->mpf_physptr, size,
						BOOTMEM_DEFAULT);
Linus Torvalds's avatar
Linus Torvalds committed
725 726
			}

727 728 729 730 731 732 733 734 735 736
#else
			if (!reserve)
				return 1;

			reserve_bootmem_generic(virt_to_phys(mpf), PAGE_SIZE);
			if (mpf->mpf_physptr)
				reserve_bootmem_generic(mpf->mpf_physptr,
							PAGE_SIZE);
#endif
		return 1;
Linus Torvalds's avatar
Linus Torvalds committed
737 738 739 740 741 742 743
		}
		bp += 4;
		length -= 16;
	}
	return 0;
}

744
static void __init __find_smp_config(unsigned reserve)
Linus Torvalds's avatar
Linus Torvalds committed
745 746 747 748 749 750 751 752 753 754 755
{
	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
	 */
756 757 758
	if (smp_scan_config(0x0, 0x400, reserve) ||
	    smp_scan_config(639 * 0x400, 0x400, reserve) ||
	    smp_scan_config(0xF0000, 0x10000, reserve))
Linus Torvalds's avatar
Linus Torvalds committed
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778
		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)
779 780 781 782 783 784 785 786 787 788 789
		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);
Linus Torvalds's avatar
Linus Torvalds committed
790 791 792 793 794 795
}

/* --------------------------------------------------------------------------
                            ACPI-based MP Configuration
   -------------------------------------------------------------------------- */

Len Brown's avatar
Len Brown committed
796
#ifdef CONFIG_ACPI
Linus Torvalds's avatar
Linus Torvalds committed
797

798
#ifdef	CONFIG_X86_IO_APIC
Linus Torvalds's avatar
Linus Torvalds committed
799 800 801 802

#define MP_ISA_BUS		0
#define MP_MAX_IOAPIC_PIN	127

803
extern struct mp_ioapic_routing mp_ioapic_routing[MAX_IO_APICS];
Linus Torvalds's avatar
Linus Torvalds committed
804

805
static int mp_find_ioapic(int gsi)
Linus Torvalds's avatar
Linus Torvalds committed
806
{
807
	int i = 0;
Linus Torvalds's avatar
Linus Torvalds committed
808 809 810 811

	/* Find the IOAPIC that manages this GSI. */
	for (i = 0; i < nr_ioapics; i++) {
		if ((gsi >= mp_ioapic_routing[i].gsi_base)
812
		    && (gsi <= mp_ioapic_routing[i].gsi_end))
Linus Torvalds's avatar
Linus Torvalds committed
813 814 815 816 817 818 819 820
			return i;
	}

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

	return -1;
}

821 822 823 824 825 826 827 828 829
static u8 uniq_ioapic_id(u8 id)
{
	if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
	    !APIC_XAPIC(apic_version[boot_cpu_physical_apicid]))
		return io_apic_get_unique_id(nr_ioapics, id);
	else
		return id;
}

Jack Steiner's avatar
Jack Steiner committed
830
void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)
Linus Torvalds's avatar
Linus Torvalds committed
831
{
832
	int idx = 0;
Linus Torvalds's avatar
Linus Torvalds committed
833

834
	if (bad_ioapic(address))
Linus Torvalds's avatar
Linus Torvalds committed
835 836
		return;

837
	idx = nr_ioapics;
Linus Torvalds's avatar
Linus Torvalds committed
838 839 840 841 842 843

	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);
844
	mp_ioapics[idx].mpc_apicid = uniq_ioapic_id(id);
Linus Torvalds's avatar
Linus Torvalds committed
845
	mp_ioapics[idx].mpc_apicver = io_apic_get_version(idx);
846 847

	/*
Linus Torvalds's avatar
Linus Torvalds committed
848 849 850 851 852
	 * Build basic GSI lookup table to facilitate gsi->io_apic lookups
	 * and to prevent reprogramming of IOAPIC pins (PCI GSIs).
	 */
	mp_ioapic_routing[idx].apic_id = mp_ioapics[idx].mpc_apicid;
	mp_ioapic_routing[idx].gsi_base = gsi_base;
853
	mp_ioapic_routing[idx].gsi_end = gsi_base +
854
	    io_apic_get_redir_entries(idx);
Linus Torvalds's avatar
Linus Torvalds committed
855

856 857
	printk("IOAPIC[%d]: apic_id %d, version %d, address 0x%x, "
	       "GSI %d-%d\n", idx, mp_ioapics[idx].mpc_apicid,
858 859
	       mp_ioapics[idx].mpc_apicver,
	       mp_ioapics[idx].mpc_apicaddr,
860
	       mp_ioapic_routing[idx].gsi_base, mp_ioapic_routing[idx].gsi_end);
861 862

	nr_ioapics++;
Linus Torvalds's avatar
Linus Torvalds committed
863 864
}

865
void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi)
Linus Torvalds's avatar
Linus Torvalds committed
866 867
{
	struct mpc_config_intsrc intsrc;
868 869
	int ioapic = -1;
	int pin = -1;
Linus Torvalds's avatar
Linus Torvalds committed
870

871
	/*
Linus Torvalds's avatar
Linus Torvalds committed
872 873 874 875 876 877 878 879 880
	 * Convert 'gsi' to 'ioapic.pin'.
	 */
	ioapic = mp_find_ioapic(gsi);
	if (ioapic < 0)
		return;
	pin = gsi - mp_ioapic_routing[ioapic].gsi_base;

	/*
	 * TBD: This check is for faulty timer entries, where the override
881
	 *      erroneously sets the trigger to level, resulting in a HUGE
Linus Torvalds's avatar
Linus Torvalds committed
882 883 884 885 886 887 888 889 890
	 *      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;
891 892 893
	intsrc.mpc_srcbusirq = bus_irq;	/* IRQ */
	intsrc.mpc_dstapic = mp_ioapics[ioapic].mpc_apicid;	/* APIC ID */
	intsrc.mpc_dstirq = pin;	/* INTIN# */
Linus Torvalds's avatar
Linus Torvalds committed
894 895

	Dprintk("Int: type %d, pol %d, trig %d, bus %d, irq %d, %d-%d\n",
896 897
		intsrc.mpc_irqtype, intsrc.mpc_irqflag & 3,
		(intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus,
Linus Torvalds's avatar
Linus Torvalds committed
898 899 900 901 902 903 904
		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");
}

905 906
int es7000_plat;

907
void __init mp_config_acpi_legacy_irqs(void)
Linus Torvalds's avatar
Linus Torvalds committed
908 909
{
	struct mpc_config_intsrc intsrc;
910 911
	int i = 0;
	int ioapic = -1;
Linus Torvalds's avatar
Linus Torvalds committed
912

913
#if defined (CONFIG_MCA) || defined (CONFIG_EISA)
914
	/*
Linus Torvalds's avatar
Linus Torvalds committed
915 916 917
	 * Fabricate the legacy ISA bus (bus #31).
	 */
	mp_bus_id_to_type[MP_ISA_BUS] = MP_BUS_ISA;
918
#endif
919
	set_bit(MP_ISA_BUS, mp_bus_not_pci);
Linus Torvalds's avatar
Linus Torvalds committed
920 921 922 923 924 925 926 927
	Dprintk("Bus #%d is ISA\n", MP_ISA_BUS);

	/*
	 * Older generations of ES7000 have no legacy identity mappings
	 */
	if (es7000_plat == 1)
		return;

928 929
	/*
	 * Locate the IOAPIC that manages the ISA IRQs (0-15).
Linus Torvalds's avatar
Linus Torvalds committed
930 931 932 933 934 935
	 */
	ioapic = mp_find_ioapic(0);
	if (ioapic < 0)
		return;

	intsrc.mpc_type = MP_INTSRC;
936
	intsrc.mpc_irqflag = 0;	/* Conforming */
Linus Torvalds's avatar
Linus Torvalds committed
937
	intsrc.mpc_srcbus = MP_ISA_BUS;
938
#ifdef CONFIG_X86_IO_APIC
Linus Torvalds's avatar
Linus Torvalds committed
939
	intsrc.mpc_dstapic = mp_ioapics[ioapic].mpc_apicid;
940
#endif
941
	/*
Linus Torvalds's avatar
Linus Torvalds committed
942
	 * Use the default configuration for the IRQs 0-15.  Unless
Simon Arlott's avatar
Simon Arlott committed
943
	 * overridden by (MADT) interrupt source override entries.
Linus Torvalds's avatar
Linus Torvalds committed
944 945 946 947 948 949 950 951
	 */
	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? */
952 953
			if (irq->mpc_srcbus == MP_ISA_BUS
			    && irq->mpc_srcbusirq == i)
Linus Torvalds's avatar
Linus Torvalds committed
954 955 956 957
				break;

			/* Do we already have a mapping for this IOAPIC pin */
			if ((irq->mpc_dstapic == intsrc.mpc_dstapic) &&
958
			    (irq->mpc_dstirq == i))
Linus Torvalds's avatar
Linus Torvalds committed
959 960 961 962 963
				break;
		}

		if (idx != mp_irq_entries) {
			printk(KERN_DEBUG "ACPI: IRQ%d used by override.\n", i);
964
			continue;	/* IRQ already used */
Linus Torvalds's avatar
Linus Torvalds committed
965 966 967
		}

		intsrc.mpc_irqtype = mp_INT;
968
		intsrc.mpc_srcbusirq = i;	/* Identity mapped */
Linus Torvalds's avatar
Linus Torvalds committed
969 970 971
		intsrc.mpc_dstirq = i;

		Dprintk("Int: type %d, pol %d, trig %d, bus %d, irq %d, "
972 973 974
			"%d-%d\n", intsrc.mpc_irqtype, intsrc.mpc_irqflag & 3,
			(intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus,
			intsrc.mpc_srcbusirq, intsrc.mpc_dstapic,
Linus Torvalds's avatar
Linus Torvalds committed
975 976 977 978 979 980 981 982
			intsrc.mpc_dstirq);

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

983
#define MAX_GSI_NUM	4096
984
#define IRQ_COMPRESSION_START	64
985

986
int mp_register_gsi(u32 gsi, int triggering, int polarity)
Linus Torvalds's avatar
Linus Torvalds committed
987
{
988 989 990
	int ioapic = -1;
	int ioapic_pin = 0;
	int idx, bit = 0;
991
	static int pci_irq = IRQ_COMPRESSION_START;
992
	/*
Joe Perches's avatar
Joe Perches committed
993
	 * Mapping between Global System Interrupts, which
994 995 996
	 * represent all possible interrupts, and IRQs
	 * assigned to actual devices.
	 */
997
	static int gsi_to_irq[MAX_GSI_NUM];
Linus Torvalds's avatar
Linus Torvalds committed
998 999

	/* Don't set up the ACPI SCI because it's already set up */
1000
	if (acpi_gbl_FADT.sci_interrupt == gsi)
Linus Torvalds's avatar
Linus Torvalds committed
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
		return gsi;

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

	ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base;

	if (ioapic_renumber_irq)
		gsi = ioapic_renumber_irq(ioapic, gsi);

1014 1015
	/*
	 * Avoid pin reprogramming.  PRTs typically include entries
Linus Torvalds's avatar
Linus Torvalds committed
1016 1017 1018 1019 1020 1021 1022
	 * 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 "
1023 1024
		       "%d-%d\n", mp_ioapic_routing[ioapic].apic_id,
		       ioapic_pin);
Linus Torvalds's avatar
Linus Torvalds committed
1025 1026
		return gsi;
	}
1027
	if ((1 << bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
Linus Torvalds's avatar
Linus Torvalds committed
1028 1029
		Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
			mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
1030
		return (gsi < IRQ_COMPRESSION_START ? gsi : gsi_to_irq[gsi]);
Linus Torvalds's avatar
Linus Torvalds committed
1031 1032
	}

1033
	mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1 << bit);
Linus Torvalds's avatar
Linus Torvalds committed
1034

1035 1036 1037 1038
	/*
	 * For GSI >= 64, use IRQ compression
	 */
	if ((gsi >= IRQ_COMPRESSION_START)
1039
	    && (triggering == ACPI_LEVEL_SENSITIVE)) {
1040 1041 1042 1043 1044 1045
		/*
		 * For PCI devices assign IRQs in order, avoiding gaps
		 * due to unused I/O APIC pins.
		 */
		int irq = gsi;
		if (gsi < MAX_GSI_NUM) {
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055
			/*
			 * Retain the VIA chipset work-around (gsi > 15), but
			 * avoid a problem where the 8254 timer (IRQ0) is setup
			 * via an override (so it's not on pin 0 of the ioapic),
			 * and at the same time, the pin 0 interrupt is a PCI
			 * type.  The gsi > 15 test could cause these two pins
			 * to be shared as IRQ0, and they are not shareable.
			 * So test for this condition, and if necessary, avoid
			 * the pin collision.
			 */
1056
			gsi = pci_irq++;
1057 1058 1059
			/*
			 * Don't assign IRQ used by ACPI SCI
			 */
1060
			if (gsi == acpi_gbl_FADT.sci_interrupt)
1061
				gsi = pci_irq++;
1062 1063 1064 1065 1066 1067 1068
			gsi_to_irq[irq] = gsi;
		} else {
			printk(KERN_ERR "GSI %u is too high\n", gsi);
			return gsi;
		}
	}

Linus Torvalds's avatar
Linus Torvalds committed
1069
	io_apic_set_pci_routing(ioapic, ioapic_pin, gsi,
1070 1071
				triggering == ACPI_EDGE_SENSITIVE ? 0 : 1,
				polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
Linus Torvalds's avatar
Linus Torvalds committed
1072 1073 1074
	return gsi;
}

1075
#endif /* CONFIG_X86_IO_APIC */
Len Brown's avatar
Len Brown committed
1076
#endif /* CONFIG_ACPI */