boot.c 31 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
42

#include <asm/pgtable.h>
#include <asm/io_apic.h>
#include <asm/apic.h>
#include <asm/io.h>
#include <asm/mpspec.h>

43
static int __initdata acpi_force = 0;
44

45
46
47
48
49
50
51
#ifdef	CONFIG_ACPI
int acpi_disabled = 0;
#else
int acpi_disabled = 1;
#endif
EXPORT_SYMBOL(acpi_disabled);

Linus Torvalds's avatar
Linus Torvalds committed
52
53
54
55
#ifdef	CONFIG_X86_64

#include <asm/proto.h>

56
57
58
static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id) { return 0; }


Len Brown's avatar
Len Brown committed
59
#else				/* X86 */
Linus Torvalds's avatar
Linus Torvalds committed
60
61
62
63

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

Len Brown's avatar
Len Brown committed
66
#endif				/* X86 */
Linus Torvalds's avatar
Linus Torvalds committed
67
68
69

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

#define PREFIX			"ACPI: "

Andrew Morton's avatar
Andrew Morton committed
74
int acpi_noirq;				/* skip ACPI IRQ initialization */
Len Brown's avatar
Len Brown committed
75
int acpi_pci_disabled __initdata;	/* skip ACPI PCI scan and IRQ initialization */
Linus Torvalds's avatar
Linus Torvalds committed
76
77
78
79
80
81
82
int acpi_ht __initdata = 1;	/* enable HT */

int acpi_lapic;
int acpi_ioapic;
int acpi_strict;
EXPORT_SYMBOL(acpi_strict);

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

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

#ifdef	CONFIG_X86_64

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

114
	if (phys_addr+size <= (end_pfn_map << PAGE_SHIFT) + PAGE_SIZE)
Linus Torvalds's avatar
Linus Torvalds committed
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
		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.
 */
char *__acpi_map_table(unsigned long phys, unsigned long size)
{
	unsigned long base, offset, mapped_size;
	int idx;

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

	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
159
	return ((unsigned char *)base + offset);
Linus Torvalds's avatar
Linus Torvalds committed
160
161
162
163
}
#endif

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

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

174
	if (!header)
Linus Torvalds's avatar
Linus Torvalds committed
175
176
		return -EINVAL;

177
	mcfg = (struct acpi_table_mcfg *)header;
Linus Torvalds's avatar
Linus Torvalds committed
178

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

191
192
193
194
195
196
197
198
	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;
	}

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

	return 0;
}
Len Brown's avatar
Len Brown committed
212
#endif				/* CONFIG_PCI_MMCONFIG */
Linus Torvalds's avatar
Linus Torvalds committed
213
214

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

219
	if (!cpu_has_apic)
Linus Torvalds's avatar
Linus Torvalds committed
220
221
		return -EINVAL;

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

228
229
	if (madt->address) {
		acpi_lapic_addr = (u64) madt->address;
Linus Torvalds's avatar
Linus Torvalds committed
230
231

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

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

Linus Torvalds's avatar
Linus Torvalds committed
237
238
239
240
	return 0;
}

static int __init
241
acpi_parse_lapic(struct acpi_subtable_header * header, const unsigned long end)
Linus Torvalds's avatar
Linus Torvalds committed
242
{
243
	struct acpi_madt_local_apic *processor = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
244

245
	processor = (struct acpi_madt_local_apic *)header;
Linus Torvalds's avatar
Linus Torvalds committed
246
247
248
249
250
251

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

	acpi_table_print_madt_entry(header);

252
253
254
255
256
257
258
	/*
	 * 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.
	 */
Len Brown's avatar
Len Brown committed
259
	mp_register_lapic(processor->id,	/* APIC ID */
260
			  processor->lapic_flags & ACPI_MADT_ENABLED);	/* Enabled? */
Linus Torvalds's avatar
Linus Torvalds committed
261
262
263
264
265

	return 0;
}

static int __init
266
acpi_parse_lapic_addr_ovr(struct acpi_subtable_header * header,
Len Brown's avatar
Len Brown committed
267
			  const unsigned long end)
Linus Torvalds's avatar
Linus Torvalds committed
268
{
269
	struct acpi_madt_local_apic_override *lapic_addr_ovr = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
270

271
	lapic_addr_ovr = (struct acpi_madt_local_apic_override *)header;
Linus Torvalds's avatar
Linus Torvalds committed
272
273
274
275
276
277
278
279
280
281

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

	acpi_lapic_addr = lapic_addr_ovr->address;

	return 0;
}

static int __init
282
acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long end)
Linus Torvalds's avatar
Linus Torvalds committed
283
{
284
	struct acpi_madt_local_apic_nmi *lapic_nmi = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
285

286
	lapic_nmi = (struct acpi_madt_local_apic_nmi *)header;
Linus Torvalds's avatar
Linus Torvalds committed
287
288
289
290
291
292
293
294
295
296
297
298

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

301
#ifdef CONFIG_X86_IO_APIC
Linus Torvalds's avatar
Linus Torvalds committed
302
303

static int __init
304
acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end)
Linus Torvalds's avatar
Linus Torvalds committed
305
{
306
	struct acpi_madt_io_apic *ioapic = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
307

308
	ioapic = (struct acpi_madt_io_apic *)header;
Linus Torvalds's avatar
Linus Torvalds committed
309
310
311

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

Linus Torvalds's avatar
Linus Torvalds committed
313
314
	acpi_table_print_madt_entry(header);

Len Brown's avatar
Len Brown committed
315
316
317
	mp_register_ioapic(ioapic->id,
			   ioapic->address, ioapic->global_irq_base);

Linus Torvalds's avatar
Linus Torvalds committed
318
319
320
321
322
323
	return 0;
}

/*
 * Parse Interrupt Source Override for the ACPI SCI
 */
324
static void __init acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger)
Linus Torvalds's avatar
Linus Torvalds committed
325
326
327
328
329
330
331
332
{
	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= */
333
334
	if (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK)
		trigger = (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2;
Linus Torvalds's avatar
Linus Torvalds committed
335

336
337
	if (acpi_sci_flags & ACPI_MADT_POLARITY_MASK)
		polarity = acpi_sci_flags & ACPI_MADT_POLARITY_MASK;
Linus Torvalds's avatar
Linus Torvalds committed
338
339

	/*
Len Brown's avatar
Len Brown committed
340
	 * mp_config_acpi_legacy_irqs() already setup IRQs < 16
Linus Torvalds's avatar
Linus Torvalds committed
341
342
343
	 * If GSI is < 16, this will update its flags,
	 * else it will create a new mp_irqs[] entry.
	 */
344
	mp_override_legacy_irq(gsi, polarity, trigger, gsi);
Linus Torvalds's avatar
Linus Torvalds committed
345
346
347

	/*
	 * stash over-ride to indicate we've been here
348
	 * and for later update of acpi_gbl_FADT
Linus Torvalds's avatar
Linus Torvalds committed
349
	 */
350
	acpi_sci_override_gsi = gsi;
Linus Torvalds's avatar
Linus Torvalds committed
351
352
353
354
	return;
}

static int __init
355
acpi_parse_int_src_ovr(struct acpi_subtable_header * header,
Len Brown's avatar
Len Brown committed
356
		       const unsigned long end)
Linus Torvalds's avatar
Linus Torvalds committed
357
{
358
	struct acpi_madt_interrupt_override *intsrc = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
359

360
	intsrc = (struct acpi_madt_interrupt_override *)header;
Linus Torvalds's avatar
Linus Torvalds committed
361
362
363
364
365
366

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

	acpi_table_print_madt_entry(header);

367
	if (intsrc->source_irq == acpi_gbl_FADT.sci_interrupt) {
368
		acpi_sci_ioapic_setup(intsrc->global_irq,
369
370
				      intsrc->inti_flags & ACPI_MADT_POLARITY_MASK,
				      (intsrc->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2);
Linus Torvalds's avatar
Linus Torvalds committed
371
372
373
374
		return 0;
	}

	if (acpi_skip_timer_override &&
375
	    intsrc->source_irq == 0 && intsrc->global_irq == 2) {
Len Brown's avatar
Len Brown committed
376
377
		printk(PREFIX "BIOS IRQ0 pin2 override ignored.\n");
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
378
379
	}

380
381
382
383
	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
384
385
386
387
388

	return 0;
}

static int __init
389
acpi_parse_nmi_src(struct acpi_subtable_header * header, const unsigned long end)
Linus Torvalds's avatar
Linus Torvalds committed
390
{
391
	struct acpi_madt_nmi_source *nmi_src = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
392

393
	nmi_src = (struct acpi_madt_nmi_source *)header;
Linus Torvalds's avatar
Linus Torvalds committed
394
395
396
397
398
399
400
401
402
403
404

	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
405
#endif				/* CONFIG_X86_IO_APIC */
Linus Torvalds's avatar
Linus Torvalds committed
406
407
408

/*
 * acpi_pic_sci_set_trigger()
409
 *
Linus Torvalds's avatar
Linus Torvalds committed
410
411
412
413
414
415
416
417
418
419
420
 * 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.
 * ECLR1 is IRQ's 0-7 (IRQ 0, 1, 2 must be 0)
 * ECLR2 is IRQ's 8-15 (IRQ 8, 13 must be 0)
 */

Len Brown's avatar
Len Brown committed
421
void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
Linus Torvalds's avatar
Linus Torvalds committed
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
{
	unsigned int mask = 1 << irq;
	unsigned int old, new;

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

	/*
	 * If we use ACPI to set PCI irq's, then we should clear ELCR
	 * 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
441
	case 1:		/* Edge - clear */
Linus Torvalds's avatar
Linus Torvalds committed
442
443
		new &= ~mask;
		break;
Len Brown's avatar
Len Brown committed
444
	case 3:		/* Level - set */
Linus Torvalds's avatar
Linus Torvalds committed
445
446
447
448
449
450
451
452
453
454
455
456
457
458
		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)
{
459
	*irq = gsi;
Linus Torvalds's avatar
Linus Torvalds committed
460
461
462
	return 0;
}

463
464
465
466
/*
 * success: return IRQ number (>=0)
 * failure: return < 0
 */
467
int acpi_register_gsi(u32 gsi, int triggering, int polarity)
Linus Torvalds's avatar
Linus Torvalds committed
468
469
470
471
472
473
474
475
476
477
478
{
	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);

479
		if (triggering == ACPI_LEVEL_SENSITIVE)
Len Brown's avatar
Len Brown committed
480
			eisa_set_level_irq(gsi);
Linus Torvalds's avatar
Linus Torvalds committed
481
482
483
484
485
	}
#endif

#ifdef CONFIG_X86_IO_APIC
	if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) {
486
		plat_gsi = mp_register_gsi(gsi, triggering, polarity);
Linus Torvalds's avatar
Linus Torvalds committed
487
488
489
490
491
	}
#endif
	acpi_gsi_to_irq(plat_gsi, &irq);
	return irq;
}
Len Brown's avatar
Len Brown committed
492

Linus Torvalds's avatar
Linus Torvalds committed
493
494
495
496
497
498
EXPORT_SYMBOL(acpi_register_gsi);

/*
 *  ACPI based hotplug support for CPU
 */
#ifdef CONFIG_ACPI_HOTPLUG_CPU
Len Brown's avatar
Len Brown committed
499
int acpi_map_lsapic(acpi_handle handle, int *pcpu)
Linus Torvalds's avatar
Linus Torvalds committed
500
{
501
502
	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
	union acpi_object *obj;
503
	struct acpi_madt_local_apic *lapic;
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
	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;
	}

521
	lapic = (struct acpi_madt_local_apic *)obj->buffer.pointer;
522

523
524
	if (lapic->header.type != ACPI_MADT_TYPE_LOCAL_APIC ||
	    !(lapic->lapic_flags & ACPI_MADT_ENABLED)) {
525
526
527
528
529
530
531
532
533
534
535
		kfree(buffer.pointer);
		return -EINVAL;
	}

	physid = lapic->id;

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

	tmp_map = cpu_present_map;
536
	mp_register_lapic(physid, lapic->lapic_flags & ACPI_MADT_ENABLED);
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551

	/*
	 * 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
552
553
}

Len Brown's avatar
Len Brown committed
554
EXPORT_SYMBOL(acpi_map_lsapic);
Linus Torvalds's avatar
Linus Torvalds committed
555

Len Brown's avatar
Len Brown committed
556
int acpi_unmap_lsapic(int cpu)
Linus Torvalds's avatar
Linus Torvalds committed
557
{
558
559
560
561
562
	x86_cpu_to_apicid[cpu] = -1;
	cpu_clear(cpu, cpu_present_map);
	num_processors--;

	return (0);
Linus Torvalds's avatar
Linus Torvalds committed
563
}
Len Brown's avatar
Len Brown committed
564

Linus Torvalds's avatar
Linus Torvalds committed
565
EXPORT_SYMBOL(acpi_unmap_lsapic);
Len Brown's avatar
Len Brown committed
566
#endif				/* CONFIG_ACPI_HOTPLUG_CPU */
Linus Torvalds's avatar
Linus Torvalds committed
567

Len Brown's avatar
Len Brown committed
568
int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
569
570
571
572
{
	/* TBD */
	return -EINVAL;
}
Len Brown's avatar
Len Brown committed
573

574
575
EXPORT_SYMBOL(acpi_register_ioapic);

Len Brown's avatar
Len Brown committed
576
int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base)
577
578
579
580
{
	/* TBD */
	return -EINVAL;
}
Len Brown's avatar
Len Brown committed
581

582
583
EXPORT_SYMBOL(acpi_unregister_ioapic);

Linus Torvalds's avatar
Linus Torvalds committed
584
static unsigned long __init
Len Brown's avatar
Len Brown committed
585
acpi_scan_rsdp(unsigned long start, unsigned long length)
Linus Torvalds's avatar
Linus Torvalds committed
586
{
Len Brown's avatar
Len Brown committed
587
588
	unsigned long offset = 0;
	unsigned long sig_len = sizeof("RSD PTR ") - 1;
Linus Torvalds's avatar
Linus Torvalds committed
589
590
591
592
593
594

	/*
	 * Scan all 16-byte boundaries of the physical memory region for the
	 * RSDP signature.
	 */
	for (offset = 0; offset < length; offset += 16) {
595
		if (strncmp((char *)(phys_to_virt(start) + offset), "RSD PTR ", sig_len))
Linus Torvalds's avatar
Linus Torvalds committed
596
597
598
599
600
601
602
			continue;
		return (start + offset);
	}

	return 0;
}

603
static int __init acpi_parse_sbf(struct acpi_table_header *table)
Linus Torvalds's avatar
Linus Torvalds committed
604
{
605
	struct acpi_table_boot *sb;
Linus Torvalds's avatar
Linus Torvalds committed
606

607
	sb = (struct acpi_table_boot *)table;
Linus Torvalds's avatar
Linus Torvalds committed
608
609
610
611
612
	if (!sb) {
		printk(KERN_WARNING PREFIX "Unable to map SBF\n");
		return -ENODEV;
	}

613
	sbf_port = sb->cmos_index;	/* Save CMOS port */
Linus Torvalds's avatar
Linus Torvalds committed
614
615
616
617
618

	return 0;
}

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

621
622
static struct __initdata resource *hpet_res;

623
static int __init acpi_parse_hpet(struct acpi_table_header *table)
Linus Torvalds's avatar
Linus Torvalds committed
624
625
626
{
	struct acpi_table_hpet *hpet_tbl;

627
	hpet_tbl = (struct acpi_table_hpet *)table;
Linus Torvalds's avatar
Linus Torvalds committed
628
629
630
631
632
	if (!hpet_tbl) {
		printk(KERN_WARNING PREFIX "Unable to map HPET\n");
		return -ENODEV;
	}

633
	if (hpet_tbl->address.space_id != ACPI_SPACE_MEM) {
Linus Torvalds's avatar
Linus Torvalds committed
634
635
636
637
		printk(KERN_WARNING PREFIX "HPET timers must be located in "
		       "memory.\n");
		return -1;
	}
638

639
	hpet_address = hpet_tbl->address.address;
Len Brown's avatar
Len Brown committed
640
	printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
641
	       hpet_tbl->id, hpet_address);
Linus Torvalds's avatar
Linus Torvalds committed
642

643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
	/*
	 * 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);

	if (!hpet_res)
		return 0;

	memset(hpet_res, 0, sizeof(*hpet_res));
	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
662
663
	return 0;
}
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678

/*
 * 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
679
680
681
682
#else
#define	acpi_parse_hpet	NULL
#endif

683
static int __init acpi_parse_fadt(struct acpi_table_header *table)
Linus Torvalds's avatar
Linus Torvalds committed
684
{
Jason Davis's avatar
Jason Davis committed
685

Linus Torvalds's avatar
Linus Torvalds committed
686
687
#ifdef CONFIG_X86_PM_TIMER
	/* detect the location of the ACPI PM Timer */
688
	if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) {
Linus Torvalds's avatar
Linus Torvalds committed
689
		/* FADT rev. 2 */
690
		if (acpi_gbl_FADT.xpm_timer_block.space_id !=
Len Brown's avatar
Len Brown committed
691
		    ACPI_ADR_SPACE_SYSTEM_IO)
Linus Torvalds's avatar
Linus Torvalds committed
692
693
			return 0;

694
		pmtmr_ioport = acpi_gbl_FADT.xpm_timer_block.address;
695
696
697
698
699
700
		/*
		 * "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)
701
			pmtmr_ioport = acpi_gbl_FADT.pm_timer_block;
Linus Torvalds's avatar
Linus Torvalds committed
702
703
	} else {
		/* FADT rev. 1 */
704
		pmtmr_ioport = acpi_gbl_FADT.pm_timer_block;
Linus Torvalds's avatar
Linus Torvalds committed
705
706
	}
	if (pmtmr_ioport)
Len Brown's avatar
Len Brown committed
707
708
		printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n",
		       pmtmr_ioport);
Linus Torvalds's avatar
Linus Torvalds committed
709
710
711
712
#endif
	return 0;
}

Len Brown's avatar
Len Brown committed
713
unsigned long __init acpi_find_rsdp(void)
Linus Torvalds's avatar
Linus Torvalds committed
714
{
Len Brown's avatar
Len Brown committed
715
	unsigned long rsdp_phys = 0;
Linus Torvalds's avatar
Linus Torvalds committed
716
717

	if (efi_enabled) {
718
719
720
721
		if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
			return efi.acpi20;
		else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
			return efi.acpi;
Linus Torvalds's avatar
Linus Torvalds committed
722
723
724
725
726
	}
	/*
	 * Scan memory looking for the RSDP signature. First search EBDA (low
	 * memory) paragraphs and then search upper memory (E0000-FFFFF).
	 */
Len Brown's avatar
Len Brown committed
727
	rsdp_phys = acpi_scan_rsdp(0, 0x400);
Linus Torvalds's avatar
Linus Torvalds committed
728
	if (!rsdp_phys)
Len Brown's avatar
Len Brown committed
729
		rsdp_phys = acpi_scan_rsdp(0xE0000, 0x20000);
Linus Torvalds's avatar
Linus Torvalds committed
730
731
732
733
734
735
736
737
738

	return rsdp_phys;
}

#ifdef	CONFIG_X86_LOCAL_APIC
/*
 * Parse LAPIC entries in MADT
 * returns 0 on success, < 0 on error
 */
Len Brown's avatar
Len Brown committed
739
static int __init acpi_parse_madt_lapic_entries(void)
Linus Torvalds's avatar
Linus Torvalds committed
740
741
742
{
	int count;

743
744
745
	if (!cpu_has_apic)
		return -ENODEV;

746
	/*
Linus Torvalds's avatar
Linus Torvalds committed
747
748
749
750
	 * 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
751
	count =
752
	    acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE,
Len Brown's avatar
Len Brown committed
753
				  acpi_parse_lapic_addr_ovr, 0);
Linus Torvalds's avatar
Linus Torvalds committed
754
	if (count < 0) {
Len Brown's avatar
Len Brown committed
755
756
		printk(KERN_ERR PREFIX
		       "Error parsing LAPIC address override entry\n");
Linus Torvalds's avatar
Linus Torvalds committed
757
758
759
760
761
		return count;
	}

	mp_register_lapic_address(acpi_lapic_addr);

762
	count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC, acpi_parse_lapic,
Len Brown's avatar
Len Brown committed
763
764
				      MAX_APICS);
	if (!count) {
Linus Torvalds's avatar
Linus Torvalds committed
765
766
767
		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
768
	} else if (count < 0) {
Linus Torvalds's avatar
Linus Torvalds committed
769
770
771
772
773
		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
774
	count =
775
	    acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_NMI, acpi_parse_lapic_nmi, 0);
Linus Torvalds's avatar
Linus Torvalds committed
776
777
778
779
780
781
782
	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
783
#endif				/* CONFIG_X86_LOCAL_APIC */
Linus Torvalds's avatar
Linus Torvalds committed
784

785
#ifdef	CONFIG_X86_IO_APIC
Linus Torvalds's avatar
Linus Torvalds committed
786
787
788
789
/*
 * Parse IOAPIC related entries in MADT
 * returns 0 on success, < 0 on error
 */
Len Brown's avatar
Len Brown committed
790
static int __init acpi_parse_madt_ioapic_entries(void)
Linus Torvalds's avatar
Linus Torvalds committed
791
792
793
794
795
796
797
798
799
800
801
{
	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
802
	}
Linus Torvalds's avatar
Linus Torvalds committed
803

804
	if (!cpu_has_apic)
805
806
		return -ENODEV;

Linus Torvalds's avatar
Linus Torvalds committed
807
	/*
Len Brown's avatar
Len Brown committed
808
	 * if "noapic" boot option, don't look for IO-APICs
Linus Torvalds's avatar
Linus Torvalds committed
809
810
811
	 */
	if (skip_ioapic_setup) {
		printk(KERN_INFO PREFIX "Skipping IOAPIC probe "
Len Brown's avatar
Len Brown committed
812
		       "due to 'noapic' option.\n");
Linus Torvalds's avatar
Linus Torvalds committed
813
814
815
		return -ENODEV;
	}

Len Brown's avatar
Len Brown committed
816
	count =
817
	    acpi_table_parse_madt(ACPI_MADT_TYPE_IO_APIC, acpi_parse_ioapic,
Len Brown's avatar
Len Brown committed
818
				  MAX_IO_APICS);
Linus Torvalds's avatar
Linus Torvalds committed
819
820
821
	if (!count) {
		printk(KERN_ERR PREFIX "No IOAPIC entries present\n");
		return -ENODEV;
Len Brown's avatar
Len Brown committed
822
	} else if (count < 0) {
Linus Torvalds's avatar
Linus Torvalds committed
823
824
825
826
		printk(KERN_ERR PREFIX "Error parsing IOAPIC entry\n");
		return count;
	}

Len Brown's avatar
Len Brown committed
827
	count =
828
	    acpi_table_parse_madt(ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, acpi_parse_int_src_ovr,
Len Brown's avatar
Len Brown committed
829
				  NR_IRQ_VECTORS);
Linus Torvalds's avatar
Linus Torvalds committed
830
	if (count < 0) {
Len Brown's avatar
Len Brown committed
831
832
		printk(KERN_ERR PREFIX
		       "Error parsing interrupt source overrides entry\n");
Linus Torvalds's avatar
Linus Torvalds committed
833
834
835
836
837
838
839
840
841
		/* 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)
842
		acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0);
Linus Torvalds's avatar
Linus Torvalds committed
843
844
845
846

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

Len Brown's avatar
Len Brown committed
847
	count =
848
	    acpi_table_parse_madt(ACPI_MADT_TYPE_NMI_SOURCE, acpi_parse_nmi_src,
Len Brown's avatar
Len Brown committed
849
				  NR_IRQ_VECTORS);
Linus Torvalds's avatar
Linus Torvalds committed
850
851
852
853
854
855
856
857
858
859
860
861
862
	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;
}
863
#endif	/* !CONFIG_X86_IO_APIC */
Linus Torvalds's avatar
Linus Torvalds committed
864

Len Brown's avatar
Len Brown committed
865
static void __init acpi_process_madt(void)
Linus Torvalds's avatar
Linus Torvalds committed
866
867
{
#ifdef CONFIG_X86_LOCAL_APIC
868
	int error;
Linus Torvalds's avatar
Linus Torvalds committed
869

870
	if (!acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt)) {
Linus Torvalds's avatar
Linus Torvalds committed
871
872
873
874
875
876
877
878

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

879
880
881
#ifdef CONFIG_X86_GENERICARCH
			generic_bigsmp_probe();
#endif
Linus Torvalds's avatar
Linus Torvalds committed
882
883
884
885
886
887
888
889
890
891
			/*
			 * 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;
892
				setup_apic_routing();
Linus Torvalds's avatar
Linus Torvalds committed
893
894
895
896
897
898
			}
		}
		if (error == -EINVAL) {
			/*
			 * Dell Precision Workstation 410, 610 come here.
			 */
Len Brown's avatar
Len Brown committed
899
900
			printk(KERN_ERR PREFIX
			       "Invalid BIOS MADT, disabling ACPI\n");
Linus Torvalds's avatar
Linus Torvalds committed
901
902
903
904
905
906
907
			disable_acpi();
		}
	}
#endif
	return;
}

908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
#ifdef __i386__

static int __init disable_acpi_irq(struct dmi_system_id *d)
{
	if (!acpi_force) {
		printk(KERN_NOTICE "%s detected: force use of acpi=noirq\n",
		       d->ident);
		acpi_noirq_set();
	}
	return 0;
}

static int __init disable_acpi_pci(struct dmi_system_id *d)
{
	if (!acpi_force) {
		printk(KERN_NOTICE "%s detected: force use of pci=noacpi\n",
		       d->ident);
		acpi_disable_pci();
	}
	return 0;
}

static int __init dmi_disable_acpi(struct dmi_system_id *d)
{
	if (!acpi_force) {
Len Brown's avatar
Len Brown committed
933
		printk(KERN_NOTICE "%s detected: acpi off\n", d->ident);
934
935
936
937
938
939
940
941
942
943
944
945
946
947
		disable_acpi();
	} else {
		printk(KERN_NOTICE
		       "Warning: DMI blacklist says broken, but acpi forced\n");
	}
	return 0;
}

/*
 * Limit ACPI to CPU enumeration for HT
 */
static int __init force_acpi_ht(struct dmi_system_id *d)
{
	if (!acpi_force) {
Len Brown's avatar
Len Brown committed
948
949
		printk(KERN_NOTICE "%s detected: force use of acpi=ht\n",
		       d->ident);
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
		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
968
969
970
971
972
973
974
	 .callback = dmi_disable_acpi,
	 .ident = "IBM Thinkpad",
	 .matches = {
		     DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
		     DMI_MATCH(DMI_BOARD_NAME, "2629H1G"),
		     },
	 },
975
976
977
978
979

	/*
	 * Boxes that need acpi=ht
	 */
	{
Len Brown's avatar
Len Brown committed
980
981
982
983
984
985
986
	 .callback = force_acpi_ht,
	 .ident = "FSC Primergy T850",
	 .matches = {
		     DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
		     DMI_MATCH(DMI_PRODUCT_NAME, "PRIMERGY T850"),
		     },
	 },
987
	{
Len Brown's avatar
Len Brown committed
988
989
990
991
992
993
994
	 .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"),
		     },
	 },
995
	{
Len Brown's avatar
Len Brown committed
996
997
998
999
1000
1001
1002
	 .callback = force_acpi_ht,
	 .ident = "Compaq Workstation W8000",
	 .matches = {
		     DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
		     DMI_MATCH(DMI_PRODUCT_NAME, "Workstation W8000"),
		     },
	 },
1003
	{
Len Brown's avatar
Len Brown committed
1004
1005
1006
1007
1008
1009
1010
	 .callback = force_acpi_ht,
	 .ident = "ASUS P4B266",
	 .matches = {
		     DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
		     DMI_MATCH(DMI_BOARD_NAME, "P4B266"),
		     },
	 },
1011
	{
Len Brown's avatar
Len Brown committed
1012
1013
1014
1015
1016
1017
1018
	 .callback = force_acpi_ht,
	 .ident = "ASUS P2B-DS",
	 .matches = {
		     DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
		     DMI_MATCH(DMI_BOARD_NAME, "P2B-DS"),
		     },
	 },
1019
	{
Len Brown's avatar
Len Brown committed
1020
1021
1022
1023
1024
1025
1026
	 .callback = force_acpi_ht,
	 .ident = "ASUS CUR-DLS",
	 .matches = {
		     DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
		     DMI_MATCH(DMI_BOARD_NAME, "CUR-DLS"),
		     },
	 },
1027
	{
Len Brown's avatar
Len Brown committed
1028
1029
1030
1031
1032
1033
1034
	 .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)"),
		     },
	 },
1035
	{
Len Brown's avatar
Len Brown committed
1036
1037
1038
1039
1040
1041
1042
	 .callback = force_acpi_ht,
	 .ident = "IBM Bladecenter",
	 .matches = {
		     DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
		     DMI_MATCH(DMI_BOARD_NAME, "IBM eServer BladeCenter HS20"),
		     },
	 },
1043
	{
Len Brown's avatar
Len Brown committed
1044
1045
1046
1047
1048
1049
1050
	 .callback = force_acpi_ht,
	 .ident = "IBM eServer xSeries 360",
	 .matches = {
		     DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
		     DMI_MATCH(DMI_BOARD_NAME, "eServer xSeries 360"),
		     },
	 },
1051
	{
Len Brown's avatar
Len Brown committed
1052
1053
1054
1055
1056
1057
1058
	 .callback = force_acpi_ht,
	 .ident = "IBM eserver xSeries 330",
	 .matches = {
		     DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
		     DMI_MATCH(DMI_BOARD_NAME, "eserver xSeries 330"),
		     },
	 },
1059
	{
Len Brown's avatar
Len Brown committed
1060
1061
1062
1063
1064
1065
1066
	 .callback = force_acpi_ht,
	 .ident = "IBM eserver xSeries 440",
	 .matches = {
		     DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
		     DMI_MATCH(DMI_PRODUCT_NAME, "eserver xSeries 440"),
		     },
	 },
1067
1068
1069
1070
1071

	/*
	 * Boxes that need ACPI PCI IRQ routing disabled
	 */
	{
Len Brown's avatar
Len Brown committed
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
	 .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"),
		     },
	 },
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
	{
		/*
		 * 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"),
		     },
	 },
1104
1105
1106
	/*
	 * Boxes that need ACPI PCI IRQ routing and PCI scan disabled
	 */
Len Brown's avatar
Len Brown committed
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
	{			/* _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")
		     },
	 },
1118
	{
Len Brown's avatar
Len Brown committed
1119
1120
1121
1122
1123
1124
1125
1126
	 .callback = disable_acpi_pci,
	 .ident = "Acer TravelMate 36x Laptop",
	 .matches = {
		     DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
		     DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
		     },
	 },
	{}
1127
1128
};

Len Brown's avatar
Len Brown committed
1129
#endif				/* __i386__ */
1130

Linus Torvalds's avatar
Linus Torvalds committed
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
/*
 * 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
1154
int __init acpi_boot_table_init(void)
Linus Torvalds's avatar
Linus Torvalds committed
1155
1156
1157
{
	int error;

1158
1159
1160
1161
#ifdef __i386__
	dmi_check_system(acpi_dmi_table);
#endif

Linus Torvalds's avatar
Linus Torvalds committed
1162
1163
1164
1165
1166
	/*
	 * 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
1167
		return 1;
Linus Torvalds's avatar
Linus Torvalds committed
1168

1169
	/*
Linus Torvalds's avatar
Linus Torvalds committed
1170
1171
1172
1173
1174
1175
1176
1177
	 * Initialize the ACPI boot-time table parser.
	 */
	error = acpi_table_init();
	if (error) {
		disable_acpi();
		return error;
	}

1178
	acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
Linus Torvalds's avatar
Linus Torvalds committed
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203

	/*
	 * 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
1204
		return 1;
Linus Torvalds's avatar
Linus Torvalds committed
1205

1206
	acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
Linus Torvalds's avatar
Linus Torvalds committed
1207
1208
1209
1210

	/*
	 * set sci_int and PM timer address
	 */
1211
	acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt);
Linus Torvalds's avatar
Linus Torvalds committed
1212
1213
1214
1215
1216
1217

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

1218
	acpi_table_parse(ACPI_SIG_HPET, acpi_parse_hpet);
Linus Torvalds's avatar
Linus Torvalds committed
1219
1220
1221

	return 0;
}
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274

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);
1275
1276
1277
1278
1279
1280
1281

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);
1282
1283
1284
1285
1286
1287
1288
#endif /* CONFIG_X86_IO_APIC */

static int __init setup_acpi_sci(char *s)
{
	if (!s)
		return -EINVAL;
	if (!strcmp(s, "edge"))
1289
1290
		acpi_sci_flags =  ACPI_MADT_TRIGGER_EDGE |
			(acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK);
1291
	else if (!strcmp(s, "level"))
1292
1293
		acpi_sci_flags = ACPI_MADT_TRIGGER_LEVEL |
			(acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK);
1294
	else if (!strcmp(s, "high"))
1295
1296
		acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_HIGH |
			(acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK);
1297
	else if (!strcmp(s, "low"))
1298
1299
		acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_LOW |
			(acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK);
1300
1301
1302
1303
1304
	else
		return -EINVAL;
	return 0;
}
early_param("acpi_sci", setup_acpi_sci);
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326

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