linux/drivers/acpi/acpica/nsrepair2.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/******************************************************************************
   3 *
   4 * Module Name: nsrepair2 - Repair for objects returned by specific
   5 *                          predefined methods
   6 *
   7 * Copyright (C) 2000 - 2019, Intel Corp.
   8 *
   9 *****************************************************************************/
  10
  11#include <acpi/acpi.h>
  12#include "accommon.h"
  13#include "acnamesp.h"
  14
  15#define _COMPONENT          ACPI_NAMESPACE
  16ACPI_MODULE_NAME("nsrepair2")
  17
  18/*
  19 * Information structure and handler for ACPI predefined names that can
  20 * be repaired on a per-name basis.
  21 */
  22typedef
  23acpi_status (*acpi_repair_function) (struct acpi_evaluate_info * info,
  24                                     union acpi_operand_object **
  25                                     return_object_ptr);
  26
  27typedef struct acpi_repair_info {
  28        char name[ACPI_NAMESEG_SIZE];
  29        acpi_repair_function repair_function;
  30
  31} acpi_repair_info;
  32
  33/* Local prototypes */
  34
  35static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
  36                                                                   acpi_namespace_node
  37                                                                   *node);
  38
  39static acpi_status
  40acpi_ns_repair_ALR(struct acpi_evaluate_info *info,
  41                   union acpi_operand_object **return_object_ptr);
  42
  43static acpi_status
  44acpi_ns_repair_CID(struct acpi_evaluate_info *info,
  45                   union acpi_operand_object **return_object_ptr);
  46
  47static acpi_status
  48acpi_ns_repair_CST(struct acpi_evaluate_info *info,
  49                   union acpi_operand_object **return_object_ptr);
  50
  51static acpi_status
  52acpi_ns_repair_FDE(struct acpi_evaluate_info *info,
  53                   union acpi_operand_object **return_object_ptr);
  54
  55static acpi_status
  56acpi_ns_repair_HID(struct acpi_evaluate_info *info,
  57                   union acpi_operand_object **return_object_ptr);
  58
  59static acpi_status
  60acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
  61                   union acpi_operand_object **return_object_ptr);
  62
  63static acpi_status
  64acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
  65                   union acpi_operand_object **return_object_ptr);
  66
  67static acpi_status
  68acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
  69                   union acpi_operand_object **return_object_ptr);
  70
  71static acpi_status
  72acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
  73                          union acpi_operand_object *return_object,
  74                          u32 start_index,
  75                          u32 expected_count,
  76                          u32 sort_index,
  77                          u8 sort_direction, char *sort_key_name);
  78
  79/* Values for sort_direction above */
  80
  81#define ACPI_SORT_ASCENDING     0
  82#define ACPI_SORT_DESCENDING    1
  83
  84static void
  85acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index);
  86
  87static void
  88acpi_ns_sort_list(union acpi_operand_object **elements,
  89                  u32 count, u32 index, u8 sort_direction);
  90
  91/*
  92 * This table contains the names of the predefined methods for which we can
  93 * perform more complex repairs.
  94 *
  95 * As necessary:
  96 *
  97 * _ALR: Sort the list ascending by ambient_illuminance
  98 * _CID: Strings: uppercase all, remove any leading asterisk
  99 * _CST: Sort the list ascending by C state type
 100 * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs
 101 * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs
 102 * _HID: Strings: uppercase all, remove any leading asterisk
 103 * _PRT: Fix reversed source_name and source_index
 104 * _PSS: Sort the list descending by Power
 105 * _TSS: Sort the list descending by Power
 106 *
 107 * Names that must be packages, but cannot be sorted:
 108 *
 109 * _BCL: Values are tied to the Package index where they appear, and cannot
 110 * be moved or sorted. These index values are used for _BQC and _BCM.
 111 * However, we can fix the case where a buffer is returned, by converting
 112 * it to a Package of integers.
 113 */
 114static const struct acpi_repair_info acpi_ns_repairable_names[] = {
 115        {"_ALR", acpi_ns_repair_ALR},
 116        {"_CID", acpi_ns_repair_CID},
 117        {"_CST", acpi_ns_repair_CST},
 118        {"_FDE", acpi_ns_repair_FDE},
 119        {"_GTM", acpi_ns_repair_FDE},   /* _GTM has same repair as _FDE */
 120        {"_HID", acpi_ns_repair_HID},
 121        {"_PRT", acpi_ns_repair_PRT},
 122        {"_PSS", acpi_ns_repair_PSS},
 123        {"_TSS", acpi_ns_repair_TSS},
 124        {{0, 0, 0, 0}, NULL}    /* Table terminator */
 125};
 126
 127#define ACPI_FDE_FIELD_COUNT        5
 128#define ACPI_FDE_BYTE_BUFFER_SIZE   5
 129#define ACPI_FDE_DWORD_BUFFER_SIZE  (ACPI_FDE_FIELD_COUNT * (u32) sizeof (u32))
 130
 131/******************************************************************************
 132 *
 133 * FUNCTION:    acpi_ns_complex_repairs
 134 *
 135 * PARAMETERS:  info                - Method execution information block
 136 *              node                - Namespace node for the method/object
 137 *              validate_status     - Original status of earlier validation
 138 *              return_object_ptr   - Pointer to the object returned from the
 139 *                                    evaluation of a method or object
 140 *
 141 * RETURN:      Status. AE_OK if repair was successful. If name is not
 142 *              matched, validate_status is returned.
 143 *
 144 * DESCRIPTION: Attempt to repair/convert a return object of a type that was
 145 *              not expected.
 146 *
 147 *****************************************************************************/
 148
 149acpi_status
 150acpi_ns_complex_repairs(struct acpi_evaluate_info *info,
 151                        struct acpi_namespace_node *node,
 152                        acpi_status validate_status,
 153                        union acpi_operand_object **return_object_ptr)
 154{
 155        const struct acpi_repair_info *predefined;
 156        acpi_status status;
 157
 158        /* Check if this name is in the list of repairable names */
 159
 160        predefined = acpi_ns_match_complex_repair(node);
 161        if (!predefined) {
 162                return (validate_status);
 163        }
 164
 165        status = predefined->repair_function(info, return_object_ptr);
 166        return (status);
 167}
 168
 169/******************************************************************************
 170 *
 171 * FUNCTION:    acpi_ns_match_complex_repair
 172 *
 173 * PARAMETERS:  node                - Namespace node for the method/object
 174 *
 175 * RETURN:      Pointer to entry in repair table. NULL indicates not found.
 176 *
 177 * DESCRIPTION: Check an object name against the repairable object list.
 178 *
 179 *****************************************************************************/
 180
 181static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
 182                                                                   acpi_namespace_node
 183                                                                   *node)
 184{
 185        const struct acpi_repair_info *this_name;
 186
 187        /* Search info table for a repairable predefined method/object name */
 188
 189        this_name = acpi_ns_repairable_names;
 190        while (this_name->repair_function) {
 191                if (ACPI_COMPARE_NAMESEG(node->name.ascii, this_name->name)) {
 192                        return (this_name);
 193                }
 194
 195                this_name++;
 196        }
 197
 198        return (NULL);          /* Not found */
 199}
 200
 201/******************************************************************************
 202 *
 203 * FUNCTION:    acpi_ns_repair_ALR
 204 *
 205 * PARAMETERS:  info                - Method execution information block
 206 *              return_object_ptr   - Pointer to the object returned from the
 207 *                                    evaluation of a method or object
 208 *
 209 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 210 *
 211 * DESCRIPTION: Repair for the _ALR object. If necessary, sort the object list
 212 *              ascending by the ambient illuminance values.
 213 *
 214 *****************************************************************************/
 215
 216static acpi_status
 217acpi_ns_repair_ALR(struct acpi_evaluate_info *info,
 218                   union acpi_operand_object **return_object_ptr)
 219{
 220        union acpi_operand_object *return_object = *return_object_ptr;
 221        acpi_status status;
 222
 223        status = acpi_ns_check_sorted_list(info, return_object, 0, 2, 1,
 224                                           ACPI_SORT_ASCENDING,
 225                                           "AmbientIlluminance");
 226
 227        return (status);
 228}
 229
 230/******************************************************************************
 231 *
 232 * FUNCTION:    acpi_ns_repair_FDE
 233 *
 234 * PARAMETERS:  info                - Method execution information block
 235 *              return_object_ptr   - Pointer to the object returned from the
 236 *                                    evaluation of a method or object
 237 *
 238 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 239 *
 240 * DESCRIPTION: Repair for the _FDE and _GTM objects. The expected return
 241 *              value is a Buffer of 5 DWORDs. This function repairs a common
 242 *              problem where the return value is a Buffer of BYTEs, not
 243 *              DWORDs.
 244 *
 245 *****************************************************************************/
 246
 247static acpi_status
 248acpi_ns_repair_FDE(struct acpi_evaluate_info *info,
 249                   union acpi_operand_object **return_object_ptr)
 250{
 251        union acpi_operand_object *return_object = *return_object_ptr;
 252        union acpi_operand_object *buffer_object;
 253        u8 *byte_buffer;
 254        u32 *dword_buffer;
 255        u32 i;
 256
 257        ACPI_FUNCTION_NAME(ns_repair_FDE);
 258
 259        switch (return_object->common.type) {
 260        case ACPI_TYPE_BUFFER:
 261
 262                /* This is the expected type. Length should be (at least) 5 DWORDs */
 263
 264                if (return_object->buffer.length >= ACPI_FDE_DWORD_BUFFER_SIZE) {
 265                        return (AE_OK);
 266                }
 267
 268                /* We can only repair if we have exactly 5 BYTEs */
 269
 270                if (return_object->buffer.length != ACPI_FDE_BYTE_BUFFER_SIZE) {
 271                        ACPI_WARN_PREDEFINED((AE_INFO,
 272                                              info->full_pathname,
 273                                              info->node_flags,
 274                                              "Incorrect return buffer length %u, expected %u",
 275                                              return_object->buffer.length,
 276                                              ACPI_FDE_DWORD_BUFFER_SIZE));
 277
 278                        return (AE_AML_OPERAND_TYPE);
 279                }
 280
 281                /* Create the new (larger) buffer object */
 282
 283                buffer_object =
 284                    acpi_ut_create_buffer_object(ACPI_FDE_DWORD_BUFFER_SIZE);
 285                if (!buffer_object) {
 286                        return (AE_NO_MEMORY);
 287                }
 288
 289                /* Expand each byte to a DWORD */
 290
 291                byte_buffer = return_object->buffer.pointer;
 292                dword_buffer = ACPI_CAST_PTR(u32,
 293                                             buffer_object->buffer.pointer);
 294
 295                for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++) {
 296                        *dword_buffer = (u32) *byte_buffer;
 297                        dword_buffer++;
 298                        byte_buffer++;
 299                }
 300
 301                ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
 302                                  "%s Expanded Byte Buffer to expected DWord Buffer\n",
 303                                  info->full_pathname));
 304                break;
 305
 306        default:
 307
 308                return (AE_AML_OPERAND_TYPE);
 309        }
 310
 311        /* Delete the original return object, return the new buffer object */
 312
 313        acpi_ut_remove_reference(return_object);
 314        *return_object_ptr = buffer_object;
 315
 316        info->return_flags |= ACPI_OBJECT_REPAIRED;
 317        return (AE_OK);
 318}
 319
 320/******************************************************************************
 321 *
 322 * FUNCTION:    acpi_ns_repair_CID
 323 *
 324 * PARAMETERS:  info                - Method execution information block
 325 *              return_object_ptr   - Pointer to the object returned from the
 326 *                                    evaluation of a method or object
 327 *
 328 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 329 *
 330 * DESCRIPTION: Repair for the _CID object. If a string, ensure that all
 331 *              letters are uppercase and that there is no leading asterisk.
 332 *              If a Package, ensure same for all string elements.
 333 *
 334 *****************************************************************************/
 335
 336static acpi_status
 337acpi_ns_repair_CID(struct acpi_evaluate_info *info,
 338                   union acpi_operand_object **return_object_ptr)
 339{
 340        acpi_status status;
 341        union acpi_operand_object *return_object = *return_object_ptr;
 342        union acpi_operand_object **element_ptr;
 343        union acpi_operand_object *original_element;
 344        u16 original_ref_count;
 345        u32 i;
 346
 347        /* Check for _CID as a simple string */
 348
 349        if (return_object->common.type == ACPI_TYPE_STRING) {
 350                status = acpi_ns_repair_HID(info, return_object_ptr);
 351                return (status);
 352        }
 353
 354        /* Exit if not a Package */
 355
 356        if (return_object->common.type != ACPI_TYPE_PACKAGE) {
 357                return (AE_OK);
 358        }
 359
 360        /* Examine each element of the _CID package */
 361
 362        element_ptr = return_object->package.elements;
 363        for (i = 0; i < return_object->package.count; i++) {
 364                original_element = *element_ptr;
 365                original_ref_count = original_element->common.reference_count;
 366
 367                status = acpi_ns_repair_HID(info, element_ptr);
 368                if (ACPI_FAILURE(status)) {
 369                        return (status);
 370                }
 371
 372                if (original_element != *element_ptr) {
 373
 374                        /* Update reference count of new object */
 375
 376                        (*element_ptr)->common.reference_count =
 377                            original_ref_count;
 378                }
 379
 380                element_ptr++;
 381        }
 382
 383        return (AE_OK);
 384}
 385
 386/******************************************************************************
 387 *
 388 * FUNCTION:    acpi_ns_repair_CST
 389 *
 390 * PARAMETERS:  info                - Method execution information block
 391 *              return_object_ptr   - Pointer to the object returned from the
 392 *                                    evaluation of a method or object
 393 *
 394 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 395 *
 396 * DESCRIPTION: Repair for the _CST object:
 397 *              1. Sort the list ascending by C state type
 398 *              2. Ensure type cannot be zero
 399 *              3. A subpackage count of zero means _CST is meaningless
 400 *              4. Count must match the number of C state subpackages
 401 *
 402 *****************************************************************************/
 403
 404static acpi_status
 405acpi_ns_repair_CST(struct acpi_evaluate_info *info,
 406                   union acpi_operand_object **return_object_ptr)
 407{
 408        union acpi_operand_object *return_object = *return_object_ptr;
 409        union acpi_operand_object **outer_elements;
 410        u32 outer_element_count;
 411        union acpi_operand_object *obj_desc;
 412        acpi_status status;
 413        u8 removing;
 414        u32 i;
 415
 416        ACPI_FUNCTION_NAME(ns_repair_CST);
 417
 418        /*
 419         * Check if the C-state type values are proportional.
 420         */
 421        outer_element_count = return_object->package.count - 1;
 422        i = 0;
 423        while (i < outer_element_count) {
 424                outer_elements = &return_object->package.elements[i + 1];
 425                removing = FALSE;
 426
 427                if ((*outer_elements)->package.count == 0) {
 428                        ACPI_WARN_PREDEFINED((AE_INFO,
 429                                              info->full_pathname,
 430                                              info->node_flags,
 431                                              "SubPackage[%u] - removing entry due to zero count",
 432                                              i));
 433                        removing = TRUE;
 434                        goto remove_element;
 435                }
 436
 437                obj_desc = (*outer_elements)->package.elements[1];      /* Index1 = Type */
 438                if ((u32)obj_desc->integer.value == 0) {
 439                        ACPI_WARN_PREDEFINED((AE_INFO,
 440                                              info->full_pathname,
 441                                              info->node_flags,
 442                                              "SubPackage[%u] - removing entry due to invalid Type(0)",
 443                                              i));
 444                        removing = TRUE;
 445                }
 446
 447remove_element:
 448                if (removing) {
 449                        acpi_ns_remove_element(return_object, i + 1);
 450                        outer_element_count--;
 451                } else {
 452                        i++;
 453                }
 454        }
 455
 456        /* Update top-level package count, Type "Integer" checked elsewhere */
 457
 458        obj_desc = return_object->package.elements[0];
 459        obj_desc->integer.value = outer_element_count;
 460
 461        /*
 462         * Entries (subpackages) in the _CST Package must be sorted by the
 463         * C-state type, in ascending order.
 464         */
 465        status = acpi_ns_check_sorted_list(info, return_object, 1, 4, 1,
 466                                           ACPI_SORT_ASCENDING, "C-State Type");
 467        if (ACPI_FAILURE(status)) {
 468                return (status);
 469        }
 470
 471        return (AE_OK);
 472}
 473
 474/******************************************************************************
 475 *
 476 * FUNCTION:    acpi_ns_repair_HID
 477 *
 478 * PARAMETERS:  info                - Method execution information block
 479 *              return_object_ptr   - Pointer to the object returned from the
 480 *                                    evaluation of a method or object
 481 *
 482 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 483 *
 484 * DESCRIPTION: Repair for the _HID object. If a string, ensure that all
 485 *              letters are uppercase and that there is no leading asterisk.
 486 *
 487 *****************************************************************************/
 488
 489static acpi_status
 490acpi_ns_repair_HID(struct acpi_evaluate_info *info,
 491                   union acpi_operand_object **return_object_ptr)
 492{
 493        union acpi_operand_object *return_object = *return_object_ptr;
 494        union acpi_operand_object *new_string;
 495        char *source;
 496        char *dest;
 497
 498        ACPI_FUNCTION_NAME(ns_repair_HID);
 499
 500        /* We only care about string _HID objects (not integers) */
 501
 502        if (return_object->common.type != ACPI_TYPE_STRING) {
 503                return (AE_OK);
 504        }
 505
 506        if (return_object->string.length == 0) {
 507                ACPI_WARN_PREDEFINED((AE_INFO,
 508                                      info->full_pathname, info->node_flags,
 509                                      "Invalid zero-length _HID or _CID string"));
 510
 511                /* Return AE_OK anyway, let driver handle it */
 512
 513                info->return_flags |= ACPI_OBJECT_REPAIRED;
 514                return (AE_OK);
 515        }
 516
 517        /* It is simplest to always create a new string object */
 518
 519        new_string = acpi_ut_create_string_object(return_object->string.length);
 520        if (!new_string) {
 521                return (AE_NO_MEMORY);
 522        }
 523
 524        /*
 525         * Remove a leading asterisk if present. For some unknown reason, there
 526         * are many machines in the field that contains IDs like this.
 527         *
 528         * Examples: "*PNP0C03", "*ACPI0003"
 529         */
 530        source = return_object->string.pointer;
 531        if (*source == '*') {
 532                source++;
 533                new_string->string.length--;
 534
 535                ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
 536                                  "%s: Removed invalid leading asterisk\n",
 537                                  info->full_pathname));
 538        }
 539
 540        /*
 541         * Copy and uppercase the string. From the ACPI 5.0 specification:
 542         *
 543         * A valid PNP ID must be of the form "AAA####" where A is an uppercase
 544         * letter and # is a hex digit. A valid ACPI ID must be of the form
 545         * "NNNN####" where N is an uppercase letter or decimal digit, and
 546         * # is a hex digit.
 547         */
 548        for (dest = new_string->string.pointer; *source; dest++, source++) {
 549                *dest = (char)toupper((int)*source);
 550        }
 551
 552        acpi_ut_remove_reference(return_object);
 553        *return_object_ptr = new_string;
 554        return (AE_OK);
 555}
 556
 557/******************************************************************************
 558 *
 559 * FUNCTION:    acpi_ns_repair_PRT
 560 *
 561 * PARAMETERS:  info                - Method execution information block
 562 *              return_object_ptr   - Pointer to the object returned from the
 563 *                                    evaluation of a method or object
 564 *
 565 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 566 *
 567 * DESCRIPTION: Repair for the _PRT object. If necessary, fix reversed
 568 *              source_name and source_index field, a common BIOS bug.
 569 *
 570 *****************************************************************************/
 571
 572static acpi_status
 573acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
 574                   union acpi_operand_object **return_object_ptr)
 575{
 576        union acpi_operand_object *package_object = *return_object_ptr;
 577        union acpi_operand_object **top_object_list;
 578        union acpi_operand_object **sub_object_list;
 579        union acpi_operand_object *obj_desc;
 580        union acpi_operand_object *sub_package;
 581        u32 element_count;
 582        u32 index;
 583
 584        /* Each element in the _PRT package is a subpackage */
 585
 586        top_object_list = package_object->package.elements;
 587        element_count = package_object->package.count;
 588
 589        /* Examine each subpackage */
 590
 591        for (index = 0; index < element_count; index++, top_object_list++) {
 592                sub_package = *top_object_list;
 593                sub_object_list = sub_package->package.elements;
 594
 595                /* Check for minimum required element count */
 596
 597                if (sub_package->package.count < 4) {
 598                        continue;
 599                }
 600
 601                /*
 602                 * If the BIOS has erroneously reversed the _PRT source_name (index 2)
 603                 * and the source_index (index 3), fix it. _PRT is important enough to
 604                 * workaround this BIOS error. This also provides compatibility with
 605                 * other ACPI implementations.
 606                 */
 607                obj_desc = sub_object_list[3];
 608                if (!obj_desc || (obj_desc->common.type != ACPI_TYPE_INTEGER)) {
 609                        sub_object_list[3] = sub_object_list[2];
 610                        sub_object_list[2] = obj_desc;
 611                        info->return_flags |= ACPI_OBJECT_REPAIRED;
 612
 613                        ACPI_WARN_PREDEFINED((AE_INFO,
 614                                              info->full_pathname,
 615                                              info->node_flags,
 616                                              "PRT[%X]: Fixed reversed SourceName and SourceIndex",
 617                                              index));
 618                }
 619        }
 620
 621        return (AE_OK);
 622}
 623
 624/******************************************************************************
 625 *
 626 * FUNCTION:    acpi_ns_repair_PSS
 627 *
 628 * PARAMETERS:  info                - Method execution information block
 629 *              return_object_ptr   - Pointer to the object returned from the
 630 *                                    evaluation of a method or object
 631 *
 632 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 633 *
 634 * DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list
 635 *              by the CPU frequencies. Check that the power dissipation values
 636 *              are all proportional to CPU frequency (i.e., sorting by
 637 *              frequency should be the same as sorting by power.)
 638 *
 639 *****************************************************************************/
 640
 641static acpi_status
 642acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
 643                   union acpi_operand_object **return_object_ptr)
 644{
 645        union acpi_operand_object *return_object = *return_object_ptr;
 646        union acpi_operand_object **outer_elements;
 647        u32 outer_element_count;
 648        union acpi_operand_object **elements;
 649        union acpi_operand_object *obj_desc;
 650        u32 previous_value;
 651        acpi_status status;
 652        u32 i;
 653
 654        /*
 655         * Entries (subpackages) in the _PSS Package must be sorted by power
 656         * dissipation, in descending order. If it appears that the list is
 657         * incorrectly sorted, sort it. We sort by cpu_frequency, since this
 658         * should be proportional to the power.
 659         */
 660        status = acpi_ns_check_sorted_list(info, return_object, 0, 6, 0,
 661                                           ACPI_SORT_DESCENDING,
 662                                           "CpuFrequency");
 663        if (ACPI_FAILURE(status)) {
 664                return (status);
 665        }
 666
 667        /*
 668         * We now know the list is correctly sorted by CPU frequency. Check if
 669         * the power dissipation values are proportional.
 670         */
 671        previous_value = ACPI_UINT32_MAX;
 672        outer_elements = return_object->package.elements;
 673        outer_element_count = return_object->package.count;
 674
 675        for (i = 0; i < outer_element_count; i++) {
 676                elements = (*outer_elements)->package.elements;
 677                obj_desc = elements[1]; /* Index1 = power_dissipation */
 678
 679                if ((u32)obj_desc->integer.value > previous_value) {
 680                        ACPI_WARN_PREDEFINED((AE_INFO,
 681                                              info->full_pathname,
 682                                              info->node_flags,
 683                                              "SubPackage[%u,%u] - suspicious power dissipation values",
 684                                              i - 1, i));
 685                }
 686
 687                previous_value = (u32) obj_desc->integer.value;
 688                outer_elements++;
 689        }
 690
 691        return (AE_OK);
 692}
 693
 694/******************************************************************************
 695 *
 696 * FUNCTION:    acpi_ns_repair_TSS
 697 *
 698 * PARAMETERS:  info                - Method execution information block
 699 *              return_object_ptr   - Pointer to the object returned from the
 700 *                                    evaluation of a method or object
 701 *
 702 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 703 *
 704 * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list
 705 *              descending by the power dissipation values.
 706 *
 707 *****************************************************************************/
 708
 709static acpi_status
 710acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
 711                   union acpi_operand_object **return_object_ptr)
 712{
 713        union acpi_operand_object *return_object = *return_object_ptr;
 714        acpi_status status;
 715        struct acpi_namespace_node *node;
 716
 717        /*
 718         * We can only sort the _TSS return package if there is no _PSS in the
 719         * same scope. This is because if _PSS is present, the ACPI specification
 720         * dictates that the _TSS Power Dissipation field is to be ignored, and
 721         * therefore some BIOSs leave garbage values in the _TSS Power field(s).
 722         * In this case, it is best to just return the _TSS package as-is.
 723         * (May, 2011)
 724         */
 725        status = acpi_ns_get_node(info->node, "^_PSS",
 726                                  ACPI_NS_NO_UPSEARCH, &node);
 727        if (ACPI_SUCCESS(status)) {
 728                return (AE_OK);
 729        }
 730
 731        status = acpi_ns_check_sorted_list(info, return_object, 0, 5, 1,
 732                                           ACPI_SORT_DESCENDING,
 733                                           "PowerDissipation");
 734
 735        return (status);
 736}
 737
 738/******************************************************************************
 739 *
 740 * FUNCTION:    acpi_ns_check_sorted_list
 741 *
 742 * PARAMETERS:  info                - Method execution information block
 743 *              return_object       - Pointer to the top-level returned object
 744 *              start_index         - Index of the first subpackage
 745 *              expected_count      - Minimum length of each subpackage
 746 *              sort_index          - Subpackage entry to sort on
 747 *              sort_direction      - Ascending or descending
 748 *              sort_key_name       - Name of the sort_index field
 749 *
 750 * RETURN:      Status. AE_OK if the list is valid and is sorted correctly or
 751 *              has been repaired by sorting the list.
 752 *
 753 * DESCRIPTION: Check if the package list is valid and sorted correctly by the
 754 *              sort_index. If not, then sort the list.
 755 *
 756 *****************************************************************************/
 757
 758static acpi_status
 759acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
 760                          union acpi_operand_object *return_object,
 761                          u32 start_index,
 762                          u32 expected_count,
 763                          u32 sort_index,
 764                          u8 sort_direction, char *sort_key_name)
 765{
 766        u32 outer_element_count;
 767        union acpi_operand_object **outer_elements;
 768        union acpi_operand_object **elements;
 769        union acpi_operand_object *obj_desc;
 770        u32 i;
 771        u32 previous_value;
 772
 773        ACPI_FUNCTION_NAME(ns_check_sorted_list);
 774
 775        /* The top-level object must be a package */
 776
 777        if (return_object->common.type != ACPI_TYPE_PACKAGE) {
 778                return (AE_AML_OPERAND_TYPE);
 779        }
 780
 781        /*
 782         * NOTE: assumes list of subpackages contains no NULL elements.
 783         * Any NULL elements should have been removed by earlier call
 784         * to acpi_ns_remove_null_elements.
 785         */
 786        outer_element_count = return_object->package.count;
 787        if (!outer_element_count || start_index >= outer_element_count) {
 788                return (AE_AML_PACKAGE_LIMIT);
 789        }
 790
 791        outer_elements = &return_object->package.elements[start_index];
 792        outer_element_count -= start_index;
 793
 794        previous_value = 0;
 795        if (sort_direction == ACPI_SORT_DESCENDING) {
 796                previous_value = ACPI_UINT32_MAX;
 797        }
 798
 799        /* Examine each subpackage */
 800
 801        for (i = 0; i < outer_element_count; i++) {
 802
 803                /* Each element of the top-level package must also be a package */
 804
 805                if ((*outer_elements)->common.type != ACPI_TYPE_PACKAGE) {
 806                        return (AE_AML_OPERAND_TYPE);
 807                }
 808
 809                /* Each subpackage must have the minimum length */
 810
 811                if ((*outer_elements)->package.count < expected_count) {
 812                        return (AE_AML_PACKAGE_LIMIT);
 813                }
 814
 815                elements = (*outer_elements)->package.elements;
 816                obj_desc = elements[sort_index];
 817
 818                if (obj_desc->common.type != ACPI_TYPE_INTEGER) {
 819                        return (AE_AML_OPERAND_TYPE);
 820                }
 821
 822                /*
 823                 * The list must be sorted in the specified order. If we detect a
 824                 * discrepancy, sort the entire list.
 825                 */
 826                if (((sort_direction == ACPI_SORT_ASCENDING) &&
 827                     (obj_desc->integer.value < previous_value)) ||
 828                    ((sort_direction == ACPI_SORT_DESCENDING) &&
 829                     (obj_desc->integer.value > previous_value))) {
 830                        acpi_ns_sort_list(&return_object->package.
 831                                          elements[start_index],
 832                                          outer_element_count, sort_index,
 833                                          sort_direction);
 834
 835                        info->return_flags |= ACPI_OBJECT_REPAIRED;
 836
 837                        ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
 838                                          "%s: Repaired unsorted list - now sorted by %s\n",
 839                                          info->full_pathname, sort_key_name));
 840                        return (AE_OK);
 841                }
 842
 843                previous_value = (u32) obj_desc->integer.value;
 844                outer_elements++;
 845        }
 846
 847        return (AE_OK);
 848}
 849
 850/******************************************************************************
 851 *
 852 * FUNCTION:    acpi_ns_sort_list
 853 *
 854 * PARAMETERS:  elements            - Package object element list
 855 *              count               - Element count for above
 856 *              index               - Sort by which package element
 857 *              sort_direction      - Ascending or Descending sort
 858 *
 859 * RETURN:      None
 860 *
 861 * DESCRIPTION: Sort the objects that are in a package element list.
 862 *
 863 * NOTE: Assumes that all NULL elements have been removed from the package,
 864 *       and that all elements have been verified to be of type Integer.
 865 *
 866 *****************************************************************************/
 867
 868static void
 869acpi_ns_sort_list(union acpi_operand_object **elements,
 870                  u32 count, u32 index, u8 sort_direction)
 871{
 872        union acpi_operand_object *obj_desc1;
 873        union acpi_operand_object *obj_desc2;
 874        union acpi_operand_object *temp_obj;
 875        u32 i;
 876        u32 j;
 877
 878        /* Simple bubble sort */
 879
 880        for (i = 1; i < count; i++) {
 881                for (j = (count - 1); j >= i; j--) {
 882                        obj_desc1 = elements[j - 1]->package.elements[index];
 883                        obj_desc2 = elements[j]->package.elements[index];
 884
 885                        if (((sort_direction == ACPI_SORT_ASCENDING) &&
 886                             (obj_desc1->integer.value >
 887                              obj_desc2->integer.value))
 888                            || ((sort_direction == ACPI_SORT_DESCENDING)
 889                                && (obj_desc1->integer.value <
 890                                    obj_desc2->integer.value))) {
 891                                temp_obj = elements[j - 1];
 892                                elements[j - 1] = elements[j];
 893                                elements[j] = temp_obj;
 894                        }
 895                }
 896        }
 897}
 898
 899/******************************************************************************
 900 *
 901 * FUNCTION:    acpi_ns_remove_element
 902 *
 903 * PARAMETERS:  obj_desc            - Package object element list
 904 *              index               - Index of element to remove
 905 *
 906 * RETURN:      None
 907 *
 908 * DESCRIPTION: Remove the requested element of a package and delete it.
 909 *
 910 *****************************************************************************/
 911
 912static void
 913acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index)
 914{
 915        union acpi_operand_object **source;
 916        union acpi_operand_object **dest;
 917        u32 count;
 918        u32 new_count;
 919        u32 i;
 920
 921        ACPI_FUNCTION_NAME(ns_remove_element);
 922
 923        count = obj_desc->package.count;
 924        new_count = count - 1;
 925
 926        source = obj_desc->package.elements;
 927        dest = source;
 928
 929        /* Examine all elements of the package object, remove matched index */
 930
 931        for (i = 0; i < count; i++) {
 932                if (i == index) {
 933                        acpi_ut_remove_reference(*source);      /* Remove one ref for being in pkg */
 934                        acpi_ut_remove_reference(*source);
 935                } else {
 936                        *dest = *source;
 937                        dest++;
 938                }
 939
 940                source++;
 941        }
 942
 943        /* NULL terminate list and update the package count */
 944
 945        *dest = NULL;
 946        obj_desc->package.count = new_count;
 947}
 948