162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: nsrepair2 - Repair for objects returned by specific
562306a36Sopenharmony_ci *                          predefined methods
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *****************************************************************************/
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <acpi/acpi.h>
1262306a36Sopenharmony_ci#include "accommon.h"
1362306a36Sopenharmony_ci#include "acnamesp.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define _COMPONENT          ACPI_NAMESPACE
1662306a36Sopenharmony_ciACPI_MODULE_NAME("nsrepair2")
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/*
1962306a36Sopenharmony_ci * Information structure and handler for ACPI predefined names that can
2062306a36Sopenharmony_ci * be repaired on a per-name basis.
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_citypedef
2362306a36Sopenharmony_ciacpi_status (*acpi_repair_function) (struct acpi_evaluate_info * info,
2462306a36Sopenharmony_ci				     union acpi_operand_object **
2562306a36Sopenharmony_ci				     return_object_ptr);
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_citypedef struct acpi_repair_info {
2862306a36Sopenharmony_ci	char name[ACPI_NAMESEG_SIZE];
2962306a36Sopenharmony_ci	acpi_repair_function repair_function;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci} acpi_repair_info;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/* Local prototypes */
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
3662306a36Sopenharmony_ci								   acpi_namespace_node
3762306a36Sopenharmony_ci								   *node);
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic acpi_status
4062306a36Sopenharmony_ciacpi_ns_repair_ALR(struct acpi_evaluate_info *info,
4162306a36Sopenharmony_ci		   union acpi_operand_object **return_object_ptr);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic acpi_status
4462306a36Sopenharmony_ciacpi_ns_repair_CID(struct acpi_evaluate_info *info,
4562306a36Sopenharmony_ci		   union acpi_operand_object **return_object_ptr);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic acpi_status
4862306a36Sopenharmony_ciacpi_ns_repair_CST(struct acpi_evaluate_info *info,
4962306a36Sopenharmony_ci		   union acpi_operand_object **return_object_ptr);
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic acpi_status
5262306a36Sopenharmony_ciacpi_ns_repair_FDE(struct acpi_evaluate_info *info,
5362306a36Sopenharmony_ci		   union acpi_operand_object **return_object_ptr);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic acpi_status
5662306a36Sopenharmony_ciacpi_ns_repair_HID(struct acpi_evaluate_info *info,
5762306a36Sopenharmony_ci		   union acpi_operand_object **return_object_ptr);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic acpi_status
6062306a36Sopenharmony_ciacpi_ns_repair_PRT(struct acpi_evaluate_info *info,
6162306a36Sopenharmony_ci		   union acpi_operand_object **return_object_ptr);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic acpi_status
6462306a36Sopenharmony_ciacpi_ns_repair_PSS(struct acpi_evaluate_info *info,
6562306a36Sopenharmony_ci		   union acpi_operand_object **return_object_ptr);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic acpi_status
6862306a36Sopenharmony_ciacpi_ns_repair_TSS(struct acpi_evaluate_info *info,
6962306a36Sopenharmony_ci		   union acpi_operand_object **return_object_ptr);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic acpi_status
7262306a36Sopenharmony_ciacpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
7362306a36Sopenharmony_ci			  union acpi_operand_object *return_object,
7462306a36Sopenharmony_ci			  u32 start_index,
7562306a36Sopenharmony_ci			  u32 expected_count,
7662306a36Sopenharmony_ci			  u32 sort_index,
7762306a36Sopenharmony_ci			  u8 sort_direction, char *sort_key_name);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/* Values for sort_direction above */
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#define ACPI_SORT_ASCENDING     0
8262306a36Sopenharmony_ci#define ACPI_SORT_DESCENDING    1
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic void
8562306a36Sopenharmony_ciacpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic void
8862306a36Sopenharmony_ciacpi_ns_sort_list(union acpi_operand_object **elements,
8962306a36Sopenharmony_ci		  u32 count, u32 index, u8 sort_direction);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/*
9262306a36Sopenharmony_ci * This table contains the names of the predefined methods for which we can
9362306a36Sopenharmony_ci * perform more complex repairs.
9462306a36Sopenharmony_ci *
9562306a36Sopenharmony_ci * As necessary:
9662306a36Sopenharmony_ci *
9762306a36Sopenharmony_ci * _ALR: Sort the list ascending by ambient_illuminance
9862306a36Sopenharmony_ci * _CID: Strings: uppercase all, remove any leading asterisk
9962306a36Sopenharmony_ci * _CST: Sort the list ascending by C state type
10062306a36Sopenharmony_ci * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs
10162306a36Sopenharmony_ci * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs
10262306a36Sopenharmony_ci * _HID: Strings: uppercase all, remove any leading asterisk
10362306a36Sopenharmony_ci * _PRT: Fix reversed source_name and source_index
10462306a36Sopenharmony_ci * _PSS: Sort the list descending by Power
10562306a36Sopenharmony_ci * _TSS: Sort the list descending by Power
10662306a36Sopenharmony_ci *
10762306a36Sopenharmony_ci * Names that must be packages, but cannot be sorted:
10862306a36Sopenharmony_ci *
10962306a36Sopenharmony_ci * _BCL: Values are tied to the Package index where they appear, and cannot
11062306a36Sopenharmony_ci * be moved or sorted. These index values are used for _BQC and _BCM.
11162306a36Sopenharmony_ci * However, we can fix the case where a buffer is returned, by converting
11262306a36Sopenharmony_ci * it to a Package of integers.
11362306a36Sopenharmony_ci */
11462306a36Sopenharmony_cistatic const struct acpi_repair_info acpi_ns_repairable_names[] = {
11562306a36Sopenharmony_ci	{"_ALR", acpi_ns_repair_ALR},
11662306a36Sopenharmony_ci	{"_CID", acpi_ns_repair_CID},
11762306a36Sopenharmony_ci	{"_CST", acpi_ns_repair_CST},
11862306a36Sopenharmony_ci	{"_FDE", acpi_ns_repair_FDE},
11962306a36Sopenharmony_ci	{"_GTM", acpi_ns_repair_FDE},	/* _GTM has same repair as _FDE */
12062306a36Sopenharmony_ci	{"_HID", acpi_ns_repair_HID},
12162306a36Sopenharmony_ci	{"_PRT", acpi_ns_repair_PRT},
12262306a36Sopenharmony_ci	{"_PSS", acpi_ns_repair_PSS},
12362306a36Sopenharmony_ci	{"_TSS", acpi_ns_repair_TSS},
12462306a36Sopenharmony_ci	{{0, 0, 0, 0}, NULL}	/* Table terminator */
12562306a36Sopenharmony_ci};
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci#define ACPI_FDE_FIELD_COUNT        5
12862306a36Sopenharmony_ci#define ACPI_FDE_BYTE_BUFFER_SIZE   5
12962306a36Sopenharmony_ci#define ACPI_FDE_DWORD_BUFFER_SIZE  (ACPI_FDE_FIELD_COUNT * (u32) sizeof (u32))
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci/******************************************************************************
13262306a36Sopenharmony_ci *
13362306a36Sopenharmony_ci * FUNCTION:    acpi_ns_complex_repairs
13462306a36Sopenharmony_ci *
13562306a36Sopenharmony_ci * PARAMETERS:  info                - Method execution information block
13662306a36Sopenharmony_ci *              node                - Namespace node for the method/object
13762306a36Sopenharmony_ci *              validate_status     - Original status of earlier validation
13862306a36Sopenharmony_ci *              return_object_ptr   - Pointer to the object returned from the
13962306a36Sopenharmony_ci *                                    evaluation of a method or object
14062306a36Sopenharmony_ci *
14162306a36Sopenharmony_ci * RETURN:      Status. AE_OK if repair was successful. If name is not
14262306a36Sopenharmony_ci *              matched, validate_status is returned.
14362306a36Sopenharmony_ci *
14462306a36Sopenharmony_ci * DESCRIPTION: Attempt to repair/convert a return object of a type that was
14562306a36Sopenharmony_ci *              not expected.
14662306a36Sopenharmony_ci *
14762306a36Sopenharmony_ci *****************************************************************************/
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ciacpi_status
15062306a36Sopenharmony_ciacpi_ns_complex_repairs(struct acpi_evaluate_info *info,
15162306a36Sopenharmony_ci			struct acpi_namespace_node *node,
15262306a36Sopenharmony_ci			acpi_status validate_status,
15362306a36Sopenharmony_ci			union acpi_operand_object **return_object_ptr)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	const struct acpi_repair_info *predefined;
15662306a36Sopenharmony_ci	acpi_status status;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ns_complex_repairs);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	/* Check if this name is in the list of repairable names */
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	predefined = acpi_ns_match_complex_repair(node);
16362306a36Sopenharmony_ci	if (!predefined) {
16462306a36Sopenharmony_ci		return_ACPI_STATUS(validate_status);
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	status = predefined->repair_function(info, return_object_ptr);
16862306a36Sopenharmony_ci	return_ACPI_STATUS(status);
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci/******************************************************************************
17262306a36Sopenharmony_ci *
17362306a36Sopenharmony_ci * FUNCTION:    acpi_ns_match_complex_repair
17462306a36Sopenharmony_ci *
17562306a36Sopenharmony_ci * PARAMETERS:  node                - Namespace node for the method/object
17662306a36Sopenharmony_ci *
17762306a36Sopenharmony_ci * RETURN:      Pointer to entry in repair table. NULL indicates not found.
17862306a36Sopenharmony_ci *
17962306a36Sopenharmony_ci * DESCRIPTION: Check an object name against the repairable object list.
18062306a36Sopenharmony_ci *
18162306a36Sopenharmony_ci *****************************************************************************/
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
18462306a36Sopenharmony_ci								   acpi_namespace_node
18562306a36Sopenharmony_ci								   *node)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	const struct acpi_repair_info *this_name;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	/* Search info table for a repairable predefined method/object name */
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	this_name = acpi_ns_repairable_names;
19262306a36Sopenharmony_ci	while (this_name->repair_function) {
19362306a36Sopenharmony_ci		if (ACPI_COMPARE_NAMESEG(node->name.ascii, this_name->name)) {
19462306a36Sopenharmony_ci			return (this_name);
19562306a36Sopenharmony_ci		}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci		this_name++;
19862306a36Sopenharmony_ci	}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	return (NULL);		/* Not found */
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci/******************************************************************************
20462306a36Sopenharmony_ci *
20562306a36Sopenharmony_ci * FUNCTION:    acpi_ns_repair_ALR
20662306a36Sopenharmony_ci *
20762306a36Sopenharmony_ci * PARAMETERS:  info                - Method execution information block
20862306a36Sopenharmony_ci *              return_object_ptr   - Pointer to the object returned from the
20962306a36Sopenharmony_ci *                                    evaluation of a method or object
21062306a36Sopenharmony_ci *
21162306a36Sopenharmony_ci * RETURN:      Status. AE_OK if object is OK or was repaired successfully
21262306a36Sopenharmony_ci *
21362306a36Sopenharmony_ci * DESCRIPTION: Repair for the _ALR object. If necessary, sort the object list
21462306a36Sopenharmony_ci *              ascending by the ambient illuminance values.
21562306a36Sopenharmony_ci *
21662306a36Sopenharmony_ci *****************************************************************************/
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic acpi_status
21962306a36Sopenharmony_ciacpi_ns_repair_ALR(struct acpi_evaluate_info *info,
22062306a36Sopenharmony_ci		   union acpi_operand_object **return_object_ptr)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	union acpi_operand_object *return_object = *return_object_ptr;
22362306a36Sopenharmony_ci	acpi_status status;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	status = acpi_ns_check_sorted_list(info, return_object, 0, 2, 1,
22662306a36Sopenharmony_ci					   ACPI_SORT_ASCENDING,
22762306a36Sopenharmony_ci					   "AmbientIlluminance");
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	return (status);
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci/******************************************************************************
23362306a36Sopenharmony_ci *
23462306a36Sopenharmony_ci * FUNCTION:    acpi_ns_repair_FDE
23562306a36Sopenharmony_ci *
23662306a36Sopenharmony_ci * PARAMETERS:  info                - Method execution information block
23762306a36Sopenharmony_ci *              return_object_ptr   - Pointer to the object returned from the
23862306a36Sopenharmony_ci *                                    evaluation of a method or object
23962306a36Sopenharmony_ci *
24062306a36Sopenharmony_ci * RETURN:      Status. AE_OK if object is OK or was repaired successfully
24162306a36Sopenharmony_ci *
24262306a36Sopenharmony_ci * DESCRIPTION: Repair for the _FDE and _GTM objects. The expected return
24362306a36Sopenharmony_ci *              value is a Buffer of 5 DWORDs. This function repairs a common
24462306a36Sopenharmony_ci *              problem where the return value is a Buffer of BYTEs, not
24562306a36Sopenharmony_ci *              DWORDs.
24662306a36Sopenharmony_ci *
24762306a36Sopenharmony_ci *****************************************************************************/
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic acpi_status
25062306a36Sopenharmony_ciacpi_ns_repair_FDE(struct acpi_evaluate_info *info,
25162306a36Sopenharmony_ci		   union acpi_operand_object **return_object_ptr)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	union acpi_operand_object *return_object = *return_object_ptr;
25462306a36Sopenharmony_ci	union acpi_operand_object *buffer_object;
25562306a36Sopenharmony_ci	u8 *byte_buffer;
25662306a36Sopenharmony_ci	u32 *dword_buffer;
25762306a36Sopenharmony_ci	u32 i;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ns_repair_FDE);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	switch (return_object->common.type) {
26262306a36Sopenharmony_ci	case ACPI_TYPE_BUFFER:
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci		/* This is the expected type. Length should be (at least) 5 DWORDs */
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci		if (return_object->buffer.length >= ACPI_FDE_DWORD_BUFFER_SIZE) {
26762306a36Sopenharmony_ci			return (AE_OK);
26862306a36Sopenharmony_ci		}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci		/* We can only repair if we have exactly 5 BYTEs */
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci		if (return_object->buffer.length != ACPI_FDE_BYTE_BUFFER_SIZE) {
27362306a36Sopenharmony_ci			ACPI_WARN_PREDEFINED((AE_INFO,
27462306a36Sopenharmony_ci					      info->full_pathname,
27562306a36Sopenharmony_ci					      info->node_flags,
27662306a36Sopenharmony_ci					      "Incorrect return buffer length %u, expected %u",
27762306a36Sopenharmony_ci					      return_object->buffer.length,
27862306a36Sopenharmony_ci					      ACPI_FDE_DWORD_BUFFER_SIZE));
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci			return (AE_AML_OPERAND_TYPE);
28162306a36Sopenharmony_ci		}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci		/* Create the new (larger) buffer object */
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci		buffer_object =
28662306a36Sopenharmony_ci		    acpi_ut_create_buffer_object(ACPI_FDE_DWORD_BUFFER_SIZE);
28762306a36Sopenharmony_ci		if (!buffer_object) {
28862306a36Sopenharmony_ci			return (AE_NO_MEMORY);
28962306a36Sopenharmony_ci		}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci		/* Expand each byte to a DWORD */
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci		byte_buffer = return_object->buffer.pointer;
29462306a36Sopenharmony_ci		dword_buffer = ACPI_CAST_PTR(u32,
29562306a36Sopenharmony_ci					     buffer_object->buffer.pointer);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci		for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++) {
29862306a36Sopenharmony_ci			*dword_buffer = (u32) *byte_buffer;
29962306a36Sopenharmony_ci			dword_buffer++;
30062306a36Sopenharmony_ci			byte_buffer++;
30162306a36Sopenharmony_ci		}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
30462306a36Sopenharmony_ci				  "%s Expanded Byte Buffer to expected DWord Buffer\n",
30562306a36Sopenharmony_ci				  info->full_pathname));
30662306a36Sopenharmony_ci		break;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	default:
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci		return (AE_AML_OPERAND_TYPE);
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	/* Delete the original return object, return the new buffer object */
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	acpi_ut_remove_reference(return_object);
31662306a36Sopenharmony_ci	*return_object_ptr = buffer_object;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	info->return_flags |= ACPI_OBJECT_REPAIRED;
31962306a36Sopenharmony_ci	return (AE_OK);
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci/******************************************************************************
32362306a36Sopenharmony_ci *
32462306a36Sopenharmony_ci * FUNCTION:    acpi_ns_repair_CID
32562306a36Sopenharmony_ci *
32662306a36Sopenharmony_ci * PARAMETERS:  info                - Method execution information block
32762306a36Sopenharmony_ci *              return_object_ptr   - Pointer to the object returned from the
32862306a36Sopenharmony_ci *                                    evaluation of a method or object
32962306a36Sopenharmony_ci *
33062306a36Sopenharmony_ci * RETURN:      Status. AE_OK if object is OK or was repaired successfully
33162306a36Sopenharmony_ci *
33262306a36Sopenharmony_ci * DESCRIPTION: Repair for the _CID object. If a string, ensure that all
33362306a36Sopenharmony_ci *              letters are uppercase and that there is no leading asterisk.
33462306a36Sopenharmony_ci *              If a Package, ensure same for all string elements.
33562306a36Sopenharmony_ci *
33662306a36Sopenharmony_ci *****************************************************************************/
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_cistatic acpi_status
33962306a36Sopenharmony_ciacpi_ns_repair_CID(struct acpi_evaluate_info *info,
34062306a36Sopenharmony_ci		   union acpi_operand_object **return_object_ptr)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	acpi_status status;
34362306a36Sopenharmony_ci	union acpi_operand_object *return_object = *return_object_ptr;
34462306a36Sopenharmony_ci	union acpi_operand_object **element_ptr;
34562306a36Sopenharmony_ci	union acpi_operand_object *original_element;
34662306a36Sopenharmony_ci	u16 original_ref_count;
34762306a36Sopenharmony_ci	u32 i;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ns_repair_CID);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	/* Check for _CID as a simple string */
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	if (return_object->common.type == ACPI_TYPE_STRING) {
35462306a36Sopenharmony_ci		status = acpi_ns_repair_HID(info, return_object_ptr);
35562306a36Sopenharmony_ci		return_ACPI_STATUS(status);
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	/* Exit if not a Package */
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	if (return_object->common.type != ACPI_TYPE_PACKAGE) {
36162306a36Sopenharmony_ci		return_ACPI_STATUS(AE_OK);
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	/* Examine each element of the _CID package */
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	element_ptr = return_object->package.elements;
36762306a36Sopenharmony_ci	for (i = 0; i < return_object->package.count; i++) {
36862306a36Sopenharmony_ci		original_element = *element_ptr;
36962306a36Sopenharmony_ci		original_ref_count = original_element->common.reference_count;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci		status = acpi_ns_repair_HID(info, element_ptr);
37262306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
37362306a36Sopenharmony_ci			return_ACPI_STATUS(status);
37462306a36Sopenharmony_ci		}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci		if (original_element != *element_ptr) {
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci			/* Update reference count of new object */
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci			(*element_ptr)->common.reference_count =
38162306a36Sopenharmony_ci			    original_ref_count;
38262306a36Sopenharmony_ci		}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci		element_ptr++;
38562306a36Sopenharmony_ci	}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	return_ACPI_STATUS(AE_OK);
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci/******************************************************************************
39162306a36Sopenharmony_ci *
39262306a36Sopenharmony_ci * FUNCTION:    acpi_ns_repair_CST
39362306a36Sopenharmony_ci *
39462306a36Sopenharmony_ci * PARAMETERS:  info                - Method execution information block
39562306a36Sopenharmony_ci *              return_object_ptr   - Pointer to the object returned from the
39662306a36Sopenharmony_ci *                                    evaluation of a method or object
39762306a36Sopenharmony_ci *
39862306a36Sopenharmony_ci * RETURN:      Status. AE_OK if object is OK or was repaired successfully
39962306a36Sopenharmony_ci *
40062306a36Sopenharmony_ci * DESCRIPTION: Repair for the _CST object:
40162306a36Sopenharmony_ci *              1. Sort the list ascending by C state type
40262306a36Sopenharmony_ci *              2. Ensure type cannot be zero
40362306a36Sopenharmony_ci *              3. A subpackage count of zero means _CST is meaningless
40462306a36Sopenharmony_ci *              4. Count must match the number of C state subpackages
40562306a36Sopenharmony_ci *
40662306a36Sopenharmony_ci *****************************************************************************/
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_cistatic acpi_status
40962306a36Sopenharmony_ciacpi_ns_repair_CST(struct acpi_evaluate_info *info,
41062306a36Sopenharmony_ci		   union acpi_operand_object **return_object_ptr)
41162306a36Sopenharmony_ci{
41262306a36Sopenharmony_ci	union acpi_operand_object *return_object = *return_object_ptr;
41362306a36Sopenharmony_ci	union acpi_operand_object **outer_elements;
41462306a36Sopenharmony_ci	u32 outer_element_count;
41562306a36Sopenharmony_ci	union acpi_operand_object *obj_desc;
41662306a36Sopenharmony_ci	acpi_status status;
41762306a36Sopenharmony_ci	u8 removing;
41862306a36Sopenharmony_ci	u32 i;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ns_repair_CST);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	/*
42362306a36Sopenharmony_ci	 * Check if the C-state type values are proportional.
42462306a36Sopenharmony_ci	 */
42562306a36Sopenharmony_ci	outer_element_count = return_object->package.count - 1;
42662306a36Sopenharmony_ci	i = 0;
42762306a36Sopenharmony_ci	while (i < outer_element_count) {
42862306a36Sopenharmony_ci		outer_elements = &return_object->package.elements[i + 1];
42962306a36Sopenharmony_ci		removing = FALSE;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci		if ((*outer_elements)->package.count == 0) {
43262306a36Sopenharmony_ci			ACPI_WARN_PREDEFINED((AE_INFO,
43362306a36Sopenharmony_ci					      info->full_pathname,
43462306a36Sopenharmony_ci					      info->node_flags,
43562306a36Sopenharmony_ci					      "SubPackage[%u] - removing entry due to zero count",
43662306a36Sopenharmony_ci					      i));
43762306a36Sopenharmony_ci			removing = TRUE;
43862306a36Sopenharmony_ci			goto remove_element;
43962306a36Sopenharmony_ci		}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci		obj_desc = (*outer_elements)->package.elements[1];	/* Index1 = Type */
44262306a36Sopenharmony_ci		if ((u32)obj_desc->integer.value == 0) {
44362306a36Sopenharmony_ci			ACPI_WARN_PREDEFINED((AE_INFO,
44462306a36Sopenharmony_ci					      info->full_pathname,
44562306a36Sopenharmony_ci					      info->node_flags,
44662306a36Sopenharmony_ci					      "SubPackage[%u] - removing entry due to invalid Type(0)",
44762306a36Sopenharmony_ci					      i));
44862306a36Sopenharmony_ci			removing = TRUE;
44962306a36Sopenharmony_ci		}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ciremove_element:
45262306a36Sopenharmony_ci		if (removing) {
45362306a36Sopenharmony_ci			acpi_ns_remove_element(return_object, i + 1);
45462306a36Sopenharmony_ci			outer_element_count--;
45562306a36Sopenharmony_ci		} else {
45662306a36Sopenharmony_ci			i++;
45762306a36Sopenharmony_ci		}
45862306a36Sopenharmony_ci	}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	/* Update top-level package count, Type "Integer" checked elsewhere */
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	obj_desc = return_object->package.elements[0];
46362306a36Sopenharmony_ci	obj_desc->integer.value = outer_element_count;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	/*
46662306a36Sopenharmony_ci	 * Entries (subpackages) in the _CST Package must be sorted by the
46762306a36Sopenharmony_ci	 * C-state type, in ascending order.
46862306a36Sopenharmony_ci	 */
46962306a36Sopenharmony_ci	status = acpi_ns_check_sorted_list(info, return_object, 1, 4, 1,
47062306a36Sopenharmony_ci					   ACPI_SORT_ASCENDING, "C-State Type");
47162306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
47262306a36Sopenharmony_ci		return (status);
47362306a36Sopenharmony_ci	}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	return (AE_OK);
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci/******************************************************************************
47962306a36Sopenharmony_ci *
48062306a36Sopenharmony_ci * FUNCTION:    acpi_ns_repair_HID
48162306a36Sopenharmony_ci *
48262306a36Sopenharmony_ci * PARAMETERS:  info                - Method execution information block
48362306a36Sopenharmony_ci *              return_object_ptr   - Pointer to the object returned from the
48462306a36Sopenharmony_ci *                                    evaluation of a method or object
48562306a36Sopenharmony_ci *
48662306a36Sopenharmony_ci * RETURN:      Status. AE_OK if object is OK or was repaired successfully
48762306a36Sopenharmony_ci *
48862306a36Sopenharmony_ci * DESCRIPTION: Repair for the _HID object. If a string, ensure that all
48962306a36Sopenharmony_ci *              letters are uppercase and that there is no leading asterisk.
49062306a36Sopenharmony_ci *
49162306a36Sopenharmony_ci *****************************************************************************/
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic acpi_status
49462306a36Sopenharmony_ciacpi_ns_repair_HID(struct acpi_evaluate_info *info,
49562306a36Sopenharmony_ci		   union acpi_operand_object **return_object_ptr)
49662306a36Sopenharmony_ci{
49762306a36Sopenharmony_ci	union acpi_operand_object *return_object = *return_object_ptr;
49862306a36Sopenharmony_ci	union acpi_operand_object *new_string;
49962306a36Sopenharmony_ci	char *source;
50062306a36Sopenharmony_ci	char *dest;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ns_repair_HID);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	/* We only care about string _HID objects (not integers) */
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	if (return_object->common.type != ACPI_TYPE_STRING) {
50762306a36Sopenharmony_ci		return_ACPI_STATUS(AE_OK);
50862306a36Sopenharmony_ci	}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	if (return_object->string.length == 0) {
51162306a36Sopenharmony_ci		ACPI_WARN_PREDEFINED((AE_INFO,
51262306a36Sopenharmony_ci				      info->full_pathname, info->node_flags,
51362306a36Sopenharmony_ci				      "Invalid zero-length _HID or _CID string"));
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci		/* Return AE_OK anyway, let driver handle it */
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci		info->return_flags |= ACPI_OBJECT_REPAIRED;
51862306a36Sopenharmony_ci		return_ACPI_STATUS(AE_OK);
51962306a36Sopenharmony_ci	}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	/* It is simplest to always create a new string object */
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	new_string = acpi_ut_create_string_object(return_object->string.length);
52462306a36Sopenharmony_ci	if (!new_string) {
52562306a36Sopenharmony_ci		return_ACPI_STATUS(AE_NO_MEMORY);
52662306a36Sopenharmony_ci	}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	/*
52962306a36Sopenharmony_ci	 * Remove a leading asterisk if present. For some unknown reason, there
53062306a36Sopenharmony_ci	 * are many machines in the field that contains IDs like this.
53162306a36Sopenharmony_ci	 *
53262306a36Sopenharmony_ci	 * Examples: "*PNP0C03", "*ACPI0003"
53362306a36Sopenharmony_ci	 */
53462306a36Sopenharmony_ci	source = return_object->string.pointer;
53562306a36Sopenharmony_ci	if (*source == '*') {
53662306a36Sopenharmony_ci		source++;
53762306a36Sopenharmony_ci		new_string->string.length--;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
54062306a36Sopenharmony_ci				  "%s: Removed invalid leading asterisk\n",
54162306a36Sopenharmony_ci				  info->full_pathname));
54262306a36Sopenharmony_ci	}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	/*
54562306a36Sopenharmony_ci	 * Copy and uppercase the string. From the ACPI 5.0 specification:
54662306a36Sopenharmony_ci	 *
54762306a36Sopenharmony_ci	 * A valid PNP ID must be of the form "AAA####" where A is an uppercase
54862306a36Sopenharmony_ci	 * letter and # is a hex digit. A valid ACPI ID must be of the form
54962306a36Sopenharmony_ci	 * "NNNN####" where N is an uppercase letter or decimal digit, and
55062306a36Sopenharmony_ci	 * # is a hex digit.
55162306a36Sopenharmony_ci	 */
55262306a36Sopenharmony_ci	for (dest = new_string->string.pointer; *source; dest++, source++) {
55362306a36Sopenharmony_ci		*dest = (char)toupper((int)*source);
55462306a36Sopenharmony_ci	}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	acpi_ut_remove_reference(return_object);
55762306a36Sopenharmony_ci	*return_object_ptr = new_string;
55862306a36Sopenharmony_ci	return_ACPI_STATUS(AE_OK);
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci/******************************************************************************
56262306a36Sopenharmony_ci *
56362306a36Sopenharmony_ci * FUNCTION:    acpi_ns_repair_PRT
56462306a36Sopenharmony_ci *
56562306a36Sopenharmony_ci * PARAMETERS:  info                - Method execution information block
56662306a36Sopenharmony_ci *              return_object_ptr   - Pointer to the object returned from the
56762306a36Sopenharmony_ci *                                    evaluation of a method or object
56862306a36Sopenharmony_ci *
56962306a36Sopenharmony_ci * RETURN:      Status. AE_OK if object is OK or was repaired successfully
57062306a36Sopenharmony_ci *
57162306a36Sopenharmony_ci * DESCRIPTION: Repair for the _PRT object. If necessary, fix reversed
57262306a36Sopenharmony_ci *              source_name and source_index field, a common BIOS bug.
57362306a36Sopenharmony_ci *
57462306a36Sopenharmony_ci *****************************************************************************/
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_cistatic acpi_status
57762306a36Sopenharmony_ciacpi_ns_repair_PRT(struct acpi_evaluate_info *info,
57862306a36Sopenharmony_ci		   union acpi_operand_object **return_object_ptr)
57962306a36Sopenharmony_ci{
58062306a36Sopenharmony_ci	union acpi_operand_object *package_object = *return_object_ptr;
58162306a36Sopenharmony_ci	union acpi_operand_object **top_object_list;
58262306a36Sopenharmony_ci	union acpi_operand_object **sub_object_list;
58362306a36Sopenharmony_ci	union acpi_operand_object *obj_desc;
58462306a36Sopenharmony_ci	union acpi_operand_object *sub_package;
58562306a36Sopenharmony_ci	u32 element_count;
58662306a36Sopenharmony_ci	u32 index;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	/* Each element in the _PRT package is a subpackage */
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	top_object_list = package_object->package.elements;
59162306a36Sopenharmony_ci	element_count = package_object->package.count;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	/* Examine each subpackage */
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	for (index = 0; index < element_count; index++, top_object_list++) {
59662306a36Sopenharmony_ci		sub_package = *top_object_list;
59762306a36Sopenharmony_ci		sub_object_list = sub_package->package.elements;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci		/* Check for minimum required element count */
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci		if (sub_package->package.count < 4) {
60262306a36Sopenharmony_ci			continue;
60362306a36Sopenharmony_ci		}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci		/*
60662306a36Sopenharmony_ci		 * If the BIOS has erroneously reversed the _PRT source_name (index 2)
60762306a36Sopenharmony_ci		 * and the source_index (index 3), fix it. _PRT is important enough to
60862306a36Sopenharmony_ci		 * workaround this BIOS error. This also provides compatibility with
60962306a36Sopenharmony_ci		 * other ACPI implementations.
61062306a36Sopenharmony_ci		 */
61162306a36Sopenharmony_ci		obj_desc = sub_object_list[3];
61262306a36Sopenharmony_ci		if (!obj_desc || (obj_desc->common.type != ACPI_TYPE_INTEGER)) {
61362306a36Sopenharmony_ci			sub_object_list[3] = sub_object_list[2];
61462306a36Sopenharmony_ci			sub_object_list[2] = obj_desc;
61562306a36Sopenharmony_ci			info->return_flags |= ACPI_OBJECT_REPAIRED;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci			ACPI_WARN_PREDEFINED((AE_INFO,
61862306a36Sopenharmony_ci					      info->full_pathname,
61962306a36Sopenharmony_ci					      info->node_flags,
62062306a36Sopenharmony_ci					      "PRT[%X]: Fixed reversed SourceName and SourceIndex",
62162306a36Sopenharmony_ci					      index));
62262306a36Sopenharmony_ci		}
62362306a36Sopenharmony_ci	}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	return (AE_OK);
62662306a36Sopenharmony_ci}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci/******************************************************************************
62962306a36Sopenharmony_ci *
63062306a36Sopenharmony_ci * FUNCTION:    acpi_ns_repair_PSS
63162306a36Sopenharmony_ci *
63262306a36Sopenharmony_ci * PARAMETERS:  info                - Method execution information block
63362306a36Sopenharmony_ci *              return_object_ptr   - Pointer to the object returned from the
63462306a36Sopenharmony_ci *                                    evaluation of a method or object
63562306a36Sopenharmony_ci *
63662306a36Sopenharmony_ci * RETURN:      Status. AE_OK if object is OK or was repaired successfully
63762306a36Sopenharmony_ci *
63862306a36Sopenharmony_ci * DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list
63962306a36Sopenharmony_ci *              by the CPU frequencies. Check that the power dissipation values
64062306a36Sopenharmony_ci *              are all proportional to CPU frequency (i.e., sorting by
64162306a36Sopenharmony_ci *              frequency should be the same as sorting by power.)
64262306a36Sopenharmony_ci *
64362306a36Sopenharmony_ci *****************************************************************************/
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_cistatic acpi_status
64662306a36Sopenharmony_ciacpi_ns_repair_PSS(struct acpi_evaluate_info *info,
64762306a36Sopenharmony_ci		   union acpi_operand_object **return_object_ptr)
64862306a36Sopenharmony_ci{
64962306a36Sopenharmony_ci	union acpi_operand_object *return_object = *return_object_ptr;
65062306a36Sopenharmony_ci	union acpi_operand_object **outer_elements;
65162306a36Sopenharmony_ci	u32 outer_element_count;
65262306a36Sopenharmony_ci	union acpi_operand_object **elements;
65362306a36Sopenharmony_ci	union acpi_operand_object *obj_desc;
65462306a36Sopenharmony_ci	u32 previous_value;
65562306a36Sopenharmony_ci	acpi_status status;
65662306a36Sopenharmony_ci	u32 i;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	/*
65962306a36Sopenharmony_ci	 * Entries (subpackages) in the _PSS Package must be sorted by power
66062306a36Sopenharmony_ci	 * dissipation, in descending order. If it appears that the list is
66162306a36Sopenharmony_ci	 * incorrectly sorted, sort it. We sort by cpu_frequency, since this
66262306a36Sopenharmony_ci	 * should be proportional to the power.
66362306a36Sopenharmony_ci	 */
66462306a36Sopenharmony_ci	status = acpi_ns_check_sorted_list(info, return_object, 0, 6, 0,
66562306a36Sopenharmony_ci					   ACPI_SORT_DESCENDING,
66662306a36Sopenharmony_ci					   "CpuFrequency");
66762306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
66862306a36Sopenharmony_ci		return (status);
66962306a36Sopenharmony_ci	}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	/*
67262306a36Sopenharmony_ci	 * We now know the list is correctly sorted by CPU frequency. Check if
67362306a36Sopenharmony_ci	 * the power dissipation values are proportional.
67462306a36Sopenharmony_ci	 */
67562306a36Sopenharmony_ci	previous_value = ACPI_UINT32_MAX;
67662306a36Sopenharmony_ci	outer_elements = return_object->package.elements;
67762306a36Sopenharmony_ci	outer_element_count = return_object->package.count;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	for (i = 0; i < outer_element_count; i++) {
68062306a36Sopenharmony_ci		elements = (*outer_elements)->package.elements;
68162306a36Sopenharmony_ci		obj_desc = elements[1];	/* Index1 = power_dissipation */
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci		if ((u32)obj_desc->integer.value > previous_value) {
68462306a36Sopenharmony_ci			ACPI_WARN_PREDEFINED((AE_INFO,
68562306a36Sopenharmony_ci					      info->full_pathname,
68662306a36Sopenharmony_ci					      info->node_flags,
68762306a36Sopenharmony_ci					      "SubPackage[%u,%u] - suspicious power dissipation values",
68862306a36Sopenharmony_ci					      i - 1, i));
68962306a36Sopenharmony_ci		}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci		previous_value = (u32) obj_desc->integer.value;
69262306a36Sopenharmony_ci		outer_elements++;
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	return (AE_OK);
69662306a36Sopenharmony_ci}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci/******************************************************************************
69962306a36Sopenharmony_ci *
70062306a36Sopenharmony_ci * FUNCTION:    acpi_ns_repair_TSS
70162306a36Sopenharmony_ci *
70262306a36Sopenharmony_ci * PARAMETERS:  info                - Method execution information block
70362306a36Sopenharmony_ci *              return_object_ptr   - Pointer to the object returned from the
70462306a36Sopenharmony_ci *                                    evaluation of a method or object
70562306a36Sopenharmony_ci *
70662306a36Sopenharmony_ci * RETURN:      Status. AE_OK if object is OK or was repaired successfully
70762306a36Sopenharmony_ci *
70862306a36Sopenharmony_ci * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list
70962306a36Sopenharmony_ci *              descending by the power dissipation values.
71062306a36Sopenharmony_ci *
71162306a36Sopenharmony_ci *****************************************************************************/
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_cistatic acpi_status
71462306a36Sopenharmony_ciacpi_ns_repair_TSS(struct acpi_evaluate_info *info,
71562306a36Sopenharmony_ci		   union acpi_operand_object **return_object_ptr)
71662306a36Sopenharmony_ci{
71762306a36Sopenharmony_ci	union acpi_operand_object *return_object = *return_object_ptr;
71862306a36Sopenharmony_ci	acpi_status status;
71962306a36Sopenharmony_ci	struct acpi_namespace_node *node;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	/*
72262306a36Sopenharmony_ci	 * We can only sort the _TSS return package if there is no _PSS in the
72362306a36Sopenharmony_ci	 * same scope. This is because if _PSS is present, the ACPI specification
72462306a36Sopenharmony_ci	 * dictates that the _TSS Power Dissipation field is to be ignored, and
72562306a36Sopenharmony_ci	 * therefore some BIOSs leave garbage values in the _TSS Power field(s).
72662306a36Sopenharmony_ci	 * In this case, it is best to just return the _TSS package as-is.
72762306a36Sopenharmony_ci	 * (May, 2011)
72862306a36Sopenharmony_ci	 */
72962306a36Sopenharmony_ci	status = acpi_ns_get_node(info->node, "^_PSS",
73062306a36Sopenharmony_ci				  ACPI_NS_NO_UPSEARCH, &node);
73162306a36Sopenharmony_ci	if (ACPI_SUCCESS(status)) {
73262306a36Sopenharmony_ci		return (AE_OK);
73362306a36Sopenharmony_ci	}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	status = acpi_ns_check_sorted_list(info, return_object, 0, 5, 1,
73662306a36Sopenharmony_ci					   ACPI_SORT_DESCENDING,
73762306a36Sopenharmony_ci					   "PowerDissipation");
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	return (status);
74062306a36Sopenharmony_ci}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci/******************************************************************************
74362306a36Sopenharmony_ci *
74462306a36Sopenharmony_ci * FUNCTION:    acpi_ns_check_sorted_list
74562306a36Sopenharmony_ci *
74662306a36Sopenharmony_ci * PARAMETERS:  info                - Method execution information block
74762306a36Sopenharmony_ci *              return_object       - Pointer to the top-level returned object
74862306a36Sopenharmony_ci *              start_index         - Index of the first subpackage
74962306a36Sopenharmony_ci *              expected_count      - Minimum length of each subpackage
75062306a36Sopenharmony_ci *              sort_index          - Subpackage entry to sort on
75162306a36Sopenharmony_ci *              sort_direction      - Ascending or descending
75262306a36Sopenharmony_ci *              sort_key_name       - Name of the sort_index field
75362306a36Sopenharmony_ci *
75462306a36Sopenharmony_ci * RETURN:      Status. AE_OK if the list is valid and is sorted correctly or
75562306a36Sopenharmony_ci *              has been repaired by sorting the list.
75662306a36Sopenharmony_ci *
75762306a36Sopenharmony_ci * DESCRIPTION: Check if the package list is valid and sorted correctly by the
75862306a36Sopenharmony_ci *              sort_index. If not, then sort the list.
75962306a36Sopenharmony_ci *
76062306a36Sopenharmony_ci *****************************************************************************/
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_cistatic acpi_status
76362306a36Sopenharmony_ciacpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
76462306a36Sopenharmony_ci			  union acpi_operand_object *return_object,
76562306a36Sopenharmony_ci			  u32 start_index,
76662306a36Sopenharmony_ci			  u32 expected_count,
76762306a36Sopenharmony_ci			  u32 sort_index,
76862306a36Sopenharmony_ci			  u8 sort_direction, char *sort_key_name)
76962306a36Sopenharmony_ci{
77062306a36Sopenharmony_ci	u32 outer_element_count;
77162306a36Sopenharmony_ci	union acpi_operand_object **outer_elements;
77262306a36Sopenharmony_ci	union acpi_operand_object **elements;
77362306a36Sopenharmony_ci	union acpi_operand_object *obj_desc;
77462306a36Sopenharmony_ci	u32 i;
77562306a36Sopenharmony_ci	u32 previous_value;
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ns_check_sorted_list);
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	/* The top-level object must be a package */
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	if (return_object->common.type != ACPI_TYPE_PACKAGE) {
78262306a36Sopenharmony_ci		return (AE_AML_OPERAND_TYPE);
78362306a36Sopenharmony_ci	}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	/*
78662306a36Sopenharmony_ci	 * NOTE: assumes list of subpackages contains no NULL elements.
78762306a36Sopenharmony_ci	 * Any NULL elements should have been removed by earlier call
78862306a36Sopenharmony_ci	 * to acpi_ns_remove_null_elements.
78962306a36Sopenharmony_ci	 */
79062306a36Sopenharmony_ci	outer_element_count = return_object->package.count;
79162306a36Sopenharmony_ci	if (!outer_element_count || start_index >= outer_element_count) {
79262306a36Sopenharmony_ci		return (AE_AML_PACKAGE_LIMIT);
79362306a36Sopenharmony_ci	}
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	outer_elements = &return_object->package.elements[start_index];
79662306a36Sopenharmony_ci	outer_element_count -= start_index;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	previous_value = 0;
79962306a36Sopenharmony_ci	if (sort_direction == ACPI_SORT_DESCENDING) {
80062306a36Sopenharmony_ci		previous_value = ACPI_UINT32_MAX;
80162306a36Sopenharmony_ci	}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	/* Examine each subpackage */
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	for (i = 0; i < outer_element_count; i++) {
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci		/* Each element of the top-level package must also be a package */
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci		if ((*outer_elements)->common.type != ACPI_TYPE_PACKAGE) {
81062306a36Sopenharmony_ci			return (AE_AML_OPERAND_TYPE);
81162306a36Sopenharmony_ci		}
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci		/* Each subpackage must have the minimum length */
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci		if ((*outer_elements)->package.count < expected_count) {
81662306a36Sopenharmony_ci			return (AE_AML_PACKAGE_LIMIT);
81762306a36Sopenharmony_ci		}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci		elements = (*outer_elements)->package.elements;
82062306a36Sopenharmony_ci		obj_desc = elements[sort_index];
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci		if (obj_desc->common.type != ACPI_TYPE_INTEGER) {
82362306a36Sopenharmony_ci			return (AE_AML_OPERAND_TYPE);
82462306a36Sopenharmony_ci		}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci		/*
82762306a36Sopenharmony_ci		 * The list must be sorted in the specified order. If we detect a
82862306a36Sopenharmony_ci		 * discrepancy, sort the entire list.
82962306a36Sopenharmony_ci		 */
83062306a36Sopenharmony_ci		if (((sort_direction == ACPI_SORT_ASCENDING) &&
83162306a36Sopenharmony_ci		     (obj_desc->integer.value < previous_value)) ||
83262306a36Sopenharmony_ci		    ((sort_direction == ACPI_SORT_DESCENDING) &&
83362306a36Sopenharmony_ci		     (obj_desc->integer.value > previous_value))) {
83462306a36Sopenharmony_ci			acpi_ns_sort_list(&return_object->package.
83562306a36Sopenharmony_ci					  elements[start_index],
83662306a36Sopenharmony_ci					  outer_element_count, sort_index,
83762306a36Sopenharmony_ci					  sort_direction);
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci			info->return_flags |= ACPI_OBJECT_REPAIRED;
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci			ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
84262306a36Sopenharmony_ci					  "%s: Repaired unsorted list - now sorted by %s\n",
84362306a36Sopenharmony_ci					  info->full_pathname, sort_key_name));
84462306a36Sopenharmony_ci			return (AE_OK);
84562306a36Sopenharmony_ci		}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci		previous_value = (u32) obj_desc->integer.value;
84862306a36Sopenharmony_ci		outer_elements++;
84962306a36Sopenharmony_ci	}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	return (AE_OK);
85262306a36Sopenharmony_ci}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci/******************************************************************************
85562306a36Sopenharmony_ci *
85662306a36Sopenharmony_ci * FUNCTION:    acpi_ns_sort_list
85762306a36Sopenharmony_ci *
85862306a36Sopenharmony_ci * PARAMETERS:  elements            - Package object element list
85962306a36Sopenharmony_ci *              count               - Element count for above
86062306a36Sopenharmony_ci *              index               - Sort by which package element
86162306a36Sopenharmony_ci *              sort_direction      - Ascending or Descending sort
86262306a36Sopenharmony_ci *
86362306a36Sopenharmony_ci * RETURN:      None
86462306a36Sopenharmony_ci *
86562306a36Sopenharmony_ci * DESCRIPTION: Sort the objects that are in a package element list.
86662306a36Sopenharmony_ci *
86762306a36Sopenharmony_ci * NOTE: Assumes that all NULL elements have been removed from the package,
86862306a36Sopenharmony_ci *       and that all elements have been verified to be of type Integer.
86962306a36Sopenharmony_ci *
87062306a36Sopenharmony_ci *****************************************************************************/
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_cistatic void
87362306a36Sopenharmony_ciacpi_ns_sort_list(union acpi_operand_object **elements,
87462306a36Sopenharmony_ci		  u32 count, u32 index, u8 sort_direction)
87562306a36Sopenharmony_ci{
87662306a36Sopenharmony_ci	union acpi_operand_object *obj_desc1;
87762306a36Sopenharmony_ci	union acpi_operand_object *obj_desc2;
87862306a36Sopenharmony_ci	union acpi_operand_object *temp_obj;
87962306a36Sopenharmony_ci	u32 i;
88062306a36Sopenharmony_ci	u32 j;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	/* Simple bubble sort */
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	for (i = 1; i < count; i++) {
88562306a36Sopenharmony_ci		for (j = (count - 1); j >= i; j--) {
88662306a36Sopenharmony_ci			obj_desc1 = elements[j - 1]->package.elements[index];
88762306a36Sopenharmony_ci			obj_desc2 = elements[j]->package.elements[index];
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci			if (((sort_direction == ACPI_SORT_ASCENDING) &&
89062306a36Sopenharmony_ci			     (obj_desc1->integer.value >
89162306a36Sopenharmony_ci			      obj_desc2->integer.value))
89262306a36Sopenharmony_ci			    || ((sort_direction == ACPI_SORT_DESCENDING)
89362306a36Sopenharmony_ci				&& (obj_desc1->integer.value <
89462306a36Sopenharmony_ci				    obj_desc2->integer.value))) {
89562306a36Sopenharmony_ci				temp_obj = elements[j - 1];
89662306a36Sopenharmony_ci				elements[j - 1] = elements[j];
89762306a36Sopenharmony_ci				elements[j] = temp_obj;
89862306a36Sopenharmony_ci			}
89962306a36Sopenharmony_ci		}
90062306a36Sopenharmony_ci	}
90162306a36Sopenharmony_ci}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci/******************************************************************************
90462306a36Sopenharmony_ci *
90562306a36Sopenharmony_ci * FUNCTION:    acpi_ns_remove_element
90662306a36Sopenharmony_ci *
90762306a36Sopenharmony_ci * PARAMETERS:  obj_desc            - Package object element list
90862306a36Sopenharmony_ci *              index               - Index of element to remove
90962306a36Sopenharmony_ci *
91062306a36Sopenharmony_ci * RETURN:      None
91162306a36Sopenharmony_ci *
91262306a36Sopenharmony_ci * DESCRIPTION: Remove the requested element of a package and delete it.
91362306a36Sopenharmony_ci *
91462306a36Sopenharmony_ci *****************************************************************************/
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_cistatic void
91762306a36Sopenharmony_ciacpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index)
91862306a36Sopenharmony_ci{
91962306a36Sopenharmony_ci	union acpi_operand_object **source;
92062306a36Sopenharmony_ci	union acpi_operand_object **dest;
92162306a36Sopenharmony_ci	u32 count;
92262306a36Sopenharmony_ci	u32 new_count;
92362306a36Sopenharmony_ci	u32 i;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ns_remove_element);
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	count = obj_desc->package.count;
92862306a36Sopenharmony_ci	new_count = count - 1;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	source = obj_desc->package.elements;
93162306a36Sopenharmony_ci	dest = source;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	/* Examine all elements of the package object, remove matched index */
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
93662306a36Sopenharmony_ci		if (i == index) {
93762306a36Sopenharmony_ci			acpi_ut_remove_reference(*source);	/* Remove one ref for being in pkg */
93862306a36Sopenharmony_ci			acpi_ut_remove_reference(*source);
93962306a36Sopenharmony_ci		} else {
94062306a36Sopenharmony_ci			*dest = *source;
94162306a36Sopenharmony_ci			dest++;
94262306a36Sopenharmony_ci		}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci		source++;
94562306a36Sopenharmony_ci	}
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	/* NULL terminate list and update the package count */
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	*dest = NULL;
95062306a36Sopenharmony_ci	obj_desc->package.count = new_count;
95162306a36Sopenharmony_ci}
952