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