From 7c94858ec17dae9071fa3bdf6b005967b9f146f4 Mon Sep 17 00:00:00 2001 From: Philip Prindeville Date: Wed, 12 Apr 2023 10:18:20 -0600 Subject: ACPICA: Fix GCC 12 dangling-pointer warning ACPICA commit aea0a5cfce262ce2ab16fd96d87c12cf5e756380 We're storing a persistent pointer to an ephemeral local variable which technically is a dangling pointer and the compiler is correct. However, since we never indirect the pointer, this is a safe operation and we can suppress the warning. Also, some C run-times (like MUSL) aren't including indirectly so we must include it explicitly or we won't have the type definition for uintptr_t. Fixes issue #867. Link: https://github.com/acpica/acpica/commit/aea0a5cf Signed-off-by: Philip Prindeville Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/utdebug.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index 1bbba8585fa6..c5f6c85a3a09 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -37,7 +37,12 @@ void acpi_ut_init_stack_ptr_trace(void) { acpi_size current_sp; +#pragma GCC diagnostic push +#if defined(__GNUC__) && __GNUC__ >= 12 +#pragma GCC diagnostic ignored "-Wdangling-pointer=" +#endif acpi_gbl_entry_stack_pointer = ¤t_sp; +#pragma GCC diagnostic pop } /******************************************************************************* -- cgit v1.2.3-70-g09d2 From 4f1094baeb14ef150b964eb1537ea71099ff7da0 Mon Sep 17 00:00:00 2001 From: George Guo Date: Thu, 20 Apr 2023 10:50:46 +0800 Subject: ACPICA: Modify ACPI_STATE_COMMON ACPICA commit 0a43d3521582b5234f69e8bb535e83325387525a Avoid trailing semicolons in macro, and it's not readable to put macro ACPI_STATE_COMMON and other variables in the same line. So modify the macro and just put it in a single line. Link: https://github.com/acpica/acpica/commit/0a43d352 Signed-off-by: George Guo Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/aclocal.h | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 12d4a024f029..75a81b6c1a16 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -560,25 +560,28 @@ struct acpi_field_info { u8 descriptor_type; /* To differentiate various internal objs */\ u8 flags; \ u16 value; \ - u16 state; + u16 state /* There are 2 bytes available here until the next natural alignment boundary */ struct acpi_common_state { -ACPI_STATE_COMMON}; + ACPI_STATE_COMMON; +}; /* * Update state - used to traverse complex objects such as packages */ struct acpi_update_state { - ACPI_STATE_COMMON union acpi_operand_object *object; + ACPI_STATE_COMMON; + union acpi_operand_object *object; }; /* * Pkg state - used to traverse nested package structures */ struct acpi_pkg_state { - ACPI_STATE_COMMON u32 index; + ACPI_STATE_COMMON; + u32 index; union acpi_operand_object *source_object; union acpi_operand_object *dest_object; struct acpi_walk_state *walk_state; @@ -591,7 +594,8 @@ struct acpi_pkg_state { * Allows nesting of these constructs */ struct acpi_control_state { - ACPI_STATE_COMMON u16 opcode; + ACPI_STATE_COMMON; + u16 opcode; union acpi_parse_object *predicate_op; u8 *aml_predicate_start; /* Start of if/while predicate */ u8 *package_end; /* End of if/while block */ @@ -602,11 +606,13 @@ struct acpi_control_state { * Scope state - current scope during namespace lookups */ struct acpi_scope_state { - ACPI_STATE_COMMON struct acpi_namespace_node *node; + ACPI_STATE_COMMON; + struct acpi_namespace_node *node; }; struct acpi_pscope_state { - ACPI_STATE_COMMON u32 arg_count; /* Number of fixed arguments */ + ACPI_STATE_COMMON; + u32 arg_count; /* Number of fixed arguments */ union acpi_parse_object *op; /* Current op being parsed */ u8 *arg_end; /* Current argument end */ u8 *pkg_end; /* Current package end */ @@ -618,7 +624,8 @@ struct acpi_pscope_state { * states are created when there are nested control methods executing. */ struct acpi_thread_state { - ACPI_STATE_COMMON u8 current_sync_level; /* Mutex Sync (nested acquire) level */ + ACPI_STATE_COMMON; + u8 current_sync_level; /* Mutex Sync (nested acquire) level */ struct acpi_walk_state *walk_state_list; /* Head of list of walk_states for this thread */ union acpi_operand_object *acquired_mutex_list; /* List of all currently acquired mutexes */ acpi_thread_id thread_id; /* Running thread ID */ @@ -629,8 +636,8 @@ struct acpi_thread_state { * AML arguments */ struct acpi_result_values { - ACPI_STATE_COMMON - union acpi_operand_object *obj_desc[ACPI_RESULTS_FRAME_OBJ_NUM]; + ACPI_STATE_COMMON; + union acpi_operand_object *obj_desc[ACPI_RESULTS_FRAME_OBJ_NUM]; }; typedef @@ -652,7 +659,8 @@ struct acpi_global_notify_handler { * handler/dispatcher. */ struct acpi_notify_info { - ACPI_STATE_COMMON u8 handler_list_id; + ACPI_STATE_COMMON; + u8 handler_list_id; struct acpi_namespace_node *node; union acpi_operand_object *handler_list_head; struct acpi_global_notify_handler *global; -- cgit v1.2.3-70-g09d2 From bac36a179a2b4163fa524de806afb04d639b6781 Mon Sep 17 00:00:00 2001 From: Jiangshan Yi Date: Thu, 20 Apr 2023 15:42:47 +0800 Subject: ACPICA: exserial.c: replace ternary operator with ACPI_MIN() ACPICA commit 2250f71fe77396db21df805222ffcbf19e1e7896 Make the code simpler and more readable. Link: https://github.com/acpica/acpica/commit/2250f71f Signed-off-by: Jiangshan Yi Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/exserial.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpica/exserial.c b/drivers/acpi/acpica/exserial.c index 5d99b1a76c83..5241f4c01c76 100644 --- a/drivers/acpi/acpica/exserial.c +++ b/drivers/acpi/acpica/exserial.c @@ -343,8 +343,7 @@ acpi_ex_write_serial_bus(union acpi_operand_object *source_desc, /* Copy the input buffer data to the transfer buffer */ buffer = buffer_desc->buffer.pointer; - data_length = (buffer_length < source_desc->buffer.length ? - buffer_length : source_desc->buffer.length); + data_length = ACPI_MIN(buffer_length, source_desc->buffer.length); memcpy(buffer, source_desc->buffer.pointer, data_length); /* Lock entire transaction if requested */ -- cgit v1.2.3-70-g09d2 From ed9aa118e4e1d5676da7047905c2080edadff65c Mon Sep 17 00:00:00 2001 From: Saket Dumbre Date: Tue, 25 Apr 2023 10:52:21 -0700 Subject: ACPICA: Add support for _DSC as per ACPI 6.5 ACPICA commit a597e3b247df72aec0f6e056c95abe2d973ac10c Link: https://github.com/acpica/acpica/commit/a597e3b2 Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acpredef.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h index e64aabe3d33a..2e442f5a3123 100644 --- a/drivers/acpi/acpica/acpredef.h +++ b/drivers/acpi/acpica/acpredef.h @@ -440,6 +440,9 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = { {{"_DOS", METHOD_1ARGS(ACPI_TYPE_INTEGER), METHOD_NO_RETURN_VALUE}}, + {{"_DSC", METHOD_0ARGS, + METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, + {{"_DSD", METHOD_0ARGS, /* ACPI 6.0 */ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each: 1 Buf, 1 Pkg */ PACKAGE_INFO(ACPI_PTYPE2_UUID_PAIR, ACPI_RTYPE_BUFFER, 1, -- cgit v1.2.3-70-g09d2 From 24a4b8724536ad7438fe94e8fd269be97e23d0d1 Mon Sep 17 00:00:00 2001 From: Jose Marinho Date: Tue, 28 Mar 2023 10:50:46 +0100 Subject: ACPICA: Detect GED device and keep track of _EVT ACPICA commit dc6fd1d12903015726a8a6f87f63e86141576a68 The GED device is described by a _HID of ACPI0013. This code traverses the namespace identifying all GED devices. For each GED device in the namespace we record 1) the Interrupt objects and the _EVT method. This information is used when an interrupt is simulate. Link: https://github.com/acpica/acpica/commit/dc6fd1d1 Signed-off-by: Jose Marinho Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acglobal.h | 1 + drivers/acpi/acpica/aclocal.h | 8 ++++++++ include/acpi/acnames.h | 1 + 3 files changed, 10 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 778241173ed4..f4c90fc99be2 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -129,6 +129,7 @@ ACPI_GLOBAL(acpi_table_handler, acpi_gbl_table_handler); ACPI_GLOBAL(void *, acpi_gbl_table_handler_context); ACPI_GLOBAL(acpi_interface_handler, acpi_gbl_interface_handler); ACPI_GLOBAL(struct acpi_sci_handler_info *, acpi_gbl_sci_handler_list); +ACPI_GLOBAL(struct acpi_ged_handler_info *, acpi_gbl_ged_handler_list); /* Owner ID support */ diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 75a81b6c1a16..82563b44af35 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -543,6 +543,14 @@ struct acpi_field_info { u32 pkg_length; }; +/* Information about the interrupt ID and _EVT of a GED device */ + +struct acpi_ged_handler_info { + struct acpi_ged_handler_info *next; + u32 int_id; /* The interrupt ID that triggers the execution ofthe evt_method. */ + struct acpi_namespace_node *evt_method; /* The _EVT method to be executed when an interrupt with ID = int_ID is received */ +}; + /***************************************************************************** * * Generic "state" object for stacks diff --git a/include/acpi/acnames.h b/include/acpi/acnames.h index d71291f25a80..76aa6aa346ba 100644 --- a/include/acpi/acnames.h +++ b/include/acpi/acnames.h @@ -22,6 +22,7 @@ #define METHOD_NAME__DDN "_DDN" #define METHOD_NAME__DIS "_DIS" #define METHOD_NAME__DMA "_DMA" +#define METHOD_NAME__EVT "_EVT" #define METHOD_NAME__HID "_HID" #define METHOD_NAME__INI "_INI" #define METHOD_NAME__PLD "_PLD" -- cgit v1.2.3-70-g09d2 From b0f2e7d7e6147f09879d7a631eceb03e1a744753 Mon Sep 17 00:00:00 2001 From: Jose Marinho Date: Sun, 26 Mar 2023 20:06:00 +0100 Subject: ACPICA: Add interrupt command to acpiexec ACPICA commit ef7cf185a046d76119b631f16e7c991543c80edc This commit add the Interrupt command to acpiexec. The Interrupt command simulates an interrupt with a int_ID (GSIV) equal to the first argument of the call. The acpiexec code simulates the behaviour by OSPM: execute the _EVT method of the GED device associated with that int_ID. Link: https://github.com/acpica/acpica/commit/ef7cf185 Signed-off-by: Jose Marinho Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acdebug.h | 2 ++ drivers/acpi/acpica/dbcmds.c | 58 +++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/acpica/dbinput.c | 8 ++++++ 3 files changed, 68 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index 22f1f7a9e5a3..911875c5a5f1 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -287,4 +287,6 @@ struct acpi_namespace_node *acpi_db_local_ns_lookup(char *name); void acpi_db_uint32_to_hex_string(u32 value, char *buffer); +void acpi_db_generate_interrupt(char *gsiv_arg); + #endif /* __ACDEBUG_H__ */ diff --git a/drivers/acpi/acpica/dbcmds.c b/drivers/acpi/acpica/dbcmds.c index 9eb68e0751c7..3d99a9048585 100644 --- a/drivers/acpi/acpica/dbcmds.c +++ b/drivers/acpi/acpica/dbcmds.c @@ -1010,6 +1010,64 @@ void acpi_db_display_resources(char *object_arg) acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); } +/******************************************************************************* + * + * FUNCTION: acpi_db_generate_ged + * + * PARAMETERS: ged_arg - Raw GED number, ascii string + * + * RETURN: None + * + * DESCRIPTION: Simulate firing of a GED + * + ******************************************************************************/ + +void acpi_db_generate_interrupt(char *gsiv_arg) +{ + u32 gsiv_number; + struct acpi_ged_handler_info *ged_info = acpi_gbl_ged_handler_list; + + if (!ged_info) { + acpi_os_printf("No GED handling present\n"); + } + + gsiv_number = strtoul(gsiv_arg, NULL, 0); + + while (ged_info) { + + if (ged_info->int_id == gsiv_number) { + struct acpi_object_list arg_list; + union acpi_object arg0; + acpi_handle evt_handle = ged_info->evt_method; + acpi_status status; + + acpi_os_printf("Evaluate GED _EVT (GSIV=%d)\n", + gsiv_number); + + if (!evt_handle) { + acpi_os_printf("Undefined _EVT method\n"); + return; + } + + arg0.integer.type = ACPI_TYPE_INTEGER; + arg0.integer.value = gsiv_number; + + arg_list.count = 1; + arg_list.pointer = &arg0; + + status = + acpi_evaluate_object(evt_handle, NULL, &arg_list, + NULL); + if (ACPI_FAILURE(status)) { + acpi_os_printf("Could not evaluate _EVT\n"); + return; + } + + } + ged_info = ged_info->next; + } +} + #if (!ACPI_REDUCED_HARDWARE) /******************************************************************************* * diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c index b8a48923064f..861b12c334ab 100644 --- a/drivers/acpi/acpica/dbinput.c +++ b/drivers/acpi/acpica/dbinput.c @@ -106,6 +106,7 @@ enum acpi_ex_debugger_commands { CMD_THREADS, CMD_TEST, + CMD_INTERRUPT, #endif }; @@ -185,6 +186,7 @@ static const struct acpi_db_command_info acpi_gbl_db_commands[] = { {"THREADS", 3}, {"TEST", 1}, + {"INTERRUPT", 1}, #endif {NULL, 0} }; @@ -318,6 +320,7 @@ static const struct acpi_db_command_help acpi_gbl_db_command_help[] = { {1, " Gpes", "Display info on all GPE devices\n"}, {1, " Sci", "Generate an SCI\n"}, {1, " Sleep [SleepState]", "Simulate sleep/wake sequence(s) (0-5)\n"}, + {1, " Interrupt ", "Simulate an interrupt\n"}, #endif {0, NULL, NULL} }; @@ -1064,6 +1067,11 @@ acpi_db_command_dispatch(char *input_buffer, acpi_os_printf("Event command not implemented\n"); break; + case CMD_INTERRUPT: + + acpi_db_generate_interrupt(acpi_gbl_db_args[1]); + break; + case CMD_GPE: acpi_db_generate_gpe(acpi_gbl_db_args[1], acpi_gbl_db_args[2]); -- cgit v1.2.3-70-g09d2 From 1e8d007a6adb6c64e9ee9c809d6f9c11d3ed0c70 Mon Sep 17 00:00:00 2001 From: Christophe Jaillet <679652+tititiou36@users.noreply.github.com> Date: Mon, 29 May 2023 17:09:43 +0200 Subject: ACPICA: Slightly simplify an error message in acpi_ds_result_push() ACPICA commit 3a9dbc5cb1573b87a16b50918977ab9e53e24408 'object' is known to be NULL at this point. There is little value to log it twice in the error message. Link: https://github.com/acpica/acpica/commit/3a9dbc5c Signed-off-by: Christophe JAILLET Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/dswstate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c index d3841ded3a81..75338a13c802 100644 --- a/drivers/acpi/acpica/dswstate.c +++ b/drivers/acpi/acpica/dswstate.c @@ -146,8 +146,8 @@ acpi_ds_result_push(union acpi_operand_object *object, if (!object) { ACPI_ERROR((AE_INFO, - "Null Object! Obj=%p State=%p Num=%u", - object, walk_state, walk_state->result_count)); + "Null Object! State=%p Num=%u", + walk_state, walk_state->result_count)); return (AE_BAD_PARAMETER); } -- cgit v1.2.3-70-g09d2 From 3a21ffdbc825e0919db9da0e27ee5ff2cc8a863e Mon Sep 17 00:00:00 2001 From: Abhishek Mainkar Date: Mon, 26 Jun 2023 22:26:06 +0000 Subject: ACPICA: Add AML_NO_OPERAND_RESOLVE flag to Timer ACPICA commit 90310989a0790032f5a0140741ff09b545af4bc5 According to the ACPI specification 19.6.134, no argument is required to be passed for ASL Timer instruction. For taking care of no argument, AML_NO_OPERAND_RESOLVE flag is added to ASL Timer instruction opcode. When ASL timer instruction interpreted by ACPI interpreter, getting error. After adding AML_NO_OPERAND_RESOLVE flag to ASL Timer instruction opcode, issue is not observed. ============================================================= UBSAN: array-index-out-of-bounds in acpica/dswexec.c:401:12 index -1 is out of range for type 'union acpi_operand_object *[9]' CPU: 37 PID: 1678 Comm: cat Not tainted 6.0.0-dev-th500-6.0.y-1+bcf8c46459e407-generic-64k HW name: NVIDIA BIOS v1.1.1-d7acbfc-dirty 12/19/2022 Call trace: dump_backtrace+0xe0/0x130 show_stack+0x20/0x60 dump_stack_lvl+0x68/0x84 dump_stack+0x18/0x34 ubsan_epilogue+0x10/0x50 __ubsan_handle_out_of_bounds+0x80/0x90 acpi_ds_exec_end_op+0x1bc/0x6d8 acpi_ps_parse_loop+0x57c/0x618 acpi_ps_parse_aml+0x1e0/0x4b4 acpi_ps_execute_method+0x24c/0x2b8 acpi_ns_evaluate+0x3a8/0x4bc acpi_evaluate_object+0x15c/0x37c acpi_evaluate_integer+0x54/0x15c show_power+0x8c/0x12c [acpi_power_meter] Link: https://github.com/acpica/acpica/commit/90310989 Signed-off-by: Abhishek Mainkar Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/psopcode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c index 09029fe545f1..39e31030e5f4 100644 --- a/drivers/acpi/acpica/psopcode.c +++ b/drivers/acpi/acpica/psopcode.c @@ -603,7 +603,7 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { /* 7E */ ACPI_OP("Timer", ARGP_TIMER_OP, ARGI_TIMER_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_0A_0T_1R, - AML_FLAGS_EXEC_0A_0T_1R), + AML_FLAGS_EXEC_0A_0T_1R | AML_NO_OPERAND_RESOLVE), /* ACPI 5.0 opcodes */ -- cgit v1.2.3-70-g09d2 From 0a0e2ea642f6e4a7fe4953f8f44a310d190c39ba Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 10 Jul 2023 17:03:29 +0300 Subject: 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(-) (limited to 'drivers/acpi') 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); +} -- cgit v1.2.3-70-g09d2 From 3272a4aadc4c91f1f9518cf6638e7e81f9ac0336 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 10 Jul 2023 17:03:30 +0300 Subject: 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(-) (limited to 'drivers/acpi') 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; -- cgit v1.2.3-70-g09d2 From c5e4d05db8602acebb532a393f10fb4cc4761467 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 10 Jul 2023 17:03:31 +0300 Subject: 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(-) (limited to 'drivers/acpi') 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) -- cgit v1.2.3-70-g09d2 From c9e6c5e64f0c00612dc429bc401da0ea673e5130 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 10 Jul 2023 17:03:32 +0300 Subject: 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 (limited to 'drivers/acpi') 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__ */ -- cgit v1.2.3-70-g09d2 From 4f37ab5e05df9a30d64663266c7f4ba3a1407c68 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 10 Jul 2023 17:03:33 +0300 Subject: 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(-) (limited to 'drivers/acpi') 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)) -- cgit v1.2.3-70-g09d2 From b9e8d0168a7a85e05d031130b247099018e2194e Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 10 Jul 2023 17:03:34 +0300 Subject: 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(-) (limited to 'drivers/acpi') 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]); } -- cgit v1.2.3-70-g09d2 From 5ba30be7fd6e3fdff1e0b01f24173a5e6a3183b2 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 10 Jul 2023 17:03:35 +0300 Subject: 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(-) (limited to 'drivers/acpi') 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 | \ -- cgit v1.2.3-70-g09d2 From c542ce36a9f0bbf7c3a607ee31f1c39fda280782 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 3 Jul 2023 11:02:44 +0300 Subject: ACPI: bus: Introduce wrappers for ACPICA notify handler install/remove Introduce new functions acpi_dev_install_notify_handler() and acpi_dev_remove_notify_handler(), to install and remove, respectively, a handler for AML Notify() operations targeted at a given ACPI device object. They will allow drivers to install Notify() handlers directly instead of providing an ACPI driver .notify() callback to be invoked in the context of a Notify() handler installed by the ACPI bus type code. In particular, this will help platform drivers to provide Notify() handlers for the ACPI companions of the platform devices they bind to. These functions are replacements for acpi_device_install_notify_handler() and acpi_device_remove_notify_handler(), respectively, and after all drivers switch over to using them, the old ones will be dropped. Suggested-by: Rafael J. Wysocki Signed-off-by: Michal Wilczynski [ rjw: Subject and changelog edits, whitespace adjustments ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 24 ++++++++++++++++++++++++ include/acpi/acpi_bus.h | 6 ++++++ 2 files changed, 30 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 2fc2b43a4ed3..b5688839be1b 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -554,6 +554,30 @@ static void acpi_device_remove_notify_handler(struct acpi_device *device, acpi_os_wait_events_complete(); } +int acpi_dev_install_notify_handler(struct acpi_device *adev, + u32 handler_type, + acpi_notify_handler handler) +{ + acpi_status status; + + status = acpi_install_notify_handler(adev->handle, handler_type, + handler, adev); + if (ACPI_FAILURE(status)) + return -ENODEV; + + return 0; +} +EXPORT_SYMBOL_GPL(acpi_dev_install_notify_handler); + +void acpi_dev_remove_notify_handler(struct acpi_device *adev, + u32 handler_type, + acpi_notify_handler handler) +{ + acpi_remove_notify_handler(adev->handle, handler_type, handler); + acpi_os_wait_events_complete(); +} +EXPORT_SYMBOL_GPL(acpi_dev_remove_notify_handler); + /* Handle events targeting \_SB device (at present only graceful shutdown) */ #define ACPI_SB_NOTIFY_SHUTDOWN_REQUEST 0x81 diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index c941d99162c0..23fbe4a16972 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -515,6 +515,12 @@ void acpi_bus_private_data_handler(acpi_handle, void *); int acpi_bus_get_private_data(acpi_handle, void **); int acpi_bus_attach_private_data(acpi_handle, void *); void acpi_bus_detach_private_data(acpi_handle); +int acpi_dev_install_notify_handler(struct acpi_device *adev, + u32 handler_type, + acpi_notify_handler handler); +void acpi_dev_remove_notify_handler(struct acpi_device *adev, + u32 handler_type, + acpi_notify_handler handler); extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32); extern int register_acpi_notifier(struct notifier_block *); extern int unregister_acpi_notifier(struct notifier_block *); -- cgit v1.2.3-70-g09d2 From 0d16710146a10cf62b3efddee8ffd006432d5d7e Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 3 Jul 2023 11:02:45 +0300 Subject: ACPI: bus: Set driver_data to NULL every time .add() fails Most ACPI drivers set driver_data in their .add() callbacks, but usually they don't clear it in the error code path. Set driver_data to NULL in acpi_device_probe() to prevent stale pointers from staying around. Signed-off-by: Michal Wilczynski [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index b5688839be1b..0168b3a556b6 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -1029,8 +1029,10 @@ static int acpi_device_probe(struct device *dev) return -ENOSYS; ret = acpi_drv->ops.add(acpi_dev); - if (ret) + if (ret) { + acpi_dev->driver_data = NULL; return ret; + } pr_debug("Driver [%s] successfully bound to device [%s]\n", acpi_drv->name, acpi_dev->pnp.bus_id); -- cgit v1.2.3-70-g09d2 From 543a2d115ae63dd4c6d931d714fd5b5d3c362f55 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 3 Jul 2023 11:02:46 +0300 Subject: ACPI: AC: Install Notify() handler directly Modify the ACPI AC driver to install its own Notify() handler directly instead of providing an ACPI driver .notify() callback. This will allow the ACPI driver .notify() callback to be eliminated and it will allow the AC driver to be switched over to a platform one in the future. Suggested-by: Rafael J. Wysocki Signed-off-by: Michal Wilczynski [ rjw: Subject and changelog edits, whitespace adjustments ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ac.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 1ace70b831cd..225dc6818751 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -34,7 +34,7 @@ MODULE_LICENSE("GPL"); static int acpi_ac_add(struct acpi_device *device); static void acpi_ac_remove(struct acpi_device *device); -static void acpi_ac_notify(struct acpi_device *device, u32 event); +static void acpi_ac_notify(acpi_handle handle, u32 event, void *data); static const struct acpi_device_id ac_device_ids[] = { {"ACPI0003", 0}, @@ -54,11 +54,9 @@ static struct acpi_driver acpi_ac_driver = { .name = "ac", .class = ACPI_AC_CLASS, .ids = ac_device_ids, - .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, .ops = { .add = acpi_ac_add, .remove = acpi_ac_remove, - .notify = acpi_ac_notify, }, .drv.pm = &acpi_ac_pm, }; @@ -128,8 +126,9 @@ static enum power_supply_property ac_props[] = { }; /* Driver Model */ -static void acpi_ac_notify(struct acpi_device *device, u32 event) +static void acpi_ac_notify(acpi_handle handle, u32 event, void *data) { + struct acpi_device *device = data; struct acpi_ac *ac = acpi_driver_data(device); if (!ac) @@ -235,7 +234,7 @@ static int acpi_ac_add(struct acpi_device *device) result = acpi_ac_get_state(ac); if (result) - goto end; + goto err_release_ac; psy_cfg.drv_data = ac; @@ -248,7 +247,7 @@ static int acpi_ac_add(struct acpi_device *device) &ac->charger_desc, &psy_cfg); if (IS_ERR(ac->charger)) { result = PTR_ERR(ac->charger); - goto end; + goto err_release_ac; } pr_info("%s [%s] (%s)\n", acpi_device_name(device), @@ -256,9 +255,19 @@ static int acpi_ac_add(struct acpi_device *device) ac->battery_nb.notifier_call = acpi_ac_battery_notify; register_acpi_notifier(&ac->battery_nb); -end: + + result = acpi_dev_install_notify_handler(device, ACPI_ALL_NOTIFY, + acpi_ac_notify); if (result) - kfree(ac); + goto err_unregister; + + return 0; + +err_unregister: + power_supply_unregister(ac->charger); + unregister_acpi_notifier(&ac->battery_nb); +err_release_ac: + kfree(ac); return result; } @@ -297,6 +306,8 @@ static void acpi_ac_remove(struct acpi_device *device) ac = acpi_driver_data(device); + acpi_dev_remove_notify_handler(device, ACPI_ALL_NOTIFY, + acpi_ac_notify); power_supply_unregister(ac->charger); unregister_acpi_notifier(&ac->battery_nb); -- cgit v1.2.3-70-g09d2 From 6f7016819766a55bf90e21fdb8a8532418009adb Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 3 Jul 2023 11:02:47 +0300 Subject: ACPI: video: Install Notify() handler directly Modify the ACPI video driver to install its own Notify() handler directly instead of providing an ACPI driver .notify() callback. This will allow the ACPI driver .notify() callback to be eliminated and it will allow the ideo driver to be switched over to a platform one in the future. Suggested-by: Rafael J. Wysocki Signed-off-by: Michal Wilczynski [ rjw: Subject and changelog edits, whitespace adjustments ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_video.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 62f4364e4460..6760303def6f 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -77,7 +77,7 @@ static DEFINE_MUTEX(video_list_lock); static LIST_HEAD(video_bus_head); static int acpi_video_bus_add(struct acpi_device *device); static void acpi_video_bus_remove(struct acpi_device *device); -static void acpi_video_bus_notify(struct acpi_device *device, u32 event); +static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data); /* * Indices in the _BCL method response: the first two items are special, @@ -104,7 +104,6 @@ static struct acpi_driver acpi_video_bus = { .ops = { .add = acpi_video_bus_add, .remove = acpi_video_bus_remove, - .notify = acpi_video_bus_notify, }, }; @@ -1527,8 +1526,9 @@ static int acpi_video_bus_stop_devices(struct acpi_video_bus *video) acpi_osi_is_win8() ? 0 : 1); } -static void acpi_video_bus_notify(struct acpi_device *device, u32 event) +static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data) { + struct acpi_device *device = data; struct acpi_video_bus *video = acpi_driver_data(device); struct input_dev *input; int keycode = 0; @@ -2053,8 +2053,19 @@ static int acpi_video_bus_add(struct acpi_device *device) acpi_video_bus_add_notify_handler(video); + error = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, + acpi_video_bus_notify); + if (error) + goto err_remove; + return 0; +err_remove: + mutex_lock(&video_list_lock); + list_del(&video->entry); + mutex_unlock(&video_list_lock); + acpi_video_bus_remove_notify_handler(video); + acpi_video_bus_unregister_backlight(video); err_put_video: acpi_video_bus_put_devices(video); kfree(video->attached_array); @@ -2075,6 +2086,9 @@ static void acpi_video_bus_remove(struct acpi_device *device) video = acpi_driver_data(device); + acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY, + acpi_video_bus_notify); + mutex_lock(&video_list_lock); list_del(&video->entry); mutex_unlock(&video_list_lock); -- cgit v1.2.3-70-g09d2 From 10666251554c576617cbaf043d38c86f31f588a7 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 3 Jul 2023 11:02:48 +0300 Subject: ACPI: battery: Install Notify() handler directly Modify the ACPI battery driver to install its own Notify() handler directly instead of providing an ACPI driver .notify() callback. This will allow the ACPI driver .notify() callback to be eliminated and it will allow the battery driver to be switched over to a platform one in the future. While at it, fix up whitespaces in acpi_battery_remove(). Suggested-by: Rafael J. Wysocki Signed-off-by: Michal Wilczynski [ rjw: Subject and changelog edits, whitespace adjustments ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/battery.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 9c67ed02d797..969bf81e8d54 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -1034,8 +1034,9 @@ static void acpi_battery_refresh(struct acpi_battery *battery) } /* Driver Interface */ -static void acpi_battery_notify(struct acpi_device *device, u32 event) +static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) { + struct acpi_device *device = data; struct acpi_battery *battery = acpi_driver_data(device); struct power_supply *old; @@ -1212,13 +1213,22 @@ static int acpi_battery_add(struct acpi_device *device) device_init_wakeup(&device->dev, 1); - return result; + result = acpi_dev_install_notify_handler(device, ACPI_ALL_NOTIFY, + acpi_battery_notify); + if (result) + goto fail_pm; + + return 0; +fail_pm: + device_init_wakeup(&device->dev, 0); + unregister_pm_notifier(&battery->pm_nb); fail: sysfs_remove_battery(battery); mutex_destroy(&battery->lock); mutex_destroy(&battery->sysfs_lock); kfree(battery); + return result; } @@ -1228,10 +1238,16 @@ static void acpi_battery_remove(struct acpi_device *device) if (!device || !acpi_driver_data(device)) return; - device_init_wakeup(&device->dev, 0); + battery = acpi_driver_data(device); + + acpi_dev_remove_notify_handler(device, ACPI_ALL_NOTIFY, + acpi_battery_notify); + + device_init_wakeup(&device->dev, 0); unregister_pm_notifier(&battery->pm_nb); sysfs_remove_battery(battery); + mutex_destroy(&battery->lock); mutex_destroy(&battery->sysfs_lock); kfree(battery); @@ -1264,11 +1280,9 @@ static struct acpi_driver acpi_battery_driver = { .name = "battery", .class = ACPI_BATTERY_CLASS, .ids = battery_device_ids, - .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, .ops = { .add = acpi_battery_add, .remove = acpi_battery_remove, - .notify = acpi_battery_notify, }, .drv.pm = &acpi_battery_pm, }; -- cgit v1.2.3-70-g09d2 From 898ff0f005bada644913fc0e463ff9b9ff6d6ff3 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 3 Jul 2023 11:02:49 +0300 Subject: ACPI: HED: Install Notify() handler directly Modify the ACPI HED driver to install its own Notify() handler directly instead of providing an ACPI driver .notify() callback. This will allow the ACPI driver .notify() callback to be eliminated and it will allow the HED driver to be switched over to a platform one in the future. Suggested-by: Rafael J. Wysocki Signed-off-by: Michal Wilczynski [ rjw: Subject and changelog edits, whitespace adjustments ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/hed.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/hed.c b/drivers/acpi/hed.c index 78d44e3fe129..46c6f8c35b43 100644 --- a/drivers/acpi/hed.c +++ b/drivers/acpi/hed.c @@ -42,22 +42,32 @@ EXPORT_SYMBOL_GPL(unregister_acpi_hed_notifier); * it is used by HEST Generic Hardware Error Source with notify type * SCI. */ -static void acpi_hed_notify(struct acpi_device *device, u32 event) +static void acpi_hed_notify(acpi_handle handle, u32 event, void *data) { blocking_notifier_call_chain(&acpi_hed_notify_list, 0, NULL); } static int acpi_hed_add(struct acpi_device *device) { + int err; + /* Only one hardware error device */ if (hed_handle) return -EINVAL; hed_handle = device->handle; - return 0; + + err = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, + acpi_hed_notify); + if (err) + hed_handle = NULL; + + return err; } static void acpi_hed_remove(struct acpi_device *device) { + acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY, + acpi_hed_notify); hed_handle = NULL; } @@ -68,7 +78,6 @@ static struct acpi_driver acpi_hed_driver = { .ops = { .add = acpi_hed_add, .remove = acpi_hed_remove, - .notify = acpi_hed_notify, }, }; module_acpi_driver(acpi_hed_driver); -- cgit v1.2.3-70-g09d2 From dcca12ab62a27cc190335161bae39f4593f708ba Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 3 Jul 2023 11:02:50 +0300 Subject: ACPI: NFIT: Install Notify() handler directly Modify the ACPI NFIT driver to install its own Notify() handler directly instead of providing an ACPI driver .notify() callback. This will allow the ACPI driver .notify() callback to be eliminated. Suggested-by: Rafael J. Wysocki Signed-off-by: Michal Wilczynski [ rjw: Subject and changelog edits, whitespace adjustments ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/nfit/core.c | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 07204d482968..9dd6ff003765 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -3282,6 +3282,23 @@ static void acpi_nfit_put_table(void *table) acpi_put_table(table); } +static void acpi_nfit_notify(acpi_handle handle, u32 event, void *data) +{ + struct acpi_device *adev = data; + + device_lock(&adev->dev); + __acpi_nfit_notify(&adev->dev, handle, event); + device_unlock(&adev->dev); +} + +static void acpi_nfit_remove_notify_handler(void *data) +{ + struct acpi_device *adev = data; + + acpi_dev_remove_notify_handler(adev, ACPI_DEVICE_NOTIFY, + acpi_nfit_notify); +} + void acpi_nfit_shutdown(void *data) { struct acpi_nfit_desc *acpi_desc = data; @@ -3368,7 +3385,18 @@ static int acpi_nfit_add(struct acpi_device *adev) if (rc) return rc; - return devm_add_action_or_reset(dev, acpi_nfit_shutdown, acpi_desc); + + rc = devm_add_action_or_reset(dev, acpi_nfit_shutdown, acpi_desc); + if (rc) + return rc; + + rc = acpi_dev_install_notify_handler(adev, ACPI_DEVICE_NOTIFY, + acpi_nfit_notify); + if (rc) + return rc; + + return devm_add_action_or_reset(dev, acpi_nfit_remove_notify_handler, + adev); } static void acpi_nfit_remove(struct acpi_device *adev) @@ -3446,13 +3474,6 @@ void __acpi_nfit_notify(struct device *dev, acpi_handle handle, u32 event) } EXPORT_SYMBOL_GPL(__acpi_nfit_notify); -static void acpi_nfit_notify(struct acpi_device *adev, u32 event) -{ - device_lock(&adev->dev); - __acpi_nfit_notify(&adev->dev, adev->handle, event); - device_unlock(&adev->dev); -} - static const struct acpi_device_id acpi_nfit_ids[] = { { "ACPI0012", 0 }, { "", 0 }, @@ -3465,7 +3486,6 @@ static struct acpi_driver acpi_nfit_driver = { .ops = { .add = acpi_nfit_add, .remove = acpi_nfit_remove, - .notify = acpi_nfit_notify, }, }; -- cgit v1.2.3-70-g09d2 From 1c28250403ae25da150346de86e96322318339e5 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 3 Jul 2023 11:02:51 +0300 Subject: ACPI: NFIT: Remove unnecessary .remove callback The ACPI NFIT driver provides an empty function as it's .remove() callback which is not necessary, so drop the empty acpi_nfit_remove() and the .remove() callback initialization from it. Suggested-by: Dan Williams Signed-off-by: Michal Wilczynski [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/nfit/core.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 9dd6ff003765..f0e6738ae3c9 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -3399,11 +3399,6 @@ static int acpi_nfit_add(struct acpi_device *adev) adev); } -static void acpi_nfit_remove(struct acpi_device *adev) -{ - /* see acpi_nfit_unregister */ -} - static void acpi_nfit_update_notify(struct device *dev, acpi_handle handle) { struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(dev); @@ -3485,7 +3480,6 @@ static struct acpi_driver acpi_nfit_driver = { .ids = acpi_nfit_ids, .ops = { .add = acpi_nfit_add, - .remove = acpi_nfit_remove, }, }; -- cgit v1.2.3-70-g09d2 From 9d67b6acf1358b67a6de3302dc9c344a7cab4807 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 3 Jul 2023 11:02:52 +0300 Subject: ACPI: thermal: Install Notify() handler directly Modify the ACPI thermal driver to install its own Notify() handler directly instead of providing an ACPI driver .notify() callback. This will allow the ACPI driver .notify() callback to be eliminated and it will allow the thermal driver to be switched over to a platform one in the future. While at it, fix up whitespaces in acpi_thermal_remove(). Suggested-by: Rafael J. Wysocki Signed-off-by: Michal Wilczynski [ rjw: Subject and changelog edits, whitespace adjustments ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/thermal.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index f9f6ebb08fdb..7d543ede775e 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -825,8 +825,9 @@ static void acpi_queue_thermal_check(struct acpi_thermal *tz) queue_work(acpi_thermal_pm_queue, &tz->thermal_check_work); } -static void acpi_thermal_notify(struct acpi_device *device, u32 event) +static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data) { + struct acpi_device *device = data; struct acpi_thermal *tz = acpi_driver_data(device); if (!tz) @@ -997,11 +998,20 @@ static int acpi_thermal_add(struct acpi_device *device) pr_info("%s [%s] (%ld C)\n", acpi_device_name(device), acpi_device_bid(device), deci_kelvin_to_celsius(tz->temperature)); - goto end; + result = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, + acpi_thermal_notify); + if (result) + goto flush_wq; + + return 0; + +flush_wq: + flush_workqueue(acpi_thermal_pm_queue); + acpi_thermal_unregister_thermal_zone(tz); free_memory: kfree(tz); -end: + return result; } @@ -1012,10 +1022,14 @@ static void acpi_thermal_remove(struct acpi_device *device) if (!device || !acpi_driver_data(device)) return; - flush_workqueue(acpi_thermal_pm_queue); tz = acpi_driver_data(device); + acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY, + acpi_thermal_notify); + + flush_workqueue(acpi_thermal_pm_queue); acpi_thermal_unregister_thermal_zone(tz); + kfree(tz); } @@ -1078,7 +1092,6 @@ static struct acpi_driver acpi_thermal_driver = { .ops = { .add = acpi_thermal_add, .remove = acpi_thermal_remove, - .notify = acpi_thermal_notify, }, .drv.pm = &acpi_thermal_pm, }; -- cgit v1.2.3-70-g09d2 From 95272641338a32734792fe4b261001847b11ed80 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 10 Jul 2023 17:03:36 +0300 Subject: 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(-) (limited to 'drivers/acpi') 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 /* -------------------------------------------------------------------------- -- cgit v1.2.3-70-g09d2 From 11e7bf5629fa6a78b72a2b755c0a8f0bbd512593 Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 10 Jul 2023 17:03:37 +0300 Subject: 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(-) (limited to 'drivers/acpi') 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; -- cgit v1.2.3-70-g09d2 From 96b709be183c56293933ef45b8b75f8af268c6de Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Tue, 18 Apr 2023 08:42:00 +0200 Subject: ACPI: video: Add backlight=native DMI quirk for Lenovo Ideapad Z470 The Lenovo Ideapad Z470 predates Windows 8, so it defaults to using acpi_video for backlight control. But this is not functional on this model. Add a DMI quirk to use the native backlight interface which works. Link: https://bugzilla.suse.com/show_bug.cgi?id=1208724 Signed-off-by: Jiri Slaby (SUSE) Reviewed-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- drivers/acpi/video_detect.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 18cc08c858cf..0c376edd64fe 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -445,6 +445,15 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_BOARD_NAME, "Lenovo IdeaPad S405"), }, }, + { + /* https://bugzilla.suse.com/show_bug.cgi?id=1208724 */ + .callback = video_detect_force_native, + /* Lenovo Ideapad Z470 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "IdeaPad Z470"), + }, + }, { /* https://bugzilla.redhat.com/show_bug.cgi?id=1187004 */ .callback = video_detect_force_native, -- cgit v1.2.3-70-g09d2 From 5f641174a12b8a876a4101201a21ef4675ecc014 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 12 Jul 2023 12:24:59 -0500 Subject: ACPI: thermal: Drop nocrt parameter The `nocrt` module parameter has no code associated with it and does nothing. As `crt=-1` has same functionality as what nocrt should be doing drop `nocrt` and associated documentation. This should fix a quirk for Gigabyte GA-7ZX that used `nocrt` and thus didn't function properly. Fixes: 8c99fdce3078 ("ACPI: thermal: set "thermal.nocrt" via DMI on Gigabyte GA-7ZX") Signed-off-by: Mario Limonciello Cc: All applicable Signed-off-by: Rafael J. Wysocki --- Documentation/admin-guide/kernel-parameters.txt | 4 ---- drivers/acpi/thermal.c | 6 +----- 2 files changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers/acpi') diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index a1457995fd41..2de235d52fac 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -6243,10 +6243,6 @@ -1: disable all critical trip points in all thermal zones : override all critical trip points - thermal.nocrt= [HW,ACPI] - Set to disable actions on ACPI thermal zone - critical and hot trip points. - thermal.off= [HW,ACPI] 1: disable ACPI thermal control diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index f9f6ebb08fdb..3163a40f02e3 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -82,10 +82,6 @@ static int tzp; module_param(tzp, int, 0444); MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds."); -static int nocrt; -module_param(nocrt, int, 0); -MODULE_PARM_DESC(nocrt, "Set to take no action upon ACPI thermal zone critical trips points."); - static int off; module_param(off, int, 0); MODULE_PARM_DESC(off, "Set to disable ACPI thermal support."); @@ -1094,7 +1090,7 @@ static int thermal_act(const struct dmi_system_id *d) { static int thermal_nocrt(const struct dmi_system_id *d) { pr_notice("%s detected: disabling all critical thermal trip point actions.\n", d->ident); - nocrt = 1; + crt = -1; return 0; } static int thermal_tzp(const struct dmi_system_id *d) { -- cgit v1.2.3-70-g09d2 From 003e0694fcd3d51ee2d55dafb2def501f9965cbd Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 19 Jul 2023 18:02:44 +0200 Subject: 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(-) (limited to 'drivers/acpi') 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(); } } -- cgit v1.2.3-70-g09d2 From fc001b36e50f4136c6b8d9fceaf17fc145ffbd0d Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Thu, 27 Jul 2023 14:33:47 +0100 Subject: ACPI: Move AMBA bus scan handling into arm64 specific directory Commit fcea0ccf4fd7 ("ACPI: bus: Consolidate all arm specific initialisation into acpi_arm_init()") moved all of the ARM-specific initialization into acpi_arm_init(). However, acpi_amba.c being outside of drivers/acpi/arm64 got ignored and hence acpi_amba_init() was not moved into acpi_arm_init(). Move the AMBA platform bus support into arm64 specific folder and make acpi_amba_init() part of acpi_arm_init(). Signed-off-by: Sudeep Holla Signed-off-by: Rafael J. Wysocki --- drivers/acpi/Makefile | 1 - drivers/acpi/acpi_amba.c | 130 -------------------------------------------- drivers/acpi/arm64/Makefile | 1 + drivers/acpi/arm64/amba.c | 130 ++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/arm64/init.c | 2 + drivers/acpi/arm64/init.h | 1 + drivers/acpi/internal.h | 5 -- drivers/acpi/scan.c | 1 - 8 files changed, 134 insertions(+), 137 deletions(-) delete mode 100644 drivers/acpi/acpi_amba.c create mode 100644 drivers/acpi/arm64/amba.c (limited to 'drivers/acpi') diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 3fc5a0d54f6e..eaa09bf52f17 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -50,7 +50,6 @@ acpi-$(CONFIG_PCI) += acpi_lpss.o acpi-y += acpi_apd.o acpi-y += acpi_platform.o acpi-y += acpi_pnp.o -acpi-$(CONFIG_ARM_AMBA) += acpi_amba.o acpi-y += power.o acpi-y += event.o acpi-y += evged.o diff --git a/drivers/acpi/acpi_amba.c b/drivers/acpi/acpi_amba.c deleted file mode 100644 index f5b443ab01c2..000000000000 --- a/drivers/acpi/acpi_amba.c +++ /dev/null @@ -1,130 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only - -/* - * ACPI support for platform bus type. - * - * Copyright (C) 2015, Linaro Ltd - * Author: Graeme Gregory - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" - -static const struct acpi_device_id amba_id_list[] = { - {"ARMH0061", 0}, /* PL061 GPIO Device */ - {"ARMH0330", 0}, /* ARM DMA Controller DMA-330 */ - {"ARMHC500", 0}, /* ARM CoreSight ETM4x */ - {"ARMHC501", 0}, /* ARM CoreSight ETR */ - {"ARMHC502", 0}, /* ARM CoreSight STM */ - {"ARMHC503", 0}, /* ARM CoreSight Debug */ - {"ARMHC979", 0}, /* ARM CoreSight TPIU */ - {"ARMHC97C", 0}, /* ARM CoreSight SoC-400 TMC, SoC-600 ETF/ETB */ - {"ARMHC98D", 0}, /* ARM CoreSight Dynamic Replicator */ - {"ARMHC9CA", 0}, /* ARM CoreSight CATU */ - {"ARMHC9FF", 0}, /* ARM CoreSight Dynamic Funnel */ - {"", 0}, -}; - -static void amba_register_dummy_clk(void) -{ - static struct clk *amba_dummy_clk; - - /* If clock already registered */ - if (amba_dummy_clk) - return; - - amba_dummy_clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, 0, 0); - clk_register_clkdev(amba_dummy_clk, "apb_pclk", NULL); -} - -static int amba_handler_attach(struct acpi_device *adev, - const struct acpi_device_id *id) -{ - struct acpi_device *parent = acpi_dev_parent(adev); - struct amba_device *dev; - struct resource_entry *rentry; - struct list_head resource_list; - bool address_found = false; - int irq_no = 0; - int ret; - - /* If the ACPI node already has a physical device attached, skip it. */ - if (adev->physical_node_count) - return 0; - - dev = amba_device_alloc(dev_name(&adev->dev), 0, 0); - if (!dev) { - dev_err(&adev->dev, "%s(): amba_device_alloc() failed\n", - __func__); - return -ENOMEM; - } - - INIT_LIST_HEAD(&resource_list); - ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); - if (ret < 0) - goto err_free; - - list_for_each_entry(rentry, &resource_list, node) { - switch (resource_type(rentry->res)) { - case IORESOURCE_MEM: - if (!address_found) { - dev->res = *rentry->res; - dev->res.name = dev_name(&dev->dev); - address_found = true; - } - break; - case IORESOURCE_IRQ: - if (irq_no < AMBA_NR_IRQS) - dev->irq[irq_no++] = rentry->res->start; - break; - default: - dev_warn(&adev->dev, "Invalid resource\n"); - break; - } - } - - acpi_dev_free_resource_list(&resource_list); - - /* - * If the ACPI node has a parent and that parent has a physical device - * attached to it, that physical device should be the parent of - * the amba device we are about to create. - */ - if (parent) - dev->dev.parent = acpi_get_first_physical_node(parent); - - ACPI_COMPANION_SET(&dev->dev, adev); - - ret = amba_device_add(dev, &iomem_resource); - if (ret) { - dev_err(&adev->dev, "%s(): amba_device_add() failed (%d)\n", - __func__, ret); - goto err_free; - } - - return 1; - -err_free: - amba_device_put(dev); - return ret; -} - -static struct acpi_scan_handler amba_handler = { - .ids = amba_id_list, - .attach = amba_handler_attach, -}; - -void __init acpi_amba_init(void) -{ - amba_register_dummy_clk(); - acpi_scan_add_handler(&amba_handler); -} diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile index f81fe24894b2..143debc1ba4a 100644 --- a/drivers/acpi/arm64/Makefile +++ b/drivers/acpi/arm64/Makefile @@ -3,4 +3,5 @@ obj-$(CONFIG_ACPI_AGDI) += agdi.o obj-$(CONFIG_ACPI_IORT) += iort.o obj-$(CONFIG_ACPI_GTDT) += gtdt.o obj-$(CONFIG_ACPI_APMT) += apmt.o +obj-$(CONFIG_ARM_AMBA) += amba.o obj-y += dma.o init.o diff --git a/drivers/acpi/arm64/amba.c b/drivers/acpi/arm64/amba.c new file mode 100644 index 000000000000..b2a7631d7ac7 --- /dev/null +++ b/drivers/acpi/arm64/amba.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * ACPI support for platform bus type. + * + * Copyright (C) 2015, Linaro Ltd + * Author: Graeme Gregory + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "init.h" + +static const struct acpi_device_id amba_id_list[] = { + {"ARMH0061", 0}, /* PL061 GPIO Device */ + {"ARMH0330", 0}, /* ARM DMA Controller DMA-330 */ + {"ARMHC500", 0}, /* ARM CoreSight ETM4x */ + {"ARMHC501", 0}, /* ARM CoreSight ETR */ + {"ARMHC502", 0}, /* ARM CoreSight STM */ + {"ARMHC503", 0}, /* ARM CoreSight Debug */ + {"ARMHC979", 0}, /* ARM CoreSight TPIU */ + {"ARMHC97C", 0}, /* ARM CoreSight SoC-400 TMC, SoC-600 ETF/ETB */ + {"ARMHC98D", 0}, /* ARM CoreSight Dynamic Replicator */ + {"ARMHC9CA", 0}, /* ARM CoreSight CATU */ + {"ARMHC9FF", 0}, /* ARM CoreSight Dynamic Funnel */ + {"", 0}, +}; + +static void amba_register_dummy_clk(void) +{ + static struct clk *amba_dummy_clk; + + /* If clock already registered */ + if (amba_dummy_clk) + return; + + amba_dummy_clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, 0, 0); + clk_register_clkdev(amba_dummy_clk, "apb_pclk", NULL); +} + +static int amba_handler_attach(struct acpi_device *adev, + const struct acpi_device_id *id) +{ + struct acpi_device *parent = acpi_dev_parent(adev); + struct amba_device *dev; + struct resource_entry *rentry; + struct list_head resource_list; + bool address_found = false; + int irq_no = 0; + int ret; + + /* If the ACPI node already has a physical device attached, skip it. */ + if (adev->physical_node_count) + return 0; + + dev = amba_device_alloc(dev_name(&adev->dev), 0, 0); + if (!dev) { + dev_err(&adev->dev, "%s(): amba_device_alloc() failed\n", + __func__); + return -ENOMEM; + } + + INIT_LIST_HEAD(&resource_list); + ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); + if (ret < 0) + goto err_free; + + list_for_each_entry(rentry, &resource_list, node) { + switch (resource_type(rentry->res)) { + case IORESOURCE_MEM: + if (!address_found) { + dev->res = *rentry->res; + dev->res.name = dev_name(&dev->dev); + address_found = true; + } + break; + case IORESOURCE_IRQ: + if (irq_no < AMBA_NR_IRQS) + dev->irq[irq_no++] = rentry->res->start; + break; + default: + dev_warn(&adev->dev, "Invalid resource\n"); + break; + } + } + + acpi_dev_free_resource_list(&resource_list); + + /* + * If the ACPI node has a parent and that parent has a physical device + * attached to it, that physical device should be the parent of + * the amba device we are about to create. + */ + if (parent) + dev->dev.parent = acpi_get_first_physical_node(parent); + + ACPI_COMPANION_SET(&dev->dev, adev); + + ret = amba_device_add(dev, &iomem_resource); + if (ret) { + dev_err(&adev->dev, "%s(): amba_device_add() failed (%d)\n", + __func__, ret); + goto err_free; + } + + return 1; + +err_free: + amba_device_put(dev); + return ret; +} + +static struct acpi_scan_handler amba_handler = { + .ids = amba_id_list, + .attach = amba_handler_attach, +}; + +void __init acpi_amba_init(void) +{ + amba_register_dummy_clk(); + acpi_scan_add_handler(&amba_handler); +} diff --git a/drivers/acpi/arm64/init.c b/drivers/acpi/arm64/init.c index d3ce53dda122..d0c8aed90fd1 100644 --- a/drivers/acpi/arm64/init.c +++ b/drivers/acpi/arm64/init.c @@ -10,4 +10,6 @@ void __init acpi_arm_init(void) acpi_apmt_init(); if (IS_ENABLED(CONFIG_ACPI_IORT)) acpi_iort_init(); + if (IS_ENABLED(CONFIG_ARM_AMBA)) + acpi_amba_init(); } diff --git a/drivers/acpi/arm64/init.h b/drivers/acpi/arm64/init.h index a1715a2a34e9..dcc277977194 100644 --- a/drivers/acpi/arm64/init.h +++ b/drivers/acpi/arm64/init.h @@ -4,3 +4,4 @@ void __init acpi_agdi_init(void); void __init acpi_apmt_init(void); void __init acpi_iort_init(void); +void __init acpi_amba_init(void); diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index f4148dc50b9c..21ec31b78216 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -28,11 +28,6 @@ void acpi_processor_init(void); void acpi_platform_init(void); void acpi_pnp_init(void); void acpi_int340x_thermal_init(void); -#ifdef CONFIG_ARM_AMBA -void acpi_amba_init(void); -#else -static inline void acpi_amba_init(void) {} -#endif int acpi_sysfs_init(void); void acpi_gpe_apply_masked_gpes(void); void acpi_container_init(void); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 5b145f1aaa1b..902763430d56 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2615,7 +2615,6 @@ void __init acpi_scan_init(void) acpi_watchdog_init(); acpi_pnp_init(); acpi_int340x_thermal_init(); - acpi_amba_init(); acpi_init_lpit(); acpi_scan_add_handler(&generic_device_handler); -- cgit v1.2.3-70-g09d2 From dabc621a311007d78bfcf60f8125c5e8c33ded7b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 25 Jul 2023 20:06:37 +0200 Subject: ACPI: thermal: Drop enabled flag from struct acpi_thermal_active The enabled field of struct acpi_thermal_active is only updated and never read, so drop it along with the related code. No intentional functional impact. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/thermal.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 3163a40f02e3..3aab121cd410 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -115,7 +115,6 @@ struct acpi_thermal_active { struct acpi_handle_list devices; unsigned long temperature; bool valid; - bool enabled; }; struct acpi_thermal_trips { @@ -1039,15 +1038,10 @@ static int acpi_thermal_resume(struct device *dev) if (!tz->trips.active[i].valid) break; - tz->trips.active[i].enabled = true; for (j = 0; j < tz->trips.active[i].devices.count; j++) { result = acpi_bus_update_power( tz->trips.active[i].devices.handles[j], &power_state); - if (result || (power_state != ACPI_STATE_D0)) { - tz->trips.active[i].enabled = false; - break; - } } } -- cgit v1.2.3-70-g09d2 From 868a4715a88114e914144fe07a630cd7230ab848 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 8 Aug 2023 22:15:15 +0200 Subject: ACPI: thermal: Do not attach private data to ACPI handles The ACPI thermal driver uses acpi_bus_attach_private_data() to attach the thermal zone object to the ACPI handle of the thermal zone and acpi_bus_detach_private_data() to clean that up, but it never uses acpi_bus_get_private_data() to retrieve that object. Drop the unneded acpi_bus_attach_private_data() and acpi_bus_detach_private_data() calls from the ACPI thermal driver and clean up the related code. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Reviewed-by: Zhang Rui --- drivers/acpi/thermal.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 3aab121cd410..a329b0dce78f 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -742,7 +742,6 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) { int trips = 0; int result; - acpi_status status; int i; if (tz->trips.critical.valid) @@ -775,24 +774,15 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) if (result) goto unregister_tzd; - status = acpi_bus_attach_private_data(tz->device->handle, - tz->thermal_zone); - if (ACPI_FAILURE(status)) { - result = -ENODEV; - goto remove_links; - } - result = thermal_zone_device_enable(tz->thermal_zone); if (result) - goto acpi_bus_detach; + goto remove_links; dev_info(&tz->device->dev, "registered as thermal_zone%d\n", thermal_zone_device_id(tz->thermal_zone)); return 0; -acpi_bus_detach: - acpi_bus_detach_private_data(tz->device->handle); remove_links: acpi_thermal_zone_sysfs_remove(tz); unregister_tzd: @@ -806,7 +796,6 @@ static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz) acpi_thermal_zone_sysfs_remove(tz); thermal_zone_device_unregister(tz->thermal_zone); tz->thermal_zone = NULL; - acpi_bus_detach_private_data(tz->device->handle); } -- cgit v1.2.3-70-g09d2 From eca3f0a8ff86b8f21061033043d243e4a466da05 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 10 Aug 2023 20:49:08 +0200 Subject: ACPI: thermal: Drop redundant local variable from acpi_thermal_resume() Commit dabc621a3110 ("ACPI: thermal: Drop enabled flag from struct acpi_thermal_active") left behind a variable that is only assigned to and never read, so drop it now. Fixes: dabc621a3110 ("ACPI: thermal: Drop enabled flag from struct acpi_thermal_active") Signed-off-by: Rafael J. Wysocki --- drivers/acpi/thermal.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index a329b0dce78f..2fc02e90c400 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -1014,7 +1014,7 @@ static int acpi_thermal_suspend(struct device *dev) static int acpi_thermal_resume(struct device *dev) { struct acpi_thermal *tz; - int i, j, power_state, result; + int i, j, power_state; if (!dev) return -EINVAL; @@ -1028,9 +1028,8 @@ static int acpi_thermal_resume(struct device *dev) break; for (j = 0; j < tz->trips.active[i].devices.count; j++) { - result = acpi_bus_update_power( - tz->trips.active[i].devices.handles[j], - &power_state); + acpi_bus_update_power(tz->trips.active[i].devices.handles[j], + &power_state); } } -- cgit v1.2.3-70-g09d2 From bf07b4a3ba3446ba4bbe1ddac235162dbda2ce57 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 7 Aug 2023 20:06:13 +0200 Subject: ACPI: thermal: Clean up acpi_thermal_register_thermal_zone() Rename the trips variable in acpi_thermal_register_thermal_zone() to trip_count so its name better reflects the purpose, rearrange white space in the loop over active trips for clarity and reduce code duplication related to calling thermal_zone_device_register() by using an extra local variable to store the passive delay value. No intentional functional impact. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/thermal.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 45a32b0148d9..4db33da40144 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -740,33 +740,29 @@ static void acpi_thermal_zone_sysfs_remove(struct acpi_thermal *tz) static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) { - int trips = 0; + int passive_delay = 0; + int trip_count = 0; int result; int i; if (tz->trips.critical.valid) - trips++; + trip_count++; if (tz->trips.hot.valid) - trips++; + trip_count++; - if (tz->trips.passive.valid) - trips++; - - for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips.active[i].valid; - i++, trips++); + if (tz->trips.passive.valid) { + trip_count++; + passive_delay = tz->trips.passive.tsp * 100; + } - if (tz->trips.passive.valid) - tz->thermal_zone = thermal_zone_device_register("acpitz", trips, 0, tz, - &acpi_thermal_zone_ops, NULL, - tz->trips.passive.tsp * 100, - tz->polling_frequency * 100); - else - tz->thermal_zone = - thermal_zone_device_register("acpitz", trips, 0, tz, - &acpi_thermal_zone_ops, NULL, - 0, tz->polling_frequency * 100); + for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips.active[i].valid; i++) + trip_count++; + tz->thermal_zone = thermal_zone_device_register("acpitz", trip_count, 0, + tz, &acpi_thermal_zone_ops, + NULL, passive_delay, + tz->polling_frequency * 100); if (IS_ERR(tz->thermal_zone)) return -ENODEV; -- cgit v1.2.3-70-g09d2 From 68f4f0378c0cee5c6b6308c1fd6eb7677f354cad Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 17 Aug 2023 11:24:27 +0200 Subject: ACPI: thermal: Carry out trip point updates under zone lock There is a race condition between acpi_thermal_trips_update() and acpi_thermal_check_fn(), because the trip points may get updated while the latter is running which in theory may lead to inconsistent results. For example, if two trips are updated together, using the temperature value of one of them from before the update and the temperature value of the other one from after the update may not lead to the expected outcome. Moreover, if thermal_get_trend() runs when a trip points update is in progress, it may end up using stale trip point temperatures. To address this, make acpi_thermal_trips_update() call thermal_zone_device_exec() to carry out the trip points update and use a new acpi_thermal_adjust_thermal_zone() wrapper around __acpi_thermal_trips_update() as the callback function for the latter. While at it, change the acpi_thermal_trips_update() return data type to void as that function always returns 0 anyway. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/thermal.c | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 4db33da40144..582984c0e8ea 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -185,7 +185,7 @@ static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz) return 0; } -static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) +static void __acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) { acpi_status status; unsigned long long tmp; @@ -393,17 +393,40 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) ACPI_THERMAL_TRIPS_EXCEPTION(flag, tz, "device"); } } +} - return 0; +static void acpi_thermal_adjust_thermal_zone(struct thermal_zone_device *thermal, + unsigned long data) +{ + __acpi_thermal_trips_update(thermal_zone_device_priv(thermal), data); +} + +static void acpi_queue_thermal_check(struct acpi_thermal *tz) +{ + if (!work_pending(&tz->thermal_check_work)) + queue_work(acpi_thermal_pm_queue, &tz->thermal_check_work); +} + +static void acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) +{ + /* + * Use thermal_zone_device_exec() to carry out the trip points + * update, so as to protect thermal_get_trend() from getting stale + * trip point temperatures and to prevent thermal_zone_device_update() + * invoked from acpi_thermal_check_fn() from producing inconsistent + * results. + */ + thermal_zone_device_exec(tz->thermal_zone, + acpi_thermal_adjust_thermal_zone, flag); + acpi_queue_thermal_check(tz); } static int acpi_thermal_get_trip_points(struct acpi_thermal *tz) { - int i, ret = acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT); bool valid; + int i; - if (ret) - return ret; + __acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT); valid = tz->trips.critical.valid | tz->trips.hot.valid | @@ -799,12 +822,6 @@ static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz) Driver Interface -------------------------------------------------------------------------- */ -static void acpi_queue_thermal_check(struct acpi_thermal *tz) -{ - if (!work_pending(&tz->thermal_check_work)) - queue_work(acpi_thermal_pm_queue, &tz->thermal_check_work); -} - static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data) { struct acpi_device *device = data; @@ -819,13 +836,11 @@ static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data) break; case ACPI_THERMAL_NOTIFY_THRESHOLDS: acpi_thermal_trips_update(tz, ACPI_TRIPS_THRESHOLDS); - acpi_queue_thermal_check(tz); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, 0); break; case ACPI_THERMAL_NOTIFY_DEVICES: acpi_thermal_trips_update(tz, ACPI_TRIPS_DEVICES); - acpi_queue_thermal_check(tz); acpi_bus_generate_netlink_event(device->pnp.device_class, dev_name(&device->dev), event, 0); break; -- cgit v1.2.3-70-g09d2 From 68b77785a1db293582558bc1460b19e8355b8f7a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 7 Aug 2023 20:10:06 +0200 Subject: ACPI: thermal: Introduce struct acpi_thermal_trip Add struct acpi_thermal_trip to contain the temperature and valid flag of each trip point in the driver's local data structures. This helps to make the subsequent changes more straightforward. No intentional functional impact. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/thermal.c | 96 +++++++++++++++++++++++--------------------------- 1 file changed, 45 insertions(+), 51 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 582984c0e8ea..bfbbbbdc658c 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -92,34 +92,27 @@ MODULE_PARM_DESC(psv, "Disable or override all passive trip points."); static struct workqueue_struct *acpi_thermal_pm_queue; -struct acpi_thermal_critical { - unsigned long temperature; - bool valid; -}; - -struct acpi_thermal_hot { +struct acpi_thermal_trip { unsigned long temperature; bool valid; }; struct acpi_thermal_passive { + struct acpi_thermal_trip trip; struct acpi_handle_list devices; - unsigned long temperature; unsigned long tc1; unsigned long tc2; unsigned long tsp; - bool valid; }; struct acpi_thermal_active { + struct acpi_thermal_trip trip; struct acpi_handle_list devices; - unsigned long temperature; - bool valid; }; struct acpi_thermal_trips { - struct acpi_thermal_critical critical; - struct acpi_thermal_hot hot; + struct acpi_thermal_trip critical; + struct acpi_thermal_trip hot; struct acpi_thermal_passive passive; struct acpi_thermal_active active[ACPI_THERMAL_MAX_ACTIVE]; }; @@ -250,9 +243,9 @@ static void __acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) } /* Passive (optional) */ - if (((flag & ACPI_TRIPS_PASSIVE) && tz->trips.passive.valid) || + if (((flag & ACPI_TRIPS_PASSIVE) && tz->trips.passive.trip.valid) || flag == ACPI_TRIPS_INIT) { - valid = tz->trips.passive.valid; + valid = tz->trips.passive.trip.valid; if (psv == -1) { status = AE_SUPPORT; } else if (psv > 0) { @@ -264,44 +257,44 @@ static void __acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) } if (ACPI_FAILURE(status)) { - tz->trips.passive.valid = false; + tz->trips.passive.trip.valid = false; } else { - tz->trips.passive.temperature = tmp; - tz->trips.passive.valid = true; + tz->trips.passive.trip.temperature = tmp; + tz->trips.passive.trip.valid = true; if (flag == ACPI_TRIPS_INIT) { status = acpi_evaluate_integer(tz->device->handle, "_TC1", NULL, &tmp); if (ACPI_FAILURE(status)) - tz->trips.passive.valid = false; + tz->trips.passive.trip.valid = false; else tz->trips.passive.tc1 = tmp; status = acpi_evaluate_integer(tz->device->handle, "_TC2", NULL, &tmp); if (ACPI_FAILURE(status)) - tz->trips.passive.valid = false; + tz->trips.passive.trip.valid = false; else tz->trips.passive.tc2 = tmp; status = acpi_evaluate_integer(tz->device->handle, "_TSP", NULL, &tmp); if (ACPI_FAILURE(status)) - tz->trips.passive.valid = false; + tz->trips.passive.trip.valid = false; else tz->trips.passive.tsp = tmp; } } } - if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.valid) { + if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.trip.valid) { memset(&devices, 0, sizeof(struct acpi_handle_list)); status = acpi_evaluate_reference(tz->device->handle, "_PSL", NULL, &devices); if (ACPI_FAILURE(status)) { acpi_handle_info(tz->device->handle, "Invalid passive threshold\n"); - tz->trips.passive.valid = false; + tz->trips.passive.trip.valid = false; } else { - tz->trips.passive.valid = true; + tz->trips.passive.trip.valid = true; } if (memcmp(&tz->trips.passive.devices, &devices, @@ -312,24 +305,24 @@ static void __acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) } } if ((flag & ACPI_TRIPS_PASSIVE) || (flag & ACPI_TRIPS_DEVICES)) { - if (valid != tz->trips.passive.valid) + if (valid != tz->trips.passive.trip.valid) ACPI_THERMAL_TRIPS_EXCEPTION(flag, tz, "state"); } /* Active (optional) */ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { char name[5] = { '_', 'A', 'C', ('0' + i), '\0' }; - valid = tz->trips.active[i].valid; + valid = tz->trips.active[i].trip.valid; if (act == -1) break; /* disable all active trip points */ if (flag == ACPI_TRIPS_INIT || ((flag & ACPI_TRIPS_ACTIVE) && - tz->trips.active[i].valid)) { + tz->trips.active[i].trip.valid)) { status = acpi_evaluate_integer(tz->device->handle, name, NULL, &tmp); if (ACPI_FAILURE(status)) { - tz->trips.active[i].valid = false; + tz->trips.active[i].trip.valid = false; if (i == 0) break; @@ -337,35 +330,36 @@ static void __acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) break; if (i == 1) - tz->trips.active[0].temperature = celsius_to_deci_kelvin(act); + tz->trips.active[0].trip.temperature = + celsius_to_deci_kelvin(act); else /* * Don't allow override higher than * the next higher trip point */ - tz->trips.active[i-1].temperature = + tz->trips.active[i-1].trip.temperature = min_t(unsigned long, - tz->trips.active[i-2].temperature, + tz->trips.active[i-2].trip.temperature, celsius_to_deci_kelvin(act)); break; } else { - tz->trips.active[i].temperature = tmp; - tz->trips.active[i].valid = true; + tz->trips.active[i].trip.temperature = tmp; + tz->trips.active[i].trip.valid = true; } } name[2] = 'L'; - if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].valid) { + if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].trip.valid) { memset(&devices, 0, sizeof(struct acpi_handle_list)); status = acpi_evaluate_reference(tz->device->handle, name, NULL, &devices); if (ACPI_FAILURE(status)) { acpi_handle_info(tz->device->handle, "Invalid active%d threshold\n", i); - tz->trips.active[i].valid = false; + tz->trips.active[i].trip.valid = false; } else { - tz->trips.active[i].valid = true; + tz->trips.active[i].trip.valid = true; } if (memcmp(&tz->trips.active[i].devices, &devices, @@ -376,10 +370,10 @@ static void __acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) } } if ((flag & ACPI_TRIPS_ACTIVE) || (flag & ACPI_TRIPS_DEVICES)) - if (valid != tz->trips.active[i].valid) + if (valid != tz->trips.active[i].trip.valid) ACPI_THERMAL_TRIPS_EXCEPTION(flag, tz, "state"); - if (!tz->trips.active[i].valid) + if (!tz->trips.active[i].trip.valid) break; } @@ -430,10 +424,10 @@ static int acpi_thermal_get_trip_points(struct acpi_thermal *tz) valid = tz->trips.critical.valid | tz->trips.hot.valid | - tz->trips.passive.valid; + tz->trips.passive.trip.valid; for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) - valid = valid || tz->trips.active[i].valid; + valid = valid || tz->trips.active[i].trip.valid; if (!valid) { pr_warn(FW_BUG "No valid trip found\n"); @@ -486,7 +480,7 @@ static int thermal_get_trip_type(struct thermal_zone_device *thermal, trip--; } - if (tz->trips.passive.valid) { + if (tz->trips.passive.trip.valid) { if (!trip) { *type = THERMAL_TRIP_PASSIVE; return 0; @@ -494,7 +488,7 @@ static int thermal_get_trip_type(struct thermal_zone_device *thermal, trip--; } - for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips.active[i].valid; i++) { + for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips.active[i].trip.valid; i++) { if (!trip) { *type = THERMAL_TRIP_ACTIVE; return 0; @@ -534,10 +528,10 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal, trip--; } - if (tz->trips.passive.valid) { + if (tz->trips.passive.trip.valid) { if (!trip) { *temp = deci_kelvin_to_millicelsius_with_offset( - tz->trips.passive.temperature, + tz->trips.passive.trip.temperature, tz->kelvin_offset); return 0; } @@ -545,10 +539,10 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal, } for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && - tz->trips.active[i].valid; i++) { + tz->trips.active[i].trip.valid; i++) { if (!trip) { *temp = deci_kelvin_to_millicelsius_with_offset( - tz->trips.active[i].temperature, + tz->trips.active[i].trip.temperature, tz->kelvin_offset); return 0; } @@ -604,7 +598,7 @@ static int thermal_get_trend(struct thermal_zone_device *thermal, * before this callback being invoked */ i = tz->trips.passive.tc1 * (tz->temperature - tz->last_temperature) + - tz->trips.passive.tc2 * (tz->temperature - tz->trips.passive.temperature); + tz->trips.passive.tc2 * (tz->temperature - tz->trips.passive.trip.temperature); if (i > 0) *trend = THERMAL_TREND_RAISING; @@ -655,7 +649,7 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, if (tz->trips.hot.valid) trip++; - if (tz->trips.passive.valid) { + if (tz->trips.passive.trip.valid) { trip++; for (i = 0; i < tz->trips.passive.devices.count; i++) { handle = tz->trips.passive.devices.handles[i]; @@ -680,7 +674,7 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, } for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { - if (!tz->trips.active[i].valid) + if (!tz->trips.active[i].trip.valid) break; trip++; @@ -774,12 +768,12 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) if (tz->trips.hot.valid) trip_count++; - if (tz->trips.passive.valid) { + if (tz->trips.passive.trip.valid) { trip_count++; passive_delay = tz->trips.passive.tsp * 100; } - for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips.active[i].valid; i++) + for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips.active[i].trip.valid; i++) trip_count++; tz->thermal_zone = thermal_zone_device_register("acpitz", trip_count, 0, @@ -1049,7 +1043,7 @@ static int acpi_thermal_resume(struct device *dev) return -EINVAL; for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { - if (!tz->trips.active[i].valid) + if (!tz->trips.active[i].trip.valid) break; for (j = 0; j < tz->trips.active[i].devices.count; j++) { -- cgit v1.2.3-70-g09d2 From ec23c1c462ded022ec0c3ed3fa92af6ca25b9599 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 9 Aug 2023 13:07:23 +0200 Subject: ACPI: thermal: Use trip point table to register thermal zones Make the ACPI thermal driver use thermal_zone_device_register_with_trips() to register its thermal zones. For this purpose, make it create a trip point table that will be passed to thermal_zone_device_register_with_trips() as an argument. Also use the thermal_zone_update_trip_temp() helper introduced previously to update temperatures of the passive and active trip points after a trip points change notification from the platform firmware. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/thermal.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 86 insertions(+), 7 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index bfbbbbdc658c..c2fe806fd3d7 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -125,6 +125,7 @@ struct acpi_thermal { unsigned long polling_frequency; volatile u8 zombie; struct acpi_thermal_trips trips; + struct thermal_trip *trip_table; struct acpi_handle_list devices; struct thermal_zone_device *thermal_zone; int kelvin_offset; /* in millidegrees */ @@ -178,6 +179,15 @@ static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz) return 0; } +static int acpi_thermal_temp(struct acpi_thermal *tz, int temp_deci_k) +{ + if (temp_deci_k == THERMAL_TEMP_INVALID) + return THERMAL_TEMP_INVALID; + + return deci_kelvin_to_millicelsius_with_offset(temp_deci_k, + tz->kelvin_offset); +} + static void __acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) { acpi_status status; @@ -389,10 +399,30 @@ static void __acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) } } +static int acpi_thermal_adjust_trip(struct thermal_trip *trip, void *data) +{ + struct acpi_thermal_trip *acpi_trip = trip->priv; + struct acpi_thermal *tz = data; + + if (!acpi_trip) + return 0; + + if (acpi_trip->valid) + trip->temperature = acpi_thermal_temp(tz, acpi_trip->temperature); + else + trip->temperature = THERMAL_TEMP_INVALID; + + return 0; +} + static void acpi_thermal_adjust_thermal_zone(struct thermal_zone_device *thermal, unsigned long data) { - __acpi_thermal_trips_update(thermal_zone_device_priv(thermal), data); + struct acpi_thermal *tz = thermal_zone_device_priv(thermal); + + __acpi_thermal_trips_update(tz, data); + + for_each_thermal_trip(tz->thermal_zone, acpi_thermal_adjust_trip, tz); } static void acpi_queue_thermal_check(struct acpi_thermal *tz) @@ -757,6 +787,8 @@ static void acpi_thermal_zone_sysfs_remove(struct acpi_thermal *tz) static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) { + struct acpi_thermal_trip *acpi_trip; + struct thermal_trip *trip; int passive_delay = 0; int trip_count = 0; int result; @@ -776,12 +808,56 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips.active[i].trip.valid; i++) trip_count++; - tz->thermal_zone = thermal_zone_device_register("acpitz", trip_count, 0, - tz, &acpi_thermal_zone_ops, - NULL, passive_delay, - tz->polling_frequency * 100); - if (IS_ERR(tz->thermal_zone)) - return -ENODEV; + trip = kcalloc(trip_count, sizeof(*trip), GFP_KERNEL); + if (!trip) + return -ENOMEM; + + tz->trip_table = trip; + + if (tz->trips.critical.valid) { + trip->type = THERMAL_TRIP_CRITICAL; + trip->temperature = acpi_thermal_temp(tz, tz->trips.critical.temperature); + trip++; + } + + if (tz->trips.hot.valid) { + trip->type = THERMAL_TRIP_HOT; + trip->temperature = acpi_thermal_temp(tz, tz->trips.hot.temperature); + trip++; + } + + acpi_trip = &tz->trips.passive.trip; + if (acpi_trip->valid) { + trip->type = THERMAL_TRIP_PASSIVE; + trip->temperature = acpi_thermal_temp(tz, acpi_trip->temperature); + trip->priv = acpi_trip; + trip++; + } + + for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { + acpi_trip = &tz->trips.active[i].trip; + + if (!acpi_trip->valid) + break; + + trip->type = THERMAL_TRIP_ACTIVE; + trip->temperature = acpi_thermal_temp(tz, acpi_trip->temperature); + trip->priv = acpi_trip; + trip++; + } + + tz->thermal_zone = thermal_zone_device_register_with_trips("acpitz", + tz->trip_table, + trip_count, + 0, tz, + &acpi_thermal_zone_ops, + NULL, + passive_delay, + tz->polling_frequency * 100); + if (IS_ERR(tz->thermal_zone)) { + result = PTR_ERR(tz->thermal_zone); + goto free_trip_table; + } result = acpi_thermal_zone_sysfs_add(tz); if (result) @@ -800,6 +876,8 @@ remove_links: acpi_thermal_zone_sysfs_remove(tz); unregister_tzd: thermal_zone_device_unregister(tz->thermal_zone); +free_trip_table: + kfree(tz->trip_table); return result; } @@ -808,6 +886,7 @@ static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz) { acpi_thermal_zone_sysfs_remove(tz); thermal_zone_device_unregister(tz->thermal_zone); + kfree(tz->trip_table); tz->thermal_zone = NULL; } -- cgit v1.2.3-70-g09d2 From 9caaad2ca02cb31fc235249f971cabdf8e11e28d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 7 Aug 2023 20:17:07 +0200 Subject: ACPI: thermal: Rework thermal_get_trend() Rework the ACPI thermal driver's .get_trend() callback function, thermal_get_trend(), so that it does not call thermal_get_trip_type() and thermal_get_trip_temp() which are going to be dropped. This reduces the overhead of the function too, because it will always carry out a trip point lookup once after the change. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/thermal.c | 66 ++++++++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 29 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index c2fe806fd3d7..bd540e4fb4d0 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -598,46 +598,54 @@ static int thermal_get_crit_temp(struct thermal_zone_device *thermal, } static int thermal_get_trend(struct thermal_zone_device *thermal, - int trip, enum thermal_trend *trend) + int trip_index, enum thermal_trend *trend) { struct acpi_thermal *tz = thermal_zone_device_priv(thermal); - enum thermal_trip_type type; - int i; + struct acpi_thermal_trip *acpi_trip; + int t, i; - if (thermal_get_trip_type(thermal, trip, &type)) + if (!tz || trip_index < 0) return -EINVAL; - if (type == THERMAL_TRIP_ACTIVE) { - int trip_temp; - int temp = deci_kelvin_to_millicelsius_with_offset( - tz->temperature, tz->kelvin_offset); - if (thermal_get_trip_temp(thermal, trip, &trip_temp)) - return -EINVAL; + if (tz->trips.critical.valid) + trip_index--; + + if (tz->trips.hot.valid) + trip_index--; + + if (trip_index < 0) + return -EINVAL; - if (temp > trip_temp) { + acpi_trip = &tz->trips.passive.trip; + if (acpi_trip->valid && !trip_index--) { + t = tz->trips.passive.tc1 * (tz->temperature - + tz->last_temperature) + + tz->trips.passive.tc2 * (tz->temperature - + acpi_trip->temperature); + if (t > 0) *trend = THERMAL_TREND_RAISING; - return 0; - } else { - /* Fall back on default trend */ - return -EINVAL; - } + else if (t < 0) + *trend = THERMAL_TREND_DROPPING; + else + *trend = THERMAL_TREND_STABLE; + + return 0; } - /* - * tz->temperature has already been updated by generic thermal layer, - * before this callback being invoked - */ - i = tz->trips.passive.tc1 * (tz->temperature - tz->last_temperature) + - tz->trips.passive.tc2 * (tz->temperature - tz->trips.passive.trip.temperature); + t = acpi_thermal_temp(tz, tz->temperature); - if (i > 0) - *trend = THERMAL_TREND_RAISING; - else if (i < 0) - *trend = THERMAL_TREND_DROPPING; - else - *trend = THERMAL_TREND_STABLE; + for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { + acpi_trip = &tz->trips.active[i].trip; + if (acpi_trip->valid && !trip_index--) { + if (t > acpi_thermal_temp(tz, acpi_trip->temperature)) { + *trend = THERMAL_TREND_RAISING; + return 0; + } + break; + } + } - return 0; + return -EINVAL; } static void acpi_thermal_zone_device_hot(struct thermal_zone_device *thermal) -- cgit v1.2.3-70-g09d2 From 2a74c4aca1d70c4ec8104997470fda2fed5de322 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 7 Aug 2023 20:18:49 +0200 Subject: ACPI: thermal: Drop unnecessary thermal zone callbacks Drop the .get_trip_type(), .get_trip_temp() and .get_crit_temp() thermal zone callbacks that are not necessary any more from the ACPI thermal driver along with the corresponding callback functions. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/thermal.c | 115 ------------------------------------------------- 1 file changed, 115 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index bd540e4fb4d0..2b4cb06d00ba 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -485,118 +485,6 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp) return 0; } -static int thermal_get_trip_type(struct thermal_zone_device *thermal, - int trip, enum thermal_trip_type *type) -{ - struct acpi_thermal *tz = thermal_zone_device_priv(thermal); - int i; - - if (!tz || trip < 0) - return -EINVAL; - - if (tz->trips.critical.valid) { - if (!trip) { - *type = THERMAL_TRIP_CRITICAL; - return 0; - } - trip--; - } - - if (tz->trips.hot.valid) { - if (!trip) { - *type = THERMAL_TRIP_HOT; - return 0; - } - trip--; - } - - if (tz->trips.passive.trip.valid) { - if (!trip) { - *type = THERMAL_TRIP_PASSIVE; - return 0; - } - trip--; - } - - for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips.active[i].trip.valid; i++) { - if (!trip) { - *type = THERMAL_TRIP_ACTIVE; - return 0; - } - trip--; - } - - return -EINVAL; -} - -static int thermal_get_trip_temp(struct thermal_zone_device *thermal, - int trip, int *temp) -{ - struct acpi_thermal *tz = thermal_zone_device_priv(thermal); - int i; - - if (!tz || trip < 0) - return -EINVAL; - - if (tz->trips.critical.valid) { - if (!trip) { - *temp = deci_kelvin_to_millicelsius_with_offset( - tz->trips.critical.temperature, - tz->kelvin_offset); - return 0; - } - trip--; - } - - if (tz->trips.hot.valid) { - if (!trip) { - *temp = deci_kelvin_to_millicelsius_with_offset( - tz->trips.hot.temperature, - tz->kelvin_offset); - return 0; - } - trip--; - } - - if (tz->trips.passive.trip.valid) { - if (!trip) { - *temp = deci_kelvin_to_millicelsius_with_offset( - tz->trips.passive.trip.temperature, - tz->kelvin_offset); - return 0; - } - trip--; - } - - for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && - tz->trips.active[i].trip.valid; i++) { - if (!trip) { - *temp = deci_kelvin_to_millicelsius_with_offset( - tz->trips.active[i].trip.temperature, - tz->kelvin_offset); - return 0; - } - trip--; - } - - return -EINVAL; -} - -static int thermal_get_crit_temp(struct thermal_zone_device *thermal, - int *temperature) -{ - struct acpi_thermal *tz = thermal_zone_device_priv(thermal); - - if (tz->trips.critical.valid) { - *temperature = deci_kelvin_to_millicelsius_with_offset( - tz->trips.critical.temperature, - tz->kelvin_offset); - return 0; - } - - return -EINVAL; -} - static int thermal_get_trend(struct thermal_zone_device *thermal, int trip_index, enum thermal_trend *trend) { @@ -759,9 +647,6 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = { .bind = acpi_thermal_bind_cooling_device, .unbind = acpi_thermal_unbind_cooling_device, .get_temp = thermal_get_temp, - .get_trip_type = thermal_get_trip_type, - .get_trip_temp = thermal_get_trip_temp, - .get_crit_temp = thermal_get_crit_temp, .get_trend = thermal_get_trend, .hot = acpi_thermal_zone_device_hot, .critical = acpi_thermal_zone_device_critical, -- cgit v1.2.3-70-g09d2 From 4ab4b3b11dca4cda61b38147f4dd81b1b7b39e95 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 17 Aug 2023 11:25:29 +0200 Subject: ACPI: thermal: Eliminate code duplication from acpi_thermal_notify() Move the acpi_bus_generate_netlink_event() invocation into acpi_thermal_trips_update() which allows the code duplication in acpi_thermal_notify() to be cleaned up, but for this purpose the event value needs to be passed to acpi_thermal_trips_update() and from there to acpi_thermal_adjust_thermal_zone() which has to determine the flag value for __acpi_thermal_trips_update() by itself. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/thermal.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 2b4cb06d00ba..419590f41ed5 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -419,8 +419,10 @@ static void acpi_thermal_adjust_thermal_zone(struct thermal_zone_device *thermal unsigned long data) { struct acpi_thermal *tz = thermal_zone_device_priv(thermal); + int flag = data == ACPI_THERMAL_NOTIFY_THRESHOLDS ? + ACPI_TRIPS_THRESHOLDS : ACPI_TRIPS_DEVICES; - __acpi_thermal_trips_update(tz, data); + __acpi_thermal_trips_update(tz, flag); for_each_thermal_trip(tz->thermal_zone, acpi_thermal_adjust_trip, tz); } @@ -431,8 +433,10 @@ static void acpi_queue_thermal_check(struct acpi_thermal *tz) queue_work(acpi_thermal_pm_queue, &tz->thermal_check_work); } -static void acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) +static void acpi_thermal_trips_update(struct acpi_thermal *tz, u32 event) { + struct acpi_device *adev = tz->device; + /* * Use thermal_zone_device_exec() to carry out the trip points * update, so as to protect thermal_get_trend() from getting stale @@ -441,8 +445,10 @@ static void acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) * results. */ thermal_zone_device_exec(tz->thermal_zone, - acpi_thermal_adjust_thermal_zone, flag); + acpi_thermal_adjust_thermal_zone, event); acpi_queue_thermal_check(tz); + acpi_bus_generate_netlink_event(adev->pnp.device_class, + dev_name(&adev->dev), event, 0); } static int acpi_thermal_get_trip_points(struct acpi_thermal *tz) @@ -801,14 +807,8 @@ static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data) acpi_queue_thermal_check(tz); break; case ACPI_THERMAL_NOTIFY_THRESHOLDS: - acpi_thermal_trips_update(tz, ACPI_TRIPS_THRESHOLDS); - acpi_bus_generate_netlink_event(device->pnp.device_class, - dev_name(&device->dev), event, 0); - break; case ACPI_THERMAL_NOTIFY_DEVICES: - acpi_thermal_trips_update(tz, ACPI_TRIPS_DEVICES); - acpi_bus_generate_netlink_event(device->pnp.device_class, - dev_name(&device->dev), event, 0); + acpi_thermal_trips_update(tz, event); break; default: acpi_handle_debug(device->handle, "Unsupported event [0x%x]\n", -- cgit v1.2.3-70-g09d2 From 7f6fd06d34f4a9bd62bc30e9232934cfb89ae4d8 Mon Sep 17 00:00:00 2001 From: Wentong Wu Date: Sat, 29 Jul 2023 19:52:55 +0800 Subject: ACPI: scan: Defer enumeration of devices with a _DEP pointing to IVSC device Inside IVSC, switching ownership requires an interface with two different hardware modules, ACE and CSI. The software interface to these modules is based on Intel MEI framework. Usually mei client devices are dynamically created, so the info of consumers depending on mei client devices is not present in the firmware tables. This causes problems with the probe ordering with respect to drivers for consumers of these MEI client devices. But on these camera sensor devices, the ACPI nodes describing the sensors all have a _DEP dependency on the matching MEI bus ACPI device, so adding IVSC MEI bus ACPI device to acpi_honor_dep_ids allows solving the probe-ordering problem by deferring the enumeration of ACPI-devices which have a _DEP dependency on an IVSC mei bus ACPI device. On TGL platform, the HID of IVSC MEI bus ACPI device is INTC1059, and on ADL platform, the HID is INTC1095. So add both of them to acpi_honor_dep_ids. Signed-off-by: Wentong Wu Reviewed-by: Sakari Ailus [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 87e385542576..c799b03d0369 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -795,6 +795,9 @@ static const char * const acpi_ignore_dep_ids[] = { /* List of HIDs for which we honor deps of matching ACPI devs, when checking _DEP lists. */ static const char * const acpi_honor_dep_ids[] = { "INT3472", /* Camera sensor PMIC / clk and regulator info */ + "INTC1059", /* IVSC (TGL) driver must be loaded to allow i2c access to camera sensors */ + "INTC1095", /* IVSC (ADL) driver must be loaded to allow i2c access to camera sensors */ + "INTC100A", /* IVSC (RPL) driver must be loaded to allow i2c access to camera sensors */ NULL }; -- cgit v1.2.3-70-g09d2 From f6fcf03ce8a9b8c135cf47f4978617bdf2829711 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Mon, 17 Jul 2023 10:22:58 +0800 Subject: 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(+) (limited to 'drivers/acpi') 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); -- cgit v1.2.3-70-g09d2 From 89c290ea758911e660878e26270e084d862c03b0 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Fri, 21 Jul 2023 23:21:43 +0800 Subject: ACPI: video: Put ACPI video and its child devices into D0 on boot Screen brightness can only be changed once on HP ZBook Fury 16 G10. The vendor reports that the issue is related to the fact that Linux doesn't invoke _PS0 at boot for all ACPI devices, as expected by the platform firmware: Scope (\_SB.PC00.GFX0) { Scope (DD1F) { Method (_PS0, 0, Serialized) // _PS0: Power State 0 { If (CondRefOf (\_SB.PC00.LPCB.EC0.SSBC)) { \_SB.PC00.LPCB.EC0.SSBC () } } ... } ... } The \_SB.PC00.GFX0.DD1F is the panel device, and its _PS0 needs to be executed at the initialization time to make the brightness control work properly. _PS0 is not evaluated for this device, because _PSC is missing, which violates the ACPI specification (ACPI 6.5, section 7.3.6). Commit b3785492268f ("ACPI / PM: Do not power manage devices in unknown initial states") tried to work around missing _PSC on platforms with defective firmware, but got reverted due to a regression. So the safest approach is to use acpi_device_fix_up_power_extended() to put ACPI video and its child devices to D0 to address the issue at hand. Link: https://bugzilla.kernel.org/show_bug.cgi?id=217683 Signed-off-by: Kai-Heng Feng Reviewed-by: Hans de Goede [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_video.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 62f4364e4460..1732780a672b 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -2027,6 +2027,12 @@ static int acpi_video_bus_add(struct acpi_device *device) if (error) goto err_put_video; + /* + * HP ZBook Fury 16 G10 requires ACPI video's child devices have _PS0 + * evaluated to have functional panel brightness control. + */ + acpi_device_fix_up_power_extended(device); + pr_info("%s [%s] (multi-head: %s rom: %s post: %s)\n", ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device), video->flags.multihead ? "yes" : "no", -- cgit v1.2.3-70-g09d2 From 8cf04bb321f036dd2e523e993897e0789bd5265c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 7 Aug 2023 11:44:08 +0200 Subject: ACPI: video: Add backlight=native DMI quirk for Apple iMac12,1 and iMac12,2 Linux defaults to picking the non-working ACPI video backlight interface on the Apple iMac12,1 and iMac12,2. Add a DMI quirk to pick the working native radeon_bl0 interface instead. Link: https://gitlab.freedesktop.org/drm/amd/-/issues/1838 Link: https://gitlab.freedesktop.org/drm/amd/-/issues/2753 Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- drivers/acpi/video_detect.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 0c376edd64fe..442396f6ed1f 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -495,6 +495,24 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "iMac11,3"), }, }, + { + /* https://gitlab.freedesktop.org/drm/amd/-/issues/1838 */ + .callback = video_detect_force_native, + /* Apple iMac12,1 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "iMac12,1"), + }, + }, + { + /* https://gitlab.freedesktop.org/drm/amd/-/issues/2753 */ + .callback = video_detect_force_native, + /* Apple iMac12,2 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "iMac12,2"), + }, + }, { /* https://bugzilla.redhat.com/show_bug.cgi?id=1217249 */ .callback = video_detect_force_native, -- cgit v1.2.3-70-g09d2 From ae769fbd143d9f9349387f27bb4f36d2ba5b45df Mon Sep 17 00:00:00 2001 From: Xiaochun Lee Date: Wed, 2 Aug 2023 21:47:46 +0800 Subject: ACPI: extlog: Fix finding the generic error data for v3 structure Fix by using acpi_hest_get_payload() to find out the correct generic error data for v3 structure. The revision v300 generic error data is different from the old one, so for compatibility with old and new version, change to a new interface to locate the right memory error section that was defined in CPER. Signed-off-by: Xiaochun Lee Reviewed-by: Tony Luck Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_extlog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c index e648158368a7..e120a96e1eae 100644 --- a/drivers/acpi/acpi_extlog.c +++ b/drivers/acpi/acpi_extlog.c @@ -172,7 +172,7 @@ static int extlog_print(struct notifier_block *nb, unsigned long val, fru_text = ""; sec_type = (guid_t *)gdata->section_type; if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) { - struct cper_sec_mem_err *mem = (void *)(gdata + 1); + struct cper_sec_mem_err *mem = acpi_hest_get_payload(gdata); if (gdata->error_data_length >= sizeof(*mem)) trace_extlog_mem_event(mem, err_seq, fru_id, fru_text, -- cgit v1.2.3-70-g09d2 From 638f139fda4f4fcb1b244b4ac755a4c4f0a6c4a2 Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Mon, 14 Aug 2023 21:56:23 +0800 Subject: ACPI: Remove assorted unused declarations of functions acpi_create_dir()/acpi_remove_dir() are never implemented since the beginning of git history. Commit f8d31489629c ("ACPICA: Debugger: Convert some mechanisms to OSPM specific") declared but never implemented acpi_run_debugger(). Commit 781d737c7466 ("ACPI: Drop power resources driver") removed acpi_power_init() but not its declaration. Signed-off-by: Yue Haibing [ rjw: Subject edits ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/internal.h | 1 - include/acpi/acpi_bus.h | 2 -- include/acpi/acpixf.h | 2 -- 3 files changed, 5 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 21ec31b78216..956aed5afded 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -123,7 +123,6 @@ int __acpi_device_uevent_modalias(const struct acpi_device *adev, /* -------------------------------------------------------------------------- Power Resource -------------------------------------------------------------------------- */ -int acpi_power_init(void); void acpi_power_resources_list_free(struct list_head *list); int acpi_extract_power_resources(union acpi_object *package, unsigned int start, struct list_head *list); diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index c941d99162c0..449ec8a015bf 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -563,8 +563,6 @@ int acpi_match_device_ids(struct acpi_device *device, const struct acpi_device_id *ids); void acpi_set_modalias(struct acpi_device *adev, const char *default_id, char *modalias, size_t len); -int acpi_create_dir(struct acpi_device *); -void acpi_remove_dir(struct acpi_device *); static inline bool acpi_device_enumerated(struct acpi_device *adev) { diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 9ffdc0425bc2..cb64010cc5d8 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -970,8 +970,6 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status void **data, void (*callback)(void *))) -void acpi_run_debugger(char *batch_buffer); - void acpi_set_debugger_thread_id(acpi_thread_id thread_id); #endif /* __ACXFACE_H__ */ -- cgit v1.2.3-70-g09d2 From 596ca52a56da1b9370d358c38acf2ba5251687d9 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Sat, 29 Jul 2023 12:20:50 +0800 Subject: ACPI: TAD: Install SystemCMOS address space handler for ACPI000E Currently, the SystemCMOS address space handler is installed for the ACPI RTC devices (PNP0B00/PNP0B01/PNP0B02) only. But there are platforms with SystemCMOS Operetion Region defined under the ACPI Time and Alarm Device (ACPI000E), which is used by the ACPI pre-defined control methods like _GRT (Get the Real time) and _SRT (Set the Real time). When accessing these control methods via the acpi_tad sysfs interface, missing SystemCMOS address space handler causes errors like below [ 478.255453] ACPI Error: No handler for Region [RTCM] (00000000a8d2dd39) [SystemCMOS] (20230331/evregion-130) [ 478.255458] ACPI Error: Region SystemCMOS (ID=5) has no handler (20230331/exfldio-261) [ 478.255461] Initialized Local Variables for Method [_GRT]: [ 478.255461] Local1: 00000000f182542c Integer 0000000000000000 [ 478.255464] No Arguments are initialized for method [_GRT] [ 478.255465] ACPI Error: Aborting method \_SB.AWAC._GRT due to previous error (AE_NOT_EXIST) (20230331/psparse-529) Export two APIs for SystemCMOS address space handler from acpi_cmos_rtc scan handler and install the handler for the ACPI Time and Alarm Device from the ACPI TAD driver. Link: https://bugzilla.kernel.org/show_bug.cgi?id=217714 Signed-off-by: Zhang Rui [ rjw: Subject and changelog edits, whitespace adjustment ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_cmos_rtc.c | 25 ++++++++++++++++++------- drivers/acpi/acpi_tad.c | 27 ++++++++++++++++++++++----- include/acpi/acpi_bus.h | 9 +++++++++ 3 files changed, 49 insertions(+), 12 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpi_cmos_rtc.c b/drivers/acpi/acpi_cmos_rtc.c index 4cf4aef7ce0c..9b55d1593d16 100644 --- a/drivers/acpi/acpi_cmos_rtc.c +++ b/drivers/acpi/acpi_cmos_rtc.c @@ -51,12 +51,11 @@ acpi_cmos_rtc_space_handler(u32 function, acpi_physical_address address, return AE_OK; } -static int acpi_install_cmos_rtc_space_handler(struct acpi_device *adev, - const struct acpi_device_id *id) +int acpi_install_cmos_rtc_space_handler(acpi_handle handle) { acpi_status status; - status = acpi_install_address_space_handler(adev->handle, + status = acpi_install_address_space_handler(handle, ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler, NULL, NULL); @@ -67,18 +66,30 @@ static int acpi_install_cmos_rtc_space_handler(struct acpi_device *adev, return 1; } +EXPORT_SYMBOL_GPL(acpi_install_cmos_rtc_space_handler); -static void acpi_remove_cmos_rtc_space_handler(struct acpi_device *adev) +void acpi_remove_cmos_rtc_space_handler(acpi_handle handle) { - if (ACPI_FAILURE(acpi_remove_address_space_handler(adev->handle, + if (ACPI_FAILURE(acpi_remove_address_space_handler(handle, ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler))) pr_err("Error removing CMOS-RTC region handler\n"); } +EXPORT_SYMBOL_GPL(acpi_remove_cmos_rtc_space_handler); + +static int acpi_cmos_rtc_attach_handler(struct acpi_device *adev, const struct acpi_device_id *id) +{ + return acpi_install_cmos_rtc_space_handler(adev->handle); +} + +static void acpi_cmos_rtc_detach_handler(struct acpi_device *adev) +{ + acpi_remove_cmos_rtc_space_handler(adev->handle); +} static struct acpi_scan_handler cmos_rtc_handler = { .ids = acpi_cmos_rtc_ids, - .attach = acpi_install_cmos_rtc_space_handler, - .detach = acpi_remove_cmos_rtc_space_handler, + .attach = acpi_cmos_rtc_attach_handler, + .detach = acpi_cmos_rtc_detach_handler, }; void __init acpi_cmos_rtc_init(void) diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c index e9b8e8305e23..33c3b16af556 100644 --- a/drivers/acpi/acpi_tad.c +++ b/drivers/acpi/acpi_tad.c @@ -557,6 +557,7 @@ static int acpi_tad_disable_timer(struct device *dev, u32 timer_id) static int acpi_tad_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; + acpi_handle handle = ACPI_HANDLE(dev); struct acpi_tad_driver_data *dd = dev_get_drvdata(dev); device_init_wakeup(dev, false); @@ -577,6 +578,7 @@ static int acpi_tad_remove(struct platform_device *pdev) pm_runtime_put_sync(dev); pm_runtime_disable(dev); + acpi_remove_cmos_rtc_space_handler(handle); return 0; } @@ -589,6 +591,11 @@ static int acpi_tad_probe(struct platform_device *pdev) unsigned long long caps; int ret; + ret = acpi_install_cmos_rtc_space_handler(handle); + if (ret < 0) { + dev_info(dev, "Unable to install space handler\n"); + return -ENODEV; + } /* * Initialization failure messages are mostly about firmware issues, so * print them at the "info" level. @@ -596,22 +603,27 @@ static int acpi_tad_probe(struct platform_device *pdev) status = acpi_evaluate_integer(handle, "_GCP", NULL, &caps); if (ACPI_FAILURE(status)) { dev_info(dev, "Unable to get capabilities\n"); - return -ENODEV; + ret = -ENODEV; + goto remove_handler; } if (!(caps & ACPI_TAD_AC_WAKE)) { dev_info(dev, "Unsupported capabilities\n"); - return -ENODEV; + ret = -ENODEV; + goto remove_handler; } if (!acpi_has_method(handle, "_PRW")) { dev_info(dev, "Missing _PRW\n"); - return -ENODEV; + ret = -ENODEV; + goto remove_handler; } dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); - if (!dd) - return -ENOMEM; + if (!dd) { + ret = -ENOMEM; + goto remove_handler; + } dd->capabilities = caps; dev_set_drvdata(dev, dd); @@ -653,6 +665,11 @@ static int acpi_tad_probe(struct platform_device *pdev) fail: acpi_tad_remove(pdev); + /* Don't fallthrough because cmos rtc space handler is removed in acpi_tad_remove() */ + return ret; + +remove_handler: + acpi_remove_cmos_rtc_space_handler(handle); return ret; } diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index c941d99162c0..fb95fff23e5b 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -645,6 +645,8 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev); #ifdef CONFIG_X86 bool acpi_device_override_status(struct acpi_device *adev, unsigned long long *status); bool acpi_quirk_skip_acpi_ac_and_battery(void); +int acpi_install_cmos_rtc_space_handler(acpi_handle handle); +void acpi_remove_cmos_rtc_space_handler(acpi_handle handle); #else static inline bool acpi_device_override_status(struct acpi_device *adev, unsigned long long *status) @@ -655,6 +657,13 @@ static inline bool acpi_quirk_skip_acpi_ac_and_battery(void) { return false; } +static inline int acpi_install_cmos_rtc_space_handler(acpi_handle handle) +{ + return 1; +} +static inline void acpi_remove_cmos_rtc_space_handler(acpi_handle handle) +{ +} #endif #if IS_ENABLED(CONFIG_X86_ANDROID_TABLETS) -- cgit v1.2.3-70-g09d2 From 3c6b1212d20bbbffcad5709ab0f2d5ed9b5859a8 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 18 Aug 2023 14:40:02 -0500 Subject: ACPI: x86: s2idle: Post-increment variables when getting constraints When code uses a pre-increment it makes the reader question "why". In the constraint fetching code there is no reason for the variables to be pre-incremented so adjust to post-increment. No intended functional changes. Reviewed-by: Kuppuswamy Sathyanarayanan Suggested-by: Bjorn Helgaas Signed-off-by: Mario Limonciello Signed-off-by: Rafael J. Wysocki --- drivers/acpi/x86/s2idle.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c index ce62e61a9605..7711dde68947 100644 --- a/drivers/acpi/x86/s2idle.c +++ b/drivers/acpi/x86/s2idle.c @@ -123,13 +123,13 @@ static void lpi_device_get_constraints_amd(void) acpi_handle_debug(lps0_device_handle, "LPI: constraints list begin:\n"); - for (j = 0; j < package->package.count; ++j) { + for (j = 0; j < package->package.count; j++) { union acpi_object *info_obj = &package->package.elements[j]; struct lpi_device_constraint_amd dev_info = {}; struct lpi_constraints *list; acpi_status status; - for (k = 0; k < info_obj->package.count; ++k) { + for (k = 0; k < info_obj->package.count; k++) { union acpi_object *obj = &info_obj->package.elements[k]; list = &lpi_constraints_table[lpi_constraints_table_size]; @@ -214,7 +214,7 @@ static void lpi_device_get_constraints(void) if (!package) continue; - for (j = 0; j < package->package.count; ++j) { + for (j = 0; j < package->package.count; j++) { union acpi_object *element = &(package->package.elements[j]); @@ -246,7 +246,7 @@ static void lpi_device_get_constraints(void) constraint->min_dstate = -1; - for (j = 0; j < package_count; ++j) { + for (j = 0; j < package_count; j++) { union acpi_object *info_obj = &info.package[j]; union acpi_object *cnstr_pkg; union acpi_object *obj; -- cgit v1.2.3-70-g09d2 From 883cf0d4cf288313b71146ddebdf5d647b76c78b Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 18 Aug 2023 14:40:03 -0500 Subject: ACPI: x86: s2idle: Catch multiple ACPI_TYPE_PACKAGE objects If a badly constructed firmware includes multiple `ACPI_TYPE_PACKAGE` objects while evaluating the AMD LPS0 _DSM, there will be a memory leak. Explicitly guard against this. Suggested-by: Bjorn Helgaas Signed-off-by: Mario Limonciello Signed-off-by: Rafael J. Wysocki --- drivers/acpi/x86/s2idle.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c index 7711dde68947..508decbac298 100644 --- a/drivers/acpi/x86/s2idle.c +++ b/drivers/acpi/x86/s2idle.c @@ -113,6 +113,12 @@ static void lpi_device_get_constraints_amd(void) union acpi_object *package = &out_obj->package.elements[i]; if (package->type == ACPI_TYPE_PACKAGE) { + if (lpi_constraints_table) { + acpi_handle_err(lps0_device_handle, + "Duplicate constraints list\n"); + goto free_acpi_buffer; + } + lpi_constraints_table = kcalloc(package->package.count, sizeof(*lpi_constraints_table), GFP_KERNEL); -- cgit v1.2.3-70-g09d2 From 9cc8cd086f05d9a01026c65c98da88561e9c619e Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 18 Aug 2023 14:40:04 -0500 Subject: ACPI: x86: s2idle: Fix a logic error parsing AMD constraints table The constraints table should be resetting the `list` object after running through all of `info_obj` iterations. This adjusts whitespace as well as less code will now be included with each loop. This fixes a functional problem is fixed where a badly formed package in the inner loop may have incorrect data. Fixes: 146f1ed852a8 ("ACPI: PM: s2idle: Add AMD support to handle _DSM") Signed-off-by: Mario Limonciello Signed-off-by: Rafael J. Wysocki --- drivers/acpi/x86/s2idle.c | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c index 508decbac298..60835953ebfc 100644 --- a/drivers/acpi/x86/s2idle.c +++ b/drivers/acpi/x86/s2idle.c @@ -135,12 +135,11 @@ static void lpi_device_get_constraints_amd(void) struct lpi_constraints *list; acpi_status status; + list = &lpi_constraints_table[lpi_constraints_table_size]; + for (k = 0; k < info_obj->package.count; k++) { union acpi_object *obj = &info_obj->package.elements[k]; - list = &lpi_constraints_table[lpi_constraints_table_size]; - list->min_dstate = -1; - switch (k) { case 0: dev_info.enabled = obj->integer.value; @@ -155,27 +154,21 @@ static void lpi_device_get_constraints_amd(void) dev_info.min_dstate = obj->integer.value; break; } + } - if (!dev_info.enabled || !dev_info.name || - !dev_info.min_dstate) - continue; + if (!dev_info.enabled || !dev_info.name || + !dev_info.min_dstate) + continue; - status = acpi_get_handle(NULL, dev_info.name, - &list->handle); - if (ACPI_FAILURE(status)) - continue; + status = acpi_get_handle(NULL, dev_info.name, &list->handle); + if (ACPI_FAILURE(status)) + continue; - acpi_handle_debug(lps0_device_handle, - "Name:%s\n", dev_info.name); + acpi_handle_debug(lps0_device_handle, + "Name:%s\n", dev_info.name); - list->min_dstate = dev_info.min_dstate; + list->min_dstate = dev_info.min_dstate; - if (list->min_dstate < 0) { - acpi_handle_debug(lps0_device_handle, - "Incomplete constraint defined\n"); - continue; - } - } lpi_constraints_table_size++; } } -- cgit v1.2.3-70-g09d2 From a879058d01e2f6e324cc98ff2ffbe4f574c100a6 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 18 Aug 2023 14:40:05 -0500 Subject: ACPI: x86: s2idle: Add more debugging for AMD constraints parsing While parsing the constraints show all the entries for the table to aid with debugging other problems later. Signed-off-by: Mario Limonciello Signed-off-by: Rafael J. Wysocki --- drivers/acpi/x86/s2idle.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c index 60835953ebfc..87563337a478 100644 --- a/drivers/acpi/x86/s2idle.c +++ b/drivers/acpi/x86/s2idle.c @@ -156,6 +156,13 @@ static void lpi_device_get_constraints_amd(void) } } + acpi_handle_debug(lps0_device_handle, + "Name:%s, Enabled: %d, States: %d, MinDstate: %d\n", + dev_info.name, + dev_info.enabled, + dev_info.function_states, + dev_info.min_dstate); + if (!dev_info.enabled || !dev_info.name || !dev_info.min_dstate) continue; @@ -164,9 +171,6 @@ static void lpi_device_get_constraints_amd(void) if (ACPI_FAILURE(status)) continue; - acpi_handle_debug(lps0_device_handle, - "Name:%s\n", dev_info.name); - list->min_dstate = dev_info.min_dstate; lpi_constraints_table_size++; -- cgit v1.2.3-70-g09d2 From 41233988112f0f5fb015172a8db68a3c052aedda Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Aug 2023 14:40:06 -0500 Subject: ACPI: x86: s2idle: Add for_each_lpi_constraint() helper We have one existing and one coming user of this macro. Introduce a helper. Signed-off-by: Andy Shevchenko Signed-off-by: Mario Limonciello Signed-off-by: Rafael J. Wysocki --- drivers/acpi/x86/s2idle.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c index 87563337a478..1aa3cd5677bd 100644 --- a/drivers/acpi/x86/s2idle.c +++ b/drivers/acpi/x86/s2idle.c @@ -94,6 +94,11 @@ static struct lpi_constraints *lpi_constraints_table; static int lpi_constraints_table_size; static int rev_id; +#define for_each_lpi_constraint(entry) \ + for (int i = 0; \ + entry = &lpi_constraints_table[i], i < lpi_constraints_table_size; \ + i++) + static void lpi_device_get_constraints_amd(void) { union acpi_object *out_obj; @@ -296,30 +301,29 @@ free_acpi_buffer: static void lpi_check_constraints(void) { - int i; + struct lpi_constraints *entry; - for (i = 0; i < lpi_constraints_table_size; ++i) { - acpi_handle handle = lpi_constraints_table[i].handle; - struct acpi_device *adev = acpi_fetch_acpi_dev(handle); + for_each_lpi_constraint(entry) { + struct acpi_device *adev = acpi_fetch_acpi_dev(entry->handle); if (!adev) continue; - acpi_handle_debug(handle, + acpi_handle_debug(entry->handle, "LPI: required min power state:%s current power state:%s\n", - acpi_power_state_string(lpi_constraints_table[i].min_dstate), + acpi_power_state_string(entry->min_dstate), acpi_power_state_string(adev->power.state)); if (!adev->flags.power_manageable) { - acpi_handle_info(handle, "LPI: Device not power manageable\n"); - lpi_constraints_table[i].handle = NULL; + acpi_handle_info(entry->handle, "LPI: Device not power manageable\n"); + entry->handle = NULL; continue; } - if (adev->power.state < lpi_constraints_table[i].min_dstate) - acpi_handle_info(handle, + if (adev->power.state < entry->min_dstate) + acpi_handle_info(entry->handle, "LPI: Constraint not met; min power state:%s current power state:%s\n", - acpi_power_state_string(lpi_constraints_table[i].min_dstate), + acpi_power_state_string(entry->min_dstate), acpi_power_state_string(adev->power.state)); } } -- cgit v1.2.3-70-g09d2 From 1c2a66d47de36608551d73562d01bb4afcf1d61a Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Fri, 18 Aug 2023 14:40:07 -0500 Subject: ACPI: x86: s2idle: Add a function to get LPS0 constraint for a device Other parts of the kernel may use LPS0 constraints information to make decisions on what power state to put a device into. Signed-off-by: Mario Limonciello [ rjw: Rewrite kerneldoc, rearrange if () statement, edit subject and changelog ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/x86/s2idle.c | 24 ++++++++++++++++++++++++ include/linux/acpi.h | 6 ++++++ 2 files changed, 30 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c index 1aa3cd5677bd..08f7c6708206 100644 --- a/drivers/acpi/x86/s2idle.c +++ b/drivers/acpi/x86/s2idle.c @@ -299,6 +299,30 @@ free_acpi_buffer: ACPI_FREE(out_obj); } +/** + * acpi_get_lps0_constraint - Get the LPS0 constraint for a device. + * @adev: Device to get the constraint for. + * + * The LPS0 constraint is the shallowest (minimum) power state in which the + * device can be so as to allow the platform as a whole to achieve additional + * energy conservation by utilizing a system-wide low-power state. + * + * Returns: + * - ACPI power state value of the constraint for @adev on success. + * - Otherwise, ACPI_STATE_UNKNOWN. + */ +int acpi_get_lps0_constraint(struct acpi_device *adev) +{ + struct lpi_constraints *entry; + + for_each_lpi_constraint(entry) { + if (adev->handle == entry->handle) + return entry->min_dstate; + } + + return ACPI_STATE_UNKNOWN; +} + static void lpi_check_constraints(void) { struct lpi_constraints *entry; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 6b4966e5d7b1..9e2a15dd33e4 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -1109,6 +1109,12 @@ struct acpi_s2idle_dev_ops { }; int acpi_register_lps0_dev(struct acpi_s2idle_dev_ops *arg); void acpi_unregister_lps0_dev(struct acpi_s2idle_dev_ops *arg); +int acpi_get_lps0_constraint(struct acpi_device *adev); +#else /* CONFIG_SUSPEND && CONFIG_X86 */ +static inline int acpi_get_lps0_constraint(struct device *dev) +{ + return ACPI_STATE_UNKNOWN; +} #endif /* CONFIG_SUSPEND && CONFIG_X86 */ #ifndef CONFIG_IA64 void arch_reserve_mem_area(acpi_physical_address addr, size_t size); -- cgit v1.2.3-70-g09d2