xref: /openbmc/linux/drivers/acpi/acpica/nsrepair2.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2ad5babeeSBob Moore /******************************************************************************
3ad5babeeSBob Moore  *
4ad5babeeSBob Moore  * Module Name: nsrepair2 - Repair for objects returned by specific
5ad5babeeSBob Moore  *                          predefined methods
6ad5babeeSBob Moore  *
7*612c2932SBob Moore  * Copyright (C) 2000 - 2023, Intel Corp.
8ad5babeeSBob Moore  *
995857638SErik Schmauss  *****************************************************************************/
10ad5babeeSBob Moore 
11ad5babeeSBob Moore #include <acpi/acpi.h>
12ad5babeeSBob Moore #include "accommon.h"
13ad5babeeSBob Moore #include "acnamesp.h"
14ad5babeeSBob Moore 
15ad5babeeSBob Moore #define _COMPONENT          ACPI_NAMESPACE
16ad5babeeSBob Moore ACPI_MODULE_NAME("nsrepair2")
17ad5babeeSBob Moore 
18ad5babeeSBob Moore /*
19ad5babeeSBob Moore  * Information structure and handler for ACPI predefined names that can
20ad5babeeSBob Moore  * be repaired on a per-name basis.
21ad5babeeSBob Moore  */
22ad5babeeSBob Moore typedef
2329a241ccSBob Moore acpi_status (*acpi_repair_function) (struct acpi_evaluate_info * info,
24f5c1e1c5SLv Zheng 				     union acpi_operand_object **
25f5c1e1c5SLv Zheng 				     return_object_ptr);
26ad5babeeSBob Moore 
27ad5babeeSBob Moore typedef struct acpi_repair_info {
2832786755SBob Moore 	char name[ACPI_NAMESEG_SIZE];
29ad5babeeSBob Moore 	acpi_repair_function repair_function;
30ad5babeeSBob Moore 
31ad5babeeSBob Moore } acpi_repair_info;
32ad5babeeSBob Moore 
33ad5babeeSBob Moore /* Local prototypes */
34ad5babeeSBob Moore 
35d5a36100SBob Moore static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
36ad5babeeSBob Moore 								   acpi_namespace_node
37ad5babeeSBob Moore 								   *node);
38ad5babeeSBob Moore 
39ad5babeeSBob Moore static acpi_status
4029a241ccSBob Moore acpi_ns_repair_ALR(struct acpi_evaluate_info *info,
41ad5babeeSBob Moore 		   union acpi_operand_object **return_object_ptr);
42ad5babeeSBob Moore 
43ad5babeeSBob Moore static acpi_status
4429a241ccSBob Moore acpi_ns_repair_CID(struct acpi_evaluate_info *info,
4577b23f71SBob Moore 		   union acpi_operand_object **return_object_ptr);
4677b23f71SBob Moore 
4777b23f71SBob Moore static acpi_status
485a9792f3SLv Zheng acpi_ns_repair_CST(struct acpi_evaluate_info *info,
495a9792f3SLv Zheng 		   union acpi_operand_object **return_object_ptr);
505a9792f3SLv Zheng 
515a9792f3SLv Zheng static acpi_status
5229a241ccSBob Moore acpi_ns_repair_FDE(struct acpi_evaluate_info *info,
5334c39c75SBob Moore 		   union acpi_operand_object **return_object_ptr);
5434c39c75SBob Moore 
5534c39c75SBob Moore static acpi_status
5629a241ccSBob Moore acpi_ns_repair_HID(struct acpi_evaluate_info *info,
5777b23f71SBob Moore 		   union acpi_operand_object **return_object_ptr);
5877b23f71SBob Moore 
5977b23f71SBob Moore static acpi_status
60aa6329c4SLv Zheng acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
61aa6329c4SLv Zheng 		   union acpi_operand_object **return_object_ptr);
62aa6329c4SLv Zheng 
63aa6329c4SLv Zheng static acpi_status
6429a241ccSBob Moore acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
65ad5babeeSBob Moore 		   union acpi_operand_object **return_object_ptr);
66ad5babeeSBob Moore 
67ad5babeeSBob Moore static acpi_status
6829a241ccSBob Moore acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
69ad5babeeSBob Moore 		   union acpi_operand_object **return_object_ptr);
70ad5babeeSBob Moore 
71ad5babeeSBob Moore static acpi_status
7229a241ccSBob Moore acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
73ad5babeeSBob Moore 			  union acpi_operand_object *return_object,
745a9792f3SLv Zheng 			  u32 start_index,
75ad5babeeSBob Moore 			  u32 expected_count,
76ad5babeeSBob Moore 			  u32 sort_index,
77ad5babeeSBob Moore 			  u8 sort_direction, char *sort_key_name);
78ad5babeeSBob Moore 
79ad5babeeSBob Moore /* Values for sort_direction above */
80ad5babeeSBob Moore 
81ad5babeeSBob Moore #define ACPI_SORT_ASCENDING     0
82ad5babeeSBob Moore #define ACPI_SORT_DESCENDING    1
83ad5babeeSBob Moore 
845a9792f3SLv Zheng static void
855a9792f3SLv Zheng acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index);
865a9792f3SLv Zheng 
875a9792f3SLv Zheng static void
885a9792f3SLv Zheng acpi_ns_sort_list(union acpi_operand_object **elements,
895a9792f3SLv Zheng 		  u32 count, u32 index, u8 sort_direction);
905a9792f3SLv Zheng 
91ad5babeeSBob Moore /*
92ad5babeeSBob Moore  * This table contains the names of the predefined methods for which we can
93ad5babeeSBob Moore  * perform more complex repairs.
94ad5babeeSBob Moore  *
9534c39c75SBob Moore  * As necessary:
9634c39c75SBob Moore  *
9734c39c75SBob Moore  * _ALR: Sort the list ascending by ambient_illuminance
9877b23f71SBob Moore  * _CID: Strings: uppercase all, remove any leading asterisk
995a9792f3SLv Zheng  * _CST: Sort the list ascending by C state type
10043420bbbSBob Moore  * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs
10143420bbbSBob Moore  * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs
10277b23f71SBob Moore  * _HID: Strings: uppercase all, remove any leading asterisk
103aa6329c4SLv Zheng  * _PRT: Fix reversed source_name and source_index
10434c39c75SBob Moore  * _PSS: Sort the list descending by Power
10534c39c75SBob Moore  * _TSS: Sort the list descending by Power
106aa9d3606SBob Moore  *
107aa9d3606SBob Moore  * Names that must be packages, but cannot be sorted:
108aa9d3606SBob Moore  *
109aa9d3606SBob Moore  * _BCL: Values are tied to the Package index where they appear, and cannot
110aa9d3606SBob Moore  * be moved or sorted. These index values are used for _BQC and _BCM.
111aa9d3606SBob Moore  * However, we can fix the case where a buffer is returned, by converting
112aa9d3606SBob Moore  * it to a Package of integers.
113ad5babeeSBob Moore  */
114ad5babeeSBob Moore static const struct acpi_repair_info acpi_ns_repairable_names[] = {
115ad5babeeSBob Moore 	{"_ALR", acpi_ns_repair_ALR},
11677b23f71SBob Moore 	{"_CID", acpi_ns_repair_CID},
1175a9792f3SLv Zheng 	{"_CST", acpi_ns_repair_CST},
11834c39c75SBob Moore 	{"_FDE", acpi_ns_repair_FDE},
11934c39c75SBob Moore 	{"_GTM", acpi_ns_repair_FDE},	/* _GTM has same repair as _FDE */
12077b23f71SBob Moore 	{"_HID", acpi_ns_repair_HID},
121aa6329c4SLv Zheng 	{"_PRT", acpi_ns_repair_PRT},
122ad5babeeSBob Moore 	{"_PSS", acpi_ns_repair_PSS},
123ad5babeeSBob Moore 	{"_TSS", acpi_ns_repair_TSS},
124ad5babeeSBob Moore 	{{0, 0, 0, 0}, NULL}	/* Table terminator */
125ad5babeeSBob Moore };
126ad5babeeSBob Moore 
12734c39c75SBob Moore #define ACPI_FDE_FIELD_COUNT        5
12834c39c75SBob Moore #define ACPI_FDE_BYTE_BUFFER_SIZE   5
129231ec06eSBob Moore #define ACPI_FDE_DWORD_BUFFER_SIZE  (ACPI_FDE_FIELD_COUNT * (u32) sizeof (u32))
13034c39c75SBob Moore 
131ad5babeeSBob Moore /******************************************************************************
132ad5babeeSBob Moore  *
133ad5babeeSBob Moore  * FUNCTION:    acpi_ns_complex_repairs
134ad5babeeSBob Moore  *
13529a241ccSBob Moore  * PARAMETERS:  info                - Method execution information block
136ba494beeSBob Moore  *              node                - Namespace node for the method/object
137ad5babeeSBob Moore  *              validate_status     - Original status of earlier validation
138ad5babeeSBob Moore  *              return_object_ptr   - Pointer to the object returned from the
139ad5babeeSBob Moore  *                                    evaluation of a method or object
140ad5babeeSBob Moore  *
141ad5babeeSBob Moore  * RETURN:      Status. AE_OK if repair was successful. If name is not
142ad5babeeSBob Moore  *              matched, validate_status is returned.
143ad5babeeSBob Moore  *
144ad5babeeSBob Moore  * DESCRIPTION: Attempt to repair/convert a return object of a type that was
145ad5babeeSBob Moore  *              not expected.
146ad5babeeSBob Moore  *
147ad5babeeSBob Moore  *****************************************************************************/
148ad5babeeSBob Moore 
149ad5babeeSBob Moore acpi_status
acpi_ns_complex_repairs(struct acpi_evaluate_info * info,struct acpi_namespace_node * node,acpi_status validate_status,union acpi_operand_object ** return_object_ptr)15029a241ccSBob Moore acpi_ns_complex_repairs(struct acpi_evaluate_info *info,
151ad5babeeSBob Moore 			struct acpi_namespace_node *node,
152ad5babeeSBob Moore 			acpi_status validate_status,
153ad5babeeSBob Moore 			union acpi_operand_object **return_object_ptr)
154ad5babeeSBob Moore {
155ad5babeeSBob Moore 	const struct acpi_repair_info *predefined;
156ad5babeeSBob Moore 	acpi_status status;
157ad5babeeSBob Moore 
1580766efdfSErik Kaneda 	ACPI_FUNCTION_TRACE(ns_complex_repairs);
1590766efdfSErik Kaneda 
160ad5babeeSBob Moore 	/* Check if this name is in the list of repairable names */
161ad5babeeSBob Moore 
162d5a36100SBob Moore 	predefined = acpi_ns_match_complex_repair(node);
163ad5babeeSBob Moore 	if (!predefined) {
1640766efdfSErik Kaneda 		return_ACPI_STATUS(validate_status);
165ad5babeeSBob Moore 	}
166ad5babeeSBob Moore 
16729a241ccSBob Moore 	status = predefined->repair_function(info, return_object_ptr);
1680766efdfSErik Kaneda 	return_ACPI_STATUS(status);
169ad5babeeSBob Moore }
170ad5babeeSBob Moore 
171ad5babeeSBob Moore /******************************************************************************
172ad5babeeSBob Moore  *
173d5a36100SBob Moore  * FUNCTION:    acpi_ns_match_complex_repair
174ad5babeeSBob Moore  *
175ba494beeSBob Moore  * PARAMETERS:  node                - Namespace node for the method/object
176ad5babeeSBob Moore  *
177ad5babeeSBob Moore  * RETURN:      Pointer to entry in repair table. NULL indicates not found.
178ad5babeeSBob Moore  *
179ad5babeeSBob Moore  * DESCRIPTION: Check an object name against the repairable object list.
180ad5babeeSBob Moore  *
181ad5babeeSBob Moore  *****************************************************************************/
182ad5babeeSBob Moore 
acpi_ns_match_complex_repair(struct acpi_namespace_node * node)183d5a36100SBob Moore static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
184ad5babeeSBob Moore 								   acpi_namespace_node
185ad5babeeSBob Moore 								   *node)
186ad5babeeSBob Moore {
187ad5babeeSBob Moore 	const struct acpi_repair_info *this_name;
188ad5babeeSBob Moore 
189ad5babeeSBob Moore 	/* Search info table for a repairable predefined method/object name */
190ad5babeeSBob Moore 
191ad5babeeSBob Moore 	this_name = acpi_ns_repairable_names;
192ad5babeeSBob Moore 	while (this_name->repair_function) {
1935599fb69SBob Moore 		if (ACPI_COMPARE_NAMESEG(node->name.ascii, this_name->name)) {
194ad5babeeSBob Moore 			return (this_name);
195ad5babeeSBob Moore 		}
1961fad8738SBob Moore 
197ad5babeeSBob Moore 		this_name++;
198ad5babeeSBob Moore 	}
199ad5babeeSBob Moore 
200ad5babeeSBob Moore 	return (NULL);		/* Not found */
201ad5babeeSBob Moore }
202ad5babeeSBob Moore 
203ad5babeeSBob Moore /******************************************************************************
204ad5babeeSBob Moore  *
205ad5babeeSBob Moore  * FUNCTION:    acpi_ns_repair_ALR
206ad5babeeSBob Moore  *
20729a241ccSBob Moore  * PARAMETERS:  info                - Method execution information block
208ad5babeeSBob Moore  *              return_object_ptr   - Pointer to the object returned from the
209ad5babeeSBob Moore  *                                    evaluation of a method or object
210ad5babeeSBob Moore  *
211ad5babeeSBob Moore  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
212ad5babeeSBob Moore  *
213ad5babeeSBob Moore  * DESCRIPTION: Repair for the _ALR object. If necessary, sort the object list
214ad5babeeSBob Moore  *              ascending by the ambient illuminance values.
215ad5babeeSBob Moore  *
216ad5babeeSBob Moore  *****************************************************************************/
217ad5babeeSBob Moore 
218ad5babeeSBob Moore static acpi_status
acpi_ns_repair_ALR(struct acpi_evaluate_info * info,union acpi_operand_object ** return_object_ptr)21929a241ccSBob Moore acpi_ns_repair_ALR(struct acpi_evaluate_info *info,
220ad5babeeSBob Moore 		   union acpi_operand_object **return_object_ptr)
221ad5babeeSBob Moore {
222ad5babeeSBob Moore 	union acpi_operand_object *return_object = *return_object_ptr;
223ad5babeeSBob Moore 	acpi_status status;
224ad5babeeSBob Moore 
2255a9792f3SLv Zheng 	status = acpi_ns_check_sorted_list(info, return_object, 0, 2, 1,
226ad5babeeSBob Moore 					   ACPI_SORT_ASCENDING,
227ad5babeeSBob Moore 					   "AmbientIlluminance");
228ad5babeeSBob Moore 
229ad5babeeSBob Moore 	return (status);
230ad5babeeSBob Moore }
231ad5babeeSBob Moore 
232ad5babeeSBob Moore /******************************************************************************
233ad5babeeSBob Moore  *
23434c39c75SBob Moore  * FUNCTION:    acpi_ns_repair_FDE
23534c39c75SBob Moore  *
23629a241ccSBob Moore  * PARAMETERS:  info                - Method execution information block
23734c39c75SBob Moore  *              return_object_ptr   - Pointer to the object returned from the
23834c39c75SBob Moore  *                                    evaluation of a method or object
23934c39c75SBob Moore  *
24034c39c75SBob Moore  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
24134c39c75SBob Moore  *
24234c39c75SBob Moore  * DESCRIPTION: Repair for the _FDE and _GTM objects. The expected return
24343420bbbSBob Moore  *              value is a Buffer of 5 DWORDs. This function repairs a common
24443420bbbSBob Moore  *              problem where the return value is a Buffer of BYTEs, not
24543420bbbSBob Moore  *              DWORDs.
24634c39c75SBob Moore  *
24734c39c75SBob Moore  *****************************************************************************/
24834c39c75SBob Moore 
24934c39c75SBob Moore static acpi_status
acpi_ns_repair_FDE(struct acpi_evaluate_info * info,union acpi_operand_object ** return_object_ptr)25029a241ccSBob Moore acpi_ns_repair_FDE(struct acpi_evaluate_info *info,
25134c39c75SBob Moore 		   union acpi_operand_object **return_object_ptr)
25234c39c75SBob Moore {
25334c39c75SBob Moore 	union acpi_operand_object *return_object = *return_object_ptr;
25434c39c75SBob Moore 	union acpi_operand_object *buffer_object;
25534c39c75SBob Moore 	u8 *byte_buffer;
25634c39c75SBob Moore 	u32 *dword_buffer;
25734c39c75SBob Moore 	u32 i;
25834c39c75SBob Moore 
2593a58176eSBob Moore 	ACPI_FUNCTION_NAME(ns_repair_FDE);
2603a58176eSBob Moore 
26134c39c75SBob Moore 	switch (return_object->common.type) {
26234c39c75SBob Moore 	case ACPI_TYPE_BUFFER:
26334c39c75SBob Moore 
26434c39c75SBob Moore 		/* This is the expected type. Length should be (at least) 5 DWORDs */
26534c39c75SBob Moore 
26634c39c75SBob Moore 		if (return_object->buffer.length >= ACPI_FDE_DWORD_BUFFER_SIZE) {
26734c39c75SBob Moore 			return (AE_OK);
26834c39c75SBob Moore 		}
26934c39c75SBob Moore 
27034c39c75SBob Moore 		/* We can only repair if we have exactly 5 BYTEs */
27134c39c75SBob Moore 
27234c39c75SBob Moore 		if (return_object->buffer.length != ACPI_FDE_BYTE_BUFFER_SIZE) {
2731fad8738SBob Moore 			ACPI_WARN_PREDEFINED((AE_INFO,
2741fad8738SBob Moore 					      info->full_pathname,
27529a241ccSBob Moore 					      info->node_flags,
27634c39c75SBob Moore 					      "Incorrect return buffer length %u, expected %u",
27734c39c75SBob Moore 					      return_object->buffer.length,
27834c39c75SBob Moore 					      ACPI_FDE_DWORD_BUFFER_SIZE));
27934c39c75SBob Moore 
28034c39c75SBob Moore 			return (AE_AML_OPERAND_TYPE);
28134c39c75SBob Moore 		}
28234c39c75SBob Moore 
28334c39c75SBob Moore 		/* Create the new (larger) buffer object */
28434c39c75SBob Moore 
28534c39c75SBob Moore 		buffer_object =
28634c39c75SBob Moore 		    acpi_ut_create_buffer_object(ACPI_FDE_DWORD_BUFFER_SIZE);
28734c39c75SBob Moore 		if (!buffer_object) {
28834c39c75SBob Moore 			return (AE_NO_MEMORY);
28934c39c75SBob Moore 		}
29034c39c75SBob Moore 
29134c39c75SBob Moore 		/* Expand each byte to a DWORD */
29234c39c75SBob Moore 
29334c39c75SBob Moore 		byte_buffer = return_object->buffer.pointer;
2941fad8738SBob Moore 		dword_buffer = ACPI_CAST_PTR(u32,
2951fad8738SBob Moore 					     buffer_object->buffer.pointer);
29634c39c75SBob Moore 
29734c39c75SBob Moore 		for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++) {
29834c39c75SBob Moore 			*dword_buffer = (u32) *byte_buffer;
29934c39c75SBob Moore 			dword_buffer++;
30034c39c75SBob Moore 			byte_buffer++;
30134c39c75SBob Moore 		}
30234c39c75SBob Moore 
3033a58176eSBob Moore 		ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
3043a58176eSBob Moore 				  "%s Expanded Byte Buffer to expected DWord Buffer\n",
30529a241ccSBob Moore 				  info->full_pathname));
30634c39c75SBob Moore 		break;
30734c39c75SBob Moore 
30834c39c75SBob Moore 	default:
3091d1ea1b7SChao Guan 
31034c39c75SBob Moore 		return (AE_AML_OPERAND_TYPE);
31134c39c75SBob Moore 	}
31234c39c75SBob Moore 
31334c39c75SBob Moore 	/* Delete the original return object, return the new buffer object */
31434c39c75SBob Moore 
31534c39c75SBob Moore 	acpi_ut_remove_reference(return_object);
31634c39c75SBob Moore 	*return_object_ptr = buffer_object;
31734c39c75SBob Moore 
31829a241ccSBob Moore 	info->return_flags |= ACPI_OBJECT_REPAIRED;
31934c39c75SBob Moore 	return (AE_OK);
32034c39c75SBob Moore }
32134c39c75SBob Moore 
32234c39c75SBob Moore /******************************************************************************
32334c39c75SBob Moore  *
32477b23f71SBob Moore  * FUNCTION:    acpi_ns_repair_CID
32577b23f71SBob Moore  *
32629a241ccSBob Moore  * PARAMETERS:  info                - Method execution information block
32777b23f71SBob Moore  *              return_object_ptr   - Pointer to the object returned from the
32877b23f71SBob Moore  *                                    evaluation of a method or object
32977b23f71SBob Moore  *
33077b23f71SBob Moore  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
33177b23f71SBob Moore  *
33277b23f71SBob Moore  * DESCRIPTION: Repair for the _CID object. If a string, ensure that all
33377b23f71SBob Moore  *              letters are uppercase and that there is no leading asterisk.
33477b23f71SBob Moore  *              If a Package, ensure same for all string elements.
33577b23f71SBob Moore  *
33677b23f71SBob Moore  *****************************************************************************/
33777b23f71SBob Moore 
33877b23f71SBob Moore static acpi_status
acpi_ns_repair_CID(struct acpi_evaluate_info * info,union acpi_operand_object ** return_object_ptr)33929a241ccSBob Moore acpi_ns_repair_CID(struct acpi_evaluate_info *info,
34077b23f71SBob Moore 		   union acpi_operand_object **return_object_ptr)
34177b23f71SBob Moore {
34277b23f71SBob Moore 	acpi_status status;
34377b23f71SBob Moore 	union acpi_operand_object *return_object = *return_object_ptr;
34477b23f71SBob Moore 	union acpi_operand_object **element_ptr;
34577b23f71SBob Moore 	union acpi_operand_object *original_element;
34677b23f71SBob Moore 	u16 original_ref_count;
34777b23f71SBob Moore 	u32 i;
34877b23f71SBob Moore 
3490766efdfSErik Kaneda 	ACPI_FUNCTION_TRACE(ns_repair_CID);
3500766efdfSErik Kaneda 
35177b23f71SBob Moore 	/* Check for _CID as a simple string */
35277b23f71SBob Moore 
35377b23f71SBob Moore 	if (return_object->common.type == ACPI_TYPE_STRING) {
35429a241ccSBob Moore 		status = acpi_ns_repair_HID(info, return_object_ptr);
3550766efdfSErik Kaneda 		return_ACPI_STATUS(status);
35677b23f71SBob Moore 	}
35777b23f71SBob Moore 
35877b23f71SBob Moore 	/* Exit if not a Package */
35977b23f71SBob Moore 
36077b23f71SBob Moore 	if (return_object->common.type != ACPI_TYPE_PACKAGE) {
3610766efdfSErik Kaneda 		return_ACPI_STATUS(AE_OK);
36277b23f71SBob Moore 	}
36377b23f71SBob Moore 
36477b23f71SBob Moore 	/* Examine each element of the _CID package */
36577b23f71SBob Moore 
36677b23f71SBob Moore 	element_ptr = return_object->package.elements;
36777b23f71SBob Moore 	for (i = 0; i < return_object->package.count; i++) {
36877b23f71SBob Moore 		original_element = *element_ptr;
36977b23f71SBob Moore 		original_ref_count = original_element->common.reference_count;
37077b23f71SBob Moore 
37129a241ccSBob Moore 		status = acpi_ns_repair_HID(info, element_ptr);
37277b23f71SBob Moore 		if (ACPI_FAILURE(status)) {
3730766efdfSErik Kaneda 			return_ACPI_STATUS(status);
37477b23f71SBob Moore 		}
37577b23f71SBob Moore 
37677b23f71SBob Moore 		if (original_element != *element_ptr) {
37777b23f71SBob Moore 
378ed7f8bc9SBob Moore 			/* Update reference count of new object */
37977b23f71SBob Moore 
38077b23f71SBob Moore 			(*element_ptr)->common.reference_count =
38177b23f71SBob Moore 			    original_ref_count;
38277b23f71SBob Moore 		}
38377b23f71SBob Moore 
38477b23f71SBob Moore 		element_ptr++;
38577b23f71SBob Moore 	}
38677b23f71SBob Moore 
3870766efdfSErik Kaneda 	return_ACPI_STATUS(AE_OK);
38877b23f71SBob Moore }
38977b23f71SBob Moore 
39077b23f71SBob Moore /******************************************************************************
39177b23f71SBob Moore  *
3925a9792f3SLv Zheng  * FUNCTION:    acpi_ns_repair_CST
3935a9792f3SLv Zheng  *
3945a9792f3SLv Zheng  * PARAMETERS:  info                - Method execution information block
3955a9792f3SLv Zheng  *              return_object_ptr   - Pointer to the object returned from the
3965a9792f3SLv Zheng  *                                    evaluation of a method or object
3975a9792f3SLv Zheng  *
3985a9792f3SLv Zheng  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
3995a9792f3SLv Zheng  *
4005a9792f3SLv Zheng  * DESCRIPTION: Repair for the _CST object:
4015a9792f3SLv Zheng  *              1. Sort the list ascending by C state type
4025a9792f3SLv Zheng  *              2. Ensure type cannot be zero
4030a16d12aSBob Moore  *              3. A subpackage count of zero means _CST is meaningless
4040a16d12aSBob Moore  *              4. Count must match the number of C state subpackages
4055a9792f3SLv Zheng  *
4065a9792f3SLv Zheng  *****************************************************************************/
4075a9792f3SLv Zheng 
4085a9792f3SLv Zheng static acpi_status
acpi_ns_repair_CST(struct acpi_evaluate_info * info,union acpi_operand_object ** return_object_ptr)4095a9792f3SLv Zheng acpi_ns_repair_CST(struct acpi_evaluate_info *info,
4105a9792f3SLv Zheng 		   union acpi_operand_object **return_object_ptr)
4115a9792f3SLv Zheng {
4125a9792f3SLv Zheng 	union acpi_operand_object *return_object = *return_object_ptr;
4135a9792f3SLv Zheng 	union acpi_operand_object **outer_elements;
4145a9792f3SLv Zheng 	u32 outer_element_count;
4155a9792f3SLv Zheng 	union acpi_operand_object *obj_desc;
4165a9792f3SLv Zheng 	acpi_status status;
4175a9792f3SLv Zheng 	u8 removing;
4185a9792f3SLv Zheng 	u32 i;
4195a9792f3SLv Zheng 
4205a9792f3SLv Zheng 	ACPI_FUNCTION_NAME(ns_repair_CST);
4215a9792f3SLv Zheng 
4225a9792f3SLv Zheng 	/*
423341e7ba1SLv Zheng 	 * Check if the C-state type values are proportional.
4245a9792f3SLv Zheng 	 */
4255a9792f3SLv Zheng 	outer_element_count = return_object->package.count - 1;
4265a9792f3SLv Zheng 	i = 0;
4275a9792f3SLv Zheng 	while (i < outer_element_count) {
4285a9792f3SLv Zheng 		outer_elements = &return_object->package.elements[i + 1];
4295a9792f3SLv Zheng 		removing = FALSE;
4305a9792f3SLv Zheng 
4315a9792f3SLv Zheng 		if ((*outer_elements)->package.count == 0) {
4321fad8738SBob Moore 			ACPI_WARN_PREDEFINED((AE_INFO,
4331fad8738SBob Moore 					      info->full_pathname,
4345a9792f3SLv Zheng 					      info->node_flags,
4355a9792f3SLv Zheng 					      "SubPackage[%u] - removing entry due to zero count",
4365a9792f3SLv Zheng 					      i));
4375a9792f3SLv Zheng 			removing = TRUE;
4385a9792f3SLv Zheng 			goto remove_element;
4395a9792f3SLv Zheng 		}
4405a9792f3SLv Zheng 
4415a9792f3SLv Zheng 		obj_desc = (*outer_elements)->package.elements[1];	/* Index1 = Type */
4425a9792f3SLv Zheng 		if ((u32)obj_desc->integer.value == 0) {
4431fad8738SBob Moore 			ACPI_WARN_PREDEFINED((AE_INFO,
4441fad8738SBob Moore 					      info->full_pathname,
4455a9792f3SLv Zheng 					      info->node_flags,
4465a9792f3SLv Zheng 					      "SubPackage[%u] - removing entry due to invalid Type(0)",
4475a9792f3SLv Zheng 					      i));
4485a9792f3SLv Zheng 			removing = TRUE;
4495a9792f3SLv Zheng 		}
4505a9792f3SLv Zheng 
4515a9792f3SLv Zheng remove_element:
4525a9792f3SLv Zheng 		if (removing) {
4535a9792f3SLv Zheng 			acpi_ns_remove_element(return_object, i + 1);
4545a9792f3SLv Zheng 			outer_element_count--;
4555a9792f3SLv Zheng 		} else {
4565a9792f3SLv Zheng 			i++;
4575a9792f3SLv Zheng 		}
4585a9792f3SLv Zheng 	}
4595a9792f3SLv Zheng 
4605a9792f3SLv Zheng 	/* Update top-level package count, Type "Integer" checked elsewhere */
4615a9792f3SLv Zheng 
4625a9792f3SLv Zheng 	obj_desc = return_object->package.elements[0];
4635a9792f3SLv Zheng 	obj_desc->integer.value = outer_element_count;
464341e7ba1SLv Zheng 
465341e7ba1SLv Zheng 	/*
466341e7ba1SLv Zheng 	 * Entries (subpackages) in the _CST Package must be sorted by the
467341e7ba1SLv Zheng 	 * C-state type, in ascending order.
468341e7ba1SLv Zheng 	 */
469341e7ba1SLv Zheng 	status = acpi_ns_check_sorted_list(info, return_object, 1, 4, 1,
470341e7ba1SLv Zheng 					   ACPI_SORT_ASCENDING, "C-State Type");
471341e7ba1SLv Zheng 	if (ACPI_FAILURE(status)) {
472341e7ba1SLv Zheng 		return (status);
473341e7ba1SLv Zheng 	}
474341e7ba1SLv Zheng 
4755a9792f3SLv Zheng 	return (AE_OK);
4765a9792f3SLv Zheng }
4775a9792f3SLv Zheng 
4785a9792f3SLv Zheng /******************************************************************************
4795a9792f3SLv Zheng  *
48077b23f71SBob Moore  * FUNCTION:    acpi_ns_repair_HID
48177b23f71SBob Moore  *
48229a241ccSBob Moore  * PARAMETERS:  info                - Method execution information block
48377b23f71SBob Moore  *              return_object_ptr   - Pointer to the object returned from the
48477b23f71SBob Moore  *                                    evaluation of a method or object
48577b23f71SBob Moore  *
48677b23f71SBob Moore  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
48777b23f71SBob Moore  *
48877b23f71SBob Moore  * DESCRIPTION: Repair for the _HID object. If a string, ensure that all
48977b23f71SBob Moore  *              letters are uppercase and that there is no leading asterisk.
49077b23f71SBob Moore  *
49177b23f71SBob Moore  *****************************************************************************/
49277b23f71SBob Moore 
49377b23f71SBob Moore static acpi_status
acpi_ns_repair_HID(struct acpi_evaluate_info * info,union acpi_operand_object ** return_object_ptr)49429a241ccSBob Moore acpi_ns_repair_HID(struct acpi_evaluate_info *info,
49577b23f71SBob Moore 		   union acpi_operand_object **return_object_ptr)
49677b23f71SBob Moore {
49777b23f71SBob Moore 	union acpi_operand_object *return_object = *return_object_ptr;
498fe0af090SArd Biesheuvel 	union acpi_operand_object *new_string;
49932cf1a12SErik Kaneda 	char *source;
500fe0af090SArd Biesheuvel 	char *dest;
50177b23f71SBob Moore 
5029db8a1c2SXiongfeng Wang 	ACPI_FUNCTION_TRACE(ns_repair_HID);
50377b23f71SBob Moore 
50477b23f71SBob Moore 	/* We only care about string _HID objects (not integers) */
50577b23f71SBob Moore 
50677b23f71SBob Moore 	if (return_object->common.type != ACPI_TYPE_STRING) {
5070766efdfSErik Kaneda 		return_ACPI_STATUS(AE_OK);
50877b23f71SBob Moore 	}
50977b23f71SBob Moore 
51077b23f71SBob Moore 	if (return_object->string.length == 0) {
5111fad8738SBob Moore 		ACPI_WARN_PREDEFINED((AE_INFO,
5121fad8738SBob Moore 				      info->full_pathname, info->node_flags,
51377b23f71SBob Moore 				      "Invalid zero-length _HID or _CID string"));
51477b23f71SBob Moore 
51577b23f71SBob Moore 		/* Return AE_OK anyway, let driver handle it */
51677b23f71SBob Moore 
51729a241ccSBob Moore 		info->return_flags |= ACPI_OBJECT_REPAIRED;
5180766efdfSErik Kaneda 		return_ACPI_STATUS(AE_OK);
51977b23f71SBob Moore 	}
52077b23f71SBob Moore 
521fe0af090SArd Biesheuvel 	/* It is simplest to always create a new string object */
522fe0af090SArd Biesheuvel 
523fe0af090SArd Biesheuvel 	new_string = acpi_ut_create_string_object(return_object->string.length);
524fe0af090SArd Biesheuvel 	if (!new_string) {
525fe0af090SArd Biesheuvel 		return_ACPI_STATUS(AE_NO_MEMORY);
526fe0af090SArd Biesheuvel 	}
527fe0af090SArd Biesheuvel 
52877b23f71SBob Moore 	/*
52977b23f71SBob Moore 	 * Remove a leading asterisk if present. For some unknown reason, there
53077b23f71SBob Moore 	 * are many machines in the field that contains IDs like this.
53177b23f71SBob Moore 	 *
53277b23f71SBob Moore 	 * Examples: "*PNP0C03", "*ACPI0003"
53377b23f71SBob Moore 	 */
53477b23f71SBob Moore 	source = return_object->string.pointer;
53577b23f71SBob Moore 	if (*source == '*') {
53677b23f71SBob Moore 		source++;
537fe0af090SArd Biesheuvel 		new_string->string.length--;
53877b23f71SBob Moore 
53977b23f71SBob Moore 		ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
54077b23f71SBob Moore 				  "%s: Removed invalid leading asterisk\n",
54129a241ccSBob Moore 				  info->full_pathname));
54277b23f71SBob Moore 	}
54377b23f71SBob Moore 
54477b23f71SBob Moore 	/*
5457fce7a4bSBob Moore 	 * Copy and uppercase the string. From the ACPI 5.0 specification:
54677b23f71SBob Moore 	 *
54777b23f71SBob Moore 	 * A valid PNP ID must be of the form "AAA####" where A is an uppercase
54877b23f71SBob Moore 	 * letter and # is a hex digit. A valid ACPI ID must be of the form
5497fce7a4bSBob Moore 	 * "NNNN####" where N is an uppercase letter or decimal digit, and
5507fce7a4bSBob Moore 	 * # is a hex digit.
55177b23f71SBob Moore 	 */
552fe0af090SArd Biesheuvel 	for (dest = new_string->string.pointer; *source; dest++, source++) {
5534fa4616eSBob Moore 		*dest = (char)toupper((int)*source);
55477b23f71SBob Moore 	}
55577b23f71SBob Moore 
556fe0af090SArd Biesheuvel 	acpi_ut_remove_reference(return_object);
557fe0af090SArd Biesheuvel 	*return_object_ptr = new_string;
5580766efdfSErik Kaneda 	return_ACPI_STATUS(AE_OK);
55977b23f71SBob Moore }
56077b23f71SBob Moore 
56177b23f71SBob Moore /******************************************************************************
56277b23f71SBob Moore  *
563aa6329c4SLv Zheng  * FUNCTION:    acpi_ns_repair_PRT
564ad5babeeSBob Moore  *
56529a241ccSBob Moore  * PARAMETERS:  info                - Method execution information block
566ad5babeeSBob Moore  *              return_object_ptr   - Pointer to the object returned from the
567ad5babeeSBob Moore  *                                    evaluation of a method or object
568ad5babeeSBob Moore  *
569ad5babeeSBob Moore  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
570ad5babeeSBob Moore  *
571aa6329c4SLv Zheng  * DESCRIPTION: Repair for the _PRT object. If necessary, fix reversed
572aa6329c4SLv Zheng  *              source_name and source_index field, a common BIOS bug.
573ad5babeeSBob Moore  *
574ad5babeeSBob Moore  *****************************************************************************/
575ad5babeeSBob Moore 
576ad5babeeSBob Moore static acpi_status
acpi_ns_repair_PRT(struct acpi_evaluate_info * info,union acpi_operand_object ** return_object_ptr)577aa6329c4SLv Zheng acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
578ad5babeeSBob Moore 		   union acpi_operand_object **return_object_ptr)
579ad5babeeSBob Moore {
580aa6329c4SLv Zheng 	union acpi_operand_object *package_object = *return_object_ptr;
581aa6329c4SLv Zheng 	union acpi_operand_object **top_object_list;
582aa6329c4SLv Zheng 	union acpi_operand_object **sub_object_list;
583aa6329c4SLv Zheng 	union acpi_operand_object *obj_desc;
5841c3c2a54SBob Moore 	union acpi_operand_object *sub_package;
585aa6329c4SLv Zheng 	u32 element_count;
586aa6329c4SLv Zheng 	u32 index;
587aa6329c4SLv Zheng 
588aa6329c4SLv Zheng 	/* Each element in the _PRT package is a subpackage */
589aa6329c4SLv Zheng 
590aa6329c4SLv Zheng 	top_object_list = package_object->package.elements;
591aa6329c4SLv Zheng 	element_count = package_object->package.count;
592aa6329c4SLv Zheng 
59369e6bb68SBob Moore 	/* Examine each subpackage */
59469e6bb68SBob Moore 
59569e6bb68SBob Moore 	for (index = 0; index < element_count; index++, top_object_list++) {
5961c3c2a54SBob Moore 		sub_package = *top_object_list;
5971c3c2a54SBob Moore 		sub_object_list = sub_package->package.elements;
5981c3c2a54SBob Moore 
59969e6bb68SBob Moore 		/* Check for minimum required element count */
60069e6bb68SBob Moore 
60169e6bb68SBob Moore 		if (sub_package->package.count < 4) {
60269e6bb68SBob Moore 			continue;
6031c3c2a54SBob Moore 		}
6048f9c9127SFenghua Yu 
6058f9c9127SFenghua Yu 		/*
606aa6329c4SLv Zheng 		 * If the BIOS has erroneously reversed the _PRT source_name (index 2)
607aa6329c4SLv Zheng 		 * and the source_index (index 3), fix it. _PRT is important enough to
608aa6329c4SLv Zheng 		 * workaround this BIOS error. This also provides compatibility with
609aa6329c4SLv Zheng 		 * other ACPI implementations.
6108f9c9127SFenghua Yu 		 */
611aa6329c4SLv Zheng 		obj_desc = sub_object_list[3];
612aa6329c4SLv Zheng 		if (!obj_desc || (obj_desc->common.type != ACPI_TYPE_INTEGER)) {
613aa6329c4SLv Zheng 			sub_object_list[3] = sub_object_list[2];
614aa6329c4SLv Zheng 			sub_object_list[2] = obj_desc;
615aa6329c4SLv Zheng 			info->return_flags |= ACPI_OBJECT_REPAIRED;
616aa6329c4SLv Zheng 
61769e6bb68SBob Moore 			ACPI_WARN_PREDEFINED((AE_INFO,
61869e6bb68SBob Moore 					      info->full_pathname,
619aa6329c4SLv Zheng 					      info->node_flags,
620aa6329c4SLv Zheng 					      "PRT[%X]: Fixed reversed SourceName and SourceIndex",
621aa6329c4SLv Zheng 					      index));
6228f9c9127SFenghua Yu 		}
623aa6329c4SLv Zheng 	}
624aa6329c4SLv Zheng 
625aa6329c4SLv Zheng 	return (AE_OK);
626ad5babeeSBob Moore }
627ad5babeeSBob Moore 
628ad5babeeSBob Moore /******************************************************************************
629ad5babeeSBob Moore  *
630ad5babeeSBob Moore  * FUNCTION:    acpi_ns_repair_PSS
631ad5babeeSBob Moore  *
63229a241ccSBob Moore  * PARAMETERS:  info                - Method execution information block
633ad5babeeSBob Moore  *              return_object_ptr   - Pointer to the object returned from the
634ad5babeeSBob Moore  *                                    evaluation of a method or object
635ad5babeeSBob Moore  *
636ad5babeeSBob Moore  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
637ad5babeeSBob Moore  *
638ad5babeeSBob Moore  * DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list
639ad5babeeSBob Moore  *              by the CPU frequencies. Check that the power dissipation values
640ad5babeeSBob Moore  *              are all proportional to CPU frequency (i.e., sorting by
641ad5babeeSBob Moore  *              frequency should be the same as sorting by power.)
642ad5babeeSBob Moore  *
643ad5babeeSBob Moore  *****************************************************************************/
644ad5babeeSBob Moore 
645ad5babeeSBob Moore static acpi_status
acpi_ns_repair_PSS(struct acpi_evaluate_info * info,union acpi_operand_object ** return_object_ptr)64629a241ccSBob Moore acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
647ad5babeeSBob Moore 		   union acpi_operand_object **return_object_ptr)
648ad5babeeSBob Moore {
649ad5babeeSBob Moore 	union acpi_operand_object *return_object = *return_object_ptr;
650ad5babeeSBob Moore 	union acpi_operand_object **outer_elements;
651ad5babeeSBob Moore 	u32 outer_element_count;
652ad5babeeSBob Moore 	union acpi_operand_object **elements;
653ad5babeeSBob Moore 	union acpi_operand_object *obj_desc;
654ad5babeeSBob Moore 	u32 previous_value;
655ad5babeeSBob Moore 	acpi_status status;
656ad5babeeSBob Moore 	u32 i;
657ad5babeeSBob Moore 
658ad5babeeSBob Moore 	/*
6590a16d12aSBob Moore 	 * Entries (subpackages) in the _PSS Package must be sorted by power
660ad5babeeSBob Moore 	 * dissipation, in descending order. If it appears that the list is
661ad5babeeSBob Moore 	 * incorrectly sorted, sort it. We sort by cpu_frequency, since this
662ad5babeeSBob Moore 	 * should be proportional to the power.
663ad5babeeSBob Moore 	 */
6645a9792f3SLv Zheng 	status = acpi_ns_check_sorted_list(info, return_object, 0, 6, 0,
665ad5babeeSBob Moore 					   ACPI_SORT_DESCENDING,
666ad5babeeSBob Moore 					   "CpuFrequency");
667ad5babeeSBob Moore 	if (ACPI_FAILURE(status)) {
668ad5babeeSBob Moore 		return (status);
669ad5babeeSBob Moore 	}
670ad5babeeSBob Moore 
671ad5babeeSBob Moore 	/*
672ad5babeeSBob Moore 	 * We now know the list is correctly sorted by CPU frequency. Check if
673ad5babeeSBob Moore 	 * the power dissipation values are proportional.
674ad5babeeSBob Moore 	 */
675ad5babeeSBob Moore 	previous_value = ACPI_UINT32_MAX;
676ad5babeeSBob Moore 	outer_elements = return_object->package.elements;
677ad5babeeSBob Moore 	outer_element_count = return_object->package.count;
678ad5babeeSBob Moore 
679ad5babeeSBob Moore 	for (i = 0; i < outer_element_count; i++) {
680ad5babeeSBob Moore 		elements = (*outer_elements)->package.elements;
681ad5babeeSBob Moore 		obj_desc = elements[1];	/* Index1 = power_dissipation */
682ad5babeeSBob Moore 
683ad5babeeSBob Moore 		if ((u32)obj_desc->integer.value > previous_value) {
6841fad8738SBob Moore 			ACPI_WARN_PREDEFINED((AE_INFO,
6851fad8738SBob Moore 					      info->full_pathname,
68629a241ccSBob Moore 					      info->node_flags,
687ad5babeeSBob Moore 					      "SubPackage[%u,%u] - suspicious power dissipation values",
688ad5babeeSBob Moore 					      i - 1, i));
689ad5babeeSBob Moore 		}
690ad5babeeSBob Moore 
691ad5babeeSBob Moore 		previous_value = (u32) obj_desc->integer.value;
692ad5babeeSBob Moore 		outer_elements++;
693ad5babeeSBob Moore 	}
694ad5babeeSBob Moore 
695ad5babeeSBob Moore 	return (AE_OK);
696ad5babeeSBob Moore }
697ad5babeeSBob Moore 
698ad5babeeSBob Moore /******************************************************************************
699ad5babeeSBob Moore  *
700aa6329c4SLv Zheng  * FUNCTION:    acpi_ns_repair_TSS
701aa6329c4SLv Zheng  *
702aa6329c4SLv Zheng  * PARAMETERS:  info                - Method execution information block
703aa6329c4SLv Zheng  *              return_object_ptr   - Pointer to the object returned from the
704aa6329c4SLv Zheng  *                                    evaluation of a method or object
705aa6329c4SLv Zheng  *
706aa6329c4SLv Zheng  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
707aa6329c4SLv Zheng  *
708aa6329c4SLv Zheng  * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list
709aa6329c4SLv Zheng  *              descending by the power dissipation values.
710aa6329c4SLv Zheng  *
711aa6329c4SLv Zheng  *****************************************************************************/
712aa6329c4SLv Zheng 
713aa6329c4SLv Zheng static acpi_status
acpi_ns_repair_TSS(struct acpi_evaluate_info * info,union acpi_operand_object ** return_object_ptr)714aa6329c4SLv Zheng acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
715aa6329c4SLv Zheng 		   union acpi_operand_object **return_object_ptr)
716aa6329c4SLv Zheng {
717aa6329c4SLv Zheng 	union acpi_operand_object *return_object = *return_object_ptr;
718aa6329c4SLv Zheng 	acpi_status status;
719aa6329c4SLv Zheng 	struct acpi_namespace_node *node;
720aa6329c4SLv Zheng 
721aa6329c4SLv Zheng 	/*
722aa6329c4SLv Zheng 	 * We can only sort the _TSS return package if there is no _PSS in the
723aa6329c4SLv Zheng 	 * same scope. This is because if _PSS is present, the ACPI specification
724aa6329c4SLv Zheng 	 * dictates that the _TSS Power Dissipation field is to be ignored, and
725aa6329c4SLv Zheng 	 * therefore some BIOSs leave garbage values in the _TSS Power field(s).
726aa6329c4SLv Zheng 	 * In this case, it is best to just return the _TSS package as-is.
727aa6329c4SLv Zheng 	 * (May, 2011)
728aa6329c4SLv Zheng 	 */
729aa6329c4SLv Zheng 	status = acpi_ns_get_node(info->node, "^_PSS",
730aa6329c4SLv Zheng 				  ACPI_NS_NO_UPSEARCH, &node);
731aa6329c4SLv Zheng 	if (ACPI_SUCCESS(status)) {
732aa6329c4SLv Zheng 		return (AE_OK);
733aa6329c4SLv Zheng 	}
734aa6329c4SLv Zheng 
7355a9792f3SLv Zheng 	status = acpi_ns_check_sorted_list(info, return_object, 0, 5, 1,
736aa6329c4SLv Zheng 					   ACPI_SORT_DESCENDING,
737aa6329c4SLv Zheng 					   "PowerDissipation");
738aa6329c4SLv Zheng 
739aa6329c4SLv Zheng 	return (status);
740aa6329c4SLv Zheng }
741aa6329c4SLv Zheng 
742aa6329c4SLv Zheng /******************************************************************************
743aa6329c4SLv Zheng  *
744ad5babeeSBob Moore  * FUNCTION:    acpi_ns_check_sorted_list
745ad5babeeSBob Moore  *
74629a241ccSBob Moore  * PARAMETERS:  info                - Method execution information block
747ad5babeeSBob Moore  *              return_object       - Pointer to the top-level returned object
7480a16d12aSBob Moore  *              start_index         - Index of the first subpackage
7490a16d12aSBob Moore  *              expected_count      - Minimum length of each subpackage
7500a16d12aSBob Moore  *              sort_index          - Subpackage entry to sort on
751ad5babeeSBob Moore  *              sort_direction      - Ascending or descending
752ad5babeeSBob Moore  *              sort_key_name       - Name of the sort_index field
753ad5babeeSBob Moore  *
754ad5babeeSBob Moore  * RETURN:      Status. AE_OK if the list is valid and is sorted correctly or
755ad5babeeSBob Moore  *              has been repaired by sorting the list.
756ad5babeeSBob Moore  *
757ad5babeeSBob Moore  * DESCRIPTION: Check if the package list is valid and sorted correctly by the
758ad5babeeSBob Moore  *              sort_index. If not, then sort the list.
759ad5babeeSBob Moore  *
760ad5babeeSBob Moore  *****************************************************************************/
761ad5babeeSBob Moore 
762ad5babeeSBob Moore static acpi_status
acpi_ns_check_sorted_list(struct acpi_evaluate_info * info,union acpi_operand_object * return_object,u32 start_index,u32 expected_count,u32 sort_index,u8 sort_direction,char * sort_key_name)76329a241ccSBob Moore acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
764ad5babeeSBob Moore 			  union acpi_operand_object *return_object,
7655a9792f3SLv Zheng 			  u32 start_index,
766ad5babeeSBob Moore 			  u32 expected_count,
767ad5babeeSBob Moore 			  u32 sort_index,
768ad5babeeSBob Moore 			  u8 sort_direction, char *sort_key_name)
769ad5babeeSBob Moore {
770ad5babeeSBob Moore 	u32 outer_element_count;
771ad5babeeSBob Moore 	union acpi_operand_object **outer_elements;
772ad5babeeSBob Moore 	union acpi_operand_object **elements;
773ad5babeeSBob Moore 	union acpi_operand_object *obj_desc;
774ad5babeeSBob Moore 	u32 i;
775ad5babeeSBob Moore 	u32 previous_value;
776ad5babeeSBob Moore 
7773a58176eSBob Moore 	ACPI_FUNCTION_NAME(ns_check_sorted_list);
7783a58176eSBob Moore 
779ad5babeeSBob Moore 	/* The top-level object must be a package */
780ad5babeeSBob Moore 
781ad5babeeSBob Moore 	if (return_object->common.type != ACPI_TYPE_PACKAGE) {
782ad5babeeSBob Moore 		return (AE_AML_OPERAND_TYPE);
783ad5babeeSBob Moore 	}
784ad5babeeSBob Moore 
785ad5babeeSBob Moore 	/*
7860a16d12aSBob Moore 	 * NOTE: assumes list of subpackages contains no NULL elements.
787d4085a3fSBob Moore 	 * Any NULL elements should have been removed by earlier call
788d4085a3fSBob Moore 	 * to acpi_ns_remove_null_elements.
789ad5babeeSBob Moore 	 */
790ad5babeeSBob Moore 	outer_element_count = return_object->package.count;
7915a9792f3SLv Zheng 	if (!outer_element_count || start_index >= outer_element_count) {
792ad5babeeSBob Moore 		return (AE_AML_PACKAGE_LIMIT);
793ad5babeeSBob Moore 	}
794ad5babeeSBob Moore 
7955a9792f3SLv Zheng 	outer_elements = &return_object->package.elements[start_index];
7965a9792f3SLv Zheng 	outer_element_count -= start_index;
7975a9792f3SLv Zheng 
798ad5babeeSBob Moore 	previous_value = 0;
799ad5babeeSBob Moore 	if (sort_direction == ACPI_SORT_DESCENDING) {
800ad5babeeSBob Moore 		previous_value = ACPI_UINT32_MAX;
801ad5babeeSBob Moore 	}
802ad5babeeSBob Moore 
803ad5babeeSBob Moore 	/* Examine each subpackage */
804ad5babeeSBob Moore 
805ad5babeeSBob Moore 	for (i = 0; i < outer_element_count; i++) {
806ad5babeeSBob Moore 
807ad5babeeSBob Moore 		/* Each element of the top-level package must also be a package */
808ad5babeeSBob Moore 
809ad5babeeSBob Moore 		if ((*outer_elements)->common.type != ACPI_TYPE_PACKAGE) {
810ad5babeeSBob Moore 			return (AE_AML_OPERAND_TYPE);
811ad5babeeSBob Moore 		}
812ad5babeeSBob Moore 
8130a16d12aSBob Moore 		/* Each subpackage must have the minimum length */
814ad5babeeSBob Moore 
815ad5babeeSBob Moore 		if ((*outer_elements)->package.count < expected_count) {
816ad5babeeSBob Moore 			return (AE_AML_PACKAGE_LIMIT);
817ad5babeeSBob Moore 		}
818ad5babeeSBob Moore 
819ad5babeeSBob Moore 		elements = (*outer_elements)->package.elements;
820ad5babeeSBob Moore 		obj_desc = elements[sort_index];
821ad5babeeSBob Moore 
822ad5babeeSBob Moore 		if (obj_desc->common.type != ACPI_TYPE_INTEGER) {
823ad5babeeSBob Moore 			return (AE_AML_OPERAND_TYPE);
824ad5babeeSBob Moore 		}
825ad5babeeSBob Moore 
826ad5babeeSBob Moore 		/*
827ad5babeeSBob Moore 		 * The list must be sorted in the specified order. If we detect a
8282147d3f0SBob Moore 		 * discrepancy, sort the entire list.
829ad5babeeSBob Moore 		 */
830ad5babeeSBob Moore 		if (((sort_direction == ACPI_SORT_ASCENDING) &&
831ad5babeeSBob Moore 		     (obj_desc->integer.value < previous_value)) ||
832ad5babeeSBob Moore 		    ((sort_direction == ACPI_SORT_DESCENDING) &&
833ad5babeeSBob Moore 		     (obj_desc->integer.value > previous_value))) {
8345a9792f3SLv Zheng 			acpi_ns_sort_list(&return_object->package.
8355a9792f3SLv Zheng 					  elements[start_index],
836ad5babeeSBob Moore 					  outer_element_count, sort_index,
837ad5babeeSBob Moore 					  sort_direction);
838ad5babeeSBob Moore 
83929a241ccSBob Moore 			info->return_flags |= ACPI_OBJECT_REPAIRED;
840ad5babeeSBob Moore 
8413a58176eSBob Moore 			ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
8423a58176eSBob Moore 					  "%s: Repaired unsorted list - now sorted by %s\n",
84329a241ccSBob Moore 					  info->full_pathname, sort_key_name));
844ad5babeeSBob Moore 			return (AE_OK);
845ad5babeeSBob Moore 		}
846ad5babeeSBob Moore 
847ad5babeeSBob Moore 		previous_value = (u32) obj_desc->integer.value;
848ad5babeeSBob Moore 		outer_elements++;
849ad5babeeSBob Moore 	}
850ad5babeeSBob Moore 
851ad5babeeSBob Moore 	return (AE_OK);
852ad5babeeSBob Moore }
853ad5babeeSBob Moore 
854ad5babeeSBob Moore /******************************************************************************
855ad5babeeSBob Moore  *
856ad5babeeSBob Moore  * FUNCTION:    acpi_ns_sort_list
857ad5babeeSBob Moore  *
858ba494beeSBob Moore  * PARAMETERS:  elements            - Package object element list
859ba494beeSBob Moore  *              count               - Element count for above
860ba494beeSBob Moore  *              index               - Sort by which package element
861ad5babeeSBob Moore  *              sort_direction      - Ascending or Descending sort
862ad5babeeSBob Moore  *
8632147d3f0SBob Moore  * RETURN:      None
864ad5babeeSBob Moore  *
865ad5babeeSBob Moore  * DESCRIPTION: Sort the objects that are in a package element list.
866ad5babeeSBob Moore  *
8672147d3f0SBob Moore  * NOTE: Assumes that all NULL elements have been removed from the package,
8682147d3f0SBob Moore  *       and that all elements have been verified to be of type Integer.
869ad5babeeSBob Moore  *
870ad5babeeSBob Moore  *****************************************************************************/
871ad5babeeSBob Moore 
8722147d3f0SBob Moore static void
acpi_ns_sort_list(union acpi_operand_object ** elements,u32 count,u32 index,u8 sort_direction)873ad5babeeSBob Moore acpi_ns_sort_list(union acpi_operand_object **elements,
874ad5babeeSBob Moore 		  u32 count, u32 index, u8 sort_direction)
875ad5babeeSBob Moore {
876ad5babeeSBob Moore 	union acpi_operand_object *obj_desc1;
877ad5babeeSBob Moore 	union acpi_operand_object *obj_desc2;
878ad5babeeSBob Moore 	union acpi_operand_object *temp_obj;
879ad5babeeSBob Moore 	u32 i;
880ad5babeeSBob Moore 	u32 j;
881ad5babeeSBob Moore 
882ad5babeeSBob Moore 	/* Simple bubble sort */
883ad5babeeSBob Moore 
884ad5babeeSBob Moore 	for (i = 1; i < count; i++) {
885ad5babeeSBob Moore 		for (j = (count - 1); j >= i; j--) {
886ad5babeeSBob Moore 			obj_desc1 = elements[j - 1]->package.elements[index];
887ad5babeeSBob Moore 			obj_desc2 = elements[j]->package.elements[index];
888ad5babeeSBob Moore 
889ad5babeeSBob Moore 			if (((sort_direction == ACPI_SORT_ASCENDING) &&
890ad5babeeSBob Moore 			     (obj_desc1->integer.value >
891ad5babeeSBob Moore 			      obj_desc2->integer.value))
892ad5babeeSBob Moore 			    || ((sort_direction == ACPI_SORT_DESCENDING)
893ad5babeeSBob Moore 				&& (obj_desc1->integer.value <
894ad5babeeSBob Moore 				    obj_desc2->integer.value))) {
895ad5babeeSBob Moore 				temp_obj = elements[j - 1];
896ad5babeeSBob Moore 				elements[j - 1] = elements[j];
897ad5babeeSBob Moore 				elements[j] = temp_obj;
898ad5babeeSBob Moore 			}
899ad5babeeSBob Moore 		}
900ad5babeeSBob Moore 	}
901ad5babeeSBob Moore }
9025a9792f3SLv Zheng 
9035a9792f3SLv Zheng /******************************************************************************
9045a9792f3SLv Zheng  *
9055a9792f3SLv Zheng  * FUNCTION:    acpi_ns_remove_element
9065a9792f3SLv Zheng  *
9075a9792f3SLv Zheng  * PARAMETERS:  obj_desc            - Package object element list
9085a9792f3SLv Zheng  *              index               - Index of element to remove
9095a9792f3SLv Zheng  *
9105a9792f3SLv Zheng  * RETURN:      None
9115a9792f3SLv Zheng  *
9125a9792f3SLv Zheng  * DESCRIPTION: Remove the requested element of a package and delete it.
9135a9792f3SLv Zheng  *
9145a9792f3SLv Zheng  *****************************************************************************/
9155a9792f3SLv Zheng 
9165a9792f3SLv Zheng static void
acpi_ns_remove_element(union acpi_operand_object * obj_desc,u32 index)9175a9792f3SLv Zheng acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index)
9185a9792f3SLv Zheng {
9195a9792f3SLv Zheng 	union acpi_operand_object **source;
9205a9792f3SLv Zheng 	union acpi_operand_object **dest;
9215a9792f3SLv Zheng 	u32 count;
9225a9792f3SLv Zheng 	u32 new_count;
9235a9792f3SLv Zheng 	u32 i;
9245a9792f3SLv Zheng 
9255a9792f3SLv Zheng 	ACPI_FUNCTION_NAME(ns_remove_element);
9265a9792f3SLv Zheng 
9275a9792f3SLv Zheng 	count = obj_desc->package.count;
9285a9792f3SLv Zheng 	new_count = count - 1;
9295a9792f3SLv Zheng 
9305a9792f3SLv Zheng 	source = obj_desc->package.elements;
9315a9792f3SLv Zheng 	dest = source;
9325a9792f3SLv Zheng 
9335a9792f3SLv Zheng 	/* Examine all elements of the package object, remove matched index */
9345a9792f3SLv Zheng 
9355a9792f3SLv Zheng 	for (i = 0; i < count; i++) {
9365a9792f3SLv Zheng 		if (i == index) {
9375a9792f3SLv Zheng 			acpi_ut_remove_reference(*source);	/* Remove one ref for being in pkg */
9385a9792f3SLv Zheng 			acpi_ut_remove_reference(*source);
9395a9792f3SLv Zheng 		} else {
9405a9792f3SLv Zheng 			*dest = *source;
9415a9792f3SLv Zheng 			dest++;
9425a9792f3SLv Zheng 		}
9431fad8738SBob Moore 
9445a9792f3SLv Zheng 		source++;
9455a9792f3SLv Zheng 	}
9465a9792f3SLv Zheng 
9475a9792f3SLv Zheng 	/* NULL terminate list and update the package count */
9485a9792f3SLv Zheng 
9495a9792f3SLv Zheng 	*dest = NULL;
9505a9792f3SLv Zheng 	obj_desc->package.count = new_count;
9515a9792f3SLv Zheng }
952