diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/acpi/processor_core.c | 126 |
1 files changed, 114 insertions, 12 deletions
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 1b6bc662b3ac..6893c0bffb5a 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c | |||
@@ -375,30 +375,126 @@ static int acpi_processor_remove_fs(struct acpi_device *device) | |||
375 | } | 375 | } |
376 | 376 | ||
377 | /* Use the acpiid in MADT to map cpus in case of SMP */ | 377 | /* Use the acpiid in MADT to map cpus in case of SMP */ |
378 | |||
378 | #ifndef CONFIG_SMP | 379 | #ifndef CONFIG_SMP |
379 | #define convert_acpiid_to_cpu(acpi_id) (-1) | 380 | #define convert_acpiid_to_cpu(acpi_id) (-1) |
380 | #else | 381 | #else |
381 | 382 | ||
383 | static struct acpi_table_madt *madt; | ||
384 | |||
385 | static int map_lapic_id(struct acpi_subtable_header *entry, | ||
386 | u32 acpi_id, int *apic_id) | ||
387 | { | ||
388 | struct acpi_madt_local_apic *lapic = | ||
389 | (struct acpi_madt_local_apic *)entry; | ||
390 | if ((lapic->lapic_flags & ACPI_MADT_ENABLED) && | ||
391 | lapic->processor_id == acpi_id) { | ||
392 | *apic_id = lapic->id; | ||
393 | return 1; | ||
394 | } | ||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | static int map_lsapic_id(struct acpi_subtable_header *entry, | ||
399 | u32 acpi_id, int *apic_id) | ||
400 | { | ||
401 | struct acpi_madt_local_sapic *lsapic = | ||
402 | (struct acpi_madt_local_sapic *)entry; | ||
403 | /* Only check enabled APICs*/ | ||
404 | if (lsapic->lapic_flags & ACPI_MADT_ENABLED) { | ||
405 | /* First check against id */ | ||
406 | if (lsapic->processor_id == acpi_id) { | ||
407 | *apic_id = lsapic->id; | ||
408 | return 1; | ||
409 | /* Check against optional uid */ | ||
410 | } else if (entry->length >= 16 && | ||
411 | lsapic->uid == acpi_id) { | ||
412 | *apic_id = lsapic->uid; | ||
413 | return 1; | ||
414 | } | ||
415 | } | ||
416 | return 0; | ||
417 | } | ||
418 | |||
382 | #ifdef CONFIG_IA64 | 419 | #ifdef CONFIG_IA64 |
383 | #define arch_acpiid_to_apicid ia64_acpiid_to_sapicid | ||
384 | #define arch_cpu_to_apicid ia64_cpu_to_sapicid | 420 | #define arch_cpu_to_apicid ia64_cpu_to_sapicid |
385 | #define ARCH_BAD_APICID (0xffff) | ||
386 | #else | 421 | #else |
387 | #define arch_acpiid_to_apicid x86_acpiid_to_apicid | ||
388 | #define arch_cpu_to_apicid x86_cpu_to_apicid | 422 | #define arch_cpu_to_apicid x86_cpu_to_apicid |
389 | #define ARCH_BAD_APICID (0xff) | ||
390 | #endif | 423 | #endif |
391 | 424 | ||
392 | static int convert_acpiid_to_cpu(u8 acpi_id) | 425 | static int map_madt_entry(u32 acpi_id) |
426 | { | ||
427 | unsigned long madt_end, entry; | ||
428 | int apic_id = -1; | ||
429 | |||
430 | if (!madt) | ||
431 | return apic_id; | ||
432 | |||
433 | entry = (unsigned long)madt; | ||
434 | madt_end = entry + madt->header.length; | ||
435 | |||
436 | /* Parse all entries looking for a match. */ | ||
437 | |||
438 | entry += sizeof(struct acpi_table_madt); | ||
439 | while (entry + sizeof(struct acpi_subtable_header) < madt_end) { | ||
440 | struct acpi_subtable_header *header = | ||
441 | (struct acpi_subtable_header *)entry; | ||
442 | if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) { | ||
443 | if (map_lapic_id(header, acpi_id, &apic_id)) | ||
444 | break; | ||
445 | } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) { | ||
446 | if (map_lsapic_id(header, acpi_id, &apic_id)) | ||
447 | break; | ||
448 | } | ||
449 | entry += header->length; | ||
450 | } | ||
451 | return apic_id; | ||
452 | } | ||
453 | |||
454 | static int map_mat_entry(acpi_handle handle, u32 acpi_id) | ||
455 | { | ||
456 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
457 | union acpi_object *obj; | ||
458 | struct acpi_subtable_header *header; | ||
459 | int apic_id = -1; | ||
460 | |||
461 | if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer))) | ||
462 | goto exit; | ||
463 | |||
464 | if (!buffer.length || !buffer.pointer) | ||
465 | goto exit; | ||
466 | |||
467 | obj = buffer.pointer; | ||
468 | if (obj->type != ACPI_TYPE_BUFFER || | ||
469 | obj->buffer.length < sizeof(struct acpi_subtable_header)) { | ||
470 | goto exit; | ||
471 | } | ||
472 | |||
473 | header = (struct acpi_subtable_header *)obj->buffer.pointer; | ||
474 | if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) { | ||
475 | map_lapic_id(header, acpi_id, &apic_id); | ||
476 | } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) { | ||
477 | map_lsapic_id(header, acpi_id, &apic_id); | ||
478 | } | ||
479 | |||
480 | exit: | ||
481 | if (buffer.pointer) | ||
482 | kfree(buffer.pointer); | ||
483 | return apic_id; | ||
484 | } | ||
485 | |||
486 | static int get_apic_id(acpi_handle handle, u32 acpi_id) | ||
393 | { | 487 | { |
394 | u16 apic_id; | ||
395 | int i; | 488 | int i; |
489 | int apic_id = -1; | ||
396 | 490 | ||
397 | apic_id = arch_acpiid_to_apicid[acpi_id]; | 491 | apic_id = map_mat_entry(handle, acpi_id); |
398 | if (apic_id == ARCH_BAD_APICID) | 492 | if (apic_id == -1) |
399 | return -1; | 493 | apic_id = map_madt_entry(acpi_id); |
494 | if (apic_id == -1) | ||
495 | return apic_id; | ||
400 | 496 | ||
401 | for (i = 0; i < NR_CPUS; i++) { | 497 | for (i = 0; i < NR_CPUS; ++i) { |
402 | if (arch_cpu_to_apicid[i] == apic_id) | 498 | if (arch_cpu_to_apicid[i] == apic_id) |
403 | return i; | 499 | return i; |
404 | } | 500 | } |
@@ -456,7 +552,7 @@ static int acpi_processor_get_info(struct acpi_processor *pr) | |||
456 | */ | 552 | */ |
457 | pr->acpi_id = object.processor.proc_id; | 553 | pr->acpi_id = object.processor.proc_id; |
458 | 554 | ||
459 | cpu_index = convert_acpiid_to_cpu(pr->acpi_id); | 555 | cpu_index = get_apic_id(pr->handle, pr->acpi_id); |
460 | 556 | ||
461 | /* Handle UP system running SMP kernel, with no LAPIC in MADT */ | 557 | /* Handle UP system running SMP kernel, with no LAPIC in MADT */ |
462 | if (!cpu0_initialized && (cpu_index == -1) && | 558 | if (!cpu0_initialized && (cpu_index == -1) && |
@@ -473,7 +569,7 @@ static int acpi_processor_get_info(struct acpi_processor *pr) | |||
473 | * less than the max # of CPUs. They should be ignored _iff | 569 | * less than the max # of CPUs. They should be ignored _iff |
474 | * they are physically not present. | 570 | * they are physically not present. |
475 | */ | 571 | */ |
476 | if (cpu_index == -1) { | 572 | if (pr->id == -1) { |
477 | if (ACPI_FAILURE | 573 | if (ACPI_FAILURE |
478 | (acpi_processor_hotadd_init(pr->handle, &pr->id))) { | 574 | (acpi_processor_hotadd_init(pr->handle, &pr->id))) { |
479 | return -ENODEV; | 575 | return -ENODEV; |
@@ -895,6 +991,12 @@ static int __init acpi_processor_init(void) | |||
895 | memset(&processors, 0, sizeof(processors)); | 991 | memset(&processors, 0, sizeof(processors)); |
896 | memset(&errata, 0, sizeof(errata)); | 992 | memset(&errata, 0, sizeof(errata)); |
897 | 993 | ||
994 | #ifdef CONFIG_SMP | ||
995 | if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, | ||
996 | (struct acpi_table_header **)&madt))) | ||
997 | madt = 0; | ||
998 | #endif | ||
999 | |||
898 | acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir); | 1000 | acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir); |
899 | if (!acpi_processor_dir) | 1001 | if (!acpi_processor_dir) |
900 | return -ENOMEM; | 1002 | return -ENOMEM; |