boot.c 41 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
/*
 *  boot.c - Architecture-Specific Low-Level ACPI Boot Support
 *
 *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
 *  Copyright (C) 2001 Jun Nakajima <jun.nakajima@intel.com>
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */

#include <linux/init.h>
#include <linux/acpi.h>
28
#include <linux/acpi_pmtmr.h>
Linus Torvalds's avatar
Linus Torvalds committed
29
#include <linux/efi.h>
30
#include <linux/cpumask.h>
Linus Torvalds's avatar
Linus Torvalds committed
31
#include <linux/module.h>
32
#include <linux/dmi.h>
33
#include <linux/irq.h>
34 35
#include <linux/bootmem.h>
#include <linux/ioport.h>
36
#include <linux/pci.h>
Linus Torvalds's avatar
Linus Torvalds committed
37 38 39 40 41 42

#include <asm/pgtable.h>
#include <asm/io_apic.h>
#include <asm/apic.h>
#include <asm/io.h>
#include <asm/mpspec.h>
43
#include <asm/smp.h>
Linus Torvalds's avatar
Linus Torvalds committed
44

45
static int __initdata acpi_force = 0;
46
u32 acpi_rsdt_forced;
47
int acpi_disabled;
48 49
EXPORT_SYMBOL(acpi_disabled);

Linus Torvalds's avatar
Linus Torvalds committed
50
#ifdef	CONFIG_X86_64
Ingo Molnar's avatar
Ingo Molnar committed
51
# include <asm/proto.h>
Len Brown's avatar
Len Brown committed
52
#endif				/* X86 */
Linus Torvalds's avatar
Linus Torvalds committed
53 54 55

#define BAD_MADT_ENTRY(entry, end) (					    \
		(!entry) || (unsigned long)entry + sizeof(*entry) > end ||  \
56
		((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
Linus Torvalds's avatar
Linus Torvalds committed
57 58 59

#define PREFIX			"ACPI: "

Andrew Morton's avatar
Andrew Morton committed
60
int acpi_noirq;				/* skip ACPI IRQ initialization */
61 62
int acpi_pci_disabled;		/* skip ACPI PCI scan and IRQ initialization */
EXPORT_SYMBOL(acpi_pci_disabled);
Linus Torvalds's avatar
Linus Torvalds committed
63 64 65 66 67 68
int acpi_ht __initdata = 1;	/* enable HT */

int acpi_lapic;
int acpi_ioapic;
int acpi_strict;

69
u8 acpi_sci_flags __initdata;
Linus Torvalds's avatar
Linus Torvalds committed
70 71
int acpi_sci_override_gsi __initdata;
int acpi_skip_timer_override __initdata;
72
int acpi_use_timer_override __initdata;
Linus Torvalds's avatar
Linus Torvalds committed
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87

#ifdef CONFIG_X86_LOCAL_APIC
static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
#endif

#ifndef __HAVE_ARCH_CMPXCHG
#warning ACPI uses CMPXCHG, i486 and later hardware
#endif

/* --------------------------------------------------------------------------
                              Boot-time Configuration
   -------------------------------------------------------------------------- */

/*
 * The default interrupt routing model is PIC (8259).  This gets
Simon Arlott's avatar
Simon Arlott committed
88
 * overridden if IOAPICs are enumerated (below).
Linus Torvalds's avatar
Linus Torvalds committed
89
 */
Len Brown's avatar
Len Brown committed
90
enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_PIC;
Linus Torvalds's avatar
Linus Torvalds committed
91 92 93 94 95 96 97 98 99 100 101 102 103 104


/*
 * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END,
 * to map the target physical address. The problem is that set_fixmap()
 * provides a single page, and it is possible that the page is not
 * sufficient.
 * By using this area, we can map up to MAX_IO_APICS pages temporarily,
 * i.e. until the next __va_range() call.
 *
 * Important Safety Note:  The fixed I/O APIC page numbers are *subtracted*
 * from the fixed base.  That's why we start at FIX_IO_APIC_BASE_END and
 * count idx down while incrementing the phys address.
 */
105
char *__init __acpi_map_table(unsigned long phys, unsigned long size)
Linus Torvalds's avatar
Linus Torvalds committed
106 107
{

Yinghai Lu's avatar
Yinghai Lu committed
108 109 110
	if (!phys || !size)
		return NULL;

111 112 113 114 115 116
	return early_ioremap(phys, size);
}
void __init __acpi_unmap_table(char *map, unsigned long size)
{
	if (!map || !size)
		return;
Linus Torvalds's avatar
Linus Torvalds committed
117

118
	early_iounmap(map, size);
Linus Torvalds's avatar
Linus Torvalds committed
119 120 121
}

#ifdef CONFIG_X86_LOCAL_APIC
122
static int __init acpi_parse_madt(struct acpi_table_header *table)
Linus Torvalds's avatar
Linus Torvalds committed
123
{
Len Brown's avatar
Len Brown committed
124
	struct acpi_table_madt *madt = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
125

126
	if (!cpu_has_apic)
Linus Torvalds's avatar
Linus Torvalds committed
127 128
		return -EINVAL;

129
	madt = (struct acpi_table_madt *)table;
Linus Torvalds's avatar
Linus Torvalds committed
130 131 132 133 134
	if (!madt) {
		printk(KERN_WARNING PREFIX "Unable to map MADT\n");
		return -ENODEV;
	}

135 136
	if (madt->address) {
		acpi_lapic_addr = (u64) madt->address;
Linus Torvalds's avatar
Linus Torvalds committed
137 138

		printk(KERN_DEBUG PREFIX "Local APIC address 0x%08x\n",
139
		       madt->address);
Linus Torvalds's avatar
Linus Torvalds committed
140 141
	}

142 143
	default_acpi_madt_oem_check(madt->header.oem_id,
				    madt->header.oem_table_id);
Len Brown's avatar
Len Brown committed
144

Linus Torvalds's avatar
Linus Torvalds committed
145 146 147
	return 0;
}

148 149
static void __cpuinit acpi_register_lapic(int id, u8 enabled)
{
Yinghai Lu's avatar
Yinghai Lu committed
150 151
	unsigned int ver = 0;

152 153 154 155 156
	if (!enabled) {
		++disabled_cpus;
		return;
	}

Yinghai Lu's avatar
Yinghai Lu committed
157 158 159 160
	if (boot_cpu_physical_apicid != -1U)
		ver = apic_version[boot_cpu_physical_apicid];

	generic_processor_info(id, ver);
161 162
}

163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
static int __init
acpi_parse_x2apic(struct acpi_subtable_header *header, const unsigned long end)
{
	struct acpi_madt_local_x2apic *processor = NULL;

	processor = (struct acpi_madt_local_x2apic *)header;

	if (BAD_MADT_ENTRY(processor, end))
		return -EINVAL;

	acpi_table_print_madt_entry(header);

#ifdef CONFIG_X86_X2APIC
	/*
	 * We need to register disabled CPU as well to permit
	 * counting disabled CPUs. This allows us to size
	 * cpus_possible_map more accurately, to permit
	 * to not preallocating memory for all NR_CPUS
	 * when we use CPU hotplug.
	 */
	acpi_register_lapic(processor->local_apic_id,	/* APIC ID */
			    processor->lapic_flags & ACPI_MADT_ENABLED);
#else
	printk(KERN_WARNING PREFIX "x2apic entry ignored\n");
#endif

	return 0;
}

Linus Torvalds's avatar
Linus Torvalds committed
192
static int __init
193
acpi_parse_lapic(struct acpi_subtable_header * header, const unsigned long end)
Linus Torvalds's avatar
Linus Torvalds committed
194
{
195
	struct acpi_madt_local_apic *processor = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
196

197
	processor = (struct acpi_madt_local_apic *)header;
Linus Torvalds's avatar
Linus Torvalds committed
198 199 200 201 202 203

	if (BAD_MADT_ENTRY(processor, end))
		return -EINVAL;

	acpi_table_print_madt_entry(header);

204 205 206 207 208 209 210
	/*
	 * We need to register disabled CPU as well to permit
	 * counting disabled CPUs. This allows us to size
	 * cpus_possible_map more accurately, to permit
	 * to not preallocating memory for all NR_CPUS
	 * when we use CPU hotplug.
	 */
211 212
	acpi_register_lapic(processor->id,	/* APIC ID */
			    processor->lapic_flags & ACPI_MADT_ENABLED);
Linus Torvalds's avatar
Linus Torvalds committed
213 214 215 216

	return 0;
}

217 218 219 220 221 222 223 224 225 226 227 228
static int __init
acpi_parse_sapic(struct acpi_subtable_header *header, const unsigned long end)
{
	struct acpi_madt_local_sapic *processor = NULL;

	processor = (struct acpi_madt_local_sapic *)header;

	if (BAD_MADT_ENTRY(processor, end))
		return -EINVAL;

	acpi_table_print_madt_entry(header);

229 230
	acpi_register_lapic((processor->id << 8) | processor->eid,/* APIC ID */
			    processor->lapic_flags & ACPI_MADT_ENABLED);
231 232 233 234

	return 0;
}

Linus Torvalds's avatar
Linus Torvalds committed
235
static int __init
236
acpi_parse_lapic_addr_ovr(struct acpi_subtable_header * header,
Len Brown's avatar
Len Brown committed
237
			  const unsigned long end)
Linus Torvalds's avatar
Linus Torvalds committed
238
{
239
	struct acpi_madt_local_apic_override *lapic_addr_ovr = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
240

241
	lapic_addr_ovr = (struct acpi_madt_local_apic_override *)header;
Linus Torvalds's avatar
Linus Torvalds committed
242 243 244 245 246 247 248 249 250

	if (BAD_MADT_ENTRY(lapic_addr_ovr, end))
		return -EINVAL;

	acpi_lapic_addr = lapic_addr_ovr->address;

	return 0;
}

251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
static int __init
acpi_parse_x2apic_nmi(struct acpi_subtable_header *header,
		      const unsigned long end)
{
	struct acpi_madt_local_x2apic_nmi *x2apic_nmi = NULL;

	x2apic_nmi = (struct acpi_madt_local_x2apic_nmi *)header;

	if (BAD_MADT_ENTRY(x2apic_nmi, end))
		return -EINVAL;

	acpi_table_print_madt_entry(header);

	if (x2apic_nmi->lint != 1)
		printk(KERN_WARNING PREFIX "NMI not connected to LINT 1!\n");

	return 0;
}

Linus Torvalds's avatar
Linus Torvalds committed
270
static int __init
271
acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long end)
Linus Torvalds's avatar
Linus Torvalds committed
272
{
273
	struct acpi_madt_local_apic_nmi *lapic_nmi = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
274

275
	lapic_nmi = (struct acpi_madt_local_apic_nmi *)header;
Linus Torvalds's avatar
Linus Torvalds committed
276 277 278 279 280 281 282 283 284 285 286 287

	if (BAD_MADT_ENTRY(lapic_nmi, end))
		return -EINVAL;

	acpi_table_print_madt_entry(header);

	if (lapic_nmi->lint != 1)
		printk(KERN_WARNING PREFIX "NMI not connected to LINT 1!\n");

	return 0;
}

Len Brown's avatar
Len Brown committed
288
#endif				/*CONFIG_X86_LOCAL_APIC */
Linus Torvalds's avatar
Linus Torvalds committed
289

290
#ifdef CONFIG_X86_IO_APIC
Linus Torvalds's avatar
Linus Torvalds committed
291 292

static int __init
293
acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end)
Linus Torvalds's avatar
Linus Torvalds committed
294
{
295
	struct acpi_madt_io_apic *ioapic = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
296

297
	ioapic = (struct acpi_madt_io_apic *)header;
Linus Torvalds's avatar
Linus Torvalds committed
298 299 300

	if (BAD_MADT_ENTRY(ioapic, end))
		return -EINVAL;
Len Brown's avatar
Len Brown committed
301

Linus Torvalds's avatar
Linus Torvalds committed
302 303
	acpi_table_print_madt_entry(header);

Len Brown's avatar
Len Brown committed
304 305 306
	mp_register_ioapic(ioapic->id,
			   ioapic->address, ioapic->global_irq_base);

Linus Torvalds's avatar
Linus Torvalds committed
307 308 309 310 311 312
	return 0;
}

/*
 * Parse Interrupt Source Override for the ACPI SCI
 */
313
static void __init acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger)
Linus Torvalds's avatar
Linus Torvalds committed
314 315 316 317 318 319 320 321
{
	if (trigger == 0)	/* compatible SCI trigger is level */
		trigger = 3;

	if (polarity == 0)	/* compatible SCI polarity is low */
		polarity = 3;

	/* Command-line over-ride via acpi_sci= */
322 323
	if (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK)
		trigger = (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2;
Linus Torvalds's avatar
Linus Torvalds committed
324

325 326
	if (acpi_sci_flags & ACPI_MADT_POLARITY_MASK)
		polarity = acpi_sci_flags & ACPI_MADT_POLARITY_MASK;
Linus Torvalds's avatar
Linus Torvalds committed
327 328

	/*
Len Brown's avatar
Len Brown committed
329
	 * mp_config_acpi_legacy_irqs() already setup IRQs < 16
Linus Torvalds's avatar
Linus Torvalds committed
330 331 332
	 * If GSI is < 16, this will update its flags,
	 * else it will create a new mp_irqs[] entry.
	 */
333
	mp_override_legacy_irq(gsi, polarity, trigger, gsi);
Linus Torvalds's avatar
Linus Torvalds committed
334 335 336

	/*
	 * stash over-ride to indicate we've been here
337
	 * and for later update of acpi_gbl_FADT
Linus Torvalds's avatar
Linus Torvalds committed
338
	 */
339
	acpi_sci_override_gsi = gsi;
Linus Torvalds's avatar
Linus Torvalds committed
340 341 342 343
	return;
}

static int __init
344
acpi_parse_int_src_ovr(struct acpi_subtable_header * header,
Len Brown's avatar
Len Brown committed
345
		       const unsigned long end)
Linus Torvalds's avatar
Linus Torvalds committed
346
{
347
	struct acpi_madt_interrupt_override *intsrc = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
348

349
	intsrc = (struct acpi_madt_interrupt_override *)header;
Linus Torvalds's avatar
Linus Torvalds committed
350 351 352 353 354 355

	if (BAD_MADT_ENTRY(intsrc, end))
		return -EINVAL;

	acpi_table_print_madt_entry(header);

356
	if (intsrc->source_irq == acpi_gbl_FADT.sci_interrupt) {
357
		acpi_sci_ioapic_setup(intsrc->global_irq,
358 359
				      intsrc->inti_flags & ACPI_MADT_POLARITY_MASK,
				      (intsrc->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2);
Linus Torvalds's avatar
Linus Torvalds committed
360 361 362 363
		return 0;
	}

	if (acpi_skip_timer_override &&
364
	    intsrc->source_irq == 0 && intsrc->global_irq == 2) {
Len Brown's avatar
Len Brown committed
365 366
		printk(PREFIX "BIOS IRQ0 pin2 override ignored.\n");
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
367 368
	}

369 370 371 372
	mp_override_legacy_irq(intsrc->source_irq,
				intsrc->inti_flags & ACPI_MADT_POLARITY_MASK,
				(intsrc->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2,
				intsrc->global_irq);
Linus Torvalds's avatar
Linus Torvalds committed
373 374 375 376 377

	return 0;
}

static int __init
378
acpi_parse_nmi_src(struct acpi_subtable_header * header, const unsigned long end)
Linus Torvalds's avatar
Linus Torvalds committed
379
{
380
	struct acpi_madt_nmi_source *nmi_src = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
381

382
	nmi_src = (struct acpi_madt_nmi_source *)header;
Linus Torvalds's avatar
Linus Torvalds committed
383 384 385 386 387 388 389 390 391 392 393

	if (BAD_MADT_ENTRY(nmi_src, end))
		return -EINVAL;

	acpi_table_print_madt_entry(header);

	/* TBD: Support nimsrc entries? */

	return 0;
}

Len Brown's avatar
Len Brown committed
394
#endif				/* CONFIG_X86_IO_APIC */
Linus Torvalds's avatar
Linus Torvalds committed
395 396 397

/*
 * acpi_pic_sci_set_trigger()
398
 *
Linus Torvalds's avatar
Linus Torvalds committed
399 400 401 402 403 404 405
 * use ELCR to set PIC-mode trigger type for SCI
 *
 * If a PIC-mode SCI is not recognized or gives spurious IRQ7's
 * it may require Edge Trigger -- use "acpi_sci=edge"
 *
 * Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers
 * for the 8259 PIC.  bit[n] = 1 means irq[n] is Level, otherwise Edge.
Simon Arlott's avatar
Simon Arlott committed
406 407
 * ECLR1 is IRQs 0-7 (IRQ 0, 1, 2 must be 0)
 * ECLR2 is IRQs 8-15 (IRQ 8, 13 must be 0)
Linus Torvalds's avatar
Linus Torvalds committed
408 409
 */

Len Brown's avatar
Len Brown committed
410
void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
Linus Torvalds's avatar
Linus Torvalds committed
411 412 413 414 415 416 417 418
{
	unsigned int mask = 1 << irq;
	unsigned int old, new;

	/* Real old ELCR mask */
	old = inb(0x4d0) | (inb(0x4d1) << 8);

	/*
Simon Arlott's avatar
Simon Arlott committed
419
	 * If we use ACPI to set PCI IRQs, then we should clear ELCR
Linus Torvalds's avatar
Linus Torvalds committed
420 421 422 423 424 425 426 427 428 429
	 * since we will set it correctly as we enable the PCI irq
	 * routing.
	 */
	new = acpi_noirq ? old : 0;

	/*
	 * Update SCI information in the ELCR, it isn't in the PCI
	 * routing tables..
	 */
	switch (trigger) {
Len Brown's avatar
Len Brown committed
430
	case 1:		/* Edge - clear */
Linus Torvalds's avatar
Linus Torvalds committed
431 432
		new &= ~mask;
		break;
Len Brown's avatar
Len Brown committed
433
	case 3:		/* Level - set */
Linus Torvalds's avatar
Linus Torvalds committed
434 435 436 437 438 439 440 441 442 443 444 445 446 447
		new |= mask;
		break;
	}

	if (old == new)
		return;

	printk(PREFIX "setting ELCR to %04x (from %04x)\n", new, old);
	outb(new, 0x4d0);
	outb(new >> 8, 0x4d1);
}

int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
{
448
	*irq = gsi;
Linus Torvalds's avatar
Linus Torvalds committed
449 450 451
	return 0;
}

452 453 454 455
/*
 * success: return IRQ number (>=0)
 * failure: return < 0
 */
456
int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
Linus Torvalds's avatar
Linus Torvalds committed
457 458 459 460 461 462 463 464 465
{
	unsigned int irq;
	unsigned int plat_gsi = gsi;

#ifdef CONFIG_PCI
	/*
	 * Make sure all (legacy) PCI IRQs are set as level-triggered.
	 */
	if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) {
466
		if (trigger == ACPI_LEVEL_SENSITIVE)
Len Brown's avatar
Len Brown committed
467
			eisa_set_level_irq(gsi);
Linus Torvalds's avatar
Linus Torvalds committed
468 469 470 471 472
	}
#endif

#ifdef CONFIG_X86_IO_APIC
	if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) {
473
		plat_gsi = mp_register_gsi(dev, gsi, trigger, polarity);
Linus Torvalds's avatar
Linus Torvalds committed
474 475 476 477 478
	}
#endif
	acpi_gsi_to_irq(plat_gsi, &irq);
	return irq;
}
Len Brown's avatar
Len Brown committed
479

Linus Torvalds's avatar
Linus Torvalds committed
480 481 482 483
/*
 *  ACPI based hotplug support for CPU
 */
#ifdef CONFIG_ACPI_HOTPLUG_CPU
484 485

static int __cpuinit _acpi_map_lsapic(acpi_handle handle, int *pcpu)
Linus Torvalds's avatar
Linus Torvalds committed
486
{
487 488
	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
	union acpi_object *obj;
489
	struct acpi_madt_local_apic *lapic;
490
	cpumask_var_t tmp_map, new_map;
491 492
	u8 physid;
	int cpu;
493
	int retval = -ENOMEM;
494 495 496 497 498 499 500 501 502 503 504 505 506 507

	if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
		return -EINVAL;

	if (!buffer.length || !buffer.pointer)
		return -EINVAL;

	obj = buffer.pointer;
	if (obj->type != ACPI_TYPE_BUFFER ||
	    obj->buffer.length < sizeof(*lapic)) {
		kfree(buffer.pointer);
		return -EINVAL;
	}

508
	lapic = (struct acpi_madt_local_apic *)obj->buffer.pointer;
509

510 511
	if (lapic->header.type != ACPI_MADT_TYPE_LOCAL_APIC ||
	    !(lapic->lapic_flags & ACPI_MADT_ENABLED)) {
512 513 514 515 516 517 518 519 520 521
		kfree(buffer.pointer);
		return -EINVAL;
	}

	physid = lapic->id;

	kfree(buffer.pointer);
	buffer.length = ACPI_ALLOCATE_BUFFER;
	buffer.pointer = NULL;

522 523 524 525 526 527 528
	if (!alloc_cpumask_var(&tmp_map, GFP_KERNEL))
		goto out;

	if (!alloc_cpumask_var(&new_map, GFP_KERNEL))
		goto free_tmp_map;

	cpumask_copy(tmp_map, cpu_present_mask);
529
	acpi_register_lapic(physid, lapic->lapic_flags & ACPI_MADT_ENABLED);
530 531 532 533 534

	/*
	 * If mp_register_lapic successfully generates a new logical cpu
	 * number, then the following will get us exactly what was mapped
	 */
535 536
	cpumask_andnot(new_map, cpu_present_mask, tmp_map);
	if (cpumask_empty(new_map)) {
537
		printk ("Unable to map lapic to logical cpu number\n");
538 539
		retval = -EINVAL;
		goto free_new_map;
540 541
	}

542
	cpu = cpumask_first(new_map);
543 544

	*pcpu = cpu;
545 546 547 548 549 550 551 552
	retval = 0;

free_new_map:
	free_cpumask_var(new_map);
free_tmp_map:
	free_cpumask_var(tmp_map);
out:
	return retval;
Linus Torvalds's avatar
Linus Torvalds committed
553 554
}

555 556 557 558 559
/* wrapper to silence section mismatch warning */
int __ref acpi_map_lsapic(acpi_handle handle, int *pcpu)
{
	return _acpi_map_lsapic(handle, pcpu);
}
Len Brown's avatar
Len Brown committed
560
EXPORT_SYMBOL(acpi_map_lsapic);
Linus Torvalds's avatar
Linus Torvalds committed
561

Len Brown's avatar
Len Brown committed
562
int acpi_unmap_lsapic(int cpu)
Linus Torvalds's avatar
Linus Torvalds committed
563
{
564
	per_cpu(x86_cpu_to_apicid, cpu) = -1;
565
	set_cpu_present(cpu, false);
566 567 568
	num_processors--;

	return (0);
Linus Torvalds's avatar
Linus Torvalds committed
569
}
Len Brown's avatar
Len Brown committed
570

Linus Torvalds's avatar
Linus Torvalds committed
571
EXPORT_SYMBOL(acpi_unmap_lsapic);
Len Brown's avatar
Len Brown committed
572
#endif				/* CONFIG_ACPI_HOTPLUG_CPU */
Linus Torvalds's avatar
Linus Torvalds committed
573

Len Brown's avatar
Len Brown committed
574
int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
575 576 577 578
{
	/* TBD */
	return -EINVAL;
}
Len Brown's avatar
Len Brown committed
579

580 581
EXPORT_SYMBOL(acpi_register_ioapic);

Len Brown's avatar
Len Brown committed
582
int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base)
583 584 585 586
{
	/* TBD */
	return -EINVAL;
}
Len Brown's avatar
Len Brown committed
587

588 589
EXPORT_SYMBOL(acpi_unregister_ioapic);

590
static int __init acpi_parse_sbf(struct acpi_table_header *table)
Linus Torvalds's avatar
Linus Torvalds committed
591
{
592
	struct acpi_table_boot *sb;
Linus Torvalds's avatar
Linus Torvalds committed
593

594
	sb = (struct acpi_table_boot *)table;
Linus Torvalds's avatar
Linus Torvalds committed
595 596 597 598 599
	if (!sb) {
		printk(KERN_WARNING PREFIX "Unable to map SBF\n");
		return -ENODEV;
	}

600
	sbf_port = sb->cmos_index;	/* Save CMOS port */
Linus Torvalds's avatar
Linus Torvalds committed
601 602 603 604 605

	return 0;
}

#ifdef CONFIG_HPET_TIMER
606
#include <asm/hpet.h>
Linus Torvalds's avatar
Linus Torvalds committed
607

608 609
static struct __initdata resource *hpet_res;

610
static int __init acpi_parse_hpet(struct acpi_table_header *table)
Linus Torvalds's avatar
Linus Torvalds committed
611 612 613
{
	struct acpi_table_hpet *hpet_tbl;

614
	hpet_tbl = (struct acpi_table_hpet *)table;
Linus Torvalds's avatar
Linus Torvalds committed
615 616 617 618 619
	if (!hpet_tbl) {
		printk(KERN_WARNING PREFIX "Unable to map HPET\n");
		return -ENODEV;
	}

620
	if (hpet_tbl->address.space_id != ACPI_SPACE_MEM) {
Linus Torvalds's avatar
Linus Torvalds committed
621 622 623 624
		printk(KERN_WARNING PREFIX "HPET timers must be located in "
		       "memory.\n");
		return -1;
	}
625

626
	hpet_address = hpet_tbl->address.address;
Thomas Gleixner's avatar
Thomas Gleixner committed
627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658

	/*
	 * Some broken BIOSes advertise HPET at 0x0. We really do not
	 * want to allocate a resource there.
	 */
	if (!hpet_address) {
		printk(KERN_WARNING PREFIX
		       "HPET id: %#x base: %#lx is invalid\n",
		       hpet_tbl->id, hpet_address);
		return 0;
	}
#ifdef CONFIG_X86_64
	/*
	 * Some even more broken BIOSes advertise HPET at
	 * 0xfed0000000000000 instead of 0xfed00000. Fix it up and add
	 * some noise:
	 */
	if (hpet_address == 0xfed0000000000000UL) {
		if (!hpet_force_user) {
			printk(KERN_WARNING PREFIX "HPET id: %#x "
			       "base: 0xfed0000000000000 is bogus\n "
			       "try hpet=force on the kernel command line to "
			       "fix it up to 0xfed00000.\n", hpet_tbl->id);
			hpet_address = 0;
			return 0;
		}
		printk(KERN_WARNING PREFIX
		       "HPET id: %#x base: 0xfed0000000000000 fixed up "
		       "to 0xfed00000.\n", hpet_tbl->id);
		hpet_address >>= 32;
	}
#endif
Len Brown's avatar
Len Brown committed
659
	printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
660
	       hpet_tbl->id, hpet_address);
Linus Torvalds's avatar
Linus Torvalds committed
661

662 663 664 665 666 667 668 669 670 671 672 673 674 675 676
	/*
	 * Allocate and initialize the HPET firmware resource for adding into
	 * the resource tree during the lateinit timeframe.
	 */
#define HPET_RESOURCE_NAME_SIZE 9
	hpet_res = alloc_bootmem(sizeof(*hpet_res) + HPET_RESOURCE_NAME_SIZE);

	hpet_res->name = (void *)&hpet_res[1];
	hpet_res->flags = IORESOURCE_MEM;
	snprintf((char *)hpet_res->name, HPET_RESOURCE_NAME_SIZE, "HPET %u",
		 hpet_tbl->sequence);

	hpet_res->start = hpet_address;
	hpet_res->end = hpet_address + (1 * 1024) - 1;

Linus Torvalds's avatar
Linus Torvalds committed
677 678
	return 0;
}
679 680 681 682 683 684 685 686 687 688 689 690 691 692 693

/*
 * hpet_insert_resource inserts the HPET resources used into the resource
 * tree.
 */
static __init int hpet_insert_resource(void)
{
	if (!hpet_res)
		return 1;

	return insert_resource(&iomem_resource, hpet_res);
}

late_initcall(hpet_insert_resource);

Linus Torvalds's avatar
Linus Torvalds committed
694 695 696 697
#else
#define	acpi_parse_hpet	NULL
#endif

698
static int __init acpi_parse_fadt(struct acpi_table_header *table)
Linus Torvalds's avatar
Linus Torvalds committed
699
{
Jason Davis's avatar
Jason Davis committed
700

Linus Torvalds's avatar
Linus Torvalds committed
701 702
#ifdef CONFIG_X86_PM_TIMER
	/* detect the location of the ACPI PM Timer */
703
	if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) {
Linus Torvalds's avatar
Linus Torvalds committed
704
		/* FADT rev. 2 */
705
		if (acpi_gbl_FADT.xpm_timer_block.space_id !=
Len Brown's avatar
Len Brown committed
706
		    ACPI_ADR_SPACE_SYSTEM_IO)
Linus Torvalds's avatar
Linus Torvalds committed
707 708
			return 0;

709
		pmtmr_ioport = acpi_gbl_FADT.xpm_timer_block.address;
710 711 712 713 714 715
		/*
		 * "X" fields are optional extensions to the original V1.0
		 * fields, so we must selectively expand V1.0 fields if the
		 * corresponding X field is zero.
	 	 */
		if (!pmtmr_ioport)
716
			pmtmr_ioport = acpi_gbl_FADT.pm_timer_block;
Linus Torvalds's avatar
Linus Torvalds committed
717 718
	} else {
		/* FADT rev. 1 */
719
		pmtmr_ioport = acpi_gbl_FADT.pm_timer_block;
Linus Torvalds's avatar
Linus Torvalds committed
720 721
	}
	if (pmtmr_ioport)
Len Brown's avatar
Len Brown committed
722 723
		printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n",
		       pmtmr_ioport);
Linus Torvalds's avatar
Linus Torvalds committed
724 725 726 727 728 729 730 731 732
#endif
	return 0;
}

#ifdef	CONFIG_X86_LOCAL_APIC
/*
 * Parse LAPIC entries in MADT
 * returns 0 on success, < 0 on error
 */
733 734 735 736 737 738

static void __init acpi_register_lapic_address(unsigned long address)
{
	mp_lapic_addr = address;

	set_fixmap_nocache(FIX_APIC_BASE, address);
Yinghai Lu's avatar
Yinghai Lu committed
739
	if (boot_cpu_physical_apicid == -1U) {
740
		boot_cpu_physical_apicid  = read_apic_id();
Yinghai Lu's avatar
Yinghai Lu committed
741 742 743
		apic_version[boot_cpu_physical_apicid] =
			 GET_APIC_VERSION(apic_read(APIC_LVR));
	}
744 745
}

746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771
static int __init early_acpi_parse_madt_lapic_addr_ovr(void)
{
	int count;

	if (!cpu_has_apic)
		return -ENODEV;

	/*
	 * Note that the LAPIC address is obtained from the MADT (32-bit value)
	 * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value).
	 */

	count =
	    acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE,
				  acpi_parse_lapic_addr_ovr, 0);
	if (count < 0) {
		printk(KERN_ERR PREFIX
		       "Error parsing LAPIC address override entry\n");
		return count;
	}

	acpi_register_lapic_address(acpi_lapic_addr);

	return count;
}

Len Brown's avatar
Len Brown committed
772
static int __init acpi_parse_madt_lapic_entries(void)
Linus Torvalds's avatar
Linus Torvalds committed
773 774
{
	int count;
775
	int x2count = 0;
Linus Torvalds's avatar
Linus Torvalds committed
776

777 778 779
	if (!cpu_has_apic)
		return -ENODEV;

780
	/*
Linus Torvalds's avatar
Linus Torvalds committed
781 782 783 784
	 * Note that the LAPIC address is obtained from the MADT (32-bit value)
	 * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value).
	 */

Len Brown's avatar
Len Brown committed
785
	count =
786
	    acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE,
Len Brown's avatar
Len Brown committed
787
				  acpi_parse_lapic_addr_ovr, 0);
Linus Torvalds's avatar
Linus Torvalds committed
788
	if (count < 0) {
Len Brown's avatar
Len Brown committed
789 790
		printk(KERN_ERR PREFIX
		       "Error parsing LAPIC address override entry\n");
Linus Torvalds's avatar
Linus Torvalds committed
791 792 793
		return count;
	}

794
	acpi_register_lapic_address(acpi_lapic_addr);
Linus Torvalds's avatar
Linus Torvalds committed
795

796 797 798
	count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_SAPIC,
				      acpi_parse_sapic, MAX_APICS);

799 800 801
	if (!count) {
		x2count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_X2APIC,
						acpi_parse_x2apic, MAX_APICS);
802 803
		count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC,
					      acpi_parse_lapic, MAX_APICS);
804 805
	}
	if (!count && !x2count) {
Linus Torvalds's avatar
Linus Torvalds committed
806 807 808
		printk(KERN_ERR PREFIX "No LAPIC entries present\n");
		/* TBD: Cleanup to allow fallback to MPS */
		return -ENODEV;
809
	} else if (count < 0 || x2count < 0) {
Linus Torvalds's avatar
Linus Torvalds committed
810 811 812 813 814
		printk(KERN_ERR PREFIX "Error parsing LAPIC entry\n");
		/* TBD: Cleanup to allow fallback to MPS */
		return count;
	}

815 816 817
	x2count =
	    acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_X2APIC_NMI,
				  acpi_parse_x2apic_nmi, 0);
Len Brown's avatar
Len Brown committed
818
	count =
819
	    acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_NMI, acpi_parse_lapic_nmi, 0);
820
	if (count < 0 || x2count < 0) {
Linus Torvalds's avatar
Linus Torvalds committed
821 822 823 824 825 826
		printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
		/* TBD: Cleanup to allow fallback to MPS */
		return count;
	}
	return 0;
}
Len Brown's avatar
Len Brown committed
827
#endif				/* CONFIG_X86_LOCAL_APIC */
Linus Torvalds's avatar
Linus Torvalds committed
828

829
#ifdef	CONFIG_X86_IO_APIC
830 831
#define MP_ISA_BUS		0

832
#ifdef CONFIG_X86_ES7000
833 834 835
extern int es7000_plat;
#endif

836 837 838 839 840 841 842 843 844 845 846 847 848 849
int __init acpi_probe_gsi(void)
{
	int idx;
	int gsi;
	int max_gsi = 0;

	if (acpi_disabled)
		return 0;

	if (!acpi_ioapic)
		return 0;

	max_gsi = 0;
	for (idx = 0; idx < nr_ioapics; idx++) {
850
		gsi = mp_gsi_routing[idx].gsi_end;
851 852 853 854 855 856 857 858

		if (gsi > max_gsi)
			max_gsi = gsi;
	}

	return max_gsi + 1;
}

859 860
static void assign_to_mp_irq(struct mpc_intsrc *m,
				    struct mpc_intsrc *mp_irq)
861
{
862
	memcpy(mp_irq, m, sizeof(struct mpc_intsrc));
863 864
}

865 866
static int mp_irq_cmp(struct mpc_intsrc *mp_irq,
				struct mpc_intsrc *m)
867
{
868
	return memcmp(mp_irq, m, sizeof(struct mpc_intsrc));
869 870
}

871
static void save_mp_irq(struct mpc_intsrc *m)
872 873 874 875 876 877 878 879 880 881 882 883 884
{
	int i;

	for (i = 0; i < mp_irq_entries; i++) {
		if (!mp_irq_cmp(&mp_irqs[i], m))
			return;
	}

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

885 886
void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi)
{
887 888
	int ioapic;
	int pin;
889
	struct mpc_intsrc mp_irq;
890 891 892 893 894 895 896

	/*
	 * Convert 'gsi' to 'ioapic.pin'.
	 */
	ioapic = mp_find_ioapic(gsi);
	if (ioapic < 0)
		return;
897
	pin = mp_find_ioapic_pin(ioapic, gsi);
898 899 900 901 902 903 904 905 906

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

907 908 909 910 911 912 913
	mp_irq.type = MP_INTSRC;
	mp_irq.irqtype = mp_INT;
	mp_irq.irqflag = (trigger << 2) | polarity;
	mp_irq.srcbus = MP_ISA_BUS;
	mp_irq.srcbusirq = bus_irq;	/* IRQ */
	mp_irq.dstapic = mp_ioapics[ioapic].apicid; /* APIC ID */
	mp_irq.dstirq = pin;	/* INTIN# */
914

915
	save_mp_irq(&mp_irq);
916 917 918 919
}

void __init mp_config_acpi_legacy_irqs(void)
{
920 921 922
	int i;
	int ioapic;
	unsigned int dstapic;
923
	struct mpc_intsrc mp_irq;
924 925 926 927 928 929 930 931

#if defined (CONFIG_MCA) || defined (CONFIG_EISA)
	/*
	 * Fabricate the legacy ISA bus (bus #31).
	 */
	mp_bus_id_to_type[MP_ISA_BUS] = MP_BUS_ISA;
#endif
	set_bit(MP_ISA_BUS, mp_bus_not_pci);
932
	pr_debug("Bus #%d is ISA\n", MP_ISA_BUS);
933

934
#ifdef CONFIG_X86_ES7000
935 936 937 938 939 940 941 942 943 944 945 946 947
	/*
	 * Older generations of ES7000 have no legacy identity mappings
	 */
	if (es7000_plat == 1)
		return;
#endif

	/*
	 * Locate the IOAPIC that manages the ISA IRQs (0-15).
	 */
	ioapic = mp_find_ioapic(0);
	if (ioapic < 0)
		return;
948
	dstapic = mp_ioapics[ioapic].apicid;
949 950 951 952 953 954 955 956 957

	/*
	 * 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++) {
958
			struct mpc_intsrc *irq = mp_irqs + idx;
959 960

			/* Do we already have a mapping for this ISA IRQ? */
961
			if (irq->srcbus == MP_ISA_BUS && irq->srcbusirq == i)
962 963 964
				break;

			/* Do we already have a mapping for this IOAPIC pin */
965
			if (irq->dstapic == dstapic && irq->dstirq == i)
966 967 968 969 970 971 972 973
				break;
		}

		if (idx != mp_irq_entries) {
			printk(KERN_DEBUG "ACPI: IRQ%d used by override.\n", i);
			continue;	/* IRQ already used */
		}

974 975 976 977 978 979 980
		mp_irq.type = MP_INTSRC;
		mp_irq.irqflag = 0;	/* Conforming */
		mp_irq.srcbus = MP_ISA_BUS;
		mp_irq.dstapic = dstapic;
		mp_irq.irqtype = mp_INT;
		mp_irq.srcbusirq = i; /* Identity mapped */
		mp_irq.dstirq = i;
981

982
		save_mp_irq(&mp_irq);
983 984 985
	}
}

986
static int mp_config_acpi_gsi(struct device *dev, u32 gsi, int trigger,
987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
			int polarity)
{
#ifdef CONFIG_X86_MPPARSE
	struct mpc_intsrc mp_irq;
	struct pci_dev *pdev;
	unsigned char number;
	unsigned int devfn;
	int ioapic;
	u8 pin;

	if (!acpi_ioapic)
		return 0;
	if (!dev)
		return 0;
	if (dev->bus != &pci_bus_type)
		return 0;

	pdev = to_pci_dev(dev);
	number = pdev->bus->number;
	devfn = pdev->devfn;
	pin = pdev->pin;
	/* print the entry should happen on mptable identically */
	mp_irq.type = MP_INTSRC;
	mp_irq.irqtype = mp_INT;
1011
	mp_irq.irqflag = (trigger == ACPI_EDGE_SENSITIVE ? 4 : 0x0c) |
1012 1013 1014 1015
				(polarity == ACPI_ACTIVE_HIGH ? 1 : 3);
	mp_irq.srcbus = number;
	mp_irq.srcbusirq = (((devfn >> 3) & 0x1f) << 2) | ((pin - 1) & 3);
	ioapic = mp_find_ioapic(gsi);
1016
	mp_irq.dstapic = mp_ioapics[ioapic].apicid;
1017 1018 1019 1020 1021 1022 1023
	mp_irq.dstirq = mp_find_ioapic_pin(ioapic, gsi);

	save_mp_irq(&mp_irq);
#endif
	return 0;
}

1024
int mp_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
1025 1026 1027
{
	int ioapic;
	int ioapic_pin;
1028
	struct io_apic_irq_attr irq_attr;
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042

	if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
		return gsi;

	/* Don't set up the ACPI SCI because it's already set up */
	if (acpi_gbl_FADT.sci_interrupt == gsi)
		return gsi;

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

1043
	ioapic_pin = mp_find_ioapic_pin(ioapic, gsi);
1044 1045 1046 1047 1048 1049 1050 1051

#ifdef CONFIG_X86_32
	if (ioapic_renumber_irq)
		gsi = ioapic_renumber_irq(ioapic, gsi);
#endif

	if (ioapic_pin > MP_MAX_IOAPIC_PIN) {
		printk(KERN_ERR "Invalid reference to IOAPIC pin "
1052
		       "%d-%d\n", mp_ioapics[ioapic].apicid,
1053 1054 1055
		       ioapic_pin);
		return gsi;
	}
1056 1057 1058

	if (enable_update_mptable)
		mp_config_acpi_gsi(dev, gsi, trigger, polarity);
1059

1060 1061 1062 1063
	set_io_apic_irq_attr(&irq_attr, ioapic, ioapic_pin,
			     trigger == ACPI_EDGE_SENSITIVE ? 0 : 1,
			     polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
	io_apic_set_pci_routing(dev, gsi, &irq_attr);
1064

1065 1066 1067
	return gsi;
}

Linus Torvalds's avatar
Linus Torvalds committed
1068 1069 1070 1071
/*
 * Parse IOAPIC related entries in MADT
 * returns 0 on success, < 0 on error
 */
Len Brown's avatar
Len Brown committed
1072
static int __init acpi_parse_madt_ioapic_entries(void)
Linus Torvalds's avatar
Linus Torvalds committed
1073 1074 1075 1076 1077 1078 1079 1080 1081
{
	int count;

	/*
	 * ACPI interpreter is required to complete interrupt setup,
	 * so if it is off, don't enumerate the io-apics with ACPI.
	 * If MPS is present, it will handle them,
	 * otherwise the system will stay in PIC mode
	 */
1082
	if (acpi_disabled || acpi_noirq)
Linus Torvalds's avatar
Linus Torvalds committed
1083 1084
		return -ENODEV;

1085
	if (!cpu_has_apic)
1086 1087
		return -ENODEV;

Linus Torvalds's avatar
Linus Torvalds committed
1088
	/*
Len Brown's avatar
Len Brown committed
1089
	 * if "noapic" boot option, don't look for IO-APICs
Linus Torvalds's avatar
Linus Torvalds committed
1090 1091 1092
	 */
	if (skip_ioapic_setup) {
		printk(KERN_INFO PREFIX "Skipping IOAPIC probe "
Len Brown's avatar
Len Brown committed
1093
		       "due to 'noapic' option.\n");
Linus Torvalds's avatar
Linus Torvalds committed
1094 1095 1096
		return -ENODEV;
	}

Len Brown's avatar
Len Brown committed
1097
	count =
1098
	    acpi_table_parse_madt(ACPI_MADT_TYPE_IO_APIC, acpi_parse_ioapic,
Len Brown's avatar
Len Brown committed
1099
				  MAX_IO_APICS);
Linus Torvalds's avatar
Linus Torvalds committed
1100 1101 1102
	if (!count) {
		printk(KERN_ERR PREFIX "No IOAPIC entries present\n");
		return -ENODEV;
Len Brown's avatar
Len Brown committed
1103
	} else if (count < 0) {
Linus Torvalds's avatar
Linus Torvalds committed
1104 1105 1106 1107
		printk(KERN_ERR PREFIX "Error parsing IOAPIC entry\n");
		return count;
	}

Len Brown's avatar
Len Brown committed