diff options
author | Yinghai Lu <yinghai@kernel.org> | 2015-02-05 00:44:48 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-02-05 09:09:26 -0500 |
commit | ecf5636dcd59cd5508641f995cc4c2bafedbb995 (patch) | |
tree | 8d89bf96bf84e988d1635af8d695772592a223dc /drivers | |
parent | b4b55cda587442477a3a9f0669e26bba4b7800c0 (diff) |
ACPI: Add interfaces to parse IOAPIC ID for IOAPIC hotplug
We need to parse APIC ID for IOAPIC registration for IOAPIC hotplug.
ACPI _MAT method and MADT table are used to figure out IOAPIC ID, just
like parsing CPU APIC ID for CPU hotplug.
[ tglx: Fixed docbook comment ]
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Len Brown <lenb@kernel.org>
Link: http://lkml.kernel.org/r/1414387308-27148-8-git-send-email-jiang.liu@linux.intel.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/acpi/processor_core.c | 123 |
1 files changed, 114 insertions, 9 deletions
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 02e48394276c..7962651cdbd4 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c | |||
@@ -4,6 +4,10 @@ | |||
4 | * | 4 | * |
5 | * Alex Chiang <achiang@hp.com> | 5 | * Alex Chiang <achiang@hp.com> |
6 | * - Unified x86/ia64 implementations | 6 | * - Unified x86/ia64 implementations |
7 | * | ||
8 | * I/O APIC hotplug support | ||
9 | * Yinghai Lu <yinghai@kernel.org> | ||
10 | * Jiang Liu <jiang.liu@intel.com> | ||
7 | */ | 11 | */ |
8 | #include <linux/export.h> | 12 | #include <linux/export.h> |
9 | #include <linux/acpi.h> | 13 | #include <linux/acpi.h> |
@@ -12,6 +16,21 @@ | |||
12 | #define _COMPONENT ACPI_PROCESSOR_COMPONENT | 16 | #define _COMPONENT ACPI_PROCESSOR_COMPONENT |
13 | ACPI_MODULE_NAME("processor_core"); | 17 | ACPI_MODULE_NAME("processor_core"); |
14 | 18 | ||
19 | static struct acpi_table_madt *get_madt_table(void) | ||
20 | { | ||
21 | static struct acpi_table_madt *madt; | ||
22 | static int read_madt; | ||
23 | |||
24 | if (!read_madt) { | ||
25 | if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, | ||
26 | (struct acpi_table_header **)&madt))) | ||
27 | madt = NULL; | ||
28 | read_madt++; | ||
29 | } | ||
30 | |||
31 | return madt; | ||
32 | } | ||
33 | |||
15 | static int map_lapic_id(struct acpi_subtable_header *entry, | 34 | static int map_lapic_id(struct acpi_subtable_header *entry, |
16 | u32 acpi_id, int *apic_id) | 35 | u32 acpi_id, int *apic_id) |
17 | { | 36 | { |
@@ -67,17 +86,10 @@ static int map_lsapic_id(struct acpi_subtable_header *entry, | |||
67 | static int map_madt_entry(int type, u32 acpi_id) | 86 | static int map_madt_entry(int type, u32 acpi_id) |
68 | { | 87 | { |
69 | unsigned long madt_end, entry; | 88 | unsigned long madt_end, entry; |
70 | static struct acpi_table_madt *madt; | ||
71 | static int read_madt; | ||
72 | int phys_id = -1; /* CPU hardware ID */ | 89 | int phys_id = -1; /* CPU hardware ID */ |
90 | struct acpi_table_madt *madt; | ||
73 | 91 | ||
74 | if (!read_madt) { | 92 | madt = get_madt_table(); |
75 | if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, | ||
76 | (struct acpi_table_header **)&madt))) | ||
77 | madt = NULL; | ||
78 | read_madt++; | ||
79 | } | ||
80 | |||
81 | if (!madt) | 93 | if (!madt) |
82 | return phys_id; | 94 | return phys_id; |
83 | 95 | ||
@@ -203,3 +215,96 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id) | |||
203 | return acpi_map_cpuid(phys_id, acpi_id); | 215 | return acpi_map_cpuid(phys_id, acpi_id); |
204 | } | 216 | } |
205 | EXPORT_SYMBOL_GPL(acpi_get_cpuid); | 217 | EXPORT_SYMBOL_GPL(acpi_get_cpuid); |
218 | |||
219 | #ifdef CONFIG_ACPI_HOTPLUG_IOAPIC | ||
220 | static int get_ioapic_id(struct acpi_subtable_header *entry, u32 gsi_base, | ||
221 | u64 *phys_addr, int *ioapic_id) | ||
222 | { | ||
223 | struct acpi_madt_io_apic *ioapic = (struct acpi_madt_io_apic *)entry; | ||
224 | |||
225 | if (ioapic->global_irq_base != gsi_base) | ||
226 | return 0; | ||
227 | |||
228 | *phys_addr = ioapic->address; | ||
229 | *ioapic_id = ioapic->id; | ||
230 | return 1; | ||
231 | } | ||
232 | |||
233 | static int parse_madt_ioapic_entry(u32 gsi_base, u64 *phys_addr) | ||
234 | { | ||
235 | struct acpi_subtable_header *hdr; | ||
236 | unsigned long madt_end, entry; | ||
237 | struct acpi_table_madt *madt; | ||
238 | int apic_id = -1; | ||
239 | |||
240 | madt = get_madt_table(); | ||
241 | if (!madt) | ||
242 | return apic_id; | ||
243 | |||
244 | entry = (unsigned long)madt; | ||
245 | madt_end = entry + madt->header.length; | ||
246 | |||
247 | /* Parse all entries looking for a match. */ | ||
248 | entry += sizeof(struct acpi_table_madt); | ||
249 | while (entry + sizeof(struct acpi_subtable_header) < madt_end) { | ||
250 | hdr = (struct acpi_subtable_header *)entry; | ||
251 | if (hdr->type == ACPI_MADT_TYPE_IO_APIC && | ||
252 | get_ioapic_id(hdr, gsi_base, phys_addr, &apic_id)) | ||
253 | break; | ||
254 | else | ||
255 | entry += hdr->length; | ||
256 | } | ||
257 | |||
258 | return apic_id; | ||
259 | } | ||
260 | |||
261 | static int parse_mat_ioapic_entry(acpi_handle handle, u32 gsi_base, | ||
262 | u64 *phys_addr) | ||
263 | { | ||
264 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
265 | struct acpi_subtable_header *header; | ||
266 | union acpi_object *obj; | ||
267 | int apic_id = -1; | ||
268 | |||
269 | if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer))) | ||
270 | goto exit; | ||
271 | |||
272 | if (!buffer.length || !buffer.pointer) | ||
273 | goto exit; | ||
274 | |||
275 | obj = buffer.pointer; | ||
276 | if (obj->type != ACPI_TYPE_BUFFER || | ||
277 | obj->buffer.length < sizeof(struct acpi_subtable_header)) | ||
278 | goto exit; | ||
279 | |||
280 | header = (struct acpi_subtable_header *)obj->buffer.pointer; | ||
281 | if (header->type == ACPI_MADT_TYPE_IO_APIC) | ||
282 | get_ioapic_id(header, gsi_base, phys_addr, &apic_id); | ||
283 | |||
284 | exit: | ||
285 | kfree(buffer.pointer); | ||
286 | return apic_id; | ||
287 | } | ||
288 | |||
289 | /** | ||
290 | * acpi_get_ioapic_id - Get IOAPIC ID and physical address matching @gsi_base | ||
291 | * @handle: ACPI object for IOAPIC device | ||
292 | * @gsi_base: GSI base to match with | ||
293 | * @phys_addr: Pointer to store physical address of matching IOAPIC record | ||
294 | * | ||
295 | * Walk resources returned by ACPI_MAT method, then ACPI MADT table, to search | ||
296 | * for an ACPI IOAPIC record matching @gsi_base. | ||
297 | * Return IOAPIC id and store physical address in @phys_addr if found a match, | ||
298 | * otherwise return <0. | ||
299 | */ | ||
300 | int acpi_get_ioapic_id(acpi_handle handle, u32 gsi_base, u64 *phys_addr) | ||
301 | { | ||
302 | int apic_id; | ||
303 | |||
304 | apic_id = parse_mat_ioapic_entry(handle, gsi_base, phys_addr); | ||
305 | if (apic_id == -1) | ||
306 | apic_id = parse_madt_ioapic_entry(gsi_base, phys_addr); | ||
307 | |||
308 | return apic_id; | ||
309 | } | ||
310 | #endif /* CONFIG_ACPI_HOTPLUG_IOAPIC */ | ||