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