xref: /openbmc/linux/drivers/acpi/acpica/pstree.c (revision 612c2932)
195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
295b482a8SLen Brown /******************************************************************************
395b482a8SLen Brown  *
495b482a8SLen Brown  * Module Name: pstree - Parser op tree manipulation/traversal/search
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 "acparser.h"
13e2f7a777SLen Brown #include "amlcode.h"
149cf7adecSBob Moore #include "acconvert.h"
1595b482a8SLen Brown 
1695b482a8SLen Brown #define _COMPONENT          ACPI_PARSER
1795b482a8SLen Brown ACPI_MODULE_NAME("pstree")
1895b482a8SLen Brown 
1995b482a8SLen Brown /* Local prototypes */
2095b482a8SLen Brown #ifdef ACPI_OBSOLETE_FUNCTIONS
2195b482a8SLen Brown union acpi_parse_object *acpi_ps_get_child(union acpi_parse_object *op);
2295b482a8SLen Brown #endif
2395b482a8SLen Brown 
2495b482a8SLen Brown /*******************************************************************************
2595b482a8SLen Brown  *
2695b482a8SLen Brown  * FUNCTION:    acpi_ps_get_arg
2795b482a8SLen Brown  *
28ba494beeSBob Moore  * PARAMETERS:  op              - Get an argument for this op
29ba494beeSBob Moore  *              argn            - Nth argument to get
3095b482a8SLen Brown  *
3195b482a8SLen Brown  * RETURN:      The argument (as an Op object). NULL if argument does not exist
3295b482a8SLen Brown  *
3395b482a8SLen Brown  * DESCRIPTION: Get the specified op's argument.
3495b482a8SLen Brown  *
3595b482a8SLen Brown  ******************************************************************************/
3695b482a8SLen Brown 
acpi_ps_get_arg(union acpi_parse_object * op,u32 argn)3795b482a8SLen Brown union acpi_parse_object *acpi_ps_get_arg(union acpi_parse_object *op, u32 argn)
3895b482a8SLen Brown {
3995b482a8SLen Brown 	union acpi_parse_object *arg = NULL;
4095b482a8SLen Brown 	const struct acpi_opcode_info *op_info;
4195b482a8SLen Brown 
4295b482a8SLen Brown 	ACPI_FUNCTION_ENTRY();
4395b482a8SLen Brown 
449ce81784SBob Moore /*
459ce81784SBob Moore 	if (Op->Common.aml_opcode == AML_INT_CONNECTION_OP)
469ce81784SBob Moore 	{
479ce81784SBob Moore 		return (Op->Common.Value.Arg);
489ce81784SBob Moore 	}
499ce81784SBob Moore */
5095b482a8SLen Brown 	/* Get the info structure for this opcode */
5195b482a8SLen Brown 
5295b482a8SLen Brown 	op_info = acpi_ps_get_opcode_info(op->common.aml_opcode);
5395b482a8SLen Brown 	if (op_info->class == AML_CLASS_UNKNOWN) {
5495b482a8SLen Brown 
5595b482a8SLen Brown 		/* Invalid opcode or ASCII character */
5695b482a8SLen Brown 
5795b482a8SLen Brown 		return (NULL);
5895b482a8SLen Brown 	}
5995b482a8SLen Brown 
6095b482a8SLen Brown 	/* Check if this opcode requires argument sub-objects */
6195b482a8SLen Brown 
6295b482a8SLen Brown 	if (!(op_info->flags & AML_HAS_ARGS)) {
6395b482a8SLen Brown 
6495b482a8SLen Brown 		/* Has no linked argument objects */
6595b482a8SLen Brown 
6695b482a8SLen Brown 		return (NULL);
6795b482a8SLen Brown 	}
6895b482a8SLen Brown 
6995b482a8SLen Brown 	/* Get the requested argument object */
7095b482a8SLen Brown 
7195b482a8SLen Brown 	arg = op->common.value.arg;
7295b482a8SLen Brown 	while (arg && argn) {
7395b482a8SLen Brown 		argn--;
7495b482a8SLen Brown 		arg = arg->common.next;
7595b482a8SLen Brown 	}
7695b482a8SLen Brown 
7795b482a8SLen Brown 	return (arg);
7895b482a8SLen Brown }
7995b482a8SLen Brown 
8095b482a8SLen Brown /*******************************************************************************
8195b482a8SLen Brown  *
8295b482a8SLen Brown  * FUNCTION:    acpi_ps_append_arg
8395b482a8SLen Brown  *
84ba494beeSBob Moore  * PARAMETERS:  op              - Append an argument to this Op.
85ba494beeSBob Moore  *              arg             - Argument Op to append
8695b482a8SLen Brown  *
8795b482a8SLen Brown  * RETURN:      None.
8895b482a8SLen Brown  *
8995b482a8SLen Brown  * DESCRIPTION: Append an argument to an op's argument list (a NULL arg is OK)
9095b482a8SLen Brown  *
9195b482a8SLen Brown  ******************************************************************************/
9295b482a8SLen Brown 
9395b482a8SLen Brown void
acpi_ps_append_arg(union acpi_parse_object * op,union acpi_parse_object * arg)9495b482a8SLen Brown acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg)
9595b482a8SLen Brown {
9695b482a8SLen Brown 	union acpi_parse_object *prev_arg;
9795b482a8SLen Brown 	const struct acpi_opcode_info *op_info;
9895b482a8SLen Brown 
99ce87e09dSBob Moore 	ACPI_FUNCTION_TRACE(ps_append_arg);
10095b482a8SLen Brown 
10195b482a8SLen Brown 	if (!op) {
102ce87e09dSBob Moore 		return_VOID;
10395b482a8SLen Brown 	}
10495b482a8SLen Brown 
10595b482a8SLen Brown 	/* Get the info structure for this opcode */
10695b482a8SLen Brown 
10795b482a8SLen Brown 	op_info = acpi_ps_get_opcode_info(op->common.aml_opcode);
10895b482a8SLen Brown 	if (op_info->class == AML_CLASS_UNKNOWN) {
10995b482a8SLen Brown 
11095b482a8SLen Brown 		/* Invalid opcode */
11195b482a8SLen Brown 
11295b482a8SLen Brown 		ACPI_ERROR((AE_INFO, "Invalid AML Opcode: 0x%2.2X",
11395b482a8SLen Brown 			    op->common.aml_opcode));
114ce87e09dSBob Moore 		return_VOID;
11595b482a8SLen Brown 	}
11695b482a8SLen Brown 
11795b482a8SLen Brown 	/* Check if this opcode requires argument sub-objects */
11895b482a8SLen Brown 
11995b482a8SLen Brown 	if (!(op_info->flags & AML_HAS_ARGS)) {
12095b482a8SLen Brown 
12195b482a8SLen Brown 		/* Has no linked argument objects */
12295b482a8SLen Brown 
123ce87e09dSBob Moore 		return_VOID;
12495b482a8SLen Brown 	}
12595b482a8SLen Brown 
12695b482a8SLen Brown 	/* Append the argument to the linked argument list */
12795b482a8SLen Brown 
12895b482a8SLen Brown 	if (op->common.value.arg) {
12995b482a8SLen Brown 
13095b482a8SLen Brown 		/* Append to existing argument list */
13195b482a8SLen Brown 
13295b482a8SLen Brown 		prev_arg = op->common.value.arg;
13395b482a8SLen Brown 		while (prev_arg->common.next) {
13495b482a8SLen Brown 			prev_arg = prev_arg->common.next;
13595b482a8SLen Brown 		}
13695b482a8SLen Brown 		prev_arg->common.next = arg;
13795b482a8SLen Brown 	} else {
13895b482a8SLen Brown 		/* No argument list, this will be the first argument */
13995b482a8SLen Brown 
14095b482a8SLen Brown 		op->common.value.arg = arg;
14195b482a8SLen Brown 	}
14295b482a8SLen Brown 
14395b482a8SLen Brown 	/* Set the parent in this arg and any args linked after it */
14495b482a8SLen Brown 
14595b482a8SLen Brown 	while (arg) {
14695b482a8SLen Brown 		arg->common.parent = op;
14795b482a8SLen Brown 		arg = arg->common.next;
14895b482a8SLen Brown 
14995b482a8SLen Brown 		op->common.arg_list_length++;
15095b482a8SLen Brown 	}
151ce87e09dSBob Moore 
152ce87e09dSBob Moore 	return_VOID;
15395b482a8SLen Brown }
15495b482a8SLen Brown 
15595b482a8SLen Brown /*******************************************************************************
15695b482a8SLen Brown  *
15795b482a8SLen Brown  * FUNCTION:    acpi_ps_get_depth_next
15895b482a8SLen Brown  *
159ba494beeSBob Moore  * PARAMETERS:  origin          - Root of subtree to search
160ba494beeSBob Moore  *              op              - Last (previous) Op that was found
16195b482a8SLen Brown  *
16295b482a8SLen Brown  * RETURN:      Next Op found in the search.
16395b482a8SLen Brown  *
16495b482a8SLen Brown  * DESCRIPTION: Get next op in tree (walking the tree in depth-first order)
16595b482a8SLen Brown  *              Return NULL when reaching "origin" or when walking up from root
16695b482a8SLen Brown  *
16795b482a8SLen Brown  ******************************************************************************/
16895b482a8SLen Brown 
acpi_ps_get_depth_next(union acpi_parse_object * origin,union acpi_parse_object * op)16995b482a8SLen Brown union acpi_parse_object *acpi_ps_get_depth_next(union acpi_parse_object *origin,
17095b482a8SLen Brown 						union acpi_parse_object *op)
17195b482a8SLen Brown {
17295b482a8SLen Brown 	union acpi_parse_object *next = NULL;
17395b482a8SLen Brown 	union acpi_parse_object *parent;
17495b482a8SLen Brown 	union acpi_parse_object *arg;
17595b482a8SLen Brown 
17695b482a8SLen Brown 	ACPI_FUNCTION_ENTRY();
17795b482a8SLen Brown 
17895b482a8SLen Brown 	if (!op) {
17995b482a8SLen Brown 		return (NULL);
18095b482a8SLen Brown 	}
18195b482a8SLen Brown 
18295b482a8SLen Brown 	/* Look for an argument or child */
18395b482a8SLen Brown 
18495b482a8SLen Brown 	next = acpi_ps_get_arg(op, 0);
18595b482a8SLen Brown 	if (next) {
1869cf7adecSBob Moore 		ASL_CV_LABEL_FILENODE(next);
18795b482a8SLen Brown 		return (next);
18895b482a8SLen Brown 	}
18995b482a8SLen Brown 
19095b482a8SLen Brown 	/* Look for a sibling */
19195b482a8SLen Brown 
19295b482a8SLen Brown 	next = op->common.next;
19395b482a8SLen Brown 	if (next) {
1949cf7adecSBob Moore 		ASL_CV_LABEL_FILENODE(next);
19595b482a8SLen Brown 		return (next);
19695b482a8SLen Brown 	}
19795b482a8SLen Brown 
19895b482a8SLen Brown 	/* Look for a sibling of parent */
19995b482a8SLen Brown 
20095b482a8SLen Brown 	parent = op->common.parent;
20195b482a8SLen Brown 
20295b482a8SLen Brown 	while (parent) {
20395b482a8SLen Brown 		arg = acpi_ps_get_arg(parent, 0);
20495b482a8SLen Brown 		while (arg && (arg != origin) && (arg != op)) {
2059cf7adecSBob Moore 
2069cf7adecSBob Moore 			ASL_CV_LABEL_FILENODE(arg);
20795b482a8SLen Brown 			arg = arg->common.next;
20895b482a8SLen Brown 		}
20995b482a8SLen Brown 
21095b482a8SLen Brown 		if (arg == origin) {
21195b482a8SLen Brown 
21295b482a8SLen Brown 			/* Reached parent of origin, end search */
21395b482a8SLen Brown 
21495b482a8SLen Brown 			return (NULL);
21595b482a8SLen Brown 		}
21695b482a8SLen Brown 
21795b482a8SLen Brown 		if (parent->common.next) {
21895b482a8SLen Brown 
21995b482a8SLen Brown 			/* Found sibling of parent */
22095b482a8SLen Brown 
2219cf7adecSBob Moore 			ASL_CV_LABEL_FILENODE(parent->common.next);
22295b482a8SLen Brown 			return (parent->common.next);
22395b482a8SLen Brown 		}
22495b482a8SLen Brown 
22595b482a8SLen Brown 		op = parent;
22695b482a8SLen Brown 		parent = parent->common.parent;
22795b482a8SLen Brown 	}
22895b482a8SLen Brown 
2299cf7adecSBob Moore 	ASL_CV_LABEL_FILENODE(next);
23095b482a8SLen Brown 	return (next);
23195b482a8SLen Brown }
23295b482a8SLen Brown 
23395b482a8SLen Brown #ifdef ACPI_OBSOLETE_FUNCTIONS
23495b482a8SLen Brown /*******************************************************************************
23595b482a8SLen Brown  *
23695b482a8SLen Brown  * FUNCTION:    acpi_ps_get_child
23795b482a8SLen Brown  *
238ba494beeSBob Moore  * PARAMETERS:  op              - Get the child of this Op
23995b482a8SLen Brown  *
24095b482a8SLen Brown  * RETURN:      Child Op, Null if none is found.
24195b482a8SLen Brown  *
24295b482a8SLen Brown  * DESCRIPTION: Get op's children or NULL if none
24395b482a8SLen Brown  *
24495b482a8SLen Brown  ******************************************************************************/
24595b482a8SLen Brown 
acpi_ps_get_child(union acpi_parse_object * op)24695b482a8SLen Brown union acpi_parse_object *acpi_ps_get_child(union acpi_parse_object *op)
24795b482a8SLen Brown {
24895b482a8SLen Brown 	union acpi_parse_object *child = NULL;
24995b482a8SLen Brown 
25095b482a8SLen Brown 	ACPI_FUNCTION_ENTRY();
25195b482a8SLen Brown 
25295b482a8SLen Brown 	switch (op->common.aml_opcode) {
25395b482a8SLen Brown 	case AML_SCOPE_OP:
25495b482a8SLen Brown 	case AML_ELSE_OP:
25595b482a8SLen Brown 	case AML_DEVICE_OP:
25695b482a8SLen Brown 	case AML_THERMAL_ZONE_OP:
25795b482a8SLen Brown 	case AML_INT_METHODCALL_OP:
25895b482a8SLen Brown 
25995b482a8SLen Brown 		child = acpi_ps_get_arg(op, 0);
26095b482a8SLen Brown 		break;
26195b482a8SLen Brown 
26295b482a8SLen Brown 	case AML_BUFFER_OP:
26395b482a8SLen Brown 	case AML_PACKAGE_OP:
2645a8361f7SSchmauss, Erik 	case AML_VARIABLE_PACKAGE_OP:
26595b482a8SLen Brown 	case AML_METHOD_OP:
26695b482a8SLen Brown 	case AML_IF_OP:
26795b482a8SLen Brown 	case AML_WHILE_OP:
26895b482a8SLen Brown 	case AML_FIELD_OP:
26995b482a8SLen Brown 
27095b482a8SLen Brown 		child = acpi_ps_get_arg(op, 1);
27195b482a8SLen Brown 		break;
27295b482a8SLen Brown 
2739ff5a21aSBob Moore 	case AML_POWER_RESOURCE_OP:
27495b482a8SLen Brown 	case AML_INDEX_FIELD_OP:
27595b482a8SLen Brown 
27695b482a8SLen Brown 		child = acpi_ps_get_arg(op, 2);
27795b482a8SLen Brown 		break;
27895b482a8SLen Brown 
27995b482a8SLen Brown 	case AML_PROCESSOR_OP:
28095b482a8SLen Brown 	case AML_BANK_FIELD_OP:
28195b482a8SLen Brown 
28295b482a8SLen Brown 		child = acpi_ps_get_arg(op, 3);
28395b482a8SLen Brown 		break;
28495b482a8SLen Brown 
28595b482a8SLen Brown 	default:
2861d1ea1b7SChao Guan 
28795b482a8SLen Brown 		/* All others have no children */
2881d1ea1b7SChao Guan 
28995b482a8SLen Brown 		break;
29095b482a8SLen Brown 	}
29195b482a8SLen Brown 
29295b482a8SLen Brown 	return (child);
29395b482a8SLen Brown }
29495b482a8SLen Brown #endif
295