summaryrefslogtreecommitdiffstats
path: root/sys/contrib/dev/acpica/components/namespace/nsrepair2.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/dev/acpica/components/namespace/nsrepair2.c')
-rw-r--r--sys/contrib/dev/acpica/components/namespace/nsrepair2.c1066
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;
+}
OpenPOWER on IntegriCloud