nsrepair2.c revision 281075
1/******************************************************************************
2 *
3 * Module Name: nsrepair2 - Repair for objects returned by specific
4 *                          predefined methods
5 *
6 *****************************************************************************/
7
8/*
9 * Copyright (C) 2000 - 2015, 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#include <contrib/dev/acpica/include/acpi.h>
46#include <contrib/dev/acpica/include/accommon.h>
47#include <contrib/dev/acpica/include/acnamesp.h>
48
49#define _COMPONENT          ACPI_NAMESPACE
50        ACPI_MODULE_NAME    ("nsrepair2")
51
52
53/*
54 * Information structure and handler for ACPI predefined names that can
55 * be repaired on a per-name basis.
56 */
57typedef
58ACPI_STATUS (*ACPI_REPAIR_FUNCTION) (
59    ACPI_EVALUATE_INFO      *Info,
60    ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
61
62typedef struct acpi_repair_info
63{
64    char                    Name[ACPI_NAME_SIZE];
65    ACPI_REPAIR_FUNCTION    RepairFunction;
66
67} ACPI_REPAIR_INFO;
68
69
70/* Local prototypes */
71
72static const ACPI_REPAIR_INFO *
73AcpiNsMatchComplexRepair (
74    ACPI_NAMESPACE_NODE     *Node);
75
76static ACPI_STATUS
77AcpiNsRepair_ALR (
78    ACPI_EVALUATE_INFO      *Info,
79    ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
80
81static ACPI_STATUS
82AcpiNsRepair_CID (
83    ACPI_EVALUATE_INFO      *Info,
84    ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
85
86static ACPI_STATUS
87AcpiNsRepair_CST (
88    ACPI_EVALUATE_INFO      *Info,
89    ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
90
91static ACPI_STATUS
92AcpiNsRepair_FDE (
93    ACPI_EVALUATE_INFO      *Info,
94    ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
95
96static ACPI_STATUS
97AcpiNsRepair_HID (
98    ACPI_EVALUATE_INFO      *Info,
99    ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
100
101static ACPI_STATUS
102AcpiNsRepair_PRT (
103    ACPI_EVALUATE_INFO      *Info,
104    ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
105
106static ACPI_STATUS
107AcpiNsRepair_PSS (
108    ACPI_EVALUATE_INFO      *Info,
109    ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
110
111static ACPI_STATUS
112AcpiNsRepair_TSS (
113    ACPI_EVALUATE_INFO      *Info,
114    ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
115
116static ACPI_STATUS
117AcpiNsCheckSortedList (
118    ACPI_EVALUATE_INFO      *Info,
119    ACPI_OPERAND_OBJECT     *ReturnObject,
120    UINT32                  StartIndex,
121    UINT32                  ExpectedCount,
122    UINT32                  SortIndex,
123    UINT8                   SortDirection,
124    char                    *SortKeyName);
125
126/* Values for SortDirection above */
127
128#define ACPI_SORT_ASCENDING     0
129#define ACPI_SORT_DESCENDING    1
130
131static void
132AcpiNsRemoveElement (
133    ACPI_OPERAND_OBJECT     *ObjDesc,
134    UINT32                  Index);
135
136static void
137AcpiNsSortList (
138    ACPI_OPERAND_OBJECT     **Elements,
139    UINT32                  Count,
140    UINT32                  Index,
141    UINT8                   SortDirection);
142
143
144/*
145 * This table contains the names of the predefined methods for which we can
146 * perform more complex repairs.
147 *
148 * As necessary:
149 *
150 * _ALR: Sort the list ascending by AmbientIlluminance
151 * _CID: Strings: uppercase all, remove any leading asterisk
152 * _CST: Sort the list ascending by C state type
153 * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs
154 * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs
155 * _HID: Strings: uppercase all, remove any leading asterisk
156 * _PRT: Fix reversed SourceName and SourceIndex
157 * _PSS: Sort the list descending by Power
158 * _TSS: Sort the list descending by Power
159 *
160 * Names that must be packages, but cannot be sorted:
161 *
162 * _BCL: Values are tied to the Package index where they appear, and cannot
163 * be moved or sorted. These index values are used for _BQC and _BCM.
164 * However, we can fix the case where a buffer is returned, by converting
165 * it to a Package of integers.
166 */
167static const ACPI_REPAIR_INFO       AcpiNsRepairableNames[] =
168{
169    {"_ALR", AcpiNsRepair_ALR},
170    {"_CID", AcpiNsRepair_CID},
171    {"_CST", AcpiNsRepair_CST},
172    {"_FDE", AcpiNsRepair_FDE},
173    {"_GTM", AcpiNsRepair_FDE},     /* _GTM has same repair as _FDE */
174    {"_HID", AcpiNsRepair_HID},
175    {"_PRT", AcpiNsRepair_PRT},
176    {"_PSS", AcpiNsRepair_PSS},
177    {"_TSS", AcpiNsRepair_TSS},
178    {{0,0,0,0}, NULL}               /* Table terminator */
179};
180
181
182#define ACPI_FDE_FIELD_COUNT        5
183#define ACPI_FDE_BYTE_BUFFER_SIZE   5
184#define ACPI_FDE_DWORD_BUFFER_SIZE  (ACPI_FDE_FIELD_COUNT * sizeof (UINT32))
185
186
187/******************************************************************************
188 *
189 * FUNCTION:    AcpiNsComplexRepairs
190 *
191 * PARAMETERS:  Info                - Method execution information block
192 *              Node                - Namespace node for the method/object
193 *              ValidateStatus      - Original status of earlier validation
194 *              ReturnObjectPtr     - Pointer to the object returned from the
195 *                                    evaluation of a method or object
196 *
197 * RETURN:      Status. AE_OK if repair was successful. If name is not
198 *              matched, ValidateStatus is returned.
199 *
200 * DESCRIPTION: Attempt to repair/convert a return object of a type that was
201 *              not expected.
202 *
203 *****************************************************************************/
204
205ACPI_STATUS
206AcpiNsComplexRepairs (
207    ACPI_EVALUATE_INFO      *Info,
208    ACPI_NAMESPACE_NODE     *Node,
209    ACPI_STATUS             ValidateStatus,
210    ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
211{
212    const ACPI_REPAIR_INFO  *Predefined;
213    ACPI_STATUS             Status;
214
215
216    /* Check if this name is in the list of repairable names */
217
218    Predefined = AcpiNsMatchComplexRepair (Node);
219    if (!Predefined)
220    {
221        return (ValidateStatus);
222    }
223
224    Status = Predefined->RepairFunction (Info, ReturnObjectPtr);
225    return (Status);
226}
227
228
229/******************************************************************************
230 *
231 * FUNCTION:    AcpiNsMatchComplexRepair
232 *
233 * PARAMETERS:  Node                - Namespace node for the method/object
234 *
235 * RETURN:      Pointer to entry in repair table. NULL indicates not found.
236 *
237 * DESCRIPTION: Check an object name against the repairable object list.
238 *
239 *****************************************************************************/
240
241static const ACPI_REPAIR_INFO *
242AcpiNsMatchComplexRepair (
243    ACPI_NAMESPACE_NODE     *Node)
244{
245    const ACPI_REPAIR_INFO  *ThisName;
246
247
248    /* Search info table for a repairable predefined method/object name */
249
250    ThisName = AcpiNsRepairableNames;
251    while (ThisName->RepairFunction)
252    {
253        if (ACPI_COMPARE_NAME (Node->Name.Ascii, ThisName->Name))
254        {
255            return (ThisName);
256        }
257        ThisName++;
258    }
259
260    return (NULL); /* Not found */
261}
262
263
264/******************************************************************************
265 *
266 * FUNCTION:    AcpiNsRepair_ALR
267 *
268 * PARAMETERS:  Info                - Method execution information block
269 *              ReturnObjectPtr     - Pointer to the object returned from the
270 *                                    evaluation of a method or object
271 *
272 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
273 *
274 * DESCRIPTION: Repair for the _ALR object. If necessary, sort the object list
275 *              ascending by the ambient illuminance values.
276 *
277 *****************************************************************************/
278
279static ACPI_STATUS
280AcpiNsRepair_ALR (
281    ACPI_EVALUATE_INFO      *Info,
282    ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
283{
284    ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
285    ACPI_STATUS             Status;
286
287
288    Status = AcpiNsCheckSortedList (Info, ReturnObject, 0, 2, 1,
289                ACPI_SORT_ASCENDING, "AmbientIlluminance");
290
291    return (Status);
292}
293
294
295/******************************************************************************
296 *
297 * FUNCTION:    AcpiNsRepair_FDE
298 *
299 * PARAMETERS:  Info                - Method execution information block
300 *              ReturnObjectPtr     - Pointer to the object returned from the
301 *                                    evaluation of a method or object
302 *
303 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
304 *
305 * DESCRIPTION: Repair for the _FDE and _GTM objects. The expected return
306 *              value is a Buffer of 5 DWORDs. This function repairs a common
307 *              problem where the return value is a Buffer of BYTEs, not
308 *              DWORDs.
309 *
310 *****************************************************************************/
311
312static ACPI_STATUS
313AcpiNsRepair_FDE (
314    ACPI_EVALUATE_INFO      *Info,
315    ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
316{
317    ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
318    ACPI_OPERAND_OBJECT     *BufferObject;
319    UINT8                   *ByteBuffer;
320    UINT32                  *DwordBuffer;
321    UINT32                  i;
322
323
324    ACPI_FUNCTION_NAME (NsRepair_FDE);
325
326
327    switch (ReturnObject->Common.Type)
328    {
329    case ACPI_TYPE_BUFFER:
330
331        /* This is the expected type. Length should be (at least) 5 DWORDs */
332
333        if (ReturnObject->Buffer.Length >= ACPI_FDE_DWORD_BUFFER_SIZE)
334        {
335            return (AE_OK);
336        }
337
338        /* We can only repair if we have exactly 5 BYTEs */
339
340        if (ReturnObject->Buffer.Length != ACPI_FDE_BYTE_BUFFER_SIZE)
341        {
342            ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags,
343                "Incorrect return buffer length %u, expected %u",
344                ReturnObject->Buffer.Length, ACPI_FDE_DWORD_BUFFER_SIZE));
345
346            return (AE_AML_OPERAND_TYPE);
347        }
348
349        /* Create the new (larger) buffer object */
350
351        BufferObject = AcpiUtCreateBufferObject (ACPI_FDE_DWORD_BUFFER_SIZE);
352        if (!BufferObject)
353        {
354            return (AE_NO_MEMORY);
355        }
356
357        /* Expand each byte to a DWORD */
358
359        ByteBuffer = ReturnObject->Buffer.Pointer;
360        DwordBuffer = ACPI_CAST_PTR (UINT32, BufferObject->Buffer.Pointer);
361
362        for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++)
363        {
364            *DwordBuffer = (UINT32) *ByteBuffer;
365            DwordBuffer++;
366            ByteBuffer++;
367        }
368
369        ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR,
370            "%s Expanded Byte Buffer to expected DWord Buffer\n",
371            Info->FullPathname));
372        break;
373
374    default:
375
376        return (AE_AML_OPERAND_TYPE);
377    }
378
379    /* Delete the original return object, return the new buffer object */
380
381    AcpiUtRemoveReference (ReturnObject);
382    *ReturnObjectPtr = BufferObject;
383
384    Info->ReturnFlags |= ACPI_OBJECT_REPAIRED;
385    return (AE_OK);
386}
387
388
389/******************************************************************************
390 *
391 * FUNCTION:    AcpiNsRepair_CID
392 *
393 * PARAMETERS:  Info                - Method execution information block
394 *              ReturnObjectPtr     - Pointer to the object returned from the
395 *                                    evaluation of a method or object
396 *
397 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
398 *
399 * DESCRIPTION: Repair for the _CID object. If a string, ensure that all
400 *              letters are uppercase and that there is no leading asterisk.
401 *              If a Package, ensure same for all string elements.
402 *
403 *****************************************************************************/
404
405static ACPI_STATUS
406AcpiNsRepair_CID (
407    ACPI_EVALUATE_INFO      *Info,
408    ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
409{
410    ACPI_STATUS             Status;
411    ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
412    ACPI_OPERAND_OBJECT     **ElementPtr;
413    ACPI_OPERAND_OBJECT     *OriginalElement;
414    UINT16                  OriginalRefCount;
415    UINT32                  i;
416
417
418    /* Check for _CID as a simple string */
419
420    if (ReturnObject->Common.Type == ACPI_TYPE_STRING)
421    {
422        Status = AcpiNsRepair_HID (Info, ReturnObjectPtr);
423        return (Status);
424    }
425
426    /* Exit if not a Package */
427
428    if (ReturnObject->Common.Type != ACPI_TYPE_PACKAGE)
429    {
430        return (AE_OK);
431    }
432
433    /* Examine each element of the _CID package */
434
435    ElementPtr = ReturnObject->Package.Elements;
436    for (i = 0; i < ReturnObject->Package.Count; i++)
437    {
438        OriginalElement = *ElementPtr;
439        OriginalRefCount = OriginalElement->Common.ReferenceCount;
440
441        Status = AcpiNsRepair_HID (Info, ElementPtr);
442        if (ACPI_FAILURE (Status))
443        {
444            return (Status);
445        }
446
447        /* Take care with reference counts */
448
449        if (OriginalElement != *ElementPtr)
450        {
451            /* Element was replaced */
452
453            (*ElementPtr)->Common.ReferenceCount =
454                OriginalRefCount;
455
456            AcpiUtRemoveReference (OriginalElement);
457        }
458
459        ElementPtr++;
460    }
461
462    return (AE_OK);
463}
464
465
466/******************************************************************************
467 *
468 * FUNCTION:    AcpiNsRepair_CST
469 *
470 * PARAMETERS:  Info                - Method execution information block
471 *              ReturnObjectPtr     - Pointer to the object returned from the
472 *                                    evaluation of a method or object
473 *
474 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
475 *
476 * DESCRIPTION: Repair for the _CST object:
477 *              1. Sort the list ascending by C state type
478 *              2. Ensure type cannot be zero
479 *              3. A subpackage count of zero means _CST is meaningless
480 *              4. Count must match the number of C state subpackages
481 *
482 *****************************************************************************/
483
484static ACPI_STATUS
485AcpiNsRepair_CST (
486    ACPI_EVALUATE_INFO      *Info,
487    ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
488{
489    ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
490    ACPI_OPERAND_OBJECT     **OuterElements;
491    UINT32                  OuterElementCount;
492    ACPI_OPERAND_OBJECT     *ObjDesc;
493    ACPI_STATUS             Status;
494    BOOLEAN                 Removing;
495    UINT32                  i;
496
497
498    ACPI_FUNCTION_NAME (NsRepair_CST);
499
500
501    /*
502     * Check if the C-state type values are proportional.
503     */
504    OuterElementCount = ReturnObject->Package.Count - 1;
505    i = 0;
506    while (i < OuterElementCount)
507    {
508        OuterElements = &ReturnObject->Package.Elements[i + 1];
509        Removing = FALSE;
510
511        if ((*OuterElements)->Package.Count == 0)
512        {
513            ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags,
514                "SubPackage[%u] - removing entry due to zero count", i));
515            Removing = TRUE;
516            goto RemoveElement;
517        }
518
519        ObjDesc = (*OuterElements)->Package.Elements[1]; /* Index1 = Type */
520        if ((UINT32) ObjDesc->Integer.Value == 0)
521        {
522            ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags,
523                "SubPackage[%u] - removing entry due to invalid Type(0)", i));
524            Removing = TRUE;
525        }
526
527RemoveElement:
528        if (Removing)
529        {
530            AcpiNsRemoveElement (ReturnObject, i + 1);
531            OuterElementCount--;
532        }
533        else
534        {
535            i++;
536        }
537    }
538
539    /* Update top-level package count, Type "Integer" checked elsewhere */
540
541    ObjDesc = ReturnObject->Package.Elements[0];
542    ObjDesc->Integer.Value = OuterElementCount;
543
544    /*
545     * Entries (subpackages) in the _CST Package must be sorted by the
546     * C-state type, in ascending order.
547     */
548    Status = AcpiNsCheckSortedList (Info, ReturnObject, 1, 4, 1,
549                ACPI_SORT_ASCENDING, "C-State Type");
550    if (ACPI_FAILURE (Status))
551    {
552        return (Status);
553    }
554
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
574static ACPI_STATUS
575AcpiNsRepair_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
664static ACPI_STATUS
665AcpiNsRepair_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    ACPI_OPERAND_OBJECT     *SubPackage;
674    UINT32                  ElementCount;
675    UINT32                  Index;
676
677
678    /* Each element in the _PRT package is a subpackage */
679
680    TopObjectList = PackageObject->Package.Elements;
681    ElementCount = PackageObject->Package.Count;
682
683    /* Examine each subpackage */
684
685    for (Index = 0; Index < ElementCount; Index++, TopObjectList++)
686    {
687        SubPackage = *TopObjectList;
688        SubObjectList = SubPackage->Package.Elements;
689
690        /* Check for minimum required element count */
691
692        if (SubPackage->Package.Count < 4)
693        {
694            continue;
695        }
696
697        /*
698         * If the BIOS has erroneously reversed the _PRT SourceName (index 2)
699         * and the SourceIndex (index 3), fix it. _PRT is important enough to
700         * workaround this BIOS error. This also provides compatibility with
701         * other ACPI implementations.
702         */
703        ObjDesc = SubObjectList[3];
704        if (!ObjDesc || (ObjDesc->Common.Type != ACPI_TYPE_INTEGER))
705        {
706            SubObjectList[3] = SubObjectList[2];
707            SubObjectList[2] = ObjDesc;
708            Info->ReturnFlags |= ACPI_OBJECT_REPAIRED;
709
710            ACPI_WARN_PREDEFINED ((AE_INFO,
711                Info->FullPathname, Info->NodeFlags,
712                "PRT[%X]: Fixed reversed SourceName and SourceIndex",
713                Index));
714        }
715    }
716
717    return (AE_OK);
718}
719
720
721/******************************************************************************
722 *
723 * FUNCTION:    AcpiNsRepair_PSS
724 *
725 * PARAMETERS:  Info                - Method execution information block
726 *              ReturnObjectPtr     - Pointer to the object returned from the
727 *                                    evaluation of a method or object
728 *
729 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
730 *
731 * DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list
732 *              by the CPU frequencies. Check that the power dissipation values
733 *              are all proportional to CPU frequency (i.e., sorting by
734 *              frequency should be the same as sorting by power.)
735 *
736 *****************************************************************************/
737
738static ACPI_STATUS
739AcpiNsRepair_PSS (
740    ACPI_EVALUATE_INFO      *Info,
741    ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
742{
743    ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
744    ACPI_OPERAND_OBJECT     **OuterElements;
745    UINT32                  OuterElementCount;
746    ACPI_OPERAND_OBJECT     **Elements;
747    ACPI_OPERAND_OBJECT     *ObjDesc;
748    UINT32                  PreviousValue;
749    ACPI_STATUS             Status;
750    UINT32                  i;
751
752
753    /*
754     * Entries (subpackages) in the _PSS Package must be sorted by power
755     * dissipation, in descending order. If it appears that the list is
756     * incorrectly sorted, sort it. We sort by CpuFrequency, since this
757     * should be proportional to the power.
758     */
759    Status =AcpiNsCheckSortedList (Info, ReturnObject, 0, 6, 0,
760                ACPI_SORT_DESCENDING, "CpuFrequency");
761    if (ACPI_FAILURE (Status))
762    {
763        return (Status);
764    }
765
766    /*
767     * We now know the list is correctly sorted by CPU frequency. Check if
768     * the power dissipation values are proportional.
769     */
770    PreviousValue = ACPI_UINT32_MAX;
771    OuterElements = ReturnObject->Package.Elements;
772    OuterElementCount = ReturnObject->Package.Count;
773
774    for (i = 0; i < OuterElementCount; i++)
775    {
776        Elements = (*OuterElements)->Package.Elements;
777        ObjDesc = Elements[1]; /* Index1 = PowerDissipation */
778
779        if ((UINT32) ObjDesc->Integer.Value > PreviousValue)
780        {
781            ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags,
782                "SubPackage[%u,%u] - suspicious power dissipation values",
783                i-1, i));
784        }
785
786        PreviousValue = (UINT32) ObjDesc->Integer.Value;
787        OuterElements++;
788    }
789
790    return (AE_OK);
791}
792
793
794/******************************************************************************
795 *
796 * FUNCTION:    AcpiNsRepair_TSS
797 *
798 * PARAMETERS:  Info                - Method execution information block
799 *              ReturnObjectPtr     - Pointer to the object returned from the
800 *                                    evaluation of a method or object
801 *
802 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
803 *
804 * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list
805 *              descending by the power dissipation values.
806 *
807 *****************************************************************************/
808
809static ACPI_STATUS
810AcpiNsRepair_TSS (
811    ACPI_EVALUATE_INFO      *Info,
812    ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
813{
814    ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
815    ACPI_STATUS             Status;
816    ACPI_NAMESPACE_NODE     *Node;
817
818
819    /*
820     * We can only sort the _TSS return package if there is no _PSS in the
821     * same scope. This is because if _PSS is present, the ACPI specification
822     * dictates that the _TSS Power Dissipation field is to be ignored, and
823     * therefore some BIOSs leave garbage values in the _TSS Power field(s).
824     * In this case, it is best to just return the _TSS package as-is.
825     * (May, 2011)
826     */
827    Status = AcpiNsGetNode (Info->Node, "^_PSS",
828        ACPI_NS_NO_UPSEARCH, &Node);
829    if (ACPI_SUCCESS (Status))
830    {
831        return (AE_OK);
832    }
833
834    Status = AcpiNsCheckSortedList (Info, ReturnObject, 0, 5, 1,
835                ACPI_SORT_DESCENDING, "PowerDissipation");
836
837    return (Status);
838}
839
840
841/******************************************************************************
842 *
843 * FUNCTION:    AcpiNsCheckSortedList
844 *
845 * PARAMETERS:  Info                - Method execution information block
846 *              ReturnObject        - Pointer to the top-level returned object
847 *              StartIndex          - Index of the first subpackage
848 *              ExpectedCount       - Minimum length of each subpackage
849 *              SortIndex           - Subpackage entry to sort on
850 *              SortDirection       - Ascending or descending
851 *              SortKeyName         - Name of the SortIndex field
852 *
853 * RETURN:      Status. AE_OK if the list is valid and is sorted correctly or
854 *              has been repaired by sorting the list.
855 *
856 * DESCRIPTION: Check if the package list is valid and sorted correctly by the
857 *              SortIndex. If not, then sort the list.
858 *
859 *****************************************************************************/
860
861static ACPI_STATUS
862AcpiNsCheckSortedList (
863    ACPI_EVALUATE_INFO      *Info,
864    ACPI_OPERAND_OBJECT     *ReturnObject,
865    UINT32                  StartIndex,
866    UINT32                  ExpectedCount,
867    UINT32                  SortIndex,
868    UINT8                   SortDirection,
869    char                    *SortKeyName)
870{
871    UINT32                  OuterElementCount;
872    ACPI_OPERAND_OBJECT     **OuterElements;
873    ACPI_OPERAND_OBJECT     **Elements;
874    ACPI_OPERAND_OBJECT     *ObjDesc;
875    UINT32                  i;
876    UINT32                  PreviousValue;
877
878
879    ACPI_FUNCTION_NAME (NsCheckSortedList);
880
881
882    /* The top-level object must be a package */
883
884    if (ReturnObject->Common.Type != ACPI_TYPE_PACKAGE)
885    {
886        return (AE_AML_OPERAND_TYPE);
887    }
888
889    /*
890     * NOTE: assumes list of subpackages contains no NULL elements.
891     * Any NULL elements should have been removed by earlier call
892     * to AcpiNsRemoveNullElements.
893     */
894    OuterElementCount = ReturnObject->Package.Count;
895    if (!OuterElementCount || StartIndex >= OuterElementCount)
896    {
897        return (AE_AML_PACKAGE_LIMIT);
898    }
899
900    OuterElements = &ReturnObject->Package.Elements[StartIndex];
901    OuterElementCount -= StartIndex;
902
903    PreviousValue = 0;
904    if (SortDirection == ACPI_SORT_DESCENDING)
905    {
906        PreviousValue = ACPI_UINT32_MAX;
907    }
908
909    /* Examine each subpackage */
910
911    for (i = 0; i < OuterElementCount; i++)
912    {
913        /* Each element of the top-level package must also be a package */
914
915        if ((*OuterElements)->Common.Type != ACPI_TYPE_PACKAGE)
916        {
917            return (AE_AML_OPERAND_TYPE);
918        }
919
920        /* Each subpackage must have the minimum length */
921
922        if ((*OuterElements)->Package.Count < ExpectedCount)
923        {
924            return (AE_AML_PACKAGE_LIMIT);
925        }
926
927        Elements = (*OuterElements)->Package.Elements;
928        ObjDesc = Elements[SortIndex];
929
930        if (ObjDesc->Common.Type != ACPI_TYPE_INTEGER)
931        {
932            return (AE_AML_OPERAND_TYPE);
933        }
934
935        /*
936         * The list must be sorted in the specified order. If we detect a
937         * discrepancy, sort the entire list.
938         */
939        if (((SortDirection == ACPI_SORT_ASCENDING) &&
940                (ObjDesc->Integer.Value < PreviousValue)) ||
941            ((SortDirection == ACPI_SORT_DESCENDING) &&
942                (ObjDesc->Integer.Value > PreviousValue)))
943        {
944            AcpiNsSortList (&ReturnObject->Package.Elements[StartIndex],
945                OuterElementCount, SortIndex, SortDirection);
946
947            Info->ReturnFlags |= ACPI_OBJECT_REPAIRED;
948
949            ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR,
950                "%s: Repaired unsorted list - now sorted by %s\n",
951                Info->FullPathname, SortKeyName));
952            return (AE_OK);
953        }
954
955        PreviousValue = (UINT32) ObjDesc->Integer.Value;
956        OuterElements++;
957    }
958
959    return (AE_OK);
960}
961
962
963/******************************************************************************
964 *
965 * FUNCTION:    AcpiNsSortList
966 *
967 * PARAMETERS:  Elements            - Package object element list
968 *              Count               - Element count for above
969 *              Index               - Sort by which package element
970 *              SortDirection       - Ascending or Descending sort
971 *
972 * RETURN:      None
973 *
974 * DESCRIPTION: Sort the objects that are in a package element list.
975 *
976 * NOTE: Assumes that all NULL elements have been removed from the package,
977 *       and that all elements have been verified to be of type Integer.
978 *
979 *****************************************************************************/
980
981static void
982AcpiNsSortList (
983    ACPI_OPERAND_OBJECT     **Elements,
984    UINT32                  Count,
985    UINT32                  Index,
986    UINT8                   SortDirection)
987{
988    ACPI_OPERAND_OBJECT     *ObjDesc1;
989    ACPI_OPERAND_OBJECT     *ObjDesc2;
990    ACPI_OPERAND_OBJECT     *TempObj;
991    UINT32                  i;
992    UINT32                  j;
993
994
995    /* Simple bubble sort */
996
997    for (i = 1; i < Count; i++)
998    {
999        for (j = (Count - 1); j >= i; j--)
1000        {
1001            ObjDesc1 = Elements[j-1]->Package.Elements[Index];
1002            ObjDesc2 = Elements[j]->Package.Elements[Index];
1003
1004            if (((SortDirection == ACPI_SORT_ASCENDING) &&
1005                    (ObjDesc1->Integer.Value > ObjDesc2->Integer.Value)) ||
1006
1007                ((SortDirection == ACPI_SORT_DESCENDING) &&
1008                    (ObjDesc1->Integer.Value < ObjDesc2->Integer.Value)))
1009            {
1010                TempObj = Elements[j-1];
1011                Elements[j-1] = Elements[j];
1012                Elements[j] = TempObj;
1013            }
1014        }
1015    }
1016}
1017
1018
1019/******************************************************************************
1020 *
1021 * FUNCTION:    AcpiNsRemoveElement
1022 *
1023 * PARAMETERS:  ObjDesc             - Package object element list
1024 *              Index               - Index of element to remove
1025 *
1026 * RETURN:      None
1027 *
1028 * DESCRIPTION: Remove the requested element of a package and delete it.
1029 *
1030 *****************************************************************************/
1031
1032static void
1033AcpiNsRemoveElement (
1034    ACPI_OPERAND_OBJECT     *ObjDesc,
1035    UINT32                  Index)
1036{
1037    ACPI_OPERAND_OBJECT     **Source;
1038    ACPI_OPERAND_OBJECT     **Dest;
1039    UINT32                  Count;
1040    UINT32                  NewCount;
1041    UINT32                  i;
1042
1043
1044    ACPI_FUNCTION_NAME (NsRemoveElement);
1045
1046
1047    Count = ObjDesc->Package.Count;
1048    NewCount = Count - 1;
1049
1050    Source = ObjDesc->Package.Elements;
1051    Dest = Source;
1052
1053    /* Examine all elements of the package object, remove matched index */
1054
1055    for (i = 0; i < Count; i++)
1056    {
1057        if (i == Index)
1058        {
1059            AcpiUtRemoveReference (*Source); /* Remove one ref for being in pkg */
1060            AcpiUtRemoveReference (*Source);
1061        }
1062        else
1063        {
1064            *Dest = *Source;
1065            Dest++;
1066        }
1067        Source++;
1068    }
1069
1070    /* NULL terminate list and update the package count */
1071
1072    *Dest = NULL;
1073    ObjDesc->Package.Count = NewCount;
1074}
1075