162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: evhandler - Support for Address Space handlers 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci *****************************************************************************/ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <acpi/acpi.h> 1162306a36Sopenharmony_ci#include "accommon.h" 1262306a36Sopenharmony_ci#include "acevents.h" 1362306a36Sopenharmony_ci#include "acnamesp.h" 1462306a36Sopenharmony_ci#include "acinterp.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define _COMPONENT ACPI_EVENTS 1762306a36Sopenharmony_ciACPI_MODULE_NAME("evhandler") 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* Local prototypes */ 2062306a36Sopenharmony_cistatic acpi_status 2162306a36Sopenharmony_ciacpi_ev_install_handler(acpi_handle obj_handle, 2262306a36Sopenharmony_ci u32 level, void *context, void **return_value); 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* These are the address spaces that will get default handlers */ 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ciu8 acpi_gbl_default_address_spaces[ACPI_NUM_DEFAULT_SPACES] = { 2762306a36Sopenharmony_ci ACPI_ADR_SPACE_SYSTEM_MEMORY, 2862306a36Sopenharmony_ci ACPI_ADR_SPACE_SYSTEM_IO, 2962306a36Sopenharmony_ci ACPI_ADR_SPACE_PCI_CONFIG, 3062306a36Sopenharmony_ci ACPI_ADR_SPACE_DATA_TABLE 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/******************************************************************************* 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci * FUNCTION: acpi_ev_install_region_handlers 3662306a36Sopenharmony_ci * 3762306a36Sopenharmony_ci * PARAMETERS: None 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * RETURN: Status 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * DESCRIPTION: Installs the core subsystem default address space handlers. 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci ******************************************************************************/ 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ciacpi_status acpi_ev_install_region_handlers(void) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci acpi_status status; 4862306a36Sopenharmony_ci u32 i; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ev_install_region_handlers); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 5362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 5462306a36Sopenharmony_ci return_ACPI_STATUS(status); 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci /* 5862306a36Sopenharmony_ci * All address spaces (PCI Config, EC, SMBus) are scope dependent and 5962306a36Sopenharmony_ci * registration must occur for a specific device. 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * In the case of the system memory and IO address spaces there is 6262306a36Sopenharmony_ci * currently no device associated with the address space. For these we 6362306a36Sopenharmony_ci * use the root. 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * We install the default PCI config space handler at the root so that 6662306a36Sopenharmony_ci * this space is immediately available even though the we have not 6762306a36Sopenharmony_ci * enumerated all the PCI Root Buses yet. This is to conform to the ACPI 6862306a36Sopenharmony_ci * specification which states that the PCI config space must be always 6962306a36Sopenharmony_ci * available -- even though we are nowhere near ready to find the PCI root 7062306a36Sopenharmony_ci * buses at this point. 7162306a36Sopenharmony_ci * 7262306a36Sopenharmony_ci * NOTE: We ignore AE_ALREADY_EXISTS because this means that a handler 7362306a36Sopenharmony_ci * has already been installed (via acpi_install_address_space_handler). 7462306a36Sopenharmony_ci * Similar for AE_SAME_HANDLER. 7562306a36Sopenharmony_ci */ 7662306a36Sopenharmony_ci for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) { 7762306a36Sopenharmony_ci status = acpi_ev_install_space_handler(acpi_gbl_root_node, 7862306a36Sopenharmony_ci acpi_gbl_default_address_spaces 7962306a36Sopenharmony_ci [i], 8062306a36Sopenharmony_ci ACPI_DEFAULT_HANDLER, 8162306a36Sopenharmony_ci NULL, NULL); 8262306a36Sopenharmony_ci switch (status) { 8362306a36Sopenharmony_ci case AE_OK: 8462306a36Sopenharmony_ci case AE_SAME_HANDLER: 8562306a36Sopenharmony_ci case AE_ALREADY_EXISTS: 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci /* These exceptions are all OK */ 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci status = AE_OK; 9062306a36Sopenharmony_ci break; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci default: 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci goto unlock_and_exit; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ciunlock_and_exit: 9962306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 10062306a36Sopenharmony_ci return_ACPI_STATUS(status); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/******************************************************************************* 10462306a36Sopenharmony_ci * 10562306a36Sopenharmony_ci * FUNCTION: acpi_ev_has_default_handler 10662306a36Sopenharmony_ci * 10762306a36Sopenharmony_ci * PARAMETERS: node - Namespace node for the device 10862306a36Sopenharmony_ci * space_id - The address space ID 10962306a36Sopenharmony_ci * 11062306a36Sopenharmony_ci * RETURN: TRUE if default handler is installed, FALSE otherwise 11162306a36Sopenharmony_ci * 11262306a36Sopenharmony_ci * DESCRIPTION: Check if the default handler is installed for the requested 11362306a36Sopenharmony_ci * space ID. 11462306a36Sopenharmony_ci * 11562306a36Sopenharmony_ci ******************************************************************************/ 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ciu8 11862306a36Sopenharmony_ciacpi_ev_has_default_handler(struct acpi_namespace_node *node, 11962306a36Sopenharmony_ci acpi_adr_space_type space_id) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci union acpi_operand_object *obj_desc; 12262306a36Sopenharmony_ci union acpi_operand_object *handler_obj; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* Must have an existing internal object */ 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci obj_desc = acpi_ns_get_attached_object(node); 12762306a36Sopenharmony_ci if (obj_desc) { 12862306a36Sopenharmony_ci handler_obj = obj_desc->common_notify.handler; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* Walk the linked list of handlers for this object */ 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci while (handler_obj) { 13362306a36Sopenharmony_ci if (handler_obj->address_space.space_id == space_id) { 13462306a36Sopenharmony_ci if (handler_obj->address_space.handler_flags & 13562306a36Sopenharmony_ci ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) { 13662306a36Sopenharmony_ci return (TRUE); 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci handler_obj = handler_obj->address_space.next; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci return (FALSE); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci/******************************************************************************* 14862306a36Sopenharmony_ci * 14962306a36Sopenharmony_ci * FUNCTION: acpi_ev_install_handler 15062306a36Sopenharmony_ci * 15162306a36Sopenharmony_ci * PARAMETERS: walk_namespace callback 15262306a36Sopenharmony_ci * 15362306a36Sopenharmony_ci * DESCRIPTION: This routine installs an address handler into objects that are 15462306a36Sopenharmony_ci * of type Region or Device. 15562306a36Sopenharmony_ci * 15662306a36Sopenharmony_ci * If the Object is a Device, and the device has a handler of 15762306a36Sopenharmony_ci * the same type then the search is terminated in that branch. 15862306a36Sopenharmony_ci * 15962306a36Sopenharmony_ci * This is because the existing handler is closer in proximity 16062306a36Sopenharmony_ci * to any more regions than the one we are trying to install. 16162306a36Sopenharmony_ci * 16262306a36Sopenharmony_ci ******************************************************************************/ 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic acpi_status 16562306a36Sopenharmony_ciacpi_ev_install_handler(acpi_handle obj_handle, 16662306a36Sopenharmony_ci u32 level, void *context, void **return_value) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci union acpi_operand_object *handler_obj; 16962306a36Sopenharmony_ci union acpi_operand_object *next_handler_obj; 17062306a36Sopenharmony_ci union acpi_operand_object *obj_desc; 17162306a36Sopenharmony_ci struct acpi_namespace_node *node; 17262306a36Sopenharmony_ci acpi_status status; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci ACPI_FUNCTION_NAME(ev_install_handler); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci handler_obj = (union acpi_operand_object *)context; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* Parameter validation */ 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci if (!handler_obj) { 18162306a36Sopenharmony_ci return (AE_OK); 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci /* Convert and validate the device handle */ 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci node = acpi_ns_validate_handle(obj_handle); 18762306a36Sopenharmony_ci if (!node) { 18862306a36Sopenharmony_ci return (AE_BAD_PARAMETER); 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci /* 19262306a36Sopenharmony_ci * We only care about regions and objects that are allowed to have 19362306a36Sopenharmony_ci * address space handlers 19462306a36Sopenharmony_ci */ 19562306a36Sopenharmony_ci if ((node->type != ACPI_TYPE_DEVICE) && 19662306a36Sopenharmony_ci (node->type != ACPI_TYPE_REGION) && (node != acpi_gbl_root_node)) { 19762306a36Sopenharmony_ci return (AE_OK); 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* Check for an existing internal object */ 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci obj_desc = acpi_ns_get_attached_object(node); 20362306a36Sopenharmony_ci if (!obj_desc) { 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* No object, just exit */ 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci return (AE_OK); 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci /* Devices are handled different than regions */ 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (obj_desc->common.type == ACPI_TYPE_DEVICE) { 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci /* Check if this Device already has a handler for this address space */ 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci next_handler_obj = 21762306a36Sopenharmony_ci acpi_ev_find_region_handler(handler_obj->address_space. 21862306a36Sopenharmony_ci space_id, 21962306a36Sopenharmony_ci obj_desc->common_notify. 22062306a36Sopenharmony_ci handler); 22162306a36Sopenharmony_ci if (next_handler_obj) { 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* Found a handler, is it for the same address space? */ 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, 22662306a36Sopenharmony_ci "Found handler for region [%s] in device %p(%p) handler %p\n", 22762306a36Sopenharmony_ci acpi_ut_get_region_name(handler_obj-> 22862306a36Sopenharmony_ci address_space. 22962306a36Sopenharmony_ci space_id), 23062306a36Sopenharmony_ci obj_desc, next_handler_obj, 23162306a36Sopenharmony_ci handler_obj)); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* 23462306a36Sopenharmony_ci * Since the object we found it on was a device, then it means 23562306a36Sopenharmony_ci * that someone has already installed a handler for the branch 23662306a36Sopenharmony_ci * of the namespace from this device on. Just bail out telling 23762306a36Sopenharmony_ci * the walk routine to not traverse this branch. This preserves 23862306a36Sopenharmony_ci * the scoping rule for handlers. 23962306a36Sopenharmony_ci */ 24062306a36Sopenharmony_ci return (AE_CTRL_DEPTH); 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci /* 24462306a36Sopenharmony_ci * As long as the device didn't have a handler for this space we 24562306a36Sopenharmony_ci * don't care about it. We just ignore it and proceed. 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_ci return (AE_OK); 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci /* Object is a Region */ 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci if (obj_desc->region.space_id != handler_obj->address_space.space_id) { 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci /* This region is for a different address space, just ignore it */ 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci return (AE_OK); 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* 26062306a36Sopenharmony_ci * Now we have a region and it is for the handler's address space type. 26162306a36Sopenharmony_ci * 26262306a36Sopenharmony_ci * First disconnect region for any previous handler (if any) 26362306a36Sopenharmony_ci */ 26462306a36Sopenharmony_ci acpi_ev_detach_region(obj_desc, FALSE); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci /* Connect the region to the new handler */ 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci status = acpi_ev_attach_region(handler_obj, obj_desc, FALSE); 26962306a36Sopenharmony_ci return (status); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/******************************************************************************* 27362306a36Sopenharmony_ci * 27462306a36Sopenharmony_ci * FUNCTION: acpi_ev_find_region_handler 27562306a36Sopenharmony_ci * 27662306a36Sopenharmony_ci * PARAMETERS: space_id - The address space ID 27762306a36Sopenharmony_ci * handler_obj - Head of the handler object list 27862306a36Sopenharmony_ci * 27962306a36Sopenharmony_ci * RETURN: Matching handler object. NULL if space ID not matched 28062306a36Sopenharmony_ci * 28162306a36Sopenharmony_ci * DESCRIPTION: Search a handler object list for a match on the address 28262306a36Sopenharmony_ci * space ID. 28362306a36Sopenharmony_ci * 28462306a36Sopenharmony_ci ******************************************************************************/ 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ciunion acpi_operand_object *acpi_ev_find_region_handler(acpi_adr_space_type 28762306a36Sopenharmony_ci space_id, 28862306a36Sopenharmony_ci union acpi_operand_object 28962306a36Sopenharmony_ci *handler_obj) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* Walk the handler list for this device */ 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci while (handler_obj) { 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci /* Same space_id indicates a handler is installed */ 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci if (handler_obj->address_space.space_id == space_id) { 29962306a36Sopenharmony_ci return (handler_obj); 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci /* Next handler object */ 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci handler_obj = handler_obj->address_space.next; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci return (NULL); 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci/******************************************************************************* 31162306a36Sopenharmony_ci * 31262306a36Sopenharmony_ci * FUNCTION: acpi_ev_install_space_handler 31362306a36Sopenharmony_ci * 31462306a36Sopenharmony_ci * PARAMETERS: node - Namespace node for the device 31562306a36Sopenharmony_ci * space_id - The address space ID 31662306a36Sopenharmony_ci * handler - Address of the handler 31762306a36Sopenharmony_ci * setup - Address of the setup function 31862306a36Sopenharmony_ci * context - Value passed to the handler on each access 31962306a36Sopenharmony_ci * 32062306a36Sopenharmony_ci * RETURN: Status 32162306a36Sopenharmony_ci * 32262306a36Sopenharmony_ci * DESCRIPTION: Install a handler for all op_regions of a given space_id. 32362306a36Sopenharmony_ci * Assumes namespace is locked 32462306a36Sopenharmony_ci * 32562306a36Sopenharmony_ci ******************************************************************************/ 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ciacpi_status 32862306a36Sopenharmony_ciacpi_ev_install_space_handler(struct acpi_namespace_node *node, 32962306a36Sopenharmony_ci acpi_adr_space_type space_id, 33062306a36Sopenharmony_ci acpi_adr_space_handler handler, 33162306a36Sopenharmony_ci acpi_adr_space_setup setup, void *context) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci union acpi_operand_object *obj_desc; 33462306a36Sopenharmony_ci union acpi_operand_object *handler_obj; 33562306a36Sopenharmony_ci acpi_status status = AE_OK; 33662306a36Sopenharmony_ci acpi_object_type type; 33762306a36Sopenharmony_ci u8 flags = 0; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ev_install_space_handler); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci /* 34262306a36Sopenharmony_ci * This registration is valid for only the types below and the root. 34362306a36Sopenharmony_ci * The root node is where the default handlers get installed. 34462306a36Sopenharmony_ci */ 34562306a36Sopenharmony_ci if ((node->type != ACPI_TYPE_DEVICE) && 34662306a36Sopenharmony_ci (node->type != ACPI_TYPE_PROCESSOR) && 34762306a36Sopenharmony_ci (node->type != ACPI_TYPE_THERMAL) && (node != acpi_gbl_root_node)) { 34862306a36Sopenharmony_ci status = AE_BAD_PARAMETER; 34962306a36Sopenharmony_ci goto unlock_and_exit; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (handler == ACPI_DEFAULT_HANDLER) { 35362306a36Sopenharmony_ci flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci switch (space_id) { 35662306a36Sopenharmony_ci case ACPI_ADR_SPACE_SYSTEM_MEMORY: 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci handler = acpi_ex_system_memory_space_handler; 35962306a36Sopenharmony_ci setup = acpi_ev_system_memory_region_setup; 36062306a36Sopenharmony_ci break; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci case ACPI_ADR_SPACE_SYSTEM_IO: 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci handler = acpi_ex_system_io_space_handler; 36562306a36Sopenharmony_ci setup = acpi_ev_io_space_region_setup; 36662306a36Sopenharmony_ci break; 36762306a36Sopenharmony_ci#ifdef ACPI_PCI_CONFIGURED 36862306a36Sopenharmony_ci case ACPI_ADR_SPACE_PCI_CONFIG: 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci handler = acpi_ex_pci_config_space_handler; 37162306a36Sopenharmony_ci setup = acpi_ev_pci_config_region_setup; 37262306a36Sopenharmony_ci break; 37362306a36Sopenharmony_ci#endif 37462306a36Sopenharmony_ci case ACPI_ADR_SPACE_CMOS: 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci handler = acpi_ex_cmos_space_handler; 37762306a36Sopenharmony_ci setup = acpi_ev_cmos_region_setup; 37862306a36Sopenharmony_ci break; 37962306a36Sopenharmony_ci#ifdef ACPI_PCI_CONFIGURED 38062306a36Sopenharmony_ci case ACPI_ADR_SPACE_PCI_BAR_TARGET: 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci handler = acpi_ex_pci_bar_space_handler; 38362306a36Sopenharmony_ci setup = acpi_ev_pci_bar_region_setup; 38462306a36Sopenharmony_ci break; 38562306a36Sopenharmony_ci#endif 38662306a36Sopenharmony_ci case ACPI_ADR_SPACE_DATA_TABLE: 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci handler = acpi_ex_data_table_space_handler; 38962306a36Sopenharmony_ci setup = acpi_ev_data_table_region_setup; 39062306a36Sopenharmony_ci break; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci default: 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci status = AE_BAD_PARAMETER; 39562306a36Sopenharmony_ci goto unlock_and_exit; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* If the caller hasn't specified a setup routine, use the default */ 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci if (!setup) { 40262306a36Sopenharmony_ci setup = acpi_ev_default_region_setup; 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* Check for an existing internal object */ 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci obj_desc = acpi_ns_get_attached_object(node); 40862306a36Sopenharmony_ci if (obj_desc) { 40962306a36Sopenharmony_ci /* 41062306a36Sopenharmony_ci * The attached device object already exists. Now make sure 41162306a36Sopenharmony_ci * the handler is not already installed. 41262306a36Sopenharmony_ci */ 41362306a36Sopenharmony_ci handler_obj = acpi_ev_find_region_handler(space_id, 41462306a36Sopenharmony_ci obj_desc-> 41562306a36Sopenharmony_ci common_notify. 41662306a36Sopenharmony_ci handler); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (handler_obj) { 41962306a36Sopenharmony_ci if (handler_obj->address_space.handler == handler) { 42062306a36Sopenharmony_ci /* 42162306a36Sopenharmony_ci * It is (relatively) OK to attempt to install the SAME 42262306a36Sopenharmony_ci * handler twice. This can easily happen with the 42362306a36Sopenharmony_ci * PCI_Config space. 42462306a36Sopenharmony_ci */ 42562306a36Sopenharmony_ci status = AE_SAME_HANDLER; 42662306a36Sopenharmony_ci goto unlock_and_exit; 42762306a36Sopenharmony_ci } else { 42862306a36Sopenharmony_ci /* A handler is already installed */ 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci status = AE_ALREADY_EXISTS; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci goto unlock_and_exit; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci } else { 43662306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, 43762306a36Sopenharmony_ci "Creating object on Device %p while installing handler\n", 43862306a36Sopenharmony_ci node)); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci /* obj_desc does not exist, create one */ 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (node->type == ACPI_TYPE_ANY) { 44362306a36Sopenharmony_ci type = ACPI_TYPE_DEVICE; 44462306a36Sopenharmony_ci } else { 44562306a36Sopenharmony_ci type = node->type; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci obj_desc = acpi_ut_create_internal_object(type); 44962306a36Sopenharmony_ci if (!obj_desc) { 45062306a36Sopenharmony_ci status = AE_NO_MEMORY; 45162306a36Sopenharmony_ci goto unlock_and_exit; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci /* Init new descriptor */ 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci obj_desc->common.type = (u8)type; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci /* Attach the new object to the Node */ 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci status = acpi_ns_attach_object(node, obj_desc, type); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci /* Remove local reference to the object */ 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci acpi_ut_remove_reference(obj_desc); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 46762306a36Sopenharmony_ci goto unlock_and_exit; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, 47262306a36Sopenharmony_ci "Installing address handler for region %s(%X) " 47362306a36Sopenharmony_ci "on Device %4.4s %p(%p)\n", 47462306a36Sopenharmony_ci acpi_ut_get_region_name(space_id), space_id, 47562306a36Sopenharmony_ci acpi_ut_get_node_name(node), node, obj_desc)); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci /* 47862306a36Sopenharmony_ci * Install the handler 47962306a36Sopenharmony_ci * 48062306a36Sopenharmony_ci * At this point there is no existing handler. Just allocate the object 48162306a36Sopenharmony_ci * for the handler and link it into the list. 48262306a36Sopenharmony_ci */ 48362306a36Sopenharmony_ci handler_obj = 48462306a36Sopenharmony_ci acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_ADDRESS_HANDLER); 48562306a36Sopenharmony_ci if (!handler_obj) { 48662306a36Sopenharmony_ci status = AE_NO_MEMORY; 48762306a36Sopenharmony_ci goto unlock_and_exit; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* Init handler obj */ 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci status = 49362306a36Sopenharmony_ci acpi_os_create_mutex(&handler_obj->address_space.context_mutex); 49462306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 49562306a36Sopenharmony_ci acpi_ut_remove_reference(handler_obj); 49662306a36Sopenharmony_ci goto unlock_and_exit; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci handler_obj->address_space.space_id = (u8)space_id; 50062306a36Sopenharmony_ci handler_obj->address_space.handler_flags = flags; 50162306a36Sopenharmony_ci handler_obj->address_space.region_list = NULL; 50262306a36Sopenharmony_ci handler_obj->address_space.node = node; 50362306a36Sopenharmony_ci handler_obj->address_space.handler = handler; 50462306a36Sopenharmony_ci handler_obj->address_space.context = context; 50562306a36Sopenharmony_ci handler_obj->address_space.setup = setup; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci /* Install at head of Device.address_space list */ 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci handler_obj->address_space.next = obj_desc->common_notify.handler; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci /* 51262306a36Sopenharmony_ci * The Device object is the first reference on the handler_obj. 51362306a36Sopenharmony_ci * Each region that uses the handler adds a reference. 51462306a36Sopenharmony_ci */ 51562306a36Sopenharmony_ci obj_desc->common_notify.handler = handler_obj; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci /* 51862306a36Sopenharmony_ci * Walk the namespace finding all of the regions this handler will 51962306a36Sopenharmony_ci * manage. 52062306a36Sopenharmony_ci * 52162306a36Sopenharmony_ci * Start at the device and search the branch toward the leaf nodes 52262306a36Sopenharmony_ci * until either the leaf is encountered or a device is detected that 52362306a36Sopenharmony_ci * has an address handler of the same type. 52462306a36Sopenharmony_ci * 52562306a36Sopenharmony_ci * In either case, back up and search down the remainder of the branch 52662306a36Sopenharmony_ci */ 52762306a36Sopenharmony_ci status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, 52862306a36Sopenharmony_ci ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, 52962306a36Sopenharmony_ci acpi_ev_install_handler, NULL, 53062306a36Sopenharmony_ci handler_obj, NULL); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ciunlock_and_exit: 53362306a36Sopenharmony_ci return_ACPI_STATUS(status); 53462306a36Sopenharmony_ci} 535