162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: dsinit - Object initialization namespace walk
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *****************************************************************************/
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <acpi/acpi.h>
1162306a36Sopenharmony_ci#include "accommon.h"
1262306a36Sopenharmony_ci#include "acdispat.h"
1362306a36Sopenharmony_ci#include "acnamesp.h"
1462306a36Sopenharmony_ci#include "actables.h"
1562306a36Sopenharmony_ci#include "acinterp.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define _COMPONENT          ACPI_DISPATCHER
1862306a36Sopenharmony_ciACPI_MODULE_NAME("dsinit")
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* Local prototypes */
2162306a36Sopenharmony_cistatic acpi_status
2262306a36Sopenharmony_ciacpi_ds_init_one_object(acpi_handle obj_handle,
2362306a36Sopenharmony_ci			u32 level, void *context, void **return_value);
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/*******************************************************************************
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci * FUNCTION:    acpi_ds_init_one_object
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci * PARAMETERS:  obj_handle      - Node for the object
3062306a36Sopenharmony_ci *              level           - Current nesting level
3162306a36Sopenharmony_ci *              context         - Points to a init info struct
3262306a36Sopenharmony_ci *              return_value    - Not used
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci * RETURN:      Status
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * DESCRIPTION: Callback from acpi_walk_namespace. Invoked for every object
3762306a36Sopenharmony_ci *              within the namespace.
3862306a36Sopenharmony_ci *
3962306a36Sopenharmony_ci *              Currently, the only objects that require initialization are:
4062306a36Sopenharmony_ci *              1) Methods
4162306a36Sopenharmony_ci *              2) Operation Regions
4262306a36Sopenharmony_ci *
4362306a36Sopenharmony_ci ******************************************************************************/
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic acpi_status
4662306a36Sopenharmony_ciacpi_ds_init_one_object(acpi_handle obj_handle,
4762306a36Sopenharmony_ci			u32 level, void *context, void **return_value)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	struct acpi_init_walk_info *info =
5062306a36Sopenharmony_ci	    (struct acpi_init_walk_info *)context;
5162306a36Sopenharmony_ci	struct acpi_namespace_node *node =
5262306a36Sopenharmony_ci	    (struct acpi_namespace_node *)obj_handle;
5362306a36Sopenharmony_ci	acpi_status status;
5462306a36Sopenharmony_ci	union acpi_operand_object *obj_desc;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	ACPI_FUNCTION_ENTRY();
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	/*
5962306a36Sopenharmony_ci	 * We are only interested in NS nodes owned by the table that
6062306a36Sopenharmony_ci	 * was just loaded
6162306a36Sopenharmony_ci	 */
6262306a36Sopenharmony_ci	if (node->owner_id != info->owner_id) {
6362306a36Sopenharmony_ci		return (AE_OK);
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	info->object_count++;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	/* And even then, we are only interested in a few object types */
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	switch (acpi_ns_get_type(obj_handle)) {
7162306a36Sopenharmony_ci	case ACPI_TYPE_REGION:
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci		status = acpi_ds_initialize_region(obj_handle);
7462306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
7562306a36Sopenharmony_ci			ACPI_EXCEPTION((AE_INFO, status,
7662306a36Sopenharmony_ci					"During Region initialization %p [%4.4s]",
7762306a36Sopenharmony_ci					obj_handle,
7862306a36Sopenharmony_ci					acpi_ut_get_node_name(obj_handle)));
7962306a36Sopenharmony_ci		}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci		info->op_region_count++;
8262306a36Sopenharmony_ci		break;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	case ACPI_TYPE_METHOD:
8562306a36Sopenharmony_ci		/*
8662306a36Sopenharmony_ci		 * Auto-serialization support. We will examine each method that is
8762306a36Sopenharmony_ci		 * not_serialized to determine if it creates any Named objects. If
8862306a36Sopenharmony_ci		 * it does, it will be marked serialized to prevent problems if
8962306a36Sopenharmony_ci		 * the method is entered by two or more threads and an attempt is
9062306a36Sopenharmony_ci		 * made to create the same named object twice -- which results in
9162306a36Sopenharmony_ci		 * an AE_ALREADY_EXISTS exception and method abort.
9262306a36Sopenharmony_ci		 */
9362306a36Sopenharmony_ci		info->method_count++;
9462306a36Sopenharmony_ci		obj_desc = acpi_ns_get_attached_object(node);
9562306a36Sopenharmony_ci		if (!obj_desc) {
9662306a36Sopenharmony_ci			break;
9762306a36Sopenharmony_ci		}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci		/* Ignore if already serialized */
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci		if (obj_desc->method.info_flags & ACPI_METHOD_SERIALIZED) {
10262306a36Sopenharmony_ci			info->serial_method_count++;
10362306a36Sopenharmony_ci			break;
10462306a36Sopenharmony_ci		}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci		if (acpi_gbl_auto_serialize_methods) {
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci			/* Parse/scan method and serialize it if necessary */
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci			acpi_ds_auto_serialize_method(node, obj_desc);
11162306a36Sopenharmony_ci			if (obj_desc->method.
11262306a36Sopenharmony_ci			    info_flags & ACPI_METHOD_SERIALIZED) {
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci				/* Method was just converted to Serialized */
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci				info->serial_method_count++;
11762306a36Sopenharmony_ci				info->serialized_method_count++;
11862306a36Sopenharmony_ci				break;
11962306a36Sopenharmony_ci			}
12062306a36Sopenharmony_ci		}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci		info->non_serial_method_count++;
12362306a36Sopenharmony_ci		break;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	case ACPI_TYPE_DEVICE:
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci		info->device_count++;
12862306a36Sopenharmony_ci		break;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	default:
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci		break;
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	/*
13662306a36Sopenharmony_ci	 * We ignore errors from above, and always return OK, since
13762306a36Sopenharmony_ci	 * we don't want to abort the walk on a single error.
13862306a36Sopenharmony_ci	 */
13962306a36Sopenharmony_ci	return (AE_OK);
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/*******************************************************************************
14362306a36Sopenharmony_ci *
14462306a36Sopenharmony_ci * FUNCTION:    acpi_ds_initialize_objects
14562306a36Sopenharmony_ci *
14662306a36Sopenharmony_ci * PARAMETERS:  table_desc      - Descriptor for parent ACPI table
14762306a36Sopenharmony_ci *              start_node      - Root of subtree to be initialized.
14862306a36Sopenharmony_ci *
14962306a36Sopenharmony_ci * RETURN:      Status
15062306a36Sopenharmony_ci *
15162306a36Sopenharmony_ci * DESCRIPTION: Walk the namespace starting at "StartNode" and perform any
15262306a36Sopenharmony_ci *              necessary initialization on the objects found therein
15362306a36Sopenharmony_ci *
15462306a36Sopenharmony_ci ******************************************************************************/
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ciacpi_status
15762306a36Sopenharmony_ciacpi_ds_initialize_objects(u32 table_index,
15862306a36Sopenharmony_ci			   struct acpi_namespace_node *start_node)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	acpi_status status;
16162306a36Sopenharmony_ci	struct acpi_init_walk_info info;
16262306a36Sopenharmony_ci	struct acpi_table_header *table;
16362306a36Sopenharmony_ci	acpi_owner_id owner_id;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ds_initialize_objects);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	status = acpi_tb_get_owner_id(table_index, &owner_id);
16862306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
16962306a36Sopenharmony_ci		return_ACPI_STATUS(status);
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
17362306a36Sopenharmony_ci			  "**** Starting initialization of namespace objects ****\n"));
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	/* Set all init info to zero */
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	memset(&info, 0, sizeof(struct acpi_init_walk_info));
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	info.owner_id = owner_id;
18062306a36Sopenharmony_ci	info.table_index = table_index;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	/* Walk entire namespace from the supplied root */
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	/*
18562306a36Sopenharmony_ci	 * We don't use acpi_walk_namespace since we do not want to acquire
18662306a36Sopenharmony_ci	 * the namespace reader lock.
18762306a36Sopenharmony_ci	 */
18862306a36Sopenharmony_ci	status =
18962306a36Sopenharmony_ci	    acpi_ns_walk_namespace(ACPI_TYPE_ANY, start_node, ACPI_UINT32_MAX,
19062306a36Sopenharmony_ci				   ACPI_NS_WALK_NO_UNLOCK,
19162306a36Sopenharmony_ci				   acpi_ds_init_one_object, NULL, &info, NULL);
19262306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
19362306a36Sopenharmony_ci		ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace"));
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	status = acpi_get_table_by_index(table_index, &table);
19762306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
19862306a36Sopenharmony_ci		return_ACPI_STATUS(status);
19962306a36Sopenharmony_ci	}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	/* DSDT is always the first AML table */
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	if (ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_DSDT)) {
20462306a36Sopenharmony_ci		ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
20562306a36Sopenharmony_ci				      "\nACPI table initialization:\n"));
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	/* Summary of objects initialized */
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
21162306a36Sopenharmony_ci			      "Table [%4.4s: %-8.8s] (id %.2X) - %4u Objects with %3u Devices, "
21262306a36Sopenharmony_ci			      "%3u Regions, %4u Methods (%u/%u/%u Serial/Non/Cvt)\n",
21362306a36Sopenharmony_ci			      table->signature, table->oem_table_id, owner_id,
21462306a36Sopenharmony_ci			      info.object_count, info.device_count,
21562306a36Sopenharmony_ci			      info.op_region_count, info.method_count,
21662306a36Sopenharmony_ci			      info.serial_method_count,
21762306a36Sopenharmony_ci			      info.non_serial_method_count,
21862306a36Sopenharmony_ci			      info.serialized_method_count));
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "%u Methods, %u Regions\n",
22162306a36Sopenharmony_ci			  info.method_count, info.op_region_count));
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	return_ACPI_STATUS(AE_OK);
22462306a36Sopenharmony_ci}
225