1/*
2 *  acpi_tables.c - ACPI Boot-Time Table Parsing
3 *
4 *  Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
5 *
6 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 *
8 *  This program is free software; you can redistribute it and/or modify
9 *  it under the terms of the GNU General Public License as published by
10 *  the Free Software Foundation; either version 2 of the License, or
11 *  (at your option) any later version.
12 *
13 *  This program is distributed in the hope that it will be useful,
14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *  GNU General Public License for more details.
17 *
18 *  You should have received a copy of the GNU General Public License
19 *  along with this program; if not, write to the Free Software
20 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 *
22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 *
24 */
25
26#include <linux/init.h>
27#include <linux/kernel.h>
28#include <linux/smp.h>
29#include <linux/string.h>
30#include <linux/types.h>
31#include <linux/irq.h>
32#include <linux/errno.h>
33#include <linux/acpi.h>
34#include <linux/bootmem.h>
35
36#define PREFIX			"ACPI: "
37
38#define ACPI_MAX_TABLES		128
39
40static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" };
41static char *mps_inti_flags_trigger[] = { "dfl", "edge", "res", "level" };
42
43static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata;
44
45static int acpi_apic_instance __initdata;
46
47void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
48{
49	if (!header)
50		return;
51
52	switch (header->type) {
53
54	case ACPI_MADT_TYPE_LOCAL_APIC:
55		{
56			struct acpi_madt_local_apic *p =
57			    (struct acpi_madt_local_apic *)header;
58			printk(KERN_INFO PREFIX
59			       "LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n",
60			       p->processor_id, p->id,
61			       (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
62		}
63		break;
64
65	case ACPI_MADT_TYPE_IO_APIC:
66		{
67			struct acpi_madt_io_apic *p =
68			    (struct acpi_madt_io_apic *)header;
69			printk(KERN_INFO PREFIX
70			       "IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n",
71			       p->id, p->address, p->global_irq_base);
72		}
73		break;
74
75	case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE:
76		{
77			struct acpi_madt_interrupt_override *p =
78			    (struct acpi_madt_interrupt_override *)header;
79			printk(KERN_INFO PREFIX
80			       "INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n",
81			       p->bus, p->source_irq, p->global_irq,
82			       mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
83			       mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2]);
84			if (p->inti_flags  &
85			    ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK))
86				printk(KERN_INFO PREFIX
87				       "INT_SRC_OVR unexpected reserved flags: 0x%x\n",
88				       p->inti_flags  &
89					~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK));
90
91		}
92		break;
93
94	case ACPI_MADT_TYPE_NMI_SOURCE:
95		{
96			struct acpi_madt_nmi_source *p =
97			    (struct acpi_madt_nmi_source *)header;
98			printk(KERN_INFO PREFIX
99			       "NMI_SRC (%s %s global_irq %d)\n",
100			       mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
101			       mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
102			       p->global_irq);
103		}
104		break;
105
106	case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
107		{
108			struct acpi_madt_local_apic_nmi *p =
109			    (struct acpi_madt_local_apic_nmi *)header;
110			printk(KERN_INFO PREFIX
111			       "LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n",
112			       p->processor_id,
113			       mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK	],
114			       mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
115			       p->lint);
116		}
117		break;
118
119	case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE:
120		{
121			struct acpi_madt_local_apic_override *p =
122			    (struct acpi_madt_local_apic_override *)header;
123			printk(KERN_INFO PREFIX
124			       "LAPIC_ADDR_OVR (address[%p])\n",
125			       (void *)(unsigned long)p->address);
126		}
127		break;
128
129	case ACPI_MADT_TYPE_IO_SAPIC:
130		{
131			struct acpi_madt_io_sapic *p =
132			    (struct acpi_madt_io_sapic *)header;
133			printk(KERN_INFO PREFIX
134			       "IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n",
135			       p->id, (void *)(unsigned long)p->address,
136			       p->global_irq_base);
137		}
138		break;
139
140	case ACPI_MADT_TYPE_LOCAL_SAPIC:
141		{
142			struct acpi_madt_local_sapic *p =
143			    (struct acpi_madt_local_sapic *)header;
144			printk(KERN_INFO PREFIX
145			       "LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n",
146			       p->processor_id, p->id, p->eid,
147			       (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
148		}
149		break;
150
151	case ACPI_MADT_TYPE_INTERRUPT_SOURCE:
152		{
153			struct acpi_madt_interrupt_source *p =
154			    (struct acpi_madt_interrupt_source *)header;
155			printk(KERN_INFO PREFIX
156			       "PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n",
157			       mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
158			       mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
159			       p->type, p->id, p->eid, p->io_sapic_vector,
160			       p->global_irq);
161		}
162		break;
163
164	default:
165		printk(KERN_WARNING PREFIX
166		       "Found unsupported MADT entry (type = 0x%x)\n",
167		       header->type);
168		break;
169	}
170}
171
172
173int __init
174acpi_table_parse_entries(char *id,
175			     unsigned long table_size,
176			     int entry_id,
177			     acpi_table_entry_handler handler,
178			     unsigned int max_entries)
179{
180	struct acpi_table_header *table_header = NULL;
181	struct acpi_subtable_header *entry;
182	unsigned int count = 0;
183	unsigned long table_end;
184
185	if (!handler)
186		return -EINVAL;
187
188	if (strncmp(id, ACPI_SIG_MADT, 4) == 0)
189		acpi_get_table(id, acpi_apic_instance, &table_header);
190	else
191		acpi_get_table(id, 0, &table_header);
192
193	if (!table_header) {
194		printk(KERN_WARNING PREFIX "%4.4s not present\n", id);
195		return -ENODEV;
196	}
197
198	table_end = (unsigned long)table_header + table_header->length;
199
200	/* Parse all entries looking for a match. */
201
202	entry = (struct acpi_subtable_header *)
203	    ((unsigned long)table_header + table_size);
204
205	while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) <
206	       table_end) {
207		if (entry->type == entry_id
208		    && (!max_entries || count++ < max_entries))
209			if (handler(entry, table_end))
210				return -EINVAL;
211
212		entry = (struct acpi_subtable_header *)
213		    ((unsigned long)entry + entry->length);
214	}
215	if (max_entries && count > max_entries) {
216		printk(KERN_WARNING PREFIX "[%4.4s:0x%02x] ignored %i entries of "
217		       "%i found\n", id, entry_id, count - max_entries, count);
218	}
219
220	return count;
221}
222
223int __init
224acpi_table_parse_madt(enum acpi_madt_type id,
225		      acpi_table_entry_handler handler, unsigned int max_entries)
226{
227	return acpi_table_parse_entries(ACPI_SIG_MADT,
228					    sizeof(struct acpi_table_madt), id,
229					    handler, max_entries);
230}
231
232/**
233 * acpi_table_parse - find table with @id, run @handler on it
234 *
235 * @id: table id to find
236 * @handler: handler to run
237 *
238 * Scan the ACPI System Descriptor Table (STD) for a table matching @id,
239 * run @handler on it.  Return 0 if table found, return on if not.
240 */
241int __init acpi_table_parse(char *id, acpi_table_handler handler)
242{
243	struct acpi_table_header *table = NULL;
244
245	if (!handler)
246		return -EINVAL;
247
248	if (strncmp(id, ACPI_SIG_MADT, 4) == 0)
249		acpi_get_table(id, acpi_apic_instance, &table);
250	else
251		acpi_get_table(id, 0, &table);
252
253	if (table) {
254		handler(table);
255		return 0;
256	} else
257		return 1;
258}
259
260/*
261 * The BIOS is supposed to supply a single APIC/MADT,
262 * but some report two.  Provide a knob to use either.
263 * (don't you wish instance 0 and 1 were not the same?)
264 */
265static void __init check_multiple_madt(void)
266{
267	struct acpi_table_header *table = NULL;
268
269	acpi_get_table(ACPI_SIG_MADT, 2, &table);
270	if (table) {
271		printk(KERN_WARNING PREFIX
272		       "BIOS bug: multiple APIC/MADT found,"
273		       " using %d\n", acpi_apic_instance);
274		printk(KERN_WARNING PREFIX
275		       "If \"acpi_apic_instance=%d\" works better, "
276		       "notify linux-acpi@vger.kernel.org\n",
277		       acpi_apic_instance ? 0 : 2);
278
279	} else
280		acpi_apic_instance = 0;
281
282	return;
283}
284
285/*
286 * acpi_table_init()
287 *
288 * find RSDP, find and checksum SDT/XSDT.
289 * checksum all tables, print SDT/XSDT
290 *
291 * result: sdt_entry[] is initialized
292 */
293
294int __init acpi_table_init(void)
295{
296	acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0);
297	check_multiple_madt();
298	return 0;
299}
300
301static int __init acpi_parse_apic_instance(char *str)
302{
303
304	acpi_apic_instance = simple_strtoul(str, NULL, 0);
305
306	printk(KERN_NOTICE PREFIX "Shall use APIC/MADT table %d\n",
307	       acpi_apic_instance);
308
309	return 0;
310}
311
312early_param("acpi_apic_instance", acpi_parse_apic_instance);
313