162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: evrgnini- ACPI address_space (op_region) init 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("evrgnini") 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/******************************************************************************* 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * FUNCTION: acpi_ev_system_memory_region_setup 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * PARAMETERS: handle - Region we are interested in 2462306a36Sopenharmony_ci * function - Start or stop 2562306a36Sopenharmony_ci * handler_context - Address space handler context 2662306a36Sopenharmony_ci * region_context - Region specific context 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * RETURN: Status 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * DESCRIPTION: Setup a system_memory operation region 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci ******************************************************************************/ 3362306a36Sopenharmony_ciacpi_status 3462306a36Sopenharmony_ciacpi_ev_system_memory_region_setup(acpi_handle handle, 3562306a36Sopenharmony_ci u32 function, 3662306a36Sopenharmony_ci void *handler_context, void **region_context) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci union acpi_operand_object *region_desc = 3962306a36Sopenharmony_ci (union acpi_operand_object *)handle; 4062306a36Sopenharmony_ci struct acpi_mem_space_context *local_region_context; 4162306a36Sopenharmony_ci struct acpi_mem_mapping *mm; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ev_system_memory_region_setup); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci if (function == ACPI_REGION_DEACTIVATE) { 4662306a36Sopenharmony_ci if (*region_context) { 4762306a36Sopenharmony_ci local_region_context = 4862306a36Sopenharmony_ci (struct acpi_mem_space_context *)*region_context; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci /* Delete memory mappings if present */ 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci while (local_region_context->first_mm) { 5362306a36Sopenharmony_ci mm = local_region_context->first_mm; 5462306a36Sopenharmony_ci local_region_context->first_mm = mm->next_mm; 5562306a36Sopenharmony_ci acpi_os_unmap_memory(mm->logical_address, 5662306a36Sopenharmony_ci mm->length); 5762306a36Sopenharmony_ci ACPI_FREE(mm); 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci ACPI_FREE(local_region_context); 6062306a36Sopenharmony_ci *region_context = NULL; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci /* Create a new context */ 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci local_region_context = 6862306a36Sopenharmony_ci ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_mem_space_context)); 6962306a36Sopenharmony_ci if (!(local_region_context)) { 7062306a36Sopenharmony_ci return_ACPI_STATUS(AE_NO_MEMORY); 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci /* Save the region length and address for use in the handler */ 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci local_region_context->length = region_desc->region.length; 7662306a36Sopenharmony_ci local_region_context->address = region_desc->region.address; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci *region_context = local_region_context; 7962306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/******************************************************************************* 8362306a36Sopenharmony_ci * 8462306a36Sopenharmony_ci * FUNCTION: acpi_ev_io_space_region_setup 8562306a36Sopenharmony_ci * 8662306a36Sopenharmony_ci * PARAMETERS: handle - Region we are interested in 8762306a36Sopenharmony_ci * function - Start or stop 8862306a36Sopenharmony_ci * handler_context - Address space handler context 8962306a36Sopenharmony_ci * region_context - Region specific context 9062306a36Sopenharmony_ci * 9162306a36Sopenharmony_ci * RETURN: Status 9262306a36Sopenharmony_ci * 9362306a36Sopenharmony_ci * DESCRIPTION: Setup a IO operation region 9462306a36Sopenharmony_ci * 9562306a36Sopenharmony_ci ******************************************************************************/ 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ciacpi_status 9862306a36Sopenharmony_ciacpi_ev_io_space_region_setup(acpi_handle handle, 9962306a36Sopenharmony_ci u32 function, 10062306a36Sopenharmony_ci void *handler_context, void **region_context) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ev_io_space_region_setup); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (function == ACPI_REGION_DEACTIVATE) { 10562306a36Sopenharmony_ci *region_context = NULL; 10662306a36Sopenharmony_ci } else { 10762306a36Sopenharmony_ci *region_context = handler_context; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/******************************************************************************* 11462306a36Sopenharmony_ci * 11562306a36Sopenharmony_ci * FUNCTION: acpi_ev_pci_config_region_setup 11662306a36Sopenharmony_ci * 11762306a36Sopenharmony_ci * PARAMETERS: handle - Region we are interested in 11862306a36Sopenharmony_ci * function - Start or stop 11962306a36Sopenharmony_ci * handler_context - Address space handler context 12062306a36Sopenharmony_ci * region_context - Region specific context 12162306a36Sopenharmony_ci * 12262306a36Sopenharmony_ci * RETURN: Status 12362306a36Sopenharmony_ci * 12462306a36Sopenharmony_ci * DESCRIPTION: Setup a PCI_Config operation region 12562306a36Sopenharmony_ci * 12662306a36Sopenharmony_ci * MUTEX: Assumes namespace is not locked 12762306a36Sopenharmony_ci * 12862306a36Sopenharmony_ci ******************************************************************************/ 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ciacpi_status 13162306a36Sopenharmony_ciacpi_ev_pci_config_region_setup(acpi_handle handle, 13262306a36Sopenharmony_ci u32 function, 13362306a36Sopenharmony_ci void *handler_context, void **region_context) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci acpi_status status = AE_OK; 13662306a36Sopenharmony_ci u64 pci_value; 13762306a36Sopenharmony_ci struct acpi_pci_id *pci_id = *region_context; 13862306a36Sopenharmony_ci union acpi_operand_object *handler_obj; 13962306a36Sopenharmony_ci struct acpi_namespace_node *parent_node; 14062306a36Sopenharmony_ci struct acpi_namespace_node *pci_root_node; 14162306a36Sopenharmony_ci struct acpi_namespace_node *pci_device_node; 14262306a36Sopenharmony_ci union acpi_operand_object *region_obj = 14362306a36Sopenharmony_ci (union acpi_operand_object *)handle; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ev_pci_config_region_setup); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci handler_obj = region_obj->region.handler; 14862306a36Sopenharmony_ci if (!handler_obj) { 14962306a36Sopenharmony_ci /* 15062306a36Sopenharmony_ci * No installed handler. This shouldn't happen because the dispatch 15162306a36Sopenharmony_ci * routine checks before we get here, but we check again just in case. 15262306a36Sopenharmony_ci */ 15362306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, 15462306a36Sopenharmony_ci "Attempting to init a region %p, with no handler\n", 15562306a36Sopenharmony_ci region_obj)); 15662306a36Sopenharmony_ci return_ACPI_STATUS(AE_NOT_EXIST); 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci *region_context = NULL; 16062306a36Sopenharmony_ci if (function == ACPI_REGION_DEACTIVATE) { 16162306a36Sopenharmony_ci if (pci_id) { 16262306a36Sopenharmony_ci ACPI_FREE(pci_id); 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci return_ACPI_STATUS(status); 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci parent_node = region_obj->region.node->parent; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci /* 17062306a36Sopenharmony_ci * Get the _SEG and _BBN values from the device upon which the handler 17162306a36Sopenharmony_ci * is installed. 17262306a36Sopenharmony_ci * 17362306a36Sopenharmony_ci * We need to get the _SEG and _BBN objects relative to the PCI BUS device. 17462306a36Sopenharmony_ci * This is the device the handler has been registered to handle. 17562306a36Sopenharmony_ci */ 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci /* 17862306a36Sopenharmony_ci * If the address_space.Node is still pointing to the root, we need 17962306a36Sopenharmony_ci * to scan upward for a PCI Root bridge and re-associate the op_region 18062306a36Sopenharmony_ci * handlers with that device. 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ci if (handler_obj->address_space.node == acpi_gbl_root_node) { 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci /* Start search from the parent object */ 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci pci_root_node = parent_node; 18762306a36Sopenharmony_ci while (pci_root_node != acpi_gbl_root_node) { 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* Get the _HID/_CID in order to detect a root_bridge */ 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (acpi_ev_is_pci_root_bridge(pci_root_node)) { 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci /* Install a handler for this PCI root bridge */ 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci status = acpi_install_address_space_handler((acpi_handle)pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); 19662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 19762306a36Sopenharmony_ci if (status == AE_SAME_HANDLER) { 19862306a36Sopenharmony_ci /* 19962306a36Sopenharmony_ci * It is OK if the handler is already installed on the 20062306a36Sopenharmony_ci * root bridge. Still need to return a context object 20162306a36Sopenharmony_ci * for the new PCI_Config operation region, however. 20262306a36Sopenharmony_ci */ 20362306a36Sopenharmony_ci } else { 20462306a36Sopenharmony_ci ACPI_EXCEPTION((AE_INFO, status, 20562306a36Sopenharmony_ci "Could not install PciConfig handler " 20662306a36Sopenharmony_ci "for Root Bridge %4.4s", 20762306a36Sopenharmony_ci acpi_ut_get_node_name 20862306a36Sopenharmony_ci (pci_root_node))); 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci break; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci pci_root_node = pci_root_node->parent; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci /* PCI root bridge not found, use namespace root node */ 21862306a36Sopenharmony_ci } else { 21962306a36Sopenharmony_ci pci_root_node = handler_obj->address_space.node; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* 22362306a36Sopenharmony_ci * If this region is now initialized, we are done. 22462306a36Sopenharmony_ci * (install_address_space_handler could have initialized it) 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_ci if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) { 22762306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci /* Region is still not initialized. Create a new context */ 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci pci_id = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pci_id)); 23362306a36Sopenharmony_ci if (!pci_id) { 23462306a36Sopenharmony_ci return_ACPI_STATUS(AE_NO_MEMORY); 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* 23862306a36Sopenharmony_ci * For PCI_Config space access, we need the segment, bus, device and 23962306a36Sopenharmony_ci * function numbers. Acquire them here. 24062306a36Sopenharmony_ci * 24162306a36Sopenharmony_ci * Find the parent device object. (This allows the operation region to be 24262306a36Sopenharmony_ci * within a subscope under the device, such as a control method.) 24362306a36Sopenharmony_ci */ 24462306a36Sopenharmony_ci pci_device_node = region_obj->region.node; 24562306a36Sopenharmony_ci while (pci_device_node && (pci_device_node->type != ACPI_TYPE_DEVICE)) { 24662306a36Sopenharmony_ci pci_device_node = pci_device_node->parent; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (!pci_device_node) { 25062306a36Sopenharmony_ci ACPI_FREE(pci_id); 25162306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_OPERAND_TYPE); 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci /* 25562306a36Sopenharmony_ci * Get the PCI device and function numbers from the _ADR object 25662306a36Sopenharmony_ci * contained in the parent's scope. 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_ci status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, 25962306a36Sopenharmony_ci pci_device_node, &pci_value); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* 26262306a36Sopenharmony_ci * The default is zero, and since the allocation above zeroed the data, 26362306a36Sopenharmony_ci * just do nothing on failure. 26462306a36Sopenharmony_ci */ 26562306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 26662306a36Sopenharmony_ci pci_id->device = ACPI_HIWORD(ACPI_LODWORD(pci_value)); 26762306a36Sopenharmony_ci pci_id->function = ACPI_LOWORD(ACPI_LODWORD(pci_value)); 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* The PCI segment number comes from the _SEG method */ 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci status = acpi_ut_evaluate_numeric_object(METHOD_NAME__SEG, 27362306a36Sopenharmony_ci pci_root_node, &pci_value); 27462306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 27562306a36Sopenharmony_ci pci_id->segment = ACPI_LOWORD(pci_value); 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci /* The PCI bus number comes from the _BBN method */ 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci status = acpi_ut_evaluate_numeric_object(METHOD_NAME__BBN, 28162306a36Sopenharmony_ci pci_root_node, &pci_value); 28262306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 28362306a36Sopenharmony_ci pci_id->bus = ACPI_LOWORD(pci_value); 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* Complete/update the PCI ID for this device */ 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci status = 28962306a36Sopenharmony_ci acpi_hw_derive_pci_id(pci_id, pci_root_node, 29062306a36Sopenharmony_ci region_obj->region.node); 29162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 29262306a36Sopenharmony_ci ACPI_FREE(pci_id); 29362306a36Sopenharmony_ci return_ACPI_STATUS(status); 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci *region_context = pci_id; 29762306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci/******************************************************************************* 30162306a36Sopenharmony_ci * 30262306a36Sopenharmony_ci * FUNCTION: acpi_ev_is_pci_root_bridge 30362306a36Sopenharmony_ci * 30462306a36Sopenharmony_ci * PARAMETERS: node - Device node being examined 30562306a36Sopenharmony_ci * 30662306a36Sopenharmony_ci * RETURN: TRUE if device is a PCI/PCI-Express Root Bridge 30762306a36Sopenharmony_ci * 30862306a36Sopenharmony_ci * DESCRIPTION: Determine if the input device represents a PCI Root Bridge by 30962306a36Sopenharmony_ci * examining the _HID and _CID for the device. 31062306a36Sopenharmony_ci * 31162306a36Sopenharmony_ci ******************************************************************************/ 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ciu8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci acpi_status status; 31662306a36Sopenharmony_ci struct acpi_pnp_device_id *hid; 31762306a36Sopenharmony_ci struct acpi_pnp_device_id_list *cid; 31862306a36Sopenharmony_ci u32 i; 31962306a36Sopenharmony_ci u8 match; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* Get the _HID and check for a PCI Root Bridge */ 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci status = acpi_ut_execute_HID(node, &hid); 32462306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 32562306a36Sopenharmony_ci return (FALSE); 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci match = acpi_ut_is_pci_root_bridge(hid->string); 32962306a36Sopenharmony_ci ACPI_FREE(hid); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (match) { 33262306a36Sopenharmony_ci return (TRUE); 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* The _HID did not match. Get the _CID and check for a PCI Root Bridge */ 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci status = acpi_ut_execute_CID(node, &cid); 33862306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 33962306a36Sopenharmony_ci return (FALSE); 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci /* Check all _CIDs in the returned list */ 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci for (i = 0; i < cid->count; i++) { 34562306a36Sopenharmony_ci if (acpi_ut_is_pci_root_bridge(cid->ids[i].string)) { 34662306a36Sopenharmony_ci ACPI_FREE(cid); 34762306a36Sopenharmony_ci return (TRUE); 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci ACPI_FREE(cid); 35262306a36Sopenharmony_ci return (FALSE); 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci/******************************************************************************* 35662306a36Sopenharmony_ci * 35762306a36Sopenharmony_ci * FUNCTION: acpi_ev_pci_bar_region_setup 35862306a36Sopenharmony_ci * 35962306a36Sopenharmony_ci * PARAMETERS: handle - Region we are interested in 36062306a36Sopenharmony_ci * function - Start or stop 36162306a36Sopenharmony_ci * handler_context - Address space handler context 36262306a36Sopenharmony_ci * region_context - Region specific context 36362306a36Sopenharmony_ci * 36462306a36Sopenharmony_ci * RETURN: Status 36562306a36Sopenharmony_ci * 36662306a36Sopenharmony_ci * DESCRIPTION: Setup a pci_BAR operation region 36762306a36Sopenharmony_ci * 36862306a36Sopenharmony_ci * MUTEX: Assumes namespace is not locked 36962306a36Sopenharmony_ci * 37062306a36Sopenharmony_ci ******************************************************************************/ 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ciacpi_status 37362306a36Sopenharmony_ciacpi_ev_pci_bar_region_setup(acpi_handle handle, 37462306a36Sopenharmony_ci u32 function, 37562306a36Sopenharmony_ci void *handler_context, void **region_context) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ev_pci_bar_region_setup); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci/******************************************************************************* 38362306a36Sopenharmony_ci * 38462306a36Sopenharmony_ci * FUNCTION: acpi_ev_cmos_region_setup 38562306a36Sopenharmony_ci * 38662306a36Sopenharmony_ci * PARAMETERS: handle - Region we are interested in 38762306a36Sopenharmony_ci * function - Start or stop 38862306a36Sopenharmony_ci * handler_context - Address space handler context 38962306a36Sopenharmony_ci * region_context - Region specific context 39062306a36Sopenharmony_ci * 39162306a36Sopenharmony_ci * RETURN: Status 39262306a36Sopenharmony_ci * 39362306a36Sopenharmony_ci * DESCRIPTION: Setup a CMOS operation region 39462306a36Sopenharmony_ci * 39562306a36Sopenharmony_ci * MUTEX: Assumes namespace is not locked 39662306a36Sopenharmony_ci * 39762306a36Sopenharmony_ci ******************************************************************************/ 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ciacpi_status 40062306a36Sopenharmony_ciacpi_ev_cmos_region_setup(acpi_handle handle, 40162306a36Sopenharmony_ci u32 function, 40262306a36Sopenharmony_ci void *handler_context, void **region_context) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ev_cmos_region_setup); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci/******************************************************************************* 41062306a36Sopenharmony_ci * 41162306a36Sopenharmony_ci * FUNCTION: acpi_ev_data_table_region_setup 41262306a36Sopenharmony_ci * 41362306a36Sopenharmony_ci * PARAMETERS: handle - Region we are interested in 41462306a36Sopenharmony_ci * function - Start or stop 41562306a36Sopenharmony_ci * handler_context - Address space handler context 41662306a36Sopenharmony_ci * region_context - Region specific context 41762306a36Sopenharmony_ci * 41862306a36Sopenharmony_ci * RETURN: Status 41962306a36Sopenharmony_ci * 42062306a36Sopenharmony_ci * DESCRIPTION: Setup a data_table_region 42162306a36Sopenharmony_ci * 42262306a36Sopenharmony_ci * MUTEX: Assumes namespace is not locked 42362306a36Sopenharmony_ci * 42462306a36Sopenharmony_ci ******************************************************************************/ 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ciacpi_status 42762306a36Sopenharmony_ciacpi_ev_data_table_region_setup(acpi_handle handle, 42862306a36Sopenharmony_ci u32 function, 42962306a36Sopenharmony_ci void *handler_context, void **region_context) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci union acpi_operand_object *region_desc = 43262306a36Sopenharmony_ci (union acpi_operand_object *)handle; 43362306a36Sopenharmony_ci struct acpi_data_table_mapping *local_region_context; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ev_data_table_region_setup); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci if (function == ACPI_REGION_DEACTIVATE) { 43862306a36Sopenharmony_ci if (*region_context) { 43962306a36Sopenharmony_ci ACPI_FREE(*region_context); 44062306a36Sopenharmony_ci *region_context = NULL; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci /* Create a new context */ 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci local_region_context = 44862306a36Sopenharmony_ci ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_data_table_mapping)); 44962306a36Sopenharmony_ci if (!(local_region_context)) { 45062306a36Sopenharmony_ci return_ACPI_STATUS(AE_NO_MEMORY); 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* Save the data table pointer for use in the handler */ 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci local_region_context->pointer = region_desc->region.pointer; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci *region_context = local_region_context; 45862306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci/******************************************************************************* 46262306a36Sopenharmony_ci * 46362306a36Sopenharmony_ci * FUNCTION: acpi_ev_default_region_setup 46462306a36Sopenharmony_ci * 46562306a36Sopenharmony_ci * PARAMETERS: handle - Region we are interested in 46662306a36Sopenharmony_ci * function - Start or stop 46762306a36Sopenharmony_ci * handler_context - Address space handler context 46862306a36Sopenharmony_ci * region_context - Region specific context 46962306a36Sopenharmony_ci * 47062306a36Sopenharmony_ci * RETURN: Status 47162306a36Sopenharmony_ci * 47262306a36Sopenharmony_ci * DESCRIPTION: Default region initialization 47362306a36Sopenharmony_ci * 47462306a36Sopenharmony_ci ******************************************************************************/ 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ciacpi_status 47762306a36Sopenharmony_ciacpi_ev_default_region_setup(acpi_handle handle, 47862306a36Sopenharmony_ci u32 function, 47962306a36Sopenharmony_ci void *handler_context, void **region_context) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ev_default_region_setup); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (function == ACPI_REGION_DEACTIVATE) { 48462306a36Sopenharmony_ci *region_context = NULL; 48562306a36Sopenharmony_ci } else { 48662306a36Sopenharmony_ci *region_context = handler_context; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci/******************************************************************************* 49362306a36Sopenharmony_ci * 49462306a36Sopenharmony_ci * FUNCTION: acpi_ev_initialize_region 49562306a36Sopenharmony_ci * 49662306a36Sopenharmony_ci * PARAMETERS: region_obj - Region we are initializing 49762306a36Sopenharmony_ci * 49862306a36Sopenharmony_ci * RETURN: Status 49962306a36Sopenharmony_ci * 50062306a36Sopenharmony_ci * DESCRIPTION: Initializes the region, finds any _REG methods and saves them 50162306a36Sopenharmony_ci * for execution at a later time 50262306a36Sopenharmony_ci * 50362306a36Sopenharmony_ci * Get the appropriate address space handler for a newly 50462306a36Sopenharmony_ci * created region. 50562306a36Sopenharmony_ci * 50662306a36Sopenharmony_ci * This also performs address space specific initialization. For 50762306a36Sopenharmony_ci * example, PCI regions must have an _ADR object that contains 50862306a36Sopenharmony_ci * a PCI address in the scope of the definition. This address is 50962306a36Sopenharmony_ci * required to perform an access to PCI config space. 51062306a36Sopenharmony_ci * 51162306a36Sopenharmony_ci * MUTEX: Interpreter should be unlocked, because we may run the _REG 51262306a36Sopenharmony_ci * method for this region. 51362306a36Sopenharmony_ci * 51462306a36Sopenharmony_ci * NOTE: Possible incompliance: 51562306a36Sopenharmony_ci * There is a behavior conflict in automatic _REG execution: 51662306a36Sopenharmony_ci * 1. When the interpreter is evaluating a method, we can only 51762306a36Sopenharmony_ci * automatically run _REG for the following case: 51862306a36Sopenharmony_ci * operation_region (OPR1, 0x80, 0x1000010, 0x4) 51962306a36Sopenharmony_ci * 2. When the interpreter is loading a table, we can also 52062306a36Sopenharmony_ci * automatically run _REG for the following case: 52162306a36Sopenharmony_ci * operation_region (OPR1, 0x80, 0x1000010, 0x4) 52262306a36Sopenharmony_ci * Though this may not be compliant to the de-facto standard, the 52362306a36Sopenharmony_ci * logic is kept in order not to trigger regressions. And keeping 52462306a36Sopenharmony_ci * this logic should be taken care by the caller of this function. 52562306a36Sopenharmony_ci * 52662306a36Sopenharmony_ci ******************************************************************************/ 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ciacpi_status acpi_ev_initialize_region(union acpi_operand_object *region_obj) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci union acpi_operand_object *handler_obj; 53162306a36Sopenharmony_ci union acpi_operand_object *obj_desc; 53262306a36Sopenharmony_ci acpi_adr_space_type space_id; 53362306a36Sopenharmony_ci struct acpi_namespace_node *node; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ev_initialize_region); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci if (!region_obj) { 53862306a36Sopenharmony_ci return_ACPI_STATUS(AE_BAD_PARAMETER); 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (region_obj->common.flags & AOPOBJ_OBJECT_INITIALIZED) { 54262306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci region_obj->common.flags |= AOPOBJ_OBJECT_INITIALIZED; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci node = region_obj->region.node->parent; 54862306a36Sopenharmony_ci space_id = region_obj->region.space_id; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci /* 55162306a36Sopenharmony_ci * The following loop depends upon the root Node having no parent 55262306a36Sopenharmony_ci * ie: acpi_gbl_root_node->Parent being set to NULL 55362306a36Sopenharmony_ci */ 55462306a36Sopenharmony_ci while (node) { 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci /* Check to see if a handler exists */ 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci handler_obj = NULL; 55962306a36Sopenharmony_ci obj_desc = acpi_ns_get_attached_object(node); 56062306a36Sopenharmony_ci if (obj_desc) { 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci /* Can only be a handler if the object exists */ 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci switch (node->type) { 56562306a36Sopenharmony_ci case ACPI_TYPE_DEVICE: 56662306a36Sopenharmony_ci case ACPI_TYPE_PROCESSOR: 56762306a36Sopenharmony_ci case ACPI_TYPE_THERMAL: 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci handler_obj = obj_desc->common_notify.handler; 57062306a36Sopenharmony_ci break; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci default: 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci /* Ignore other objects */ 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci break; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci handler_obj = 58062306a36Sopenharmony_ci acpi_ev_find_region_handler(space_id, handler_obj); 58162306a36Sopenharmony_ci if (handler_obj) { 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci /* Found correct handler */ 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, 58662306a36Sopenharmony_ci "Found handler %p for region %p in obj %p\n", 58762306a36Sopenharmony_ci handler_obj, region_obj, 58862306a36Sopenharmony_ci obj_desc)); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci (void)acpi_ev_attach_region(handler_obj, 59162306a36Sopenharmony_ci region_obj, FALSE); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci /* 59462306a36Sopenharmony_ci * Tell all users that this region is usable by 59562306a36Sopenharmony_ci * running the _REG method 59662306a36Sopenharmony_ci */ 59762306a36Sopenharmony_ci acpi_ex_exit_interpreter(); 59862306a36Sopenharmony_ci (void)acpi_ev_execute_reg_method(region_obj, 59962306a36Sopenharmony_ci ACPI_REG_CONNECT); 60062306a36Sopenharmony_ci acpi_ex_enter_interpreter(); 60162306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci /* This node does not have the handler we need; Pop up one level */ 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci node = node->parent; 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci /* 61162306a36Sopenharmony_ci * If we get here, there is no handler for this region. This is not 61262306a36Sopenharmony_ci * fatal because many regions get created before a handler is installed 61362306a36Sopenharmony_ci * for said region. 61462306a36Sopenharmony_ci */ 61562306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, 61662306a36Sopenharmony_ci "No handler for RegionType %s(%X) (RegionObj %p)\n", 61762306a36Sopenharmony_ci acpi_ut_get_region_name(space_id), space_id, 61862306a36Sopenharmony_ci region_obj)); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 62162306a36Sopenharmony_ci} 622