xref: /openbmc/linux/drivers/acpi/acpica/evrgnini.c (revision 8b1cafdcb4b75c5027c52f1e82b47ebe727ad7ed)
195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
295b482a8SLen Brown /******************************************************************************
395b482a8SLen Brown  *
495b482a8SLen Brown  * Module Name: evrgnini- ACPI address_space (op_region) init
595b482a8SLen Brown  *
6da6f8320SBob Moore  * Copyright (C) 2000 - 2018, Intel Corp.
795b482a8SLen Brown  *
895857638SErik Schmauss  *****************************************************************************/
995b482a8SLen Brown 
1095b482a8SLen Brown #include <acpi/acpi.h>
11e2f7a777SLen Brown #include "accommon.h"
12e2f7a777SLen Brown #include "acevents.h"
13e2f7a777SLen Brown #include "acnamesp.h"
148633db6bSLv Zheng #include "acinterp.h"
1595b482a8SLen Brown 
1695b482a8SLen Brown #define _COMPONENT          ACPI_EVENTS
1795b482a8SLen Brown ACPI_MODULE_NAME("evrgnini")
1895b482a8SLen Brown 
1995b482a8SLen Brown /*******************************************************************************
2095b482a8SLen Brown  *
2195b482a8SLen Brown  * FUNCTION:    acpi_ev_system_memory_region_setup
2295b482a8SLen Brown  *
23ba494beeSBob Moore  * PARAMETERS:  handle              - Region we are interested in
24ba494beeSBob Moore  *              function            - Start or stop
2595b482a8SLen Brown  *              handler_context     - Address space handler context
2695b482a8SLen Brown  *              region_context      - Region specific context
2795b482a8SLen Brown  *
2895b482a8SLen Brown  * RETURN:      Status
2995b482a8SLen Brown  *
3095b482a8SLen Brown  * DESCRIPTION: Setup a system_memory operation region
3195b482a8SLen Brown  *
3295b482a8SLen Brown  ******************************************************************************/
3395b482a8SLen Brown acpi_status
3495b482a8SLen Brown acpi_ev_system_memory_region_setup(acpi_handle handle,
3595b482a8SLen Brown 				   u32 function,
3695b482a8SLen Brown 				   void *handler_context, void **region_context)
3795b482a8SLen Brown {
3895b482a8SLen Brown 	union acpi_operand_object *region_desc =
3995b482a8SLen Brown 	    (union acpi_operand_object *)handle;
4095b482a8SLen Brown 	struct acpi_mem_space_context *local_region_context;
4195b482a8SLen Brown 
4295b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ev_system_memory_region_setup);
4395b482a8SLen Brown 
4495b482a8SLen Brown 	if (function == ACPI_REGION_DEACTIVATE) {
4595b482a8SLen Brown 		if (*region_context) {
4695b482a8SLen Brown 			local_region_context =
4795b482a8SLen Brown 			    (struct acpi_mem_space_context *)*region_context;
4895b482a8SLen Brown 
4995b482a8SLen Brown 			/* Delete a cached mapping if present */
5095b482a8SLen Brown 
5195b482a8SLen Brown 			if (local_region_context->mapped_length) {
5295b482a8SLen Brown 				acpi_os_unmap_memory(local_region_context->
5395b482a8SLen Brown 						     mapped_logical_address,
5495b482a8SLen Brown 						     local_region_context->
5595b482a8SLen Brown 						     mapped_length);
5695b482a8SLen Brown 			}
5795b482a8SLen Brown 			ACPI_FREE(local_region_context);
5895b482a8SLen Brown 			*region_context = NULL;
5995b482a8SLen Brown 		}
6095b482a8SLen Brown 		return_ACPI_STATUS(AE_OK);
6195b482a8SLen Brown 	}
6295b482a8SLen Brown 
6395b482a8SLen Brown 	/* Create a new context */
6495b482a8SLen Brown 
6595b482a8SLen Brown 	local_region_context =
6695b482a8SLen Brown 	    ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_mem_space_context));
6795b482a8SLen Brown 	if (!(local_region_context)) {
6895b482a8SLen Brown 		return_ACPI_STATUS(AE_NO_MEMORY);
6995b482a8SLen Brown 	}
7095b482a8SLen Brown 
7195b482a8SLen Brown 	/* Save the region length and address for use in the handler */
7295b482a8SLen Brown 
7395b482a8SLen Brown 	local_region_context->length = region_desc->region.length;
7495b482a8SLen Brown 	local_region_context->address = region_desc->region.address;
7595b482a8SLen Brown 
7695b482a8SLen Brown 	*region_context = local_region_context;
7795b482a8SLen Brown 	return_ACPI_STATUS(AE_OK);
7895b482a8SLen Brown }
7995b482a8SLen Brown 
8095b482a8SLen Brown /*******************************************************************************
8195b482a8SLen Brown  *
8295b482a8SLen Brown  * FUNCTION:    acpi_ev_io_space_region_setup
8395b482a8SLen Brown  *
84ba494beeSBob Moore  * PARAMETERS:  handle              - Region we are interested in
85ba494beeSBob Moore  *              function            - Start or stop
8695b482a8SLen Brown  *              handler_context     - Address space handler context
8795b482a8SLen Brown  *              region_context      - Region specific context
8895b482a8SLen Brown  *
8995b482a8SLen Brown  * RETURN:      Status
9095b482a8SLen Brown  *
9195b482a8SLen Brown  * DESCRIPTION: Setup a IO operation region
9295b482a8SLen Brown  *
9395b482a8SLen Brown  ******************************************************************************/
9495b482a8SLen Brown 
9595b482a8SLen Brown acpi_status
9695b482a8SLen Brown acpi_ev_io_space_region_setup(acpi_handle handle,
9795b482a8SLen Brown 			      u32 function,
9895b482a8SLen Brown 			      void *handler_context, void **region_context)
9995b482a8SLen Brown {
10095b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ev_io_space_region_setup);
10195b482a8SLen Brown 
10295b482a8SLen Brown 	if (function == ACPI_REGION_DEACTIVATE) {
10395b482a8SLen Brown 		*region_context = NULL;
10495b482a8SLen Brown 	} else {
10595b482a8SLen Brown 		*region_context = handler_context;
10695b482a8SLen Brown 	}
10795b482a8SLen Brown 
10895b482a8SLen Brown 	return_ACPI_STATUS(AE_OK);
10995b482a8SLen Brown }
11095b482a8SLen Brown 
11195b482a8SLen Brown /*******************************************************************************
11295b482a8SLen Brown  *
11395b482a8SLen Brown  * FUNCTION:    acpi_ev_pci_config_region_setup
11495b482a8SLen Brown  *
115ba494beeSBob Moore  * PARAMETERS:  handle              - Region we are interested in
116ba494beeSBob Moore  *              function            - Start or stop
11795b482a8SLen Brown  *              handler_context     - Address space handler context
11895b482a8SLen Brown  *              region_context      - Region specific context
11995b482a8SLen Brown  *
12095b482a8SLen Brown  * RETURN:      Status
12195b482a8SLen Brown  *
12295b482a8SLen Brown  * DESCRIPTION: Setup a PCI_Config operation region
12395b482a8SLen Brown  *
12495b482a8SLen Brown  * MUTEX:       Assumes namespace is not locked
12595b482a8SLen Brown  *
12695b482a8SLen Brown  ******************************************************************************/
12795b482a8SLen Brown 
12895b482a8SLen Brown acpi_status
12995b482a8SLen Brown acpi_ev_pci_config_region_setup(acpi_handle handle,
13095b482a8SLen Brown 				u32 function,
13195b482a8SLen Brown 				void *handler_context, void **region_context)
13295b482a8SLen Brown {
13395b482a8SLen Brown 	acpi_status status = AE_OK;
1345df7e6cbSBob Moore 	u64 pci_value;
13595b482a8SLen Brown 	struct acpi_pci_id *pci_id = *region_context;
13695b482a8SLen Brown 	union acpi_operand_object *handler_obj;
13795b482a8SLen Brown 	struct acpi_namespace_node *parent_node;
13895b482a8SLen Brown 	struct acpi_namespace_node *pci_root_node;
13995b482a8SLen Brown 	struct acpi_namespace_node *pci_device_node;
14095b482a8SLen Brown 	union acpi_operand_object *region_obj =
14195b482a8SLen Brown 	    (union acpi_operand_object *)handle;
14295b482a8SLen Brown 
14395b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ev_pci_config_region_setup);
14495b482a8SLen Brown 
14595b482a8SLen Brown 	handler_obj = region_obj->region.handler;
14695b482a8SLen Brown 	if (!handler_obj) {
14795b482a8SLen Brown 		/*
14895b482a8SLen Brown 		 * No installed handler. This shouldn't happen because the dispatch
14995b482a8SLen Brown 		 * routine checks before we get here, but we check again just in case.
15095b482a8SLen Brown 		 */
15195b482a8SLen Brown 		ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
15295b482a8SLen Brown 				  "Attempting to init a region %p, with no handler\n",
15395b482a8SLen Brown 				  region_obj));
15495b482a8SLen Brown 		return_ACPI_STATUS(AE_NOT_EXIST);
15595b482a8SLen Brown 	}
15695b482a8SLen Brown 
15795b482a8SLen Brown 	*region_context = NULL;
15895b482a8SLen Brown 	if (function == ACPI_REGION_DEACTIVATE) {
15995b482a8SLen Brown 		if (pci_id) {
16095b482a8SLen Brown 			ACPI_FREE(pci_id);
16195b482a8SLen Brown 		}
16295b482a8SLen Brown 		return_ACPI_STATUS(status);
16395b482a8SLen Brown 	}
16495b482a8SLen Brown 
165c45b5c09SAlexey Starikovskiy 	parent_node = region_obj->region.node->parent;
16695b482a8SLen Brown 
16795b482a8SLen Brown 	/*
16895b482a8SLen Brown 	 * Get the _SEG and _BBN values from the device upon which the handler
16995b482a8SLen Brown 	 * is installed.
17095b482a8SLen Brown 	 *
17195b482a8SLen Brown 	 * We need to get the _SEG and _BBN objects relative to the PCI BUS device.
17295b482a8SLen Brown 	 * This is the device the handler has been registered to handle.
17395b482a8SLen Brown 	 */
17495b482a8SLen Brown 
17595b482a8SLen Brown 	/*
17695b482a8SLen Brown 	 * If the address_space.Node is still pointing to the root, we need
17795b482a8SLen Brown 	 * to scan upward for a PCI Root bridge and re-associate the op_region
17895b482a8SLen Brown 	 * handlers with that device.
17995b482a8SLen Brown 	 */
18095b482a8SLen Brown 	if (handler_obj->address_space.node == acpi_gbl_root_node) {
18195b482a8SLen Brown 
18295b482a8SLen Brown 		/* Start search from the parent object */
18395b482a8SLen Brown 
18495b482a8SLen Brown 		pci_root_node = parent_node;
18595b482a8SLen Brown 		while (pci_root_node != acpi_gbl_root_node) {
18695b482a8SLen Brown 
18795b482a8SLen Brown 			/* Get the _HID/_CID in order to detect a root_bridge */
18895b482a8SLen Brown 
18995b482a8SLen Brown 			if (acpi_ev_is_pci_root_bridge(pci_root_node)) {
19095b482a8SLen Brown 
19195b482a8SLen Brown 				/* Install a handler for this PCI root bridge */
19295b482a8SLen Brown 
1931f86e8c1SLv Zheng 				status = acpi_install_address_space_handler((acpi_handle)pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL);
19495b482a8SLen Brown 				if (ACPI_FAILURE(status)) {
19595b482a8SLen Brown 					if (status == AE_SAME_HANDLER) {
19695b482a8SLen Brown 						/*
19795b482a8SLen Brown 						 * It is OK if the handler is already installed on the
19895b482a8SLen Brown 						 * root bridge. Still need to return a context object
19995b482a8SLen Brown 						 * for the new PCI_Config operation region, however.
20095b482a8SLen Brown 						 */
20195b482a8SLen Brown 						status = AE_OK;
20295b482a8SLen Brown 					} else {
20395b482a8SLen Brown 						ACPI_EXCEPTION((AE_INFO, status,
204d4913dc6SBob Moore 								"Could not install PciConfig handler "
205d4913dc6SBob Moore 								"for Root Bridge %4.4s",
20695b482a8SLen Brown 								acpi_ut_get_node_name
20795b482a8SLen Brown 								(pci_root_node)));
20895b482a8SLen Brown 					}
20995b482a8SLen Brown 				}
21095b482a8SLen Brown 				break;
21195b482a8SLen Brown 			}
21295b482a8SLen Brown 
213c45b5c09SAlexey Starikovskiy 			pci_root_node = pci_root_node->parent;
21495b482a8SLen Brown 		}
21595b482a8SLen Brown 
21695b482a8SLen Brown 		/* PCI root bridge not found, use namespace root node */
21795b482a8SLen Brown 	} else {
21895b482a8SLen Brown 		pci_root_node = handler_obj->address_space.node;
21995b482a8SLen Brown 	}
22095b482a8SLen Brown 
22195b482a8SLen Brown 	/*
22295b482a8SLen Brown 	 * If this region is now initialized, we are done.
22395b482a8SLen Brown 	 * (install_address_space_handler could have initialized it)
22495b482a8SLen Brown 	 */
22595b482a8SLen Brown 	if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) {
22695b482a8SLen Brown 		return_ACPI_STATUS(AE_OK);
22795b482a8SLen Brown 	}
22895b482a8SLen Brown 
22995b482a8SLen Brown 	/* Region is still not initialized. Create a new context */
23095b482a8SLen Brown 
23195b482a8SLen Brown 	pci_id = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pci_id));
23295b482a8SLen Brown 	if (!pci_id) {
23395b482a8SLen Brown 		return_ACPI_STATUS(AE_NO_MEMORY);
23495b482a8SLen Brown 	}
23595b482a8SLen Brown 
23695b482a8SLen Brown 	/*
23795b482a8SLen Brown 	 * For PCI_Config space access, we need the segment, bus, device and
23895b482a8SLen Brown 	 * function numbers. Acquire them here.
23995b482a8SLen Brown 	 *
24095b482a8SLen Brown 	 * Find the parent device object. (This allows the operation region to be
24195b482a8SLen Brown 	 * within a subscope under the device, such as a control method.)
24295b482a8SLen Brown 	 */
24395b482a8SLen Brown 	pci_device_node = region_obj->region.node;
24495b482a8SLen Brown 	while (pci_device_node && (pci_device_node->type != ACPI_TYPE_DEVICE)) {
245c45b5c09SAlexey Starikovskiy 		pci_device_node = pci_device_node->parent;
24695b482a8SLen Brown 	}
24795b482a8SLen Brown 
24895b482a8SLen Brown 	if (!pci_device_node) {
24995b482a8SLen Brown 		ACPI_FREE(pci_id);
25095b482a8SLen Brown 		return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
25195b482a8SLen Brown 	}
25295b482a8SLen Brown 
25395b482a8SLen Brown 	/*
25495abccb5SBob Moore 	 * Get the PCI device and function numbers from the _ADR object
25595abccb5SBob Moore 	 * contained in the parent's scope.
25695b482a8SLen Brown 	 */
257d4913dc6SBob Moore 	status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR,
258d4913dc6SBob Moore 						 pci_device_node, &pci_value);
25995b482a8SLen Brown 
26095b482a8SLen Brown 	/*
26195b482a8SLen Brown 	 * The default is zero, and since the allocation above zeroed the data,
26295b482a8SLen Brown 	 * just do nothing on failure.
26395b482a8SLen Brown 	 */
26495b482a8SLen Brown 	if (ACPI_SUCCESS(status)) {
26595b482a8SLen Brown 		pci_id->device = ACPI_HIWORD(ACPI_LODWORD(pci_value));
26695b482a8SLen Brown 		pci_id->function = ACPI_LOWORD(ACPI_LODWORD(pci_value));
26795b482a8SLen Brown 	}
26895b482a8SLen Brown 
26995b482a8SLen Brown 	/* The PCI segment number comes from the _SEG method */
27095b482a8SLen Brown 
271d4913dc6SBob Moore 	status = acpi_ut_evaluate_numeric_object(METHOD_NAME__SEG,
272d4913dc6SBob Moore 						 pci_root_node, &pci_value);
27395b482a8SLen Brown 	if (ACPI_SUCCESS(status)) {
27495b482a8SLen Brown 		pci_id->segment = ACPI_LOWORD(pci_value);
27595b482a8SLen Brown 	}
27695b482a8SLen Brown 
27795b482a8SLen Brown 	/* The PCI bus number comes from the _BBN method */
27895b482a8SLen Brown 
279d4913dc6SBob Moore 	status = acpi_ut_evaluate_numeric_object(METHOD_NAME__BBN,
280d4913dc6SBob Moore 						 pci_root_node, &pci_value);
28195b482a8SLen Brown 	if (ACPI_SUCCESS(status)) {
28295b482a8SLen Brown 		pci_id->bus = ACPI_LOWORD(pci_value);
28395b482a8SLen Brown 	}
28495b482a8SLen Brown 
28595abccb5SBob Moore 	/* Complete/update the PCI ID for this device */
28695b482a8SLen Brown 
28795abccb5SBob Moore 	status =
28895abccb5SBob Moore 	    acpi_hw_derive_pci_id(pci_id, pci_root_node,
28995abccb5SBob Moore 				  region_obj->region.node);
29095abccb5SBob Moore 	if (ACPI_FAILURE(status)) {
29195abccb5SBob Moore 		ACPI_FREE(pci_id);
29295abccb5SBob Moore 		return_ACPI_STATUS(status);
29395abccb5SBob Moore 	}
29495b482a8SLen Brown 
29595b482a8SLen Brown 	*region_context = pci_id;
29695b482a8SLen Brown 	return_ACPI_STATUS(AE_OK);
29795b482a8SLen Brown }
29895b482a8SLen Brown 
29995b482a8SLen Brown /*******************************************************************************
30095b482a8SLen Brown  *
30195b482a8SLen Brown  * FUNCTION:    acpi_ev_is_pci_root_bridge
30295b482a8SLen Brown  *
303ba494beeSBob Moore  * PARAMETERS:  node            - Device node being examined
30495b482a8SLen Brown  *
30595b482a8SLen Brown  * RETURN:      TRUE if device is a PCI/PCI-Express Root Bridge
30695b482a8SLen Brown  *
30795b482a8SLen Brown  * DESCRIPTION: Determine if the input device represents a PCI Root Bridge by
30895b482a8SLen Brown  *              examining the _HID and _CID for the device.
30995b482a8SLen Brown  *
31095b482a8SLen Brown  ******************************************************************************/
31195b482a8SLen Brown 
312*8b1cafdcSBob Moore u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node)
31395b482a8SLen Brown {
31495b482a8SLen Brown 	acpi_status status;
31578e25fefSLv Zheng 	struct acpi_pnp_device_id *hid;
31678e25fefSLv Zheng 	struct acpi_pnp_device_id_list *cid;
31795b482a8SLen Brown 	u32 i;
31815b8dd53SBob Moore 	u8 match;
31995b482a8SLen Brown 
32095b482a8SLen Brown 	/* Get the _HID and check for a PCI Root Bridge */
32195b482a8SLen Brown 
32295b482a8SLen Brown 	status = acpi_ut_execute_HID(node, &hid);
32395b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
32495b482a8SLen Brown 		return (FALSE);
32595b482a8SLen Brown 	}
32695b482a8SLen Brown 
32715b8dd53SBob Moore 	match = acpi_ut_is_pci_root_bridge(hid->string);
32815b8dd53SBob Moore 	ACPI_FREE(hid);
32915b8dd53SBob Moore 
33015b8dd53SBob Moore 	if (match) {
33195b482a8SLen Brown 		return (TRUE);
33295b482a8SLen Brown 	}
33395b482a8SLen Brown 
33495b482a8SLen Brown 	/* The _HID did not match. Get the _CID and check for a PCI Root Bridge */
33595b482a8SLen Brown 
33695b482a8SLen Brown 	status = acpi_ut_execute_CID(node, &cid);
33795b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
33895b482a8SLen Brown 		return (FALSE);
33995b482a8SLen Brown 	}
34095b482a8SLen Brown 
34195b482a8SLen Brown 	/* Check all _CIDs in the returned list */
34295b482a8SLen Brown 
34395b482a8SLen Brown 	for (i = 0; i < cid->count; i++) {
34415b8dd53SBob Moore 		if (acpi_ut_is_pci_root_bridge(cid->ids[i].string)) {
34595b482a8SLen Brown 			ACPI_FREE(cid);
34695b482a8SLen Brown 			return (TRUE);
34795b482a8SLen Brown 		}
34895b482a8SLen Brown 	}
34995b482a8SLen Brown 
35095b482a8SLen Brown 	ACPI_FREE(cid);
35195b482a8SLen Brown 	return (FALSE);
35295b482a8SLen Brown }
35395b482a8SLen Brown 
35495b482a8SLen Brown /*******************************************************************************
35595b482a8SLen Brown  *
35695b482a8SLen Brown  * FUNCTION:    acpi_ev_pci_bar_region_setup
35795b482a8SLen Brown  *
358ba494beeSBob Moore  * PARAMETERS:  handle              - Region we are interested in
359ba494beeSBob Moore  *              function            - Start or stop
36095b482a8SLen Brown  *              handler_context     - Address space handler context
36195b482a8SLen Brown  *              region_context      - Region specific context
36295b482a8SLen Brown  *
36395b482a8SLen Brown  * RETURN:      Status
36495b482a8SLen Brown  *
365ba494beeSBob Moore  * DESCRIPTION: Setup a pci_BAR operation region
36695b482a8SLen Brown  *
36795b482a8SLen Brown  * MUTEX:       Assumes namespace is not locked
36895b482a8SLen Brown  *
36995b482a8SLen Brown  ******************************************************************************/
37095b482a8SLen Brown 
37195b482a8SLen Brown acpi_status
37295b482a8SLen Brown acpi_ev_pci_bar_region_setup(acpi_handle handle,
37395b482a8SLen Brown 			     u32 function,
37495b482a8SLen Brown 			     void *handler_context, void **region_context)
37595b482a8SLen Brown {
37695b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ev_pci_bar_region_setup);
37795b482a8SLen Brown 
37895b482a8SLen Brown 	return_ACPI_STATUS(AE_OK);
37995b482a8SLen Brown }
38095b482a8SLen Brown 
38195b482a8SLen Brown /*******************************************************************************
38295b482a8SLen Brown  *
38395b482a8SLen Brown  * FUNCTION:    acpi_ev_cmos_region_setup
38495b482a8SLen Brown  *
385ba494beeSBob Moore  * PARAMETERS:  handle              - Region we are interested in
386ba494beeSBob Moore  *              function            - Start or stop
38795b482a8SLen Brown  *              handler_context     - Address space handler context
38895b482a8SLen Brown  *              region_context      - Region specific context
38995b482a8SLen Brown  *
39095b482a8SLen Brown  * RETURN:      Status
39195b482a8SLen Brown  *
39295b482a8SLen Brown  * DESCRIPTION: Setup a CMOS operation region
39395b482a8SLen Brown  *
39495b482a8SLen Brown  * MUTEX:       Assumes namespace is not locked
39595b482a8SLen Brown  *
39695b482a8SLen Brown  ******************************************************************************/
39795b482a8SLen Brown 
39895b482a8SLen Brown acpi_status
39995b482a8SLen Brown acpi_ev_cmos_region_setup(acpi_handle handle,
40095b482a8SLen Brown 			  u32 function,
40195b482a8SLen Brown 			  void *handler_context, void **region_context)
40295b482a8SLen Brown {
40395b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ev_cmos_region_setup);
40495b482a8SLen Brown 
40595b482a8SLen Brown 	return_ACPI_STATUS(AE_OK);
40695b482a8SLen Brown }
40795b482a8SLen Brown 
40895b482a8SLen Brown /*******************************************************************************
40995b482a8SLen Brown  *
41095b482a8SLen Brown  * FUNCTION:    acpi_ev_default_region_setup
41195b482a8SLen Brown  *
412ba494beeSBob Moore  * PARAMETERS:  handle              - Region we are interested in
413ba494beeSBob Moore  *              function            - Start or stop
41495b482a8SLen Brown  *              handler_context     - Address space handler context
41595b482a8SLen Brown  *              region_context      - Region specific context
41695b482a8SLen Brown  *
41795b482a8SLen Brown  * RETURN:      Status
41895b482a8SLen Brown  *
41995b482a8SLen Brown  * DESCRIPTION: Default region initialization
42095b482a8SLen Brown  *
42195b482a8SLen Brown  ******************************************************************************/
42295b482a8SLen Brown 
42395b482a8SLen Brown acpi_status
42495b482a8SLen Brown acpi_ev_default_region_setup(acpi_handle handle,
42595b482a8SLen Brown 			     u32 function,
42695b482a8SLen Brown 			     void *handler_context, void **region_context)
42795b482a8SLen Brown {
42895b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ev_default_region_setup);
42995b482a8SLen Brown 
43095b482a8SLen Brown 	if (function == ACPI_REGION_DEACTIVATE) {
43195b482a8SLen Brown 		*region_context = NULL;
43295b482a8SLen Brown 	} else {
43395b482a8SLen Brown 		*region_context = handler_context;
43495b482a8SLen Brown 	}
43595b482a8SLen Brown 
43695b482a8SLen Brown 	return_ACPI_STATUS(AE_OK);
43795b482a8SLen Brown }
43895b482a8SLen Brown 
43995b482a8SLen Brown /*******************************************************************************
44095b482a8SLen Brown  *
44195b482a8SLen Brown  * FUNCTION:    acpi_ev_initialize_region
44295b482a8SLen Brown  *
44395b482a8SLen Brown  * PARAMETERS:  region_obj      - Region we are initializing
44495b482a8SLen Brown  *
44595b482a8SLen Brown  * RETURN:      Status
44695b482a8SLen Brown  *
44795b482a8SLen Brown  * DESCRIPTION: Initializes the region, finds any _REG methods and saves them
44895b482a8SLen Brown  *              for execution at a later time
44995b482a8SLen Brown  *
45095b482a8SLen Brown  *              Get the appropriate address space handler for a newly
45195b482a8SLen Brown  *              created region.
45295b482a8SLen Brown  *
45395b482a8SLen Brown  *              This also performs address space specific initialization. For
45495b482a8SLen Brown  *              example, PCI regions must have an _ADR object that contains
45595b482a8SLen Brown  *              a PCI address in the scope of the definition. This address is
45695b482a8SLen Brown  *              required to perform an access to PCI config space.
45795b482a8SLen Brown  *
45895b482a8SLen Brown  * MUTEX:       Interpreter should be unlocked, because we may run the _REG
45995b482a8SLen Brown  *              method for this region.
46095b482a8SLen Brown  *
461760235cdSLv Zheng  * NOTE:        Possible incompliance:
462760235cdSLv Zheng  *              There is a behavior conflict in automatic _REG execution:
463760235cdSLv Zheng  *              1. When the interpreter is evaluating a method, we can only
464760235cdSLv Zheng  *                 automatically run _REG for the following case:
465760235cdSLv Zheng  *                   operation_region (OPR1, 0x80, 0x1000010, 0x4)
466760235cdSLv Zheng  *              2. When the interpreter is loading a table, we can also
467760235cdSLv Zheng  *                 automatically run _REG for the following case:
468760235cdSLv Zheng  *                   operation_region (OPR1, 0x80, 0x1000010, 0x4)
469760235cdSLv Zheng  *              Though this may not be compliant to the de-facto standard, the
470760235cdSLv Zheng  *              logic is kept in order not to trigger regressions. And keeping
471760235cdSLv Zheng  *              this logic should be taken care by the caller of this function.
472760235cdSLv Zheng  *
47395b482a8SLen Brown  ******************************************************************************/
47495b482a8SLen Brown 
475760235cdSLv Zheng acpi_status acpi_ev_initialize_region(union acpi_operand_object *region_obj)
47695b482a8SLen Brown {
47795b482a8SLen Brown 	union acpi_operand_object *handler_obj;
47895b482a8SLen Brown 	union acpi_operand_object *obj_desc;
47995b482a8SLen Brown 	acpi_adr_space_type space_id;
48095b482a8SLen Brown 	struct acpi_namespace_node *node;
48195b482a8SLen Brown 
482760235cdSLv Zheng 	ACPI_FUNCTION_TRACE(ev_initialize_region);
48395b482a8SLen Brown 
48495b482a8SLen Brown 	if (!region_obj) {
48595b482a8SLen Brown 		return_ACPI_STATUS(AE_BAD_PARAMETER);
48695b482a8SLen Brown 	}
48795b482a8SLen Brown 
48895b482a8SLen Brown 	if (region_obj->common.flags & AOPOBJ_OBJECT_INITIALIZED) {
48995b482a8SLen Brown 		return_ACPI_STATUS(AE_OK);
49095b482a8SLen Brown 	}
49195b482a8SLen Brown 
492849c2571SLv Zheng 	region_obj->common.flags |= AOPOBJ_OBJECT_INITIALIZED;
49395b482a8SLen Brown 
494c45b5c09SAlexey Starikovskiy 	node = region_obj->region.node->parent;
49595b482a8SLen Brown 	space_id = region_obj->region.space_id;
49695b482a8SLen Brown 
49795b482a8SLen Brown 	/*
49895b482a8SLen Brown 	 * The following loop depends upon the root Node having no parent
4997b738064SBob Moore 	 * ie: acpi_gbl_root_node->Parent being set to NULL
50095b482a8SLen Brown 	 */
50195b482a8SLen Brown 	while (node) {
50295b482a8SLen Brown 
50395b482a8SLen Brown 		/* Check to see if a handler exists */
50495b482a8SLen Brown 
50595b482a8SLen Brown 		handler_obj = NULL;
50695b482a8SLen Brown 		obj_desc = acpi_ns_get_attached_object(node);
50795b482a8SLen Brown 		if (obj_desc) {
50895b482a8SLen Brown 
50995b482a8SLen Brown 			/* Can only be a handler if the object exists */
51095b482a8SLen Brown 
51195b482a8SLen Brown 			switch (node->type) {
51295b482a8SLen Brown 			case ACPI_TYPE_DEVICE:
51395b482a8SLen Brown 			case ACPI_TYPE_PROCESSOR:
51495b482a8SLen Brown 			case ACPI_TYPE_THERMAL:
51595b482a8SLen Brown 
516aa6abd2bSLv Zheng 				handler_obj = obj_desc->common_notify.handler;
51795b482a8SLen Brown 				break;
51895b482a8SLen Brown 
519e31c32cfSLin Ming 			case ACPI_TYPE_METHOD:
520e31c32cfSLin Ming 				/*
521e31c32cfSLin Ming 				 * If we are executing module level code, the original
522e31c32cfSLin Ming 				 * Node's object was replaced by this Method object and we
523e31c32cfSLin Ming 				 * saved the handler in the method object.
524e31c32cfSLin Ming 				 *
525a406dea8SBob Moore 				 * Note: Only used for the legacy MLC support. Will
526a406dea8SBob Moore 				 * be removed in the future.
527a406dea8SBob Moore 				 *
528e31c32cfSLin Ming 				 * See acpi_ns_exec_module_code
529e31c32cfSLin Ming 				 */
530e7d970f6SBob Moore 				if (!acpi_gbl_execute_tables_as_methods &&
531de56ba95SLv Zheng 				    obj_desc->method.
53226294842SLin Ming 				    info_flags & ACPI_METHOD_MODULE_LEVEL) {
533e31c32cfSLin Ming 					handler_obj =
53426294842SLin Ming 					    obj_desc->method.dispatch.handler;
535e31c32cfSLin Ming 				}
536e31c32cfSLin Ming 				break;
537e31c32cfSLin Ming 
53895b482a8SLen Brown 			default:
5391d1ea1b7SChao Guan 
54095b482a8SLen Brown 				/* Ignore other objects */
5411d1ea1b7SChao Guan 
54295b482a8SLen Brown 				break;
54395b482a8SLen Brown 			}
54495b482a8SLen Brown 
545f31a99ceSLv Zheng 			handler_obj =
546f31a99ceSLv Zheng 			    acpi_ev_find_region_handler(space_id, handler_obj);
547f31a99ceSLv Zheng 			if (handler_obj) {
54895b482a8SLen Brown 
54995b482a8SLen Brown 				/* Found correct handler */
55095b482a8SLen Brown 
55195b482a8SLen Brown 				ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
55295b482a8SLen Brown 						  "Found handler %p for region %p in obj %p\n",
553f31a99ceSLv Zheng 						  handler_obj, region_obj,
55495b482a8SLen Brown 						  obj_desc));
55595b482a8SLen Brown 
556760235cdSLv Zheng 				(void)acpi_ev_attach_region(handler_obj,
557760235cdSLv Zheng 							    region_obj, FALSE);
55895b482a8SLen Brown 
55995b482a8SLen Brown 				/*
560d4913dc6SBob Moore 				 * Tell all users that this region is usable by
561d4913dc6SBob Moore 				 * running the _REG method
56295b482a8SLen Brown 				 */
5638633db6bSLv Zheng 				acpi_ex_exit_interpreter();
564760235cdSLv Zheng 				(void)acpi_ev_execute_reg_method(region_obj,
565f31a99ceSLv Zheng 								 ACPI_REG_CONNECT);
5668633db6bSLv Zheng 				acpi_ex_enter_interpreter();
56795b482a8SLen Brown 				return_ACPI_STATUS(AE_OK);
56895b482a8SLen Brown 			}
56995b482a8SLen Brown 		}
57095b482a8SLen Brown 
57195b482a8SLen Brown 		/* This node does not have the handler we need; Pop up one level */
57295b482a8SLen Brown 
573c45b5c09SAlexey Starikovskiy 		node = node->parent;
57495b482a8SLen Brown 	}
57595b482a8SLen Brown 
576760235cdSLv Zheng 	/*
577760235cdSLv Zheng 	 * If we get here, there is no handler for this region. This is not
578760235cdSLv Zheng 	 * fatal because many regions get created before a handler is installed
579760235cdSLv Zheng 	 * for said region.
580760235cdSLv Zheng 	 */
58195b482a8SLen Brown 	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
58295b482a8SLen Brown 			  "No handler for RegionType %s(%X) (RegionObj %p)\n",
58395b482a8SLen Brown 			  acpi_ut_get_region_name(space_id), space_id,
58495b482a8SLen Brown 			  region_obj));
58595b482a8SLen Brown 
586760235cdSLv Zheng 	return_ACPI_STATUS(AE_OK);
58795b482a8SLen Brown }
588