From 0a0e2ea642f6e4a7fe4953f8f44a310d190c39ba Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 10 Jul 2023 17:03:29 +0300 Subject: [PATCH 01/11] ACPI: processor: Move MWAIT quirk out of acpi_processor.c Commit 2a2a64714d9c ("ACPI: Disable MWAIT via DMI on broken Compal board") introduced a workaround for MWAIT for a specific x86 system. Move the code outside of acpi_processor.c to acpi/x86/ directory for consistency and rename the functions associated with it, so their names start with "acpi_proc_quirk_" to make the goal obvious. No intentional functional impact. Suggested-by: Rafael J. Wysocki Signed-off-by: Michal Wilczynski [ rjw: Subject and changelog edits, two function names changed ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/internal.h | 2 ++ drivers/acpi/processor_pdc.c | 29 +---------------------------- drivers/acpi/x86/utils.c | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index f4148dc50b9c..a5b7ebfd99be 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -153,6 +153,8 @@ int acpi_wakeup_device_init(void); -------------------------------------------------------------------------- */ #ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC void acpi_early_processor_set_pdc(void); + +void acpi_proc_quirk_mwait_check(void); #else static inline void acpi_early_processor_set_pdc(void) {} #endif diff --git a/drivers/acpi/processor_pdc.c b/drivers/acpi/processor_pdc.c index 18fb04523f93..06583cf37365 100644 --- a/drivers/acpi/processor_pdc.c +++ b/drivers/acpi/processor_pdc.c @@ -174,36 +174,9 @@ early_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv) return AE_OK; } -static int __init set_no_mwait(const struct dmi_system_id *id) -{ - pr_notice("%s detected - disabling mwait for CPU C-states\n", - id->ident); - boot_option_idle_override = IDLE_NOMWAIT; - return 0; -} - -static const struct dmi_system_id processor_idle_dmi_table[] __initconst = { - { - set_no_mwait, "Extensa 5220", { - DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_VERSION, "0100"), - DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL}, - {}, -}; - -static void __init processor_dmi_check(void) -{ - /* - * Check whether the system is DMI table. If yes, OSPM - * should not use mwait for CPU-states. - */ - dmi_check_system(processor_idle_dmi_table); -} - void __init acpi_early_processor_set_pdc(void) { - processor_dmi_check(); + acpi_proc_quirk_mwait_check(); acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c index c2b925f8cd4e..63d834dd3811 100644 --- a/drivers/acpi/x86/utils.c +++ b/drivers/acpi/x86/utils.c @@ -518,3 +518,38 @@ bool acpi_quirk_skip_acpi_ac_and_battery(void) return false; } EXPORT_SYMBOL_GPL(acpi_quirk_skip_acpi_ac_and_battery); + +/* This section provides a workaround for a specific x86 system + * which requires disabling of mwait to work correctly. + */ +static int __init acpi_proc_quirk_set_no_mwait(const struct dmi_system_id *id) +{ + pr_notice("%s detected - disabling mwait for CPU C-states\n", + id->ident); + boot_option_idle_override = IDLE_NOMWAIT; + return 0; +} + +static const struct dmi_system_id acpi_proc_quirk_mwait_dmi_table[] __initconst = { + { + .callback = acpi_proc_quirk_set_no_mwait, + .ident = "Extensa 5220", + .matches = { + DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_VERSION, "0100"), + DMI_MATCH(DMI_BOARD_NAME, "Columbia"), + }, + .driver_data = NULL, + }, + {} +}; + +void __init acpi_proc_quirk_mwait_check(void) +{ + /* + * Check whether the system is DMI table. If yes, OSPM + * should not use mwait for CPU-states. + */ + dmi_check_system(acpi_proc_quirk_mwait_dmi_table); +} From 3272a4aadc4c91f1f9518cf6638e7e81f9ac0336 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 10 Jul 2023 17:03:30 +0300 Subject: [PATCH 02/11] ACPI: processor: Move processor_physically_present() to acpi_processor.c Since _PDC method is deprecated and a preferred method of communicating OSPM processor power management capabilities is _OSC, there is a need to move function checking whether processor is present as this logic is not _PDC specific. Move processor_physically_present() to acpi_processor.c. No intentional functional impact. Suggested-by: Rafael J. Wysocki Signed-off-by: Michal Wilczynski [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_processor.c | 52 ++++++++++++++++++++++++++++++++++- drivers/acpi/internal.h | 1 + drivers/acpi/processor_pdc.c | 49 --------------------------------- 3 files changed, 52 insertions(+), 50 deletions(-) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index f9aa02cac6d1..ebb4efd3d0aa 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -21,6 +22,8 @@ #include +#include + #include "internal.h" DEFINE_PER_CPU(struct acpi_processor *, processors); @@ -508,7 +511,54 @@ static void acpi_processor_remove(struct acpi_device *device) } #endif /* CONFIG_ACPI_HOTPLUG_CPU */ -#ifdef CONFIG_X86 +#ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC +bool __init processor_physically_present(acpi_handle handle) +{ + int cpuid, type; + u32 acpi_id; + acpi_status status; + acpi_object_type acpi_type; + unsigned long long tmp; + union acpi_object object = {}; + struct acpi_buffer buffer = { sizeof(union acpi_object), &object }; + + status = acpi_get_type(handle, &acpi_type); + if (ACPI_FAILURE(status)) + return false; + + switch (acpi_type) { + case ACPI_TYPE_PROCESSOR: + status = acpi_evaluate_object(handle, NULL, NULL, &buffer); + if (ACPI_FAILURE(status)) + return false; + acpi_id = object.processor.proc_id; + break; + case ACPI_TYPE_DEVICE: + status = acpi_evaluate_integer(handle, METHOD_NAME__UID, + NULL, &tmp); + if (ACPI_FAILURE(status)) + return false; + acpi_id = tmp; + break; + default: + return false; + } + + if (xen_initial_domain()) + /* + * When running as a Xen dom0 the number of processors Linux + * sees can be different from the real number of processors on + * the system, and we still need to execute _PDC or _OSC for + * all of them. + */ + return xen_processor_present(acpi_id); + + type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0; + cpuid = acpi_get_cpuid(handle, type, acpi_id); + + return !invalid_logical_cpuid(cpuid); +} + static bool acpi_hwp_native_thermal_lvt_set; static acpi_status __init acpi_hwp_native_thermal_lvt_osc(acpi_handle handle, u32 lvl, diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index a5b7ebfd99be..ed2599ae3e83 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -155,6 +155,7 @@ int acpi_wakeup_device_init(void); void acpi_early_processor_set_pdc(void); void acpi_proc_quirk_mwait_check(void); +bool processor_physically_present(acpi_handle handle); #else static inline void acpi_early_processor_set_pdc(void) {} #endif diff --git a/drivers/acpi/processor_pdc.c b/drivers/acpi/processor_pdc.c index 06583cf37365..4c5becd65737 100644 --- a/drivers/acpi/processor_pdc.c +++ b/drivers/acpi/processor_pdc.c @@ -9,61 +9,12 @@ #define pr_fmt(fmt) "ACPI: " fmt -#include #include #include #include -#include - #include "internal.h" -static bool __init processor_physically_present(acpi_handle handle) -{ - int cpuid, type; - u32 acpi_id; - acpi_status status; - acpi_object_type acpi_type; - unsigned long long tmp; - union acpi_object object = { 0 }; - struct acpi_buffer buffer = { sizeof(union acpi_object), &object }; - - status = acpi_get_type(handle, &acpi_type); - if (ACPI_FAILURE(status)) - return false; - - switch (acpi_type) { - case ACPI_TYPE_PROCESSOR: - status = acpi_evaluate_object(handle, NULL, NULL, &buffer); - if (ACPI_FAILURE(status)) - return false; - acpi_id = object.processor.proc_id; - break; - case ACPI_TYPE_DEVICE: - status = acpi_evaluate_integer(handle, "_UID", NULL, &tmp); - if (ACPI_FAILURE(status)) - return false; - acpi_id = tmp; - break; - default: - return false; - } - - if (xen_initial_domain()) - /* - * When running as a Xen dom0 the number of processors Linux - * sees can be different from the real number of processors on - * the system, and we still need to execute _PDC for all of - * them. - */ - return xen_processor_present(acpi_id); - - type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0; - cpuid = acpi_get_cpuid(handle, type, acpi_id); - - return !invalid_logical_cpuid(cpuid); -} - static void acpi_set_pdc_bits(u32 *buf) { buf[0] = ACPI_PDC_REVISION_ID; From c5e4d05db8602acebb532a393f10fb4cc4761467 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 10 Jul 2023 17:03:31 +0300 Subject: [PATCH 03/11] ACPI: processor: Refactor arch_acpi_set_pdc_bits() The capabilities buffer modified by the arch_acpi_set_pdc_bits() is not _PDC-specific, as it can be used by _OSC too. Change the name of that function to better reflect its independence from _PDC and make it take the capabilities buffer address as the argument directly, without any offset, as _OSC and _PDC use different capabilities buffer offsets. No intentional functional impact. Suggested-by: Rafael J. Wysocki Signed-off-by: Michal Wilczynski Reviewed-by: Andy Shevchenko [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- arch/ia64/include/asm/acpi.h | 4 ++-- arch/x86/include/asm/acpi.h | 10 +++++----- drivers/acpi/processor_pdc.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/ia64/include/asm/acpi.h b/arch/ia64/include/asm/acpi.h index 87927eb824cc..43797cb44383 100644 --- a/arch/ia64/include/asm/acpi.h +++ b/arch/ia64/include/asm/acpi.h @@ -69,9 +69,9 @@ extern int __initdata nid_to_pxm_map[MAX_NUMNODES]; #endif static inline bool arch_has_acpi_pdc(void) { return true; } -static inline void arch_acpi_set_pdc_bits(u32 *buf) +static inline void arch_acpi_set_proc_cap_bits(u32 *cap) { - buf[2] |= ACPI_PDC_EST_CAPABILITY_SMP; + *cap |= ACPI_PDC_EST_CAPABILITY_SMP; } #ifdef CONFIG_ACPI_NUMA diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h index 8eb74cf386db..6a498d1781e7 100644 --- a/arch/x86/include/asm/acpi.h +++ b/arch/x86/include/asm/acpi.h @@ -100,23 +100,23 @@ static inline bool arch_has_acpi_pdc(void) c->x86_vendor == X86_VENDOR_CENTAUR); } -static inline void arch_acpi_set_pdc_bits(u32 *buf) +static inline void arch_acpi_set_proc_cap_bits(u32 *cap) { struct cpuinfo_x86 *c = &cpu_data(0); - buf[2] |= ACPI_PDC_C_CAPABILITY_SMP; + *cap |= ACPI_PDC_C_CAPABILITY_SMP; if (cpu_has(c, X86_FEATURE_EST)) - buf[2] |= ACPI_PDC_EST_CAPABILITY_SWSMP; + *cap |= ACPI_PDC_EST_CAPABILITY_SWSMP; if (cpu_has(c, X86_FEATURE_ACPI)) - buf[2] |= ACPI_PDC_T_FFH; + *cap |= ACPI_PDC_T_FFH; /* * If mwait/monitor is unsupported, C2/C3_FFH will be disabled */ if (!cpu_has(c, X86_FEATURE_MWAIT)) - buf[2] &= ~(ACPI_PDC_C_C2C3_FFH); + *cap &= ~(ACPI_PDC_C_C2C3_FFH); } static inline bool acpi_has_cpu_in_madt(void) diff --git a/drivers/acpi/processor_pdc.c b/drivers/acpi/processor_pdc.c index 4c5becd65737..9e7b5ddb9ec2 100644 --- a/drivers/acpi/processor_pdc.c +++ b/drivers/acpi/processor_pdc.c @@ -24,7 +24,7 @@ static void acpi_set_pdc_bits(u32 *buf) buf[2] = ACPI_PDC_SMP_T_SWCOORD; /* Twiddle arch-specific bits needed for _PDC */ - arch_acpi_set_pdc_bits(buf); + arch_acpi_set_proc_cap_bits(&buf[2]); } static struct acpi_object_list *acpi_processor_alloc_pdc(void) From c9e6c5e64f0c00612dc429bc401da0ea673e5130 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 10 Jul 2023 17:03:32 +0300 Subject: [PATCH 04/11] ACPI: processor: Rename ACPI_PDC symbols The prefix in the names of the ACPI_PDC symbols suggests that they are only relevant for _PDC, but in fact they can also be used in the _OSC. Change that prefix to a more generic ACPI_PROC_CAP that will better reflect the purpose of those symbols as they represent bits in a general processor capabilities buffer. Rename pdc_intel.h to proc_cap_intel.h to follow the change of the symbol name prefix. No intentional functional impact. Suggested-by: Rafael J. Wysocki Signed-off-by: Michal Wilczynski [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- arch/ia64/include/asm/acpi.h | 4 ++-- arch/x86/include/asm/acpi.h | 11 +++++----- arch/x86/xen/enlighten_pv.c | 8 +++---- drivers/acpi/processor_pdc.c | 2 +- include/acpi/pdc_intel.h | 36 -------------------------------- include/acpi/proc_cap_intel.h | 39 +++++++++++++++++++++++++++++++++++ 6 files changed, 52 insertions(+), 48 deletions(-) delete mode 100644 include/acpi/pdc_intel.h create mode 100644 include/acpi/proc_cap_intel.h diff --git a/arch/ia64/include/asm/acpi.h b/arch/ia64/include/asm/acpi.h index 43797cb44383..58500a964238 100644 --- a/arch/ia64/include/asm/acpi.h +++ b/arch/ia64/include/asm/acpi.h @@ -11,7 +11,7 @@ #ifdef __KERNEL__ -#include +#include #include #include @@ -71,7 +71,7 @@ extern int __initdata nid_to_pxm_map[MAX_NUMNODES]; static inline bool arch_has_acpi_pdc(void) { return true; } static inline void arch_acpi_set_proc_cap_bits(u32 *cap) { - *cap |= ACPI_PDC_EST_CAPABILITY_SMP; + *cap |= ACPI_PROC_CAP_EST_CAPABILITY_SMP; } #ifdef CONFIG_ACPI_NUMA diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h index 6a498d1781e7..ce5ad6a496e6 100644 --- a/arch/x86/include/asm/acpi.h +++ b/arch/x86/include/asm/acpi.h @@ -6,7 +6,7 @@ * Copyright (C) 2001 Paul Diefenbaugh * Copyright (C) 2001 Patrick Mochel */ -#include +#include #include #include @@ -104,19 +104,20 @@ static inline void arch_acpi_set_proc_cap_bits(u32 *cap) { struct cpuinfo_x86 *c = &cpu_data(0); - *cap |= ACPI_PDC_C_CAPABILITY_SMP; + *cap |= ACPI_PROC_CAP_C_CAPABILITY_SMP; if (cpu_has(c, X86_FEATURE_EST)) - *cap |= ACPI_PDC_EST_CAPABILITY_SWSMP; + *cap |= ACPI_PROC_CAP_EST_CAPABILITY_SWSMP; if (cpu_has(c, X86_FEATURE_ACPI)) - *cap |= ACPI_PDC_T_FFH; + *cap |= ACPI_PROC_CAP_T_FFH; /* * If mwait/monitor is unsupported, C2/C3_FFH will be disabled */ if (!cpu_has(c, X86_FEATURE_MWAIT)) - *cap &= ~(ACPI_PDC_C_C2C3_FFH); + *cap &= ~(ACPI_PROC_CAP_C_C2C3_FFH); + } static inline bool acpi_has_cpu_in_madt(void) diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c index 93b658248d01..a3864e2167a8 100644 --- a/arch/x86/xen/enlighten_pv.c +++ b/arch/x86/xen/enlighten_pv.c @@ -79,7 +79,7 @@ #ifdef CONFIG_ACPI #include #include -#include +#include #include #include #endif @@ -288,17 +288,17 @@ static bool __init xen_check_mwait(void) native_cpuid(&ax, &bx, &cx, &dx); - /* Ask the Hypervisor whether to clear ACPI_PDC_C_C2C3_FFH. If so, + /* Ask the Hypervisor whether to clear ACPI_PROC_CAP_C_C2C3_FFH. If so, * don't expose MWAIT_LEAF and let ACPI pick the IOPORT version of C3. */ buf[0] = ACPI_PDC_REVISION_ID; buf[1] = 1; - buf[2] = (ACPI_PDC_C_CAPABILITY_SMP | ACPI_PDC_EST_CAPABILITY_SWSMP); + buf[2] = (ACPI_PROC_CAP_C_CAPABILITY_SMP | ACPI_PROC_CAP_EST_CAPABILITY_SWSMP); set_xen_guest_handle(op.u.set_pminfo.pdc, buf); if ((HYPERVISOR_platform_op(&op) == 0) && - (buf[2] & (ACPI_PDC_C_C1_FFH | ACPI_PDC_C_C2C3_FFH))) { + (buf[2] & (ACPI_PROC_CAP_C_C1_FFH | ACPI_PROC_CAP_C_C2C3_FFH))) { cpuid_leaf5_ecx_val = cx; cpuid_leaf5_edx_val = dx; } diff --git a/drivers/acpi/processor_pdc.c b/drivers/acpi/processor_pdc.c index 9e7b5ddb9ec2..7948b5d41907 100644 --- a/drivers/acpi/processor_pdc.c +++ b/drivers/acpi/processor_pdc.c @@ -21,7 +21,7 @@ static void acpi_set_pdc_bits(u32 *buf) buf[1] = 1; /* Enable coordination with firmware's _TSD info */ - buf[2] = ACPI_PDC_SMP_T_SWCOORD; + buf[2] = ACPI_PROC_CAP_SMP_T_SWCOORD; /* Twiddle arch-specific bits needed for _PDC */ arch_acpi_set_proc_cap_bits(&buf[2]); diff --git a/include/acpi/pdc_intel.h b/include/acpi/pdc_intel.h deleted file mode 100644 index 967c552d1cd3..000000000000 --- a/include/acpi/pdc_intel.h +++ /dev/null @@ -1,36 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - -/* _PDC bit definition for Intel processors */ - -#ifndef __PDC_INTEL_H__ -#define __PDC_INTEL_H__ - -#define ACPI_PDC_P_FFH (0x0001) -#define ACPI_PDC_C_C1_HALT (0x0002) -#define ACPI_PDC_T_FFH (0x0004) -#define ACPI_PDC_SMP_C1PT (0x0008) -#define ACPI_PDC_SMP_C2C3 (0x0010) -#define ACPI_PDC_SMP_P_SWCOORD (0x0020) -#define ACPI_PDC_SMP_C_SWCOORD (0x0040) -#define ACPI_PDC_SMP_T_SWCOORD (0x0080) -#define ACPI_PDC_C_C1_FFH (0x0100) -#define ACPI_PDC_C_C2C3_FFH (0x0200) -#define ACPI_PDC_SMP_P_HWCOORD (0x0800) - -#define ACPI_PDC_EST_CAPABILITY_SMP (ACPI_PDC_SMP_C1PT | \ - ACPI_PDC_C_C1_HALT | \ - ACPI_PDC_P_FFH) - -#define ACPI_PDC_EST_CAPABILITY_SWSMP (ACPI_PDC_SMP_C1PT | \ - ACPI_PDC_C_C1_HALT | \ - ACPI_PDC_SMP_P_SWCOORD | \ - ACPI_PDC_SMP_P_HWCOORD | \ - ACPI_PDC_P_FFH) - -#define ACPI_PDC_C_CAPABILITY_SMP (ACPI_PDC_SMP_C2C3 | \ - ACPI_PDC_SMP_C1PT | \ - ACPI_PDC_C_C1_HALT | \ - ACPI_PDC_C_C1_FFH | \ - ACPI_PDC_C_C2C3_FFH) - -#endif /* __PDC_INTEL_H__ */ diff --git a/include/acpi/proc_cap_intel.h b/include/acpi/proc_cap_intel.h new file mode 100644 index 000000000000..57e5e2628abb --- /dev/null +++ b/include/acpi/proc_cap_intel.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* Vendor specific processor capabilities bit definition + * for Intel processors. Those bits are used to convey OSPM + * power management capabilities to the platform. + */ + +#ifndef __PROC_CAP_INTEL_H__ +#define __PROC_CAP_INTEL_H__ + +#define ACPI_PROC_CAP_P_FFH (0x0001) +#define ACPI_PROC_CAP_C_C1_HALT (0x0002) +#define ACPI_PROC_CAP_T_FFH (0x0004) +#define ACPI_PROC_CAP_SMP_C1PT (0x0008) +#define ACPI_PROC_CAP_SMP_C2C3 (0x0010) +#define ACPI_PROC_CAP_SMP_P_SWCOORD (0x0020) +#define ACPI_PROC_CAP_SMP_C_SWCOORD (0x0040) +#define ACPI_PROC_CAP_SMP_T_SWCOORD (0x0080) +#define ACPI_PROC_CAP_C_C1_FFH (0x0100) +#define ACPI_PROC_CAP_C_C2C3_FFH (0x0200) +#define ACPI_PROC_CAP_SMP_P_HWCOORD (0x0800) + +#define ACPI_PROC_CAP_EST_CAPABILITY_SMP (ACPI_PROC_CAP_SMP_C1PT | \ + ACPI_PROC_CAP_C_C1_HALT | \ + ACPI_PROC_CAP_P_FFH) + +#define ACPI_PROC_CAP_EST_CAPABILITY_SWSMP (ACPI_PROC_CAP_SMP_C1PT | \ + ACPI_PROC_CAP_C_C1_HALT | \ + ACPI_PROC_CAP_SMP_P_SWCOORD | \ + ACPI_PROC_CAP_SMP_P_HWCOORD | \ + ACPI_PROC_CAP_P_FFH) + +#define ACPI_PROC_CAP_C_CAPABILITY_SMP (ACPI_PROC_CAP_SMP_C2C3 | \ + ACPI_PROC_CAP_SMP_C1PT | \ + ACPI_PROC_CAP_C_C1_HALT | \ + ACPI_PROC_CAP_C_C1_FFH | \ + ACPI_PROC_CAP_C_C2C3_FFH) + +#endif /* __PROC_CAP_INTEL_H__ */ From 4f37ab5e05df9a30d64663266c7f4ba3a1407c68 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 10 Jul 2023 17:03:33 +0300 Subject: [PATCH 05/11] ACPI: processor: Clear C_C2C3_FFH and C_C1_FFH in arch_acpi_set_proc_cap_bits() Currently arch_acpi_set_proc_cap_bits() clears ACPI_PDC_C_C2C3_FFH bit in case MWAIT instruction is not supported. It should also clear ACPI_PDC_C_C1_FFH, as when MWAIT is not supported, C1 is entered by executing the HLT instruction. Quote from the C_C1_FFH description: "If set, OSPM is capable of performing native C State instructions (beyond halt) for the C1 handler in multi-processor configurations". As without MWAIT there is no native C-state instructions beyond HALT, this bit should be toggled off." Clear ACPI_PDC_C_C1_FFH and ACPI_PDC_C_C2C3_FFH in arch_acpi_set_proc_cap_bits() in case MWAIT is not supported or overridden. Remove setting those bits from the processor_pdc.c code. Suggested-by: Rafael J. Wysocki Signed-off-by: Michal Wilczynski [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- arch/x86/include/asm/acpi.h | 9 +++++---- drivers/acpi/processor_pdc.c | 14 -------------- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h index ce5ad6a496e6..d615238bcd78 100644 --- a/arch/x86/include/asm/acpi.h +++ b/arch/x86/include/asm/acpi.h @@ -113,11 +113,12 @@ static inline void arch_acpi_set_proc_cap_bits(u32 *cap) *cap |= ACPI_PROC_CAP_T_FFH; /* - * If mwait/monitor is unsupported, C2/C3_FFH will be disabled + * If mwait/monitor is unsupported, C_C1_FFH and + * C2/C3_FFH will be disabled. */ - if (!cpu_has(c, X86_FEATURE_MWAIT)) - *cap &= ~(ACPI_PROC_CAP_C_C2C3_FFH); - + if (!cpu_has(c, X86_FEATURE_MWAIT) || + boot_option_idle_override == IDLE_NOMWAIT) + *cap &= ~(ACPI_PROC_CAP_C_C1_FFH | ACPI_PROC_CAP_C_C2C3_FFH); } static inline bool acpi_has_cpu_in_madt(void) diff --git a/drivers/acpi/processor_pdc.c b/drivers/acpi/processor_pdc.c index 7948b5d41907..3c6035262dc2 100644 --- a/drivers/acpi/processor_pdc.c +++ b/drivers/acpi/processor_pdc.c @@ -74,20 +74,6 @@ acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in) { acpi_status status = AE_OK; - if (boot_option_idle_override == IDLE_NOMWAIT) { - /* - * If mwait is disabled for CPU C-states, the C2C3_FFH access - * mode will be disabled in the parameter of _PDC object. - * Of course C1_FFH access mode will also be disabled. - */ - union acpi_object *obj; - u32 *buffer = NULL; - - obj = pdc_in->pointer; - buffer = (u32 *)(obj->buffer.pointer); - buffer[2] &= ~(ACPI_PDC_C_C2C3_FFH | ACPI_PDC_C_C1_FFH); - - } status = acpi_evaluate_object(handle, "_PDC", pdc_in, NULL); if (ACPI_FAILURE(status)) From b9e8d0168a7a85e05d031130b247099018e2194e Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 10 Jul 2023 17:03:34 +0300 Subject: [PATCH 06/11] ACPI: processor: Set CAP_SMP_T_SWCOORD in arch_acpi_set_proc_cap_bits() Currently, ACPI_PROC_CAP_SMP_T_SWCOORD is set in acpi_set_pdc_bits(), but it is not _PDC-specific. It should be set along with the other processor capability bits. Move the setting of ACPI_PROC_CAP_SMP_T_SWCOORD to arch_acpi_set_proc_cap_bits(). Suggested-by: Rafael J. Wysocki Signed-off-by: Michal Wilczynski [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- arch/x86/include/asm/acpi.h | 3 +++ drivers/acpi/processor_pdc.c | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h index d615238bcd78..6f6752a2ea36 100644 --- a/arch/x86/include/asm/acpi.h +++ b/arch/x86/include/asm/acpi.h @@ -106,6 +106,9 @@ static inline void arch_acpi_set_proc_cap_bits(u32 *cap) *cap |= ACPI_PROC_CAP_C_CAPABILITY_SMP; + /* Enable coordination with firmware's _TSD info */ + *cap |= ACPI_PROC_CAP_SMP_T_SWCOORD; + if (cpu_has(c, X86_FEATURE_EST)) *cap |= ACPI_PROC_CAP_EST_CAPABILITY_SWSMP; diff --git a/drivers/acpi/processor_pdc.c b/drivers/acpi/processor_pdc.c index 3c6035262dc2..1a8591e9a9bf 100644 --- a/drivers/acpi/processor_pdc.c +++ b/drivers/acpi/processor_pdc.c @@ -20,9 +20,6 @@ static void acpi_set_pdc_bits(u32 *buf) buf[0] = ACPI_PDC_REVISION_ID; buf[1] = 1; - /* Enable coordination with firmware's _TSD info */ - buf[2] = ACPI_PROC_CAP_SMP_T_SWCOORD; - /* Twiddle arch-specific bits needed for _PDC */ arch_acpi_set_proc_cap_bits(&buf[2]); } From 5ba30be7fd6e3fdff1e0b01f24173a5e6a3183b2 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 10 Jul 2023 17:03:35 +0300 Subject: [PATCH 07/11] ACPI: processor: Introduce acpi_processor_osc() The processor _OSC method is already used for a workaround introduced in commit a21211672c9a ("ACPI / processor: Request native thermal interrupt handling via _OSC"), but in accordance with ACPI 6.5 (and earlier), it should be used for negotiating all of the processor capabilities instead of _PDC (which has been deprecated since ACPI 3.0 and got removed from ACPI 6.5 entirely). Create a new callback function called acpi_processor_osc() to be invoked for every processor object and processor device in the ACPI namespace, in analogy with the already existing acpi_hwp_native_thermal_lvt_osc(). Make this function implement the workaround mentioned above and convey all of the OSPM processor support information to the platform firmware by setting all of the appropriate processor capabilities bits before evaluating _OSC for the given processor. For this purpose, make it call arch_acpi_set_proc_cap_bits() and modify the latter to set ACPI_PROC_CAP_COLLAB_PROC_PERF along with the other processor capabilities bits. Suggested-by: Rafael J. Wysocki Signed-off-by: Michal Wilczynski Reviewed-by: Andy Shevchenko [ rjw: Subject and changelog edits, whitespace fixup ] Signed-off-by: Rafael J. Wysocki --- arch/x86/include/asm/acpi.h | 3 +++ drivers/acpi/acpi_processor.c | 30 +++++++++++++++++++++++++++++- include/acpi/proc_cap_intel.h | 1 + 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h index 6f6752a2ea36..6c3af9486153 100644 --- a/arch/x86/include/asm/acpi.h +++ b/arch/x86/include/asm/acpi.h @@ -115,6 +115,9 @@ static inline void arch_acpi_set_proc_cap_bits(u32 *cap) if (cpu_has(c, X86_FEATURE_ACPI)) *cap |= ACPI_PROC_CAP_T_FFH; + if (cpu_has(c, X86_FEATURE_HWP)) + *cap |= ACPI_PROC_CAP_COLLAB_PROC_PERF; + /* * If mwait/monitor is unsupported, C_C1_FFH and * C2/C3_FFH will be disabled. diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index ebb4efd3d0aa..163bd3d52acd 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -559,13 +559,41 @@ bool __init processor_physically_present(acpi_handle handle) return !invalid_logical_cpuid(cpuid); } +/* vendor specific UUID indicating an Intel platform */ +static u8 sb_uuid_str[] = "4077A616-290C-47BE-9EBD-D87058713953"; static bool acpi_hwp_native_thermal_lvt_set; + +static acpi_status __init acpi_processor_osc(acpi_handle handle, u32 lvl, + void *context, void **rv) +{ + u32 capbuf[2] = {}; + struct acpi_osc_context osc_context = { + .uuid_str = sb_uuid_str, + .rev = 1, + .cap.length = 8, + .cap.pointer = capbuf, + }; + acpi_status status; + + if (!processor_physically_present(handle)) + return AE_OK; + + arch_acpi_set_proc_cap_bits(&capbuf[OSC_SUPPORT_DWORD]); + + status = acpi_run_osc(handle, &osc_context); + if (ACPI_FAILURE(status)) + return status; + + kfree(osc_context.ret.pointer); + + return AE_OK; +} + static acpi_status __init acpi_hwp_native_thermal_lvt_osc(acpi_handle handle, u32 lvl, void *context, void **rv) { - u8 sb_uuid_str[] = "4077A616-290C-47BE-9EBD-D87058713953"; u32 capbuf[2]; struct acpi_osc_context osc_context = { .uuid_str = sb_uuid_str, diff --git a/include/acpi/proc_cap_intel.h b/include/acpi/proc_cap_intel.h index 57e5e2628abb..ddcdc41d6c3e 100644 --- a/include/acpi/proc_cap_intel.h +++ b/include/acpi/proc_cap_intel.h @@ -19,6 +19,7 @@ #define ACPI_PROC_CAP_C_C1_FFH (0x0100) #define ACPI_PROC_CAP_C_C2C3_FFH (0x0200) #define ACPI_PROC_CAP_SMP_P_HWCOORD (0x0800) +#define ACPI_PROC_CAP_COLLAB_PROC_PERF (0x1000) #define ACPI_PROC_CAP_EST_CAPABILITY_SMP (ACPI_PROC_CAP_SMP_C1PT | \ ACPI_PROC_CAP_C_C1_HALT | \ From 95272641338a32734792fe4b261001847b11ed80 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 10 Jul 2023 17:03:36 +0300 Subject: [PATCH 08/11] ACPI: processor: Use _OSC to convey OSPM processor support information Change acpi_early_processor_osc() to return a value in case of a failure and make it static. Also make it run acpi_processor_osc() for every processor object or processor device found in the ACPI Namespace (previously, its only purpose was to work around platform firmware defects on Skylake systems). Introduce a new function called acpi_early_processor_control_setup() that will invoke acpi_early_processor_osc() first in order to convey the OS processor support information to the platform firmware and if that fails, it will fall back to using _PDC. Suggested-by: Rafael J. Wysocki Signed-off-by: Michal Wilczynski Reviewed-by: Andy Shevchenko [ rjw: Subject and changelog edits, change function return value to bool, add missing 'static', change messages ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_processor.c | 35 ++++++++++++++++++++++++++--------- drivers/acpi/bus.c | 5 +---- drivers/acpi/internal.h | 9 ++------- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 163bd3d52acd..8f4d70ae694f 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -624,16 +624,33 @@ static acpi_status __init acpi_hwp_native_thermal_lvt_osc(acpi_handle handle, return AE_OK; } -void __init acpi_early_processor_osc(void) +static bool __init acpi_early_processor_osc(void) { - if (boot_cpu_has(X86_FEATURE_HWP)) { - acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, - acpi_hwp_native_thermal_lvt_osc, - NULL, NULL, NULL); - acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID, - acpi_hwp_native_thermal_lvt_osc, - NULL, NULL); + acpi_status status; + + acpi_proc_quirk_mwait_check(); + + status = acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, acpi_processor_osc, NULL, + NULL, NULL); + if (ACPI_FAILURE(status)) + return false; + + status = acpi_get_devices(ACPI_PROCESSOR_DEVICE_HID, acpi_processor_osc, + NULL, NULL); + if (ACPI_FAILURE(status)) + return false; + + return true; +} + +void __init acpi_early_processor_control_setup(void) +{ + if (acpi_early_processor_osc()) { + pr_info("_OSC evaluated successfully\n"); + } else { + pr_info("_OSC evaluation failed, trying _PDC\n"); + acpi_early_processor_set_pdc(); } } #endif diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 2fc2b43a4ed3..a39f2f3a2cd6 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -1296,9 +1296,6 @@ static int __init acpi_bus_init(void) goto error1; } - /* Set capability bits for _OSC under processor scope */ - acpi_early_processor_osc(); - /* * _OSC method may exist in module level code, * so it must be run after ACPI_FULL_INITIALIZATION @@ -1314,7 +1311,7 @@ static int __init acpi_bus_init(void) acpi_sysfs_init(); - acpi_early_processor_set_pdc(); + acpi_early_processor_control_setup(); /* * Maybe EC region is required at bus_scan/acpi_get_devices. So it diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index ed2599ae3e83..ced8224d7472 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -152,18 +152,13 @@ int acpi_wakeup_device_init(void); Processor -------------------------------------------------------------------------- */ #ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC +void acpi_early_processor_control_setup(void); void acpi_early_processor_set_pdc(void); void acpi_proc_quirk_mwait_check(void); bool processor_physically_present(acpi_handle handle); #else -static inline void acpi_early_processor_set_pdc(void) {} -#endif - -#ifdef CONFIG_X86 -void acpi_early_processor_osc(void); -#else -static inline void acpi_early_processor_osc(void) {} +static inline void acpi_early_processor_control_setup(void) {} #endif /* -------------------------------------------------------------------------- From 11e7bf5629fa6a78b72a2b755c0a8f0bbd512593 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 10 Jul 2023 17:03:37 +0300 Subject: [PATCH 09/11] ACPI: processor: Remove acpi_hwp_native_thermal_lvt_osc() The workaround for buggy skylake BIOSes is now implemented in acpi_processor_osc() and acpi_hwp_native_thermal_lvt_osc() has no callers, so drop it. Suggested-by: Rafael J. Wysocki Signed-off-by: Michal Wilczynski Reviewed-by: Andy Shevchenko [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_processor.c | 36 ----------------------------------- 1 file changed, 36 deletions(-) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 8f4d70ae694f..9e35b8d8d334 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -561,7 +561,6 @@ bool __init processor_physically_present(acpi_handle handle) /* vendor specific UUID indicating an Intel platform */ static u8 sb_uuid_str[] = "4077A616-290C-47BE-9EBD-D87058713953"; -static bool acpi_hwp_native_thermal_lvt_set; static acpi_status __init acpi_processor_osc(acpi_handle handle, u32 lvl, void *context, void **rv) @@ -589,41 +588,6 @@ static acpi_status __init acpi_processor_osc(acpi_handle handle, u32 lvl, return AE_OK; } -static acpi_status __init acpi_hwp_native_thermal_lvt_osc(acpi_handle handle, - u32 lvl, - void *context, - void **rv) -{ - u32 capbuf[2]; - struct acpi_osc_context osc_context = { - .uuid_str = sb_uuid_str, - .rev = 1, - .cap.length = 8, - .cap.pointer = capbuf, - }; - - if (acpi_hwp_native_thermal_lvt_set) - return AE_CTRL_TERMINATE; - - capbuf[0] = 0x0000; - capbuf[1] = 0x1000; /* set bit 12 */ - - if (ACPI_SUCCESS(acpi_run_osc(handle, &osc_context))) { - if (osc_context.ret.pointer && osc_context.ret.length > 1) { - u32 *capbuf_ret = osc_context.ret.pointer; - - if (capbuf_ret[1] & 0x1000) { - acpi_handle_info(handle, - "_OSC native thermal LVT Acked\n"); - acpi_hwp_native_thermal_lvt_set = true; - } - } - kfree(osc_context.ret.pointer); - } - - return AE_OK; -} - static bool __init acpi_early_processor_osc(void) { acpi_status status; From 003e0694fcd3d51ee2d55dafb2def501f9965cbd Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 19 Jul 2023 18:02:44 +0200 Subject: [PATCH 10/11] ACPI: processor: Refine messages in acpi_early_processor_control_setup() The source and meaning of the messages printed by acpi_early_processor_control_setup() is unclear, so add a pr_fmt() definition to acpi_processor.c and expand the messages to make it clear that they are about CPUs. Signed-off-by: Rafael J. Wysocki Reviewed-by: Michal Wilczynski --- drivers/acpi/acpi_processor.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 9e35b8d8d334..c711db8a9c33 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -9,6 +9,7 @@ * Copyright (C) 2013, Intel Corporation * Rafael J. Wysocki */ +#define pr_fmt(fmt) "ACPI: " fmt #include #include @@ -611,9 +612,9 @@ static bool __init acpi_early_processor_osc(void) void __init acpi_early_processor_control_setup(void) { if (acpi_early_processor_osc()) { - pr_info("_OSC evaluated successfully\n"); + pr_info("_OSC evaluated successfully for all CPUs\n"); } else { - pr_info("_OSC evaluation failed, trying _PDC\n"); + pr_info("_OSC evaluation for CPUs failed, trying _PDC\n"); acpi_early_processor_set_pdc(); } } From f6fcf03ce8a9b8c135cf47f4978617bdf2829711 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Mon, 17 Jul 2023 10:22:58 +0800 Subject: [PATCH 11/11] ACPI: processor: LoongArch: Get physical ID from MADT With ACPI Spec 6.5 chapter 5.2.12.20, each processor in LoongArch systems has a Core Programmable Interrupt Controller in MADT. The value of its type is 0x11 in the spec and defined as enum variable ACPI_MADT_TYPE_CORE_PIC in the Linux kernel. Physical IDs can be retrieved from MADT for LoongArch systems during initialization and they can be retrieved from the _MAT output for hotplug CPUs. Add physical CPU ID enumeration for LoongArch systems. Signed-off-by: Bibo Mao [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_core.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index d6606a9f2da6..7dd6dbaa98c3 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -132,6 +132,30 @@ static int map_rintc_hartid(struct acpi_subtable_header *entry, return -EINVAL; } +/* + * Retrieve LoongArch CPU physical id + */ +static int map_core_pic_id(struct acpi_subtable_header *entry, + int device_declaration, u32 acpi_id, phys_cpuid_t *phys_id) +{ + struct acpi_madt_core_pic *core_pic = + container_of(entry, struct acpi_madt_core_pic, header); + + if (!(core_pic->flags & ACPI_MADT_ENABLED)) + return -ENODEV; + + /* device_declaration means Device object in DSDT, in LoongArch + * system, logical processor acpi_id is required in _UID property + * of DSDT table, so we should check device_declaration here + */ + if (device_declaration && (core_pic->processor_id == acpi_id)) { + *phys_id = core_pic->core_id; + return 0; + } + + return -EINVAL; +} + static phys_cpuid_t map_madt_entry(struct acpi_table_madt *madt, int type, u32 acpi_id) { @@ -165,6 +189,9 @@ static phys_cpuid_t map_madt_entry(struct acpi_table_madt *madt, } else if (header->type == ACPI_MADT_TYPE_RINTC) { if (!map_rintc_hartid(header, type, acpi_id, &phys_id)) break; + } else if (header->type == ACPI_MADT_TYPE_CORE_PIC) { + if (!map_core_pic_id(header, type, acpi_id, &phys_id)) + break; } entry += header->length; } @@ -216,6 +243,8 @@ static phys_cpuid_t map_mat_entry(acpi_handle handle, int type, u32 acpi_id) map_x2apic_id(header, type, acpi_id, &phys_id); else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) map_gicc_mpidr(header, type, acpi_id, &phys_id); + else if (header->type == ACPI_MADT_TYPE_CORE_PIC) + map_core_pic_id(header, type, acpi_id, &phys_id); exit: kfree(buffer.pointer);