/******************************************************************************1*2* Module Name: evrgnini- ACPI address_space (op_region) init3*4*****************************************************************************/56/*7* Copyright (C) 2000 - 2011, Intel Corp.8* All rights reserved.9*10* Redistribution and use in source and binary forms, with or without11* modification, are permitted provided that the following conditions12* are met:13* 1. Redistributions of source code must retain the above copyright14* notice, this list of conditions, and the following disclaimer,15* without modification.16* 2. Redistributions in binary form must reproduce at minimum a disclaimer17* substantially similar to the "NO WARRANTY" disclaimer below18* ("Disclaimer") and any redistribution must be conditioned upon19* including a substantially similar Disclaimer requirement for further20* binary redistribution.21* 3. Neither the names of the above-listed copyright holders nor the names22* of any contributors may be used to endorse or promote products derived23* from this software without specific prior written permission.24*25* Alternatively, this software may be distributed under the terms of the26* GNU General Public License ("GPL") version 2 as published by the Free27* Software Foundation.28*29* NO WARRANTY30* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS31* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT32* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR33* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT34* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL35* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS36* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)37* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,38* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING39* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE40* POSSIBILITY OF SUCH DAMAGES.41*/4243#include <acpi/acpi.h>44#include "accommon.h"45#include "acevents.h"46#include "acnamesp.h"4748#define _COMPONENT ACPI_EVENTS49ACPI_MODULE_NAME("evrgnini")5051/* Local prototypes */52static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node);5354/*******************************************************************************55*56* FUNCTION: acpi_ev_system_memory_region_setup57*58* PARAMETERS: Handle - Region we are interested in59* Function - Start or stop60* handler_context - Address space handler context61* region_context - Region specific context62*63* RETURN: Status64*65* DESCRIPTION: Setup a system_memory operation region66*67******************************************************************************/6869acpi_status70acpi_ev_system_memory_region_setup(acpi_handle handle,71u32 function,72void *handler_context, void **region_context)73{74union acpi_operand_object *region_desc =75(union acpi_operand_object *)handle;76struct acpi_mem_space_context *local_region_context;7778ACPI_FUNCTION_TRACE(ev_system_memory_region_setup);7980if (function == ACPI_REGION_DEACTIVATE) {81if (*region_context) {82local_region_context =83(struct acpi_mem_space_context *)*region_context;8485/* Delete a cached mapping if present */8687if (local_region_context->mapped_length) {88acpi_os_unmap_memory(local_region_context->89mapped_logical_address,90local_region_context->91mapped_length);92}93ACPI_FREE(local_region_context);94*region_context = NULL;95}96return_ACPI_STATUS(AE_OK);97}9899/* Create a new context */100101local_region_context =102ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_mem_space_context));103if (!(local_region_context)) {104return_ACPI_STATUS(AE_NO_MEMORY);105}106107/* Save the region length and address for use in the handler */108109local_region_context->length = region_desc->region.length;110local_region_context->address = region_desc->region.address;111112*region_context = local_region_context;113return_ACPI_STATUS(AE_OK);114}115116/*******************************************************************************117*118* FUNCTION: acpi_ev_io_space_region_setup119*120* PARAMETERS: Handle - Region we are interested in121* Function - Start or stop122* handler_context - Address space handler context123* region_context - Region specific context124*125* RETURN: Status126*127* DESCRIPTION: Setup a IO operation region128*129******************************************************************************/130131acpi_status132acpi_ev_io_space_region_setup(acpi_handle handle,133u32 function,134void *handler_context, void **region_context)135{136ACPI_FUNCTION_TRACE(ev_io_space_region_setup);137138if (function == ACPI_REGION_DEACTIVATE) {139*region_context = NULL;140} else {141*region_context = handler_context;142}143144return_ACPI_STATUS(AE_OK);145}146147/*******************************************************************************148*149* FUNCTION: acpi_ev_pci_config_region_setup150*151* PARAMETERS: Handle - Region we are interested in152* Function - Start or stop153* handler_context - Address space handler context154* region_context - Region specific context155*156* RETURN: Status157*158* DESCRIPTION: Setup a PCI_Config operation region159*160* MUTEX: Assumes namespace is not locked161*162******************************************************************************/163164acpi_status165acpi_ev_pci_config_region_setup(acpi_handle handle,166u32 function,167void *handler_context, void **region_context)168{169acpi_status status = AE_OK;170u64 pci_value;171struct acpi_pci_id *pci_id = *region_context;172union acpi_operand_object *handler_obj;173struct acpi_namespace_node *parent_node;174struct acpi_namespace_node *pci_root_node;175struct acpi_namespace_node *pci_device_node;176union acpi_operand_object *region_obj =177(union acpi_operand_object *)handle;178179ACPI_FUNCTION_TRACE(ev_pci_config_region_setup);180181handler_obj = region_obj->region.handler;182if (!handler_obj) {183/*184* No installed handler. This shouldn't happen because the dispatch185* routine checks before we get here, but we check again just in case.186*/187ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,188"Attempting to init a region %p, with no handler\n",189region_obj));190return_ACPI_STATUS(AE_NOT_EXIST);191}192193*region_context = NULL;194if (function == ACPI_REGION_DEACTIVATE) {195if (pci_id) {196ACPI_FREE(pci_id);197}198return_ACPI_STATUS(status);199}200201parent_node = region_obj->region.node->parent;202203/*204* Get the _SEG and _BBN values from the device upon which the handler205* is installed.206*207* We need to get the _SEG and _BBN objects relative to the PCI BUS device.208* This is the device the handler has been registered to handle.209*/210211/*212* If the address_space.Node is still pointing to the root, we need213* to scan upward for a PCI Root bridge and re-associate the op_region214* handlers with that device.215*/216if (handler_obj->address_space.node == acpi_gbl_root_node) {217218/* Start search from the parent object */219220pci_root_node = parent_node;221while (pci_root_node != acpi_gbl_root_node) {222223/* Get the _HID/_CID in order to detect a root_bridge */224225if (acpi_ev_is_pci_root_bridge(pci_root_node)) {226227/* Install a handler for this PCI root bridge */228229status =230acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL);231if (ACPI_FAILURE(status)) {232if (status == AE_SAME_HANDLER) {233/*234* It is OK if the handler is already installed on the235* root bridge. Still need to return a context object236* for the new PCI_Config operation region, however.237*/238status = AE_OK;239} else {240ACPI_EXCEPTION((AE_INFO, status,241"Could not install PciConfig handler "242"for Root Bridge %4.4s",243acpi_ut_get_node_name244(pci_root_node)));245}246}247break;248}249250pci_root_node = pci_root_node->parent;251}252253/* PCI root bridge not found, use namespace root node */254} else {255pci_root_node = handler_obj->address_space.node;256}257258/*259* If this region is now initialized, we are done.260* (install_address_space_handler could have initialized it)261*/262if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) {263return_ACPI_STATUS(AE_OK);264}265266/* Region is still not initialized. Create a new context */267268pci_id = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pci_id));269if (!pci_id) {270return_ACPI_STATUS(AE_NO_MEMORY);271}272273/*274* For PCI_Config space access, we need the segment, bus, device and275* function numbers. Acquire them here.276*277* Find the parent device object. (This allows the operation region to be278* within a subscope under the device, such as a control method.)279*/280pci_device_node = region_obj->region.node;281while (pci_device_node && (pci_device_node->type != ACPI_TYPE_DEVICE)) {282pci_device_node = pci_device_node->parent;283}284285if (!pci_device_node) {286ACPI_FREE(pci_id);287return_ACPI_STATUS(AE_AML_OPERAND_TYPE);288}289290/*291* Get the PCI device and function numbers from the _ADR object292* contained in the parent's scope.293*/294status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR,295pci_device_node, &pci_value);296297/*298* The default is zero, and since the allocation above zeroed the data,299* just do nothing on failure.300*/301if (ACPI_SUCCESS(status)) {302pci_id->device = ACPI_HIWORD(ACPI_LODWORD(pci_value));303pci_id->function = ACPI_LOWORD(ACPI_LODWORD(pci_value));304}305306/* The PCI segment number comes from the _SEG method */307308status = acpi_ut_evaluate_numeric_object(METHOD_NAME__SEG,309pci_root_node, &pci_value);310if (ACPI_SUCCESS(status)) {311pci_id->segment = ACPI_LOWORD(pci_value);312}313314/* The PCI bus number comes from the _BBN method */315316status = acpi_ut_evaluate_numeric_object(METHOD_NAME__BBN,317pci_root_node, &pci_value);318if (ACPI_SUCCESS(status)) {319pci_id->bus = ACPI_LOWORD(pci_value);320}321322/* Complete/update the PCI ID for this device */323324status =325acpi_hw_derive_pci_id(pci_id, pci_root_node,326region_obj->region.node);327if (ACPI_FAILURE(status)) {328ACPI_FREE(pci_id);329return_ACPI_STATUS(status);330}331332*region_context = pci_id;333return_ACPI_STATUS(AE_OK);334}335336/*******************************************************************************337*338* FUNCTION: acpi_ev_is_pci_root_bridge339*340* PARAMETERS: Node - Device node being examined341*342* RETURN: TRUE if device is a PCI/PCI-Express Root Bridge343*344* DESCRIPTION: Determine if the input device represents a PCI Root Bridge by345* examining the _HID and _CID for the device.346*347******************************************************************************/348349static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node)350{351acpi_status status;352struct acpica_device_id *hid;353struct acpica_device_id_list *cid;354u32 i;355u8 match;356357/* Get the _HID and check for a PCI Root Bridge */358359status = acpi_ut_execute_HID(node, &hid);360if (ACPI_FAILURE(status)) {361return (FALSE);362}363364match = acpi_ut_is_pci_root_bridge(hid->string);365ACPI_FREE(hid);366367if (match) {368return (TRUE);369}370371/* The _HID did not match. Get the _CID and check for a PCI Root Bridge */372373status = acpi_ut_execute_CID(node, &cid);374if (ACPI_FAILURE(status)) {375return (FALSE);376}377378/* Check all _CIDs in the returned list */379380for (i = 0; i < cid->count; i++) {381if (acpi_ut_is_pci_root_bridge(cid->ids[i].string)) {382ACPI_FREE(cid);383return (TRUE);384}385}386387ACPI_FREE(cid);388return (FALSE);389}390391/*******************************************************************************392*393* FUNCTION: acpi_ev_pci_bar_region_setup394*395* PARAMETERS: Handle - Region we are interested in396* Function - Start or stop397* handler_context - Address space handler context398* region_context - Region specific context399*400* RETURN: Status401*402* DESCRIPTION: Setup a pci_bAR operation region403*404* MUTEX: Assumes namespace is not locked405*406******************************************************************************/407408acpi_status409acpi_ev_pci_bar_region_setup(acpi_handle handle,410u32 function,411void *handler_context, void **region_context)412{413ACPI_FUNCTION_TRACE(ev_pci_bar_region_setup);414415return_ACPI_STATUS(AE_OK);416}417418/*******************************************************************************419*420* FUNCTION: acpi_ev_cmos_region_setup421*422* PARAMETERS: Handle - Region we are interested in423* Function - Start or stop424* handler_context - Address space handler context425* region_context - Region specific context426*427* RETURN: Status428*429* DESCRIPTION: Setup a CMOS operation region430*431* MUTEX: Assumes namespace is not locked432*433******************************************************************************/434435acpi_status436acpi_ev_cmos_region_setup(acpi_handle handle,437u32 function,438void *handler_context, void **region_context)439{440ACPI_FUNCTION_TRACE(ev_cmos_region_setup);441442return_ACPI_STATUS(AE_OK);443}444445/*******************************************************************************446*447* FUNCTION: acpi_ev_default_region_setup448*449* PARAMETERS: Handle - Region we are interested in450* Function - Start or stop451* handler_context - Address space handler context452* region_context - Region specific context453*454* RETURN: Status455*456* DESCRIPTION: Default region initialization457*458******************************************************************************/459460acpi_status461acpi_ev_default_region_setup(acpi_handle handle,462u32 function,463void *handler_context, void **region_context)464{465ACPI_FUNCTION_TRACE(ev_default_region_setup);466467if (function == ACPI_REGION_DEACTIVATE) {468*region_context = NULL;469} else {470*region_context = handler_context;471}472473return_ACPI_STATUS(AE_OK);474}475476/*******************************************************************************477*478* FUNCTION: acpi_ev_initialize_region479*480* PARAMETERS: region_obj - Region we are initializing481* acpi_ns_locked - Is namespace locked?482*483* RETURN: Status484*485* DESCRIPTION: Initializes the region, finds any _REG methods and saves them486* for execution at a later time487*488* Get the appropriate address space handler for a newly489* created region.490*491* This also performs address space specific initialization. For492* example, PCI regions must have an _ADR object that contains493* a PCI address in the scope of the definition. This address is494* required to perform an access to PCI config space.495*496* MUTEX: Interpreter should be unlocked, because we may run the _REG497* method for this region.498*499******************************************************************************/500501acpi_status502acpi_ev_initialize_region(union acpi_operand_object *region_obj,503u8 acpi_ns_locked)504{505union acpi_operand_object *handler_obj;506union acpi_operand_object *obj_desc;507acpi_adr_space_type space_id;508struct acpi_namespace_node *node;509acpi_status status;510struct acpi_namespace_node *method_node;511acpi_name *reg_name_ptr = (acpi_name *) METHOD_NAME__REG;512union acpi_operand_object *region_obj2;513514ACPI_FUNCTION_TRACE_U32(ev_initialize_region, acpi_ns_locked);515516if (!region_obj) {517return_ACPI_STATUS(AE_BAD_PARAMETER);518}519520if (region_obj->common.flags & AOPOBJ_OBJECT_INITIALIZED) {521return_ACPI_STATUS(AE_OK);522}523524region_obj2 = acpi_ns_get_secondary_object(region_obj);525if (!region_obj2) {526return_ACPI_STATUS(AE_NOT_EXIST);527}528529node = region_obj->region.node->parent;530space_id = region_obj->region.space_id;531532/* Setup defaults */533534region_obj->region.handler = NULL;535region_obj2->extra.method_REG = NULL;536region_obj->common.flags &= ~(AOPOBJ_SETUP_COMPLETE);537region_obj->common.flags |= AOPOBJ_OBJECT_INITIALIZED;538539/* Find any "_REG" method associated with this region definition */540541status =542acpi_ns_search_one_scope(*reg_name_ptr, node, ACPI_TYPE_METHOD,543&method_node);544if (ACPI_SUCCESS(status)) {545/*546* The _REG method is optional and there can be only one per region547* definition. This will be executed when the handler is attached548* or removed549*/550region_obj2->extra.method_REG = method_node;551}552553/*554* The following loop depends upon the root Node having no parent555* ie: acpi_gbl_root_node->parent_entry being set to NULL556*/557while (node) {558559/* Check to see if a handler exists */560561handler_obj = NULL;562obj_desc = acpi_ns_get_attached_object(node);563if (obj_desc) {564565/* Can only be a handler if the object exists */566567switch (node->type) {568case ACPI_TYPE_DEVICE:569570handler_obj = obj_desc->device.handler;571break;572573case ACPI_TYPE_PROCESSOR:574575handler_obj = obj_desc->processor.handler;576break;577578case ACPI_TYPE_THERMAL:579580handler_obj = obj_desc->thermal_zone.handler;581break;582583case ACPI_TYPE_METHOD:584/*585* If we are executing module level code, the original586* Node's object was replaced by this Method object and we587* saved the handler in the method object.588*589* See acpi_ns_exec_module_code590*/591if (obj_desc->method.592info_flags & ACPI_METHOD_MODULE_LEVEL) {593handler_obj =594obj_desc->method.dispatch.handler;595}596break;597598default:599/* Ignore other objects */600break;601}602603while (handler_obj) {604605/* Is this handler of the correct type? */606607if (handler_obj->address_space.space_id ==608space_id) {609610/* Found correct handler */611612ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,613"Found handler %p for region %p in obj %p\n",614handler_obj,615region_obj,616obj_desc));617618status =619acpi_ev_attach_region(handler_obj,620region_obj,621acpi_ns_locked);622623/*624* Tell all users that this region is usable by625* running the _REG method626*/627if (acpi_ns_locked) {628status =629acpi_ut_release_mutex630(ACPI_MTX_NAMESPACE);631if (ACPI_FAILURE(status)) {632return_ACPI_STATUS633(status);634}635}636637status =638acpi_ev_execute_reg_method639(region_obj, ACPI_REG_CONNECT);640641if (acpi_ns_locked) {642status =643acpi_ut_acquire_mutex644(ACPI_MTX_NAMESPACE);645if (ACPI_FAILURE(status)) {646return_ACPI_STATUS647(status);648}649}650651return_ACPI_STATUS(AE_OK);652}653654/* Try next handler in the list */655656handler_obj = handler_obj->address_space.next;657}658}659660/* This node does not have the handler we need; Pop up one level */661662node = node->parent;663}664665/* If we get here, there is no handler for this region */666667ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,668"No handler for RegionType %s(%X) (RegionObj %p)\n",669acpi_ut_get_region_name(space_id), space_id,670region_obj));671672return_ACPI_STATUS(AE_NOT_EXIST);673}674675676