Commit 64ab5e40 authored by Linus Torvalds's avatar Linus Torvalds

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"
parents e4a55b55 71bf41b8
...@@ -188,13 +188,9 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj, ...@@ -188,13 +188,9 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
u8 acpi_ns_is_locked); u8 acpi_ns_is_locked);
void 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); 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_status
acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function); acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function);
......
...@@ -20,6 +20,10 @@ extern u8 acpi_gbl_default_address_spaces[]; ...@@ -20,6 +20,10 @@ extern u8 acpi_gbl_default_address_spaces[];
/* Local prototypes */ /* 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 static acpi_status
acpi_ev_reg_run(acpi_handle obj_handle, acpi_ev_reg_run(acpi_handle obj_handle,
u32 level, void *context, void **return_value); u32 level, void *context, void **return_value);
...@@ -61,6 +65,7 @@ acpi_status acpi_ev_initialize_op_regions(void) ...@@ -61,6 +65,7 @@ acpi_status acpi_ev_initialize_op_regions(void)
acpi_gbl_default_address_spaces acpi_gbl_default_address_spaces
[i])) { [i])) {
acpi_ev_execute_reg_methods(acpi_gbl_root_node, acpi_ev_execute_reg_methods(acpi_gbl_root_node,
ACPI_UINT32_MAX,
acpi_gbl_default_address_spaces acpi_gbl_default_address_spaces
[i], ACPI_REG_CONNECT); [i], ACPI_REG_CONNECT);
} }
...@@ -668,6 +673,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) ...@@ -668,6 +673,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
* FUNCTION: acpi_ev_execute_reg_methods * FUNCTION: acpi_ev_execute_reg_methods
* *
* PARAMETERS: node - Namespace node for the device * PARAMETERS: node - Namespace node for the device
* max_depth - Depth to which search for _REG
* space_id - The address space ID * space_id - The address space ID
* function - Passed to _REG: On (1) or Off (0) * function - Passed to _REG: On (1) or Off (0)
* *
...@@ -679,7 +685,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) ...@@ -679,7 +685,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
******************************************************************************/ ******************************************************************************/
void 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) acpi_adr_space_type space_id, u32 function)
{ {
struct acpi_reg_walk_info info; struct acpi_reg_walk_info info;
...@@ -713,7 +719,7 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, ...@@ -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 and _REG methods. (i.e. handlers must be installed for all
* regions of this Space ID before we can run any _REG methods) * 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, ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, NULL,
&info, NULL); &info, NULL);
...@@ -814,7 +820,7 @@ acpi_ev_reg_run(acpi_handle obj_handle, ...@@ -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_ev_execute_orphan_reg_method(struct acpi_namespace_node *device_node,
acpi_adr_space_type space_id) acpi_adr_space_type space_id)
{ {
......
...@@ -85,7 +85,8 @@ acpi_install_address_space_handler_internal(acpi_handle device, ...@@ -85,7 +85,8 @@ acpi_install_address_space_handler_internal(acpi_handle device,
/* Run all _REG methods for this address space */ /* Run all _REG methods for this address space */
if (run_reg) { 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: unlock_and_exit:
...@@ -263,6 +264,7 @@ ACPI_EXPORT_SYMBOL(acpi_remove_address_space_handler) ...@@ -263,6 +264,7 @@ ACPI_EXPORT_SYMBOL(acpi_remove_address_space_handler)
* FUNCTION: acpi_execute_reg_methods * FUNCTION: acpi_execute_reg_methods
* *
* PARAMETERS: device - Handle for the device * PARAMETERS: device - Handle for the device
* max_depth - Depth to which search for _REG
* space_id - The address space ID * space_id - The address space ID
* *
* RETURN: Status * RETURN: Status
...@@ -271,7 +273,8 @@ ACPI_EXPORT_SYMBOL(acpi_remove_address_space_handler) ...@@ -271,7 +273,8 @@ ACPI_EXPORT_SYMBOL(acpi_remove_address_space_handler)
* *
******************************************************************************/ ******************************************************************************/
acpi_status 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; struct acpi_namespace_node *node;
acpi_status status; acpi_status status;
...@@ -296,7 +299,8 @@ acpi_execute_reg_methods(acpi_handle device, acpi_adr_space_type space_id) ...@@ -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 */ /* 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 { } else {
status = AE_BAD_PARAMETER; status = AE_BAD_PARAMETER;
} }
...@@ -306,57 +310,3 @@ acpi_execute_reg_methods(acpi_handle device, acpi_adr_space_type space_id) ...@@ -306,57 +310,3 @@ acpi_execute_reg_methods(acpi_handle device, acpi_adr_space_type space_id)
} }
ACPI_EXPORT_SYMBOL(acpi_execute_reg_methods) 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)
...@@ -1487,12 +1487,13 @@ static bool install_gpio_irq_event_handler(struct acpi_ec *ec) ...@@ -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, static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device,
bool call_reg) bool call_reg)
{ {
acpi_handle scope_handle = ec == first_ec ? ACPI_ROOT_OBJECT : ec->handle;
acpi_status status; acpi_status status;
acpi_ec_start(ec, false); acpi_ec_start(ec, false);
if (!test_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags)) { 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); acpi_ec_enter_noirq(ec);
status = acpi_install_address_space_handler_no_reg(scope_handle, status = acpi_install_address_space_handler_no_reg(scope_handle,
ACPI_ADR_SPACE_EC, ACPI_ADR_SPACE_EC,
...@@ -1506,10 +1507,7 @@ static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device, ...@@ -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)) { if (call_reg && !test_bit(EC_FLAGS_EC_REG_CALLED, &ec->flags)) {
acpi_execute_reg_methods(scope_handle, ACPI_ADR_SPACE_EC); acpi_execute_reg_methods(ec->handle, ACPI_UINT32_MAX, ACPI_ADR_SPACE_EC);
if (scope_handle != ec->handle)
acpi_execute_orphan_reg_method(ec->handle, ACPI_ADR_SPACE_EC);
set_bit(EC_FLAGS_EC_REG_CALLED, &ec->flags); set_bit(EC_FLAGS_EC_REG_CALLED, &ec->flags);
} }
...@@ -1724,6 +1722,12 @@ static void acpi_ec_remove(struct acpi_device *device) ...@@ -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 static acpi_status
ec_parse_io_ports(struct acpi_resource *resource, void *context) ec_parse_io_ports(struct acpi_resource *resource, void *context)
{ {
......
...@@ -223,6 +223,7 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, ...@@ -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, acpi_handle handle, acpi_ec_query_func func,
void *data); void *data);
void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit); 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 #ifdef CONFIG_PM_SLEEP
void acpi_ec_flush_work(void); void acpi_ec_flush_work(void);
......
...@@ -2273,6 +2273,8 @@ static int acpi_bus_attach(struct acpi_device *device, void *first_pass) ...@@ -2273,6 +2273,8 @@ static int acpi_bus_attach(struct acpi_device *device, void *first_pass)
if (device->handler) if (device->handler)
goto ok; goto ok;
acpi_ec_register_opregions(device);
if (!device->flags.initialized) { if (!device->flags.initialized) {
device->flags.power_manageable = device->flags.power_manageable =
device->power.states[ACPI_STATE_D0].flags.valid; device->power.states[ACPI_STATE_D0].flags.valid;
......
...@@ -660,12 +660,9 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status ...@@ -660,12 +660,9 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status
void *context)) void *context))
ACPI_EXTERNAL_RETURN_STATUS(acpi_status ACPI_EXTERNAL_RETURN_STATUS(acpi_status
acpi_execute_reg_methods(acpi_handle device, acpi_execute_reg_methods(acpi_handle device,
u32 nax_depth,
acpi_adr_space_type acpi_adr_space_type
space_id)) 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_EXTERNAL_RETURN_STATUS(acpi_status
acpi_remove_address_space_handler(acpi_handle acpi_remove_address_space_handler(acpi_handle
device, device,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment