blob: 0c2742f8c4da94c7ebb1d0c619a7eb147fe476ea [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * boot.c - Architecture-Specific Low-Level ACPI Boot Support
3 *
4 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
5 * Copyright (C) 2001 Jun Nakajima <jun.nakajima@intel.com>
6 *
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24 */
25
26#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <linux/acpi.h>
Thomas Gleixnerd66bea52007-02-16 01:27:57 -080028#include <linux/acpi_pmtmr.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/efi.h>
Ashok Raj73fea172006-09-26 10:52:35 +020030#include <linux/cpumask.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/module.h>
Andrey Paninaea00142005-06-25 14:54:42 -070032#include <linux/dmi.h>
Nick Pigginb33fa1f2005-10-01 02:34:42 +100033#include <linux/irq.h>
adurbin@google.comf0f4c342006-09-26 10:52:39 +020034#include <linux/bootmem.h>
35#include <linux/ioport.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
37#include <asm/pgtable.h>
38#include <asm/io_apic.h>
39#include <asm/apic.h>
Ingo Molnar183fe062008-07-09 11:32:10 +020040#include <asm/genapic.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <asm/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <asm/mpspec.h>
Alexey Starikovskiydfac2182008-04-04 23:41:50 +040043#include <asm/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
Glauber de Oliveira Costaf6bc4022008-03-19 14:25:53 -030045#ifdef CONFIG_X86_LOCAL_APIC
46# include <mach_apic.h>
47#endif
48
Adrian Bunke8924ac2006-09-26 10:52:35 +020049static int __initdata acpi_force = 0;
Rusty Russell1a3f2392006-09-26 10:52:32 +020050
Andi Kleendf3bb572006-09-26 10:52:33 +020051#ifdef CONFIG_ACPI
52int acpi_disabled = 0;
53#else
54int acpi_disabled = 1;
55#endif
56EXPORT_SYMBOL(acpi_disabled);
57
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#ifdef CONFIG_X86_64
59
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#include <asm/proto.h>
Jack Steinerae261862008-03-28 14:12:06 -050061#include <asm/genapic.h>
Linus Torvalds637029c2006-02-27 20:41:56 -080062
Len Brown4be44fc2005-08-05 00:44:28 -040063#else /* X86 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
65#ifdef CONFIG_X86_LOCAL_APIC
66#include <mach_apic.h>
67#include <mach_mpparse.h>
Len Brown4be44fc2005-08-05 00:44:28 -040068#endif /* CONFIG_X86_LOCAL_APIC */
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
Len Brown4be44fc2005-08-05 00:44:28 -040070#endif /* X86 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
72#define BAD_MADT_ENTRY(entry, end) ( \
73 (!entry) || (unsigned long)entry + sizeof(*entry) > end || \
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +030074 ((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
76#define PREFIX "ACPI: "
77
Andrew Morton90d53902006-11-02 22:07:18 -080078int acpi_noirq; /* skip ACPI IRQ initialization */
Yinghai Lu6e4be1f2008-02-05 00:01:48 -080079int acpi_pci_disabled; /* skip ACPI PCI scan and IRQ initialization */
80EXPORT_SYMBOL(acpi_pci_disabled);
Linus Torvalds1da177e2005-04-16 15:20:36 -070081int acpi_ht __initdata = 1; /* enable HT */
82
83int acpi_lapic;
84int acpi_ioapic;
85int acpi_strict;
Linus Torvalds1da177e2005-04-16 15:20:36 -070086
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +030087u8 acpi_sci_flags __initdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -070088int acpi_sci_override_gsi __initdata;
89int acpi_skip_timer_override __initdata;
Andi Kleenfa18f472006-11-14 16:57:46 +010090int acpi_use_timer_override __initdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
92#ifdef CONFIG_X86_LOCAL_APIC
93static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
94#endif
95
96#ifndef __HAVE_ARCH_CMPXCHG
97#warning ACPI uses CMPXCHG, i486 and later hardware
98#endif
99
John Kellera726c602008-07-29 14:34:16 -0500100
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101/* --------------------------------------------------------------------------
102 Boot-time Configuration
103 -------------------------------------------------------------------------- */
104
105/*
106 * The default interrupt routing model is PIC (8259). This gets
Simon Arlott27b46d72007-10-20 01:13:56 +0200107 * overridden if IOAPICs are enumerated (below).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 */
Len Brown4be44fc2005-08-05 00:44:28 -0400109enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_PIC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111
112/*
113 * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END,
114 * to map the target physical address. The problem is that set_fixmap()
115 * provides a single page, and it is possible that the page is not
116 * sufficient.
117 * By using this area, we can map up to MAX_IO_APICS pages temporarily,
118 * i.e. until the next __va_range() call.
119 *
120 * Important Safety Note: The fixed I/O APIC page numbers are *subtracted*
121 * from the fixed base. That's why we start at FIX_IO_APIC_BASE_END and
122 * count idx down while incrementing the phys address.
123 */
Jan Beulich2fdf0742007-12-13 08:33:59 +0000124char *__init __acpi_map_table(unsigned long phys, unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125{
126 unsigned long base, offset, mapped_size;
127 int idx;
128
Yinghai Luf34fa822008-07-09 20:16:36 -0700129 if (!phys || !size)
130 return NULL;
131
Yinghai Luf361a452008-07-10 20:38:26 -0700132 if (phys+size <= (max_low_pfn_mapped << PAGE_SHIFT))
Len Brown4be44fc2005-08-05 00:44:28 -0400133 return __va(phys);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134
135 offset = phys & (PAGE_SIZE - 1);
136 mapped_size = PAGE_SIZE - offset;
Yinghai Luf34fa822008-07-09 20:16:36 -0700137 clear_fixmap(FIX_ACPI_END);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 set_fixmap(FIX_ACPI_END, phys);
139 base = fix_to_virt(FIX_ACPI_END);
140
141 /*
142 * Most cases can be covered by the below.
143 */
144 idx = FIX_ACPI_END;
145 while (mapped_size < size) {
146 if (--idx < FIX_ACPI_BEGIN)
147 return NULL; /* cannot handle this */
148 phys += PAGE_SIZE;
Yinghai Luf34fa822008-07-09 20:16:36 -0700149 clear_fixmap(idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 set_fixmap(idx, phys);
151 mapped_size += PAGE_SIZE;
152 }
153
Len Brown4be44fc2005-08-05 00:44:28 -0400154 return ((unsigned char *)base + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
157#ifdef CONFIG_PCI_MMCONFIG
Pavel Vasilyev1339c362008-10-15 17:33:48 -0400158
159static int acpi_mcfg_64bit_base_addr __initdata = FALSE;
160
Greg Kroah-Hartman54549392005-06-23 17:35:56 -0700161/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300162struct acpi_mcfg_allocation *pci_mmcfg_config;
Greg Kroah-Hartman54549392005-06-23 17:35:56 -0700163int pci_mmcfg_config_num;
164
John Kellera726c602008-07-29 14:34:16 -0500165static int __init acpi_mcfg_oem_check(struct acpi_table_mcfg *mcfg)
166{
167 if (!strcmp(mcfg->header.oem_id, "SGI"))
168 acpi_mcfg_64bit_base_addr = TRUE;
169
170 return 0;
171}
172
Alexey Starikovskiyceb6c462007-02-02 19:48:22 +0300173int __init acpi_parse_mcfg(struct acpi_table_header *header)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174{
175 struct acpi_table_mcfg *mcfg;
Greg Kroah-Hartman54549392005-06-23 17:35:56 -0700176 unsigned long i;
177 int config_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
Alexey Starikovskiyceb6c462007-02-02 19:48:22 +0300179 if (!header)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 return -EINVAL;
181
Alexey Starikovskiyceb6c462007-02-02 19:48:22 +0300182 mcfg = (struct acpi_table_mcfg *)header;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
Greg Kroah-Hartman54549392005-06-23 17:35:56 -0700184 /* how many config structures do we have */
185 pci_mmcfg_config_num = 0;
Alexey Starikovskiyceb6c462007-02-02 19:48:22 +0300186 i = header->length - sizeof(struct acpi_table_mcfg);
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300187 while (i >= sizeof(struct acpi_mcfg_allocation)) {
Greg Kroah-Hartman54549392005-06-23 17:35:56 -0700188 ++pci_mmcfg_config_num;
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300189 i -= sizeof(struct acpi_mcfg_allocation);
Greg Kroah-Hartman54549392005-06-23 17:35:56 -0700190 };
191 if (pci_mmcfg_config_num == 0) {
192 printk(KERN_ERR PREFIX "MMCONFIG has no entries\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 return -ENODEV;
194 }
195
Greg Kroah-Hartman54549392005-06-23 17:35:56 -0700196 config_size = pci_mmcfg_config_num * sizeof(*pci_mmcfg_config);
197 pci_mmcfg_config = kmalloc(config_size, GFP_KERNEL);
198 if (!pci_mmcfg_config) {
199 printk(KERN_WARNING PREFIX
200 "No memory for MCFG config tables\n");
201 return -ENOMEM;
202 }
203
Alexey Starikovskiyad363f82007-02-02 19:48:22 +0300204 memcpy(pci_mmcfg_config, &mcfg[1], config_size);
John Kellera726c602008-07-29 14:34:16 -0500205
206 acpi_mcfg_oem_check(mcfg);
207
Greg Kroah-Hartman54549392005-06-23 17:35:56 -0700208 for (i = 0; i < pci_mmcfg_config_num; ++i) {
John Kellera726c602008-07-29 14:34:16 -0500209 if ((pci_mmcfg_config[i].address > 0xFFFFFFFF) &&
210 !acpi_mcfg_64bit_base_addr) {
Greg Kroah-Hartman54549392005-06-23 17:35:56 -0700211 printk(KERN_ERR PREFIX
212 "MMCONFIG not in low 4GB of memory\n");
Konrad Rzeszutekacc7c2e2006-06-15 12:08:30 -0400213 kfree(pci_mmcfg_config);
214 pci_mmcfg_config_num = 0;
Greg Kroah-Hartman54549392005-06-23 17:35:56 -0700215 return -ENODEV;
216 }
217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
219 return 0;
220}
Len Brown4be44fc2005-08-05 00:44:28 -0400221#endif /* CONFIG_PCI_MMCONFIG */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222
223#ifdef CONFIG_X86_LOCAL_APIC
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300224static int __init acpi_parse_madt(struct acpi_table_header *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225{
Len Brown4be44fc2005-08-05 00:44:28 -0400226 struct acpi_table_madt *madt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300228 if (!cpu_has_apic)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 return -EINVAL;
230
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300231 madt = (struct acpi_table_madt *)table;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 if (!madt) {
233 printk(KERN_WARNING PREFIX "Unable to map MADT\n");
234 return -ENODEV;
235 }
236
Alexey Starikovskiyad363f82007-02-02 19:48:22 +0300237 if (madt->address) {
238 acpi_lapic_addr = (u64) madt->address;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
240 printk(KERN_DEBUG PREFIX "Local APIC address 0x%08x\n",
Alexey Starikovskiyad363f82007-02-02 19:48:22 +0300241 madt->address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 }
243
244 acpi_madt_oem_check(madt->header.oem_id, madt->header.oem_table_id);
Len Brown4be44fc2005-08-05 00:44:28 -0400245
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 return 0;
247}
248
Alexey Starikovskiydfac2182008-04-04 23:41:50 +0400249static void __cpuinit acpi_register_lapic(int id, u8 enabled)
250{
Yinghai Lufb3bbd62008-05-22 18:22:30 -0700251 unsigned int ver = 0;
252
Alexey Starikovskiydfac2182008-04-04 23:41:50 +0400253 if (!enabled) {
254 ++disabled_cpus;
255 return;
256 }
257
Yinghai Lufb3bbd62008-05-22 18:22:30 -0700258#ifdef CONFIG_X86_32
259 if (boot_cpu_physical_apicid != -1U)
260 ver = apic_version[boot_cpu_physical_apicid];
261#endif
262
263 generic_processor_info(id, ver);
Alexey Starikovskiydfac2182008-04-04 23:41:50 +0400264}
265
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266static int __init
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300267acpi_parse_lapic(struct acpi_subtable_header * header, const unsigned long end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268{
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300269 struct acpi_madt_local_apic *processor = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300271 processor = (struct acpi_madt_local_apic *)header;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
273 if (BAD_MADT_ENTRY(processor, end))
274 return -EINVAL;
275
276 acpi_table_print_madt_entry(header);
277
Ashok Raj7f66ae42006-02-03 21:51:50 +0100278 /*
279 * We need to register disabled CPU as well to permit
280 * counting disabled CPUs. This allows us to size
281 * cpus_possible_map more accurately, to permit
282 * to not preallocating memory for all NR_CPUS
283 * when we use CPU hotplug.
284 */
Alexey Starikovskiydfac2182008-04-04 23:41:50 +0400285 acpi_register_lapic(processor->id, /* APIC ID */
286 processor->lapic_flags & ACPI_MADT_ENABLED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
288 return 0;
289}
290
291static int __init
Jack Steinerac049c12008-03-28 14:12:09 -0500292acpi_parse_sapic(struct acpi_subtable_header *header, const unsigned long end)
293{
294 struct acpi_madt_local_sapic *processor = NULL;
295
296 processor = (struct acpi_madt_local_sapic *)header;
297
298 if (BAD_MADT_ENTRY(processor, end))
299 return -EINVAL;
300
301 acpi_table_print_madt_entry(header);
302
Alexey Starikovskiydfac2182008-04-04 23:41:50 +0400303 acpi_register_lapic((processor->id << 8) | processor->eid,/* APIC ID */
304 processor->lapic_flags & ACPI_MADT_ENABLED);
Jack Steinerac049c12008-03-28 14:12:09 -0500305
306 return 0;
307}
308
309static int __init
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300310acpi_parse_lapic_addr_ovr(struct acpi_subtable_header * header,
Len Brown4be44fc2005-08-05 00:44:28 -0400311 const unsigned long end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312{
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300313 struct acpi_madt_local_apic_override *lapic_addr_ovr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300315 lapic_addr_ovr = (struct acpi_madt_local_apic_override *)header;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
317 if (BAD_MADT_ENTRY(lapic_addr_ovr, end))
318 return -EINVAL;
319
320 acpi_lapic_addr = lapic_addr_ovr->address;
321
322 return 0;
323}
324
325static int __init
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300326acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327{
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300328 struct acpi_madt_local_apic_nmi *lapic_nmi = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300330 lapic_nmi = (struct acpi_madt_local_apic_nmi *)header;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
332 if (BAD_MADT_ENTRY(lapic_nmi, end))
333 return -EINVAL;
334
335 acpi_table_print_madt_entry(header);
336
337 if (lapic_nmi->lint != 1)
338 printk(KERN_WARNING PREFIX "NMI not connected to LINT 1!\n");
339
340 return 0;
341}
342
Len Brown4be44fc2005-08-05 00:44:28 -0400343#endif /*CONFIG_X86_LOCAL_APIC */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
Len Brown84663612005-08-24 12:09:07 -0400345#ifdef CONFIG_X86_IO_APIC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
347static int __init
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300348acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349{
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300350 struct acpi_madt_io_apic *ioapic = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300352 ioapic = (struct acpi_madt_io_apic *)header;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
354 if (BAD_MADT_ENTRY(ioapic, end))
355 return -EINVAL;
Len Brown4be44fc2005-08-05 00:44:28 -0400356
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 acpi_table_print_madt_entry(header);
358
Len Brown4be44fc2005-08-05 00:44:28 -0400359 mp_register_ioapic(ioapic->id,
360 ioapic->address, ioapic->global_irq_base);
361
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 return 0;
363}
364
365/*
366 * Parse Interrupt Source Override for the ACPI SCI
367 */
Len Browne82c3542006-12-21 01:29:59 -0500368static void __init acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369{
370 if (trigger == 0) /* compatible SCI trigger is level */
371 trigger = 3;
372
373 if (polarity == 0) /* compatible SCI polarity is low */
374 polarity = 3;
375
376 /* Command-line over-ride via acpi_sci= */
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300377 if (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK)
378 trigger = (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300380 if (acpi_sci_flags & ACPI_MADT_POLARITY_MASK)
381 polarity = acpi_sci_flags & ACPI_MADT_POLARITY_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
383 /*
Len Brown4be44fc2005-08-05 00:44:28 -0400384 * mp_config_acpi_legacy_irqs() already setup IRQs < 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 * If GSI is < 16, this will update its flags,
386 * else it will create a new mp_irqs[] entry.
387 */
Len Brown7bdd21c2006-12-02 02:27:46 -0500388 mp_override_legacy_irq(gsi, polarity, trigger, gsi);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
390 /*
391 * stash over-ride to indicate we've been here
Alexey Starikovskiycee324b2007-02-02 19:48:22 +0300392 * and for later update of acpi_gbl_FADT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 */
Len Brown7bdd21c2006-12-02 02:27:46 -0500394 acpi_sci_override_gsi = gsi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 return;
396}
397
398static int __init
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300399acpi_parse_int_src_ovr(struct acpi_subtable_header * header,
Len Brown4be44fc2005-08-05 00:44:28 -0400400 const unsigned long end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401{
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300402 struct acpi_madt_interrupt_override *intsrc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300404 intsrc = (struct acpi_madt_interrupt_override *)header;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
406 if (BAD_MADT_ENTRY(intsrc, end))
407 return -EINVAL;
408
409 acpi_table_print_madt_entry(header);
410
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300411 if (intsrc->source_irq == acpi_gbl_FADT.sci_interrupt) {
Len Brown7bdd21c2006-12-02 02:27:46 -0500412 acpi_sci_ioapic_setup(intsrc->global_irq,
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300413 intsrc->inti_flags & ACPI_MADT_POLARITY_MASK,
414 (intsrc->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 return 0;
416 }
417
418 if (acpi_skip_timer_override &&
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300419 intsrc->source_irq == 0 && intsrc->global_irq == 2) {
Len Brown4be44fc2005-08-05 00:44:28 -0400420 printk(PREFIX "BIOS IRQ0 pin2 override ignored.\n");
421 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 }
423
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300424 mp_override_legacy_irq(intsrc->source_irq,
425 intsrc->inti_flags & ACPI_MADT_POLARITY_MASK,
426 (intsrc->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2,
427 intsrc->global_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
429 return 0;
430}
431
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432static int __init
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300433acpi_parse_nmi_src(struct acpi_subtable_header * header, const unsigned long end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434{
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300435 struct acpi_madt_nmi_source *nmi_src = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300437 nmi_src = (struct acpi_madt_nmi_source *)header;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438
439 if (BAD_MADT_ENTRY(nmi_src, end))
440 return -EINVAL;
441
442 acpi_table_print_madt_entry(header);
443
444 /* TBD: Support nimsrc entries? */
445
446 return 0;
447}
448
Len Brown4be44fc2005-08-05 00:44:28 -0400449#endif /* CONFIG_X86_IO_APIC */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451/*
452 * acpi_pic_sci_set_trigger()
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300453 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 * use ELCR to set PIC-mode trigger type for SCI
455 *
456 * If a PIC-mode SCI is not recognized or gives spurious IRQ7's
457 * it may require Edge Trigger -- use "acpi_sci=edge"
458 *
459 * Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers
460 * for the 8259 PIC. bit[n] = 1 means irq[n] is Level, otherwise Edge.
Simon Arlott27b46d72007-10-20 01:13:56 +0200461 * ECLR1 is IRQs 0-7 (IRQ 0, 1, 2 must be 0)
462 * ECLR2 is IRQs 8-15 (IRQ 8, 13 must be 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 */
464
Len Brown4be44fc2005-08-05 00:44:28 -0400465void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466{
467 unsigned int mask = 1 << irq;
468 unsigned int old, new;
469
470 /* Real old ELCR mask */
471 old = inb(0x4d0) | (inb(0x4d1) << 8);
472
473 /*
Simon Arlott27b46d72007-10-20 01:13:56 +0200474 * If we use ACPI to set PCI IRQs, then we should clear ELCR
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 * since we will set it correctly as we enable the PCI irq
476 * routing.
477 */
478 new = acpi_noirq ? old : 0;
479
480 /*
481 * Update SCI information in the ELCR, it isn't in the PCI
482 * routing tables..
483 */
484 switch (trigger) {
Len Brown4be44fc2005-08-05 00:44:28 -0400485 case 1: /* Edge - clear */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 new &= ~mask;
487 break;
Len Brown4be44fc2005-08-05 00:44:28 -0400488 case 3: /* Level - set */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 new |= mask;
490 break;
491 }
492
493 if (old == new)
494 return;
495
496 printk(PREFIX "setting ELCR to %04x (from %04x)\n", new, old);
497 outb(new, 0x4d0);
498 outb(new >> 8, 0x4d1);
499}
500
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
502{
Eric W. Biedermanf023d762006-10-04 02:16:52 -0700503 *irq = gsi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 return 0;
505}
506
Kenji Kaneshige1f3a6a12005-07-28 14:42:00 -0400507/*
508 * success: return IRQ number (>=0)
509 * failure: return < 0
510 */
Len Browncb654692005-12-28 02:43:51 -0500511int acpi_register_gsi(u32 gsi, int triggering, int polarity)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512{
513 unsigned int irq;
514 unsigned int plat_gsi = gsi;
515
516#ifdef CONFIG_PCI
517 /*
518 * Make sure all (legacy) PCI IRQs are set as level-triggered.
519 */
520 if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) {
Len Browncb654692005-12-28 02:43:51 -0500521 if (triggering == ACPI_LEVEL_SENSITIVE)
Len Brown4be44fc2005-08-05 00:44:28 -0400522 eisa_set_level_irq(gsi);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 }
524#endif
525
526#ifdef CONFIG_X86_IO_APIC
527 if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) {
Len Browncb654692005-12-28 02:43:51 -0500528 plat_gsi = mp_register_gsi(gsi, triggering, polarity);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 }
530#endif
531 acpi_gsi_to_irq(plat_gsi, &irq);
532 return irq;
533}
Len Brown4be44fc2005-08-05 00:44:28 -0400534
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535/*
536 * ACPI based hotplug support for CPU
537 */
538#ifdef CONFIG_ACPI_HOTPLUG_CPU
Sam Ravnborg009cbad2008-02-01 17:49:42 +0100539
540static int __cpuinit _acpi_map_lsapic(acpi_handle handle, int *pcpu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541{
Ashok Raj73fea172006-09-26 10:52:35 +0200542 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
543 union acpi_object *obj;
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300544 struct acpi_madt_local_apic *lapic;
Ashok Raj73fea172006-09-26 10:52:35 +0200545 cpumask_t tmp_map, new_map;
546 u8 physid;
547 int cpu;
548
549 if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
550 return -EINVAL;
551
552 if (!buffer.length || !buffer.pointer)
553 return -EINVAL;
554
555 obj = buffer.pointer;
556 if (obj->type != ACPI_TYPE_BUFFER ||
557 obj->buffer.length < sizeof(*lapic)) {
558 kfree(buffer.pointer);
559 return -EINVAL;
560 }
561
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300562 lapic = (struct acpi_madt_local_apic *)obj->buffer.pointer;
Ashok Raj73fea172006-09-26 10:52:35 +0200563
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300564 if (lapic->header.type != ACPI_MADT_TYPE_LOCAL_APIC ||
565 !(lapic->lapic_flags & ACPI_MADT_ENABLED)) {
Ashok Raj73fea172006-09-26 10:52:35 +0200566 kfree(buffer.pointer);
567 return -EINVAL;
568 }
569
570 physid = lapic->id;
571
572 kfree(buffer.pointer);
573 buffer.length = ACPI_ALLOCATE_BUFFER;
574 buffer.pointer = NULL;
575
576 tmp_map = cpu_present_map;
Alexey Starikovskiydfac2182008-04-04 23:41:50 +0400577 acpi_register_lapic(physid, lapic->lapic_flags & ACPI_MADT_ENABLED);
Ashok Raj73fea172006-09-26 10:52:35 +0200578
579 /*
580 * If mp_register_lapic successfully generates a new logical cpu
581 * number, then the following will get us exactly what was mapped
582 */
583 cpus_andnot(new_map, cpu_present_map, tmp_map);
584 if (cpus_empty(new_map)) {
585 printk ("Unable to map lapic to logical cpu number\n");
586 return -EINVAL;
587 }
588
589 cpu = first_cpu(new_map);
590
591 *pcpu = cpu;
592 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593}
Len Brown4be44fc2005-08-05 00:44:28 -0400594
Sam Ravnborg009cbad2008-02-01 17:49:42 +0100595/* wrapper to silence section mismatch warning */
596int __ref acpi_map_lsapic(acpi_handle handle, int *pcpu)
597{
598 return _acpi_map_lsapic(handle, pcpu);
599}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600EXPORT_SYMBOL(acpi_map_lsapic);
601
Len Brown4be44fc2005-08-05 00:44:28 -0400602int acpi_unmap_lsapic(int cpu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603{
Mike Travis71fff5e2007-10-19 20:35:03 +0200604 per_cpu(x86_cpu_to_apicid, cpu) = -1;
Ashok Raj73fea172006-09-26 10:52:35 +0200605 cpu_clear(cpu, cpu_present_map);
606 num_processors--;
607
608 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609}
Len Brown4be44fc2005-08-05 00:44:28 -0400610
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611EXPORT_SYMBOL(acpi_unmap_lsapic);
Len Brown4be44fc2005-08-05 00:44:28 -0400612#endif /* CONFIG_ACPI_HOTPLUG_CPU */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613
Len Brown4be44fc2005-08-05 00:44:28 -0400614int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
Kenji Kaneshigeb1bb2482005-04-28 00:25:58 -0700615{
616 /* TBD */
617 return -EINVAL;
618}
Len Brown4be44fc2005-08-05 00:44:28 -0400619
Kenji Kaneshigeb1bb2482005-04-28 00:25:58 -0700620EXPORT_SYMBOL(acpi_register_ioapic);
621
Len Brown4be44fc2005-08-05 00:44:28 -0400622int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base)
Kenji Kaneshigeb1bb2482005-04-28 00:25:58 -0700623{
624 /* TBD */
625 return -EINVAL;
626}
Len Brown4be44fc2005-08-05 00:44:28 -0400627
Kenji Kaneshigeb1bb2482005-04-28 00:25:58 -0700628EXPORT_SYMBOL(acpi_unregister_ioapic);
629
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300630static int __init acpi_parse_sbf(struct acpi_table_header *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631{
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300632 struct acpi_table_boot *sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300634 sb = (struct acpi_table_boot *)table;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 if (!sb) {
636 printk(KERN_WARNING PREFIX "Unable to map SBF\n");
637 return -ENODEV;
638 }
639
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300640 sbf_port = sb->cmos_index; /* Save CMOS port */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
642 return 0;
643}
644
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645#ifdef CONFIG_HPET_TIMER
john stultz2d0c87c2007-02-16 01:28:18 -0800646#include <asm/hpet.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
Aaron Durbina1dfd852007-07-21 17:11:39 +0200648static struct __initdata resource *hpet_res;
649
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300650static int __init acpi_parse_hpet(struct acpi_table_header *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651{
652 struct acpi_table_hpet *hpet_tbl;
653
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300654 hpet_tbl = (struct acpi_table_hpet *)table;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 if (!hpet_tbl) {
656 printk(KERN_WARNING PREFIX "Unable to map HPET\n");
657 return -ENODEV;
658 }
659
Alexey Starikovskiyad363f82007-02-02 19:48:22 +0300660 if (hpet_tbl->address.space_id != ACPI_SPACE_MEM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 printk(KERN_WARNING PREFIX "HPET timers must be located in "
662 "memory.\n");
663 return -1;
664 }
adurbin@google.comf0f4c342006-09-26 10:52:39 +0200665
john stultz2d0c87c2007-02-16 01:28:18 -0800666 hpet_address = hpet_tbl->address.address;
Thomas Gleixnerf4df73c2007-11-15 21:41:50 -0500667
668 /*
669 * Some broken BIOSes advertise HPET at 0x0. We really do not
670 * want to allocate a resource there.
671 */
672 if (!hpet_address) {
673 printk(KERN_WARNING PREFIX
674 "HPET id: %#x base: %#lx is invalid\n",
675 hpet_tbl->id, hpet_address);
676 return 0;
677 }
678#ifdef CONFIG_X86_64
679 /*
680 * Some even more broken BIOSes advertise HPET at
681 * 0xfed0000000000000 instead of 0xfed00000. Fix it up and add
682 * some noise:
683 */
684 if (hpet_address == 0xfed0000000000000UL) {
685 if (!hpet_force_user) {
686 printk(KERN_WARNING PREFIX "HPET id: %#x "
687 "base: 0xfed0000000000000 is bogus\n "
688 "try hpet=force on the kernel command line to "
689 "fix it up to 0xfed00000.\n", hpet_tbl->id);
690 hpet_address = 0;
691 return 0;
692 }
693 printk(KERN_WARNING PREFIX
694 "HPET id: %#x base: 0xfed0000000000000 fixed up "
695 "to 0xfed00000.\n", hpet_tbl->id);
696 hpet_address >>= 32;
697 }
698#endif
Len Brown4be44fc2005-08-05 00:44:28 -0400699 printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
john stultz2d0c87c2007-02-16 01:28:18 -0800700 hpet_tbl->id, hpet_address);
adurbin@google.comf0f4c342006-09-26 10:52:39 +0200701
Aaron Durbina1dfd852007-07-21 17:11:39 +0200702 /*
703 * Allocate and initialize the HPET firmware resource for adding into
704 * the resource tree during the lateinit timeframe.
705 */
706#define HPET_RESOURCE_NAME_SIZE 9
707 hpet_res = alloc_bootmem(sizeof(*hpet_res) + HPET_RESOURCE_NAME_SIZE);
708
Aaron Durbina1dfd852007-07-21 17:11:39 +0200709 hpet_res->name = (void *)&hpet_res[1];
710 hpet_res->flags = IORESOURCE_MEM;
711 snprintf((char *)hpet_res->name, HPET_RESOURCE_NAME_SIZE, "HPET %u",
712 hpet_tbl->sequence);
713
714 hpet_res->start = hpet_address;
715 hpet_res->end = hpet_address + (1 * 1024) - 1;
716
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 return 0;
718}
Aaron Durbina1dfd852007-07-21 17:11:39 +0200719
720/*
721 * hpet_insert_resource inserts the HPET resources used into the resource
722 * tree.
723 */
724static __init int hpet_insert_resource(void)
725{
726 if (!hpet_res)
727 return 1;
728
729 return insert_resource(&iomem_resource, hpet_res);
730}
731
732late_initcall(hpet_insert_resource);
733
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734#else
735#define acpi_parse_hpet NULL
736#endif
737
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300738static int __init acpi_parse_fadt(struct acpi_table_header *table)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739{
Jason Davis90660ec2005-04-16 15:24:53 -0700740
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741#ifdef CONFIG_X86_PM_TIMER
742 /* detect the location of the ACPI PM Timer */
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300743 if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 /* FADT rev. 2 */
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300745 if (acpi_gbl_FADT.xpm_timer_block.space_id !=
Len Brown4be44fc2005-08-05 00:44:28 -0400746 ACPI_ADR_SPACE_SYSTEM_IO)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 return 0;
748
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300749 pmtmr_ioport = acpi_gbl_FADT.xpm_timer_block.address;
David Shaohua Lie6e87b42005-09-21 01:35:00 -0400750 /*
751 * "X" fields are optional extensions to the original V1.0
752 * fields, so we must selectively expand V1.0 fields if the
753 * corresponding X field is zero.
754 */
755 if (!pmtmr_ioport)
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300756 pmtmr_ioport = acpi_gbl_FADT.pm_timer_block;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 } else {
758 /* FADT rev. 1 */
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300759 pmtmr_ioport = acpi_gbl_FADT.pm_timer_block;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 }
761 if (pmtmr_ioport)
Len Brown4be44fc2005-08-05 00:44:28 -0400762 printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n",
763 pmtmr_ioport);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764#endif
765 return 0;
766}
767
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768#ifdef CONFIG_X86_LOCAL_APIC
769/*
770 * Parse LAPIC entries in MADT
771 * returns 0 on success, < 0 on error
772 */
Alexey Starikovskiy31d20922008-04-04 23:41:57 +0400773
774static void __init acpi_register_lapic_address(unsigned long address)
775{
776 mp_lapic_addr = address;
777
778 set_fixmap_nocache(FIX_APIC_BASE, address);
Yinghai Lufb3bbd62008-05-22 18:22:30 -0700779 if (boot_cpu_physical_apicid == -1U) {
Alexey Starikovskiy31d20922008-04-04 23:41:57 +0400780 boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id());
Yinghai Lufb3bbd62008-05-22 18:22:30 -0700781#ifdef CONFIG_X86_32
782 apic_version[boot_cpu_physical_apicid] =
783 GET_APIC_VERSION(apic_read(APIC_LVR));
784#endif
785 }
Alexey Starikovskiy31d20922008-04-04 23:41:57 +0400786}
787
Yinghai Lucbf9bd62008-02-19 03:21:06 -0800788static int __init early_acpi_parse_madt_lapic_addr_ovr(void)
789{
790 int count;
791
792 if (!cpu_has_apic)
793 return -ENODEV;
794
795 /*
796 * Note that the LAPIC address is obtained from the MADT (32-bit value)
797 * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value).
798 */
799
800 count =
801 acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE,
802 acpi_parse_lapic_addr_ovr, 0);
803 if (count < 0) {
804 printk(KERN_ERR PREFIX
805 "Error parsing LAPIC address override entry\n");
806 return count;
807 }
808
809 acpi_register_lapic_address(acpi_lapic_addr);
810
811 return count;
812}
813
Len Brown4be44fc2005-08-05 00:44:28 -0400814static int __init acpi_parse_madt_lapic_entries(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815{
816 int count;
817
Andi Kleen0fcd2702006-04-11 12:54:36 +0200818 if (!cpu_has_apic)
819 return -ENODEV;
820
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300821 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 * Note that the LAPIC address is obtained from the MADT (32-bit value)
823 * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value).
824 */
825
Len Brown4be44fc2005-08-05 00:44:28 -0400826 count =
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300827 acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE,
Len Brown4be44fc2005-08-05 00:44:28 -0400828 acpi_parse_lapic_addr_ovr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 if (count < 0) {
Len Brown4be44fc2005-08-05 00:44:28 -0400830 printk(KERN_ERR PREFIX
831 "Error parsing LAPIC address override entry\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 return count;
833 }
834
Alexey Starikovskiy31d20922008-04-04 23:41:57 +0400835 acpi_register_lapic_address(acpi_lapic_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
Jack Steinerac049c12008-03-28 14:12:09 -0500837 count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_SAPIC,
838 acpi_parse_sapic, MAX_APICS);
839
840 if (!count)
841 count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC,
842 acpi_parse_lapic, MAX_APICS);
Len Brown4be44fc2005-08-05 00:44:28 -0400843 if (!count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 printk(KERN_ERR PREFIX "No LAPIC entries present\n");
845 /* TBD: Cleanup to allow fallback to MPS */
846 return -ENODEV;
Len Brown4be44fc2005-08-05 00:44:28 -0400847 } else if (count < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 printk(KERN_ERR PREFIX "Error parsing LAPIC entry\n");
849 /* TBD: Cleanup to allow fallback to MPS */
850 return count;
851 }
852
Len Brown4be44fc2005-08-05 00:44:28 -0400853 count =
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +0300854 acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_NMI, acpi_parse_lapic_nmi, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 if (count < 0) {
856 printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
857 /* TBD: Cleanup to allow fallback to MPS */
858 return count;
859 }
860 return 0;
861}
Len Brown4be44fc2005-08-05 00:44:28 -0400862#endif /* CONFIG_X86_LOCAL_APIC */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863
Len Brown84663612005-08-24 12:09:07 -0400864#ifdef CONFIG_X86_IO_APIC
Alexey Starikovskiy11113f82008-05-14 19:02:57 +0400865#define MP_ISA_BUS 0
866
Yinghai Lud49c4282008-06-08 18:31:54 -0700867#ifdef CONFIG_X86_ES7000
Alexey Starikovskiy11113f82008-05-14 19:02:57 +0400868extern int es7000_plat;
869#endif
870
Alexey Starikovskiy5f895142008-05-14 19:03:04 +0400871static struct {
872 int apic_id;
873 int gsi_base;
874 int gsi_end;
875 DECLARE_BITMAP(pin_programmed, MP_MAX_IOAPIC_PIN + 1);
876} mp_ioapic_routing[MAX_IO_APICS];
Alexey Starikovskiy11113f82008-05-14 19:02:57 +0400877
878static int mp_find_ioapic(int gsi)
879{
880 int i = 0;
881
882 /* Find the IOAPIC that manages this GSI. */
883 for (i = 0; i < nr_ioapics; i++) {
884 if ((gsi >= mp_ioapic_routing[i].gsi_base)
885 && (gsi <= mp_ioapic_routing[i].gsi_end))
886 return i;
887 }
888
889 printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi);
890 return -1;
891}
892
893static u8 __init uniq_ioapic_id(u8 id)
894{
895#ifdef CONFIG_X86_32
896 if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
897 !APIC_XAPIC(apic_version[boot_cpu_physical_apicid]))
898 return io_apic_get_unique_id(nr_ioapics, id);
899 else
900 return id;
901#else
902 int i;
903 DECLARE_BITMAP(used, 256);
904 bitmap_zero(used, 256);
905 for (i = 0; i < nr_ioapics; i++) {
Alexey Starikovskiyec2cd0a2008-05-14 19:03:10 +0400906 struct mp_config_ioapic *ia = &mp_ioapics[i];
907 __set_bit(ia->mp_apicid, used);
Alexey Starikovskiy11113f82008-05-14 19:02:57 +0400908 }
909 if (!test_bit(id, used))
910 return id;
911 return find_first_zero_bit(used, 256);
912#endif
913}
914
915static int bad_ioapic(unsigned long address)
916{
917 if (nr_ioapics >= MAX_IO_APICS) {
918 printk(KERN_ERR "ERROR: Max # of I/O APICs (%d) exceeded "
919 "(found %d)\n", MAX_IO_APICS, nr_ioapics);
920 panic("Recompile kernel with bigger MAX_IO_APICS!\n");
921 }
922 if (!address) {
923 printk(KERN_ERR "WARNING: Bogus (zero) I/O APIC address"
924 " found in table, skipping!\n");
925 return 1;
926 }
927 return 0;
928}
929
930void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)
931{
932 int idx = 0;
933
934 if (bad_ioapic(address))
935 return;
936
937 idx = nr_ioapics;
938
Alexey Starikovskiyec2cd0a2008-05-14 19:03:10 +0400939 mp_ioapics[idx].mp_type = MP_IOAPIC;
940 mp_ioapics[idx].mp_flags = MPC_APIC_USABLE;
941 mp_ioapics[idx].mp_apicaddr = address;
Alexey Starikovskiy11113f82008-05-14 19:02:57 +0400942
943 set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
Alexey Starikovskiyec2cd0a2008-05-14 19:03:10 +0400944 mp_ioapics[idx].mp_apicid = uniq_ioapic_id(id);
Alexey Starikovskiy11113f82008-05-14 19:02:57 +0400945#ifdef CONFIG_X86_32
Alexey Starikovskiyec2cd0a2008-05-14 19:03:10 +0400946 mp_ioapics[idx].mp_apicver = io_apic_get_version(idx);
Alexey Starikovskiy11113f82008-05-14 19:02:57 +0400947#else
Alexey Starikovskiyec2cd0a2008-05-14 19:03:10 +0400948 mp_ioapics[idx].mp_apicver = 0;
Alexey Starikovskiy11113f82008-05-14 19:02:57 +0400949#endif
950 /*
951 * Build basic GSI lookup table to facilitate gsi->io_apic lookups
952 * and to prevent reprogramming of IOAPIC pins (PCI GSIs).
953 */
Alexey Starikovskiyec2cd0a2008-05-14 19:03:10 +0400954 mp_ioapic_routing[idx].apic_id = mp_ioapics[idx].mp_apicid;
Alexey Starikovskiy11113f82008-05-14 19:02:57 +0400955 mp_ioapic_routing[idx].gsi_base = gsi_base;
956 mp_ioapic_routing[idx].gsi_end = gsi_base +
957 io_apic_get_redir_entries(idx);
958
Alexey Starikovskiyec2cd0a2008-05-14 19:03:10 +0400959 printk(KERN_INFO "IOAPIC[%d]: apic_id %d, version %d, address 0x%lx, "
960 "GSI %d-%d\n", idx, mp_ioapics[idx].mp_apicid,
961 mp_ioapics[idx].mp_apicver, mp_ioapics[idx].mp_apicaddr,
Alexey Starikovskiy11113f82008-05-14 19:02:57 +0400962 mp_ioapic_routing[idx].gsi_base, mp_ioapic_routing[idx].gsi_end);
963
964 nr_ioapics++;
965}
966
Yinghai Lufcfa1462008-06-18 17:29:31 -0700967static void assign_to_mp_irq(struct mp_config_intsrc *m,
968 struct mp_config_intsrc *mp_irq)
969{
970 memcpy(mp_irq, m, sizeof(struct mp_config_intsrc));
971}
972
973static int mp_irq_cmp(struct mp_config_intsrc *mp_irq,
974 struct mp_config_intsrc *m)
975{
976 return memcmp(mp_irq, m, sizeof(struct mp_config_intsrc));
977}
978
979static void save_mp_irq(struct mp_config_intsrc *m)
980{
981 int i;
982
983 for (i = 0; i < mp_irq_entries; i++) {
984 if (!mp_irq_cmp(&mp_irqs[i], m))
985 return;
986 }
987
988 assign_to_mp_irq(m, &mp_irqs[mp_irq_entries]);
989 if (++mp_irq_entries == MAX_IRQ_SOURCES)
990 panic("Max # of irq sources exceeded!!\n");
991}
992
Alexey Starikovskiy11113f82008-05-14 19:02:57 +0400993void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi)
994{
Yinghai Lu6df88092008-06-15 18:19:46 -0700995 int ioapic;
996 int pin;
Yinghai Lufcfa1462008-06-18 17:29:31 -0700997 struct mp_config_intsrc mp_irq;
Alexey Starikovskiy11113f82008-05-14 19:02:57 +0400998
999 /*
1000 * Convert 'gsi' to 'ioapic.pin'.
1001 */
1002 ioapic = mp_find_ioapic(gsi);
1003 if (ioapic < 0)
1004 return;
1005 pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
1006
1007 /*
1008 * TBD: This check is for faulty timer entries, where the override
1009 * erroneously sets the trigger to level, resulting in a HUGE
1010 * increase of timer interrupts!
1011 */
1012 if ((bus_irq == 0) && (trigger == 3))
1013 trigger = 1;
1014
Yinghai Lufcfa1462008-06-18 17:29:31 -07001015 mp_irq.mp_type = MP_INTSRC;
1016 mp_irq.mp_irqtype = mp_INT;
1017 mp_irq.mp_irqflag = (trigger << 2) | polarity;
1018 mp_irq.mp_srcbus = MP_ISA_BUS;
1019 mp_irq.mp_srcbusirq = bus_irq; /* IRQ */
1020 mp_irq.mp_dstapic = mp_ioapics[ioapic].mp_apicid; /* APIC ID */
1021 mp_irq.mp_dstirq = pin; /* INTIN# */
Alexey Starikovskiy11113f82008-05-14 19:02:57 +04001022
Yinghai Lufcfa1462008-06-18 17:29:31 -07001023 save_mp_irq(&mp_irq);
Alexey Starikovskiy11113f82008-05-14 19:02:57 +04001024}
1025
1026void __init mp_config_acpi_legacy_irqs(void)
1027{
Yinghai Lu6df88092008-06-15 18:19:46 -07001028 int i;
1029 int ioapic;
1030 unsigned int dstapic;
Yinghai Lufcfa1462008-06-18 17:29:31 -07001031 struct mp_config_intsrc mp_irq;
Alexey Starikovskiy11113f82008-05-14 19:02:57 +04001032
1033#if defined (CONFIG_MCA) || defined (CONFIG_EISA)
1034 /*
1035 * Fabricate the legacy ISA bus (bus #31).
1036 */
1037 mp_bus_id_to_type[MP_ISA_BUS] = MP_BUS_ISA;
1038#endif
1039 set_bit(MP_ISA_BUS, mp_bus_not_pci);
Thomas Gleixnercfc1b9a2008-07-21 21:35:38 +02001040 pr_debug("Bus #%d is ISA\n", MP_ISA_BUS);
Alexey Starikovskiy11113f82008-05-14 19:02:57 +04001041
Yinghai Lud49c4282008-06-08 18:31:54 -07001042#ifdef CONFIG_X86_ES7000
Alexey Starikovskiy11113f82008-05-14 19:02:57 +04001043 /*
1044 * Older generations of ES7000 have no legacy identity mappings
1045 */
1046 if (es7000_plat == 1)
1047 return;
1048#endif
1049
1050 /*
1051 * Locate the IOAPIC that manages the ISA IRQs (0-15).
1052 */
1053 ioapic = mp_find_ioapic(0);
1054 if (ioapic < 0)
1055 return;
Yinghai Lu6df88092008-06-15 18:19:46 -07001056 dstapic = mp_ioapics[ioapic].mp_apicid;
Alexey Starikovskiy11113f82008-05-14 19:02:57 +04001057
Alexey Starikovskiy11113f82008-05-14 19:02:57 +04001058 /*
1059 * Use the default configuration for the IRQs 0-15. Unless
1060 * overridden by (MADT) interrupt source override entries.
1061 */
1062 for (i = 0; i < 16; i++) {
1063 int idx;
1064
1065 for (idx = 0; idx < mp_irq_entries; idx++) {
Alexey Starikovskiy2fddb6e282008-05-14 19:03:17 +04001066 struct mp_config_intsrc *irq = mp_irqs + idx;
Alexey Starikovskiy11113f82008-05-14 19:02:57 +04001067
1068 /* Do we already have a mapping for this ISA IRQ? */
Alexey Starikovskiy2fddb6e282008-05-14 19:03:17 +04001069 if (irq->mp_srcbus == MP_ISA_BUS
1070 && irq->mp_srcbusirq == i)
Alexey Starikovskiy11113f82008-05-14 19:02:57 +04001071 break;
1072
1073 /* Do we already have a mapping for this IOAPIC pin */
Yinghai Lu6df88092008-06-15 18:19:46 -07001074 if (irq->mp_dstapic == dstapic &&
1075 irq->mp_dstirq == i)
Alexey Starikovskiy11113f82008-05-14 19:02:57 +04001076 break;
1077 }
1078
1079 if (idx != mp_irq_entries) {
1080 printk(KERN_DEBUG "ACPI: IRQ%d used by override.\n", i);
1081 continue; /* IRQ already used */
1082 }
1083
Yinghai Lufcfa1462008-06-18 17:29:31 -07001084 mp_irq.mp_type = MP_INTSRC;
1085 mp_irq.mp_irqflag = 0; /* Conforming */
1086 mp_irq.mp_srcbus = MP_ISA_BUS;
1087 mp_irq.mp_dstapic = dstapic;
1088 mp_irq.mp_irqtype = mp_INT;
1089 mp_irq.mp_srcbusirq = i; /* Identity mapped */
1090 mp_irq.mp_dstirq = i;
Alexey Starikovskiy11113f82008-05-14 19:02:57 +04001091
Yinghai Lufcfa1462008-06-18 17:29:31 -07001092 save_mp_irq(&mp_irq);
Alexey Starikovskiy11113f82008-05-14 19:02:57 +04001093 }
1094}
1095
1096int mp_register_gsi(u32 gsi, int triggering, int polarity)
1097{
1098 int ioapic;
1099 int ioapic_pin;
1100#ifdef CONFIG_X86_32
1101#define MAX_GSI_NUM 4096
1102#define IRQ_COMPRESSION_START 64
1103
1104 static int pci_irq = IRQ_COMPRESSION_START;
1105 /*
1106 * Mapping between Global System Interrupts, which
1107 * represent all possible interrupts, and IRQs
1108 * assigned to actual devices.
1109 */
1110 static int gsi_to_irq[MAX_GSI_NUM];
1111#else
1112
1113 if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
1114 return gsi;
1115#endif
1116
1117 /* Don't set up the ACPI SCI because it's already set up */
1118 if (acpi_gbl_FADT.sci_interrupt == gsi)
1119 return gsi;
1120
1121 ioapic = mp_find_ioapic(gsi);
1122 if (ioapic < 0) {
1123 printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi);
1124 return gsi;
1125 }
1126
1127 ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
1128
1129#ifdef CONFIG_X86_32
1130 if (ioapic_renumber_irq)
1131 gsi = ioapic_renumber_irq(ioapic, gsi);
1132#endif
1133
1134 /*
1135 * Avoid pin reprogramming. PRTs typically include entries
1136 * with redundant pin->gsi mappings (but unique PCI devices);
1137 * we only program the IOAPIC on the first.
1138 */
1139 if (ioapic_pin > MP_MAX_IOAPIC_PIN) {
1140 printk(KERN_ERR "Invalid reference to IOAPIC pin "
1141 "%d-%d\n", mp_ioapic_routing[ioapic].apic_id,
1142 ioapic_pin);
1143 return gsi;
1144 }
1145 if (test_bit(ioapic_pin, mp_ioapic_routing[ioapic].pin_programmed)) {
Thomas Gleixnercfc1b9a2008-07-21 21:35:38 +02001146 pr_debug(KERN_DEBUG "Pin %d-%d already programmed\n",
1147 mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
Alexey Starikovskiy11113f82008-05-14 19:02:57 +04001148#ifdef CONFIG_X86_32
1149 return (gsi < IRQ_COMPRESSION_START ? gsi : gsi_to_irq[gsi]);
1150#else
1151 return gsi;
1152#endif
1153 }
1154
1155 set_bit(ioapic_pin, mp_ioapic_routing[ioapic].pin_programmed);
1156#ifdef CONFIG_X86_32
1157 /*
1158 * For GSI >= 64, use IRQ compression
1159 */
1160 if ((gsi >= IRQ_COMPRESSION_START)
1161 && (triggering == ACPI_LEVEL_SENSITIVE)) {
1162 /*
1163 * For PCI devices assign IRQs in order, avoiding gaps
1164 * due to unused I/O APIC pins.
1165 */
1166 int irq = gsi;
1167 if (gsi < MAX_GSI_NUM) {
1168 /*
1169 * Retain the VIA chipset work-around (gsi > 15), but
1170 * avoid a problem where the 8254 timer (IRQ0) is setup
1171 * via an override (so it's not on pin 0 of the ioapic),
1172 * and at the same time, the pin 0 interrupt is a PCI
1173 * type. The gsi > 15 test could cause these two pins
1174 * to be shared as IRQ0, and they are not shareable.
1175 * So test for this condition, and if necessary, avoid
1176 * the pin collision.
1177 */
1178 gsi = pci_irq++;
1179 /*
1180 * Don't assign IRQ used by ACPI SCI
1181 */
1182 if (gsi == acpi_gbl_FADT.sci_interrupt)
1183 gsi = pci_irq++;
1184 gsi_to_irq[irq] = gsi;
1185 } else {
1186 printk(KERN_ERR "GSI %u is too high\n", gsi);
1187 return gsi;
1188 }
1189 }
1190#endif
1191 io_apic_set_pci_routing(ioapic, ioapic_pin, gsi,
1192 triggering == ACPI_EDGE_SENSITIVE ? 0 : 1,
1193 polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
1194 return gsi;
1195}
1196
Yinghai Lu2944e162008-06-01 13:17:38 -07001197int mp_config_acpi_gsi(unsigned char number, unsigned int devfn, u8 pin,
1198 u32 gsi, int triggering, int polarity)
1199{
Yinghai Lufcfa1462008-06-18 17:29:31 -07001200#ifdef CONFIG_X86_MPPARSE
1201 struct mp_config_intsrc mp_irq;
Yinghai Lu2944e162008-06-01 13:17:38 -07001202 int ioapic;
1203
Yinghai Lufcfa1462008-06-18 17:29:31 -07001204 if (!acpi_ioapic)
Yinghai Lud867e532008-06-14 01:26:41 -07001205 return 0;
1206
Yinghai Lu2944e162008-06-01 13:17:38 -07001207 /* print the entry should happen on mptable identically */
Yinghai Lufcfa1462008-06-18 17:29:31 -07001208 mp_irq.mp_type = MP_INTSRC;
1209 mp_irq.mp_irqtype = mp_INT;
1210 mp_irq.mp_irqflag = (triggering == ACPI_EDGE_SENSITIVE ? 4 : 0x0c) |
Yinghai Lu2944e162008-06-01 13:17:38 -07001211 (polarity == ACPI_ACTIVE_HIGH ? 1 : 3);
Yinghai Lufcfa1462008-06-18 17:29:31 -07001212 mp_irq.mp_srcbus = number;
1213 mp_irq.mp_srcbusirq = (((devfn >> 3) & 0x1f) << 2) | ((pin - 1) & 3);
Yinghai Lu2944e162008-06-01 13:17:38 -07001214 ioapic = mp_find_ioapic(gsi);
Yinghai Lufcfa1462008-06-18 17:29:31 -07001215 mp_irq.mp_dstapic = mp_ioapic_routing[ioapic].apic_id;
1216 mp_irq.mp_dstirq = gsi - mp_ioapic_routing[ioapic].gsi_base;
Yinghai Lu2944e162008-06-01 13:17:38 -07001217
Yinghai Lufcfa1462008-06-18 17:29:31 -07001218 save_mp_irq(&mp_irq);
1219#endif
Yinghai Lu2944e162008-06-01 13:17:38 -07001220 return 0;
1221}
1222
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223/*
1224 * Parse IOAPIC related entries in MADT
1225 * returns 0 on success, < 0 on error
1226 */
Len Brown4be44fc2005-08-05 00:44:28 -04001227static int __init acpi_parse_madt_ioapic_entries(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228{
1229 int count;
1230
1231 /*
1232 * ACPI interpreter is required to complete interrupt setup,
1233 * so if it is off, don't enumerate the io-apics with ACPI.
1234 * If MPS is present, it will handle them,
1235 * otherwise the system will stay in PIC mode
1236 */
1237 if (acpi_disabled || acpi_noirq) {
1238 return -ENODEV;
Len Brown4be44fc2005-08-05 00:44:28 -04001239 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +03001241 if (!cpu_has_apic)
Andi Kleend3b6a342006-04-07 19:49:39 +02001242 return -ENODEV;
1243
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 /*
Len Brown4be44fc2005-08-05 00:44:28 -04001245 * if "noapic" boot option, don't look for IO-APICs
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 */
1247 if (skip_ioapic_setup) {
1248 printk(KERN_INFO PREFIX "Skipping IOAPIC probe "
Len Brown4be44fc2005-08-05 00:44:28 -04001249 "due to 'noapic' option.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 return -ENODEV;
1251 }
1252
Len Brown4be44fc2005-08-05 00:44:28 -04001253 count =
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +03001254 acpi_table_parse_madt(ACPI_MADT_TYPE_IO_APIC, acpi_parse_ioapic,
Len Brown4be44fc2005-08-05 00:44:28 -04001255 MAX_IO_APICS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 if (!count) {
1257 printk(KERN_ERR PREFIX "No IOAPIC entries present\n");
1258 return -ENODEV;
Len Brown4be44fc2005-08-05 00:44:28 -04001259 } else if (count < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 printk(KERN_ERR PREFIX "Error parsing IOAPIC entry\n");
1261 return count;
1262 }
1263
Len Brown4be44fc2005-08-05 00:44:28 -04001264 count =
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +03001265 acpi_table_parse_madt(ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, acpi_parse_int_src_ovr,
Len Brown4be44fc2005-08-05 00:44:28 -04001266 NR_IRQ_VECTORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 if (count < 0) {
Len Brown4be44fc2005-08-05 00:44:28 -04001268 printk(KERN_ERR PREFIX
1269 "Error parsing interrupt source overrides entry\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 /* TBD: Cleanup to allow fallback to MPS */
1271 return count;
1272 }
1273
1274 /*
1275 * If BIOS did not supply an INT_SRC_OVR for the SCI
1276 * pretend we got one so we can set the SCI flags.
1277 */
1278 if (!acpi_sci_override_gsi)
Alexey Starikovskiycee324b2007-02-02 19:48:22 +03001279 acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280
1281 /* Fill in identity legacy mapings where no override */
1282 mp_config_acpi_legacy_irqs();
1283
Len Brown4be44fc2005-08-05 00:44:28 -04001284 count =
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +03001285 acpi_table_parse_madt(ACPI_MADT_TYPE_NMI_SOURCE, acpi_parse_nmi_src,
Len Brown4be44fc2005-08-05 00:44:28 -04001286 NR_IRQ_VECTORS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 if (count < 0) {
1288 printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
1289 /* TBD: Cleanup to allow fallback to MPS */
1290 return count;
1291 }
1292
1293 return 0;
1294}
1295#else
1296static inline int acpi_parse_madt_ioapic_entries(void)
1297{
1298 return -1;
1299}
Len Brown84663612005-08-24 12:09:07 -04001300#endif /* !CONFIG_X86_IO_APIC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301
Yinghai Lucbf9bd62008-02-19 03:21:06 -08001302static void __init early_acpi_process_madt(void)
1303{
1304#ifdef CONFIG_X86_LOCAL_APIC
1305 int error;
1306
1307 if (!acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt)) {
1308
1309 /*
1310 * Parse MADT LAPIC entries
1311 */
1312 error = early_acpi_parse_madt_lapic_addr_ovr();
1313 if (!error) {
1314 acpi_lapic = 1;
1315 smp_found_config = 1;
1316 }
1317 if (error == -EINVAL) {
1318 /*
1319 * Dell Precision Workstation 410, 610 come here.
1320 */
1321 printk(KERN_ERR PREFIX
1322 "Invalid BIOS MADT, disabling ACPI\n");
1323 disable_acpi();
1324 }
1325 }
1326#endif
1327}
1328
Len Brown4be44fc2005-08-05 00:44:28 -04001329static void __init acpi_process_madt(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330{
1331#ifdef CONFIG_X86_LOCAL_APIC
Len Brown7f8f97c2007-02-10 21:28:03 -05001332 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333
Len Brown7f8f97c2007-02-10 21:28:03 -05001334 if (!acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335
1336 /*
1337 * Parse MADT LAPIC entries
1338 */
1339 error = acpi_parse_madt_lapic_entries();
1340 if (!error) {
1341 acpi_lapic = 1;
1342
Venkatesh Pallipadi911a62d2005-09-03 15:56:31 -07001343#ifdef CONFIG_X86_GENERICARCH
1344 generic_bigsmp_probe();
1345#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 /*
1347 * Parse MADT IO-APIC entries
1348 */
1349 error = acpi_parse_madt_ioapic_entries();
1350 if (!error) {
1351 acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
1352 acpi_irq_balance_set(NULL);
1353 acpi_ioapic = 1;
1354
1355 smp_found_config = 1;
Ingo Molnar3c43f032007-05-02 19:27:04 +02001356 setup_apic_routing();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 }
1358 }
1359 if (error == -EINVAL) {
1360 /*
1361 * Dell Precision Workstation 410, 610 come here.
1362 */
Len Brown4be44fc2005-08-05 00:44:28 -04001363 printk(KERN_ERR PREFIX
1364 "Invalid BIOS MADT, disabling ACPI\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 disable_acpi();
1366 }
1367 }
1368#endif
1369 return;
1370}
1371
Jeff Garzik18552562007-10-03 15:15:40 -04001372static int __init disable_acpi_irq(const struct dmi_system_id *d)
Andrey Paninaea00142005-06-25 14:54:42 -07001373{
1374 if (!acpi_force) {
1375 printk(KERN_NOTICE "%s detected: force use of acpi=noirq\n",
1376 d->ident);
1377 acpi_noirq_set();
1378 }
1379 return 0;
1380}
1381
Jeff Garzik18552562007-10-03 15:15:40 -04001382static int __init disable_acpi_pci(const struct dmi_system_id *d)
Andrey Paninaea00142005-06-25 14:54:42 -07001383{
1384 if (!acpi_force) {
1385 printk(KERN_NOTICE "%s detected: force use of pci=noacpi\n",
1386 d->ident);
1387 acpi_disable_pci();
1388 }
1389 return 0;
1390}
Andrey Paninaea00142005-06-25 14:54:42 -07001391
Jeff Garzik18552562007-10-03 15:15:40 -04001392static int __init dmi_disable_acpi(const struct dmi_system_id *d)
Andrey Paninaea00142005-06-25 14:54:42 -07001393{
1394 if (!acpi_force) {
Len Brown4be44fc2005-08-05 00:44:28 -04001395 printk(KERN_NOTICE "%s detected: acpi off\n", d->ident);
Andrey Paninaea00142005-06-25 14:54:42 -07001396 disable_acpi();
1397 } else {
1398 printk(KERN_NOTICE
1399 "Warning: DMI blacklist says broken, but acpi forced\n");
1400 }
1401 return 0;
1402}
1403
1404/*
1405 * Limit ACPI to CPU enumeration for HT
1406 */
Jeff Garzik18552562007-10-03 15:15:40 -04001407static int __init force_acpi_ht(const struct dmi_system_id *d)
Andrey Paninaea00142005-06-25 14:54:42 -07001408{
1409 if (!acpi_force) {
Len Brown4be44fc2005-08-05 00:44:28 -04001410 printk(KERN_NOTICE "%s detected: force use of acpi=ht\n",
1411 d->ident);
Andrey Paninaea00142005-06-25 14:54:42 -07001412 disable_acpi();
1413 acpi_ht = 1;
1414 } else {
1415 printk(KERN_NOTICE
1416 "Warning: acpi=force overrules DMI blacklist: acpi=ht\n");
1417 }
1418 return 0;
1419}
1420
1421/*
Rafael J. Wysockie2079c42008-07-08 16:12:26 +02001422 * Force ignoring BIOS IRQ0 pin2 override
1423 */
1424static int __init dmi_ignore_irq0_timer_override(const struct dmi_system_id *d)
1425{
1426 pr_notice("%s detected: Ignoring BIOS IRQ0 pin2 override\n", d->ident);
1427 acpi_skip_timer_override = 1;
Rafael J. Wysockie2079c42008-07-08 16:12:26 +02001428 return 0;
1429}
1430
1431/*
Andrey Paninaea00142005-06-25 14:54:42 -07001432 * If your system is blacklisted here, but you find that acpi=force
1433 * works for you, please contact acpi-devel@sourceforge.net
1434 */
1435static struct dmi_system_id __initdata acpi_dmi_table[] = {
1436 /*
1437 * Boxes that need ACPI disabled
1438 */
1439 {
Len Brown4be44fc2005-08-05 00:44:28 -04001440 .callback = dmi_disable_acpi,
1441 .ident = "IBM Thinkpad",
1442 .matches = {
1443 DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
1444 DMI_MATCH(DMI_BOARD_NAME, "2629H1G"),
1445 },
1446 },
Andrey Paninaea00142005-06-25 14:54:42 -07001447
1448 /*
1449 * Boxes that need acpi=ht
1450 */
1451 {
Len Brown4be44fc2005-08-05 00:44:28 -04001452 .callback = force_acpi_ht,
1453 .ident = "FSC Primergy T850",
1454 .matches = {
1455 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
1456 DMI_MATCH(DMI_PRODUCT_NAME, "PRIMERGY T850"),
1457 },
1458 },
Andrey Paninaea00142005-06-25 14:54:42 -07001459 {
Len Brown4be44fc2005-08-05 00:44:28 -04001460 .callback = force_acpi_ht,
Len Brown4be44fc2005-08-05 00:44:28 -04001461 .ident = "HP VISUALIZE NT Workstation",
1462 .matches = {
1463 DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
1464 DMI_MATCH(DMI_PRODUCT_NAME, "HP VISUALIZE NT Workstation"),
1465 },
1466 },
Andrey Paninaea00142005-06-25 14:54:42 -07001467 {
Len Brown4be44fc2005-08-05 00:44:28 -04001468 .callback = force_acpi_ht,
1469 .ident = "Compaq Workstation W8000",
1470 .matches = {
1471 DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
1472 DMI_MATCH(DMI_PRODUCT_NAME, "Workstation W8000"),
1473 },
1474 },
Andrey Paninaea00142005-06-25 14:54:42 -07001475 {
Len Brown4be44fc2005-08-05 00:44:28 -04001476 .callback = force_acpi_ht,
1477 .ident = "ASUS P4B266",
1478 .matches = {
1479 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
1480 DMI_MATCH(DMI_BOARD_NAME, "P4B266"),
1481 },
1482 },
Andrey Paninaea00142005-06-25 14:54:42 -07001483 {
Len Brown4be44fc2005-08-05 00:44:28 -04001484 .callback = force_acpi_ht,
1485 .ident = "ASUS P2B-DS",
1486 .matches = {
1487 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
1488 DMI_MATCH(DMI_BOARD_NAME, "P2B-DS"),
1489 },
1490 },
Andrey Paninaea00142005-06-25 14:54:42 -07001491 {
Len Brown4be44fc2005-08-05 00:44:28 -04001492 .callback = force_acpi_ht,
1493 .ident = "ASUS CUR-DLS",
1494 .matches = {
1495 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
1496 DMI_MATCH(DMI_BOARD_NAME, "CUR-DLS"),
1497 },
1498 },
Andrey Paninaea00142005-06-25 14:54:42 -07001499 {
Len Brown4be44fc2005-08-05 00:44:28 -04001500 .callback = force_acpi_ht,
1501 .ident = "ABIT i440BX-W83977",
1502 .matches = {
1503 DMI_MATCH(DMI_BOARD_VENDOR, "ABIT <http://www.abit.com>"),
1504 DMI_MATCH(DMI_BOARD_NAME, "i440BX-W83977 (BP6)"),
1505 },
1506 },
Andrey Paninaea00142005-06-25 14:54:42 -07001507 {
Len Brown4be44fc2005-08-05 00:44:28 -04001508 .callback = force_acpi_ht,
1509 .ident = "IBM Bladecenter",
1510 .matches = {
1511 DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
1512 DMI_MATCH(DMI_BOARD_NAME, "IBM eServer BladeCenter HS20"),
1513 },
1514 },
Andrey Paninaea00142005-06-25 14:54:42 -07001515 {
Len Brown4be44fc2005-08-05 00:44:28 -04001516 .callback = force_acpi_ht,
1517 .ident = "IBM eServer xSeries 360",
1518 .matches = {
1519 DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
1520 DMI_MATCH(DMI_BOARD_NAME, "eServer xSeries 360"),
1521 },
1522 },
Andrey Paninaea00142005-06-25 14:54:42 -07001523 {
Len Brown4be44fc2005-08-05 00:44:28 -04001524 .callback = force_acpi_ht,
1525 .ident = "IBM eserver xSeries 330",
1526 .matches = {
1527 DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
1528 DMI_MATCH(DMI_BOARD_NAME, "eserver xSeries 330"),
1529 },
1530 },
Andrey Paninaea00142005-06-25 14:54:42 -07001531 {
Len Brown4be44fc2005-08-05 00:44:28 -04001532 .callback = force_acpi_ht,
1533 .ident = "IBM eserver xSeries 440",
1534 .matches = {
1535 DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
1536 DMI_MATCH(DMI_PRODUCT_NAME, "eserver xSeries 440"),
1537 },
1538 },
Andrey Paninaea00142005-06-25 14:54:42 -07001539
Andrey Paninaea00142005-06-25 14:54:42 -07001540 /*
1541 * Boxes that need ACPI PCI IRQ routing disabled
1542 */
1543 {
Len Brown4be44fc2005-08-05 00:44:28 -04001544 .callback = disable_acpi_irq,
1545 .ident = "ASUS A7V",
1546 .matches = {
1547 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC"),
1548 DMI_MATCH(DMI_BOARD_NAME, "<A7V>"),
1549 /* newer BIOS, Revision 1011, does work */
1550 DMI_MATCH(DMI_BIOS_VERSION,
1551 "ASUS A7V ACPI BIOS Revision 1007"),
1552 },
1553 },
Len Brown74586fc2007-03-08 02:48:30 -05001554 {
1555 /*
1556 * Latest BIOS for IBM 600E (1.16) has bad pcinum
1557 * for LPC bridge, which is needed for the PCI
1558 * interrupt links to work. DSDT fix is in bug 5966.
1559 * 2645, 2646 model numbers are shared with 600/600E/600X
1560 */
1561 .callback = disable_acpi_irq,
1562 .ident = "IBM Thinkpad 600 Series 2645",
1563 .matches = {
1564 DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
1565 DMI_MATCH(DMI_BOARD_NAME, "2645"),
1566 },
1567 },
1568 {
1569 .callback = disable_acpi_irq,
1570 .ident = "IBM Thinkpad 600 Series 2646",
1571 .matches = {
1572 DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
1573 DMI_MATCH(DMI_BOARD_NAME, "2646"),
1574 },
1575 },
Andrey Paninaea00142005-06-25 14:54:42 -07001576 /*
1577 * Boxes that need ACPI PCI IRQ routing and PCI scan disabled
1578 */
Len Brown4be44fc2005-08-05 00:44:28 -04001579 { /* _BBN 0 bug */
1580 .callback = disable_acpi_pci,
1581 .ident = "ASUS PR-DLS",
1582 .matches = {
1583 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
1584 DMI_MATCH(DMI_BOARD_NAME, "PR-DLS"),
1585 DMI_MATCH(DMI_BIOS_VERSION,
1586 "ASUS PR-DLS ACPI BIOS Revision 1010"),
1587 DMI_MATCH(DMI_BIOS_DATE, "03/21/2003")
1588 },
1589 },
Andrey Paninaea00142005-06-25 14:54:42 -07001590 {
Len Brown4be44fc2005-08-05 00:44:28 -04001591 .callback = disable_acpi_pci,
1592 .ident = "Acer TravelMate 36x Laptop",
1593 .matches = {
1594 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
1595 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
1596 },
1597 },
Matthew Garrett9340e1c2008-07-01 01:12:06 +01001598 /*
1599 * HP laptops which use a DSDT reporting as HP/SB400/10000,
1600 * which includes some code which overrides all temperature
1601 * trip points to 16C if the INTIN2 input of the I/O APIC
1602 * is enabled. This input is incorrectly designated the
1603 * ISA IRQ 0 via an interrupt source override even though
1604 * it is wired to the output of the master 8259A and INTIN0
Rafael J. Wysockie2079c42008-07-08 16:12:26 +02001605 * is not connected at all. Force ignoring BIOS IRQ0 pin2
1606 * override in that cases.
1607 */
1608 {
1609 .callback = dmi_ignore_irq0_timer_override,
Rafael J. Wysockie84956f2008-10-06 11:59:29 +02001610 .ident = "HP nx6115 laptop",
1611 .matches = {
1612 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
1613 DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6115"),
1614 },
1615 },
1616 {
1617 .callback = dmi_ignore_irq0_timer_override,
Rafael J. Wysockie2079c42008-07-08 16:12:26 +02001618 .ident = "HP NX6125 laptop",
1619 .matches = {
1620 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
1621 DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6125"),
1622 },
1623 },
1624 {
1625 .callback = dmi_ignore_irq0_timer_override,
1626 .ident = "HP NX6325 laptop",
1627 .matches = {
1628 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
1629 DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6325"),
1630 },
1631 },
Rafael J. Wysockie84956f2008-10-06 11:59:29 +02001632 {
1633 .callback = dmi_ignore_irq0_timer_override,
1634 .ident = "HP 6715b laptop",
1635 .matches = {
1636 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
1637 DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 6715b"),
1638 },
1639 },
Len Brown4be44fc2005-08-05 00:44:28 -04001640 {}
Andrey Paninaea00142005-06-25 14:54:42 -07001641};
1642
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643/*
1644 * acpi_boot_table_init() and acpi_boot_init()
1645 * called from setup_arch(), always.
1646 * 1. checksums all tables
1647 * 2. enumerates lapics
1648 * 3. enumerates io-apics
1649 *
1650 * acpi_table_init() is separate to allow reading SRAT without
1651 * other side effects.
1652 *
1653 * side effects of acpi_boot_init:
1654 * acpi_lapic = 1 if LAPIC found
1655 * acpi_ioapic = 1 if IOAPIC found
1656 * if (acpi_lapic && acpi_ioapic) smp_found_config = 1;
1657 * if acpi_blacklisted() acpi_disabled = 1;
1658 * acpi_irq_model=...
1659 * ...
1660 *
1661 * return value: (currently ignored)
1662 * 0: success
1663 * !0: failure
1664 */
1665
Len Brown4be44fc2005-08-05 00:44:28 -04001666int __init acpi_boot_table_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667{
1668 int error;
1669
Andrey Paninaea00142005-06-25 14:54:42 -07001670 dmi_check_system(acpi_dmi_table);
Andrey Paninaea00142005-06-25 14:54:42 -07001671
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 /*
1673 * If acpi_disabled, bail out
1674 * One exception: acpi=ht continues far enough to enumerate LAPICs
1675 */
1676 if (acpi_disabled && !acpi_ht)
Len Brown4be44fc2005-08-05 00:44:28 -04001677 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +03001679 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 * Initialize the ACPI boot-time table parser.
1681 */
1682 error = acpi_table_init();
1683 if (error) {
1684 disable_acpi();
1685 return error;
1686 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +03001688 acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
1690 /*
1691 * blacklist may disable ACPI entirely
1692 */
1693 error = acpi_blacklisted();
1694 if (error) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 if (acpi_force) {
1696 printk(KERN_WARNING PREFIX "acpi=force override\n");
1697 } else {
1698 printk(KERN_WARNING PREFIX "Disabling ACPI support\n");
1699 disable_acpi();
1700 return error;
1701 }
1702 }
1703
1704 return 0;
1705}
1706
Yinghai Lucbf9bd62008-02-19 03:21:06 -08001707int __init early_acpi_boot_init(void)
1708{
1709 /*
1710 * If acpi_disabled, bail out
1711 * One exception: acpi=ht continues far enough to enumerate LAPICs
1712 */
1713 if (acpi_disabled && !acpi_ht)
1714 return 1;
1715
1716 /*
1717 * Process the Multiple APIC Description Table (MADT), if present
1718 */
1719 early_acpi_process_madt();
1720
1721 return 0;
1722}
1723
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724int __init acpi_boot_init(void)
1725{
1726 /*
1727 * If acpi_disabled, bail out
1728 * One exception: acpi=ht continues far enough to enumerate LAPICs
1729 */
1730 if (acpi_disabled && !acpi_ht)
Len Brown4be44fc2005-08-05 00:44:28 -04001731 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +03001733 acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734
1735 /*
1736 * set sci_int and PM timer address
1737 */
Alexey Starikovskiyceb6c462007-02-02 19:48:22 +03001738 acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739
1740 /*
1741 * Process the Multiple APIC Description Table (MADT), if present
1742 */
1743 acpi_process_madt();
1744
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +03001745 acpi_table_parse(ACPI_SIG_HPET, acpi_parse_hpet);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746
1747 return 0;
1748}
Rusty Russell1a3f2392006-09-26 10:52:32 +02001749
1750static int __init parse_acpi(char *arg)
1751{
1752 if (!arg)
1753 return -EINVAL;
1754
1755 /* "acpi=off" disables both ACPI table parsing and interpreter */
1756 if (strcmp(arg, "off") == 0) {
1757 disable_acpi();
1758 }
1759 /* acpi=force to over-ride black-list */
1760 else if (strcmp(arg, "force") == 0) {
1761 acpi_force = 1;
1762 acpi_ht = 1;
1763 acpi_disabled = 0;
1764 }
1765 /* acpi=strict disables out-of-spec workarounds */
1766 else if (strcmp(arg, "strict") == 0) {
1767 acpi_strict = 1;
1768 }
1769 /* Limit ACPI just to boot-time to enable HT */
1770 else if (strcmp(arg, "ht") == 0) {
1771 if (!acpi_force)
1772 disable_acpi();
1773 acpi_ht = 1;
1774 }
1775 /* "acpi=noirq" disables ACPI interrupt routing */
1776 else if (strcmp(arg, "noirq") == 0) {
1777 acpi_noirq_set();
1778 } else {
1779 /* Core will printk when we return error. */
1780 return -EINVAL;
1781 }
1782 return 0;
1783}
1784early_param("acpi", parse_acpi);
1785
1786/* FIXME: Using pci= for an ACPI parameter is a travesty. */
1787static int __init parse_pci(char *arg)
1788{
1789 if (arg && strcmp(arg, "noacpi") == 0)
1790 acpi_disable_pci();
1791 return 0;
1792}
1793early_param("pci", parse_pci);
1794
Yinghai Lu3c999f12008-06-20 16:11:20 -07001795int __init acpi_mps_check(void)
1796{
1797#if defined(CONFIG_X86_LOCAL_APIC) && !defined(CONFIG_X86_MPPARSE)
1798/* mptable code is not built-in*/
1799 if (acpi_disabled || acpi_noirq) {
1800 printk(KERN_WARNING "MPS support code is not built-in.\n"
1801 "Using acpi=off or acpi=noirq or pci=noacpi "
1802 "may have problem\n");
1803 return 1;
1804 }
1805#endif
1806 return 0;
1807}
1808
Rusty Russell1a3f2392006-09-26 10:52:32 +02001809#ifdef CONFIG_X86_IO_APIC
1810static int __init parse_acpi_skip_timer_override(char *arg)
1811{
1812 acpi_skip_timer_override = 1;
1813 return 0;
1814}
1815early_param("acpi_skip_timer_override", parse_acpi_skip_timer_override);
Andi Kleenfa18f472006-11-14 16:57:46 +01001816
1817static int __init parse_acpi_use_timer_override(char *arg)
1818{
1819 acpi_use_timer_override = 1;
1820 return 0;
1821}
1822early_param("acpi_use_timer_override", parse_acpi_use_timer_override);
Rusty Russell1a3f2392006-09-26 10:52:32 +02001823#endif /* CONFIG_X86_IO_APIC */
1824
1825static int __init setup_acpi_sci(char *s)
1826{
1827 if (!s)
1828 return -EINVAL;
1829 if (!strcmp(s, "edge"))
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +03001830 acpi_sci_flags = ACPI_MADT_TRIGGER_EDGE |
1831 (acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK);
Rusty Russell1a3f2392006-09-26 10:52:32 +02001832 else if (!strcmp(s, "level"))
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +03001833 acpi_sci_flags = ACPI_MADT_TRIGGER_LEVEL |
1834 (acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK);
Rusty Russell1a3f2392006-09-26 10:52:32 +02001835 else if (!strcmp(s, "high"))
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +03001836 acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_HIGH |
1837 (acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK);
Rusty Russell1a3f2392006-09-26 10:52:32 +02001838 else if (!strcmp(s, "low"))
Alexey Starikovskiy5f3b1a82007-02-02 19:48:22 +03001839 acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_LOW |
1840 (acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK);
Rusty Russell1a3f2392006-09-26 10:52:32 +02001841 else
1842 return -EINVAL;
1843 return 0;
1844}
1845early_param("acpi_sci", setup_acpi_sci);
Andrew Mortond0a90812006-10-20 14:30:27 -07001846
1847int __acpi_acquire_global_lock(unsigned int *lock)
1848{
1849 unsigned int old, new, val;
1850 do {
1851 old = *lock;
1852 new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1));
1853 val = cmpxchg(lock, old, new);
1854 } while (unlikely (val != old));
1855 return (new < 3) ? -1 : 0;
1856}
1857
1858int __acpi_release_global_lock(unsigned int *lock)
1859{
1860 unsigned int old, new, val;
1861 do {
1862 old = *lock;
1863 new = old & ~0x3;
1864 val = cmpxchg(lock, old, new);
1865 } while (unlikely (val != old));
1866 return old & 0x1;
1867}