Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /******************************************************************************
0003  *
0004  * Module Name: nsrepair2 - Repair for objects returned by specific
0005  *                          predefined methods
0006  *
0007  * Copyright (C) 2000 - 2022, Intel Corp.
0008  *
0009  *****************************************************************************/
0010 
0011 #include <acpi/acpi.h>
0012 #include "accommon.h"
0013 #include "acnamesp.h"
0014 
0015 #define _COMPONENT          ACPI_NAMESPACE
0016 ACPI_MODULE_NAME("nsrepair2")
0017 
0018 /*
0019  * Information structure and handler for ACPI predefined names that can
0020  * be repaired on a per-name basis.
0021  */
0022 typedef
0023 acpi_status (*acpi_repair_function) (struct acpi_evaluate_info * info,
0024                      union acpi_operand_object **
0025                      return_object_ptr);
0026 
0027 typedef struct acpi_repair_info {
0028     char name[ACPI_NAMESEG_SIZE];
0029     acpi_repair_function repair_function;
0030 
0031 } acpi_repair_info;
0032 
0033 /* Local prototypes */
0034 
0035 static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
0036                                    acpi_namespace_node
0037                                    *node);
0038 
0039 static acpi_status
0040 acpi_ns_repair_ALR(struct acpi_evaluate_info *info,
0041            union acpi_operand_object **return_object_ptr);
0042 
0043 static acpi_status
0044 acpi_ns_repair_CID(struct acpi_evaluate_info *info,
0045            union acpi_operand_object **return_object_ptr);
0046 
0047 static acpi_status
0048 acpi_ns_repair_CST(struct acpi_evaluate_info *info,
0049            union acpi_operand_object **return_object_ptr);
0050 
0051 static acpi_status
0052 acpi_ns_repair_FDE(struct acpi_evaluate_info *info,
0053            union acpi_operand_object **return_object_ptr);
0054 
0055 static acpi_status
0056 acpi_ns_repair_HID(struct acpi_evaluate_info *info,
0057            union acpi_operand_object **return_object_ptr);
0058 
0059 static acpi_status
0060 acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
0061            union acpi_operand_object **return_object_ptr);
0062 
0063 static acpi_status
0064 acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
0065            union acpi_operand_object **return_object_ptr);
0066 
0067 static acpi_status
0068 acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
0069            union acpi_operand_object **return_object_ptr);
0070 
0071 static acpi_status
0072 acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
0073               union acpi_operand_object *return_object,
0074               u32 start_index,
0075               u32 expected_count,
0076               u32 sort_index,
0077               u8 sort_direction, char *sort_key_name);
0078 
0079 /* Values for sort_direction above */
0080 
0081 #define ACPI_SORT_ASCENDING     0
0082 #define ACPI_SORT_DESCENDING    1
0083 
0084 static void
0085 acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index);
0086 
0087 static void
0088 acpi_ns_sort_list(union acpi_operand_object **elements,
0089           u32 count, u32 index, u8 sort_direction);
0090 
0091 /*
0092  * This table contains the names of the predefined methods for which we can
0093  * perform more complex repairs.
0094  *
0095  * As necessary:
0096  *
0097  * _ALR: Sort the list ascending by ambient_illuminance
0098  * _CID: Strings: uppercase all, remove any leading asterisk
0099  * _CST: Sort the list ascending by C state type
0100  * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs
0101  * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs
0102  * _HID: Strings: uppercase all, remove any leading asterisk
0103  * _PRT: Fix reversed source_name and source_index
0104  * _PSS: Sort the list descending by Power
0105  * _TSS: Sort the list descending by Power
0106  *
0107  * Names that must be packages, but cannot be sorted:
0108  *
0109  * _BCL: Values are tied to the Package index where they appear, and cannot
0110  * be moved or sorted. These index values are used for _BQC and _BCM.
0111  * However, we can fix the case where a buffer is returned, by converting
0112  * it to a Package of integers.
0113  */
0114 static const struct acpi_repair_info acpi_ns_repairable_names[] = {
0115     {"_ALR", acpi_ns_repair_ALR},
0116     {"_CID", acpi_ns_repair_CID},
0117     {"_CST", acpi_ns_repair_CST},
0118     {"_FDE", acpi_ns_repair_FDE},
0119     {"_GTM", acpi_ns_repair_FDE},   /* _GTM has same repair as _FDE */
0120     {"_HID", acpi_ns_repair_HID},
0121     {"_PRT", acpi_ns_repair_PRT},
0122     {"_PSS", acpi_ns_repair_PSS},
0123     {"_TSS", acpi_ns_repair_TSS},
0124     {{0, 0, 0, 0}, NULL}    /* Table terminator */
0125 };
0126 
0127 #define ACPI_FDE_FIELD_COUNT        5
0128 #define ACPI_FDE_BYTE_BUFFER_SIZE   5
0129 #define ACPI_FDE_DWORD_BUFFER_SIZE  (ACPI_FDE_FIELD_COUNT * (u32) sizeof (u32))
0130 
0131 /******************************************************************************
0132  *
0133  * FUNCTION:    acpi_ns_complex_repairs
0134  *
0135  * PARAMETERS:  info                - Method execution information block
0136  *              node                - Namespace node for the method/object
0137  *              validate_status     - Original status of earlier validation
0138  *              return_object_ptr   - Pointer to the object returned from the
0139  *                                    evaluation of a method or object
0140  *
0141  * RETURN:      Status. AE_OK if repair was successful. If name is not
0142  *              matched, validate_status is returned.
0143  *
0144  * DESCRIPTION: Attempt to repair/convert a return object of a type that was
0145  *              not expected.
0146  *
0147  *****************************************************************************/
0148 
0149 acpi_status
0150 acpi_ns_complex_repairs(struct acpi_evaluate_info *info,
0151             struct acpi_namespace_node *node,
0152             acpi_status validate_status,
0153             union acpi_operand_object **return_object_ptr)
0154 {
0155     const struct acpi_repair_info *predefined;
0156     acpi_status status;
0157 
0158     ACPI_FUNCTION_TRACE(ns_complex_repairs);
0159 
0160     /* Check if this name is in the list of repairable names */
0161 
0162     predefined = acpi_ns_match_complex_repair(node);
0163     if (!predefined) {
0164         return_ACPI_STATUS(validate_status);
0165     }
0166 
0167     status = predefined->repair_function(info, return_object_ptr);
0168     return_ACPI_STATUS(status);
0169 }
0170 
0171 /******************************************************************************
0172  *
0173  * FUNCTION:    acpi_ns_match_complex_repair
0174  *
0175  * PARAMETERS:  node                - Namespace node for the method/object
0176  *
0177  * RETURN:      Pointer to entry in repair table. NULL indicates not found.
0178  *
0179  * DESCRIPTION: Check an object name against the repairable object list.
0180  *
0181  *****************************************************************************/
0182 
0183 static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
0184                                    acpi_namespace_node
0185                                    *node)
0186 {
0187     const struct acpi_repair_info *this_name;
0188 
0189     /* Search info table for a repairable predefined method/object name */
0190 
0191     this_name = acpi_ns_repairable_names;
0192     while (this_name->repair_function) {
0193         if (ACPI_COMPARE_NAMESEG(node->name.ascii, this_name->name)) {
0194             return (this_name);
0195         }
0196 
0197         this_name++;
0198     }
0199 
0200     return (NULL);      /* Not found */
0201 }
0202 
0203 /******************************************************************************
0204  *
0205  * FUNCTION:    acpi_ns_repair_ALR
0206  *
0207  * PARAMETERS:  info                - Method execution information block
0208  *              return_object_ptr   - Pointer to the object returned from the
0209  *                                    evaluation of a method or object
0210  *
0211  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
0212  *
0213  * DESCRIPTION: Repair for the _ALR object. If necessary, sort the object list
0214  *              ascending by the ambient illuminance values.
0215  *
0216  *****************************************************************************/
0217 
0218 static acpi_status
0219 acpi_ns_repair_ALR(struct acpi_evaluate_info *info,
0220            union acpi_operand_object **return_object_ptr)
0221 {
0222     union acpi_operand_object *return_object = *return_object_ptr;
0223     acpi_status status;
0224 
0225     status = acpi_ns_check_sorted_list(info, return_object, 0, 2, 1,
0226                        ACPI_SORT_ASCENDING,
0227                        "AmbientIlluminance");
0228 
0229     return (status);
0230 }
0231 
0232 /******************************************************************************
0233  *
0234  * FUNCTION:    acpi_ns_repair_FDE
0235  *
0236  * PARAMETERS:  info                - Method execution information block
0237  *              return_object_ptr   - Pointer to the object returned from the
0238  *                                    evaluation of a method or object
0239  *
0240  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
0241  *
0242  * DESCRIPTION: Repair for the _FDE and _GTM objects. The expected return
0243  *              value is a Buffer of 5 DWORDs. This function repairs a common
0244  *              problem where the return value is a Buffer of BYTEs, not
0245  *              DWORDs.
0246  *
0247  *****************************************************************************/
0248 
0249 static acpi_status
0250 acpi_ns_repair_FDE(struct acpi_evaluate_info *info,
0251            union acpi_operand_object **return_object_ptr)
0252 {
0253     union acpi_operand_object *return_object = *return_object_ptr;
0254     union acpi_operand_object *buffer_object;
0255     u8 *byte_buffer;
0256     u32 *dword_buffer;
0257     u32 i;
0258 
0259     ACPI_FUNCTION_NAME(ns_repair_FDE);
0260 
0261     switch (return_object->common.type) {
0262     case ACPI_TYPE_BUFFER:
0263 
0264         /* This is the expected type. Length should be (at least) 5 DWORDs */
0265 
0266         if (return_object->buffer.length >= ACPI_FDE_DWORD_BUFFER_SIZE) {
0267             return (AE_OK);
0268         }
0269 
0270         /* We can only repair if we have exactly 5 BYTEs */
0271 
0272         if (return_object->buffer.length != ACPI_FDE_BYTE_BUFFER_SIZE) {
0273             ACPI_WARN_PREDEFINED((AE_INFO,
0274                           info->full_pathname,
0275                           info->node_flags,
0276                           "Incorrect return buffer length %u, expected %u",
0277                           return_object->buffer.length,
0278                           ACPI_FDE_DWORD_BUFFER_SIZE));
0279 
0280             return (AE_AML_OPERAND_TYPE);
0281         }
0282 
0283         /* Create the new (larger) buffer object */
0284 
0285         buffer_object =
0286             acpi_ut_create_buffer_object(ACPI_FDE_DWORD_BUFFER_SIZE);
0287         if (!buffer_object) {
0288             return (AE_NO_MEMORY);
0289         }
0290 
0291         /* Expand each byte to a DWORD */
0292 
0293         byte_buffer = return_object->buffer.pointer;
0294         dword_buffer = ACPI_CAST_PTR(u32,
0295                          buffer_object->buffer.pointer);
0296 
0297         for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++) {
0298             *dword_buffer = (u32) *byte_buffer;
0299             dword_buffer++;
0300             byte_buffer++;
0301         }
0302 
0303         ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
0304                   "%s Expanded Byte Buffer to expected DWord Buffer\n",
0305                   info->full_pathname));
0306         break;
0307 
0308     default:
0309 
0310         return (AE_AML_OPERAND_TYPE);
0311     }
0312 
0313     /* Delete the original return object, return the new buffer object */
0314 
0315     acpi_ut_remove_reference(return_object);
0316     *return_object_ptr = buffer_object;
0317 
0318     info->return_flags |= ACPI_OBJECT_REPAIRED;
0319     return (AE_OK);
0320 }
0321 
0322 /******************************************************************************
0323  *
0324  * FUNCTION:    acpi_ns_repair_CID
0325  *
0326  * PARAMETERS:  info                - Method execution information block
0327  *              return_object_ptr   - Pointer to the object returned from the
0328  *                                    evaluation of a method or object
0329  *
0330  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
0331  *
0332  * DESCRIPTION: Repair for the _CID object. If a string, ensure that all
0333  *              letters are uppercase and that there is no leading asterisk.
0334  *              If a Package, ensure same for all string elements.
0335  *
0336  *****************************************************************************/
0337 
0338 static acpi_status
0339 acpi_ns_repair_CID(struct acpi_evaluate_info *info,
0340            union acpi_operand_object **return_object_ptr)
0341 {
0342     acpi_status status;
0343     union acpi_operand_object *return_object = *return_object_ptr;
0344     union acpi_operand_object **element_ptr;
0345     union acpi_operand_object *original_element;
0346     u16 original_ref_count;
0347     u32 i;
0348 
0349     ACPI_FUNCTION_TRACE(ns_repair_CID);
0350 
0351     /* Check for _CID as a simple string */
0352 
0353     if (return_object->common.type == ACPI_TYPE_STRING) {
0354         status = acpi_ns_repair_HID(info, return_object_ptr);
0355         return_ACPI_STATUS(status);
0356     }
0357 
0358     /* Exit if not a Package */
0359 
0360     if (return_object->common.type != ACPI_TYPE_PACKAGE) {
0361         return_ACPI_STATUS(AE_OK);
0362     }
0363 
0364     /* Examine each element of the _CID package */
0365 
0366     element_ptr = return_object->package.elements;
0367     for (i = 0; i < return_object->package.count; i++) {
0368         original_element = *element_ptr;
0369         original_ref_count = original_element->common.reference_count;
0370 
0371         status = acpi_ns_repair_HID(info, element_ptr);
0372         if (ACPI_FAILURE(status)) {
0373             return_ACPI_STATUS(status);
0374         }
0375 
0376         if (original_element != *element_ptr) {
0377 
0378             /* Update reference count of new object */
0379 
0380             (*element_ptr)->common.reference_count =
0381                 original_ref_count;
0382         }
0383 
0384         element_ptr++;
0385     }
0386 
0387     return_ACPI_STATUS(AE_OK);
0388 }
0389 
0390 /******************************************************************************
0391  *
0392  * FUNCTION:    acpi_ns_repair_CST
0393  *
0394  * PARAMETERS:  info                - Method execution information block
0395  *              return_object_ptr   - Pointer to the object returned from the
0396  *                                    evaluation of a method or object
0397  *
0398  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
0399  *
0400  * DESCRIPTION: Repair for the _CST object:
0401  *              1. Sort the list ascending by C state type
0402  *              2. Ensure type cannot be zero
0403  *              3. A subpackage count of zero means _CST is meaningless
0404  *              4. Count must match the number of C state subpackages
0405  *
0406  *****************************************************************************/
0407 
0408 static acpi_status
0409 acpi_ns_repair_CST(struct acpi_evaluate_info *info,
0410            union acpi_operand_object **return_object_ptr)
0411 {
0412     union acpi_operand_object *return_object = *return_object_ptr;
0413     union acpi_operand_object **outer_elements;
0414     u32 outer_element_count;
0415     union acpi_operand_object *obj_desc;
0416     acpi_status status;
0417     u8 removing;
0418     u32 i;
0419 
0420     ACPI_FUNCTION_NAME(ns_repair_CST);
0421 
0422     /*
0423      * Check if the C-state type values are proportional.
0424      */
0425     outer_element_count = return_object->package.count - 1;
0426     i = 0;
0427     while (i < outer_element_count) {
0428         outer_elements = &return_object->package.elements[i + 1];
0429         removing = FALSE;
0430 
0431         if ((*outer_elements)->package.count == 0) {
0432             ACPI_WARN_PREDEFINED((AE_INFO,
0433                           info->full_pathname,
0434                           info->node_flags,
0435                           "SubPackage[%u] - removing entry due to zero count",
0436                           i));
0437             removing = TRUE;
0438             goto remove_element;
0439         }
0440 
0441         obj_desc = (*outer_elements)->package.elements[1];  /* Index1 = Type */
0442         if ((u32)obj_desc->integer.value == 0) {
0443             ACPI_WARN_PREDEFINED((AE_INFO,
0444                           info->full_pathname,
0445                           info->node_flags,
0446                           "SubPackage[%u] - removing entry due to invalid Type(0)",
0447                           i));
0448             removing = TRUE;
0449         }
0450 
0451 remove_element:
0452         if (removing) {
0453             acpi_ns_remove_element(return_object, i + 1);
0454             outer_element_count--;
0455         } else {
0456             i++;
0457         }
0458     }
0459 
0460     /* Update top-level package count, Type "Integer" checked elsewhere */
0461 
0462     obj_desc = return_object->package.elements[0];
0463     obj_desc->integer.value = outer_element_count;
0464 
0465     /*
0466      * Entries (subpackages) in the _CST Package must be sorted by the
0467      * C-state type, in ascending order.
0468      */
0469     status = acpi_ns_check_sorted_list(info, return_object, 1, 4, 1,
0470                        ACPI_SORT_ASCENDING, "C-State Type");
0471     if (ACPI_FAILURE(status)) {
0472         return (status);
0473     }
0474 
0475     return (AE_OK);
0476 }
0477 
0478 /******************************************************************************
0479  *
0480  * FUNCTION:    acpi_ns_repair_HID
0481  *
0482  * PARAMETERS:  info                - Method execution information block
0483  *              return_object_ptr   - Pointer to the object returned from the
0484  *                                    evaluation of a method or object
0485  *
0486  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
0487  *
0488  * DESCRIPTION: Repair for the _HID object. If a string, ensure that all
0489  *              letters are uppercase and that there is no leading asterisk.
0490  *
0491  *****************************************************************************/
0492 
0493 static acpi_status
0494 acpi_ns_repair_HID(struct acpi_evaluate_info *info,
0495            union acpi_operand_object **return_object_ptr)
0496 {
0497     union acpi_operand_object *return_object = *return_object_ptr;
0498     union acpi_operand_object *new_string;
0499     char *source;
0500     char *dest;
0501 
0502     ACPI_FUNCTION_NAME(ns_repair_HID);
0503 
0504     /* We only care about string _HID objects (not integers) */
0505 
0506     if (return_object->common.type != ACPI_TYPE_STRING) {
0507         return_ACPI_STATUS(AE_OK);
0508     }
0509 
0510     if (return_object->string.length == 0) {
0511         ACPI_WARN_PREDEFINED((AE_INFO,
0512                       info->full_pathname, info->node_flags,
0513                       "Invalid zero-length _HID or _CID string"));
0514 
0515         /* Return AE_OK anyway, let driver handle it */
0516 
0517         info->return_flags |= ACPI_OBJECT_REPAIRED;
0518         return_ACPI_STATUS(AE_OK);
0519     }
0520 
0521     /* It is simplest to always create a new string object */
0522 
0523     new_string = acpi_ut_create_string_object(return_object->string.length);
0524     if (!new_string) {
0525         return_ACPI_STATUS(AE_NO_MEMORY);
0526     }
0527 
0528     /*
0529      * Remove a leading asterisk if present. For some unknown reason, there
0530      * are many machines in the field that contains IDs like this.
0531      *
0532      * Examples: "*PNP0C03", "*ACPI0003"
0533      */
0534     source = return_object->string.pointer;
0535     if (*source == '*') {
0536         source++;
0537         new_string->string.length--;
0538 
0539         ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
0540                   "%s: Removed invalid leading asterisk\n",
0541                   info->full_pathname));
0542     }
0543 
0544     /*
0545      * Copy and uppercase the string. From the ACPI 5.0 specification:
0546      *
0547      * A valid PNP ID must be of the form "AAA####" where A is an uppercase
0548      * letter and # is a hex digit. A valid ACPI ID must be of the form
0549      * "NNNN####" where N is an uppercase letter or decimal digit, and
0550      * # is a hex digit.
0551      */
0552     for (dest = new_string->string.pointer; *source; dest++, source++) {
0553         *dest = (char)toupper((int)*source);
0554     }
0555 
0556     acpi_ut_remove_reference(return_object);
0557     *return_object_ptr = new_string;
0558     return_ACPI_STATUS(AE_OK);
0559 }
0560 
0561 /******************************************************************************
0562  *
0563  * FUNCTION:    acpi_ns_repair_PRT
0564  *
0565  * PARAMETERS:  info                - Method execution information block
0566  *              return_object_ptr   - Pointer to the object returned from the
0567  *                                    evaluation of a method or object
0568  *
0569  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
0570  *
0571  * DESCRIPTION: Repair for the _PRT object. If necessary, fix reversed
0572  *              source_name and source_index field, a common BIOS bug.
0573  *
0574  *****************************************************************************/
0575 
0576 static acpi_status
0577 acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
0578            union acpi_operand_object **return_object_ptr)
0579 {
0580     union acpi_operand_object *package_object = *return_object_ptr;
0581     union acpi_operand_object **top_object_list;
0582     union acpi_operand_object **sub_object_list;
0583     union acpi_operand_object *obj_desc;
0584     union acpi_operand_object *sub_package;
0585     u32 element_count;
0586     u32 index;
0587 
0588     /* Each element in the _PRT package is a subpackage */
0589 
0590     top_object_list = package_object->package.elements;
0591     element_count = package_object->package.count;
0592 
0593     /* Examine each subpackage */
0594 
0595     for (index = 0; index < element_count; index++, top_object_list++) {
0596         sub_package = *top_object_list;
0597         sub_object_list = sub_package->package.elements;
0598 
0599         /* Check for minimum required element count */
0600 
0601         if (sub_package->package.count < 4) {
0602             continue;
0603         }
0604 
0605         /*
0606          * If the BIOS has erroneously reversed the _PRT source_name (index 2)
0607          * and the source_index (index 3), fix it. _PRT is important enough to
0608          * workaround this BIOS error. This also provides compatibility with
0609          * other ACPI implementations.
0610          */
0611         obj_desc = sub_object_list[3];
0612         if (!obj_desc || (obj_desc->common.type != ACPI_TYPE_INTEGER)) {
0613             sub_object_list[3] = sub_object_list[2];
0614             sub_object_list[2] = obj_desc;
0615             info->return_flags |= ACPI_OBJECT_REPAIRED;
0616 
0617             ACPI_WARN_PREDEFINED((AE_INFO,
0618                           info->full_pathname,
0619                           info->node_flags,
0620                           "PRT[%X]: Fixed reversed SourceName and SourceIndex",
0621                           index));
0622         }
0623     }
0624 
0625     return (AE_OK);
0626 }
0627 
0628 /******************************************************************************
0629  *
0630  * FUNCTION:    acpi_ns_repair_PSS
0631  *
0632  * PARAMETERS:  info                - Method execution information block
0633  *              return_object_ptr   - Pointer to the object returned from the
0634  *                                    evaluation of a method or object
0635  *
0636  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
0637  *
0638  * DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list
0639  *              by the CPU frequencies. Check that the power dissipation values
0640  *              are all proportional to CPU frequency (i.e., sorting by
0641  *              frequency should be the same as sorting by power.)
0642  *
0643  *****************************************************************************/
0644 
0645 static acpi_status
0646 acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
0647            union acpi_operand_object **return_object_ptr)
0648 {
0649     union acpi_operand_object *return_object = *return_object_ptr;
0650     union acpi_operand_object **outer_elements;
0651     u32 outer_element_count;
0652     union acpi_operand_object **elements;
0653     union acpi_operand_object *obj_desc;
0654     u32 previous_value;
0655     acpi_status status;
0656     u32 i;
0657 
0658     /*
0659      * Entries (subpackages) in the _PSS Package must be sorted by power
0660      * dissipation, in descending order. If it appears that the list is
0661      * incorrectly sorted, sort it. We sort by cpu_frequency, since this
0662      * should be proportional to the power.
0663      */
0664     status = acpi_ns_check_sorted_list(info, return_object, 0, 6, 0,
0665                        ACPI_SORT_DESCENDING,
0666                        "CpuFrequency");
0667     if (ACPI_FAILURE(status)) {
0668         return (status);
0669     }
0670 
0671     /*
0672      * We now know the list is correctly sorted by CPU frequency. Check if
0673      * the power dissipation values are proportional.
0674      */
0675     previous_value = ACPI_UINT32_MAX;
0676     outer_elements = return_object->package.elements;
0677     outer_element_count = return_object->package.count;
0678 
0679     for (i = 0; i < outer_element_count; i++) {
0680         elements = (*outer_elements)->package.elements;
0681         obj_desc = elements[1]; /* Index1 = power_dissipation */
0682 
0683         if ((u32)obj_desc->integer.value > previous_value) {
0684             ACPI_WARN_PREDEFINED((AE_INFO,
0685                           info->full_pathname,
0686                           info->node_flags,
0687                           "SubPackage[%u,%u] - suspicious power dissipation values",
0688                           i - 1, i));
0689         }
0690 
0691         previous_value = (u32) obj_desc->integer.value;
0692         outer_elements++;
0693     }
0694 
0695     return (AE_OK);
0696 }
0697 
0698 /******************************************************************************
0699  *
0700  * FUNCTION:    acpi_ns_repair_TSS
0701  *
0702  * PARAMETERS:  info                - Method execution information block
0703  *              return_object_ptr   - Pointer to the object returned from the
0704  *                                    evaluation of a method or object
0705  *
0706  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
0707  *
0708  * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list
0709  *              descending by the power dissipation values.
0710  *
0711  *****************************************************************************/
0712 
0713 static acpi_status
0714 acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
0715            union acpi_operand_object **return_object_ptr)
0716 {
0717     union acpi_operand_object *return_object = *return_object_ptr;
0718     acpi_status status;
0719     struct acpi_namespace_node *node;
0720 
0721     /*
0722      * We can only sort the _TSS return package if there is no _PSS in the
0723      * same scope. This is because if _PSS is present, the ACPI specification
0724      * dictates that the _TSS Power Dissipation field is to be ignored, and
0725      * therefore some BIOSs leave garbage values in the _TSS Power field(s).
0726      * In this case, it is best to just return the _TSS package as-is.
0727      * (May, 2011)
0728      */
0729     status = acpi_ns_get_node(info->node, "^_PSS",
0730                   ACPI_NS_NO_UPSEARCH, &node);
0731     if (ACPI_SUCCESS(status)) {
0732         return (AE_OK);
0733     }
0734 
0735     status = acpi_ns_check_sorted_list(info, return_object, 0, 5, 1,
0736                        ACPI_SORT_DESCENDING,
0737                        "PowerDissipation");
0738 
0739     return (status);
0740 }
0741 
0742 /******************************************************************************
0743  *
0744  * FUNCTION:    acpi_ns_check_sorted_list
0745  *
0746  * PARAMETERS:  info                - Method execution information block
0747  *              return_object       - Pointer to the top-level returned object
0748  *              start_index         - Index of the first subpackage
0749  *              expected_count      - Minimum length of each subpackage
0750  *              sort_index          - Subpackage entry to sort on
0751  *              sort_direction      - Ascending or descending
0752  *              sort_key_name       - Name of the sort_index field
0753  *
0754  * RETURN:      Status. AE_OK if the list is valid and is sorted correctly or
0755  *              has been repaired by sorting the list.
0756  *
0757  * DESCRIPTION: Check if the package list is valid and sorted correctly by the
0758  *              sort_index. If not, then sort the list.
0759  *
0760  *****************************************************************************/
0761 
0762 static acpi_status
0763 acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
0764               union acpi_operand_object *return_object,
0765               u32 start_index,
0766               u32 expected_count,
0767               u32 sort_index,
0768               u8 sort_direction, char *sort_key_name)
0769 {
0770     u32 outer_element_count;
0771     union acpi_operand_object **outer_elements;
0772     union acpi_operand_object **elements;
0773     union acpi_operand_object *obj_desc;
0774     u32 i;
0775     u32 previous_value;
0776 
0777     ACPI_FUNCTION_NAME(ns_check_sorted_list);
0778 
0779     /* The top-level object must be a package */
0780 
0781     if (return_object->common.type != ACPI_TYPE_PACKAGE) {
0782         return (AE_AML_OPERAND_TYPE);
0783     }
0784 
0785     /*
0786      * NOTE: assumes list of subpackages contains no NULL elements.
0787      * Any NULL elements should have been removed by earlier call
0788      * to acpi_ns_remove_null_elements.
0789      */
0790     outer_element_count = return_object->package.count;
0791     if (!outer_element_count || start_index >= outer_element_count) {
0792         return (AE_AML_PACKAGE_LIMIT);
0793     }
0794 
0795     outer_elements = &return_object->package.elements[start_index];
0796     outer_element_count -= start_index;
0797 
0798     previous_value = 0;
0799     if (sort_direction == ACPI_SORT_DESCENDING) {
0800         previous_value = ACPI_UINT32_MAX;
0801     }
0802 
0803     /* Examine each subpackage */
0804 
0805     for (i = 0; i < outer_element_count; i++) {
0806 
0807         /* Each element of the top-level package must also be a package */
0808 
0809         if ((*outer_elements)->common.type != ACPI_TYPE_PACKAGE) {
0810             return (AE_AML_OPERAND_TYPE);
0811         }
0812 
0813         /* Each subpackage must have the minimum length */
0814 
0815         if ((*outer_elements)->package.count < expected_count) {
0816             return (AE_AML_PACKAGE_LIMIT);
0817         }
0818 
0819         elements = (*outer_elements)->package.elements;
0820         obj_desc = elements[sort_index];
0821 
0822         if (obj_desc->common.type != ACPI_TYPE_INTEGER) {
0823             return (AE_AML_OPERAND_TYPE);
0824         }
0825 
0826         /*
0827          * The list must be sorted in the specified order. If we detect a
0828          * discrepancy, sort the entire list.
0829          */
0830         if (((sort_direction == ACPI_SORT_ASCENDING) &&
0831              (obj_desc->integer.value < previous_value)) ||
0832             ((sort_direction == ACPI_SORT_DESCENDING) &&
0833              (obj_desc->integer.value > previous_value))) {
0834             acpi_ns_sort_list(&return_object->package.
0835                       elements[start_index],
0836                       outer_element_count, sort_index,
0837                       sort_direction);
0838 
0839             info->return_flags |= ACPI_OBJECT_REPAIRED;
0840 
0841             ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
0842                       "%s: Repaired unsorted list - now sorted by %s\n",
0843                       info->full_pathname, sort_key_name));
0844             return (AE_OK);
0845         }
0846 
0847         previous_value = (u32) obj_desc->integer.value;
0848         outer_elements++;
0849     }
0850 
0851     return (AE_OK);
0852 }
0853 
0854 /******************************************************************************
0855  *
0856  * FUNCTION:    acpi_ns_sort_list
0857  *
0858  * PARAMETERS:  elements            - Package object element list
0859  *              count               - Element count for above
0860  *              index               - Sort by which package element
0861  *              sort_direction      - Ascending or Descending sort
0862  *
0863  * RETURN:      None
0864  *
0865  * DESCRIPTION: Sort the objects that are in a package element list.
0866  *
0867  * NOTE: Assumes that all NULL elements have been removed from the package,
0868  *       and that all elements have been verified to be of type Integer.
0869  *
0870  *****************************************************************************/
0871 
0872 static void
0873 acpi_ns_sort_list(union acpi_operand_object **elements,
0874           u32 count, u32 index, u8 sort_direction)
0875 {
0876     union acpi_operand_object *obj_desc1;
0877     union acpi_operand_object *obj_desc2;
0878     union acpi_operand_object *temp_obj;
0879     u32 i;
0880     u32 j;
0881 
0882     /* Simple bubble sort */
0883 
0884     for (i = 1; i < count; i++) {
0885         for (j = (count - 1); j >= i; j--) {
0886             obj_desc1 = elements[j - 1]->package.elements[index];
0887             obj_desc2 = elements[j]->package.elements[index];
0888 
0889             if (((sort_direction == ACPI_SORT_ASCENDING) &&
0890                  (obj_desc1->integer.value >
0891                   obj_desc2->integer.value))
0892                 || ((sort_direction == ACPI_SORT_DESCENDING)
0893                 && (obj_desc1->integer.value <
0894                     obj_desc2->integer.value))) {
0895                 temp_obj = elements[j - 1];
0896                 elements[j - 1] = elements[j];
0897                 elements[j] = temp_obj;
0898             }
0899         }
0900     }
0901 }
0902 
0903 /******************************************************************************
0904  *
0905  * FUNCTION:    acpi_ns_remove_element
0906  *
0907  * PARAMETERS:  obj_desc            - Package object element list
0908  *              index               - Index of element to remove
0909  *
0910  * RETURN:      None
0911  *
0912  * DESCRIPTION: Remove the requested element of a package and delete it.
0913  *
0914  *****************************************************************************/
0915 
0916 static void
0917 acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index)
0918 {
0919     union acpi_operand_object **source;
0920     union acpi_operand_object **dest;
0921     u32 count;
0922     u32 new_count;
0923     u32 i;
0924 
0925     ACPI_FUNCTION_NAME(ns_remove_element);
0926 
0927     count = obj_desc->package.count;
0928     new_count = count - 1;
0929 
0930     source = obj_desc->package.elements;
0931     dest = source;
0932 
0933     /* Examine all elements of the package object, remove matched index */
0934 
0935     for (i = 0; i < count; i++) {
0936         if (i == index) {
0937             acpi_ut_remove_reference(*source);  /* Remove one ref for being in pkg */
0938             acpi_ut_remove_reference(*source);
0939         } else {
0940             *dest = *source;
0941             dest++;
0942         }
0943 
0944         source++;
0945     }
0946 
0947     /* NULL terminate list and update the package count */
0948 
0949     *dest = NULL;
0950     obj_desc->package.count = new_count;
0951 }