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 *
6*612c2932SBob Moore * Copyright (C) 2000 - 2023, 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
acpi_ev_system_memory_region_setup(acpi_handle handle,u32 function,void * handler_context,void ** region_context)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;
41b8fcd0e5SRafael J. Wysocki struct acpi_mem_mapping *mm;
4295b482a8SLen Brown
4395b482a8SLen Brown ACPI_FUNCTION_TRACE(ev_system_memory_region_setup);
4495b482a8SLen Brown
4595b482a8SLen Brown if (function == ACPI_REGION_DEACTIVATE) {
4695b482a8SLen Brown if (*region_context) {
4795b482a8SLen Brown local_region_context =
4895b482a8SLen Brown (struct acpi_mem_space_context *)*region_context;
4995b482a8SLen Brown
50b8fcd0e5SRafael J. Wysocki /* Delete memory mappings if present */
5195b482a8SLen Brown
52b8fcd0e5SRafael J. Wysocki while (local_region_context->first_mm) {
53b8fcd0e5SRafael J. Wysocki mm = local_region_context->first_mm;
54b8fcd0e5SRafael J. Wysocki local_region_context->first_mm = mm->next_mm;
55b8fcd0e5SRafael J. Wysocki acpi_os_unmap_memory(mm->logical_address,
56b8fcd0e5SRafael J. Wysocki mm->length);
57b8fcd0e5SRafael J. Wysocki ACPI_FREE(mm);
5895b482a8SLen Brown }
5995b482a8SLen Brown ACPI_FREE(local_region_context);
6095b482a8SLen Brown *region_context = NULL;
6195b482a8SLen Brown }
6295b482a8SLen Brown return_ACPI_STATUS(AE_OK);
6395b482a8SLen Brown }
6495b482a8SLen Brown
6595b482a8SLen Brown /* Create a new context */
6695b482a8SLen Brown
6795b482a8SLen Brown local_region_context =
6895b482a8SLen Brown ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_mem_space_context));
6995b482a8SLen Brown if (!(local_region_context)) {
7095b482a8SLen Brown return_ACPI_STATUS(AE_NO_MEMORY);
7195b482a8SLen Brown }
7295b482a8SLen Brown
7395b482a8SLen Brown /* Save the region length and address for use in the handler */
7495b482a8SLen Brown
7595b482a8SLen Brown local_region_context->length = region_desc->region.length;
7695b482a8SLen Brown local_region_context->address = region_desc->region.address;
7795b482a8SLen Brown
7895b482a8SLen Brown *region_context = local_region_context;
7995b482a8SLen Brown return_ACPI_STATUS(AE_OK);
8095b482a8SLen Brown }
8195b482a8SLen Brown
8295b482a8SLen Brown /*******************************************************************************
8395b482a8SLen Brown *
8495b482a8SLen Brown * FUNCTION: acpi_ev_io_space_region_setup
8595b482a8SLen Brown *
86ba494beeSBob Moore * PARAMETERS: handle - Region we are interested in
87ba494beeSBob Moore * function - Start or stop
8895b482a8SLen Brown * handler_context - Address space handler context
8995b482a8SLen Brown * region_context - Region specific context
9095b482a8SLen Brown *
9195b482a8SLen Brown * RETURN: Status
9295b482a8SLen Brown *
9395b482a8SLen Brown * DESCRIPTION: Setup a IO operation region
9495b482a8SLen Brown *
9595b482a8SLen Brown ******************************************************************************/
9695b482a8SLen Brown
9795b482a8SLen Brown acpi_status
acpi_ev_io_space_region_setup(acpi_handle handle,u32 function,void * handler_context,void ** region_context)9895b482a8SLen Brown acpi_ev_io_space_region_setup(acpi_handle handle,
9995b482a8SLen Brown u32 function,
10095b482a8SLen Brown void *handler_context, void **region_context)
10195b482a8SLen Brown {
10295b482a8SLen Brown ACPI_FUNCTION_TRACE(ev_io_space_region_setup);
10395b482a8SLen Brown
10495b482a8SLen Brown if (function == ACPI_REGION_DEACTIVATE) {
10595b482a8SLen Brown *region_context = NULL;
10695b482a8SLen Brown } else {
10795b482a8SLen Brown *region_context = handler_context;
10895b482a8SLen Brown }
10995b482a8SLen Brown
11095b482a8SLen Brown return_ACPI_STATUS(AE_OK);
11195b482a8SLen Brown }
11295b482a8SLen Brown
11395b482a8SLen Brown /*******************************************************************************
11495b482a8SLen Brown *
11595b482a8SLen Brown * FUNCTION: acpi_ev_pci_config_region_setup
11695b482a8SLen Brown *
117ba494beeSBob Moore * PARAMETERS: handle - Region we are interested in
118ba494beeSBob Moore * function - Start or stop
11995b482a8SLen Brown * handler_context - Address space handler context
12095b482a8SLen Brown * region_context - Region specific context
12195b482a8SLen Brown *
12295b482a8SLen Brown * RETURN: Status
12395b482a8SLen Brown *
12495b482a8SLen Brown * DESCRIPTION: Setup a PCI_Config operation region
12595b482a8SLen Brown *
12695b482a8SLen Brown * MUTEX: Assumes namespace is not locked
12795b482a8SLen Brown *
12895b482a8SLen Brown ******************************************************************************/
12995b482a8SLen Brown
13095b482a8SLen Brown acpi_status
acpi_ev_pci_config_region_setup(acpi_handle handle,u32 function,void * handler_context,void ** region_context)13195b482a8SLen Brown acpi_ev_pci_config_region_setup(acpi_handle handle,
13295b482a8SLen Brown u32 function,
13395b482a8SLen Brown void *handler_context, void **region_context)
13495b482a8SLen Brown {
13595b482a8SLen Brown acpi_status status = AE_OK;
1365df7e6cbSBob Moore u64 pci_value;
13795b482a8SLen Brown struct acpi_pci_id *pci_id = *region_context;
13895b482a8SLen Brown union acpi_operand_object *handler_obj;
13995b482a8SLen Brown struct acpi_namespace_node *parent_node;
14095b482a8SLen Brown struct acpi_namespace_node *pci_root_node;
14195b482a8SLen Brown struct acpi_namespace_node *pci_device_node;
14295b482a8SLen Brown union acpi_operand_object *region_obj =
14395b482a8SLen Brown (union acpi_operand_object *)handle;
14495b482a8SLen Brown
14595b482a8SLen Brown ACPI_FUNCTION_TRACE(ev_pci_config_region_setup);
14695b482a8SLen Brown
14795b482a8SLen Brown handler_obj = region_obj->region.handler;
14895b482a8SLen Brown if (!handler_obj) {
14995b482a8SLen Brown /*
15095b482a8SLen Brown * No installed handler. This shouldn't happen because the dispatch
15195b482a8SLen Brown * routine checks before we get here, but we check again just in case.
15295b482a8SLen Brown */
15395b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
15495b482a8SLen Brown "Attempting to init a region %p, with no handler\n",
15595b482a8SLen Brown region_obj));
15695b482a8SLen Brown return_ACPI_STATUS(AE_NOT_EXIST);
15795b482a8SLen Brown }
15895b482a8SLen Brown
15995b482a8SLen Brown *region_context = NULL;
16095b482a8SLen Brown if (function == ACPI_REGION_DEACTIVATE) {
16195b482a8SLen Brown if (pci_id) {
16295b482a8SLen Brown ACPI_FREE(pci_id);
16395b482a8SLen Brown }
16495b482a8SLen Brown return_ACPI_STATUS(status);
16595b482a8SLen Brown }
16695b482a8SLen Brown
167c45b5c09SAlexey Starikovskiy parent_node = region_obj->region.node->parent;
16895b482a8SLen Brown
16995b482a8SLen Brown /*
17095b482a8SLen Brown * Get the _SEG and _BBN values from the device upon which the handler
17195b482a8SLen Brown * is installed.
17295b482a8SLen Brown *
17395b482a8SLen Brown * We need to get the _SEG and _BBN objects relative to the PCI BUS device.
17495b482a8SLen Brown * This is the device the handler has been registered to handle.
17595b482a8SLen Brown */
17695b482a8SLen Brown
17795b482a8SLen Brown /*
17895b482a8SLen Brown * If the address_space.Node is still pointing to the root, we need
17995b482a8SLen Brown * to scan upward for a PCI Root bridge and re-associate the op_region
18095b482a8SLen Brown * handlers with that device.
18195b482a8SLen Brown */
18295b482a8SLen Brown if (handler_obj->address_space.node == acpi_gbl_root_node) {
18395b482a8SLen Brown
18495b482a8SLen Brown /* Start search from the parent object */
18595b482a8SLen Brown
18695b482a8SLen Brown pci_root_node = parent_node;
18795b482a8SLen Brown while (pci_root_node != acpi_gbl_root_node) {
18895b482a8SLen Brown
18995b482a8SLen Brown /* Get the _HID/_CID in order to detect a root_bridge */
19095b482a8SLen Brown
19195b482a8SLen Brown if (acpi_ev_is_pci_root_bridge(pci_root_node)) {
19295b482a8SLen Brown
19395b482a8SLen Brown /* Install a handler for this PCI root bridge */
19495b482a8SLen Brown
1951f86e8c1SLv Zheng status = acpi_install_address_space_handler((acpi_handle)pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL);
19695b482a8SLen Brown if (ACPI_FAILURE(status)) {
19795b482a8SLen Brown if (status == AE_SAME_HANDLER) {
19895b482a8SLen Brown /*
19995b482a8SLen Brown * It is OK if the handler is already installed on the
20095b482a8SLen Brown * root bridge. Still need to return a context object
20195b482a8SLen Brown * for the new PCI_Config operation region, however.
20295b482a8SLen Brown */
20395b482a8SLen Brown } else {
20495b482a8SLen Brown ACPI_EXCEPTION((AE_INFO, status,
205d4913dc6SBob Moore "Could not install PciConfig handler "
206d4913dc6SBob Moore "for Root Bridge %4.4s",
20795b482a8SLen Brown acpi_ut_get_node_name
20895b482a8SLen Brown (pci_root_node)));
20995b482a8SLen Brown }
21095b482a8SLen Brown }
21195b482a8SLen Brown break;
21295b482a8SLen Brown }
21395b482a8SLen Brown
214c45b5c09SAlexey Starikovskiy pci_root_node = pci_root_node->parent;
21595b482a8SLen Brown }
21695b482a8SLen Brown
21795b482a8SLen Brown /* PCI root bridge not found, use namespace root node */
21895b482a8SLen Brown } else {
21995b482a8SLen Brown pci_root_node = handler_obj->address_space.node;
22095b482a8SLen Brown }
22195b482a8SLen Brown
22295b482a8SLen Brown /*
22395b482a8SLen Brown * If this region is now initialized, we are done.
22495b482a8SLen Brown * (install_address_space_handler could have initialized it)
22595b482a8SLen Brown */
22695b482a8SLen Brown if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) {
22795b482a8SLen Brown return_ACPI_STATUS(AE_OK);
22895b482a8SLen Brown }
22995b482a8SLen Brown
23095b482a8SLen Brown /* Region is still not initialized. Create a new context */
23195b482a8SLen Brown
23295b482a8SLen Brown pci_id = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pci_id));
23395b482a8SLen Brown if (!pci_id) {
23495b482a8SLen Brown return_ACPI_STATUS(AE_NO_MEMORY);
23595b482a8SLen Brown }
23695b482a8SLen Brown
23795b482a8SLen Brown /*
23895b482a8SLen Brown * For PCI_Config space access, we need the segment, bus, device and
23995b482a8SLen Brown * function numbers. Acquire them here.
24095b482a8SLen Brown *
24195b482a8SLen Brown * Find the parent device object. (This allows the operation region to be
24295b482a8SLen Brown * within a subscope under the device, such as a control method.)
24395b482a8SLen Brown */
24495b482a8SLen Brown pci_device_node = region_obj->region.node;
24595b482a8SLen Brown while (pci_device_node && (pci_device_node->type != ACPI_TYPE_DEVICE)) {
246c45b5c09SAlexey Starikovskiy pci_device_node = pci_device_node->parent;
24795b482a8SLen Brown }
24895b482a8SLen Brown
24995b482a8SLen Brown if (!pci_device_node) {
25095b482a8SLen Brown ACPI_FREE(pci_id);
25195b482a8SLen Brown return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
25295b482a8SLen Brown }
25395b482a8SLen Brown
25495b482a8SLen Brown /*
25595abccb5SBob Moore * Get the PCI device and function numbers from the _ADR object
25695abccb5SBob Moore * contained in the parent's scope.
25795b482a8SLen Brown */
258d4913dc6SBob Moore status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR,
259d4913dc6SBob Moore pci_device_node, &pci_value);
26095b482a8SLen Brown
26195b482a8SLen Brown /*
26295b482a8SLen Brown * The default is zero, and since the allocation above zeroed the data,
26395b482a8SLen Brown * just do nothing on failure.
26495b482a8SLen Brown */
26595b482a8SLen Brown if (ACPI_SUCCESS(status)) {
26695b482a8SLen Brown pci_id->device = ACPI_HIWORD(ACPI_LODWORD(pci_value));
26795b482a8SLen Brown pci_id->function = ACPI_LOWORD(ACPI_LODWORD(pci_value));
26895b482a8SLen Brown }
26995b482a8SLen Brown
27095b482a8SLen Brown /* The PCI segment number comes from the _SEG method */
27195b482a8SLen Brown
272d4913dc6SBob Moore status = acpi_ut_evaluate_numeric_object(METHOD_NAME__SEG,
273d4913dc6SBob Moore pci_root_node, &pci_value);
27495b482a8SLen Brown if (ACPI_SUCCESS(status)) {
27595b482a8SLen Brown pci_id->segment = ACPI_LOWORD(pci_value);
27695b482a8SLen Brown }
27795b482a8SLen Brown
27895b482a8SLen Brown /* The PCI bus number comes from the _BBN method */
27995b482a8SLen Brown
280d4913dc6SBob Moore status = acpi_ut_evaluate_numeric_object(METHOD_NAME__BBN,
281d4913dc6SBob Moore pci_root_node, &pci_value);
28295b482a8SLen Brown if (ACPI_SUCCESS(status)) {
28395b482a8SLen Brown pci_id->bus = ACPI_LOWORD(pci_value);
28495b482a8SLen Brown }
28595b482a8SLen Brown
28695abccb5SBob Moore /* Complete/update the PCI ID for this device */
28795b482a8SLen Brown
28895abccb5SBob Moore status =
28995abccb5SBob Moore acpi_hw_derive_pci_id(pci_id, pci_root_node,
29095abccb5SBob Moore region_obj->region.node);
29195abccb5SBob Moore if (ACPI_FAILURE(status)) {
29295abccb5SBob Moore ACPI_FREE(pci_id);
29395abccb5SBob Moore return_ACPI_STATUS(status);
29495abccb5SBob Moore }
29595b482a8SLen Brown
29695b482a8SLen Brown *region_context = pci_id;
29795b482a8SLen Brown return_ACPI_STATUS(AE_OK);
29895b482a8SLen Brown }
29995b482a8SLen Brown
30095b482a8SLen Brown /*******************************************************************************
30195b482a8SLen Brown *
30295b482a8SLen Brown * FUNCTION: acpi_ev_is_pci_root_bridge
30395b482a8SLen Brown *
304ba494beeSBob Moore * PARAMETERS: node - Device node being examined
30595b482a8SLen Brown *
30695b482a8SLen Brown * RETURN: TRUE if device is a PCI/PCI-Express Root Bridge
30795b482a8SLen Brown *
30895b482a8SLen Brown * DESCRIPTION: Determine if the input device represents a PCI Root Bridge by
30995b482a8SLen Brown * examining the _HID and _CID for the device.
31095b482a8SLen Brown *
31195b482a8SLen Brown ******************************************************************************/
31295b482a8SLen Brown
acpi_ev_is_pci_root_bridge(struct acpi_namespace_node * node)3138b1cafdcSBob Moore u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node)
31495b482a8SLen Brown {
31595b482a8SLen Brown acpi_status status;
31678e25fefSLv Zheng struct acpi_pnp_device_id *hid;
31778e25fefSLv Zheng struct acpi_pnp_device_id_list *cid;
31895b482a8SLen Brown u32 i;
31915b8dd53SBob Moore u8 match;
32095b482a8SLen Brown
32195b482a8SLen Brown /* Get the _HID and check for a PCI Root Bridge */
32295b482a8SLen Brown
32395b482a8SLen Brown status = acpi_ut_execute_HID(node, &hid);
32495b482a8SLen Brown if (ACPI_FAILURE(status)) {
32595b482a8SLen Brown return (FALSE);
32695b482a8SLen Brown }
32795b482a8SLen Brown
32815b8dd53SBob Moore match = acpi_ut_is_pci_root_bridge(hid->string);
32915b8dd53SBob Moore ACPI_FREE(hid);
33015b8dd53SBob Moore
33115b8dd53SBob Moore if (match) {
33295b482a8SLen Brown return (TRUE);
33395b482a8SLen Brown }
33495b482a8SLen Brown
33595b482a8SLen Brown /* The _HID did not match. Get the _CID and check for a PCI Root Bridge */
33695b482a8SLen Brown
33795b482a8SLen Brown status = acpi_ut_execute_CID(node, &cid);
33895b482a8SLen Brown if (ACPI_FAILURE(status)) {
33995b482a8SLen Brown return (FALSE);
34095b482a8SLen Brown }
34195b482a8SLen Brown
34295b482a8SLen Brown /* Check all _CIDs in the returned list */
34395b482a8SLen Brown
34495b482a8SLen Brown for (i = 0; i < cid->count; i++) {
34515b8dd53SBob Moore if (acpi_ut_is_pci_root_bridge(cid->ids[i].string)) {
34695b482a8SLen Brown ACPI_FREE(cid);
34795b482a8SLen Brown return (TRUE);
34895b482a8SLen Brown }
34995b482a8SLen Brown }
35095b482a8SLen Brown
35195b482a8SLen Brown ACPI_FREE(cid);
35295b482a8SLen Brown return (FALSE);
35395b482a8SLen Brown }
35495b482a8SLen Brown
35595b482a8SLen Brown /*******************************************************************************
35695b482a8SLen Brown *
35795b482a8SLen Brown * FUNCTION: acpi_ev_pci_bar_region_setup
35895b482a8SLen Brown *
359ba494beeSBob Moore * PARAMETERS: handle - Region we are interested in
360ba494beeSBob Moore * function - Start or stop
36195b482a8SLen Brown * handler_context - Address space handler context
36295b482a8SLen Brown * region_context - Region specific context
36395b482a8SLen Brown *
36495b482a8SLen Brown * RETURN: Status
36595b482a8SLen Brown *
366ba494beeSBob Moore * DESCRIPTION: Setup a pci_BAR operation region
36795b482a8SLen Brown *
36895b482a8SLen Brown * MUTEX: Assumes namespace is not locked
36995b482a8SLen Brown *
37095b482a8SLen Brown ******************************************************************************/
37195b482a8SLen Brown
37295b482a8SLen Brown acpi_status
acpi_ev_pci_bar_region_setup(acpi_handle handle,u32 function,void * handler_context,void ** region_context)37395b482a8SLen Brown acpi_ev_pci_bar_region_setup(acpi_handle handle,
37495b482a8SLen Brown u32 function,
37595b482a8SLen Brown void *handler_context, void **region_context)
37695b482a8SLen Brown {
37795b482a8SLen Brown ACPI_FUNCTION_TRACE(ev_pci_bar_region_setup);
37895b482a8SLen Brown
37995b482a8SLen Brown return_ACPI_STATUS(AE_OK);
38095b482a8SLen Brown }
38195b482a8SLen Brown
38295b482a8SLen Brown /*******************************************************************************
38395b482a8SLen Brown *
38495b482a8SLen Brown * FUNCTION: acpi_ev_cmos_region_setup
38595b482a8SLen Brown *
386ba494beeSBob Moore * PARAMETERS: handle - Region we are interested in
387ba494beeSBob Moore * function - Start or stop
38895b482a8SLen Brown * handler_context - Address space handler context
38995b482a8SLen Brown * region_context - Region specific context
39095b482a8SLen Brown *
39195b482a8SLen Brown * RETURN: Status
39295b482a8SLen Brown *
39395b482a8SLen Brown * DESCRIPTION: Setup a CMOS operation region
39495b482a8SLen Brown *
39595b482a8SLen Brown * MUTEX: Assumes namespace is not locked
39695b482a8SLen Brown *
39795b482a8SLen Brown ******************************************************************************/
39895b482a8SLen Brown
39995b482a8SLen Brown acpi_status
acpi_ev_cmos_region_setup(acpi_handle handle,u32 function,void * handler_context,void ** region_context)40095b482a8SLen Brown acpi_ev_cmos_region_setup(acpi_handle handle,
40195b482a8SLen Brown u32 function,
40295b482a8SLen Brown void *handler_context, void **region_context)
40395b482a8SLen Brown {
40495b482a8SLen Brown ACPI_FUNCTION_TRACE(ev_cmos_region_setup);
40595b482a8SLen Brown
40695b482a8SLen Brown return_ACPI_STATUS(AE_OK);
40795b482a8SLen Brown }
40895b482a8SLen Brown
40995b482a8SLen Brown /*******************************************************************************
41095b482a8SLen Brown *
411ca25f92bSJessica Clarke * FUNCTION: acpi_ev_data_table_region_setup
412ca25f92bSJessica Clarke *
413ca25f92bSJessica Clarke * PARAMETERS: handle - Region we are interested in
414ca25f92bSJessica Clarke * function - Start or stop
415ca25f92bSJessica Clarke * handler_context - Address space handler context
416ca25f92bSJessica Clarke * region_context - Region specific context
417ca25f92bSJessica Clarke *
418ca25f92bSJessica Clarke * RETURN: Status
419ca25f92bSJessica Clarke *
420ca25f92bSJessica Clarke * DESCRIPTION: Setup a data_table_region
421ca25f92bSJessica Clarke *
422ca25f92bSJessica Clarke * MUTEX: Assumes namespace is not locked
423ca25f92bSJessica Clarke *
424ca25f92bSJessica Clarke ******************************************************************************/
425ca25f92bSJessica Clarke
426ca25f92bSJessica Clarke acpi_status
acpi_ev_data_table_region_setup(acpi_handle handle,u32 function,void * handler_context,void ** region_context)427ca25f92bSJessica Clarke acpi_ev_data_table_region_setup(acpi_handle handle,
428ca25f92bSJessica Clarke u32 function,
429ca25f92bSJessica Clarke void *handler_context, void **region_context)
430ca25f92bSJessica Clarke {
431ca25f92bSJessica Clarke union acpi_operand_object *region_desc =
432ca25f92bSJessica Clarke (union acpi_operand_object *)handle;
4339737ff46SPedro Falcato struct acpi_data_table_mapping *local_region_context;
434ca25f92bSJessica Clarke
435ca25f92bSJessica Clarke ACPI_FUNCTION_TRACE(ev_data_table_region_setup);
436ca25f92bSJessica Clarke
437ca25f92bSJessica Clarke if (function == ACPI_REGION_DEACTIVATE) {
438ca25f92bSJessica Clarke if (*region_context) {
439ca25f92bSJessica Clarke ACPI_FREE(*region_context);
440ca25f92bSJessica Clarke *region_context = NULL;
441ca25f92bSJessica Clarke }
442ca25f92bSJessica Clarke return_ACPI_STATUS(AE_OK);
443ca25f92bSJessica Clarke }
444ca25f92bSJessica Clarke
445ca25f92bSJessica Clarke /* Create a new context */
446ca25f92bSJessica Clarke
447ca25f92bSJessica Clarke local_region_context =
4489737ff46SPedro Falcato ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_data_table_mapping));
449ca25f92bSJessica Clarke if (!(local_region_context)) {
450ca25f92bSJessica Clarke return_ACPI_STATUS(AE_NO_MEMORY);
451ca25f92bSJessica Clarke }
452ca25f92bSJessica Clarke
453ca25f92bSJessica Clarke /* Save the data table pointer for use in the handler */
454ca25f92bSJessica Clarke
455ca25f92bSJessica Clarke local_region_context->pointer = region_desc->region.pointer;
456ca25f92bSJessica Clarke
457ca25f92bSJessica Clarke *region_context = local_region_context;
458ca25f92bSJessica Clarke return_ACPI_STATUS(AE_OK);
459ca25f92bSJessica Clarke }
460ca25f92bSJessica Clarke
461ca25f92bSJessica Clarke /*******************************************************************************
462ca25f92bSJessica Clarke *
46395b482a8SLen Brown * FUNCTION: acpi_ev_default_region_setup
46495b482a8SLen Brown *
465ba494beeSBob Moore * PARAMETERS: handle - Region we are interested in
466ba494beeSBob Moore * function - Start or stop
46795b482a8SLen Brown * handler_context - Address space handler context
46895b482a8SLen Brown * region_context - Region specific context
46995b482a8SLen Brown *
47095b482a8SLen Brown * RETURN: Status
47195b482a8SLen Brown *
47295b482a8SLen Brown * DESCRIPTION: Default region initialization
47395b482a8SLen Brown *
47495b482a8SLen Brown ******************************************************************************/
47595b482a8SLen Brown
47695b482a8SLen Brown acpi_status
acpi_ev_default_region_setup(acpi_handle handle,u32 function,void * handler_context,void ** region_context)47795b482a8SLen Brown acpi_ev_default_region_setup(acpi_handle handle,
47895b482a8SLen Brown u32 function,
47995b482a8SLen Brown void *handler_context, void **region_context)
48095b482a8SLen Brown {
48195b482a8SLen Brown ACPI_FUNCTION_TRACE(ev_default_region_setup);
48295b482a8SLen Brown
48395b482a8SLen Brown if (function == ACPI_REGION_DEACTIVATE) {
48495b482a8SLen Brown *region_context = NULL;
48595b482a8SLen Brown } else {
48695b482a8SLen Brown *region_context = handler_context;
48795b482a8SLen Brown }
48895b482a8SLen Brown
48995b482a8SLen Brown return_ACPI_STATUS(AE_OK);
49095b482a8SLen Brown }
49195b482a8SLen Brown
49295b482a8SLen Brown /*******************************************************************************
49395b482a8SLen Brown *
49495b482a8SLen Brown * FUNCTION: acpi_ev_initialize_region
49595b482a8SLen Brown *
49695b482a8SLen Brown * PARAMETERS: region_obj - Region we are initializing
49795b482a8SLen Brown *
49895b482a8SLen Brown * RETURN: Status
49995b482a8SLen Brown *
50095b482a8SLen Brown * DESCRIPTION: Initializes the region, finds any _REG methods and saves them
50195b482a8SLen Brown * for execution at a later time
50295b482a8SLen Brown *
50395b482a8SLen Brown * Get the appropriate address space handler for a newly
50495b482a8SLen Brown * created region.
50595b482a8SLen Brown *
50695b482a8SLen Brown * This also performs address space specific initialization. For
50795b482a8SLen Brown * example, PCI regions must have an _ADR object that contains
50895b482a8SLen Brown * a PCI address in the scope of the definition. This address is
50995b482a8SLen Brown * required to perform an access to PCI config space.
51095b482a8SLen Brown *
51195b482a8SLen Brown * MUTEX: Interpreter should be unlocked, because we may run the _REG
51295b482a8SLen Brown * method for this region.
51395b482a8SLen Brown *
514760235cdSLv Zheng * NOTE: Possible incompliance:
515760235cdSLv Zheng * There is a behavior conflict in automatic _REG execution:
516760235cdSLv Zheng * 1. When the interpreter is evaluating a method, we can only
517760235cdSLv Zheng * automatically run _REG for the following case:
518760235cdSLv Zheng * operation_region (OPR1, 0x80, 0x1000010, 0x4)
519760235cdSLv Zheng * 2. When the interpreter is loading a table, we can also
520760235cdSLv Zheng * automatically run _REG for the following case:
521760235cdSLv Zheng * operation_region (OPR1, 0x80, 0x1000010, 0x4)
522760235cdSLv Zheng * Though this may not be compliant to the de-facto standard, the
523760235cdSLv Zheng * logic is kept in order not to trigger regressions. And keeping
524760235cdSLv Zheng * this logic should be taken care by the caller of this function.
525760235cdSLv Zheng *
52695b482a8SLen Brown ******************************************************************************/
52795b482a8SLen Brown
acpi_ev_initialize_region(union acpi_operand_object * region_obj)528760235cdSLv Zheng acpi_status acpi_ev_initialize_region(union acpi_operand_object *region_obj)
52995b482a8SLen Brown {
53095b482a8SLen Brown union acpi_operand_object *handler_obj;
53195b482a8SLen Brown union acpi_operand_object *obj_desc;
53295b482a8SLen Brown acpi_adr_space_type space_id;
53395b482a8SLen Brown struct acpi_namespace_node *node;
53495b482a8SLen Brown
535760235cdSLv Zheng ACPI_FUNCTION_TRACE(ev_initialize_region);
53695b482a8SLen Brown
53795b482a8SLen Brown if (!region_obj) {
53895b482a8SLen Brown return_ACPI_STATUS(AE_BAD_PARAMETER);
53995b482a8SLen Brown }
54095b482a8SLen Brown
54195b482a8SLen Brown if (region_obj->common.flags & AOPOBJ_OBJECT_INITIALIZED) {
54295b482a8SLen Brown return_ACPI_STATUS(AE_OK);
54395b482a8SLen Brown }
54495b482a8SLen Brown
545849c2571SLv Zheng region_obj->common.flags |= AOPOBJ_OBJECT_INITIALIZED;
54695b482a8SLen Brown
547c45b5c09SAlexey Starikovskiy node = region_obj->region.node->parent;
54895b482a8SLen Brown space_id = region_obj->region.space_id;
54995b482a8SLen Brown
55095b482a8SLen Brown /*
55195b482a8SLen Brown * The following loop depends upon the root Node having no parent
5527b738064SBob Moore * ie: acpi_gbl_root_node->Parent being set to NULL
55395b482a8SLen Brown */
55495b482a8SLen Brown while (node) {
55595b482a8SLen Brown
55695b482a8SLen Brown /* Check to see if a handler exists */
55795b482a8SLen Brown
55895b482a8SLen Brown handler_obj = NULL;
55995b482a8SLen Brown obj_desc = acpi_ns_get_attached_object(node);
56095b482a8SLen Brown if (obj_desc) {
56195b482a8SLen Brown
56295b482a8SLen Brown /* Can only be a handler if the object exists */
56395b482a8SLen Brown
56495b482a8SLen Brown switch (node->type) {
56595b482a8SLen Brown case ACPI_TYPE_DEVICE:
56695b482a8SLen Brown case ACPI_TYPE_PROCESSOR:
56795b482a8SLen Brown case ACPI_TYPE_THERMAL:
56895b482a8SLen Brown
569aa6abd2bSLv Zheng handler_obj = obj_desc->common_notify.handler;
57095b482a8SLen Brown break;
57195b482a8SLen Brown
57295b482a8SLen Brown default:
5731d1ea1b7SChao Guan
57495b482a8SLen Brown /* Ignore other objects */
5751d1ea1b7SChao Guan
57695b482a8SLen Brown break;
57795b482a8SLen Brown }
57895b482a8SLen Brown
579f31a99ceSLv Zheng handler_obj =
580f31a99ceSLv Zheng acpi_ev_find_region_handler(space_id, handler_obj);
581f31a99ceSLv Zheng if (handler_obj) {
58295b482a8SLen Brown
58395b482a8SLen Brown /* Found correct handler */
58495b482a8SLen Brown
58595b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
58695b482a8SLen Brown "Found handler %p for region %p in obj %p\n",
587f31a99ceSLv Zheng handler_obj, region_obj,
58895b482a8SLen Brown obj_desc));
58995b482a8SLen Brown
590760235cdSLv Zheng (void)acpi_ev_attach_region(handler_obj,
591760235cdSLv Zheng region_obj, FALSE);
59295b482a8SLen Brown
59395b482a8SLen Brown /*
594d4913dc6SBob Moore * Tell all users that this region is usable by
595d4913dc6SBob Moore * running the _REG method
59695b482a8SLen Brown */
5978633db6bSLv Zheng acpi_ex_exit_interpreter();
598760235cdSLv Zheng (void)acpi_ev_execute_reg_method(region_obj,
599f31a99ceSLv Zheng ACPI_REG_CONNECT);
6008633db6bSLv Zheng acpi_ex_enter_interpreter();
60195b482a8SLen Brown return_ACPI_STATUS(AE_OK);
60295b482a8SLen Brown }
60395b482a8SLen Brown }
60495b482a8SLen Brown
60595b482a8SLen Brown /* This node does not have the handler we need; Pop up one level */
60695b482a8SLen Brown
607c45b5c09SAlexey Starikovskiy node = node->parent;
60895b482a8SLen Brown }
60995b482a8SLen Brown
610760235cdSLv Zheng /*
611760235cdSLv Zheng * If we get here, there is no handler for this region. This is not
612760235cdSLv Zheng * fatal because many regions get created before a handler is installed
613760235cdSLv Zheng * for said region.
614760235cdSLv Zheng */
61595b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
61695b482a8SLen Brown "No handler for RegionType %s(%X) (RegionObj %p)\n",
61795b482a8SLen Brown acpi_ut_get_region_name(space_id), space_id,
61895b482a8SLen Brown region_obj));
61995b482a8SLen Brown
620760235cdSLv Zheng return_ACPI_STATUS(AE_OK);
62195b482a8SLen Brown }
622