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_NAME_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 * 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_NAME(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 } 948