Merge tag 'pm-5.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
[sfrench/cifs-2.6.git] / drivers / acpi / acpica / nsrepair2.c
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /******************************************************************************
3  *
4  * Module Name: nsrepair2 - Repair for objects returned by specific
5  *                          predefined methods
6  *
7  * Copyright (C) 2000 - 2019, Intel Corp.
8  *
9  *****************************************************************************/
10
11 #include <acpi/acpi.h>
12 #include "accommon.h"
13 #include "acnamesp.h"
14
15 #define _COMPONENT          ACPI_NAMESPACE
16 ACPI_MODULE_NAME("nsrepair2")
17
18 /*
19  * Information structure and handler for ACPI predefined names that can
20  * be repaired on a per-name basis.
21  */
22 typedef
23 acpi_status (*acpi_repair_function) (struct acpi_evaluate_info * info,
24                                      union acpi_operand_object **
25                                      return_object_ptr);
26
27 typedef struct acpi_repair_info {
28         char name[ACPI_NAMESEG_SIZE];
29         acpi_repair_function repair_function;
30
31 } acpi_repair_info;
32
33 /* Local prototypes */
34
35 static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
36                                                                    acpi_namespace_node
37                                                                    *node);
38
39 static acpi_status
40 acpi_ns_repair_ALR(struct acpi_evaluate_info *info,
41                    union acpi_operand_object **return_object_ptr);
42
43 static acpi_status
44 acpi_ns_repair_CID(struct acpi_evaluate_info *info,
45                    union acpi_operand_object **return_object_ptr);
46
47 static acpi_status
48 acpi_ns_repair_CST(struct acpi_evaluate_info *info,
49                    union acpi_operand_object **return_object_ptr);
50
51 static acpi_status
52 acpi_ns_repair_FDE(struct acpi_evaluate_info *info,
53                    union acpi_operand_object **return_object_ptr);
54
55 static acpi_status
56 acpi_ns_repair_HID(struct acpi_evaluate_info *info,
57                    union acpi_operand_object **return_object_ptr);
58
59 static acpi_status
60 acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
61                    union acpi_operand_object **return_object_ptr);
62
63 static acpi_status
64 acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
65                    union acpi_operand_object **return_object_ptr);
66
67 static acpi_status
68 acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
69                    union acpi_operand_object **return_object_ptr);
70
71 static acpi_status
72 acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
73                           union acpi_operand_object *return_object,
74                           u32 start_index,
75                           u32 expected_count,
76                           u32 sort_index,
77                           u8 sort_direction, char *sort_key_name);
78
79 /* Values for sort_direction above */
80
81 #define ACPI_SORT_ASCENDING     0
82 #define ACPI_SORT_DESCENDING    1
83
84 static void
85 acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index);
86
87 static void
88 acpi_ns_sort_list(union acpi_operand_object **elements,
89                   u32 count, u32 index, u8 sort_direction);
90
91 /*
92  * This table contains the names of the predefined methods for which we can
93  * perform more complex repairs.
94  *
95  * As necessary:
96  *
97  * _ALR: Sort the list ascending by ambient_illuminance
98  * _CID: Strings: uppercase all, remove any leading asterisk
99  * _CST: Sort the list ascending by C state type
100  * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs
101  * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs
102  * _HID: Strings: uppercase all, remove any leading asterisk
103  * _PRT: Fix reversed source_name and source_index
104  * _PSS: Sort the list descending by Power
105  * _TSS: Sort the list descending by Power
106  *
107  * Names that must be packages, but cannot be sorted:
108  *
109  * _BCL: Values are tied to the Package index where they appear, and cannot
110  * be moved or sorted. These index values are used for _BQC and _BCM.
111  * However, we can fix the case where a buffer is returned, by converting
112  * it to a Package of integers.
113  */
114 static const struct acpi_repair_info acpi_ns_repairable_names[] = {
115         {"_ALR", acpi_ns_repair_ALR},
116         {"_CID", acpi_ns_repair_CID},
117         {"_CST", acpi_ns_repair_CST},
118         {"_FDE", acpi_ns_repair_FDE},
119         {"_GTM", acpi_ns_repair_FDE},   /* _GTM has same repair as _FDE */
120         {"_HID", acpi_ns_repair_HID},
121         {"_PRT", acpi_ns_repair_PRT},
122         {"_PSS", acpi_ns_repair_PSS},
123         {"_TSS", acpi_ns_repair_TSS},
124         {{0, 0, 0, 0}, NULL}    /* Table terminator */
125 };
126
127 #define ACPI_FDE_FIELD_COUNT        5
128 #define ACPI_FDE_BYTE_BUFFER_SIZE   5
129 #define ACPI_FDE_DWORD_BUFFER_SIZE  (ACPI_FDE_FIELD_COUNT * sizeof (u32))
130
131 /******************************************************************************
132  *
133  * FUNCTION:    acpi_ns_complex_repairs
134  *
135  * PARAMETERS:  info                - Method execution information block
136  *              node                - Namespace node for the method/object
137  *              validate_status     - Original status of earlier validation
138  *              return_object_ptr   - Pointer to the object returned from the
139  *                                    evaluation of a method or object
140  *
141  * RETURN:      Status. AE_OK if repair was successful. If name is not
142  *              matched, validate_status is returned.
143  *
144  * DESCRIPTION: Attempt to repair/convert a return object of a type that was
145  *              not expected.
146  *
147  *****************************************************************************/
148
149 acpi_status
150 acpi_ns_complex_repairs(struct acpi_evaluate_info *info,
151                         struct acpi_namespace_node *node,
152                         acpi_status validate_status,
153                         union acpi_operand_object **return_object_ptr)
154 {
155         const struct acpi_repair_info *predefined;
156         acpi_status status;
157
158         /* Check if this name is in the list of repairable names */
159
160         predefined = acpi_ns_match_complex_repair(node);
161         if (!predefined) {
162                 return (validate_status);
163         }
164
165         status = predefined->repair_function(info, return_object_ptr);
166         return (status);
167 }
168
169 /******************************************************************************
170  *
171  * FUNCTION:    acpi_ns_match_complex_repair
172  *
173  * PARAMETERS:  node                - Namespace node for the method/object
174  *
175  * RETURN:      Pointer to entry in repair table. NULL indicates not found.
176  *
177  * DESCRIPTION: Check an object name against the repairable object list.
178  *
179  *****************************************************************************/
180
181 static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
182                                                                    acpi_namespace_node
183                                                                    *node)
184 {
185         const struct acpi_repair_info *this_name;
186
187         /* Search info table for a repairable predefined method/object name */
188
189         this_name = acpi_ns_repairable_names;
190         while (this_name->repair_function) {
191                 if (ACPI_COMPARE_NAMESEG(node->name.ascii, this_name->name)) {
192                         return (this_name);
193                 }
194
195                 this_name++;
196         }
197
198         return (NULL);          /* Not found */
199 }
200
201 /******************************************************************************
202  *
203  * FUNCTION:    acpi_ns_repair_ALR
204  *
205  * PARAMETERS:  info                - Method execution information block
206  *              return_object_ptr   - Pointer to the object returned from the
207  *                                    evaluation of a method or object
208  *
209  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
210  *
211  * DESCRIPTION: Repair for the _ALR object. If necessary, sort the object list
212  *              ascending by the ambient illuminance values.
213  *
214  *****************************************************************************/
215
216 static acpi_status
217 acpi_ns_repair_ALR(struct acpi_evaluate_info *info,
218                    union acpi_operand_object **return_object_ptr)
219 {
220         union acpi_operand_object *return_object = *return_object_ptr;
221         acpi_status status;
222
223         status = acpi_ns_check_sorted_list(info, return_object, 0, 2, 1,
224                                            ACPI_SORT_ASCENDING,
225                                            "AmbientIlluminance");
226
227         return (status);
228 }
229
230 /******************************************************************************
231  *
232  * FUNCTION:    acpi_ns_repair_FDE
233  *
234  * PARAMETERS:  info                - Method execution information block
235  *              return_object_ptr   - Pointer to the object returned from the
236  *                                    evaluation of a method or object
237  *
238  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
239  *
240  * DESCRIPTION: Repair for the _FDE and _GTM objects. The expected return
241  *              value is a Buffer of 5 DWORDs. This function repairs a common
242  *              problem where the return value is a Buffer of BYTEs, not
243  *              DWORDs.
244  *
245  *****************************************************************************/
246
247 static acpi_status
248 acpi_ns_repair_FDE(struct acpi_evaluate_info *info,
249                    union acpi_operand_object **return_object_ptr)
250 {
251         union acpi_operand_object *return_object = *return_object_ptr;
252         union acpi_operand_object *buffer_object;
253         u8 *byte_buffer;
254         u32 *dword_buffer;
255         u32 i;
256
257         ACPI_FUNCTION_NAME(ns_repair_FDE);
258
259         switch (return_object->common.type) {
260         case ACPI_TYPE_BUFFER:
261
262                 /* This is the expected type. Length should be (at least) 5 DWORDs */
263
264                 if (return_object->buffer.length >= ACPI_FDE_DWORD_BUFFER_SIZE) {
265                         return (AE_OK);
266                 }
267
268                 /* We can only repair if we have exactly 5 BYTEs */
269
270                 if (return_object->buffer.length != ACPI_FDE_BYTE_BUFFER_SIZE) {
271                         ACPI_WARN_PREDEFINED((AE_INFO,
272                                               info->full_pathname,
273                                               info->node_flags,
274                                               "Incorrect return buffer length %u, expected %u",
275                                               return_object->buffer.length,
276                                               ACPI_FDE_DWORD_BUFFER_SIZE));
277
278                         return (AE_AML_OPERAND_TYPE);
279                 }
280
281                 /* Create the new (larger) buffer object */
282
283                 buffer_object =
284                     acpi_ut_create_buffer_object(ACPI_FDE_DWORD_BUFFER_SIZE);
285                 if (!buffer_object) {
286                         return (AE_NO_MEMORY);
287                 }
288
289                 /* Expand each byte to a DWORD */
290
291                 byte_buffer = return_object->buffer.pointer;
292                 dword_buffer = ACPI_CAST_PTR(u32,
293                                              buffer_object->buffer.pointer);
294
295                 for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++) {
296                         *dword_buffer = (u32) *byte_buffer;
297                         dword_buffer++;
298                         byte_buffer++;
299                 }
300
301                 ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
302                                   "%s Expanded Byte Buffer to expected DWord Buffer\n",
303                                   info->full_pathname));
304                 break;
305
306         default:
307
308                 return (AE_AML_OPERAND_TYPE);
309         }
310
311         /* Delete the original return object, return the new buffer object */
312
313         acpi_ut_remove_reference(return_object);
314         *return_object_ptr = buffer_object;
315
316         info->return_flags |= ACPI_OBJECT_REPAIRED;
317         return (AE_OK);
318 }
319
320 /******************************************************************************
321  *
322  * FUNCTION:    acpi_ns_repair_CID
323  *
324  * PARAMETERS:  info                - Method execution information block
325  *              return_object_ptr   - Pointer to the object returned from the
326  *                                    evaluation of a method or object
327  *
328  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
329  *
330  * DESCRIPTION: Repair for the _CID object. If a string, ensure that all
331  *              letters are uppercase and that there is no leading asterisk.
332  *              If a Package, ensure same for all string elements.
333  *
334  *****************************************************************************/
335
336 static acpi_status
337 acpi_ns_repair_CID(struct acpi_evaluate_info *info,
338                    union acpi_operand_object **return_object_ptr)
339 {
340         acpi_status status;
341         union acpi_operand_object *return_object = *return_object_ptr;
342         union acpi_operand_object **element_ptr;
343         union acpi_operand_object *original_element;
344         u16 original_ref_count;
345         u32 i;
346
347         /* Check for _CID as a simple string */
348
349         if (return_object->common.type == ACPI_TYPE_STRING) {
350                 status = acpi_ns_repair_HID(info, return_object_ptr);
351                 return (status);
352         }
353
354         /* Exit if not a Package */
355
356         if (return_object->common.type != ACPI_TYPE_PACKAGE) {
357                 return (AE_OK);
358         }
359
360         /* Examine each element of the _CID package */
361
362         element_ptr = return_object->package.elements;
363         for (i = 0; i < return_object->package.count; i++) {
364                 original_element = *element_ptr;
365                 original_ref_count = original_element->common.reference_count;
366
367                 status = acpi_ns_repair_HID(info, element_ptr);
368                 if (ACPI_FAILURE(status)) {
369                         return (status);
370                 }
371
372                 if (original_element != *element_ptr) {
373
374                         /* Update reference count of new object */
375
376                         (*element_ptr)->common.reference_count =
377                             original_ref_count;
378                 }
379
380                 element_ptr++;
381         }
382
383         return (AE_OK);
384 }
385
386 /******************************************************************************
387  *
388  * FUNCTION:    acpi_ns_repair_CST
389  *
390  * PARAMETERS:  info                - Method execution information block
391  *              return_object_ptr   - Pointer to the object returned from the
392  *                                    evaluation of a method or object
393  *
394  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
395  *
396  * DESCRIPTION: Repair for the _CST object:
397  *              1. Sort the list ascending by C state type
398  *              2. Ensure type cannot be zero
399  *              3. A subpackage count of zero means _CST is meaningless
400  *              4. Count must match the number of C state subpackages
401  *
402  *****************************************************************************/
403
404 static acpi_status
405 acpi_ns_repair_CST(struct acpi_evaluate_info *info,
406                    union acpi_operand_object **return_object_ptr)
407 {
408         union acpi_operand_object *return_object = *return_object_ptr;
409         union acpi_operand_object **outer_elements;
410         u32 outer_element_count;
411         union acpi_operand_object *obj_desc;
412         acpi_status status;
413         u8 removing;
414         u32 i;
415
416         ACPI_FUNCTION_NAME(ns_repair_CST);
417
418         /*
419          * Check if the C-state type values are proportional.
420          */
421         outer_element_count = return_object->package.count - 1;
422         i = 0;
423         while (i < outer_element_count) {
424                 outer_elements = &return_object->package.elements[i + 1];
425                 removing = FALSE;
426
427                 if ((*outer_elements)->package.count == 0) {
428                         ACPI_WARN_PREDEFINED((AE_INFO,
429                                               info->full_pathname,
430                                               info->node_flags,
431                                               "SubPackage[%u] - removing entry due to zero count",
432                                               i));
433                         removing = TRUE;
434                         goto remove_element;
435                 }
436
437                 obj_desc = (*outer_elements)->package.elements[1];      /* Index1 = Type */
438                 if ((u32)obj_desc->integer.value == 0) {
439                         ACPI_WARN_PREDEFINED((AE_INFO,
440                                               info->full_pathname,
441                                               info->node_flags,
442                                               "SubPackage[%u] - removing entry due to invalid Type(0)",
443                                               i));
444                         removing = TRUE;
445                 }
446
447 remove_element:
448                 if (removing) {
449                         acpi_ns_remove_element(return_object, i + 1);
450                         outer_element_count--;
451                 } else {
452                         i++;
453                 }
454         }
455
456         /* Update top-level package count, Type "Integer" checked elsewhere */
457
458         obj_desc = return_object->package.elements[0];
459         obj_desc->integer.value = outer_element_count;
460
461         /*
462          * Entries (subpackages) in the _CST Package must be sorted by the
463          * C-state type, in ascending order.
464          */
465         status = acpi_ns_check_sorted_list(info, return_object, 1, 4, 1,
466                                            ACPI_SORT_ASCENDING, "C-State Type");
467         if (ACPI_FAILURE(status)) {
468                 return (status);
469         }
470
471         return (AE_OK);
472 }
473
474 /******************************************************************************
475  *
476  * FUNCTION:    acpi_ns_repair_HID
477  *
478  * PARAMETERS:  info                - Method execution information block
479  *              return_object_ptr   - Pointer to the object returned from the
480  *                                    evaluation of a method or object
481  *
482  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
483  *
484  * DESCRIPTION: Repair for the _HID object. If a string, ensure that all
485  *              letters are uppercase and that there is no leading asterisk.
486  *
487  *****************************************************************************/
488
489 static acpi_status
490 acpi_ns_repair_HID(struct acpi_evaluate_info *info,
491                    union acpi_operand_object **return_object_ptr)
492 {
493         union acpi_operand_object *return_object = *return_object_ptr;
494         union acpi_operand_object *new_string;
495         char *source;
496         char *dest;
497
498         ACPI_FUNCTION_NAME(ns_repair_HID);
499
500         /* We only care about string _HID objects (not integers) */
501
502         if (return_object->common.type != ACPI_TYPE_STRING) {
503                 return (AE_OK);
504         }
505
506         if (return_object->string.length == 0) {
507                 ACPI_WARN_PREDEFINED((AE_INFO,
508                                       info->full_pathname, info->node_flags,
509                                       "Invalid zero-length _HID or _CID string"));
510
511                 /* Return AE_OK anyway, let driver handle it */
512
513                 info->return_flags |= ACPI_OBJECT_REPAIRED;
514                 return (AE_OK);
515         }
516
517         /* It is simplest to always create a new string object */
518
519         new_string = acpi_ut_create_string_object(return_object->string.length);
520         if (!new_string) {
521                 return (AE_NO_MEMORY);
522         }
523
524         /*
525          * Remove a leading asterisk if present. For some unknown reason, there
526          * are many machines in the field that contains IDs like this.
527          *
528          * Examples: "*PNP0C03", "*ACPI0003"
529          */
530         source = return_object->string.pointer;
531         if (*source == '*') {
532                 source++;
533                 new_string->string.length--;
534
535                 ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
536                                   "%s: Removed invalid leading asterisk\n",
537                                   info->full_pathname));
538         }
539
540         /*
541          * Copy and uppercase the string. From the ACPI 5.0 specification:
542          *
543          * A valid PNP ID must be of the form "AAA####" where A is an uppercase
544          * letter and # is a hex digit. A valid ACPI ID must be of the form
545          * "NNNN####" where N is an uppercase letter or decimal digit, and
546          * # is a hex digit.
547          */
548         for (dest = new_string->string.pointer; *source; dest++, source++) {
549                 *dest = (char)toupper((int)*source);
550         }
551
552         acpi_ut_remove_reference(return_object);
553         *return_object_ptr = new_string;
554         return (AE_OK);
555 }
556
557 /******************************************************************************
558  *
559  * FUNCTION:    acpi_ns_repair_PRT
560  *
561  * PARAMETERS:  info                - Method execution information block
562  *              return_object_ptr   - Pointer to the object returned from the
563  *                                    evaluation of a method or object
564  *
565  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
566  *
567  * DESCRIPTION: Repair for the _PRT object. If necessary, fix reversed
568  *              source_name and source_index field, a common BIOS bug.
569  *
570  *****************************************************************************/
571
572 static acpi_status
573 acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
574                    union acpi_operand_object **return_object_ptr)
575 {
576         union acpi_operand_object *package_object = *return_object_ptr;
577         union acpi_operand_object **top_object_list;
578         union acpi_operand_object **sub_object_list;
579         union acpi_operand_object *obj_desc;
580         union acpi_operand_object *sub_package;
581         u32 element_count;
582         u32 index;
583
584         /* Each element in the _PRT package is a subpackage */
585
586         top_object_list = package_object->package.elements;
587         element_count = package_object->package.count;
588
589         /* Examine each subpackage */
590
591         for (index = 0; index < element_count; index++, top_object_list++) {
592                 sub_package = *top_object_list;
593                 sub_object_list = sub_package->package.elements;
594
595                 /* Check for minimum required element count */
596
597                 if (sub_package->package.count < 4) {
598                         continue;
599                 }
600
601                 /*
602                  * If the BIOS has erroneously reversed the _PRT source_name (index 2)
603                  * and the source_index (index 3), fix it. _PRT is important enough to
604                  * workaround this BIOS error. This also provides compatibility with
605                  * other ACPI implementations.
606                  */
607                 obj_desc = sub_object_list[3];
608                 if (!obj_desc || (obj_desc->common.type != ACPI_TYPE_INTEGER)) {
609                         sub_object_list[3] = sub_object_list[2];
610                         sub_object_list[2] = obj_desc;
611                         info->return_flags |= ACPI_OBJECT_REPAIRED;
612
613                         ACPI_WARN_PREDEFINED((AE_INFO,
614                                               info->full_pathname,
615                                               info->node_flags,
616                                               "PRT[%X]: Fixed reversed SourceName and SourceIndex",
617                                               index));
618                 }
619         }
620
621         return (AE_OK);
622 }
623
624 /******************************************************************************
625  *
626  * FUNCTION:    acpi_ns_repair_PSS
627  *
628  * PARAMETERS:  info                - Method execution information block
629  *              return_object_ptr   - Pointer to the object returned from the
630  *                                    evaluation of a method or object
631  *
632  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
633  *
634  * DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list
635  *              by the CPU frequencies. Check that the power dissipation values
636  *              are all proportional to CPU frequency (i.e., sorting by
637  *              frequency should be the same as sorting by power.)
638  *
639  *****************************************************************************/
640
641 static acpi_status
642 acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
643                    union acpi_operand_object **return_object_ptr)
644 {
645         union acpi_operand_object *return_object = *return_object_ptr;
646         union acpi_operand_object **outer_elements;
647         u32 outer_element_count;
648         union acpi_operand_object **elements;
649         union acpi_operand_object *obj_desc;
650         u32 previous_value;
651         acpi_status status;
652         u32 i;
653
654         /*
655          * Entries (subpackages) in the _PSS Package must be sorted by power
656          * dissipation, in descending order. If it appears that the list is
657          * incorrectly sorted, sort it. We sort by cpu_frequency, since this
658          * should be proportional to the power.
659          */
660         status = acpi_ns_check_sorted_list(info, return_object, 0, 6, 0,
661                                            ACPI_SORT_DESCENDING,
662                                            "CpuFrequency");
663         if (ACPI_FAILURE(status)) {
664                 return (status);
665         }
666
667         /*
668          * We now know the list is correctly sorted by CPU frequency. Check if
669          * the power dissipation values are proportional.
670          */
671         previous_value = ACPI_UINT32_MAX;
672         outer_elements = return_object->package.elements;
673         outer_element_count = return_object->package.count;
674
675         for (i = 0; i < outer_element_count; i++) {
676                 elements = (*outer_elements)->package.elements;
677                 obj_desc = elements[1]; /* Index1 = power_dissipation */
678
679                 if ((u32)obj_desc->integer.value > previous_value) {
680                         ACPI_WARN_PREDEFINED((AE_INFO,
681                                               info->full_pathname,
682                                               info->node_flags,
683                                               "SubPackage[%u,%u] - suspicious power dissipation values",
684                                               i - 1, i));
685                 }
686
687                 previous_value = (u32) obj_desc->integer.value;
688                 outer_elements++;
689         }
690
691         return (AE_OK);
692 }
693
694 /******************************************************************************
695  *
696  * FUNCTION:    acpi_ns_repair_TSS
697  *
698  * PARAMETERS:  info                - Method execution information block
699  *              return_object_ptr   - Pointer to the object returned from the
700  *                                    evaluation of a method or object
701  *
702  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
703  *
704  * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list
705  *              descending by the power dissipation values.
706  *
707  *****************************************************************************/
708
709 static acpi_status
710 acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
711                    union acpi_operand_object **return_object_ptr)
712 {
713         union acpi_operand_object *return_object = *return_object_ptr;
714         acpi_status status;
715         struct acpi_namespace_node *node;
716
717         /*
718          * We can only sort the _TSS return package if there is no _PSS in the
719          * same scope. This is because if _PSS is present, the ACPI specification
720          * dictates that the _TSS Power Dissipation field is to be ignored, and
721          * therefore some BIOSs leave garbage values in the _TSS Power field(s).
722          * In this case, it is best to just return the _TSS package as-is.
723          * (May, 2011)
724          */
725         status = acpi_ns_get_node(info->node, "^_PSS",
726                                   ACPI_NS_NO_UPSEARCH, &node);
727         if (ACPI_SUCCESS(status)) {
728                 return (AE_OK);
729         }
730
731         status = acpi_ns_check_sorted_list(info, return_object, 0, 5, 1,
732                                            ACPI_SORT_DESCENDING,
733                                            "PowerDissipation");
734
735         return (status);
736 }
737
738 /******************************************************************************
739  *
740  * FUNCTION:    acpi_ns_check_sorted_list
741  *
742  * PARAMETERS:  info                - Method execution information block
743  *              return_object       - Pointer to the top-level returned object
744  *              start_index         - Index of the first subpackage
745  *              expected_count      - Minimum length of each subpackage
746  *              sort_index          - Subpackage entry to sort on
747  *              sort_direction      - Ascending or descending
748  *              sort_key_name       - Name of the sort_index field
749  *
750  * RETURN:      Status. AE_OK if the list is valid and is sorted correctly or
751  *              has been repaired by sorting the list.
752  *
753  * DESCRIPTION: Check if the package list is valid and sorted correctly by the
754  *              sort_index. If not, then sort the list.
755  *
756  *****************************************************************************/
757
758 static acpi_status
759 acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
760                           union acpi_operand_object *return_object,
761                           u32 start_index,
762                           u32 expected_count,
763                           u32 sort_index,
764                           u8 sort_direction, char *sort_key_name)
765 {
766         u32 outer_element_count;
767         union acpi_operand_object **outer_elements;
768         union acpi_operand_object **elements;
769         union acpi_operand_object *obj_desc;
770         u32 i;
771         u32 previous_value;
772
773         ACPI_FUNCTION_NAME(ns_check_sorted_list);
774
775         /* The top-level object must be a package */
776
777         if (return_object->common.type != ACPI_TYPE_PACKAGE) {
778                 return (AE_AML_OPERAND_TYPE);
779         }
780
781         /*
782          * NOTE: assumes list of subpackages contains no NULL elements.
783          * Any NULL elements should have been removed by earlier call
784          * to acpi_ns_remove_null_elements.
785          */
786         outer_element_count = return_object->package.count;
787         if (!outer_element_count || start_index >= outer_element_count) {
788                 return (AE_AML_PACKAGE_LIMIT);
789         }
790
791         outer_elements = &return_object->package.elements[start_index];
792         outer_element_count -= start_index;
793
794         previous_value = 0;
795         if (sort_direction == ACPI_SORT_DESCENDING) {
796                 previous_value = ACPI_UINT32_MAX;
797         }
798
799         /* Examine each subpackage */
800
801         for (i = 0; i < outer_element_count; i++) {
802
803                 /* Each element of the top-level package must also be a package */
804
805                 if ((*outer_elements)->common.type != ACPI_TYPE_PACKAGE) {
806                         return (AE_AML_OPERAND_TYPE);
807                 }
808
809                 /* Each subpackage must have the minimum length */
810
811                 if ((*outer_elements)->package.count < expected_count) {
812                         return (AE_AML_PACKAGE_LIMIT);
813                 }
814
815                 elements = (*outer_elements)->package.elements;
816                 obj_desc = elements[sort_index];
817
818                 if (obj_desc->common.type != ACPI_TYPE_INTEGER) {
819                         return (AE_AML_OPERAND_TYPE);
820                 }
821
822                 /*
823                  * The list must be sorted in the specified order. If we detect a
824                  * discrepancy, sort the entire list.
825                  */
826                 if (((sort_direction == ACPI_SORT_ASCENDING) &&
827                      (obj_desc->integer.value < previous_value)) ||
828                     ((sort_direction == ACPI_SORT_DESCENDING) &&
829                      (obj_desc->integer.value > previous_value))) {
830                         acpi_ns_sort_list(&return_object->package.
831                                           elements[start_index],
832                                           outer_element_count, sort_index,
833                                           sort_direction);
834
835                         info->return_flags |= ACPI_OBJECT_REPAIRED;
836
837                         ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
838                                           "%s: Repaired unsorted list - now sorted by %s\n",
839                                           info->full_pathname, sort_key_name));
840                         return (AE_OK);
841                 }
842
843                 previous_value = (u32) obj_desc->integer.value;
844                 outer_elements++;
845         }
846
847         return (AE_OK);
848 }
849
850 /******************************************************************************
851  *
852  * FUNCTION:    acpi_ns_sort_list
853  *
854  * PARAMETERS:  elements            - Package object element list
855  *              count               - Element count for above
856  *              index               - Sort by which package element
857  *              sort_direction      - Ascending or Descending sort
858  *
859  * RETURN:      None
860  *
861  * DESCRIPTION: Sort the objects that are in a package element list.
862  *
863  * NOTE: Assumes that all NULL elements have been removed from the package,
864  *       and that all elements have been verified to be of type Integer.
865  *
866  *****************************************************************************/
867
868 static void
869 acpi_ns_sort_list(union acpi_operand_object **elements,
870                   u32 count, u32 index, u8 sort_direction)
871 {
872         union acpi_operand_object *obj_desc1;
873         union acpi_operand_object *obj_desc2;
874         union acpi_operand_object *temp_obj;
875         u32 i;
876         u32 j;
877
878         /* Simple bubble sort */
879
880         for (i = 1; i < count; i++) {
881                 for (j = (count - 1); j >= i; j--) {
882                         obj_desc1 = elements[j - 1]->package.elements[index];
883                         obj_desc2 = elements[j]->package.elements[index];
884
885                         if (((sort_direction == ACPI_SORT_ASCENDING) &&
886                              (obj_desc1->integer.value >
887                               obj_desc2->integer.value))
888                             || ((sort_direction == ACPI_SORT_DESCENDING)
889                                 && (obj_desc1->integer.value <
890                                     obj_desc2->integer.value))) {
891                                 temp_obj = elements[j - 1];
892                                 elements[j - 1] = elements[j];
893                                 elements[j] = temp_obj;
894                         }
895                 }
896         }
897 }
898
899 /******************************************************************************
900  *
901  * FUNCTION:    acpi_ns_remove_element
902  *
903  * PARAMETERS:  obj_desc            - Package object element list
904  *              index               - Index of element to remove
905  *
906  * RETURN:      None
907  *
908  * DESCRIPTION: Remove the requested element of a package and delete it.
909  *
910  *****************************************************************************/
911
912 static void
913 acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index)
914 {
915         union acpi_operand_object **source;
916         union acpi_operand_object **dest;
917         u32 count;
918         u32 new_count;
919         u32 i;
920
921         ACPI_FUNCTION_NAME(ns_remove_element);
922
923         count = obj_desc->package.count;
924         new_count = count - 1;
925
926         source = obj_desc->package.elements;
927         dest = source;
928
929         /* Examine all elements of the package object, remove matched index */
930
931         for (i = 0; i < count; i++) {
932                 if (i == index) {
933                         acpi_ut_remove_reference(*source);      /* Remove one ref for being in pkg */
934                         acpi_ut_remove_reference(*source);
935                 } else {
936                         *dest = *source;
937                         dest++;
938                 }
939
940                 source++;
941         }
942
943         /* NULL terminate list and update the package count */
944
945         *dest = NULL;
946         obj_desc->package.count = new_count;
947 }