diff options
Diffstat (limited to 'sys/contrib/dev/acpica/components/namespace/nsrepair2.c')
-rw-r--r-- | sys/contrib/dev/acpica/components/namespace/nsrepair2.c | 1066 |
1 files changed, 1066 insertions, 0 deletions
diff --git a/sys/contrib/dev/acpica/components/namespace/nsrepair2.c b/sys/contrib/dev/acpica/components/namespace/nsrepair2.c new file mode 100644 index 0000000..85379e6 --- /dev/null +++ b/sys/contrib/dev/acpica/components/namespace/nsrepair2.c @@ -0,0 +1,1066 @@ +/****************************************************************************** + * + * Module Name: nsrepair2 - Repair for objects returned by specific + * predefined methods + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2013, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define __NSREPAIR2_C__ + +#include <contrib/dev/acpica/include/acpi.h> +#include <contrib/dev/acpica/include/accommon.h> +#include <contrib/dev/acpica/include/acnamesp.h> + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsrepair2") + + +/* + * Information structure and handler for ACPI predefined names that can + * be repaired on a per-name basis. + */ +typedef +ACPI_STATUS (*ACPI_REPAIR_FUNCTION) ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + +typedef struct acpi_repair_info +{ + char Name[ACPI_NAME_SIZE]; + ACPI_REPAIR_FUNCTION RepairFunction; + +} ACPI_REPAIR_INFO; + + +/* Local prototypes */ + +static const ACPI_REPAIR_INFO * +AcpiNsMatchComplexRepair ( + ACPI_NAMESPACE_NODE *Node); + +static ACPI_STATUS +AcpiNsRepair_ALR ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + +static ACPI_STATUS +AcpiNsRepair_CID ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + +static ACPI_STATUS +AcpiNsRepair_CST ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + +static ACPI_STATUS +AcpiNsRepair_FDE ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + +static ACPI_STATUS +AcpiNsRepair_HID ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + +static ACPI_STATUS +AcpiNsRepair_PRT ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + +static ACPI_STATUS +AcpiNsRepair_PSS ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + +static ACPI_STATUS +AcpiNsRepair_TSS ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + +static ACPI_STATUS +AcpiNsCheckSortedList ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT *ReturnObject, + UINT32 StartIndex, + UINT32 ExpectedCount, + UINT32 SortIndex, + UINT8 SortDirection, + char *SortKeyName); + +/* Values for SortDirection above */ + +#define ACPI_SORT_ASCENDING 0 +#define ACPI_SORT_DESCENDING 1 + +static void +AcpiNsRemoveElement ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT32 Index); + +static void +AcpiNsSortList ( + ACPI_OPERAND_OBJECT **Elements, + UINT32 Count, + UINT32 Index, + UINT8 SortDirection); + + +/* + * This table contains the names of the predefined methods for which we can + * perform more complex repairs. + * + * As necessary: + * + * _ALR: Sort the list ascending by AmbientIlluminance + * _CID: Strings: uppercase all, remove any leading asterisk + * _CST: Sort the list ascending by C state type + * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs + * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs + * _HID: Strings: uppercase all, remove any leading asterisk + * _PRT: Fix reversed SourceName and SourceIndex + * _PSS: Sort the list descending by Power + * _TSS: Sort the list descending by Power + * + * Names that must be packages, but cannot be sorted: + * + * _BCL: Values are tied to the Package index where they appear, and cannot + * be moved or sorted. These index values are used for _BQC and _BCM. + * However, we can fix the case where a buffer is returned, by converting + * it to a Package of integers. + */ +static const ACPI_REPAIR_INFO AcpiNsRepairableNames[] = +{ + {"_ALR", AcpiNsRepair_ALR}, + {"_CID", AcpiNsRepair_CID}, + {"_CST", AcpiNsRepair_CST}, + {"_FDE", AcpiNsRepair_FDE}, + {"_GTM", AcpiNsRepair_FDE}, /* _GTM has same repair as _FDE */ + {"_HID", AcpiNsRepair_HID}, + {"_PRT", AcpiNsRepair_PRT}, + {"_PSS", AcpiNsRepair_PSS}, + {"_TSS", AcpiNsRepair_TSS}, + {{0,0,0,0}, NULL} /* Table terminator */ +}; + + +#define ACPI_FDE_FIELD_COUNT 5 +#define ACPI_FDE_BYTE_BUFFER_SIZE 5 +#define ACPI_FDE_DWORD_BUFFER_SIZE (ACPI_FDE_FIELD_COUNT * sizeof (UINT32)) + + +/****************************************************************************** + * + * FUNCTION: AcpiNsComplexRepairs + * + * PARAMETERS: Info - Method execution information block + * Node - Namespace node for the method/object + * ValidateStatus - Original status of earlier validation + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if repair was successful. If name is not + * matched, ValidateStatus is returned. + * + * DESCRIPTION: Attempt to repair/convert a return object of a type that was + * not expected. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiNsComplexRepairs ( + ACPI_EVALUATE_INFO *Info, + ACPI_NAMESPACE_NODE *Node, + ACPI_STATUS ValidateStatus, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + const ACPI_REPAIR_INFO *Predefined; + ACPI_STATUS Status; + + + /* Check if this name is in the list of repairable names */ + + Predefined = AcpiNsMatchComplexRepair (Node); + if (!Predefined) + { + return (ValidateStatus); + } + + Status = Predefined->RepairFunction (Info, ReturnObjectPtr); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsMatchComplexRepair + * + * PARAMETERS: Node - Namespace node for the method/object + * + * RETURN: Pointer to entry in repair table. NULL indicates not found. + * + * DESCRIPTION: Check an object name against the repairable object list. + * + *****************************************************************************/ + +static const ACPI_REPAIR_INFO * +AcpiNsMatchComplexRepair ( + ACPI_NAMESPACE_NODE *Node) +{ + const ACPI_REPAIR_INFO *ThisName; + + + /* Search info table for a repairable predefined method/object name */ + + ThisName = AcpiNsRepairableNames; + while (ThisName->RepairFunction) + { + if (ACPI_COMPARE_NAME (Node->Name.Ascii, ThisName->Name)) + { + return (ThisName); + } + ThisName++; + } + + return (NULL); /* Not found */ +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsRepair_ALR + * + * PARAMETERS: Info - Method execution information block + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if object is OK or was repaired successfully + * + * DESCRIPTION: Repair for the _ALR object. If necessary, sort the object list + * ascending by the ambient illuminance values. + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiNsRepair_ALR ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; + ACPI_STATUS Status; + + + Status = AcpiNsCheckSortedList (Info, ReturnObject, 0, 2, 1, + ACPI_SORT_ASCENDING, "AmbientIlluminance"); + + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsRepair_FDE + * + * PARAMETERS: Info - Method execution information block + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if object is OK or was repaired successfully + * + * DESCRIPTION: Repair for the _FDE and _GTM objects. The expected return + * value is a Buffer of 5 DWORDs. This function repairs a common + * problem where the return value is a Buffer of BYTEs, not + * DWORDs. + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiNsRepair_FDE ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; + ACPI_OPERAND_OBJECT *BufferObject; + UINT8 *ByteBuffer; + UINT32 *DwordBuffer; + UINT32 i; + + + ACPI_FUNCTION_NAME (NsRepair_FDE); + + + switch (ReturnObject->Common.Type) + { + case ACPI_TYPE_BUFFER: + + /* This is the expected type. Length should be (at least) 5 DWORDs */ + + if (ReturnObject->Buffer.Length >= ACPI_FDE_DWORD_BUFFER_SIZE) + { + return (AE_OK); + } + + /* We can only repair if we have exactly 5 BYTEs */ + + if (ReturnObject->Buffer.Length != ACPI_FDE_BYTE_BUFFER_SIZE) + { + ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, + "Incorrect return buffer length %u, expected %u", + ReturnObject->Buffer.Length, ACPI_FDE_DWORD_BUFFER_SIZE)); + + return (AE_AML_OPERAND_TYPE); + } + + /* Create the new (larger) buffer object */ + + BufferObject = AcpiUtCreateBufferObject (ACPI_FDE_DWORD_BUFFER_SIZE); + if (!BufferObject) + { + return (AE_NO_MEMORY); + } + + /* Expand each byte to a DWORD */ + + ByteBuffer = ReturnObject->Buffer.Pointer; + DwordBuffer = ACPI_CAST_PTR (UINT32, BufferObject->Buffer.Pointer); + + for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++) + { + *DwordBuffer = (UINT32) *ByteBuffer; + DwordBuffer++; + ByteBuffer++; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR, + "%s Expanded Byte Buffer to expected DWord Buffer\n", + Info->FullPathname)); + break; + + default: + + return (AE_AML_OPERAND_TYPE); + } + + /* Delete the original return object, return the new buffer object */ + + AcpiUtRemoveReference (ReturnObject); + *ReturnObjectPtr = BufferObject; + + Info->ReturnFlags |= ACPI_OBJECT_REPAIRED; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsRepair_CID + * + * PARAMETERS: Info - Method execution information block + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if object is OK or was repaired successfully + * + * DESCRIPTION: Repair for the _CID object. If a string, ensure that all + * letters are uppercase and that there is no leading asterisk. + * If a Package, ensure same for all string elements. + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiNsRepair_CID ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; + ACPI_OPERAND_OBJECT **ElementPtr; + ACPI_OPERAND_OBJECT *OriginalElement; + UINT16 OriginalRefCount; + UINT32 i; + + + /* Check for _CID as a simple string */ + + if (ReturnObject->Common.Type == ACPI_TYPE_STRING) + { + Status = AcpiNsRepair_HID (Info, ReturnObjectPtr); + return (Status); + } + + /* Exit if not a Package */ + + if (ReturnObject->Common.Type != ACPI_TYPE_PACKAGE) + { + return (AE_OK); + } + + /* Examine each element of the _CID package */ + + ElementPtr = ReturnObject->Package.Elements; + for (i = 0; i < ReturnObject->Package.Count; i++) + { + OriginalElement = *ElementPtr; + OriginalRefCount = OriginalElement->Common.ReferenceCount; + + Status = AcpiNsRepair_HID (Info, ElementPtr); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Take care with reference counts */ + + if (OriginalElement != *ElementPtr) + { + /* Element was replaced */ + + (*ElementPtr)->Common.ReferenceCount = + OriginalRefCount; + + AcpiUtRemoveReference (OriginalElement); + } + + ElementPtr++; + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsRepair_CST + * + * PARAMETERS: Info - Method execution information block + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if object is OK or was repaired successfully + * + * DESCRIPTION: Repair for the _CST object: + * 1. Sort the list ascending by C state type + * 2. Ensure type cannot be zero + * 3. A sub-package count of zero means _CST is meaningless + * 4. Count must match the number of C state sub-packages + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiNsRepair_CST ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; + ACPI_OPERAND_OBJECT **OuterElements; + UINT32 OuterElementCount; + ACPI_OPERAND_OBJECT *ObjDesc; + ACPI_STATUS Status; + BOOLEAN Removing; + UINT32 i; + + + ACPI_FUNCTION_NAME (NsRepair_CST); + + + /* + * Entries (subpackages) in the _CST Package must be sorted by the + * C-state type, in ascending order. + */ + Status = AcpiNsCheckSortedList (Info, ReturnObject, 1, 4, 1, + ACPI_SORT_ASCENDING, "C-State Type"); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* + * We now know the list is correctly sorted by C-state type. Check if + * the C-state type values are proportional. + */ + OuterElementCount = ReturnObject->Package.Count - 1; + i = 0; + while (i < OuterElementCount) + { + OuterElements = &ReturnObject->Package.Elements[i + 1]; + Removing = FALSE; + + if ((*OuterElements)->Package.Count == 0) + { + ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, + "SubPackage[%u] - removing entry due to zero count", i)); + Removing = TRUE; + } + + ObjDesc = (*OuterElements)->Package.Elements[1]; /* Index1 = Type */ + if ((UINT32) ObjDesc->Integer.Value == 0) + { + ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, + "SubPackage[%u] - removing entry due to invalid Type(0)", i)); + Removing = TRUE; + } + + if (Removing) + { + AcpiNsRemoveElement (ReturnObject, i + 1); + OuterElementCount--; + } + else + { + i++; + } + } + + /* Update top-level package count, Type "Integer" checked elsewhere */ + + ObjDesc = ReturnObject->Package.Elements[0]; + ObjDesc->Integer.Value = OuterElementCount; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsRepair_HID + * + * PARAMETERS: Info - Method execution information block + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if object is OK or was repaired successfully + * + * DESCRIPTION: Repair for the _HID object. If a string, ensure that all + * letters are uppercase and that there is no leading asterisk. + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiNsRepair_HID ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; + ACPI_OPERAND_OBJECT *NewString; + char *Source; + char *Dest; + + + ACPI_FUNCTION_NAME (NsRepair_HID); + + + /* We only care about string _HID objects (not integers) */ + + if (ReturnObject->Common.Type != ACPI_TYPE_STRING) + { + return (AE_OK); + } + + if (ReturnObject->String.Length == 0) + { + ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, + "Invalid zero-length _HID or _CID string")); + + /* Return AE_OK anyway, let driver handle it */ + + Info->ReturnFlags |= ACPI_OBJECT_REPAIRED; + return (AE_OK); + } + + /* It is simplest to always create a new string object */ + + NewString = AcpiUtCreateStringObject (ReturnObject->String.Length); + if (!NewString) + { + return (AE_NO_MEMORY); + } + + /* + * Remove a leading asterisk if present. For some unknown reason, there + * are many machines in the field that contains IDs like this. + * + * Examples: "*PNP0C03", "*ACPI0003" + */ + Source = ReturnObject->String.Pointer; + if (*Source == '*') + { + Source++; + NewString->String.Length--; + + ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR, + "%s: Removed invalid leading asterisk\n", Info->FullPathname)); + } + + /* + * Copy and uppercase the string. From the ACPI 5.0 specification: + * + * A valid PNP ID must be of the form "AAA####" where A is an uppercase + * letter and # is a hex digit. A valid ACPI ID must be of the form + * "NNNN####" where N is an uppercase letter or decimal digit, and + * # is a hex digit. + */ + for (Dest = NewString->String.Pointer; *Source; Dest++, Source++) + { + *Dest = (char) ACPI_TOUPPER (*Source); + } + + AcpiUtRemoveReference (ReturnObject); + *ReturnObjectPtr = NewString; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsRepair_PRT + * + * PARAMETERS: Info - Method execution information block + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if object is OK or was repaired successfully + * + * DESCRIPTION: Repair for the _PRT object. If necessary, fix reversed + * SourceName and SourceIndex field, a common BIOS bug. + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiNsRepair_PRT ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + ACPI_OPERAND_OBJECT *PackageObject = *ReturnObjectPtr; + ACPI_OPERAND_OBJECT **TopObjectList; + ACPI_OPERAND_OBJECT **SubObjectList; + ACPI_OPERAND_OBJECT *ObjDesc; + UINT32 ElementCount; + UINT32 Index; + + + /* Each element in the _PRT package is a subpackage */ + + TopObjectList = PackageObject->Package.Elements; + ElementCount = PackageObject->Package.Count; + + for (Index = 0; Index < ElementCount; Index++) + { + SubObjectList = (*TopObjectList)->Package.Elements; + + /* + * If the BIOS has erroneously reversed the _PRT SourceName (index 2) + * and the SourceIndex (index 3), fix it. _PRT is important enough to + * workaround this BIOS error. This also provides compatibility with + * other ACPI implementations. + */ + ObjDesc = SubObjectList[3]; + if (!ObjDesc || (ObjDesc->Common.Type != ACPI_TYPE_INTEGER)) + { + SubObjectList[3] = SubObjectList[2]; + SubObjectList[2] = ObjDesc; + Info->ReturnFlags |= ACPI_OBJECT_REPAIRED; + + ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, + "PRT[%X]: Fixed reversed SourceName and SourceIndex", + Index)); + } + + /* Point to the next ACPI_OPERAND_OBJECT in the top level package */ + + TopObjectList++; + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsRepair_PSS + * + * PARAMETERS: Info - Method execution information block + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if object is OK or was repaired successfully + * + * DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list + * by the CPU frequencies. Check that the power dissipation values + * are all proportional to CPU frequency (i.e., sorting by + * frequency should be the same as sorting by power.) + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiNsRepair_PSS ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; + ACPI_OPERAND_OBJECT **OuterElements; + UINT32 OuterElementCount; + ACPI_OPERAND_OBJECT **Elements; + ACPI_OPERAND_OBJECT *ObjDesc; + UINT32 PreviousValue; + ACPI_STATUS Status; + UINT32 i; + + + /* + * Entries (sub-packages) in the _PSS Package must be sorted by power + * dissipation, in descending order. If it appears that the list is + * incorrectly sorted, sort it. We sort by CpuFrequency, since this + * should be proportional to the power. + */ + Status =AcpiNsCheckSortedList (Info, ReturnObject, 0, 6, 0, + ACPI_SORT_DESCENDING, "CpuFrequency"); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* + * We now know the list is correctly sorted by CPU frequency. Check if + * the power dissipation values are proportional. + */ + PreviousValue = ACPI_UINT32_MAX; + OuterElements = ReturnObject->Package.Elements; + OuterElementCount = ReturnObject->Package.Count; + + for (i = 0; i < OuterElementCount; i++) + { + Elements = (*OuterElements)->Package.Elements; + ObjDesc = Elements[1]; /* Index1 = PowerDissipation */ + + if ((UINT32) ObjDesc->Integer.Value > PreviousValue) + { + ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, + "SubPackage[%u,%u] - suspicious power dissipation values", + i-1, i)); + } + + PreviousValue = (UINT32) ObjDesc->Integer.Value; + OuterElements++; + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsRepair_TSS + * + * PARAMETERS: Info - Method execution information block + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if object is OK or was repaired successfully + * + * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list + * descending by the power dissipation values. + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiNsRepair_TSS ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node; + + + /* + * We can only sort the _TSS return package if there is no _PSS in the + * same scope. This is because if _PSS is present, the ACPI specification + * dictates that the _TSS Power Dissipation field is to be ignored, and + * therefore some BIOSs leave garbage values in the _TSS Power field(s). + * In this case, it is best to just return the _TSS package as-is. + * (May, 2011) + */ + Status = AcpiNsGetNode (Info->Node, "^_PSS", + ACPI_NS_NO_UPSEARCH, &Node); + if (ACPI_SUCCESS (Status)) + { + return (AE_OK); + } + + Status = AcpiNsCheckSortedList (Info, ReturnObject, 0, 5, 1, + ACPI_SORT_DESCENDING, "PowerDissipation"); + + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsCheckSortedList + * + * PARAMETERS: Info - Method execution information block + * ReturnObject - Pointer to the top-level returned object + * StartIndex - Index of the first sub-package + * ExpectedCount - Minimum length of each sub-package + * SortIndex - Sub-package entry to sort on + * SortDirection - Ascending or descending + * SortKeyName - Name of the SortIndex field + * + * RETURN: Status. AE_OK if the list is valid and is sorted correctly or + * has been repaired by sorting the list. + * + * DESCRIPTION: Check if the package list is valid and sorted correctly by the + * SortIndex. If not, then sort the list. + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiNsCheckSortedList ( + ACPI_EVALUATE_INFO *Info, + ACPI_OPERAND_OBJECT *ReturnObject, + UINT32 StartIndex, + UINT32 ExpectedCount, + UINT32 SortIndex, + UINT8 SortDirection, + char *SortKeyName) +{ + UINT32 OuterElementCount; + ACPI_OPERAND_OBJECT **OuterElements; + ACPI_OPERAND_OBJECT **Elements; + ACPI_OPERAND_OBJECT *ObjDesc; + UINT32 i; + UINT32 PreviousValue; + + + ACPI_FUNCTION_NAME (NsCheckSortedList); + + + /* The top-level object must be a package */ + + if (ReturnObject->Common.Type != ACPI_TYPE_PACKAGE) + { + return (AE_AML_OPERAND_TYPE); + } + + /* + * NOTE: assumes list of sub-packages contains no NULL elements. + * Any NULL elements should have been removed by earlier call + * to AcpiNsRemoveNullElements. + */ + OuterElementCount = ReturnObject->Package.Count; + if (!OuterElementCount || StartIndex >= OuterElementCount) + { + return (AE_AML_PACKAGE_LIMIT); + } + + OuterElements = &ReturnObject->Package.Elements[StartIndex]; + OuterElementCount -= StartIndex; + + PreviousValue = 0; + if (SortDirection == ACPI_SORT_DESCENDING) + { + PreviousValue = ACPI_UINT32_MAX; + } + + /* Examine each subpackage */ + + for (i = 0; i < OuterElementCount; i++) + { + /* Each element of the top-level package must also be a package */ + + if ((*OuterElements)->Common.Type != ACPI_TYPE_PACKAGE) + { + return (AE_AML_OPERAND_TYPE); + } + + /* Each sub-package must have the minimum length */ + + if ((*OuterElements)->Package.Count < ExpectedCount) + { + return (AE_AML_PACKAGE_LIMIT); + } + + Elements = (*OuterElements)->Package.Elements; + ObjDesc = Elements[SortIndex]; + + if (ObjDesc->Common.Type != ACPI_TYPE_INTEGER) + { + return (AE_AML_OPERAND_TYPE); + } + + /* + * The list must be sorted in the specified order. If we detect a + * discrepancy, sort the entire list. + */ + if (((SortDirection == ACPI_SORT_ASCENDING) && + (ObjDesc->Integer.Value < PreviousValue)) || + ((SortDirection == ACPI_SORT_DESCENDING) && + (ObjDesc->Integer.Value > PreviousValue))) + { + AcpiNsSortList (&ReturnObject->Package.Elements[StartIndex], + OuterElementCount, SortIndex, SortDirection); + + Info->ReturnFlags |= ACPI_OBJECT_REPAIRED; + + ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR, + "%s: Repaired unsorted list - now sorted by %s\n", + Info->FullPathname, SortKeyName)); + return (AE_OK); + } + + PreviousValue = (UINT32) ObjDesc->Integer.Value; + OuterElements++; + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsSortList + * + * PARAMETERS: Elements - Package object element list + * Count - Element count for above + * Index - Sort by which package element + * SortDirection - Ascending or Descending sort + * + * RETURN: None + * + * DESCRIPTION: Sort the objects that are in a package element list. + * + * NOTE: Assumes that all NULL elements have been removed from the package, + * and that all elements have been verified to be of type Integer. + * + *****************************************************************************/ + +static void +AcpiNsSortList ( + ACPI_OPERAND_OBJECT **Elements, + UINT32 Count, + UINT32 Index, + UINT8 SortDirection) +{ + ACPI_OPERAND_OBJECT *ObjDesc1; + ACPI_OPERAND_OBJECT *ObjDesc2; + ACPI_OPERAND_OBJECT *TempObj; + UINT32 i; + UINT32 j; + + + /* Simple bubble sort */ + + for (i = 1; i < Count; i++) + { + for (j = (Count - 1); j >= i; j--) + { + ObjDesc1 = Elements[j-1]->Package.Elements[Index]; + ObjDesc2 = Elements[j]->Package.Elements[Index]; + + if (((SortDirection == ACPI_SORT_ASCENDING) && + (ObjDesc1->Integer.Value > ObjDesc2->Integer.Value)) || + + ((SortDirection == ACPI_SORT_DESCENDING) && + (ObjDesc1->Integer.Value < ObjDesc2->Integer.Value))) + { + TempObj = Elements[j-1]; + Elements[j-1] = Elements[j]; + Elements[j] = TempObj; + } + } + } +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsRemoveElement + * + * PARAMETERS: ObjDesc - Package object element list + * Index - Index of element to remove + * + * RETURN: None + * + * DESCRIPTION: Remove the requested element of a package and delete it. + * + *****************************************************************************/ + +static void +AcpiNsRemoveElement ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT32 Index) +{ + ACPI_OPERAND_OBJECT **Source; + ACPI_OPERAND_OBJECT **Dest; + UINT32 Count; + UINT32 NewCount; + UINT32 i; + + + ACPI_FUNCTION_NAME (NsRemoveElement); + + + Count = ObjDesc->Package.Count; + NewCount = Count - 1; + + Source = ObjDesc->Package.Elements; + Dest = Source; + + /* Examine all elements of the package object, remove matched index */ + + for (i = 0; i < Count; i++) + { + if (i == Index) + { + AcpiUtRemoveReference (*Source); /* Remove one ref for being in pkg */ + AcpiUtRemoveReference (*Source); + } + else + { + *Dest = *Source; + Dest++; + } + Source++; + } + + /* NULL terminate list and update the package count */ + + *Dest = NULL; + ObjDesc->Package.Count = NewCount; +} |