xref: /openbmc/linux/drivers/acpi/acpica/evrgnini.c (revision e2f7a7772880458edff1b1cc5a988947229fac26)
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