ACPI fix for 6.11-rc4

Fix an issue related to the ACPI EC device handling that causes the
 _REG control method to be evaluated for EC operation regions that are
 not expected to be used which confuses the platform firmware and
 provokes various types of misbehavior on some systems (Rafael Wysocki).
 -----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCAAwFiEE4fcc61cGeeHD/fCwgsRv/nhiVHEFAma/fHISHHJqd0Byand5
 c29ja2kubmV0AAoJEILEb/54YlRxQXcP/1ECLnwMTDwb1ApyDCsCff5a7BzCfR+9
 tOfryqE1pW/uEEFDrDbMCFpst72RJ22LqxtC5FF4ur7PsyeEmdhAoS8Igxbz2ypt
 +cAs+utCwG8aQVC+0fuQmu8mwMc3TaknV+LXW/lLtSyzxdth/xpSrCRYRpDqYfCk
 il6Wbnc2N8RX5f78jWYiW7+IeC6KDRMlCJvlwZxBi1k/uRsZu4m3CRHEv4OGUCE2
 sOpRkpK/XT5WCSFQmq1ItFN6LWDDt93U0QBCY425F3J7R4kRg8pgo5Y+2ulMVikv
 tA5JpvPH2A103VJIX0DVznz3CtGjouDtnQNOE20Xy3kgn/KqZ9OmaYTVlARBa/zk
 t0zx/2Q5q70qB27abD/2qSbczWbDoak2U6js1qCSl1Tjca6zS5tvjZy2jPTEGL43
 QoFrMHVYpp0grn+eyOgwcwpwK6XaDBKUIvgdizSc85Yiy+DpWzGIwsMl/HmXSoga
 OwRcXjiOozuznXVcfVAXsCrmbK8bfs5pkdDBIW7nsfAfAirP+Qzid4RqcjiyVJkf
 f3gpzmy96vl0/1Z0UL4cNmmfLmFiEj2jkd2Mypp1sWI5W1GKk185A/SJ7jvNdtJb
 sDD/3MxT7YO3bERLso8iZhRzwJ5tYz5zaP9tUTo+A7p8vErBTgW9Aq9jjKhBOs0Y
 3yppKt3+hKOX
 =j+R8
 -----END PGP SIGNATURE-----

Merge tag 'acpi-6.11-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull ACPI fix from Rafael Wysocki:
 "Fix an issue related to the ACPI EC device handling that causes the
  _REG control method to be evaluated for EC operation regions that are
  not expected to be used.

  This confuses the platform firmware and provokes various types of
  misbehavior on some systems (Rafael Wysocki)"

* tag 'acpi-6.11-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  ACPI: EC: Evaluate _REG outside the EC scope more carefully
  ACPICA: Add a depth argument to acpi_execute_reg_methods()
  Revert "ACPI: EC: Evaluate orphan _REG under EC device"
This commit is contained in:
Linus Torvalds 2024-08-16 11:43:54 -07:00
commit 64ab5e4039
7 changed files with 30 additions and 74 deletions

View File

@ -188,13 +188,9 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
u8 acpi_ns_is_locked);
void
acpi_ev_execute_reg_methods(struct acpi_namespace_node *node,
acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, u32 max_depth,
acpi_adr_space_type space_id, u32 function);
void
acpi_ev_execute_orphan_reg_method(struct acpi_namespace_node *node,
acpi_adr_space_type space_id);
acpi_status
acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function);

View File

@ -20,6 +20,10 @@ extern u8 acpi_gbl_default_address_spaces[];
/* Local prototypes */
static void
acpi_ev_execute_orphan_reg_method(struct acpi_namespace_node *device_node,
acpi_adr_space_type space_id);
static acpi_status
acpi_ev_reg_run(acpi_handle obj_handle,
u32 level, void *context, void **return_value);
@ -61,6 +65,7 @@ acpi_status acpi_ev_initialize_op_regions(void)
acpi_gbl_default_address_spaces
[i])) {
acpi_ev_execute_reg_methods(acpi_gbl_root_node,
ACPI_UINT32_MAX,
acpi_gbl_default_address_spaces
[i], ACPI_REG_CONNECT);
}
@ -668,6 +673,7 @@ cleanup1:
* FUNCTION: acpi_ev_execute_reg_methods
*
* PARAMETERS: node - Namespace node for the device
* max_depth - Depth to which search for _REG
* space_id - The address space ID
* function - Passed to _REG: On (1) or Off (0)
*
@ -679,7 +685,7 @@ cleanup1:
******************************************************************************/
void
acpi_ev_execute_reg_methods(struct acpi_namespace_node *node,
acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, u32 max_depth,
acpi_adr_space_type space_id, u32 function)
{
struct acpi_reg_walk_info info;
@ -713,7 +719,7 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node,
* regions and _REG methods. (i.e. handlers must be installed for all
* regions of this Space ID before we can run any _REG methods)
*/
(void)acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX,
(void)acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, max_depth,
ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, NULL,
&info, NULL);
@ -814,7 +820,7 @@ acpi_ev_reg_run(acpi_handle obj_handle,
*
******************************************************************************/
void
static void
acpi_ev_execute_orphan_reg_method(struct acpi_namespace_node *device_node,
acpi_adr_space_type space_id)
{

View File

@ -85,7 +85,8 @@ acpi_install_address_space_handler_internal(acpi_handle device,
/* Run all _REG methods for this address space */
if (run_reg) {
acpi_ev_execute_reg_methods(node, space_id, ACPI_REG_CONNECT);
acpi_ev_execute_reg_methods(node, ACPI_UINT32_MAX, space_id,
ACPI_REG_CONNECT);
}
unlock_and_exit:
@ -263,6 +264,7 @@ ACPI_EXPORT_SYMBOL(acpi_remove_address_space_handler)
* FUNCTION: acpi_execute_reg_methods
*
* PARAMETERS: device - Handle for the device
* max_depth - Depth to which search for _REG
* space_id - The address space ID
*
* RETURN: Status
@ -271,7 +273,8 @@ ACPI_EXPORT_SYMBOL(acpi_remove_address_space_handler)
*
******************************************************************************/
acpi_status
acpi_execute_reg_methods(acpi_handle device, acpi_adr_space_type space_id)
acpi_execute_reg_methods(acpi_handle device, u32 max_depth,
acpi_adr_space_type space_id)
{
struct acpi_namespace_node *node;
acpi_status status;
@ -296,7 +299,8 @@ acpi_execute_reg_methods(acpi_handle device, acpi_adr_space_type space_id)
/* Run all _REG methods for this address space */
acpi_ev_execute_reg_methods(node, space_id, ACPI_REG_CONNECT);
acpi_ev_execute_reg_methods(node, max_depth, space_id,
ACPI_REG_CONNECT);
} else {
status = AE_BAD_PARAMETER;
}
@ -306,57 +310,3 @@ acpi_execute_reg_methods(acpi_handle device, acpi_adr_space_type space_id)
}
ACPI_EXPORT_SYMBOL(acpi_execute_reg_methods)
/*******************************************************************************
*
* FUNCTION: acpi_execute_orphan_reg_method
*
* PARAMETERS: device - Handle for the device
* space_id - The address space ID
*
* RETURN: Status
*
* DESCRIPTION: Execute an "orphan" _REG method that appears under an ACPI
* device. This is a _REG method that has no corresponding region
* within the device's scope.
*
******************************************************************************/
acpi_status
acpi_execute_orphan_reg_method(acpi_handle device, acpi_adr_space_type space_id)
{
struct acpi_namespace_node *node;
acpi_status status;
ACPI_FUNCTION_TRACE(acpi_execute_orphan_reg_method);
/* Parameter validation */
if (!device) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
/* Convert and validate the device handle */
node = acpi_ns_validate_handle(device);
if (node) {
/*
* If an "orphan" _REG method is present in the device's scope
* for the given address space ID, run it.
*/
acpi_ev_execute_orphan_reg_method(node, space_id);
} else {
status = AE_BAD_PARAMETER;
}
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
return_ACPI_STATUS(status);
}
ACPI_EXPORT_SYMBOL(acpi_execute_orphan_reg_method)

View File

@ -1487,12 +1487,13 @@ static bool install_gpio_irq_event_handler(struct acpi_ec *ec)
static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device,
bool call_reg)
{
acpi_handle scope_handle = ec == first_ec ? ACPI_ROOT_OBJECT : ec->handle;
acpi_status status;
acpi_ec_start(ec, false);
if (!test_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags)) {
acpi_handle scope_handle = ec == first_ec ? ACPI_ROOT_OBJECT : ec->handle;
acpi_ec_enter_noirq(ec);
status = acpi_install_address_space_handler_no_reg(scope_handle,
ACPI_ADR_SPACE_EC,
@ -1506,10 +1507,7 @@ static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device,
}
if (call_reg && !test_bit(EC_FLAGS_EC_REG_CALLED, &ec->flags)) {
acpi_execute_reg_methods(scope_handle, ACPI_ADR_SPACE_EC);
if (scope_handle != ec->handle)
acpi_execute_orphan_reg_method(ec->handle, ACPI_ADR_SPACE_EC);
acpi_execute_reg_methods(ec->handle, ACPI_UINT32_MAX, ACPI_ADR_SPACE_EC);
set_bit(EC_FLAGS_EC_REG_CALLED, &ec->flags);
}
@ -1724,6 +1722,12 @@ static void acpi_ec_remove(struct acpi_device *device)
}
}
void acpi_ec_register_opregions(struct acpi_device *adev)
{
if (first_ec && first_ec->handle != adev->handle)
acpi_execute_reg_methods(adev->handle, 1, ACPI_ADR_SPACE_EC);
}
static acpi_status
ec_parse_io_ports(struct acpi_resource *resource, void *context)
{

View File

@ -223,6 +223,7 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
acpi_handle handle, acpi_ec_query_func func,
void *data);
void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit);
void acpi_ec_register_opregions(struct acpi_device *adev);
#ifdef CONFIG_PM_SLEEP
void acpi_ec_flush_work(void);

View File

@ -2273,6 +2273,8 @@ static int acpi_bus_attach(struct acpi_device *device, void *first_pass)
if (device->handler)
goto ok;
acpi_ec_register_opregions(device);
if (!device->flags.initialized) {
device->flags.power_manageable =
device->power.states[ACPI_STATE_D0].flags.valid;

View File

@ -660,12 +660,9 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status
void *context))
ACPI_EXTERNAL_RETURN_STATUS(acpi_status
acpi_execute_reg_methods(acpi_handle device,
u32 nax_depth,
acpi_adr_space_type
space_id))
ACPI_EXTERNAL_RETURN_STATUS(acpi_status
acpi_execute_orphan_reg_method(acpi_handle device,
acpi_adr_space_type
space_id))
ACPI_EXTERNAL_RETURN_STATUS(acpi_status
acpi_remove_address_space_handler(acpi_handle
device,