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 | |
| 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>
| -rw-r--r-- | drivers/acpi/processor_core.c | 123 | ||||
| -rw-r--r-- | include/linux/acpi.h | 4 |
2 files changed, 118 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 */ | ||
diff --git a/include/linux/acpi.h b/include/linux/acpi.h index e53822148b6a..24c7aa8b1d20 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h | |||
| @@ -152,6 +152,10 @@ int acpi_map_cpu(acpi_handle handle, int physid, int *pcpu); | |||
| 152 | int acpi_unmap_cpu(int cpu); | 152 | int acpi_unmap_cpu(int cpu); |
| 153 | #endif /* CONFIG_ACPI_HOTPLUG_CPU */ | 153 | #endif /* CONFIG_ACPI_HOTPLUG_CPU */ |
| 154 | 154 | ||
| 155 | #ifdef CONFIG_ACPI_HOTPLUG_IOAPIC | ||
| 156 | int acpi_get_ioapic_id(acpi_handle handle, u32 gsi_base, u64 *phys_addr); | ||
| 157 | #endif | ||
| 158 | |||
| 155 | int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base); | 159 | int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base); |
| 156 | int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base); | 160 | int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base); |
| 157 | int acpi_ioapic_registered(acpi_handle handle, u32 gsi_base); | 161 | int acpi_ioapic_registered(acpi_handle handle, u32 gsi_base); |
