boot.c 32.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
/*
 *  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>
Linus Torvalds's avatar
Linus Torvalds committed
36
37
38
39
40
41

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

44
45
46
47
#ifdef CONFIG_X86_LOCAL_APIC
# include <mach_apic.h>
#endif

48
static int __initdata acpi_force = 0;
49

50
51
52
53
54
55
56
#ifdef	CONFIG_ACPI
int acpi_disabled = 0;
#else
int acpi_disabled = 1;
#endif
EXPORT_SYMBOL(acpi_disabled);

Linus Torvalds's avatar
Linus Torvalds committed
57
58
59
#ifdef	CONFIG_X86_64

#include <asm/proto.h>
60
#include <asm/genapic.h>
61

Len Brown's avatar
Len Brown committed
62
#else				/* X86 */
Linus Torvalds's avatar
Linus Torvalds committed
63
64
65
66

#ifdef	CONFIG_X86_LOCAL_APIC
#include <mach_apic.h>
#include <mach_mpparse.h>
Len Brown's avatar
Len Brown committed
67
#endif				/* CONFIG_X86_LOCAL_APIC */
Linus Torvalds's avatar
Linus Torvalds committed
68

Len Brown's avatar
Len Brown committed
69
#endif				/* X86 */
Linus Torvalds's avatar
Linus Torvalds committed
70
71
72

#define BAD_MADT_ENTRY(entry, end) (					    \
		(!entry) || (unsigned long)entry + sizeof(*entry) > end ||  \
73
		((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
Linus Torvalds's avatar
Linus Torvalds committed
74
75
76

#define PREFIX			"ACPI: "

Andrew Morton's avatar
Andrew Morton committed
77
int acpi_noirq;				/* skip ACPI IRQ initialization */
78
79
int acpi_pci_disabled;		/* skip ACPI PCI scan and IRQ initialization */
EXPORT_SYMBOL(acpi_pci_disabled);
Linus Torvalds's avatar
Linus Torvalds committed
80
81
82
83
84
85
int acpi_ht __initdata = 1;	/* enable HT */

int acpi_lapic;
int acpi_ioapic;
int acpi_strict;

86
u8 acpi_sci_flags __initdata;
Linus Torvalds's avatar
Linus Torvalds committed
87
88
int acpi_sci_override_gsi __initdata;
int acpi_skip_timer_override __initdata;
89
int acpi_use_timer_override __initdata;
Linus Torvalds's avatar
Linus Torvalds committed
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104

#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
105
 * overridden if IOAPICs are enumerated (below).
Linus Torvalds's avatar
Linus Torvalds committed
106
 */
Len Brown's avatar
Len Brown committed
107
enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_PIC;
Linus Torvalds's avatar
Linus Torvalds committed
108
109
110
111

#ifdef	CONFIG_X86_64

/* rely on all ACPI tables being in the direct mapping */
112
char *__init __acpi_map_table(unsigned long phys_addr, unsigned long size)
Linus Torvalds's avatar
Linus Torvalds committed
113
114
{
	if (!phys_addr || !size)
Len Brown's avatar
Len Brown committed
115
		return NULL;
Linus Torvalds's avatar
Linus Torvalds committed
116

117
	if (phys_addr+size <= (max_pfn_mapped << PAGE_SHIFT) + PAGE_SIZE)
Linus Torvalds's avatar
Linus Torvalds committed
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
		return __va(phys_addr);

	return NULL;
}

#else

/*
 * 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.
 */
137
char *__init __acpi_map_table(unsigned long phys, unsigned long size)
Linus Torvalds's avatar
Linus Torvalds committed
138
139
140
141
{
	unsigned long base, offset, mapped_size;
	int idx;

Len Brown's avatar
Len Brown committed
142
143
	if (phys + size < 8 * 1024 * 1024)
		return __va(phys);
Linus Torvalds's avatar
Linus Torvalds committed
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161

	offset = phys & (PAGE_SIZE - 1);
	mapped_size = PAGE_SIZE - offset;
	set_fixmap(FIX_ACPI_END, phys);
	base = fix_to_virt(FIX_ACPI_END);

	/*
	 * Most cases can be covered by the below.
	 */
	idx = FIX_ACPI_END;
	while (mapped_size < size) {
		if (--idx < FIX_ACPI_BEGIN)
			return NULL;	/* cannot handle this */
		phys += PAGE_SIZE;
		set_fixmap(idx, phys);
		mapped_size += PAGE_SIZE;
	}

Len Brown's avatar
Len Brown committed
162
	return ((unsigned char *)base + offset);
Linus Torvalds's avatar
Linus Torvalds committed
163
164
165
166
}
#endif

#ifdef CONFIG_PCI_MMCONFIG
167
/* The physical address of the MMCONFIG aperture.  Set from ACPI tables. */
168
struct acpi_mcfg_allocation *pci_mmcfg_config;
169
170
int pci_mmcfg_config_num;

171
int __init acpi_parse_mcfg(struct acpi_table_header *header)
Linus Torvalds's avatar
Linus Torvalds committed
172
173
{
	struct acpi_table_mcfg *mcfg;
174
175
	unsigned long i;
	int config_size;
Linus Torvalds's avatar
Linus Torvalds committed
176

177
	if (!header)
Linus Torvalds's avatar
Linus Torvalds committed
178
179
		return -EINVAL;

180
	mcfg = (struct acpi_table_mcfg *)header;
Linus Torvalds's avatar
Linus Torvalds committed
181

182
183
	/* how many config structures do we have */
	pci_mmcfg_config_num = 0;
184
	i = header->length - sizeof(struct acpi_table_mcfg);
185
	while (i >= sizeof(struct acpi_mcfg_allocation)) {
186
		++pci_mmcfg_config_num;
187
		i -= sizeof(struct acpi_mcfg_allocation);
188
189
190
	};
	if (pci_mmcfg_config_num == 0) {
		printk(KERN_ERR PREFIX "MMCONFIG has no entries\n");
Linus Torvalds's avatar
Linus Torvalds committed
191
192
193
		return -ENODEV;
	}

194
195
196
197
198
199
200
201
	config_size = pci_mmcfg_config_num * sizeof(*pci_mmcfg_config);
	pci_mmcfg_config = kmalloc(config_size, GFP_KERNEL);
	if (!pci_mmcfg_config) {
		printk(KERN_WARNING PREFIX
		       "No memory for MCFG config tables\n");
		return -ENOMEM;
	}

202
	memcpy(pci_mmcfg_config, &mcfg[1], config_size);
203
	for (i = 0; i < pci_mmcfg_config_num; ++i) {
204
		if (pci_mmcfg_config[i].address > 0xFFFFFFFF) {
205
206
			printk(KERN_ERR PREFIX
			       "MMCONFIG not in low 4GB of memory\n");
207
208
			kfree(pci_mmcfg_config);
			pci_mmcfg_config_num = 0;
209
210
211
			return -ENODEV;
		}
	}
Linus Torvalds's avatar
Linus Torvalds committed
212
213
214

	return 0;
}
Len Brown's avatar
Len Brown committed
215
#endif				/* CONFIG_PCI_MMCONFIG */
Linus Torvalds's avatar
Linus Torvalds committed
216
217

#ifdef CONFIG_X86_LOCAL_APIC
218
static int __init acpi_parse_madt(struct acpi_table_header *table)
Linus Torvalds's avatar
Linus Torvalds committed
219
{
Len Brown's avatar
Len Brown committed
220
	struct acpi_table_madt *madt = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
221

222
	if (!cpu_has_apic)
Linus Torvalds's avatar
Linus Torvalds committed
223
224
		return -EINVAL;

225
	madt = (struct acpi_table_madt *)table;
Linus Torvalds's avatar
Linus Torvalds committed
226
227
228
229
230
	if (!madt) {
		printk(KERN_WARNING PREFIX "Unable to map MADT\n");
		return -ENODEV;
	}

231
232
	if (madt->address) {
		acpi_lapic_addr = (u64) madt->address;
Linus Torvalds's avatar
Linus Torvalds committed
233
234

		printk(KERN_DEBUG PREFIX "Local APIC address 0x%08x\n",
235
		       madt->address);
Linus Torvalds's avatar
Linus Torvalds committed
236
237
238
	}

	acpi_madt_oem_check(madt->header.oem_id, madt->header.oem_table_id);
Len Brown's avatar
Len Brown committed
239

Linus Torvalds's avatar
Linus Torvalds committed
240
241
242
	return 0;
}

243
244
245
246
247
248
249
250
251
252
static void __cpuinit acpi_register_lapic(int id, u8 enabled)
{
	if (!enabled) {
		++disabled_cpus;
		return;
	}

	generic_processor_info(id, 0);
}

Linus Torvalds's avatar
Linus Torvalds committed
253
static int __init
254
acpi_parse_lapic(struct acpi_subtable_header * header, const unsigned long end)
Linus Torvalds's avatar
Linus Torvalds committed
255
{
256
	struct acpi_madt_local_apic *processor = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
257

258
	processor = (struct acpi_madt_local_apic *)header;
Linus Torvalds's avatar
Linus Torvalds committed
259
260
261
262
263
264

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

	acpi_table_print_madt_entry(header);

265
266
267
268
269
270
271
	/*
	 * 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.
	 */
272
273
	acpi_register_lapic(processor->id,	/* APIC ID */
			    processor->lapic_flags & ACPI_MADT_ENABLED);
Linus Torvalds's avatar
Linus Torvalds committed
274
275
276
277

	return 0;
}

278
279
280
281
282
283
284
285
286
287
288
289
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);

290
291
	acpi_register_lapic((processor->id << 8) | processor->eid,/* APIC ID */
			    processor->lapic_flags & ACPI_MADT_ENABLED);
292
293
294
295

	return 0;
}

Linus Torvalds's avatar
Linus Torvalds committed
296
static int __init
297
acpi_parse_lapic_addr_ovr(struct acpi_subtable_header * header,
Len Brown's avatar
Len Brown committed
298
			  const unsigned long end)
Linus Torvalds's avatar
Linus Torvalds committed
299
{
300
	struct acpi_madt_local_apic_override *lapic_addr_ovr = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
301

302
	lapic_addr_ovr = (struct acpi_madt_local_apic_override *)header;
Linus Torvalds's avatar
Linus Torvalds committed
303
304
305
306
307
308
309
310
311
312

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

	acpi_lapic_addr = lapic_addr_ovr->address;

	return 0;
}

static int __init
313
acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long end)
Linus Torvalds's avatar
Linus Torvalds committed
314
{
315
	struct acpi_madt_local_apic_nmi *lapic_nmi = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
316

317
	lapic_nmi = (struct acpi_madt_local_apic_nmi *)header;
Linus Torvalds's avatar
Linus Torvalds committed
318
319
320
321
322
323
324
325
326
327
328
329

	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
330
#endif				/*CONFIG_X86_LOCAL_APIC */
Linus Torvalds's avatar
Linus Torvalds committed
331

332
#ifdef CONFIG_X86_IO_APIC
Linus Torvalds's avatar
Linus Torvalds committed
333

334
335
struct mp_ioapic_routing mp_ioapic_routing[MAX_IO_APICS];

Linus Torvalds's avatar
Linus Torvalds committed
336
static int __init
337
acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end)
Linus Torvalds's avatar
Linus Torvalds committed
338
{
339
	struct acpi_madt_io_apic *ioapic = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
340

341
	ioapic = (struct acpi_madt_io_apic *)header;
Linus Torvalds's avatar
Linus Torvalds committed
342
343
344

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

Linus Torvalds's avatar
Linus Torvalds committed
346
347
	acpi_table_print_madt_entry(header);

Len Brown's avatar
Len Brown committed
348
349
350
	mp_register_ioapic(ioapic->id,
			   ioapic->address, ioapic->global_irq_base);

Linus Torvalds's avatar
Linus Torvalds committed
351
352
353
354
355
356
	return 0;
}

/*
 * Parse Interrupt Source Override for the ACPI SCI
 */
357
static void __init acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger)
Linus Torvalds's avatar
Linus Torvalds committed
358
359
360
361
362
363
364
365
{
	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= */
366
367
	if (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK)
		trigger = (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2;
Linus Torvalds's avatar
Linus Torvalds committed
368

369
370
	if (acpi_sci_flags & ACPI_MADT_POLARITY_MASK)
		polarity = acpi_sci_flags & ACPI_MADT_POLARITY_MASK;
Linus Torvalds's avatar
Linus Torvalds committed
371
372

	/*
Len Brown's avatar
Len Brown committed
373
	 * mp_config_acpi_legacy_irqs() already setup IRQs < 16
Linus Torvalds's avatar
Linus Torvalds committed
374
375
376
	 * If GSI is < 16, this will update its flags,
	 * else it will create a new mp_irqs[] entry.
	 */
377
	mp_override_legacy_irq(gsi, polarity, trigger, gsi);
Linus Torvalds's avatar
Linus Torvalds committed
378
379
380

	/*
	 * stash over-ride to indicate we've been here
381
	 * and for later update of acpi_gbl_FADT
Linus Torvalds's avatar
Linus Torvalds committed
382
	 */
383
	acpi_sci_override_gsi = gsi;
Linus Torvalds's avatar
Linus Torvalds committed
384
385
386
387
	return;
}

static int __init
388
acpi_parse_int_src_ovr(struct acpi_subtable_header * header,
Len Brown's avatar
Len Brown committed
389
		       const unsigned long end)
Linus Torvalds's avatar
Linus Torvalds committed
390
{
391
	struct acpi_madt_interrupt_override *intsrc = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
392

393
	intsrc = (struct acpi_madt_interrupt_override *)header;
Linus Torvalds's avatar
Linus Torvalds committed
394
395
396
397
398
399

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

	acpi_table_print_madt_entry(header);

400
	if (intsrc->source_irq == acpi_gbl_FADT.sci_interrupt) {
401
		acpi_sci_ioapic_setup(intsrc->global_irq,
402
403
				      intsrc->inti_flags & ACPI_MADT_POLARITY_MASK,
				      (intsrc->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2);
Linus Torvalds's avatar
Linus Torvalds committed
404
405
406
407
		return 0;
	}

	if (acpi_skip_timer_override &&
408
	    intsrc->source_irq == 0 && intsrc->global_irq == 2) {
Len Brown's avatar
Len Brown committed
409
410
		printk(PREFIX "BIOS IRQ0 pin2 override ignored.\n");
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
411
412
	}

413
414
415
416
	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
417
418
419
420
421

	return 0;
}

static int __init
422
acpi_parse_nmi_src(struct acpi_subtable_header * header, const unsigned long end)
Linus Torvalds's avatar
Linus Torvalds committed
423
{
424
	struct acpi_madt_nmi_source *nmi_src = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
425

426
	nmi_src = (struct acpi_madt_nmi_source *)header;
Linus Torvalds's avatar
Linus Torvalds committed
427
428
429
430
431
432
433
434
435
436
437

	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
438
#endif				/* CONFIG_X86_IO_APIC */
Linus Torvalds's avatar
Linus Torvalds committed
439
440
441

/*
 * acpi_pic_sci_set_trigger()
442
 *
Linus Torvalds's avatar
Linus Torvalds committed
443
444
445
446
447
448
449
 * 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
450
451
 * 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
452
453
 */

Len Brown's avatar
Len Brown committed
454
void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
Linus Torvalds's avatar
Linus Torvalds committed
455
456
457
458
459
460
461
462
{
	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
463
	 * If we use ACPI to set PCI IRQs, then we should clear ELCR
Linus Torvalds's avatar
Linus Torvalds committed
464
465
466
467
468
469
470
471
472
473
	 * 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
474
	case 1:		/* Edge - clear */
Linus Torvalds's avatar
Linus Torvalds committed
475
476
		new &= ~mask;
		break;
Len Brown's avatar
Len Brown committed
477
	case 3:		/* Level - set */
Linus Torvalds's avatar
Linus Torvalds committed
478
479
480
481
482
483
484
485
486
487
488
489
490
491
		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)
{
492
	*irq = gsi;
Linus Torvalds's avatar
Linus Torvalds committed
493
494
495
	return 0;
}

496
497
498
499
/*
 * success: return IRQ number (>=0)
 * failure: return < 0
 */
500
int acpi_register_gsi(u32 gsi, int triggering, int polarity)
Linus Torvalds's avatar
Linus Torvalds committed
501
502
503
504
505
506
507
508
509
510
511
{
	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) {
		extern void eisa_set_level_irq(unsigned int irq);

512
		if (triggering == ACPI_LEVEL_SENSITIVE)
Len Brown's avatar
Len Brown committed
513
			eisa_set_level_irq(gsi);
Linus Torvalds's avatar
Linus Torvalds committed
514
515
516
517
518
	}
#endif

#ifdef CONFIG_X86_IO_APIC
	if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) {
519
		plat_gsi = mp_register_gsi(gsi, triggering, polarity);
Linus Torvalds's avatar
Linus Torvalds committed
520
521
522
523
524
	}
#endif
	acpi_gsi_to_irq(plat_gsi, &irq);
	return irq;
}
Len Brown's avatar
Len Brown committed
525

Linus Torvalds's avatar
Linus Torvalds committed
526
527
528
529
/*
 *  ACPI based hotplug support for CPU
 */
#ifdef CONFIG_ACPI_HOTPLUG_CPU
530
531

static int __cpuinit _acpi_map_lsapic(acpi_handle handle, int *pcpu)
Linus Torvalds's avatar
Linus Torvalds committed
532
{
533
534
	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
	union acpi_object *obj;
535
	struct acpi_madt_local_apic *lapic;
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
	cpumask_t tmp_map, new_map;
	u8 physid;
	int cpu;

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

553
	lapic = (struct acpi_madt_local_apic *)obj->buffer.pointer;
554

555
556
	if (lapic->header.type != ACPI_MADT_TYPE_LOCAL_APIC ||
	    !(lapic->lapic_flags & ACPI_MADT_ENABLED)) {
557
558
559
560
561
562
563
564
565
566
567
		kfree(buffer.pointer);
		return -EINVAL;
	}

	physid = lapic->id;

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

	tmp_map = cpu_present_map;
568
	acpi_register_lapic(physid, lapic->lapic_flags & ACPI_MADT_ENABLED);
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583

	/*
	 * If mp_register_lapic successfully generates a new logical cpu
	 * number, then the following will get us exactly what was mapped
	 */
	cpus_andnot(new_map, cpu_present_map, tmp_map);
	if (cpus_empty(new_map)) {
		printk ("Unable to map lapic to logical cpu number\n");
		return -EINVAL;
	}

	cpu = first_cpu(new_map);

	*pcpu = cpu;
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
584
585
}

586
587
588
589
590
/* 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
591
EXPORT_SYMBOL(acpi_map_lsapic);
Linus Torvalds's avatar
Linus Torvalds committed
592

Len Brown's avatar
Len Brown committed
593
int acpi_unmap_lsapic(int cpu)
Linus Torvalds's avatar
Linus Torvalds committed
594
{
595
	per_cpu(x86_cpu_to_apicid, cpu) = -1;
596
597
598
599
	cpu_clear(cpu, cpu_present_map);
	num_processors--;

	return (0);
Linus Torvalds's avatar
Linus Torvalds committed
600
}
Len Brown's avatar
Len Brown committed
601

Linus Torvalds's avatar
Linus Torvalds committed
602
EXPORT_SYMBOL(acpi_unmap_lsapic);
Len Brown's avatar
Len Brown committed
603
#endif				/* CONFIG_ACPI_HOTPLUG_CPU */
Linus Torvalds's avatar
Linus Torvalds committed
604

Len Brown's avatar
Len Brown committed
605
int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
606
607
608
609
{
	/* TBD */
	return -EINVAL;
}
Len Brown's avatar
Len Brown committed
610

611
612
EXPORT_SYMBOL(acpi_register_ioapic);

Len Brown's avatar
Len Brown committed
613
int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base)
614
615
616
617
{
	/* TBD */
	return -EINVAL;
}
Len Brown's avatar
Len Brown committed
618

619
620
EXPORT_SYMBOL(acpi_unregister_ioapic);

621
static int __init acpi_parse_sbf(struct acpi_table_header *table)
Linus Torvalds's avatar
Linus Torvalds committed
622
{
623
	struct acpi_table_boot *sb;
Linus Torvalds's avatar
Linus Torvalds committed
624

625
	sb = (struct acpi_table_boot *)table;
Linus Torvalds's avatar
Linus Torvalds committed
626
627
628
629
630
	if (!sb) {
		printk(KERN_WARNING PREFIX "Unable to map SBF\n");
		return -ENODEV;
	}

631
	sbf_port = sb->cmos_index;	/* Save CMOS port */
Linus Torvalds's avatar
Linus Torvalds committed
632
633
634
635
636

	return 0;
}

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

639
640
static struct __initdata resource *hpet_res;

641
static int __init acpi_parse_hpet(struct acpi_table_header *table)
Linus Torvalds's avatar
Linus Torvalds committed
642
643
644
{
	struct acpi_table_hpet *hpet_tbl;

645
	hpet_tbl = (struct acpi_table_hpet *)table;
Linus Torvalds's avatar
Linus Torvalds committed
646
647
648
649
650
	if (!hpet_tbl) {
		printk(KERN_WARNING PREFIX "Unable to map HPET\n");
		return -ENODEV;
	}

651
	if (hpet_tbl->address.space_id != ACPI_SPACE_MEM) {
Linus Torvalds's avatar
Linus Torvalds committed
652
653
654
655
		printk(KERN_WARNING PREFIX "HPET timers must be located in "
		       "memory.\n");
		return -1;
	}
656

657
	hpet_address = hpet_tbl->address.address;
Thomas Gleixner's avatar
Thomas Gleixner committed
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689

	/*
	 * 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
690
	printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
691
	       hpet_tbl->id, hpet_address);
Linus Torvalds's avatar
Linus Torvalds committed
692

693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
	/*
	 * 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
708
709
	return 0;
}
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724

/*
 * 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
725
726
727
728
#else
#define	acpi_parse_hpet	NULL
#endif

729
static int __init acpi_parse_fadt(struct acpi_table_header *table)
Linus Torvalds's avatar
Linus Torvalds committed
730
{
Jason Davis's avatar
Jason Davis committed
731

Linus Torvalds's avatar
Linus Torvalds committed
732
733
#ifdef CONFIG_X86_PM_TIMER
	/* detect the location of the ACPI PM Timer */
734
	if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) {
Linus Torvalds's avatar
Linus Torvalds committed
735
		/* FADT rev. 2 */
736
		if (acpi_gbl_FADT.xpm_timer_block.space_id !=
Len Brown's avatar
Len Brown committed
737
		    ACPI_ADR_SPACE_SYSTEM_IO)
Linus Torvalds's avatar
Linus Torvalds committed
738
739
			return 0;

740
		pmtmr_ioport = acpi_gbl_FADT.xpm_timer_block.address;
741
742
743
744
745
746
		/*
		 * "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)
747
			pmtmr_ioport = acpi_gbl_FADT.pm_timer_block;
Linus Torvalds's avatar
Linus Torvalds committed
748
749
	} else {
		/* FADT rev. 1 */
750
		pmtmr_ioport = acpi_gbl_FADT.pm_timer_block;
Linus Torvalds's avatar
Linus Torvalds committed
751
752
	}
	if (pmtmr_ioport)
Len Brown's avatar
Len Brown committed
753
754
		printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n",
		       pmtmr_ioport);
Linus Torvalds's avatar
Linus Torvalds committed
755
756
757
758
759
760
761
762
763
#endif
	return 0;
}

#ifdef	CONFIG_X86_LOCAL_APIC
/*
 * Parse LAPIC entries in MADT
 * returns 0 on success, < 0 on error
 */
764
765
766
767
768
769
770
771
772
773

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

	set_fixmap_nocache(FIX_APIC_BASE, address);
	if (boot_cpu_physical_apicid == -1U)
		boot_cpu_physical_apicid  = GET_APIC_ID(read_apic_id());
}

Len Brown's avatar
Len Brown committed
774
static int __init acpi_parse_madt_lapic_entries(void)
Linus Torvalds's avatar
Linus Torvalds committed
775
776
777
{
	int count;

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

781
	/*
Linus Torvalds's avatar
Linus Torvalds committed
782
783
784
785
	 * 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
786
	count =
787
	    acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE,
Len Brown's avatar
Len Brown committed
788
				  acpi_parse_lapic_addr_ovr, 0);
Linus Torvalds's avatar
Linus Torvalds committed
789
	if (count < 0) {
Len Brown's avatar
Len Brown committed
790
791
		printk(KERN_ERR PREFIX
		       "Error parsing LAPIC address override entry\n");
Linus Torvalds's avatar
Linus Torvalds committed
792
793
794
		return count;
	}

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

797
798
799
800
801
802
	count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_SAPIC,
				      acpi_parse_sapic, MAX_APICS);

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

Len Brown's avatar
Len Brown committed
813
	count =
814
	    acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_NMI, acpi_parse_lapic_nmi, 0);
Linus Torvalds's avatar
Linus Torvalds committed
815
816
817
818
819
820
821
	if (count < 0) {
		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
822
#endif				/* CONFIG_X86_LOCAL_APIC */
Linus Torvalds's avatar
Linus Torvalds committed
823

824
#ifdef	CONFIG_X86_IO_APIC
Linus Torvalds's avatar
Linus Torvalds committed
825
826
827
828
/*
 * Parse IOAPIC related entries in MADT
 * returns 0 on success, < 0 on error
 */
Len Brown's avatar
Len Brown committed
829
static int __init acpi_parse_madt_ioapic_entries(void)
Linus Torvalds's avatar
Linus Torvalds committed
830
831
832
833
834
835
836
837
838
839
840
{
	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
	 */
	if (acpi_disabled || acpi_noirq) {
		return -ENODEV;
Len Brown's avatar
Len Brown committed
841
	}
Linus Torvalds's avatar
Linus Torvalds committed
842

843
	if (!cpu_has_apic)
844
845
		return -ENODEV;

Linus Torvalds's avatar
Linus Torvalds committed
846
	/*
Len Brown's avatar
Len Brown committed
847
	 * if "noapic" boot option, don't look for IO-APICs
Linus Torvalds's avatar
Linus Torvalds committed
848
849
850
	 */
	if (skip_ioapic_setup) {
		printk(KERN_INFO PREFIX "Skipping IOAPIC probe "
Len Brown's avatar
Len Brown committed
851
		       "due to 'noapic' option.\n");
Linus Torvalds's avatar
Linus Torvalds committed
852
853
854
		return -ENODEV;
	}

Len Brown's avatar
Len Brown committed
855
	count =
856
	    acpi_table_parse_madt(ACPI_MADT_TYPE_IO_APIC, acpi_parse_ioapic,
Len Brown's avatar
Len Brown committed
857
				  MAX_IO_APICS);
Linus Torvalds's avatar
Linus Torvalds committed
858
859
860
	if (!count) {
		printk(KERN_ERR PREFIX "No IOAPIC entries present\n");
		return -ENODEV;
Len Brown's avatar
Len Brown committed
861
	} else if (count < 0) {
Linus Torvalds's avatar
Linus Torvalds committed
862
863
864
865
		printk(KERN_ERR PREFIX "Error parsing IOAPIC entry\n");
		return count;
	}

Len Brown's avatar
Len Brown committed
866
	count =
867
	    acpi_table_parse_madt(ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, acpi_parse_int_src_ovr,
Len Brown's avatar
Len Brown committed
868
				  NR_IRQ_VECTORS);
Linus Torvalds's avatar
Linus Torvalds committed
869
	if (count < 0) {
Len Brown's avatar
Len Brown committed
870
871
		printk(KERN_ERR PREFIX
		       "Error parsing interrupt source overrides entry\n");
Linus Torvalds's avatar
Linus Torvalds committed
872
873
874
875
876
877
878
879
880
		/* TBD: Cleanup to allow fallback to MPS */
		return count;
	}

	/*
	 * If BIOS did not supply an INT_SRC_OVR for the SCI
	 * pretend we got one so we can set the SCI flags.
	 */
	if (!acpi_sci_override_gsi)
881
		acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0);
Linus Torvalds's avatar
Linus Torvalds committed
882
883
884
885

	/* Fill in identity legacy mapings where no override */
	mp_config_acpi_legacy_irqs();

Len Brown's avatar
Len Brown committed
886
	count =
887
	    acpi_table_parse_madt(ACPI_MADT_TYPE_NMI_SOURCE, acpi_parse_nmi_src,
Len Brown's avatar
Len Brown committed
888
				  NR_IRQ_VECTORS);
Linus Torvalds's avatar
Linus Torvalds committed
889
890
891
892
893
894
895
896
897
898
899
900
901
	if (count < 0) {
		printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
		/* TBD: Cleanup to allow fallback to MPS */
		return count;
	}

	return 0;
}
#else
static inline int acpi_parse_madt_ioapic_entries(void)
{
	return -1;
}
902
#endif	/* !CONFIG_X86_IO_APIC */
Linus Torvalds's avatar
Linus Torvalds committed
903

Len Brown's avatar
Len Brown committed
904
static void __init acpi_process_madt(void)
Linus Torvalds's avatar
Linus Torvalds committed
905
906
{
#ifdef CONFIG_X86_LOCAL_APIC
907
	int error;
Linus Torvalds's avatar
Linus Torvalds committed
908

909
	if (!acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt)) {
Linus Torvalds's avatar
Linus Torvalds committed
910
911
912
913
914
915
916
917

		/*
		 * Parse MADT LAPIC entries
		 */
		error = acpi_parse_madt_lapic_entries();
		if (!error) {
			acpi_lapic = 1;

918
919
920
#ifdef CONFIG_X86_GENERICARCH
			generic_bigsmp_probe();
#endif
Linus Torvalds's avatar
Linus Torvalds committed
921
922
923
924
925
926
927
928
929
930
			/*
			 * Parse MADT IO-APIC entries
			 */
			error = acpi_parse_madt_ioapic_entries();
			if (!error) {
				acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
				acpi_irq_balance_set(NULL);
				acpi_ioapic = 1;

				smp_found_config = 1;
931
				setup_apic_routing();
Linus Torvalds's avatar
Linus Torvalds committed
932
933
934
935
936
937
			}
		}
		if (error == -EINVAL) {
			/*
			 * Dell Precision Workstation 410, 610 come here.
			 */
Len Brown's avatar
Len Brown committed
938
939
			printk(KERN_ERR PREFIX
			       "Invalid BIOS MADT, disabling ACPI\n");
Linus Torvalds's avatar
Linus Torvalds committed
940
941
942
943
944
945
946
			disable_acpi();
		}
	}
#endif
	return;
}

947
948
#ifdef __i386__

949
static int __init disable_acpi_irq(const struct dmi_system_id *d)
950
951
952
953
954
955
956
957
958
{
	if (!acpi_force) {
		printk(KERN_NOTICE "%s detected: force use of acpi=noirq\n",
		       d->ident);
		acpi_noirq_set();
	}
	return 0;
}

959
static int __init disable_acpi_pci(const struct dmi_system_id *d)
960
961
962
963
964
965
966
967
968
{
	if (!acpi_force) {
		printk(KERN_NOTICE "%s detected: force use of pci=noacpi\n",
		       d->ident);
		acpi_disable_pci();
	}
	return 0;
}

969
static int __init dmi_disable_acpi(const struct dmi_system_id *d)
970
971
{
	if (!acpi_force) {
Len Brown's avatar
Len Brown committed
972
		printk(KERN_NOTICE "%s detected: acpi off\n", d->ident);
973
974
975
976
977
978
979
980
981
982
983
		disable_acpi();
	} else {
		printk(KERN_NOTICE
		       "Warning: DMI blacklist says broken, but acpi forced\n");
	}
	return 0;
}

/*
 * Limit ACPI to CPU enumeration for HT
 */
984
static int __init force_acpi_ht(const struct dmi_system_id *d)
985
986
{
	if (!acpi_force) {
Len Brown's avatar
Len Brown committed
987
988
		printk(KERN_NOTICE "%s detected: force use of acpi=ht\n",
		       d->ident);
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
		disable_acpi();
		acpi_ht = 1;
	} else {
		printk(KERN_NOTICE
		       "Warning: acpi=force overrules DMI blacklist: acpi=ht\n");
	}
	return 0;
}

/*
 * If your system is blacklisted here, but you find that acpi=force
 * works for you, please contact acpi-devel@sourceforge.net
 */
static struct dmi_system_id __initdata acpi_dmi_table[] = {
	/*
	 * Boxes that need ACPI disabled
	 */
	{
Len Brown's avatar
Len Brown committed
1007
1008
1009
1010
1011
1012
1013
	 .callback = dmi_disable_acpi,
	 .ident = "IBM Thinkpad",
	 .matches = {
		     DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
		     DMI_MATCH(DMI_BOARD_NAME, "2629H1G"),
		     },
	 },
1014
1015
1016
1017
1018

	/*
	 * Boxes that need acpi=ht
	 */
	{
Len Brown's avatar
Len Brown committed
1019
1020
1021
1022
1023
1024
1025
	 .callback = force_acpi_ht,
	 .ident = "FSC Primergy T850",
	 .matches = {
		     DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
		     DMI_MATCH(DMI_PRODUCT_NAME, "PRIMERGY T850"),
		     },
	 },
1026
	{
Len Brown's avatar
Len Brown committed
1027
1028
1029
1030
1031
1032
1033
	 .callback = force_acpi_ht,
	 .ident = "HP VISUALIZE NT Workstation",
	 .matches = {
		     DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
		     DMI_MATCH(DMI_PRODUCT_NAME, "HP VISUALIZE NT Workstation"),
		     },
	 },
1034
	{
Len Brown's avatar
Len Brown committed
1035
1036
1037
1038
1039
1040
1041
	 .callback = force_acpi_ht,
	 .ident = "Compaq Workstation W8000",
	 .matches = {
		     DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
		     DMI_MATCH(DMI_PRODUCT_NAME, "Workstation W8000"),
		     },
	 },
1042
	{
Len Brown's avatar
Len Brown committed
1043
1044
1045
1046
1047
1048
1049
	 .callback = force_acpi_ht,
	 .ident = "ASUS P4B266",
	 .matches = {
		     DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
		     DMI_MATCH(DMI_BOARD_NAME, "P4B266"),
		     },
	 },
1050
	{
Len Brown's avatar
Len Brown committed
1051
1052
1053
1054
1055
1056
1057
	 .callback = force_acpi_ht,
	 .ident = "ASUS P2B-DS",
	 .matches = {
		     DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
		     DMI_MATCH(DMI_BOARD_NAME, "P2B-DS"),
		     },
	 },
1058
	{
Len Brown's avatar
Len Brown committed
1059
1060
1061
1062
1063
1064
1065
	 .callback = force_acpi_ht,
	 .ident = "ASUS CUR-DLS",
	 .matches = {
		     DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
		     DMI_MATCH(DMI_BOARD_NAME, "CUR-DLS"),
		     },
	 },
1066
	{
Len Brown's avatar
Len Brown committed
1067
1068
1069
1070
1071
1072
1073
	 .callback = force_acpi_ht,
	 .ident = "ABIT i440BX-W83977",
	 .matches = {
		     DMI_MATCH(DMI_BOARD_VENDOR, "ABIT <http://www.abit.com>"),
		     DMI_MATCH(DMI_BOARD_NAME, "i440BX-W83977 (BP6)"),
		     },
	 },
1074
	{
Len Brown's avatar
Len Brown committed
1075
1076
1077
1078
1079
1080
1081
	 .callback = force_acpi_ht,
	 .ident = "IBM Bladecenter",
	 .matches = {
		     DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
		     DMI_MATCH(DMI_BOARD_NAME, "IBM eServer BladeCenter HS20"),
		     },
	 },
1082
	{
Len Brown's avatar
Len Brown committed
1083
1084
1085
1086
1087
1088
1089
	 .callback = force_acpi_ht,
	 .ident = "IBM eServer xSeries 360",
	 .matches = {
		     DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
		     DMI_MATCH(DMI_BOARD_NAME, "eServer xSeries 360"),
		     },
	 },
1090
	{
Len Brown's avatar
Len Brown committed
1091
1092
1093
1094
1095
1096
1097
	 .callback = force_acpi_ht,
	 .ident = "IBM eserver xSeries 330",
	 .matches = {
		     DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
		     DMI_MATCH(DMI_BOARD_NAME, "eserver xSeries 330"),
		     },
	 },
1098
	{
Len Brown's avatar
Len Brown committed
1099
1100
1101
1102
1103
1104
1105
	 .callback = force_acpi_ht,
	 .ident = "IBM eserver xSeries 440",
	 .matches = {
		     DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
		     DMI_MATCH(DMI_PRODUCT_NAME, "eserver xSeries 440"),
		     },
	 },
1106
1107
1108
1109
1110

	/*
	 * Boxes that need ACPI PCI IRQ routing disabled
	 */
	{
Len Brown's avatar
Len Brown committed
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
	 .callback = disable_acpi_irq,
	 .ident = "ASUS A7V",
	 .matches = {
		     DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC"),
		     DMI_MATCH(DMI_BOARD_NAME, "<A7V>"),
		     /* newer BIOS, Revision 1011, does work */
		     DMI_MATCH(DMI_BIOS_VERSION,
			       "ASUS A7V ACPI BIOS Revision 1007"),
		     },
	 },
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
	{
		/*
		 * Latest BIOS for IBM 600E (1.16) has bad pcinum
		 * for LPC bridge, which is needed for the PCI
		 * interrupt links to work. DSDT fix is in bug 5966.
		 * 2645, 2646 model numbers are shared with 600/600E/600X
		 */
	 .callback = disable_acpi_irq,
	 .ident = "IBM Thinkpad 600 Series 2645",
	 .matches = {
		     DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
		     DMI_MATCH(DMI_BOARD_NAME, "2645"),
		     },
	 },
	{
	 .callback = disable_acpi_irq,
	 .ident = "IBM Thinkpad 600 Series 2646",
	 .matches = {
		     DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
		     DMI_MATCH(DMI_BOARD_NAME, "2646"),
		     },
	 },
1143
1144
1145
	/*
	 * Boxes that need ACPI PCI IRQ routing and PCI scan disabled
	 */
Len Brown's avatar
Len Brown committed
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
	{			/* _BBN 0 bug */
	 .callback = disable_acpi_pci,
	 .ident = "ASUS PR-DLS",
	 .matches = {
		     DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
		     DMI_MATCH(DMI_BOARD_NAME, "PR-DLS"),
		     DMI_MATCH(DMI_BIOS_VERSION,
			       "ASUS PR-DLS ACPI BIOS Revision 1010"),
		     DMI_MATCH(DMI_BIOS_DATE, "03/21/2003")
		     },
	 },
1157
	{
Len Brown's avatar
Len Brown committed
1158
1159
1160
1161
1162
1163
1164
1165
	 .callback = disable_acpi_pci,
	 .ident = "Acer TravelMate 36x Laptop",
	 .matches = {
		     DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
		     DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
		     },
	 },
	{}
1166
1167
};

Len Brown's avatar
Len Brown committed
1168
#endif				/* __i386__ */
1169

Linus Torvalds's avatar
Linus Torvalds committed
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
/*
 * acpi_boot_table_init() and acpi_boot_init()
 *  called from setup_arch(), always.
 *	1. checksums all tables
 *	2. enumerates lapics
 *	3. enumerates io-apics
 *
 * acpi_table_init() is separate to allow reading SRAT without
 * other side effects.
 *
 * side effects of acpi_boot_init:
 *	acpi_lapic = 1 if LAPIC found
 *	acpi_ioapic = 1 if IOAPIC found
 *	if (acpi_lapic && acpi_ioapic) smp_found_config = 1;
 *	if acpi_blacklisted() acpi_disabled = 1;
 *	acpi_irq_model=...
 *	...
 *
 * return value: (currently ignored)
 *	0: success
 *	!0: failure
 */

Len Brown's avatar
Len Brown committed
1193
int __init acpi_boot_table_init(void)
Linus Torvalds's avatar
Linus Torvalds committed
1194
1195
1196
{
	int error;

1197
1198
1199
1200
#ifdef __i386__
	dmi_check_system(acpi_dmi_table);
#endif

Linus Torvalds's avatar
Linus Torvalds committed
1201
1202
1203
1204
1205
	/*
	 * If acpi_disabled, bail out
	 * One exception: acpi=ht continues far enough to enumerate LAPICs
	 */
	if (acpi_disabled && !acpi_ht)
Len Brown's avatar
Len Brown committed
1206
		return 1;
Linus Torvalds's avatar
Linus Torvalds committed
1207

1208
	/*
Linus Torvalds's avatar
Linus Torvalds committed
1209
1210
1211
1212
1213
1214
1215
1216
	 * Initialize the ACPI boot-time table parser.
	 */
	error = acpi_table_init();
	if (error) {
		disable_acpi();
		return error;
	}

1217
	acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
Linus Torvalds's avatar
Linus Torvalds committed
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242

	/*
	 * blacklist may disable ACPI entirely
	 */
	error = acpi_blacklisted();
	if (error) {
		if (acpi_force) {
			printk(KERN_WARNING PREFIX "acpi=force override\n");
		} else {
			printk(KERN_WARNING PREFIX "Disabling ACPI support\n");
			disable_acpi();
			return error;
		}
	}

	return 0;
}

int __init acpi_boot_init(void)
{
	/*
	 * If acpi_disabled, bail out
	 * One exception: acpi=ht continues far enough to enumerate LAPICs
	 */
	if (acpi_disabled && !acpi_ht)
Len Brown's avatar
Len Brown committed
1243
		return 1;
Linus Torvalds's avatar
Linus Torvalds committed
1244

1245
	acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
Linus Torvalds's avatar
Linus Torvalds committed
1246
1247
1248
1249

	/*
	 * set sci_int and PM timer address
	 */
1250
	acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt);
Linus Torvalds's avatar
Linus Torvalds committed
1251
1252
1253
1254
1255
1256

	/*
	 * Process the Multiple APIC Description Table (MADT), if present
	 */
	acpi_process_madt();

1257
	acpi_table_parse(ACPI_SIG_HPET, acpi_parse_hpet);
Linus Torvalds's avatar
Linus Torvalds committed
1258
1259
1260

	return 0;
}
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313

static int __init parse_acpi(char *arg)
{
	if (!arg)
		return -EINVAL;

	/* "acpi=off" disables both ACPI table parsing and interpreter */
	if (strcmp(arg, "off") == 0) {
		disable_acpi();
	}
	/* acpi=force to over-ride black-list */
	else if (strcmp(arg, "force") == 0) {
		acpi_force = 1;
		acpi_ht = 1;
		acpi_disabled = 0;
	}
	/* acpi=strict disables out-of-spec workarounds */
	else if (strcmp(arg, "strict") == 0) {
		acpi_strict = 1;
	}
	/* Limit ACPI just to boot-time to enable HT */
	else if (strcmp(arg, "ht") == 0) {
		if (!acpi_force)
			disable_acpi();
		acpi_ht = 1;
	}
	/* "acpi=noirq" disables ACPI interrupt routing */
	else if (strcmp(arg, "noirq") == 0) {
		acpi_noirq_set();
	} else {
		/* Core will printk when we return error. */
		return -EINVAL;
	}
	return 0;
}
early_param("acpi", parse_acpi);

/* FIXME: Using pci= for an ACPI parameter is a travesty. */
static int __init parse_pci(char *arg)
{
	if (arg && strcmp(arg, "noacpi") == 0)
		acpi_disable_pci();
	return 0;
}
early_param("pci", parse_pci);

#ifdef CONFIG_X86_IO_APIC
static int __init parse_acpi_skip_timer_override(char *arg)
{
	acpi_skip_timer_override = 1;
	return 0;
}
early_param("acpi_skip_timer_override", parse_acpi_skip_timer_override);
1314
1315
1316
1317
1318
1319
1320

static int __init parse_acpi_use_timer_override(char *arg)
{
	acpi_use_timer_override = 1;
	return 0;
}
early_param("acpi_use_timer_override", parse_acpi_use_timer_override);
1321
1322
1323
1324
1325
1326
1327
#endif /* CONFIG_X86_IO_APIC */

static int __init setup_acpi_sci(char *s)
{
	if (!s)
		return -EINVAL;
	if (!strcmp(s, "edge"))
1328
1329
		acpi_sci_flags =  ACPI_MADT_TRIGGER_EDGE |
			(acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK);
1330
	else if (!strcmp(s, "level"))
1331
1332
		acpi_sci_flags = ACPI_MADT_TRIGGER_LEVEL |
			(acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK);
1333
	else if (!strcmp(s, "high"))
1334
1335
		acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_HIGH |
			(acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK);
1336
	else if (!strcmp(s, "low"))
1337
1338
		acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_LOW |
			(acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK);
1339
1340
1341
1342
1343
	else
		return -EINVAL;
	return 0;
}
early_param("acpi_sci", setup_acpi_sci);
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365

int __acpi_acquire_global_lock(unsigned int *lock)
{
	unsigned int old, new, val;
	do {
		old = *lock;
		new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1));
		val = cmpxchg(lock, old, new);
	} while (unlikely (val != old));
	return (new < 3) ? -1 : 0;
}

int __acpi_release_global_lock(unsigned int *lock)
{
	unsigned int old, new, val;
	do {
		old = *lock;
		new = old & ~0x3;
		val = cmpxchg(lock, old, new);
	} while (unlikely (val != old));
	return old & 0x1;
}