195b482a8SLen Brown /****************************************************************************** 295b482a8SLen Brown * 395b482a8SLen Brown * Module Name: evrgnini- ACPI address_space (op_region) init 495b482a8SLen Brown * 595b482a8SLen Brown *****************************************************************************/ 695b482a8SLen Brown 795b482a8SLen Brown /* 895b482a8SLen Brown * Copyright (C) 2000 - 2008, Intel Corp. 995b482a8SLen Brown * All rights reserved. 1095b482a8SLen Brown * 1195b482a8SLen Brown * Redistribution and use in source and binary forms, with or without 1295b482a8SLen Brown * modification, are permitted provided that the following conditions 1395b482a8SLen Brown * are met: 1495b482a8SLen Brown * 1. Redistributions of source code must retain the above copyright 1595b482a8SLen Brown * notice, this list of conditions, and the following disclaimer, 1695b482a8SLen Brown * without modification. 1795b482a8SLen Brown * 2. Redistributions in binary form must reproduce at minimum a disclaimer 1895b482a8SLen Brown * substantially similar to the "NO WARRANTY" disclaimer below 1995b482a8SLen Brown * ("Disclaimer") and any redistribution must be conditioned upon 2095b482a8SLen Brown * including a substantially similar Disclaimer requirement for further 2195b482a8SLen Brown * binary redistribution. 2295b482a8SLen Brown * 3. Neither the names of the above-listed copyright holders nor the names 2395b482a8SLen Brown * of any contributors may be used to endorse or promote products derived 2495b482a8SLen Brown * from this software without specific prior written permission. 2595b482a8SLen Brown * 2695b482a8SLen Brown * Alternatively, this software may be distributed under the terms of the 2795b482a8SLen Brown * GNU General Public License ("GPL") version 2 as published by the Free 2895b482a8SLen Brown * Software Foundation. 2995b482a8SLen Brown * 3095b482a8SLen Brown * NO WARRANTY 3195b482a8SLen Brown * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3295b482a8SLen Brown * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3395b482a8SLen Brown * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 3495b482a8SLen Brown * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3595b482a8SLen Brown * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3695b482a8SLen Brown * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3795b482a8SLen Brown * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3895b482a8SLen Brown * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 3995b482a8SLen Brown * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 4095b482a8SLen Brown * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 4195b482a8SLen Brown * POSSIBILITY OF SUCH DAMAGES. 4295b482a8SLen Brown */ 4395b482a8SLen Brown 4495b482a8SLen Brown #include <acpi/acpi.h> 45*e2f7a777SLen Brown #include "accommon.h" 46*e2f7a777SLen Brown #include "acevents.h" 47*e2f7a777SLen Brown #include "acnamesp.h" 4895b482a8SLen Brown 4995b482a8SLen Brown #define _COMPONENT ACPI_EVENTS 5095b482a8SLen Brown ACPI_MODULE_NAME("evrgnini") 5195b482a8SLen Brown 5295b482a8SLen Brown /* Local prototypes */ 5395b482a8SLen Brown static u8 acpi_ev_match_pci_root_bridge(char *id); 5495b482a8SLen Brown 5595b482a8SLen Brown static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node); 5695b482a8SLen Brown 5795b482a8SLen Brown /******************************************************************************* 5895b482a8SLen Brown * 5995b482a8SLen Brown * FUNCTION: acpi_ev_system_memory_region_setup 6095b482a8SLen Brown * 6195b482a8SLen Brown * PARAMETERS: Handle - Region we are interested in 6295b482a8SLen Brown * Function - Start or stop 6395b482a8SLen Brown * handler_context - Address space handler context 6495b482a8SLen Brown * region_context - Region specific context 6595b482a8SLen Brown * 6695b482a8SLen Brown * RETURN: Status 6795b482a8SLen Brown * 6895b482a8SLen Brown * DESCRIPTION: Setup a system_memory operation region 6995b482a8SLen Brown * 7095b482a8SLen Brown ******************************************************************************/ 7195b482a8SLen Brown 7295b482a8SLen Brown acpi_status 7395b482a8SLen Brown acpi_ev_system_memory_region_setup(acpi_handle handle, 7495b482a8SLen Brown u32 function, 7595b482a8SLen Brown void *handler_context, void **region_context) 7695b482a8SLen Brown { 7795b482a8SLen Brown union acpi_operand_object *region_desc = 7895b482a8SLen Brown (union acpi_operand_object *)handle; 7995b482a8SLen Brown struct acpi_mem_space_context *local_region_context; 8095b482a8SLen Brown 8195b482a8SLen Brown ACPI_FUNCTION_TRACE(ev_system_memory_region_setup); 8295b482a8SLen Brown 8395b482a8SLen Brown if (function == ACPI_REGION_DEACTIVATE) { 8495b482a8SLen Brown if (*region_context) { 8595b482a8SLen Brown local_region_context = 8695b482a8SLen Brown (struct acpi_mem_space_context *)*region_context; 8795b482a8SLen Brown 8895b482a8SLen Brown /* Delete a cached mapping if present */ 8995b482a8SLen Brown 9095b482a8SLen Brown if (local_region_context->mapped_length) { 9195b482a8SLen Brown acpi_os_unmap_memory(local_region_context-> 9295b482a8SLen Brown mapped_logical_address, 9395b482a8SLen Brown local_region_context-> 9495b482a8SLen Brown mapped_length); 9595b482a8SLen Brown } 9695b482a8SLen Brown ACPI_FREE(local_region_context); 9795b482a8SLen Brown *region_context = NULL; 9895b482a8SLen Brown } 9995b482a8SLen Brown return_ACPI_STATUS(AE_OK); 10095b482a8SLen Brown } 10195b482a8SLen Brown 10295b482a8SLen Brown /* Create a new context */ 10395b482a8SLen Brown 10495b482a8SLen Brown local_region_context = 10595b482a8SLen Brown ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_mem_space_context)); 10695b482a8SLen Brown if (!(local_region_context)) { 10795b482a8SLen Brown return_ACPI_STATUS(AE_NO_MEMORY); 10895b482a8SLen Brown } 10995b482a8SLen Brown 11095b482a8SLen Brown /* Save the region length and address for use in the handler */ 11195b482a8SLen Brown 11295b482a8SLen Brown local_region_context->length = region_desc->region.length; 11395b482a8SLen Brown local_region_context->address = region_desc->region.address; 11495b482a8SLen Brown 11595b482a8SLen Brown *region_context = local_region_context; 11695b482a8SLen Brown return_ACPI_STATUS(AE_OK); 11795b482a8SLen Brown } 11895b482a8SLen Brown 11995b482a8SLen Brown /******************************************************************************* 12095b482a8SLen Brown * 12195b482a8SLen Brown * FUNCTION: acpi_ev_io_space_region_setup 12295b482a8SLen Brown * 12395b482a8SLen Brown * PARAMETERS: Handle - Region we are interested in 12495b482a8SLen Brown * Function - Start or stop 12595b482a8SLen Brown * handler_context - Address space handler context 12695b482a8SLen Brown * region_context - Region specific context 12795b482a8SLen Brown * 12895b482a8SLen Brown * RETURN: Status 12995b482a8SLen Brown * 13095b482a8SLen Brown * DESCRIPTION: Setup a IO operation region 13195b482a8SLen Brown * 13295b482a8SLen Brown ******************************************************************************/ 13395b482a8SLen Brown 13495b482a8SLen Brown acpi_status 13595b482a8SLen Brown acpi_ev_io_space_region_setup(acpi_handle handle, 13695b482a8SLen Brown u32 function, 13795b482a8SLen Brown void *handler_context, void **region_context) 13895b482a8SLen Brown { 13995b482a8SLen Brown ACPI_FUNCTION_TRACE(ev_io_space_region_setup); 14095b482a8SLen Brown 14195b482a8SLen Brown if (function == ACPI_REGION_DEACTIVATE) { 14295b482a8SLen Brown *region_context = NULL; 14395b482a8SLen Brown } else { 14495b482a8SLen Brown *region_context = handler_context; 14595b482a8SLen Brown } 14695b482a8SLen Brown 14795b482a8SLen Brown return_ACPI_STATUS(AE_OK); 14895b482a8SLen Brown } 14995b482a8SLen Brown 15095b482a8SLen Brown /******************************************************************************* 15195b482a8SLen Brown * 15295b482a8SLen Brown * FUNCTION: acpi_ev_pci_config_region_setup 15395b482a8SLen Brown * 15495b482a8SLen Brown * PARAMETERS: Handle - Region we are interested in 15595b482a8SLen Brown * Function - Start or stop 15695b482a8SLen Brown * handler_context - Address space handler context 15795b482a8SLen Brown * region_context - Region specific context 15895b482a8SLen Brown * 15995b482a8SLen Brown * RETURN: Status 16095b482a8SLen Brown * 16195b482a8SLen Brown * DESCRIPTION: Setup a PCI_Config operation region 16295b482a8SLen Brown * 16395b482a8SLen Brown * MUTEX: Assumes namespace is not locked 16495b482a8SLen Brown * 16595b482a8SLen Brown ******************************************************************************/ 16695b482a8SLen Brown 16795b482a8SLen Brown acpi_status 16895b482a8SLen Brown acpi_ev_pci_config_region_setup(acpi_handle handle, 16995b482a8SLen Brown u32 function, 17095b482a8SLen Brown void *handler_context, void **region_context) 17195b482a8SLen Brown { 17295b482a8SLen Brown acpi_status status = AE_OK; 17395b482a8SLen Brown acpi_integer pci_value; 17495b482a8SLen Brown struct acpi_pci_id *pci_id = *region_context; 17595b482a8SLen Brown union acpi_operand_object *handler_obj; 17695b482a8SLen Brown struct acpi_namespace_node *parent_node; 17795b482a8SLen Brown struct acpi_namespace_node *pci_root_node; 17895b482a8SLen Brown struct acpi_namespace_node *pci_device_node; 17995b482a8SLen Brown union acpi_operand_object *region_obj = 18095b482a8SLen Brown (union acpi_operand_object *)handle; 18195b482a8SLen Brown 18295b482a8SLen Brown ACPI_FUNCTION_TRACE(ev_pci_config_region_setup); 18395b482a8SLen Brown 18495b482a8SLen Brown handler_obj = region_obj->region.handler; 18595b482a8SLen Brown if (!handler_obj) { 18695b482a8SLen Brown /* 18795b482a8SLen Brown * No installed handler. This shouldn't happen because the dispatch 18895b482a8SLen Brown * routine checks before we get here, but we check again just in case. 18995b482a8SLen Brown */ 19095b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, 19195b482a8SLen Brown "Attempting to init a region %p, with no handler\n", 19295b482a8SLen Brown region_obj)); 19395b482a8SLen Brown return_ACPI_STATUS(AE_NOT_EXIST); 19495b482a8SLen Brown } 19595b482a8SLen Brown 19695b482a8SLen Brown *region_context = NULL; 19795b482a8SLen Brown if (function == ACPI_REGION_DEACTIVATE) { 19895b482a8SLen Brown if (pci_id) { 19995b482a8SLen Brown ACPI_FREE(pci_id); 20095b482a8SLen Brown } 20195b482a8SLen Brown return_ACPI_STATUS(status); 20295b482a8SLen Brown } 20395b482a8SLen Brown 20495b482a8SLen Brown parent_node = acpi_ns_get_parent_node(region_obj->region.node); 20595b482a8SLen Brown 20695b482a8SLen Brown /* 20795b482a8SLen Brown * Get the _SEG and _BBN values from the device upon which the handler 20895b482a8SLen Brown * is installed. 20995b482a8SLen Brown * 21095b482a8SLen Brown * We need to get the _SEG and _BBN objects relative to the PCI BUS device. 21195b482a8SLen Brown * This is the device the handler has been registered to handle. 21295b482a8SLen Brown */ 21395b482a8SLen Brown 21495b482a8SLen Brown /* 21595b482a8SLen Brown * If the address_space.Node is still pointing to the root, we need 21695b482a8SLen Brown * to scan upward for a PCI Root bridge and re-associate the op_region 21795b482a8SLen Brown * handlers with that device. 21895b482a8SLen Brown */ 21995b482a8SLen Brown if (handler_obj->address_space.node == acpi_gbl_root_node) { 22095b482a8SLen Brown 22195b482a8SLen Brown /* Start search from the parent object */ 22295b482a8SLen Brown 22395b482a8SLen Brown pci_root_node = parent_node; 22495b482a8SLen Brown while (pci_root_node != acpi_gbl_root_node) { 22595b482a8SLen Brown 22695b482a8SLen Brown /* Get the _HID/_CID in order to detect a root_bridge */ 22795b482a8SLen Brown 22895b482a8SLen Brown if (acpi_ev_is_pci_root_bridge(pci_root_node)) { 22995b482a8SLen Brown 23095b482a8SLen Brown /* Install a handler for this PCI root bridge */ 23195b482a8SLen Brown 23295b482a8SLen Brown status = 23395b482a8SLen Brown acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); 23495b482a8SLen Brown if (ACPI_FAILURE(status)) { 23595b482a8SLen Brown if (status == AE_SAME_HANDLER) { 23695b482a8SLen Brown /* 23795b482a8SLen Brown * It is OK if the handler is already installed on the 23895b482a8SLen Brown * root bridge. Still need to return a context object 23995b482a8SLen Brown * for the new PCI_Config operation region, however. 24095b482a8SLen Brown */ 24195b482a8SLen Brown status = AE_OK; 24295b482a8SLen Brown } else { 24395b482a8SLen Brown ACPI_EXCEPTION((AE_INFO, status, 24495b482a8SLen Brown "Could not install PciConfig handler for Root Bridge %4.4s", 24595b482a8SLen Brown acpi_ut_get_node_name 24695b482a8SLen Brown (pci_root_node))); 24795b482a8SLen Brown } 24895b482a8SLen Brown } 24995b482a8SLen Brown break; 25095b482a8SLen Brown } 25195b482a8SLen Brown 25295b482a8SLen Brown pci_root_node = acpi_ns_get_parent_node(pci_root_node); 25395b482a8SLen Brown } 25495b482a8SLen Brown 25595b482a8SLen Brown /* PCI root bridge not found, use namespace root node */ 25695b482a8SLen Brown } else { 25795b482a8SLen Brown pci_root_node = handler_obj->address_space.node; 25895b482a8SLen Brown } 25995b482a8SLen Brown 26095b482a8SLen Brown /* 26195b482a8SLen Brown * If this region is now initialized, we are done. 26295b482a8SLen Brown * (install_address_space_handler could have initialized it) 26395b482a8SLen Brown */ 26495b482a8SLen Brown if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) { 26595b482a8SLen Brown return_ACPI_STATUS(AE_OK); 26695b482a8SLen Brown } 26795b482a8SLen Brown 26895b482a8SLen Brown /* Region is still not initialized. Create a new context */ 26995b482a8SLen Brown 27095b482a8SLen Brown pci_id = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pci_id)); 27195b482a8SLen Brown if (!pci_id) { 27295b482a8SLen Brown return_ACPI_STATUS(AE_NO_MEMORY); 27395b482a8SLen Brown } 27495b482a8SLen Brown 27595b482a8SLen Brown /* 27695b482a8SLen Brown * For PCI_Config space access, we need the segment, bus, device and 27795b482a8SLen Brown * function numbers. Acquire them here. 27895b482a8SLen Brown * 27995b482a8SLen Brown * Find the parent device object. (This allows the operation region to be 28095b482a8SLen Brown * within a subscope under the device, such as a control method.) 28195b482a8SLen Brown */ 28295b482a8SLen Brown pci_device_node = region_obj->region.node; 28395b482a8SLen Brown while (pci_device_node && (pci_device_node->type != ACPI_TYPE_DEVICE)) { 28495b482a8SLen Brown pci_device_node = acpi_ns_get_parent_node(pci_device_node); 28595b482a8SLen Brown } 28695b482a8SLen Brown 28795b482a8SLen Brown if (!pci_device_node) { 28895b482a8SLen Brown ACPI_FREE(pci_id); 28995b482a8SLen Brown return_ACPI_STATUS(AE_AML_OPERAND_TYPE); 29095b482a8SLen Brown } 29195b482a8SLen Brown 29295b482a8SLen Brown /* 29395b482a8SLen Brown * Get the PCI device and function numbers from the _ADR object contained 29495b482a8SLen Brown * in the parent's scope. 29595b482a8SLen Brown */ 29695b482a8SLen Brown status = 29795b482a8SLen Brown acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, pci_device_node, 29895b482a8SLen Brown &pci_value); 29995b482a8SLen Brown 30095b482a8SLen Brown /* 30195b482a8SLen Brown * The default is zero, and since the allocation above zeroed the data, 30295b482a8SLen Brown * just do nothing on failure. 30395b482a8SLen Brown */ 30495b482a8SLen Brown if (ACPI_SUCCESS(status)) { 30595b482a8SLen Brown pci_id->device = ACPI_HIWORD(ACPI_LODWORD(pci_value)); 30695b482a8SLen Brown pci_id->function = ACPI_LOWORD(ACPI_LODWORD(pci_value)); 30795b482a8SLen Brown } 30895b482a8SLen Brown 30995b482a8SLen Brown /* The PCI segment number comes from the _SEG method */ 31095b482a8SLen Brown 31195b482a8SLen Brown status = 31295b482a8SLen Brown acpi_ut_evaluate_numeric_object(METHOD_NAME__SEG, pci_root_node, 31395b482a8SLen Brown &pci_value); 31495b482a8SLen Brown if (ACPI_SUCCESS(status)) { 31595b482a8SLen Brown pci_id->segment = ACPI_LOWORD(pci_value); 31695b482a8SLen Brown } 31795b482a8SLen Brown 31895b482a8SLen Brown /* The PCI bus number comes from the _BBN method */ 31995b482a8SLen Brown 32095b482a8SLen Brown status = 32195b482a8SLen Brown acpi_ut_evaluate_numeric_object(METHOD_NAME__BBN, pci_root_node, 32295b482a8SLen Brown &pci_value); 32395b482a8SLen Brown if (ACPI_SUCCESS(status)) { 32495b482a8SLen Brown pci_id->bus = ACPI_LOWORD(pci_value); 32595b482a8SLen Brown } 32695b482a8SLen Brown 32795b482a8SLen Brown /* Complete this device's pci_id */ 32895b482a8SLen Brown 32995b482a8SLen Brown acpi_os_derive_pci_id(pci_root_node, region_obj->region.node, &pci_id); 33095b482a8SLen Brown 33195b482a8SLen Brown *region_context = pci_id; 33295b482a8SLen Brown return_ACPI_STATUS(AE_OK); 33395b482a8SLen Brown } 33495b482a8SLen Brown 33595b482a8SLen Brown /******************************************************************************* 33695b482a8SLen Brown * 33795b482a8SLen Brown * FUNCTION: acpi_ev_match_pci_root_bridge 33895b482a8SLen Brown * 33995b482a8SLen Brown * PARAMETERS: Id - The HID/CID in string format 34095b482a8SLen Brown * 34195b482a8SLen Brown * RETURN: TRUE if the Id is a match for a PCI/PCI-Express Root Bridge 34295b482a8SLen Brown * 34395b482a8SLen Brown * DESCRIPTION: Determine if the input ID is a PCI Root Bridge ID. 34495b482a8SLen Brown * 34595b482a8SLen Brown ******************************************************************************/ 34695b482a8SLen Brown 34795b482a8SLen Brown static u8 acpi_ev_match_pci_root_bridge(char *id) 34895b482a8SLen Brown { 34995b482a8SLen Brown 35095b482a8SLen Brown /* 35195b482a8SLen Brown * Check if this is a PCI root. 35295b482a8SLen Brown * ACPI 3.0+: check for a PCI Express root also. 35395b482a8SLen Brown */ 35495b482a8SLen Brown if (!(ACPI_STRNCMP(id, 35595b482a8SLen Brown PCI_ROOT_HID_STRING, 35695b482a8SLen Brown sizeof(PCI_ROOT_HID_STRING))) || 35795b482a8SLen Brown !(ACPI_STRNCMP(id, 35895b482a8SLen Brown PCI_EXPRESS_ROOT_HID_STRING, 35995b482a8SLen Brown sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) { 36095b482a8SLen Brown return (TRUE); 36195b482a8SLen Brown } 36295b482a8SLen Brown 36395b482a8SLen Brown return (FALSE); 36495b482a8SLen Brown } 36595b482a8SLen Brown 36695b482a8SLen Brown /******************************************************************************* 36795b482a8SLen Brown * 36895b482a8SLen Brown * FUNCTION: acpi_ev_is_pci_root_bridge 36995b482a8SLen Brown * 37095b482a8SLen Brown * PARAMETERS: Node - Device node being examined 37195b482a8SLen Brown * 37295b482a8SLen Brown * RETURN: TRUE if device is a PCI/PCI-Express Root Bridge 37395b482a8SLen Brown * 37495b482a8SLen Brown * DESCRIPTION: Determine if the input device represents a PCI Root Bridge by 37595b482a8SLen Brown * examining the _HID and _CID for the device. 37695b482a8SLen Brown * 37795b482a8SLen Brown ******************************************************************************/ 37895b482a8SLen Brown 37995b482a8SLen Brown static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node) 38095b482a8SLen Brown { 38195b482a8SLen Brown acpi_status status; 38295b482a8SLen Brown struct acpica_device_id hid; 38395b482a8SLen Brown struct acpi_compatible_id_list *cid; 38495b482a8SLen Brown u32 i; 38595b482a8SLen Brown 38695b482a8SLen Brown /* Get the _HID and check for a PCI Root Bridge */ 38795b482a8SLen Brown 38895b482a8SLen Brown status = acpi_ut_execute_HID(node, &hid); 38995b482a8SLen Brown if (ACPI_FAILURE(status)) { 39095b482a8SLen Brown return (FALSE); 39195b482a8SLen Brown } 39295b482a8SLen Brown 39395b482a8SLen Brown if (acpi_ev_match_pci_root_bridge(hid.value)) { 39495b482a8SLen Brown return (TRUE); 39595b482a8SLen Brown } 39695b482a8SLen Brown 39795b482a8SLen Brown /* The _HID did not match. Get the _CID and check for a PCI Root Bridge */ 39895b482a8SLen Brown 39995b482a8SLen Brown status = acpi_ut_execute_CID(node, &cid); 40095b482a8SLen Brown if (ACPI_FAILURE(status)) { 40195b482a8SLen Brown return (FALSE); 40295b482a8SLen Brown } 40395b482a8SLen Brown 40495b482a8SLen Brown /* Check all _CIDs in the returned list */ 40595b482a8SLen Brown 40695b482a8SLen Brown for (i = 0; i < cid->count; i++) { 40795b482a8SLen Brown if (acpi_ev_match_pci_root_bridge(cid->id[i].value)) { 40895b482a8SLen Brown ACPI_FREE(cid); 40995b482a8SLen Brown return (TRUE); 41095b482a8SLen Brown } 41195b482a8SLen Brown } 41295b482a8SLen Brown 41395b482a8SLen Brown ACPI_FREE(cid); 41495b482a8SLen Brown return (FALSE); 41595b482a8SLen Brown } 41695b482a8SLen Brown 41795b482a8SLen Brown /******************************************************************************* 41895b482a8SLen Brown * 41995b482a8SLen Brown * FUNCTION: acpi_ev_pci_bar_region_setup 42095b482a8SLen Brown * 42195b482a8SLen Brown * PARAMETERS: Handle - Region we are interested in 42295b482a8SLen Brown * Function - Start or stop 42395b482a8SLen Brown * handler_context - Address space handler context 42495b482a8SLen Brown * region_context - Region specific context 42595b482a8SLen Brown * 42695b482a8SLen Brown * RETURN: Status 42795b482a8SLen Brown * 42895b482a8SLen Brown * DESCRIPTION: Setup a pci_bAR operation region 42995b482a8SLen Brown * 43095b482a8SLen Brown * MUTEX: Assumes namespace is not locked 43195b482a8SLen Brown * 43295b482a8SLen Brown ******************************************************************************/ 43395b482a8SLen Brown 43495b482a8SLen Brown acpi_status 43595b482a8SLen Brown acpi_ev_pci_bar_region_setup(acpi_handle handle, 43695b482a8SLen Brown u32 function, 43795b482a8SLen Brown void *handler_context, void **region_context) 43895b482a8SLen Brown { 43995b482a8SLen Brown ACPI_FUNCTION_TRACE(ev_pci_bar_region_setup); 44095b482a8SLen Brown 44195b482a8SLen Brown return_ACPI_STATUS(AE_OK); 44295b482a8SLen Brown } 44395b482a8SLen Brown 44495b482a8SLen Brown /******************************************************************************* 44595b482a8SLen Brown * 44695b482a8SLen Brown * FUNCTION: acpi_ev_cmos_region_setup 44795b482a8SLen Brown * 44895b482a8SLen Brown * PARAMETERS: Handle - Region we are interested in 44995b482a8SLen Brown * Function - Start or stop 45095b482a8SLen Brown * handler_context - Address space handler context 45195b482a8SLen Brown * region_context - Region specific context 45295b482a8SLen Brown * 45395b482a8SLen Brown * RETURN: Status 45495b482a8SLen Brown * 45595b482a8SLen Brown * DESCRIPTION: Setup a CMOS operation region 45695b482a8SLen Brown * 45795b482a8SLen Brown * MUTEX: Assumes namespace is not locked 45895b482a8SLen Brown * 45995b482a8SLen Brown ******************************************************************************/ 46095b482a8SLen Brown 46195b482a8SLen Brown acpi_status 46295b482a8SLen Brown acpi_ev_cmos_region_setup(acpi_handle handle, 46395b482a8SLen Brown u32 function, 46495b482a8SLen Brown void *handler_context, void **region_context) 46595b482a8SLen Brown { 46695b482a8SLen Brown ACPI_FUNCTION_TRACE(ev_cmos_region_setup); 46795b482a8SLen Brown 46895b482a8SLen Brown return_ACPI_STATUS(AE_OK); 46995b482a8SLen Brown } 47095b482a8SLen Brown 47195b482a8SLen Brown /******************************************************************************* 47295b482a8SLen Brown * 47395b482a8SLen Brown * FUNCTION: acpi_ev_default_region_setup 47495b482a8SLen Brown * 47595b482a8SLen Brown * PARAMETERS: Handle - Region we are interested in 47695b482a8SLen Brown * Function - Start or stop 47795b482a8SLen Brown * handler_context - Address space handler context 47895b482a8SLen Brown * region_context - Region specific context 47995b482a8SLen Brown * 48095b482a8SLen Brown * RETURN: Status 48195b482a8SLen Brown * 48295b482a8SLen Brown * DESCRIPTION: Default region initialization 48395b482a8SLen Brown * 48495b482a8SLen Brown ******************************************************************************/ 48595b482a8SLen Brown 48695b482a8SLen Brown acpi_status 48795b482a8SLen Brown acpi_ev_default_region_setup(acpi_handle handle, 48895b482a8SLen Brown u32 function, 48995b482a8SLen Brown void *handler_context, void **region_context) 49095b482a8SLen Brown { 49195b482a8SLen Brown ACPI_FUNCTION_TRACE(ev_default_region_setup); 49295b482a8SLen Brown 49395b482a8SLen Brown if (function == ACPI_REGION_DEACTIVATE) { 49495b482a8SLen Brown *region_context = NULL; 49595b482a8SLen Brown } else { 49695b482a8SLen Brown *region_context = handler_context; 49795b482a8SLen Brown } 49895b482a8SLen Brown 49995b482a8SLen Brown return_ACPI_STATUS(AE_OK); 50095b482a8SLen Brown } 50195b482a8SLen Brown 50295b482a8SLen Brown /******************************************************************************* 50395b482a8SLen Brown * 50495b482a8SLen Brown * FUNCTION: acpi_ev_initialize_region 50595b482a8SLen Brown * 50695b482a8SLen Brown * PARAMETERS: region_obj - Region we are initializing 50795b482a8SLen Brown * acpi_ns_locked - Is namespace locked? 50895b482a8SLen Brown * 50995b482a8SLen Brown * RETURN: Status 51095b482a8SLen Brown * 51195b482a8SLen Brown * DESCRIPTION: Initializes the region, finds any _REG methods and saves them 51295b482a8SLen Brown * for execution at a later time 51395b482a8SLen Brown * 51495b482a8SLen Brown * Get the appropriate address space handler for a newly 51595b482a8SLen Brown * created region. 51695b482a8SLen Brown * 51795b482a8SLen Brown * This also performs address space specific initialization. For 51895b482a8SLen Brown * example, PCI regions must have an _ADR object that contains 51995b482a8SLen Brown * a PCI address in the scope of the definition. This address is 52095b482a8SLen Brown * required to perform an access to PCI config space. 52195b482a8SLen Brown * 52295b482a8SLen Brown * MUTEX: Interpreter should be unlocked, because we may run the _REG 52395b482a8SLen Brown * method for this region. 52495b482a8SLen Brown * 52595b482a8SLen Brown ******************************************************************************/ 52695b482a8SLen Brown 52795b482a8SLen Brown acpi_status 52895b482a8SLen Brown acpi_ev_initialize_region(union acpi_operand_object *region_obj, 52995b482a8SLen Brown u8 acpi_ns_locked) 53095b482a8SLen Brown { 53195b482a8SLen Brown union acpi_operand_object *handler_obj; 53295b482a8SLen Brown union acpi_operand_object *obj_desc; 53395b482a8SLen Brown acpi_adr_space_type space_id; 53495b482a8SLen Brown struct acpi_namespace_node *node; 53595b482a8SLen Brown acpi_status status; 53695b482a8SLen Brown struct acpi_namespace_node *method_node; 53795b482a8SLen Brown acpi_name *reg_name_ptr = (acpi_name *) METHOD_NAME__REG; 53895b482a8SLen Brown union acpi_operand_object *region_obj2; 53995b482a8SLen Brown 54095b482a8SLen Brown ACPI_FUNCTION_TRACE_U32(ev_initialize_region, acpi_ns_locked); 54195b482a8SLen Brown 54295b482a8SLen Brown if (!region_obj) { 54395b482a8SLen Brown return_ACPI_STATUS(AE_BAD_PARAMETER); 54495b482a8SLen Brown } 54595b482a8SLen Brown 54695b482a8SLen Brown if (region_obj->common.flags & AOPOBJ_OBJECT_INITIALIZED) { 54795b482a8SLen Brown return_ACPI_STATUS(AE_OK); 54895b482a8SLen Brown } 54995b482a8SLen Brown 55095b482a8SLen Brown region_obj2 = acpi_ns_get_secondary_object(region_obj); 55195b482a8SLen Brown if (!region_obj2) { 55295b482a8SLen Brown return_ACPI_STATUS(AE_NOT_EXIST); 55395b482a8SLen Brown } 55495b482a8SLen Brown 55595b482a8SLen Brown node = acpi_ns_get_parent_node(region_obj->region.node); 55695b482a8SLen Brown space_id = region_obj->region.space_id; 55795b482a8SLen Brown 55895b482a8SLen Brown /* Setup defaults */ 55995b482a8SLen Brown 56095b482a8SLen Brown region_obj->region.handler = NULL; 56195b482a8SLen Brown region_obj2->extra.method_REG = NULL; 56295b482a8SLen Brown region_obj->common.flags &= ~(AOPOBJ_SETUP_COMPLETE); 56395b482a8SLen Brown region_obj->common.flags |= AOPOBJ_OBJECT_INITIALIZED; 56495b482a8SLen Brown 56595b482a8SLen Brown /* Find any "_REG" method associated with this region definition */ 56695b482a8SLen Brown 56795b482a8SLen Brown status = 56895b482a8SLen Brown acpi_ns_search_one_scope(*reg_name_ptr, node, ACPI_TYPE_METHOD, 56995b482a8SLen Brown &method_node); 57095b482a8SLen Brown if (ACPI_SUCCESS(status)) { 57195b482a8SLen Brown /* 57295b482a8SLen Brown * The _REG method is optional and there can be only one per region 57395b482a8SLen Brown * definition. This will be executed when the handler is attached 57495b482a8SLen Brown * or removed 57595b482a8SLen Brown */ 57695b482a8SLen Brown region_obj2->extra.method_REG = method_node; 57795b482a8SLen Brown } 57895b482a8SLen Brown 57995b482a8SLen Brown /* 58095b482a8SLen Brown * The following loop depends upon the root Node having no parent 58195b482a8SLen Brown * ie: acpi_gbl_root_node->parent_entry being set to NULL 58295b482a8SLen Brown */ 58395b482a8SLen Brown while (node) { 58495b482a8SLen Brown 58595b482a8SLen Brown /* Check to see if a handler exists */ 58695b482a8SLen Brown 58795b482a8SLen Brown handler_obj = NULL; 58895b482a8SLen Brown obj_desc = acpi_ns_get_attached_object(node); 58995b482a8SLen Brown if (obj_desc) { 59095b482a8SLen Brown 59195b482a8SLen Brown /* Can only be a handler if the object exists */ 59295b482a8SLen Brown 59395b482a8SLen Brown switch (node->type) { 59495b482a8SLen Brown case ACPI_TYPE_DEVICE: 59595b482a8SLen Brown 59695b482a8SLen Brown handler_obj = obj_desc->device.handler; 59795b482a8SLen Brown break; 59895b482a8SLen Brown 59995b482a8SLen Brown case ACPI_TYPE_PROCESSOR: 60095b482a8SLen Brown 60195b482a8SLen Brown handler_obj = obj_desc->processor.handler; 60295b482a8SLen Brown break; 60395b482a8SLen Brown 60495b482a8SLen Brown case ACPI_TYPE_THERMAL: 60595b482a8SLen Brown 60695b482a8SLen Brown handler_obj = obj_desc->thermal_zone.handler; 60795b482a8SLen Brown break; 60895b482a8SLen Brown 60995b482a8SLen Brown default: 61095b482a8SLen Brown /* Ignore other objects */ 61195b482a8SLen Brown break; 61295b482a8SLen Brown } 61395b482a8SLen Brown 61495b482a8SLen Brown while (handler_obj) { 61595b482a8SLen Brown 61695b482a8SLen Brown /* Is this handler of the correct type? */ 61795b482a8SLen Brown 61895b482a8SLen Brown if (handler_obj->address_space.space_id == 61995b482a8SLen Brown space_id) { 62095b482a8SLen Brown 62195b482a8SLen Brown /* Found correct handler */ 62295b482a8SLen Brown 62395b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, 62495b482a8SLen Brown "Found handler %p for region %p in obj %p\n", 62595b482a8SLen Brown handler_obj, 62695b482a8SLen Brown region_obj, 62795b482a8SLen Brown obj_desc)); 62895b482a8SLen Brown 62995b482a8SLen Brown status = 63095b482a8SLen Brown acpi_ev_attach_region(handler_obj, 63195b482a8SLen Brown region_obj, 63295b482a8SLen Brown acpi_ns_locked); 63395b482a8SLen Brown 63495b482a8SLen Brown /* 63595b482a8SLen Brown * Tell all users that this region is usable by running the _REG 63695b482a8SLen Brown * method 63795b482a8SLen Brown */ 63895b482a8SLen Brown if (acpi_ns_locked) { 63995b482a8SLen Brown status = 64095b482a8SLen Brown acpi_ut_release_mutex 64195b482a8SLen Brown (ACPI_MTX_NAMESPACE); 64295b482a8SLen Brown if (ACPI_FAILURE(status)) { 64395b482a8SLen Brown return_ACPI_STATUS 64495b482a8SLen Brown (status); 64595b482a8SLen Brown } 64695b482a8SLen Brown } 64795b482a8SLen Brown 64895b482a8SLen Brown status = 64995b482a8SLen Brown acpi_ev_execute_reg_method 65095b482a8SLen Brown (region_obj, 1); 65195b482a8SLen Brown 65295b482a8SLen Brown if (acpi_ns_locked) { 65395b482a8SLen Brown status = 65495b482a8SLen Brown acpi_ut_acquire_mutex 65595b482a8SLen Brown (ACPI_MTX_NAMESPACE); 65695b482a8SLen Brown if (ACPI_FAILURE(status)) { 65795b482a8SLen Brown return_ACPI_STATUS 65895b482a8SLen Brown (status); 65995b482a8SLen Brown } 66095b482a8SLen Brown } 66195b482a8SLen Brown 66295b482a8SLen Brown return_ACPI_STATUS(AE_OK); 66395b482a8SLen Brown } 66495b482a8SLen Brown 66595b482a8SLen Brown /* Try next handler in the list */ 66695b482a8SLen Brown 66795b482a8SLen Brown handler_obj = handler_obj->address_space.next; 66895b482a8SLen Brown } 66995b482a8SLen Brown } 67095b482a8SLen Brown 67195b482a8SLen Brown /* This node does not have the handler we need; Pop up one level */ 67295b482a8SLen Brown 67395b482a8SLen Brown node = acpi_ns_get_parent_node(node); 67495b482a8SLen Brown } 67595b482a8SLen Brown 67695b482a8SLen Brown /* If we get here, there is no handler for this region */ 67795b482a8SLen Brown 67895b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, 67995b482a8SLen Brown "No handler for RegionType %s(%X) (RegionObj %p)\n", 68095b482a8SLen Brown acpi_ut_get_region_name(space_id), space_id, 68195b482a8SLen Brown region_obj)); 68295b482a8SLen Brown 68395b482a8SLen Brown return_ACPI_STATUS(AE_NOT_EXIST); 68495b482a8SLen Brown } 685