1 /****************************************************************************** 2 * 3 * Module Name: nsrepair2 - Repair for objects returned by specific 4 * predefined methods 5 * 6 *****************************************************************************/ 7 8 /* 9 * Copyright (C) 2000 - 2014, 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 subpackage count of zero means _CST is meaningless 482 * 4. Count must match the number of C state subpackages 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 * Check if the C-state type values are proportional. 505 */ 506 OuterElementCount = ReturnObject->Package.Count - 1; 507 i = 0; 508 while (i < OuterElementCount) 509 { 510 OuterElements = &ReturnObject->Package.Elements[i + 1]; 511 Removing = FALSE; 512 513 if ((*OuterElements)->Package.Count == 0) 514 { 515 ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, 516 "SubPackage[%u] - removing entry due to zero count", i)); 517 Removing = TRUE; 518 goto RemoveElement; 519 } 520 521 ObjDesc = (*OuterElements)->Package.Elements[1]; /* Index1 = Type */ 522 if ((UINT32) ObjDesc->Integer.Value == 0) 523 { 524 ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, 525 "SubPackage[%u] - removing entry due to invalid Type(0)", i)); 526 Removing = TRUE; 527 } 528 529 RemoveElement: 530 if (Removing) 531 { 532 AcpiNsRemoveElement (ReturnObject, i + 1); 533 OuterElementCount--; 534 } 535 else 536 { 537 i++; 538 } 539 } 540 541 /* Update top-level package count, Type "Integer" checked elsewhere */ 542 543 ObjDesc = ReturnObject->Package.Elements[0]; 544 ObjDesc->Integer.Value = OuterElementCount; 545 546 /* 547 * Entries (subpackages) in the _CST Package must be sorted by the 548 * C-state type, in ascending order. 549 */ 550 Status = AcpiNsCheckSortedList (Info, ReturnObject, 1, 4, 1, 551 ACPI_SORT_ASCENDING, "C-State Type"); 552 if (ACPI_FAILURE (Status)) 553 { 554 return (Status); 555 } 556 557 return (AE_OK); 558 } 559 560 561 /****************************************************************************** 562 * 563 * FUNCTION: AcpiNsRepair_HID 564 * 565 * PARAMETERS: Info - Method execution information block 566 * ReturnObjectPtr - Pointer to the object returned from the 567 * evaluation of a method or object 568 * 569 * RETURN: Status. AE_OK if object is OK or was repaired successfully 570 * 571 * DESCRIPTION: Repair for the _HID object. If a string, ensure that all 572 * letters are uppercase and that there is no leading asterisk. 573 * 574 *****************************************************************************/ 575 576 static ACPI_STATUS 577 AcpiNsRepair_HID ( 578 ACPI_EVALUATE_INFO *Info, 579 ACPI_OPERAND_OBJECT **ReturnObjectPtr) 580 { 581 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; 582 ACPI_OPERAND_OBJECT *NewString; 583 char *Source; 584 char *Dest; 585 586 587 ACPI_FUNCTION_NAME (NsRepair_HID); 588 589 590 /* We only care about string _HID objects (not integers) */ 591 592 if (ReturnObject->Common.Type != ACPI_TYPE_STRING) 593 { 594 return (AE_OK); 595 } 596 597 if (ReturnObject->String.Length == 0) 598 { 599 ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, 600 "Invalid zero-length _HID or _CID string")); 601 602 /* Return AE_OK anyway, let driver handle it */ 603 604 Info->ReturnFlags |= ACPI_OBJECT_REPAIRED; 605 return (AE_OK); 606 } 607 608 /* It is simplest to always create a new string object */ 609 610 NewString = AcpiUtCreateStringObject (ReturnObject->String.Length); 611 if (!NewString) 612 { 613 return (AE_NO_MEMORY); 614 } 615 616 /* 617 * Remove a leading asterisk if present. For some unknown reason, there 618 * are many machines in the field that contains IDs like this. 619 * 620 * Examples: "*PNP0C03", "*ACPI0003" 621 */ 622 Source = ReturnObject->String.Pointer; 623 if (*Source == '*') 624 { 625 Source++; 626 NewString->String.Length--; 627 628 ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR, 629 "%s: Removed invalid leading asterisk\n", Info->FullPathname)); 630 } 631 632 /* 633 * Copy and uppercase the string. From the ACPI 5.0 specification: 634 * 635 * A valid PNP ID must be of the form "AAA####" where A is an uppercase 636 * letter and # is a hex digit. A valid ACPI ID must be of the form 637 * "NNNN####" where N is an uppercase letter or decimal digit, and 638 * # is a hex digit. 639 */ 640 for (Dest = NewString->String.Pointer; *Source; Dest++, Source++) 641 { 642 *Dest = (char) ACPI_TOUPPER (*Source); 643 } 644 645 AcpiUtRemoveReference (ReturnObject); 646 *ReturnObjectPtr = NewString; 647 return (AE_OK); 648 } 649 650 651 /****************************************************************************** 652 * 653 * FUNCTION: AcpiNsRepair_PRT 654 * 655 * PARAMETERS: Info - Method execution information block 656 * ReturnObjectPtr - Pointer to the object returned from the 657 * evaluation of a method or object 658 * 659 * RETURN: Status. AE_OK if object is OK or was repaired successfully 660 * 661 * DESCRIPTION: Repair for the _PRT object. If necessary, fix reversed 662 * SourceName and SourceIndex field, a common BIOS bug. 663 * 664 *****************************************************************************/ 665 666 static ACPI_STATUS 667 AcpiNsRepair_PRT ( 668 ACPI_EVALUATE_INFO *Info, 669 ACPI_OPERAND_OBJECT **ReturnObjectPtr) 670 { 671 ACPI_OPERAND_OBJECT *PackageObject = *ReturnObjectPtr; 672 ACPI_OPERAND_OBJECT **TopObjectList; 673 ACPI_OPERAND_OBJECT **SubObjectList; 674 ACPI_OPERAND_OBJECT *ObjDesc; 675 ACPI_OPERAND_OBJECT *SubPackage; 676 UINT32 ElementCount; 677 UINT32 Index; 678 679 680 /* Each element in the _PRT package is a subpackage */ 681 682 TopObjectList = PackageObject->Package.Elements; 683 ElementCount = PackageObject->Package.Count; 684 685 /* Examine each subpackage */ 686 687 for (Index = 0; Index < ElementCount; Index++, TopObjectList++) 688 { 689 SubPackage = *TopObjectList; 690 SubObjectList = SubPackage->Package.Elements; 691 692 /* Check for minimum required element count */ 693 694 if (SubPackage->Package.Count < 4) 695 { 696 continue; 697 } 698 699 /* 700 * If the BIOS has erroneously reversed the _PRT SourceName (index 2) 701 * and the SourceIndex (index 3), fix it. _PRT is important enough to 702 * workaround this BIOS error. This also provides compatibility with 703 * other ACPI implementations. 704 */ 705 ObjDesc = SubObjectList[3]; 706 if (!ObjDesc || (ObjDesc->Common.Type != ACPI_TYPE_INTEGER)) 707 { 708 SubObjectList[3] = SubObjectList[2]; 709 SubObjectList[2] = ObjDesc; 710 Info->ReturnFlags |= ACPI_OBJECT_REPAIRED; 711 712 ACPI_WARN_PREDEFINED ((AE_INFO, 713 Info->FullPathname, Info->NodeFlags, 714 "PRT[%X]: Fixed reversed SourceName and SourceIndex", 715 Index)); 716 } 717 } 718 719 return (AE_OK); 720 } 721 722 723 /****************************************************************************** 724 * 725 * FUNCTION: AcpiNsRepair_PSS 726 * 727 * PARAMETERS: Info - Method execution information block 728 * ReturnObjectPtr - Pointer to the object returned from the 729 * evaluation of a method or object 730 * 731 * RETURN: Status. AE_OK if object is OK or was repaired successfully 732 * 733 * DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list 734 * by the CPU frequencies. Check that the power dissipation values 735 * are all proportional to CPU frequency (i.e., sorting by 736 * frequency should be the same as sorting by power.) 737 * 738 *****************************************************************************/ 739 740 static ACPI_STATUS 741 AcpiNsRepair_PSS ( 742 ACPI_EVALUATE_INFO *Info, 743 ACPI_OPERAND_OBJECT **ReturnObjectPtr) 744 { 745 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; 746 ACPI_OPERAND_OBJECT **OuterElements; 747 UINT32 OuterElementCount; 748 ACPI_OPERAND_OBJECT **Elements; 749 ACPI_OPERAND_OBJECT *ObjDesc; 750 UINT32 PreviousValue; 751 ACPI_STATUS Status; 752 UINT32 i; 753 754 755 /* 756 * Entries (subpackages) in the _PSS Package must be sorted by power 757 * dissipation, in descending order. If it appears that the list is 758 * incorrectly sorted, sort it. We sort by CpuFrequency, since this 759 * should be proportional to the power. 760 */ 761 Status =AcpiNsCheckSortedList (Info, ReturnObject, 0, 6, 0, 762 ACPI_SORT_DESCENDING, "CpuFrequency"); 763 if (ACPI_FAILURE (Status)) 764 { 765 return (Status); 766 } 767 768 /* 769 * We now know the list is correctly sorted by CPU frequency. Check if 770 * the power dissipation values are proportional. 771 */ 772 PreviousValue = ACPI_UINT32_MAX; 773 OuterElements = ReturnObject->Package.Elements; 774 OuterElementCount = ReturnObject->Package.Count; 775 776 for (i = 0; i < OuterElementCount; i++) 777 { 778 Elements = (*OuterElements)->Package.Elements; 779 ObjDesc = Elements[1]; /* Index1 = PowerDissipation */ 780 781 if ((UINT32) ObjDesc->Integer.Value > PreviousValue) 782 { 783 ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, 784 "SubPackage[%u,%u] - suspicious power dissipation values", 785 i-1, i)); 786 } 787 788 PreviousValue = (UINT32) ObjDesc->Integer.Value; 789 OuterElements++; 790 } 791 792 return (AE_OK); 793 } 794 795 796 /****************************************************************************** 797 * 798 * FUNCTION: AcpiNsRepair_TSS 799 * 800 * PARAMETERS: Info - Method execution information block 801 * ReturnObjectPtr - Pointer to the object returned from the 802 * evaluation of a method or object 803 * 804 * RETURN: Status. AE_OK if object is OK or was repaired successfully 805 * 806 * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list 807 * descending by the power dissipation values. 808 * 809 *****************************************************************************/ 810 811 static ACPI_STATUS 812 AcpiNsRepair_TSS ( 813 ACPI_EVALUATE_INFO *Info, 814 ACPI_OPERAND_OBJECT **ReturnObjectPtr) 815 { 816 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; 817 ACPI_STATUS Status; 818 ACPI_NAMESPACE_NODE *Node; 819 820 821 /* 822 * We can only sort the _TSS return package if there is no _PSS in the 823 * same scope. This is because if _PSS is present, the ACPI specification 824 * dictates that the _TSS Power Dissipation field is to be ignored, and 825 * therefore some BIOSs leave garbage values in the _TSS Power field(s). 826 * In this case, it is best to just return the _TSS package as-is. 827 * (May, 2011) 828 */ 829 Status = AcpiNsGetNode (Info->Node, "^_PSS", 830 ACPI_NS_NO_UPSEARCH, &Node); 831 if (ACPI_SUCCESS (Status)) 832 { 833 return (AE_OK); 834 } 835 836 Status = AcpiNsCheckSortedList (Info, ReturnObject, 0, 5, 1, 837 ACPI_SORT_DESCENDING, "PowerDissipation"); 838 839 return (Status); 840 } 841 842 843 /****************************************************************************** 844 * 845 * FUNCTION: AcpiNsCheckSortedList 846 * 847 * PARAMETERS: Info - Method execution information block 848 * ReturnObject - Pointer to the top-level returned object 849 * StartIndex - Index of the first subpackage 850 * ExpectedCount - Minimum length of each subpackage 851 * SortIndex - Subpackage entry to sort on 852 * SortDirection - Ascending or descending 853 * SortKeyName - Name of the SortIndex field 854 * 855 * RETURN: Status. AE_OK if the list is valid and is sorted correctly or 856 * has been repaired by sorting the list. 857 * 858 * DESCRIPTION: Check if the package list is valid and sorted correctly by the 859 * SortIndex. If not, then sort the list. 860 * 861 *****************************************************************************/ 862 863 static ACPI_STATUS 864 AcpiNsCheckSortedList ( 865 ACPI_EVALUATE_INFO *Info, 866 ACPI_OPERAND_OBJECT *ReturnObject, 867 UINT32 StartIndex, 868 UINT32 ExpectedCount, 869 UINT32 SortIndex, 870 UINT8 SortDirection, 871 char *SortKeyName) 872 { 873 UINT32 OuterElementCount; 874 ACPI_OPERAND_OBJECT **OuterElements; 875 ACPI_OPERAND_OBJECT **Elements; 876 ACPI_OPERAND_OBJECT *ObjDesc; 877 UINT32 i; 878 UINT32 PreviousValue; 879 880 881 ACPI_FUNCTION_NAME (NsCheckSortedList); 882 883 884 /* The top-level object must be a package */ 885 886 if (ReturnObject->Common.Type != ACPI_TYPE_PACKAGE) 887 { 888 return (AE_AML_OPERAND_TYPE); 889 } 890 891 /* 892 * NOTE: assumes list of subpackages contains no NULL elements. 893 * Any NULL elements should have been removed by earlier call 894 * to AcpiNsRemoveNullElements. 895 */ 896 OuterElementCount = ReturnObject->Package.Count; 897 if (!OuterElementCount || StartIndex >= OuterElementCount) 898 { 899 return (AE_AML_PACKAGE_LIMIT); 900 } 901 902 OuterElements = &ReturnObject->Package.Elements[StartIndex]; 903 OuterElementCount -= StartIndex; 904 905 PreviousValue = 0; 906 if (SortDirection == ACPI_SORT_DESCENDING) 907 { 908 PreviousValue = ACPI_UINT32_MAX; 909 } 910 911 /* Examine each subpackage */ 912 913 for (i = 0; i < OuterElementCount; i++) 914 { 915 /* Each element of the top-level package must also be a package */ 916 917 if ((*OuterElements)->Common.Type != ACPI_TYPE_PACKAGE) 918 { 919 return (AE_AML_OPERAND_TYPE); 920 } 921 922 /* Each subpackage must have the minimum length */ 923 924 if ((*OuterElements)->Package.Count < ExpectedCount) 925 { 926 return (AE_AML_PACKAGE_LIMIT); 927 } 928 929 Elements = (*OuterElements)->Package.Elements; 930 ObjDesc = Elements[SortIndex]; 931 932 if (ObjDesc->Common.Type != ACPI_TYPE_INTEGER) 933 { 934 return (AE_AML_OPERAND_TYPE); 935 } 936 937 /* 938 * The list must be sorted in the specified order. If we detect a 939 * discrepancy, sort the entire list. 940 */ 941 if (((SortDirection == ACPI_SORT_ASCENDING) && 942 (ObjDesc->Integer.Value < PreviousValue)) || 943 ((SortDirection == ACPI_SORT_DESCENDING) && 944 (ObjDesc->Integer.Value > PreviousValue))) 945 { 946 AcpiNsSortList (&ReturnObject->Package.Elements[StartIndex], 947 OuterElementCount, SortIndex, SortDirection); 948 949 Info->ReturnFlags |= ACPI_OBJECT_REPAIRED; 950 951 ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR, 952 "%s: Repaired unsorted list - now sorted by %s\n", 953 Info->FullPathname, SortKeyName)); 954 return (AE_OK); 955 } 956 957 PreviousValue = (UINT32) ObjDesc->Integer.Value; 958 OuterElements++; 959 } 960 961 return (AE_OK); 962 } 963 964 965 /****************************************************************************** 966 * 967 * FUNCTION: AcpiNsSortList 968 * 969 * PARAMETERS: Elements - Package object element list 970 * Count - Element count for above 971 * Index - Sort by which package element 972 * SortDirection - Ascending or Descending sort 973 * 974 * RETURN: None 975 * 976 * DESCRIPTION: Sort the objects that are in a package element list. 977 * 978 * NOTE: Assumes that all NULL elements have been removed from the package, 979 * and that all elements have been verified to be of type Integer. 980 * 981 *****************************************************************************/ 982 983 static void 984 AcpiNsSortList ( 985 ACPI_OPERAND_OBJECT **Elements, 986 UINT32 Count, 987 UINT32 Index, 988 UINT8 SortDirection) 989 { 990 ACPI_OPERAND_OBJECT *ObjDesc1; 991 ACPI_OPERAND_OBJECT *ObjDesc2; 992 ACPI_OPERAND_OBJECT *TempObj; 993 UINT32 i; 994 UINT32 j; 995 996 997 /* Simple bubble sort */ 998 999 for (i = 1; i < Count; i++) 1000 { 1001 for (j = (Count - 1); j >= i; j--) 1002 { 1003 ObjDesc1 = Elements[j-1]->Package.Elements[Index]; 1004 ObjDesc2 = Elements[j]->Package.Elements[Index]; 1005 1006 if (((SortDirection == ACPI_SORT_ASCENDING) && 1007 (ObjDesc1->Integer.Value > ObjDesc2->Integer.Value)) || 1008 1009 ((SortDirection == ACPI_SORT_DESCENDING) && 1010 (ObjDesc1->Integer.Value < ObjDesc2->Integer.Value))) 1011 { 1012 TempObj = Elements[j-1]; 1013 Elements[j-1] = Elements[j]; 1014 Elements[j] = TempObj; 1015 } 1016 } 1017 } 1018 } 1019 1020 1021 /****************************************************************************** 1022 * 1023 * FUNCTION: AcpiNsRemoveElement 1024 * 1025 * PARAMETERS: ObjDesc - Package object element list 1026 * Index - Index of element to remove 1027 * 1028 * RETURN: None 1029 * 1030 * DESCRIPTION: Remove the requested element of a package and delete it. 1031 * 1032 *****************************************************************************/ 1033 1034 static void 1035 AcpiNsRemoveElement ( 1036 ACPI_OPERAND_OBJECT *ObjDesc, 1037 UINT32 Index) 1038 { 1039 ACPI_OPERAND_OBJECT **Source; 1040 ACPI_OPERAND_OBJECT **Dest; 1041 UINT32 Count; 1042 UINT32 NewCount; 1043 UINT32 i; 1044 1045 1046 ACPI_FUNCTION_NAME (NsRemoveElement); 1047 1048 1049 Count = ObjDesc->Package.Count; 1050 NewCount = Count - 1; 1051 1052 Source = ObjDesc->Package.Elements; 1053 Dest = Source; 1054 1055 /* Examine all elements of the package object, remove matched index */ 1056 1057 for (i = 0; i < Count; i++) 1058 { 1059 if (i == Index) 1060 { 1061 AcpiUtRemoveReference (*Source); /* Remove one ref for being in pkg */ 1062 AcpiUtRemoveReference (*Source); 1063 } 1064 else 1065 { 1066 *Dest = *Source; 1067 Dest++; 1068 } 1069 Source++; 1070 } 1071 1072 /* NULL terminate list and update the package count */ 1073 1074 *Dest = NULL; 1075 ObjDesc->Package.Count = NewCount; 1076 } 1077