nsrepair2.c revision 306536
1/******************************************************************************
2 *
3 * Module Name: nsrepair2 - Repair for objects returned by specific
4 *                          predefined methods
5 *
6 *****************************************************************************/
7
8/*
9 * Copyright (C) 2000 - 2016, 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
258        ThisName++;
259    }
260
261    return (NULL); /* Not found */
262}
263
264
265/******************************************************************************
266 *
267 * FUNCTION:    AcpiNsRepair_ALR
268 *
269 * PARAMETERS:  Info                - Method execution information block
270 *              ReturnObjectPtr     - Pointer to the object returned from the
271 *                                    evaluation of a method or object
272 *
273 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
274 *
275 * DESCRIPTION: Repair for the _ALR object. If necessary, sort the object list
276 *              ascending by the ambient illuminance values.
277 *
278 *****************************************************************************/
279
280static ACPI_STATUS
281AcpiNsRepair_ALR (
282    ACPI_EVALUATE_INFO      *Info,
283    ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
284{
285    ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
286    ACPI_STATUS             Status;
287
288
289    Status = AcpiNsCheckSortedList (Info, ReturnObject, 0, 2, 1,
290        ACPI_SORT_ASCENDING, "AmbientIlluminance");
291
292    return (Status);
293}
294
295
296/******************************************************************************
297 *
298 * FUNCTION:    AcpiNsRepair_FDE
299 *
300 * PARAMETERS:  Info                - Method execution information block
301 *              ReturnObjectPtr     - Pointer to the object returned from the
302 *                                    evaluation of a method or object
303 *
304 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
305 *
306 * DESCRIPTION: Repair for the _FDE and _GTM objects. The expected return
307 *              value is a Buffer of 5 DWORDs. This function repairs a common
308 *              problem where the return value is a Buffer of BYTEs, not
309 *              DWORDs.
310 *
311 *****************************************************************************/
312
313static ACPI_STATUS
314AcpiNsRepair_FDE (
315    ACPI_EVALUATE_INFO      *Info,
316    ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
317{
318    ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
319    ACPI_OPERAND_OBJECT     *BufferObject;
320    UINT8                   *ByteBuffer;
321    UINT32                  *DwordBuffer;
322    UINT32                  i;
323
324
325    ACPI_FUNCTION_NAME (NsRepair_FDE);
326
327
328    switch (ReturnObject->Common.Type)
329    {
330    case ACPI_TYPE_BUFFER:
331
332        /* This is the expected type. Length should be (at least) 5 DWORDs */
333
334        if (ReturnObject->Buffer.Length >= ACPI_FDE_DWORD_BUFFER_SIZE)
335        {
336            return (AE_OK);
337        }
338
339        /* We can only repair if we have exactly 5 BYTEs */
340
341        if (ReturnObject->Buffer.Length != ACPI_FDE_BYTE_BUFFER_SIZE)
342        {
343            ACPI_WARN_PREDEFINED ((AE_INFO,
344                Info->FullPathname, Info->NodeFlags,
345                "Incorrect return buffer length %u, expected %u",
346                ReturnObject->Buffer.Length, ACPI_FDE_DWORD_BUFFER_SIZE));
347
348            return (AE_AML_OPERAND_TYPE);
349        }
350
351        /* Create the new (larger) buffer object */
352
353        BufferObject = AcpiUtCreateBufferObject (
354            ACPI_FDE_DWORD_BUFFER_SIZE);
355        if (!BufferObject)
356        {
357            return (AE_NO_MEMORY);
358        }
359
360        /* Expand each byte to a DWORD */
361
362        ByteBuffer = ReturnObject->Buffer.Pointer;
363        DwordBuffer = ACPI_CAST_PTR (UINT32,
364            BufferObject->Buffer.Pointer);
365
366        for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++)
367        {
368            *DwordBuffer = (UINT32) *ByteBuffer;
369            DwordBuffer++;
370            ByteBuffer++;
371        }
372
373        ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR,
374            "%s Expanded Byte Buffer to expected DWord Buffer\n",
375            Info->FullPathname));
376        break;
377
378    default:
379
380        return (AE_AML_OPERAND_TYPE);
381    }
382
383    /* Delete the original return object, return the new buffer object */
384
385    AcpiUtRemoveReference (ReturnObject);
386    *ReturnObjectPtr = BufferObject;
387
388    Info->ReturnFlags |= ACPI_OBJECT_REPAIRED;
389    return (AE_OK);
390}
391
392
393/******************************************************************************
394 *
395 * FUNCTION:    AcpiNsRepair_CID
396 *
397 * PARAMETERS:  Info                - Method execution information block
398 *              ReturnObjectPtr     - Pointer to the object returned from the
399 *                                    evaluation of a method or object
400 *
401 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
402 *
403 * DESCRIPTION: Repair for the _CID object. If a string, ensure that all
404 *              letters are uppercase and that there is no leading asterisk.
405 *              If a Package, ensure same for all string elements.
406 *
407 *****************************************************************************/
408
409static ACPI_STATUS
410AcpiNsRepair_CID (
411    ACPI_EVALUATE_INFO      *Info,
412    ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
413{
414    ACPI_STATUS             Status;
415    ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
416    ACPI_OPERAND_OBJECT     **ElementPtr;
417    ACPI_OPERAND_OBJECT     *OriginalElement;
418    UINT16                  OriginalRefCount;
419    UINT32                  i;
420
421
422    /* Check for _CID as a simple string */
423
424    if (ReturnObject->Common.Type == ACPI_TYPE_STRING)
425    {
426        Status = AcpiNsRepair_HID (Info, ReturnObjectPtr);
427        return (Status);
428    }
429
430    /* Exit if not a Package */
431
432    if (ReturnObject->Common.Type != ACPI_TYPE_PACKAGE)
433    {
434        return (AE_OK);
435    }
436
437    /* Examine each element of the _CID package */
438
439    ElementPtr = ReturnObject->Package.Elements;
440    for (i = 0; i < ReturnObject->Package.Count; i++)
441    {
442        OriginalElement = *ElementPtr;
443        OriginalRefCount = OriginalElement->Common.ReferenceCount;
444
445        Status = AcpiNsRepair_HID (Info, ElementPtr);
446        if (ACPI_FAILURE (Status))
447        {
448            return (Status);
449        }
450
451        /* Take care with reference counts */
452
453        if (OriginalElement != *ElementPtr)
454        {
455            /* Element was replaced */
456
457            (*ElementPtr)->Common.ReferenceCount =
458                OriginalRefCount;
459
460            AcpiUtRemoveReference (OriginalElement);
461        }
462
463        ElementPtr++;
464    }
465
466    return (AE_OK);
467}
468
469
470/******************************************************************************
471 *
472 * FUNCTION:    AcpiNsRepair_CST
473 *
474 * PARAMETERS:  Info                - Method execution information block
475 *              ReturnObjectPtr     - Pointer to the object returned from the
476 *                                    evaluation of a method or object
477 *
478 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
479 *
480 * DESCRIPTION: Repair for the _CST object:
481 *              1. Sort the list ascending by C state type
482 *              2. Ensure type cannot be zero
483 *              3. A subpackage count of zero means _CST is meaningless
484 *              4. Count must match the number of C state subpackages
485 *
486 *****************************************************************************/
487
488static ACPI_STATUS
489AcpiNsRepair_CST (
490    ACPI_EVALUATE_INFO      *Info,
491    ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
492{
493    ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
494    ACPI_OPERAND_OBJECT     **OuterElements;
495    UINT32                  OuterElementCount;
496    ACPI_OPERAND_OBJECT     *ObjDesc;
497    ACPI_STATUS             Status;
498    BOOLEAN                 Removing;
499    UINT32                  i;
500
501
502    ACPI_FUNCTION_NAME (NsRepair_CST);
503
504
505    /*
506     * Check if the C-state type values are proportional.
507     */
508    OuterElementCount = ReturnObject->Package.Count - 1;
509    i = 0;
510    while (i < OuterElementCount)
511    {
512        OuterElements = &ReturnObject->Package.Elements[i + 1];
513        Removing = FALSE;
514
515        if ((*OuterElements)->Package.Count == 0)
516        {
517            ACPI_WARN_PREDEFINED ((AE_INFO,
518                Info->FullPathname, Info->NodeFlags,
519                "SubPackage[%u] - removing entry due to zero count", i));
520            Removing = TRUE;
521            goto RemoveElement;
522        }
523
524        ObjDesc = (*OuterElements)->Package.Elements[1]; /* Index1 = Type */
525        if ((UINT32) ObjDesc->Integer.Value == 0)
526        {
527            ACPI_WARN_PREDEFINED ((AE_INFO,
528                Info->FullPathname, Info->NodeFlags,
529                "SubPackage[%u] - removing entry due to invalid Type(0)", i));
530            Removing = TRUE;
531        }
532
533RemoveElement:
534        if (Removing)
535        {
536            AcpiNsRemoveElement (ReturnObject, i + 1);
537            OuterElementCount--;
538        }
539        else
540        {
541            i++;
542        }
543    }
544
545    /* Update top-level package count, Type "Integer" checked elsewhere */
546
547    ObjDesc = ReturnObject->Package.Elements[0];
548    ObjDesc->Integer.Value = OuterElementCount;
549
550    /*
551     * Entries (subpackages) in the _CST Package must be sorted by the
552     * C-state type, in ascending order.
553     */
554    Status = AcpiNsCheckSortedList (Info, ReturnObject, 1, 4, 1,
555        ACPI_SORT_ASCENDING, "C-State Type");
556    if (ACPI_FAILURE (Status))
557    {
558        return (Status);
559    }
560
561    return (AE_OK);
562}
563
564
565/******************************************************************************
566 *
567 * FUNCTION:    AcpiNsRepair_HID
568 *
569 * PARAMETERS:  Info                - Method execution information block
570 *              ReturnObjectPtr     - Pointer to the object returned from the
571 *                                    evaluation of a method or object
572 *
573 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
574 *
575 * DESCRIPTION: Repair for the _HID object. If a string, ensure that all
576 *              letters are uppercase and that there is no leading asterisk.
577 *
578 *****************************************************************************/
579
580static ACPI_STATUS
581AcpiNsRepair_HID (
582    ACPI_EVALUATE_INFO      *Info,
583    ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
584{
585    ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
586    ACPI_OPERAND_OBJECT     *NewString;
587    char                    *Source;
588    char                    *Dest;
589
590
591    ACPI_FUNCTION_NAME (NsRepair_HID);
592
593
594    /* We only care about string _HID objects (not integers) */
595
596    if (ReturnObject->Common.Type != ACPI_TYPE_STRING)
597    {
598        return (AE_OK);
599    }
600
601    if (ReturnObject->String.Length == 0)
602    {
603        ACPI_WARN_PREDEFINED ((AE_INFO,
604            Info->FullPathname, Info->NodeFlags,
605            "Invalid zero-length _HID or _CID string"));
606
607        /* Return AE_OK anyway, let driver handle it */
608
609        Info->ReturnFlags |= ACPI_OBJECT_REPAIRED;
610        return (AE_OK);
611    }
612
613    /* It is simplest to always create a new string object */
614
615    NewString = AcpiUtCreateStringObject (ReturnObject->String.Length);
616    if (!NewString)
617    {
618        return (AE_NO_MEMORY);
619    }
620
621    /*
622     * Remove a leading asterisk if present. For some unknown reason, there
623     * are many machines in the field that contains IDs like this.
624     *
625     * Examples: "*PNP0C03", "*ACPI0003"
626     */
627    Source = ReturnObject->String.Pointer;
628    if (*Source == '*')
629    {
630        Source++;
631        NewString->String.Length--;
632
633        ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR,
634            "%s: Removed invalid leading asterisk\n", Info->FullPathname));
635    }
636
637    /*
638     * Copy and uppercase the string. From the ACPI 5.0 specification:
639     *
640     * A valid PNP ID must be of the form "AAA####" where A is an uppercase
641     * letter and # is a hex digit. A valid ACPI ID must be of the form
642     * "NNNN####" where N is an uppercase letter or decimal digit, and
643     * # is a hex digit.
644     */
645    for (Dest = NewString->String.Pointer; *Source; Dest++, Source++)
646    {
647        *Dest = (char) toupper ((int) *Source);
648    }
649
650    AcpiUtRemoveReference (ReturnObject);
651    *ReturnObjectPtr = NewString;
652    return (AE_OK);
653}
654
655
656/******************************************************************************
657 *
658 * FUNCTION:    AcpiNsRepair_PRT
659 *
660 * PARAMETERS:  Info                - Method execution information block
661 *              ReturnObjectPtr     - Pointer to the object returned from the
662 *                                    evaluation of a method or object
663 *
664 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
665 *
666 * DESCRIPTION: Repair for the _PRT object. If necessary, fix reversed
667 *              SourceName and SourceIndex field, a common BIOS bug.
668 *
669 *****************************************************************************/
670
671static ACPI_STATUS
672AcpiNsRepair_PRT (
673    ACPI_EVALUATE_INFO      *Info,
674    ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
675{
676    ACPI_OPERAND_OBJECT     *PackageObject = *ReturnObjectPtr;
677    ACPI_OPERAND_OBJECT     **TopObjectList;
678    ACPI_OPERAND_OBJECT     **SubObjectList;
679    ACPI_OPERAND_OBJECT     *ObjDesc;
680    ACPI_OPERAND_OBJECT     *SubPackage;
681    UINT32                  ElementCount;
682    UINT32                  Index;
683
684
685    /* Each element in the _PRT package is a subpackage */
686
687    TopObjectList = PackageObject->Package.Elements;
688    ElementCount = PackageObject->Package.Count;
689
690    /* Examine each subpackage */
691
692    for (Index = 0; Index < ElementCount; Index++, TopObjectList++)
693    {
694        SubPackage = *TopObjectList;
695        SubObjectList = SubPackage->Package.Elements;
696
697        /* Check for minimum required element count */
698
699        if (SubPackage->Package.Count < 4)
700        {
701            continue;
702        }
703
704        /*
705         * If the BIOS has erroneously reversed the _PRT SourceName (index 2)
706         * and the SourceIndex (index 3), fix it. _PRT is important enough to
707         * workaround this BIOS error. This also provides compatibility with
708         * other ACPI implementations.
709         */
710        ObjDesc = SubObjectList[3];
711        if (!ObjDesc || (ObjDesc->Common.Type != ACPI_TYPE_INTEGER))
712        {
713            SubObjectList[3] = SubObjectList[2];
714            SubObjectList[2] = ObjDesc;
715            Info->ReturnFlags |= ACPI_OBJECT_REPAIRED;
716
717            ACPI_WARN_PREDEFINED ((AE_INFO,
718                Info->FullPathname, Info->NodeFlags,
719                "PRT[%X]: Fixed reversed SourceName and SourceIndex",
720                Index));
721        }
722    }
723
724    return (AE_OK);
725}
726
727
728/******************************************************************************
729 *
730 * FUNCTION:    AcpiNsRepair_PSS
731 *
732 * PARAMETERS:  Info                - Method execution information block
733 *              ReturnObjectPtr     - Pointer to the object returned from the
734 *                                    evaluation of a method or object
735 *
736 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
737 *
738 * DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list
739 *              by the CPU frequencies. Check that the power dissipation values
740 *              are all proportional to CPU frequency (i.e., sorting by
741 *              frequency should be the same as sorting by power.)
742 *
743 *****************************************************************************/
744
745static ACPI_STATUS
746AcpiNsRepair_PSS (
747    ACPI_EVALUATE_INFO      *Info,
748    ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
749{
750    ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
751    ACPI_OPERAND_OBJECT     **OuterElements;
752    UINT32                  OuterElementCount;
753    ACPI_OPERAND_OBJECT     **Elements;
754    ACPI_OPERAND_OBJECT     *ObjDesc;
755    UINT32                  PreviousValue;
756    ACPI_STATUS             Status;
757    UINT32                  i;
758
759
760    /*
761     * Entries (subpackages) in the _PSS Package must be sorted by power
762     * dissipation, in descending order. If it appears that the list is
763     * incorrectly sorted, sort it. We sort by CpuFrequency, since this
764     * should be proportional to the power.
765     */
766    Status = AcpiNsCheckSortedList (Info, ReturnObject, 0, 6, 0,
767        ACPI_SORT_DESCENDING, "CpuFrequency");
768    if (ACPI_FAILURE (Status))
769    {
770        return (Status);
771    }
772
773    /*
774     * We now know the list is correctly sorted by CPU frequency. Check if
775     * the power dissipation values are proportional.
776     */
777    PreviousValue = ACPI_UINT32_MAX;
778    OuterElements = ReturnObject->Package.Elements;
779    OuterElementCount = ReturnObject->Package.Count;
780
781    for (i = 0; i < OuterElementCount; i++)
782    {
783        Elements = (*OuterElements)->Package.Elements;
784        ObjDesc = Elements[1]; /* Index1 = PowerDissipation */
785
786        if ((UINT32) ObjDesc->Integer.Value > PreviousValue)
787        {
788            ACPI_WARN_PREDEFINED ((AE_INFO,
789                Info->FullPathname, Info->NodeFlags,
790                "SubPackage[%u,%u] - suspicious power dissipation values",
791                i-1, i));
792        }
793
794        PreviousValue = (UINT32) ObjDesc->Integer.Value;
795        OuterElements++;
796    }
797
798    return (AE_OK);
799}
800
801
802/******************************************************************************
803 *
804 * FUNCTION:    AcpiNsRepair_TSS
805 *
806 * PARAMETERS:  Info                - Method execution information block
807 *              ReturnObjectPtr     - Pointer to the object returned from the
808 *                                    evaluation of a method or object
809 *
810 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
811 *
812 * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list
813 *              descending by the power dissipation values.
814 *
815 *****************************************************************************/
816
817static ACPI_STATUS
818AcpiNsRepair_TSS (
819    ACPI_EVALUATE_INFO      *Info,
820    ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
821{
822    ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
823    ACPI_STATUS             Status;
824    ACPI_NAMESPACE_NODE     *Node;
825
826
827    /*
828     * We can only sort the _TSS return package if there is no _PSS in the
829     * same scope. This is because if _PSS is present, the ACPI specification
830     * dictates that the _TSS Power Dissipation field is to be ignored, and
831     * therefore some BIOSs leave garbage values in the _TSS Power field(s).
832     * In this case, it is best to just return the _TSS package as-is.
833     * (May, 2011)
834     */
835    Status = AcpiNsGetNode (Info->Node, "^_PSS",
836        ACPI_NS_NO_UPSEARCH, &Node);
837    if (ACPI_SUCCESS (Status))
838    {
839        return (AE_OK);
840    }
841
842    Status = AcpiNsCheckSortedList (Info, ReturnObject, 0, 5, 1,
843        ACPI_SORT_DESCENDING, "PowerDissipation");
844
845    return (Status);
846}
847
848
849/******************************************************************************
850 *
851 * FUNCTION:    AcpiNsCheckSortedList
852 *
853 * PARAMETERS:  Info                - Method execution information block
854 *              ReturnObject        - Pointer to the top-level returned object
855 *              StartIndex          - Index of the first subpackage
856 *              ExpectedCount       - Minimum length of each subpackage
857 *              SortIndex           - Subpackage entry to sort on
858 *              SortDirection       - Ascending or descending
859 *              SortKeyName         - Name of the SortIndex field
860 *
861 * RETURN:      Status. AE_OK if the list is valid and is sorted correctly or
862 *              has been repaired by sorting the list.
863 *
864 * DESCRIPTION: Check if the package list is valid and sorted correctly by the
865 *              SortIndex. If not, then sort the list.
866 *
867 *****************************************************************************/
868
869static ACPI_STATUS
870AcpiNsCheckSortedList (
871    ACPI_EVALUATE_INFO      *Info,
872    ACPI_OPERAND_OBJECT     *ReturnObject,
873    UINT32                  StartIndex,
874    UINT32                  ExpectedCount,
875    UINT32                  SortIndex,
876    UINT8                   SortDirection,
877    char                    *SortKeyName)
878{
879    UINT32                  OuterElementCount;
880    ACPI_OPERAND_OBJECT     **OuterElements;
881    ACPI_OPERAND_OBJECT     **Elements;
882    ACPI_OPERAND_OBJECT     *ObjDesc;
883    UINT32                  i;
884    UINT32                  PreviousValue;
885
886
887    ACPI_FUNCTION_NAME (NsCheckSortedList);
888
889
890    /* The top-level object must be a package */
891
892    if (ReturnObject->Common.Type != ACPI_TYPE_PACKAGE)
893    {
894        return (AE_AML_OPERAND_TYPE);
895    }
896
897    /*
898     * NOTE: assumes list of subpackages contains no NULL elements.
899     * Any NULL elements should have been removed by earlier call
900     * to AcpiNsRemoveNullElements.
901     */
902    OuterElementCount = ReturnObject->Package.Count;
903    if (!OuterElementCount || StartIndex >= OuterElementCount)
904    {
905        return (AE_AML_PACKAGE_LIMIT);
906    }
907
908    OuterElements = &ReturnObject->Package.Elements[StartIndex];
909    OuterElementCount -= StartIndex;
910
911    PreviousValue = 0;
912    if (SortDirection == ACPI_SORT_DESCENDING)
913    {
914        PreviousValue = ACPI_UINT32_MAX;
915    }
916
917    /* Examine each subpackage */
918
919    for (i = 0; i < OuterElementCount; i++)
920    {
921        /* Each element of the top-level package must also be a package */
922
923        if ((*OuterElements)->Common.Type != ACPI_TYPE_PACKAGE)
924        {
925            return (AE_AML_OPERAND_TYPE);
926        }
927
928        /* Each subpackage must have the minimum length */
929
930        if ((*OuterElements)->Package.Count < ExpectedCount)
931        {
932            return (AE_AML_PACKAGE_LIMIT);
933        }
934
935        Elements = (*OuterElements)->Package.Elements;
936        ObjDesc = Elements[SortIndex];
937
938        if (ObjDesc->Common.Type != ACPI_TYPE_INTEGER)
939        {
940            return (AE_AML_OPERAND_TYPE);
941        }
942
943        /*
944         * The list must be sorted in the specified order. If we detect a
945         * discrepancy, sort the entire list.
946         */
947        if (((SortDirection == ACPI_SORT_ASCENDING) &&
948                (ObjDesc->Integer.Value < PreviousValue)) ||
949            ((SortDirection == ACPI_SORT_DESCENDING) &&
950                (ObjDesc->Integer.Value > PreviousValue)))
951        {
952            AcpiNsSortList (&ReturnObject->Package.Elements[StartIndex],
953                OuterElementCount, SortIndex, SortDirection);
954
955            Info->ReturnFlags |= ACPI_OBJECT_REPAIRED;
956
957            ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR,
958                "%s: Repaired unsorted list - now sorted by %s\n",
959                Info->FullPathname, SortKeyName));
960            return (AE_OK);
961        }
962
963        PreviousValue = (UINT32) ObjDesc->Integer.Value;
964        OuterElements++;
965    }
966
967    return (AE_OK);
968}
969
970
971/******************************************************************************
972 *
973 * FUNCTION:    AcpiNsSortList
974 *
975 * PARAMETERS:  Elements            - Package object element list
976 *              Count               - Element count for above
977 *              Index               - Sort by which package element
978 *              SortDirection       - Ascending or Descending sort
979 *
980 * RETURN:      None
981 *
982 * DESCRIPTION: Sort the objects that are in a package element list.
983 *
984 * NOTE: Assumes that all NULL elements have been removed from the package,
985 *       and that all elements have been verified to be of type Integer.
986 *
987 *****************************************************************************/
988
989static void
990AcpiNsSortList (
991    ACPI_OPERAND_OBJECT     **Elements,
992    UINT32                  Count,
993    UINT32                  Index,
994    UINT8                   SortDirection)
995{
996    ACPI_OPERAND_OBJECT     *ObjDesc1;
997    ACPI_OPERAND_OBJECT     *ObjDesc2;
998    ACPI_OPERAND_OBJECT     *TempObj;
999    UINT32                  i;
1000    UINT32                  j;
1001
1002
1003    /* Simple bubble sort */
1004
1005    for (i = 1; i < Count; i++)
1006    {
1007        for (j = (Count - 1); j >= i; j--)
1008        {
1009            ObjDesc1 = Elements[j-1]->Package.Elements[Index];
1010            ObjDesc2 = Elements[j]->Package.Elements[Index];
1011
1012            if (((SortDirection == ACPI_SORT_ASCENDING) &&
1013                    (ObjDesc1->Integer.Value > ObjDesc2->Integer.Value)) ||
1014
1015                ((SortDirection == ACPI_SORT_DESCENDING) &&
1016                    (ObjDesc1->Integer.Value < ObjDesc2->Integer.Value)))
1017            {
1018                TempObj = Elements[j-1];
1019                Elements[j-1] = Elements[j];
1020                Elements[j] = TempObj;
1021            }
1022        }
1023    }
1024}
1025
1026
1027/******************************************************************************
1028 *
1029 * FUNCTION:    AcpiNsRemoveElement
1030 *
1031 * PARAMETERS:  ObjDesc             - Package object element list
1032 *              Index               - Index of element to remove
1033 *
1034 * RETURN:      None
1035 *
1036 * DESCRIPTION: Remove the requested element of a package and delete it.
1037 *
1038 *****************************************************************************/
1039
1040static void
1041AcpiNsRemoveElement (
1042    ACPI_OPERAND_OBJECT     *ObjDesc,
1043    UINT32                  Index)
1044{
1045    ACPI_OPERAND_OBJECT     **Source;
1046    ACPI_OPERAND_OBJECT     **Dest;
1047    UINT32                  Count;
1048    UINT32                  NewCount;
1049    UINT32                  i;
1050
1051
1052    ACPI_FUNCTION_NAME (NsRemoveElement);
1053
1054
1055    Count = ObjDesc->Package.Count;
1056    NewCount = Count - 1;
1057
1058    Source = ObjDesc->Package.Elements;
1059    Dest = Source;
1060
1061    /* Examine all elements of the package object, remove matched index */
1062
1063    for (i = 0; i < Count; i++)
1064    {
1065        if (i == Index)
1066        {
1067            AcpiUtRemoveReference (*Source); /* Remove one ref for being in pkg */
1068            AcpiUtRemoveReference (*Source);
1069        }
1070        else
1071        {
1072            *Dest = *Source;
1073            Dest++;
1074        }
1075
1076        Source++;
1077    }
1078
1079    /* NULL terminate list and update the package count */
1080
1081    *Dest = NULL;
1082    ObjDesc->Package.Count = NewCount;
1083}
1084