1 /****************************************************************************** 2 * 3 * Module Name: nsrepair2 - Repair for objects returned by specific 4 * predefined methods 5 * 6 *****************************************************************************/ 7 8 /* 9 * Copyright (C) 2000 - 2013, Intel Corp. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions, and the following disclaimer, 17 * without modification. 18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 19 * substantially similar to the "NO WARRANTY" disclaimer below 20 * ("Disclaimer") and any redistribution must be conditioned upon 21 * including a substantially similar Disclaimer requirement for further 22 * binary redistribution. 23 * 3. Neither the names of the above-listed copyright holders nor the names 24 * of any contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * Alternatively, this software may be distributed under the terms of the 28 * GNU General Public License ("GPL") version 2 as published by the Free 29 * Software Foundation. 30 * 31 * NO WARRANTY 32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 35 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 36 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 41 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 42 * POSSIBILITY OF SUCH DAMAGES. 43 */ 44 45 #define __NSREPAIR2_C__ 46 47 #include <contrib/dev/acpica/include/acpi.h> 48 #include <contrib/dev/acpica/include/accommon.h> 49 #include <contrib/dev/acpica/include/acnamesp.h> 50 51 #define _COMPONENT ACPI_NAMESPACE 52 ACPI_MODULE_NAME ("nsrepair2") 53 54 55 /* 56 * Information structure and handler for ACPI predefined names that can 57 * be repaired on a per-name basis. 58 */ 59 typedef 60 ACPI_STATUS (*ACPI_REPAIR_FUNCTION) ( 61 ACPI_EVALUATE_INFO *Info, 62 ACPI_OPERAND_OBJECT **ReturnObjectPtr); 63 64 typedef struct acpi_repair_info 65 { 66 char Name[ACPI_NAME_SIZE]; 67 ACPI_REPAIR_FUNCTION RepairFunction; 68 69 } ACPI_REPAIR_INFO; 70 71 72 /* Local prototypes */ 73 74 static const ACPI_REPAIR_INFO * 75 AcpiNsMatchComplexRepair ( 76 ACPI_NAMESPACE_NODE *Node); 77 78 static ACPI_STATUS 79 AcpiNsRepair_ALR ( 80 ACPI_EVALUATE_INFO *Info, 81 ACPI_OPERAND_OBJECT **ReturnObjectPtr); 82 83 static ACPI_STATUS 84 AcpiNsRepair_CID ( 85 ACPI_EVALUATE_INFO *Info, 86 ACPI_OPERAND_OBJECT **ReturnObjectPtr); 87 88 static ACPI_STATUS 89 AcpiNsRepair_CST ( 90 ACPI_EVALUATE_INFO *Info, 91 ACPI_OPERAND_OBJECT **ReturnObjectPtr); 92 93 static ACPI_STATUS 94 AcpiNsRepair_FDE ( 95 ACPI_EVALUATE_INFO *Info, 96 ACPI_OPERAND_OBJECT **ReturnObjectPtr); 97 98 static ACPI_STATUS 99 AcpiNsRepair_HID ( 100 ACPI_EVALUATE_INFO *Info, 101 ACPI_OPERAND_OBJECT **ReturnObjectPtr); 102 103 static ACPI_STATUS 104 AcpiNsRepair_PRT ( 105 ACPI_EVALUATE_INFO *Info, 106 ACPI_OPERAND_OBJECT **ReturnObjectPtr); 107 108 static ACPI_STATUS 109 AcpiNsRepair_PSS ( 110 ACPI_EVALUATE_INFO *Info, 111 ACPI_OPERAND_OBJECT **ReturnObjectPtr); 112 113 static ACPI_STATUS 114 AcpiNsRepair_TSS ( 115 ACPI_EVALUATE_INFO *Info, 116 ACPI_OPERAND_OBJECT **ReturnObjectPtr); 117 118 static ACPI_STATUS 119 AcpiNsCheckSortedList ( 120 ACPI_EVALUATE_INFO *Info, 121 ACPI_OPERAND_OBJECT *ReturnObject, 122 UINT32 StartIndex, 123 UINT32 ExpectedCount, 124 UINT32 SortIndex, 125 UINT8 SortDirection, 126 char *SortKeyName); 127 128 /* Values for SortDirection above */ 129 130 #define ACPI_SORT_ASCENDING 0 131 #define ACPI_SORT_DESCENDING 1 132 133 static void 134 AcpiNsRemoveElement ( 135 ACPI_OPERAND_OBJECT *ObjDesc, 136 UINT32 Index); 137 138 static void 139 AcpiNsSortList ( 140 ACPI_OPERAND_OBJECT **Elements, 141 UINT32 Count, 142 UINT32 Index, 143 UINT8 SortDirection); 144 145 146 /* 147 * This table contains the names of the predefined methods for which we can 148 * perform more complex repairs. 149 * 150 * As necessary: 151 * 152 * _ALR: Sort the list ascending by AmbientIlluminance 153 * _CID: Strings: uppercase all, remove any leading asterisk 154 * _CST: Sort the list ascending by C state type 155 * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs 156 * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs 157 * _HID: Strings: uppercase all, remove any leading asterisk 158 * _PRT: Fix reversed SourceName and SourceIndex 159 * _PSS: Sort the list descending by Power 160 * _TSS: Sort the list descending by Power 161 * 162 * Names that must be packages, but cannot be sorted: 163 * 164 * _BCL: Values are tied to the Package index where they appear, and cannot 165 * be moved or sorted. These index values are used for _BQC and _BCM. 166 * However, we can fix the case where a buffer is returned, by converting 167 * it to a Package of integers. 168 */ 169 static const ACPI_REPAIR_INFO AcpiNsRepairableNames[] = 170 { 171 {"_ALR", AcpiNsRepair_ALR}, 172 {"_CID", AcpiNsRepair_CID}, 173 {"_CST", AcpiNsRepair_CST}, 174 {"_FDE", AcpiNsRepair_FDE}, 175 {"_GTM", AcpiNsRepair_FDE}, /* _GTM has same repair as _FDE */ 176 {"_HID", AcpiNsRepair_HID}, 177 {"_PRT", AcpiNsRepair_PRT}, 178 {"_PSS", AcpiNsRepair_PSS}, 179 {"_TSS", AcpiNsRepair_TSS}, 180 {{0,0,0,0}, NULL} /* Table terminator */ 181 }; 182 183 184 #define ACPI_FDE_FIELD_COUNT 5 185 #define ACPI_FDE_BYTE_BUFFER_SIZE 5 186 #define ACPI_FDE_DWORD_BUFFER_SIZE (ACPI_FDE_FIELD_COUNT * sizeof (UINT32)) 187 188 189 /****************************************************************************** 190 * 191 * FUNCTION: AcpiNsComplexRepairs 192 * 193 * PARAMETERS: Info - Method execution information block 194 * Node - Namespace node for the method/object 195 * ValidateStatus - Original status of earlier validation 196 * ReturnObjectPtr - Pointer to the object returned from the 197 * evaluation of a method or object 198 * 199 * RETURN: Status. AE_OK if repair was successful. If name is not 200 * matched, ValidateStatus is returned. 201 * 202 * DESCRIPTION: Attempt to repair/convert a return object of a type that was 203 * not expected. 204 * 205 *****************************************************************************/ 206 207 ACPI_STATUS 208 AcpiNsComplexRepairs ( 209 ACPI_EVALUATE_INFO *Info, 210 ACPI_NAMESPACE_NODE *Node, 211 ACPI_STATUS ValidateStatus, 212 ACPI_OPERAND_OBJECT **ReturnObjectPtr) 213 { 214 const ACPI_REPAIR_INFO *Predefined; 215 ACPI_STATUS Status; 216 217 218 /* Check if this name is in the list of repairable names */ 219 220 Predefined = AcpiNsMatchComplexRepair (Node); 221 if (!Predefined) 222 { 223 return (ValidateStatus); 224 } 225 226 Status = Predefined->RepairFunction (Info, ReturnObjectPtr); 227 return (Status); 228 } 229 230 231 /****************************************************************************** 232 * 233 * FUNCTION: AcpiNsMatchComplexRepair 234 * 235 * PARAMETERS: Node - Namespace node for the method/object 236 * 237 * RETURN: Pointer to entry in repair table. NULL indicates not found. 238 * 239 * DESCRIPTION: Check an object name against the repairable object list. 240 * 241 *****************************************************************************/ 242 243 static const ACPI_REPAIR_INFO * 244 AcpiNsMatchComplexRepair ( 245 ACPI_NAMESPACE_NODE *Node) 246 { 247 const ACPI_REPAIR_INFO *ThisName; 248 249 250 /* Search info table for a repairable predefined method/object name */ 251 252 ThisName = AcpiNsRepairableNames; 253 while (ThisName->RepairFunction) 254 { 255 if (ACPI_COMPARE_NAME (Node->Name.Ascii, ThisName->Name)) 256 { 257 return (ThisName); 258 } 259 ThisName++; 260 } 261 262 return (NULL); /* Not found */ 263 } 264 265 266 /****************************************************************************** 267 * 268 * FUNCTION: AcpiNsRepair_ALR 269 * 270 * PARAMETERS: Info - Method execution information block 271 * ReturnObjectPtr - Pointer to the object returned from the 272 * evaluation of a method or object 273 * 274 * RETURN: Status. AE_OK if object is OK or was repaired successfully 275 * 276 * DESCRIPTION: Repair for the _ALR object. If necessary, sort the object list 277 * ascending by the ambient illuminance values. 278 * 279 *****************************************************************************/ 280 281 static ACPI_STATUS 282 AcpiNsRepair_ALR ( 283 ACPI_EVALUATE_INFO *Info, 284 ACPI_OPERAND_OBJECT **ReturnObjectPtr) 285 { 286 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; 287 ACPI_STATUS Status; 288 289 290 Status = AcpiNsCheckSortedList (Info, ReturnObject, 0, 2, 1, 291 ACPI_SORT_ASCENDING, "AmbientIlluminance"); 292 293 return (Status); 294 } 295 296 297 /****************************************************************************** 298 * 299 * FUNCTION: AcpiNsRepair_FDE 300 * 301 * PARAMETERS: Info - Method execution information block 302 * ReturnObjectPtr - Pointer to the object returned from the 303 * evaluation of a method or object 304 * 305 * RETURN: Status. AE_OK if object is OK or was repaired successfully 306 * 307 * DESCRIPTION: Repair for the _FDE and _GTM objects. The expected return 308 * value is a Buffer of 5 DWORDs. This function repairs a common 309 * problem where the return value is a Buffer of BYTEs, not 310 * DWORDs. 311 * 312 *****************************************************************************/ 313 314 static ACPI_STATUS 315 AcpiNsRepair_FDE ( 316 ACPI_EVALUATE_INFO *Info, 317 ACPI_OPERAND_OBJECT **ReturnObjectPtr) 318 { 319 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; 320 ACPI_OPERAND_OBJECT *BufferObject; 321 UINT8 *ByteBuffer; 322 UINT32 *DwordBuffer; 323 UINT32 i; 324 325 326 ACPI_FUNCTION_NAME (NsRepair_FDE); 327 328 329 switch (ReturnObject->Common.Type) 330 { 331 case ACPI_TYPE_BUFFER: 332 333 /* This is the expected type. Length should be (at least) 5 DWORDs */ 334 335 if (ReturnObject->Buffer.Length >= ACPI_FDE_DWORD_BUFFER_SIZE) 336 { 337 return (AE_OK); 338 } 339 340 /* We can only repair if we have exactly 5 BYTEs */ 341 342 if (ReturnObject->Buffer.Length != ACPI_FDE_BYTE_BUFFER_SIZE) 343 { 344 ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, 345 "Incorrect return buffer length %u, expected %u", 346 ReturnObject->Buffer.Length, ACPI_FDE_DWORD_BUFFER_SIZE)); 347 348 return (AE_AML_OPERAND_TYPE); 349 } 350 351 /* Create the new (larger) buffer object */ 352 353 BufferObject = AcpiUtCreateBufferObject (ACPI_FDE_DWORD_BUFFER_SIZE); 354 if (!BufferObject) 355 { 356 return (AE_NO_MEMORY); 357 } 358 359 /* Expand each byte to a DWORD */ 360 361 ByteBuffer = ReturnObject->Buffer.Pointer; 362 DwordBuffer = ACPI_CAST_PTR (UINT32, BufferObject->Buffer.Pointer); 363 364 for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++) 365 { 366 *DwordBuffer = (UINT32) *ByteBuffer; 367 DwordBuffer++; 368 ByteBuffer++; 369 } 370 371 ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR, 372 "%s Expanded Byte Buffer to expected DWord Buffer\n", 373 Info->FullPathname)); 374 break; 375 376 default: 377 378 return (AE_AML_OPERAND_TYPE); 379 } 380 381 /* Delete the original return object, return the new buffer object */ 382 383 AcpiUtRemoveReference (ReturnObject); 384 *ReturnObjectPtr = BufferObject; 385 386 Info->ReturnFlags |= ACPI_OBJECT_REPAIRED; 387 return (AE_OK); 388 } 389 390 391 /****************************************************************************** 392 * 393 * FUNCTION: AcpiNsRepair_CID 394 * 395 * PARAMETERS: Info - Method execution information block 396 * ReturnObjectPtr - Pointer to the object returned from the 397 * evaluation of a method or object 398 * 399 * RETURN: Status. AE_OK if object is OK or was repaired successfully 400 * 401 * DESCRIPTION: Repair for the _CID object. If a string, ensure that all 402 * letters are uppercase and that there is no leading asterisk. 403 * If a Package, ensure same for all string elements. 404 * 405 *****************************************************************************/ 406 407 static ACPI_STATUS 408 AcpiNsRepair_CID ( 409 ACPI_EVALUATE_INFO *Info, 410 ACPI_OPERAND_OBJECT **ReturnObjectPtr) 411 { 412 ACPI_STATUS Status; 413 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; 414 ACPI_OPERAND_OBJECT **ElementPtr; 415 ACPI_OPERAND_OBJECT *OriginalElement; 416 UINT16 OriginalRefCount; 417 UINT32 i; 418 419 420 /* Check for _CID as a simple string */ 421 422 if (ReturnObject->Common.Type == ACPI_TYPE_STRING) 423 { 424 Status = AcpiNsRepair_HID (Info, ReturnObjectPtr); 425 return (Status); 426 } 427 428 /* Exit if not a Package */ 429 430 if (ReturnObject->Common.Type != ACPI_TYPE_PACKAGE) 431 { 432 return (AE_OK); 433 } 434 435 /* Examine each element of the _CID package */ 436 437 ElementPtr = ReturnObject->Package.Elements; 438 for (i = 0; i < ReturnObject->Package.Count; i++) 439 { 440 OriginalElement = *ElementPtr; 441 OriginalRefCount = OriginalElement->Common.ReferenceCount; 442 443 Status = AcpiNsRepair_HID (Info, ElementPtr); 444 if (ACPI_FAILURE (Status)) 445 { 446 return (Status); 447 } 448 449 /* Take care with reference counts */ 450 451 if (OriginalElement != *ElementPtr) 452 { 453 /* Element was replaced */ 454 455 (*ElementPtr)->Common.ReferenceCount = 456 OriginalRefCount; 457 458 AcpiUtRemoveReference (OriginalElement); 459 } 460 461 ElementPtr++; 462 } 463 464 return (AE_OK); 465 } 466 467 468 /****************************************************************************** 469 * 470 * FUNCTION: AcpiNsRepair_CST 471 * 472 * PARAMETERS: Info - Method execution information block 473 * ReturnObjectPtr - Pointer to the object returned from the 474 * evaluation of a method or object 475 * 476 * RETURN: Status. AE_OK if object is OK or was repaired successfully 477 * 478 * DESCRIPTION: Repair for the _CST object: 479 * 1. Sort the list ascending by C state type 480 * 2. Ensure type cannot be zero 481 * 3. A sub-package count of zero means _CST is meaningless 482 * 4. Count must match the number of C state sub-packages 483 * 484 *****************************************************************************/ 485 486 static ACPI_STATUS 487 AcpiNsRepair_CST ( 488 ACPI_EVALUATE_INFO *Info, 489 ACPI_OPERAND_OBJECT **ReturnObjectPtr) 490 { 491 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; 492 ACPI_OPERAND_OBJECT **OuterElements; 493 UINT32 OuterElementCount; 494 ACPI_OPERAND_OBJECT *ObjDesc; 495 ACPI_STATUS Status; 496 BOOLEAN Removing; 497 UINT32 i; 498 499 500 ACPI_FUNCTION_NAME (NsRepair_CST); 501 502 503 /* 504 * Entries (subpackages) in the _CST Package must be sorted by the 505 * C-state type, in ascending order. 506 */ 507 Status = AcpiNsCheckSortedList (Info, ReturnObject, 1, 4, 1, 508 ACPI_SORT_ASCENDING, "C-State Type"); 509 if (ACPI_FAILURE (Status)) 510 { 511 return (Status); 512 } 513 514 /* 515 * We now know the list is correctly sorted by C-state type. Check if 516 * the C-state type values are proportional. 517 */ 518 OuterElementCount = ReturnObject->Package.Count - 1; 519 i = 0; 520 while (i < OuterElementCount) 521 { 522 OuterElements = &ReturnObject->Package.Elements[i + 1]; 523 Removing = FALSE; 524 525 if ((*OuterElements)->Package.Count == 0) 526 { 527 ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, 528 "SubPackage[%u] - removing entry due to zero count", i)); 529 Removing = TRUE; 530 } 531 532 ObjDesc = (*OuterElements)->Package.Elements[1]; /* Index1 = Type */ 533 if ((UINT32) ObjDesc->Integer.Value == 0) 534 { 535 ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, 536 "SubPackage[%u] - removing entry due to invalid Type(0)", i)); 537 Removing = TRUE; 538 } 539 540 if (Removing) 541 { 542 AcpiNsRemoveElement (ReturnObject, i + 1); 543 OuterElementCount--; 544 } 545 else 546 { 547 i++; 548 } 549 } 550 551 /* Update top-level package count, Type "Integer" checked elsewhere */ 552 553 ObjDesc = ReturnObject->Package.Elements[0]; 554 ObjDesc->Integer.Value = OuterElementCount; 555 return (AE_OK); 556 } 557 558 559 /****************************************************************************** 560 * 561 * FUNCTION: AcpiNsRepair_HID 562 * 563 * PARAMETERS: Info - Method execution information block 564 * ReturnObjectPtr - Pointer to the object returned from the 565 * evaluation of a method or object 566 * 567 * RETURN: Status. AE_OK if object is OK or was repaired successfully 568 * 569 * DESCRIPTION: Repair for the _HID object. If a string, ensure that all 570 * letters are uppercase and that there is no leading asterisk. 571 * 572 *****************************************************************************/ 573 574 static ACPI_STATUS 575 AcpiNsRepair_HID ( 576 ACPI_EVALUATE_INFO *Info, 577 ACPI_OPERAND_OBJECT **ReturnObjectPtr) 578 { 579 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; 580 ACPI_OPERAND_OBJECT *NewString; 581 char *Source; 582 char *Dest; 583 584 585 ACPI_FUNCTION_NAME (NsRepair_HID); 586 587 588 /* We only care about string _HID objects (not integers) */ 589 590 if (ReturnObject->Common.Type != ACPI_TYPE_STRING) 591 { 592 return (AE_OK); 593 } 594 595 if (ReturnObject->String.Length == 0) 596 { 597 ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, 598 "Invalid zero-length _HID or _CID string")); 599 600 /* Return AE_OK anyway, let driver handle it */ 601 602 Info->ReturnFlags |= ACPI_OBJECT_REPAIRED; 603 return (AE_OK); 604 } 605 606 /* It is simplest to always create a new string object */ 607 608 NewString = AcpiUtCreateStringObject (ReturnObject->String.Length); 609 if (!NewString) 610 { 611 return (AE_NO_MEMORY); 612 } 613 614 /* 615 * Remove a leading asterisk if present. For some unknown reason, there 616 * are many machines in the field that contains IDs like this. 617 * 618 * Examples: "*PNP0C03", "*ACPI0003" 619 */ 620 Source = ReturnObject->String.Pointer; 621 if (*Source == '*') 622 { 623 Source++; 624 NewString->String.Length--; 625 626 ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR, 627 "%s: Removed invalid leading asterisk\n", Info->FullPathname)); 628 } 629 630 /* 631 * Copy and uppercase the string. From the ACPI 5.0 specification: 632 * 633 * A valid PNP ID must be of the form "AAA####" where A is an uppercase 634 * letter and # is a hex digit. A valid ACPI ID must be of the form 635 * "NNNN####" where N is an uppercase letter or decimal digit, and 636 * # is a hex digit. 637 */ 638 for (Dest = NewString->String.Pointer; *Source; Dest++, Source++) 639 { 640 *Dest = (char) ACPI_TOUPPER (*Source); 641 } 642 643 AcpiUtRemoveReference (ReturnObject); 644 *ReturnObjectPtr = NewString; 645 return (AE_OK); 646 } 647 648 649 /****************************************************************************** 650 * 651 * FUNCTION: AcpiNsRepair_PRT 652 * 653 * PARAMETERS: Info - Method execution information block 654 * ReturnObjectPtr - Pointer to the object returned from the 655 * evaluation of a method or object 656 * 657 * RETURN: Status. AE_OK if object is OK or was repaired successfully 658 * 659 * DESCRIPTION: Repair for the _PRT object. If necessary, fix reversed 660 * SourceName and SourceIndex field, a common BIOS bug. 661 * 662 *****************************************************************************/ 663 664 static ACPI_STATUS 665 AcpiNsRepair_PRT ( 666 ACPI_EVALUATE_INFO *Info, 667 ACPI_OPERAND_OBJECT **ReturnObjectPtr) 668 { 669 ACPI_OPERAND_OBJECT *PackageObject = *ReturnObjectPtr; 670 ACPI_OPERAND_OBJECT **TopObjectList; 671 ACPI_OPERAND_OBJECT **SubObjectList; 672 ACPI_OPERAND_OBJECT *ObjDesc; 673 UINT32 ElementCount; 674 UINT32 Index; 675 676 677 /* Each element in the _PRT package is a subpackage */ 678 679 TopObjectList = PackageObject->Package.Elements; 680 ElementCount = PackageObject->Package.Count; 681 682 for (Index = 0; Index < ElementCount; Index++) 683 { 684 SubObjectList = (*TopObjectList)->Package.Elements; 685 686 /* 687 * If the BIOS has erroneously reversed the _PRT SourceName (index 2) 688 * and the SourceIndex (index 3), fix it. _PRT is important enough to 689 * workaround this BIOS error. This also provides compatibility with 690 * other ACPI implementations. 691 */ 692 ObjDesc = SubObjectList[3]; 693 if (!ObjDesc || (ObjDesc->Common.Type != ACPI_TYPE_INTEGER)) 694 { 695 SubObjectList[3] = SubObjectList[2]; 696 SubObjectList[2] = ObjDesc; 697 Info->ReturnFlags |= ACPI_OBJECT_REPAIRED; 698 699 ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, 700 "PRT[%X]: Fixed reversed SourceName and SourceIndex", 701 Index)); 702 } 703 704 /* Point to the next ACPI_OPERAND_OBJECT in the top level package */ 705 706 TopObjectList++; 707 } 708 709 return (AE_OK); 710 } 711 712 713 /****************************************************************************** 714 * 715 * FUNCTION: AcpiNsRepair_PSS 716 * 717 * PARAMETERS: Info - Method execution information block 718 * ReturnObjectPtr - Pointer to the object returned from the 719 * evaluation of a method or object 720 * 721 * RETURN: Status. AE_OK if object is OK or was repaired successfully 722 * 723 * DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list 724 * by the CPU frequencies. Check that the power dissipation values 725 * are all proportional to CPU frequency (i.e., sorting by 726 * frequency should be the same as sorting by power.) 727 * 728 *****************************************************************************/ 729 730 static ACPI_STATUS 731 AcpiNsRepair_PSS ( 732 ACPI_EVALUATE_INFO *Info, 733 ACPI_OPERAND_OBJECT **ReturnObjectPtr) 734 { 735 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; 736 ACPI_OPERAND_OBJECT **OuterElements; 737 UINT32 OuterElementCount; 738 ACPI_OPERAND_OBJECT **Elements; 739 ACPI_OPERAND_OBJECT *ObjDesc; 740 UINT32 PreviousValue; 741 ACPI_STATUS Status; 742 UINT32 i; 743 744 745 /* 746 * Entries (sub-packages) in the _PSS Package must be sorted by power 747 * dissipation, in descending order. If it appears that the list is 748 * incorrectly sorted, sort it. We sort by CpuFrequency, since this 749 * should be proportional to the power. 750 */ 751 Status =AcpiNsCheckSortedList (Info, ReturnObject, 0, 6, 0, 752 ACPI_SORT_DESCENDING, "CpuFrequency"); 753 if (ACPI_FAILURE (Status)) 754 { 755 return (Status); 756 } 757 758 /* 759 * We now know the list is correctly sorted by CPU frequency. Check if 760 * the power dissipation values are proportional. 761 */ 762 PreviousValue = ACPI_UINT32_MAX; 763 OuterElements = ReturnObject->Package.Elements; 764 OuterElementCount = ReturnObject->Package.Count; 765 766 for (i = 0; i < OuterElementCount; i++) 767 { 768 Elements = (*OuterElements)->Package.Elements; 769 ObjDesc = Elements[1]; /* Index1 = PowerDissipation */ 770 771 if ((UINT32) ObjDesc->Integer.Value > PreviousValue) 772 { 773 ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, 774 "SubPackage[%u,%u] - suspicious power dissipation values", 775 i-1, i)); 776 } 777 778 PreviousValue = (UINT32) ObjDesc->Integer.Value; 779 OuterElements++; 780 } 781 782 return (AE_OK); 783 } 784 785 786 /****************************************************************************** 787 * 788 * FUNCTION: AcpiNsRepair_TSS 789 * 790 * PARAMETERS: Info - Method execution information block 791 * ReturnObjectPtr - Pointer to the object returned from the 792 * evaluation of a method or object 793 * 794 * RETURN: Status. AE_OK if object is OK or was repaired successfully 795 * 796 * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list 797 * descending by the power dissipation values. 798 * 799 *****************************************************************************/ 800 801 static ACPI_STATUS 802 AcpiNsRepair_TSS ( 803 ACPI_EVALUATE_INFO *Info, 804 ACPI_OPERAND_OBJECT **ReturnObjectPtr) 805 { 806 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; 807 ACPI_STATUS Status; 808 ACPI_NAMESPACE_NODE *Node; 809 810 811 /* 812 * We can only sort the _TSS return package if there is no _PSS in the 813 * same scope. This is because if _PSS is present, the ACPI specification 814 * dictates that the _TSS Power Dissipation field is to be ignored, and 815 * therefore some BIOSs leave garbage values in the _TSS Power field(s). 816 * In this case, it is best to just return the _TSS package as-is. 817 * (May, 2011) 818 */ 819 Status = AcpiNsGetNode (Info->Node, "^_PSS", 820 ACPI_NS_NO_UPSEARCH, &Node); 821 if (ACPI_SUCCESS (Status)) 822 { 823 return (AE_OK); 824 } 825 826 Status = AcpiNsCheckSortedList (Info, ReturnObject, 0, 5, 1, 827 ACPI_SORT_DESCENDING, "PowerDissipation"); 828 829 return (Status); 830 } 831 832 833 /****************************************************************************** 834 * 835 * FUNCTION: AcpiNsCheckSortedList 836 * 837 * PARAMETERS: Info - Method execution information block 838 * ReturnObject - Pointer to the top-level returned object 839 * StartIndex - Index of the first sub-package 840 * ExpectedCount - Minimum length of each sub-package 841 * SortIndex - Sub-package entry to sort on 842 * SortDirection - Ascending or descending 843 * SortKeyName - Name of the SortIndex field 844 * 845 * RETURN: Status. AE_OK if the list is valid and is sorted correctly or 846 * has been repaired by sorting the list. 847 * 848 * DESCRIPTION: Check if the package list is valid and sorted correctly by the 849 * SortIndex. If not, then sort the list. 850 * 851 *****************************************************************************/ 852 853 static ACPI_STATUS 854 AcpiNsCheckSortedList ( 855 ACPI_EVALUATE_INFO *Info, 856 ACPI_OPERAND_OBJECT *ReturnObject, 857 UINT32 StartIndex, 858 UINT32 ExpectedCount, 859 UINT32 SortIndex, 860 UINT8 SortDirection, 861 char *SortKeyName) 862 { 863 UINT32 OuterElementCount; 864 ACPI_OPERAND_OBJECT **OuterElements; 865 ACPI_OPERAND_OBJECT **Elements; 866 ACPI_OPERAND_OBJECT *ObjDesc; 867 UINT32 i; 868 UINT32 PreviousValue; 869 870 871 ACPI_FUNCTION_NAME (NsCheckSortedList); 872 873 874 /* The top-level object must be a package */ 875 876 if (ReturnObject->Common.Type != ACPI_TYPE_PACKAGE) 877 { 878 return (AE_AML_OPERAND_TYPE); 879 } 880 881 /* 882 * NOTE: assumes list of sub-packages contains no NULL elements. 883 * Any NULL elements should have been removed by earlier call 884 * to AcpiNsRemoveNullElements. 885 */ 886 OuterElementCount = ReturnObject->Package.Count; 887 if (!OuterElementCount || StartIndex >= OuterElementCount) 888 { 889 return (AE_AML_PACKAGE_LIMIT); 890 } 891 892 OuterElements = &ReturnObject->Package.Elements[StartIndex]; 893 OuterElementCount -= StartIndex; 894 895 PreviousValue = 0; 896 if (SortDirection == ACPI_SORT_DESCENDING) 897 { 898 PreviousValue = ACPI_UINT32_MAX; 899 } 900 901 /* Examine each subpackage */ 902 903 for (i = 0; i < OuterElementCount; i++) 904 { 905 /* Each element of the top-level package must also be a package */ 906 907 if ((*OuterElements)->Common.Type != ACPI_TYPE_PACKAGE) 908 { 909 return (AE_AML_OPERAND_TYPE); 910 } 911 912 /* Each sub-package must have the minimum length */ 913 914 if ((*OuterElements)->Package.Count < ExpectedCount) 915 { 916 return (AE_AML_PACKAGE_LIMIT); 917 } 918 919 Elements = (*OuterElements)->Package.Elements; 920 ObjDesc = Elements[SortIndex]; 921 922 if (ObjDesc->Common.Type != ACPI_TYPE_INTEGER) 923 { 924 return (AE_AML_OPERAND_TYPE); 925 } 926 927 /* 928 * The list must be sorted in the specified order. If we detect a 929 * discrepancy, sort the entire list. 930 */ 931 if (((SortDirection == ACPI_SORT_ASCENDING) && 932 (ObjDesc->Integer.Value < PreviousValue)) || 933 ((SortDirection == ACPI_SORT_DESCENDING) && 934 (ObjDesc->Integer.Value > PreviousValue))) 935 { 936 AcpiNsSortList (&ReturnObject->Package.Elements[StartIndex], 937 OuterElementCount, SortIndex, SortDirection); 938 939 Info->ReturnFlags |= ACPI_OBJECT_REPAIRED; 940 941 ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR, 942 "%s: Repaired unsorted list - now sorted by %s\n", 943 Info->FullPathname, SortKeyName)); 944 return (AE_OK); 945 } 946 947 PreviousValue = (UINT32) ObjDesc->Integer.Value; 948 OuterElements++; 949 } 950 951 return (AE_OK); 952 } 953 954 955 /****************************************************************************** 956 * 957 * FUNCTION: AcpiNsSortList 958 * 959 * PARAMETERS: Elements - Package object element list 960 * Count - Element count for above 961 * Index - Sort by which package element 962 * SortDirection - Ascending or Descending sort 963 * 964 * RETURN: None 965 * 966 * DESCRIPTION: Sort the objects that are in a package element list. 967 * 968 * NOTE: Assumes that all NULL elements have been removed from the package, 969 * and that all elements have been verified to be of type Integer. 970 * 971 *****************************************************************************/ 972 973 static void 974 AcpiNsSortList ( 975 ACPI_OPERAND_OBJECT **Elements, 976 UINT32 Count, 977 UINT32 Index, 978 UINT8 SortDirection) 979 { 980 ACPI_OPERAND_OBJECT *ObjDesc1; 981 ACPI_OPERAND_OBJECT *ObjDesc2; 982 ACPI_OPERAND_OBJECT *TempObj; 983 UINT32 i; 984 UINT32 j; 985 986 987 /* Simple bubble sort */ 988 989 for (i = 1; i < Count; i++) 990 { 991 for (j = (Count - 1); j >= i; j--) 992 { 993 ObjDesc1 = Elements[j-1]->Package.Elements[Index]; 994 ObjDesc2 = Elements[j]->Package.Elements[Index]; 995 996 if (((SortDirection == ACPI_SORT_ASCENDING) && 997 (ObjDesc1->Integer.Value > ObjDesc2->Integer.Value)) || 998 999 ((SortDirection == ACPI_SORT_DESCENDING) && 1000 (ObjDesc1->Integer.Value < ObjDesc2->Integer.Value))) 1001 { 1002 TempObj = Elements[j-1]; 1003 Elements[j-1] = Elements[j]; 1004 Elements[j] = TempObj; 1005 } 1006 } 1007 } 1008 } 1009 1010 1011 /****************************************************************************** 1012 * 1013 * FUNCTION: AcpiNsRemoveElement 1014 * 1015 * PARAMETERS: ObjDesc - Package object element list 1016 * Index - Index of element to remove 1017 * 1018 * RETURN: None 1019 * 1020 * DESCRIPTION: Remove the requested element of a package and delete it. 1021 * 1022 *****************************************************************************/ 1023 1024 static void 1025 AcpiNsRemoveElement ( 1026 ACPI_OPERAND_OBJECT *ObjDesc, 1027 UINT32 Index) 1028 { 1029 ACPI_OPERAND_OBJECT **Source; 1030 ACPI_OPERAND_OBJECT **Dest; 1031 UINT32 Count; 1032 UINT32 NewCount; 1033 UINT32 i; 1034 1035 1036 ACPI_FUNCTION_NAME (NsRemoveElement); 1037 1038 1039 Count = ObjDesc->Package.Count; 1040 NewCount = Count - 1; 1041 1042 Source = ObjDesc->Package.Elements; 1043 Dest = Source; 1044 1045 /* Examine all elements of the package object, remove matched index */ 1046 1047 for (i = 0; i < Count; i++) 1048 { 1049 if (i == Index) 1050 { 1051 AcpiUtRemoveReference (*Source); /* Remove one ref for being in pkg */ 1052 AcpiUtRemoveReference (*Source); 1053 } 1054 else 1055 { 1056 *Dest = *Source; 1057 Dest++; 1058 } 1059 Source++; 1060 } 1061 1062 /* NULL terminate list and update the package count */ 1063 1064 *Dest = NULL; 1065 ObjDesc->Package.Count = NewCount; 1066 } 1067