root/drivers/acpi/acpica/nsrepair2.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ACPI_MODULE_NAME
  2. acpi_ns_complex_repairs
  3. acpi_ns_match_complex_repair
  4. acpi_ns_repair_ALR
  5. acpi_ns_repair_FDE
  6. acpi_ns_repair_CID
  7. acpi_ns_repair_CST
  8. acpi_ns_repair_HID
  9. acpi_ns_repair_PRT
  10. acpi_ns_repair_PSS
  11. acpi_ns_repair_TSS
  12. acpi_ns_check_sorted_list
  13. acpi_ns_sort_list
  14. acpi_ns_remove_element

   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
  16 ACPI_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  */
  22 typedef
  23 acpi_status (*acpi_repair_function) (struct acpi_evaluate_info * info,
  24                                      union acpi_operand_object **
  25                                      return_object_ptr);
  26 
  27 typedef 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 
  35 static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
  36                                                                    acpi_namespace_node
  37                                                                    *node);
  38 
  39 static acpi_status
  40 acpi_ns_repair_ALR(struct acpi_evaluate_info *info,
  41                    union acpi_operand_object **return_object_ptr);
  42 
  43 static acpi_status
  44 acpi_ns_repair_CID(struct acpi_evaluate_info *info,
  45                    union acpi_operand_object **return_object_ptr);
  46 
  47 static acpi_status
  48 acpi_ns_repair_CST(struct acpi_evaluate_info *info,
  49                    union acpi_operand_object **return_object_ptr);
  50 
  51 static acpi_status
  52 acpi_ns_repair_FDE(struct acpi_evaluate_info *info,
  53                    union acpi_operand_object **return_object_ptr);
  54 
  55 static acpi_status
  56 acpi_ns_repair_HID(struct acpi_evaluate_info *info,
  57                    union acpi_operand_object **return_object_ptr);
  58 
  59 static acpi_status
  60 acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
  61                    union acpi_operand_object **return_object_ptr);
  62 
  63 static acpi_status
  64 acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
  65                    union acpi_operand_object **return_object_ptr);
  66 
  67 static acpi_status
  68 acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
  69                    union acpi_operand_object **return_object_ptr);
  70 
  71 static acpi_status
  72 acpi_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 
  84 static void
  85 acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index);
  86 
  87 static void
  88 acpi_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  */
 114 static 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 
 149 acpi_status
 150 acpi_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 
 181 static 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 
 216 static acpi_status
 217 acpi_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 
 247 static acpi_status
 248 acpi_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 
 336 static acpi_status
 337 acpi_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 
 404 static acpi_status
 405 acpi_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 
 447 remove_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 
 489 static acpi_status
 490 acpi_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 
 572 static acpi_status
 573 acpi_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 
 641 static acpi_status
 642 acpi_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 
 709 static acpi_status
 710 acpi_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 
 758 static acpi_status
 759 acpi_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 
 868 static void
 869 acpi_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 
 912 static void
 913 acpi_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 }

/* [<][>][^][v][top][bottom][index][help] */