|
9 | 9 | * Copyright (C) 2013, Intel Corporation |
10 | 10 | * Rafael J. Wysocki <rafael.j.wysocki@intel.com> |
11 | 11 | */ |
| 12 | +#define pr_fmt(fmt) "ACPI: " fmt |
12 | 13 |
|
13 | 14 | #include <linux/acpi.h> |
14 | 15 | #include <linux/device.h> |
| 16 | +#include <linux/dmi.h> |
15 | 17 | #include <linux/kernel.h> |
16 | 18 | #include <linux/module.h> |
17 | 19 | #include <linux/pci.h> |
|
21 | 23 |
|
22 | 24 | #include <asm/cpu.h> |
23 | 25 |
|
| 26 | +#include <xen/xen.h> |
| 27 | + |
24 | 28 | #include "internal.h" |
25 | 29 |
|
26 | 30 | DEFINE_PER_CPU(struct acpi_processor *, processors); |
@@ -508,54 +512,110 @@ static void acpi_processor_remove(struct acpi_device *device) |
508 | 512 | } |
509 | 513 | #endif /* CONFIG_ACPI_HOTPLUG_CPU */ |
510 | 514 |
|
511 | | -#ifdef CONFIG_X86 |
512 | | -static bool acpi_hwp_native_thermal_lvt_set; |
513 | | -static acpi_status __init acpi_hwp_native_thermal_lvt_osc(acpi_handle handle, |
514 | | - u32 lvl, |
515 | | - void *context, |
516 | | - void **rv) |
| 515 | +#ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC |
| 516 | +bool __init processor_physically_present(acpi_handle handle) |
| 517 | +{ |
| 518 | + int cpuid, type; |
| 519 | + u32 acpi_id; |
| 520 | + acpi_status status; |
| 521 | + acpi_object_type acpi_type; |
| 522 | + unsigned long long tmp; |
| 523 | + union acpi_object object = {}; |
| 524 | + struct acpi_buffer buffer = { sizeof(union acpi_object), &object }; |
| 525 | + |
| 526 | + status = acpi_get_type(handle, &acpi_type); |
| 527 | + if (ACPI_FAILURE(status)) |
| 528 | + return false; |
| 529 | + |
| 530 | + switch (acpi_type) { |
| 531 | + case ACPI_TYPE_PROCESSOR: |
| 532 | + status = acpi_evaluate_object(handle, NULL, NULL, &buffer); |
| 533 | + if (ACPI_FAILURE(status)) |
| 534 | + return false; |
| 535 | + acpi_id = object.processor.proc_id; |
| 536 | + break; |
| 537 | + case ACPI_TYPE_DEVICE: |
| 538 | + status = acpi_evaluate_integer(handle, METHOD_NAME__UID, |
| 539 | + NULL, &tmp); |
| 540 | + if (ACPI_FAILURE(status)) |
| 541 | + return false; |
| 542 | + acpi_id = tmp; |
| 543 | + break; |
| 544 | + default: |
| 545 | + return false; |
| 546 | + } |
| 547 | + |
| 548 | + if (xen_initial_domain()) |
| 549 | + /* |
| 550 | + * When running as a Xen dom0 the number of processors Linux |
| 551 | + * sees can be different from the real number of processors on |
| 552 | + * the system, and we still need to execute _PDC or _OSC for |
| 553 | + * all of them. |
| 554 | + */ |
| 555 | + return xen_processor_present(acpi_id); |
| 556 | + |
| 557 | + type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0; |
| 558 | + cpuid = acpi_get_cpuid(handle, type, acpi_id); |
| 559 | + |
| 560 | + return !invalid_logical_cpuid(cpuid); |
| 561 | +} |
| 562 | + |
| 563 | +/* vendor specific UUID indicating an Intel platform */ |
| 564 | +static u8 sb_uuid_str[] = "4077A616-290C-47BE-9EBD-D87058713953"; |
| 565 | + |
| 566 | +static acpi_status __init acpi_processor_osc(acpi_handle handle, u32 lvl, |
| 567 | + void *context, void **rv) |
517 | 568 | { |
518 | | - u8 sb_uuid_str[] = "4077A616-290C-47BE-9EBD-D87058713953"; |
519 | | - u32 capbuf[2]; |
| 569 | + u32 capbuf[2] = {}; |
520 | 570 | struct acpi_osc_context osc_context = { |
521 | 571 | .uuid_str = sb_uuid_str, |
522 | 572 | .rev = 1, |
523 | 573 | .cap.length = 8, |
524 | 574 | .cap.pointer = capbuf, |
525 | 575 | }; |
| 576 | + acpi_status status; |
526 | 577 |
|
527 | | - if (acpi_hwp_native_thermal_lvt_set) |
528 | | - return AE_CTRL_TERMINATE; |
| 578 | + if (!processor_physically_present(handle)) |
| 579 | + return AE_OK; |
529 | 580 |
|
530 | | - capbuf[0] = 0x0000; |
531 | | - capbuf[1] = 0x1000; /* set bit 12 */ |
| 581 | + arch_acpi_set_proc_cap_bits(&capbuf[OSC_SUPPORT_DWORD]); |
532 | 582 |
|
533 | | - if (ACPI_SUCCESS(acpi_run_osc(handle, &osc_context))) { |
534 | | - if (osc_context.ret.pointer && osc_context.ret.length > 1) { |
535 | | - u32 *capbuf_ret = osc_context.ret.pointer; |
| 583 | + status = acpi_run_osc(handle, &osc_context); |
| 584 | + if (ACPI_FAILURE(status)) |
| 585 | + return status; |
536 | 586 |
|
537 | | - if (capbuf_ret[1] & 0x1000) { |
538 | | - acpi_handle_info(handle, |
539 | | - "_OSC native thermal LVT Acked\n"); |
540 | | - acpi_hwp_native_thermal_lvt_set = true; |
541 | | - } |
542 | | - } |
543 | | - kfree(osc_context.ret.pointer); |
544 | | - } |
| 587 | + kfree(osc_context.ret.pointer); |
545 | 588 |
|
546 | 589 | return AE_OK; |
547 | 590 | } |
548 | 591 |
|
549 | | -void __init acpi_early_processor_osc(void) |
| 592 | +static bool __init acpi_early_processor_osc(void) |
550 | 593 | { |
551 | | - if (boot_cpu_has(X86_FEATURE_HWP)) { |
552 | | - acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, |
553 | | - ACPI_UINT32_MAX, |
554 | | - acpi_hwp_native_thermal_lvt_osc, |
555 | | - NULL, NULL, NULL); |
556 | | - acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID, |
557 | | - acpi_hwp_native_thermal_lvt_osc, |
558 | | - NULL, NULL); |
| 594 | + acpi_status status; |
| 595 | + |
| 596 | + acpi_proc_quirk_mwait_check(); |
| 597 | + |
| 598 | + status = acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, |
| 599 | + ACPI_UINT32_MAX, acpi_processor_osc, NULL, |
| 600 | + NULL, NULL); |
| 601 | + if (ACPI_FAILURE(status)) |
| 602 | + return false; |
| 603 | + |
| 604 | + status = acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID, acpi_processor_osc, |
| 605 | + NULL, NULL); |
| 606 | + if (ACPI_FAILURE(status)) |
| 607 | + return false; |
| 608 | + |
| 609 | + return true; |
| 610 | +} |
| 611 | + |
| 612 | +void __init acpi_early_processor_control_setup(void) |
| 613 | +{ |
| 614 | + if (acpi_early_processor_osc()) { |
| 615 | + pr_info("_OSC evaluated successfully for all CPUs\n"); |
| 616 | + } else { |
| 617 | + pr_info("_OSC evaluation for CPUs failed, trying _PDC\n"); |
| 618 | + acpi_early_processor_set_pdc(); |
559 | 619 | } |
560 | 620 | } |
561 | 621 | #endif |
|
0 commit comments