Merge branch 'cache' (early part)
[pandora-kernel.git] / drivers / acpi / acpica / nsrepair2.c
1 /******************************************************************************
2  *
3  * Module Name: nsrepair2 - Repair for objects returned by specific
4  *                          predefined methods
5  *
6  *****************************************************************************/
7
8 /*
9  * Copyright (C) 2000 - 2009, 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 <acpi/acpi.h>
46 #include "accommon.h"
47 #include "acnamesp.h"
48
49 #define _COMPONENT          ACPI_NAMESPACE
50 ACPI_MODULE_NAME("nsrepair2")
51
52 /*
53  * Information structure and handler for ACPI predefined names that can
54  * be repaired on a per-name basis.
55  */
56 typedef
57 acpi_status(*acpi_repair_function) (struct acpi_predefined_data *data,
58                                     union acpi_operand_object **return_object_ptr);
59
60 typedef struct acpi_repair_info {
61         char name[ACPI_NAME_SIZE];
62         acpi_repair_function repair_function;
63
64 } acpi_repair_info;
65
66 /* Local prototypes */
67
68 static const struct acpi_repair_info *acpi_ns_match_repairable_name(struct
69                                                                     acpi_namespace_node
70                                                                     *node);
71
72 static acpi_status
73 acpi_ns_repair_ALR(struct acpi_predefined_data *data,
74                    union acpi_operand_object **return_object_ptr);
75
76 static acpi_status
77 acpi_ns_repair_PSS(struct acpi_predefined_data *data,
78                    union acpi_operand_object **return_object_ptr);
79
80 static acpi_status
81 acpi_ns_repair_TSS(struct acpi_predefined_data *data,
82                    union acpi_operand_object **return_object_ptr);
83
84 static acpi_status
85 acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
86                           union acpi_operand_object *return_object,
87                           u32 expected_count,
88                           u32 sort_index,
89                           u8 sort_direction, char *sort_key_name);
90
91 static acpi_status
92 acpi_ns_remove_null_elements(union acpi_operand_object *package);
93
94 static acpi_status
95 acpi_ns_sort_list(union acpi_operand_object **elements,
96                   u32 count, u32 index, u8 sort_direction);
97
98 /* Values for sort_direction above */
99
100 #define ACPI_SORT_ASCENDING     0
101 #define ACPI_SORT_DESCENDING    1
102
103 /*
104  * This table contains the names of the predefined methods for which we can
105  * perform more complex repairs.
106  *
107  * _ALR: Sort the list ascending by ambient_illuminance if necessary
108  * _PSS: Sort the list descending by Power if necessary
109  * _TSS: Sort the list descending by Power if necessary
110  */
111 static const struct acpi_repair_info acpi_ns_repairable_names[] = {
112         {"_ALR", acpi_ns_repair_ALR},
113         {"_PSS", acpi_ns_repair_PSS},
114         {"_TSS", acpi_ns_repair_TSS},
115         {{0, 0, 0, 0}, NULL}    /* Table terminator */
116 };
117
118 /******************************************************************************
119  *
120  * FUNCTION:    acpi_ns_complex_repairs
121  *
122  * PARAMETERS:  Data                - Pointer to validation data structure
123  *              Node                - Namespace node for the method/object
124  *              validate_status     - Original status of earlier validation
125  *              return_object_ptr   - Pointer to the object returned from the
126  *                                    evaluation of a method or object
127  *
128  * RETURN:      Status. AE_OK if repair was successful. If name is not
129  *              matched, validate_status is returned.
130  *
131  * DESCRIPTION: Attempt to repair/convert a return object of a type that was
132  *              not expected.
133  *
134  *****************************************************************************/
135
136 acpi_status
137 acpi_ns_complex_repairs(struct acpi_predefined_data *data,
138                         struct acpi_namespace_node *node,
139                         acpi_status validate_status,
140                         union acpi_operand_object **return_object_ptr)
141 {
142         const struct acpi_repair_info *predefined;
143         acpi_status status;
144
145         /* Check if this name is in the list of repairable names */
146
147         predefined = acpi_ns_match_repairable_name(node);
148         if (!predefined) {
149                 return (validate_status);
150         }
151
152         status = predefined->repair_function(data, return_object_ptr);
153         return (status);
154 }
155
156 /******************************************************************************
157  *
158  * FUNCTION:    acpi_ns_match_repairable_name
159  *
160  * PARAMETERS:  Node                - Namespace node for the method/object
161  *
162  * RETURN:      Pointer to entry in repair table. NULL indicates not found.
163  *
164  * DESCRIPTION: Check an object name against the repairable object list.
165  *
166  *****************************************************************************/
167
168 static const struct acpi_repair_info *acpi_ns_match_repairable_name(struct
169                                                                     acpi_namespace_node
170                                                                     *node)
171 {
172         const struct acpi_repair_info *this_name;
173
174         /* Search info table for a repairable predefined method/object name */
175
176         this_name = acpi_ns_repairable_names;
177         while (this_name->repair_function) {
178                 if (ACPI_COMPARE_NAME(node->name.ascii, this_name->name)) {
179                         return (this_name);
180                 }
181                 this_name++;
182         }
183
184         return (NULL);          /* Not found */
185 }
186
187 /******************************************************************************
188  *
189  * FUNCTION:    acpi_ns_repair_ALR
190  *
191  * PARAMETERS:  Data                - Pointer to validation data structure
192  *              return_object_ptr   - Pointer to the object returned from the
193  *                                    evaluation of a method or object
194  *
195  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
196  *
197  * DESCRIPTION: Repair for the _ALR object. If necessary, sort the object list
198  *              ascending by the ambient illuminance values.
199  *
200  *****************************************************************************/
201
202 static acpi_status
203 acpi_ns_repair_ALR(struct acpi_predefined_data *data,
204                    union acpi_operand_object **return_object_ptr)
205 {
206         union acpi_operand_object *return_object = *return_object_ptr;
207         acpi_status status;
208
209         status = acpi_ns_check_sorted_list(data, return_object, 2, 1,
210                                            ACPI_SORT_ASCENDING,
211                                            "AmbientIlluminance");
212
213         return (status);
214 }
215
216 /******************************************************************************
217  *
218  * FUNCTION:    acpi_ns_repair_TSS
219  *
220  * PARAMETERS:  Data                - Pointer to validation data structure
221  *              return_object_ptr   - Pointer to the object returned from the
222  *                                    evaluation of a method or object
223  *
224  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
225  *
226  * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list
227  *              descending by the power dissipation values.
228  *
229  *****************************************************************************/
230
231 static acpi_status
232 acpi_ns_repair_TSS(struct acpi_predefined_data *data,
233                    union acpi_operand_object **return_object_ptr)
234 {
235         union acpi_operand_object *return_object = *return_object_ptr;
236         acpi_status status;
237
238         status = acpi_ns_check_sorted_list(data, return_object, 5, 1,
239                                            ACPI_SORT_DESCENDING,
240                                            "PowerDissipation");
241
242         return (status);
243 }
244
245 /******************************************************************************
246  *
247  * FUNCTION:    acpi_ns_repair_PSS
248  *
249  * PARAMETERS:  Data                - Pointer to validation data structure
250  *              return_object_ptr   - Pointer to the object returned from the
251  *                                    evaluation of a method or object
252  *
253  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
254  *
255  * DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list
256  *              by the CPU frequencies. Check that the power dissipation values
257  *              are all proportional to CPU frequency (i.e., sorting by
258  *              frequency should be the same as sorting by power.)
259  *
260  *****************************************************************************/
261
262 static acpi_status
263 acpi_ns_repair_PSS(struct acpi_predefined_data *data,
264                    union acpi_operand_object **return_object_ptr)
265 {
266         union acpi_operand_object *return_object = *return_object_ptr;
267         union acpi_operand_object **outer_elements;
268         u32 outer_element_count;
269         union acpi_operand_object **elements;
270         union acpi_operand_object *obj_desc;
271         u32 previous_value;
272         acpi_status status;
273         u32 i;
274
275         /*
276          * Entries (sub-packages) in the _PSS Package must be sorted by power
277          * dissipation, in descending order. If it appears that the list is
278          * incorrectly sorted, sort it. We sort by cpu_frequency, since this
279          * should be proportional to the power.
280          */
281         status = acpi_ns_check_sorted_list(data, return_object, 6, 0,
282                                            ACPI_SORT_DESCENDING,
283                                            "CpuFrequency");
284         if (ACPI_FAILURE(status)) {
285                 return (status);
286         }
287
288         /*
289          * We now know the list is correctly sorted by CPU frequency. Check if
290          * the power dissipation values are proportional.
291          */
292         previous_value = ACPI_UINT32_MAX;
293         outer_elements = return_object->package.elements;
294         outer_element_count = return_object->package.count;
295
296         for (i = 0; i < outer_element_count; i++) {
297                 elements = (*outer_elements)->package.elements;
298                 obj_desc = elements[1]; /* Index1 = power_dissipation */
299
300                 if ((u32) obj_desc->integer.value > previous_value) {
301                         ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
302                                               data->node_flags,
303                                               "SubPackage[%u,%u] - suspicious power dissipation values",
304                                               i - 1, i));
305                 }
306
307                 previous_value = (u32) obj_desc->integer.value;
308                 outer_elements++;
309         }
310
311         return (AE_OK);
312 }
313
314 /******************************************************************************
315  *
316  * FUNCTION:    acpi_ns_check_sorted_list
317  *
318  * PARAMETERS:  Data                - Pointer to validation data structure
319  *              return_object       - Pointer to the top-level returned object
320  *              expected_count      - Minimum length of each sub-package
321  *              sort_index          - Sub-package entry to sort on
322  *              sort_direction      - Ascending or descending
323  *              sort_key_name       - Name of the sort_index field
324  *
325  * RETURN:      Status. AE_OK if the list is valid and is sorted correctly or
326  *              has been repaired by sorting the list.
327  *
328  * DESCRIPTION: Check if the package list is valid and sorted correctly by the
329  *              sort_index. If not, then sort the list.
330  *
331  *****************************************************************************/
332
333 static acpi_status
334 acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
335                           union acpi_operand_object *return_object,
336                           u32 expected_count,
337                           u32 sort_index,
338                           u8 sort_direction, char *sort_key_name)
339 {
340         u32 outer_element_count;
341         union acpi_operand_object **outer_elements;
342         union acpi_operand_object **elements;
343         union acpi_operand_object *obj_desc;
344         u32 i;
345         u32 previous_value;
346         acpi_status status;
347
348         /* The top-level object must be a package */
349
350         if (return_object->common.type != ACPI_TYPE_PACKAGE) {
351                 return (AE_AML_OPERAND_TYPE);
352         }
353
354         /*
355          * Detect any NULL package elements and remove them from the
356          * package.
357          *
358          * TBD: We may want to do this for all predefined names that
359          * return a variable-length package of packages.
360          */
361         status = acpi_ns_remove_null_elements(return_object);
362         if (status == AE_NULL_ENTRY) {
363                 ACPI_INFO_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
364                                       "NULL elements removed from package"));
365
366                 /* Exit if package is now zero length */
367
368                 if (!return_object->package.count) {
369                         return (AE_NULL_ENTRY);
370                 }
371         }
372
373         outer_elements = return_object->package.elements;
374         outer_element_count = return_object->package.count;
375         if (!outer_element_count) {
376                 return (AE_AML_PACKAGE_LIMIT);
377         }
378
379         previous_value = 0;
380         if (sort_direction == ACPI_SORT_DESCENDING) {
381                 previous_value = ACPI_UINT32_MAX;
382         }
383
384         /* Examine each subpackage */
385
386         for (i = 0; i < outer_element_count; i++) {
387
388                 /* Each element of the top-level package must also be a package */
389
390                 if ((*outer_elements)->common.type != ACPI_TYPE_PACKAGE) {
391                         return (AE_AML_OPERAND_TYPE);
392                 }
393
394                 /* Each sub-package must have the minimum length */
395
396                 if ((*outer_elements)->package.count < expected_count) {
397                         return (AE_AML_PACKAGE_LIMIT);
398                 }
399
400                 elements = (*outer_elements)->package.elements;
401                 obj_desc = elements[sort_index];
402
403                 if (obj_desc->common.type != ACPI_TYPE_INTEGER) {
404                         return (AE_AML_OPERAND_TYPE);
405                 }
406
407                 /*
408                  * The list must be sorted in the specified order. If we detect a
409                  * discrepancy, issue a warning and sort the entire list
410                  */
411                 if (((sort_direction == ACPI_SORT_ASCENDING) &&
412                      (obj_desc->integer.value < previous_value)) ||
413                     ((sort_direction == ACPI_SORT_DESCENDING) &&
414                      (obj_desc->integer.value > previous_value))) {
415                         status =
416                             acpi_ns_sort_list(return_object->package.elements,
417                                               outer_element_count, sort_index,
418                                               sort_direction);
419                         if (ACPI_FAILURE(status)) {
420                                 return (status);
421                         }
422
423                         data->flags |= ACPI_OBJECT_REPAIRED;
424
425                         ACPI_INFO_PREDEFINED((AE_INFO, data->pathname,
426                                               data->node_flags,
427                                               "Repaired unsorted list - now sorted by %s",
428                                               sort_key_name));
429                         return (AE_OK);
430                 }
431
432                 previous_value = (u32) obj_desc->integer.value;
433                 outer_elements++;
434         }
435
436         return (AE_OK);
437 }
438
439 /******************************************************************************
440  *
441  * FUNCTION:    acpi_ns_remove_null_elements
442  *
443  * PARAMETERS:  obj_desc            - A Package object
444  *
445  * RETURN:      Status. AE_NULL_ENTRY means that one or more elements were
446  *              removed.
447  *
448  * DESCRIPTION: Remove all NULL package elements and update the package count.
449  *
450  *****************************************************************************/
451
452 static acpi_status
453 acpi_ns_remove_null_elements(union acpi_operand_object *obj_desc)
454 {
455         union acpi_operand_object **source;
456         union acpi_operand_object **dest;
457         acpi_status status = AE_OK;
458         u32 count;
459         u32 new_count;
460         u32 i;
461
462         count = obj_desc->package.count;
463         new_count = count;
464
465         source = obj_desc->package.elements;
466         dest = source;
467
468         /* Examine all elements of the package object */
469
470         for (i = 0; i < count; i++) {
471                 if (!*source) {
472                         status = AE_NULL_ENTRY;
473                         new_count--;
474                 } else {
475                         *dest = *source;
476                         dest++;
477                 }
478                 source++;
479         }
480
481         if (status == AE_NULL_ENTRY) {
482
483                 /* NULL terminate list and update the package count */
484
485                 *dest = NULL;
486                 obj_desc->package.count = new_count;
487         }
488
489         return (status);
490 }
491
492 /******************************************************************************
493  *
494  * FUNCTION:    acpi_ns_sort_list
495  *
496  * PARAMETERS:  Elements            - Package object element list
497  *              Count               - Element count for above
498  *              Index               - Sort by which package element
499  *              sort_direction      - Ascending or Descending sort
500  *
501  * RETURN:      Status
502  *
503  * DESCRIPTION: Sort the objects that are in a package element list.
504  *
505  * NOTE: Assumes that all NULL elements have been removed from the package.
506  *
507  *****************************************************************************/
508
509 static acpi_status
510 acpi_ns_sort_list(union acpi_operand_object **elements,
511                   u32 count, u32 index, u8 sort_direction)
512 {
513         union acpi_operand_object *obj_desc1;
514         union acpi_operand_object *obj_desc2;
515         union acpi_operand_object *temp_obj;
516         u32 i;
517         u32 j;
518
519         /* Simple bubble sort */
520
521         for (i = 1; i < count; i++) {
522                 for (j = (count - 1); j >= i; j--) {
523                         obj_desc1 = elements[j - 1]->package.elements[index];
524                         obj_desc2 = elements[j]->package.elements[index];
525
526                         if (((sort_direction == ACPI_SORT_ASCENDING) &&
527                              (obj_desc1->integer.value >
528                               obj_desc2->integer.value))
529                             || ((sort_direction == ACPI_SORT_DESCENDING)
530                                 && (obj_desc1->integer.value <
531                                     obj_desc2->integer.value))) {
532                                 temp_obj = elements[j - 1];
533                                 elements[j - 1] = elements[j];
534                                 elements[j] = temp_obj;
535                         }
536                 }
537         }
538
539         return (AE_OK);
540 }