Branch data Line data Source code
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 - 2020, 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 * (u32) 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 : 6644 : 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 : 6644 : const struct acpi_repair_info *predefined;
156 : 6644 : acpi_status status;
157 : :
158 : : /* Check if this name is in the list of repairable names */
159 : :
160 : 6644 : predefined = acpi_ns_match_complex_repair(node);
161 [ + + ]: 6644 : if (!predefined) {
162 : : return (validate_status);
163 : : }
164 : :
165 : 1133 : status = predefined->repair_function(info, return_object_ptr);
166 : 1133 : 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 : 6644 : static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
182 : : acpi_namespace_node
183 : : *node)
184 : : {
185 : 6644 : const struct acpi_repair_info *this_name;
186 : :
187 : : /* Search info table for a repairable predefined method/object name */
188 : :
189 : 6644 : this_name = acpi_ns_repairable_names;
190 [ + + ]: 61710 : while (this_name->repair_function) {
191 [ + + ]: 56199 : if (ACPI_COMPARE_NAMESEG(node->name.ascii, this_name->name)) {
192 : 1133 : return (this_name);
193 : : }
194 : :
195 : 55066 : 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 : 0 : acpi_ns_repair_ALR(struct acpi_evaluate_info *info,
218 : : union acpi_operand_object **return_object_ptr)
219 : : {
220 : 0 : union acpi_operand_object *return_object = *return_object_ptr;
221 : 0 : acpi_status status;
222 : :
223 : 0 : status = acpi_ns_check_sorted_list(info, return_object, 0, 2, 1,
224 : : ACPI_SORT_ASCENDING,
225 : : "AmbientIlluminance");
226 : :
227 : 0 : 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 : 0 : acpi_ns_repair_FDE(struct acpi_evaluate_info *info,
249 : : union acpi_operand_object **return_object_ptr)
250 : : {
251 : 0 : union acpi_operand_object *return_object = *return_object_ptr;
252 : 0 : union acpi_operand_object *buffer_object;
253 : 0 : u8 *byte_buffer;
254 : 0 : u32 *dword_buffer;
255 : 0 : u32 i;
256 : :
257 : 0 : ACPI_FUNCTION_NAME(ns_repair_FDE);
258 : :
259 [ # # ]: 0 : switch (return_object->common.type) {
260 : 0 : case ACPI_TYPE_BUFFER:
261 : :
262 : : /* This is the expected type. Length should be (at least) 5 DWORDs */
263 : :
264 [ # # ]: 0 : 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 [ # # ]: 0 : if (return_object->buffer.length != ACPI_FDE_BYTE_BUFFER_SIZE) {
271 : 0 : 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 : 0 : return (AE_AML_OPERAND_TYPE);
279 : : }
280 : :
281 : : /* Create the new (larger) buffer object */
282 : :
283 : 0 : buffer_object =
284 : 0 : acpi_ut_create_buffer_object(ACPI_FDE_DWORD_BUFFER_SIZE);
285 [ # # ]: 0 : if (!buffer_object) {
286 : : return (AE_NO_MEMORY);
287 : : }
288 : :
289 : : /* Expand each byte to a DWORD */
290 : :
291 : 0 : byte_buffer = return_object->buffer.pointer;
292 : 0 : dword_buffer = ACPI_CAST_PTR(u32,
293 : : buffer_object->buffer.pointer);
294 : :
295 [ # # ]: 0 : for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++) {
296 : 0 : *dword_buffer = (u32) *byte_buffer;
297 : 0 : dword_buffer++;
298 : 0 : byte_buffer++;
299 : : }
300 : :
301 : : ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
302 : : "%s Expanded Byte Buffer to expected DWord Buffer\n",
303 : 0 : info->full_pathname));
304 : 0 : 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 : 0 : acpi_ut_remove_reference(return_object);
314 : 0 : *return_object_ptr = buffer_object;
315 : :
316 : 0 : info->return_flags |= ACPI_OBJECT_REPAIRED;
317 : 0 : 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 : 55 : acpi_ns_repair_CID(struct acpi_evaluate_info *info,
338 : : union acpi_operand_object **return_object_ptr)
339 : : {
340 : 55 : acpi_status status;
341 : 55 : union acpi_operand_object *return_object = *return_object_ptr;
342 : 55 : union acpi_operand_object **element_ptr;
343 : 55 : union acpi_operand_object *original_element;
344 : 55 : u16 original_ref_count;
345 : 55 : u32 i;
346 : :
347 : : /* Check for _CID as a simple string */
348 : :
349 [ - + ]: 55 : if (return_object->common.type == ACPI_TYPE_STRING) {
350 : 0 : status = acpi_ns_repair_HID(info, return_object_ptr);
351 : 0 : return (status);
352 : : }
353 : :
354 : : /* Exit if not a Package */
355 : :
356 [ - + ]: 55 : if (return_object->common.type != ACPI_TYPE_PACKAGE) {
357 : : return (AE_OK);
358 : : }
359 : :
360 : : /* Examine each element of the _CID package */
361 : :
362 : 0 : element_ptr = return_object->package.elements;
363 [ # # ]: 0 : for (i = 0; i < return_object->package.count; i++) {
364 : 0 : original_element = *element_ptr;
365 : 0 : original_ref_count = original_element->common.reference_count;
366 : :
367 : 0 : status = acpi_ns_repair_HID(info, element_ptr);
368 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
369 : 0 : return (status);
370 : : }
371 : :
372 [ # # ]: 0 : if (original_element != *element_ptr) {
373 : :
374 : : /* Update reference count of new object */
375 : :
376 : 0 : (*element_ptr)->common.reference_count =
377 : : original_ref_count;
378 : : }
379 : :
380 : 0 : 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 : 0 : acpi_ns_repair_CST(struct acpi_evaluate_info *info,
406 : : union acpi_operand_object **return_object_ptr)
407 : : {
408 : 0 : union acpi_operand_object *return_object = *return_object_ptr;
409 : 0 : union acpi_operand_object **outer_elements;
410 : 0 : u32 outer_element_count;
411 : 0 : union acpi_operand_object *obj_desc;
412 : 0 : acpi_status status;
413 : 0 : u8 removing;
414 : 0 : u32 i;
415 : :
416 : 0 : ACPI_FUNCTION_NAME(ns_repair_CST);
417 : :
418 : : /*
419 : : * Check if the C-state type values are proportional.
420 : : */
421 : 0 : outer_element_count = return_object->package.count - 1;
422 : 0 : i = 0;
423 [ # # ]: 0 : while (i < outer_element_count) {
424 : 0 : outer_elements = &return_object->package.elements[i + 1];
425 : 0 : removing = FALSE;
426 : :
427 [ # # ]: 0 : if ((*outer_elements)->package.count == 0) {
428 : 0 : 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 : 0 : removing = TRUE;
434 : 0 : goto remove_element;
435 : : }
436 : :
437 : 0 : obj_desc = (*outer_elements)->package.elements[1]; /* Index1 = Type */
438 [ # # ]: 0 : if ((u32)obj_desc->integer.value == 0) {
439 : 0 : 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 : 0 : removing = TRUE;
445 : : }
446 : :
447 : 0 : remove_element:
448 : 0 : if (removing) {
449 : 0 : acpi_ns_remove_element(return_object, i + 1);
450 : 0 : outer_element_count--;
451 : : } else {
452 : : i++;
453 : : }
454 : : }
455 : :
456 : : /* Update top-level package count, Type "Integer" checked elsewhere */
457 : :
458 : 0 : obj_desc = return_object->package.elements[0];
459 : 0 : 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 : 0 : status = acpi_ns_check_sorted_list(info, return_object, 1, 4, 1,
466 : : ACPI_SORT_ASCENDING, "C-State Type");
467 : 0 : 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 : 1056 : acpi_ns_repair_HID(struct acpi_evaluate_info *info,
491 : : union acpi_operand_object **return_object_ptr)
492 : : {
493 : 1056 : union acpi_operand_object *return_object = *return_object_ptr;
494 : 1056 : union acpi_operand_object *new_string;
495 : 1056 : char *source;
496 : 1056 : char *dest;
497 : :
498 : 1056 : ACPI_FUNCTION_NAME(ns_repair_HID);
499 : :
500 : : /* We only care about string _HID objects (not integers) */
501 : :
502 [ + + ]: 1056 : if (return_object->common.type != ACPI_TYPE_STRING) {
503 : : return (AE_OK);
504 : : }
505 : :
506 [ - + ]: 220 : if (return_object->string.length == 0) {
507 : 0 : 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 : 0 : info->return_flags |= ACPI_OBJECT_REPAIRED;
514 : 0 : return (AE_OK);
515 : : }
516 : :
517 : : /* It is simplest to always create a new string object */
518 : :
519 : 220 : new_string = acpi_ut_create_string_object(return_object->string.length);
520 [ + - ]: 220 : 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 : 220 : source = return_object->string.pointer;
531 [ - + ]: 220 : if (*source == '*') {
532 : 0 : source++;
533 : 0 : new_string->string.length--;
534 : :
535 : : ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
536 : : "%s: Removed invalid leading asterisk\n",
537 : 220 : 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 [ + + ]: 1870 : for (dest = new_string->string.pointer; *source; dest++, source++) {
549 : 1650 : *dest = (char)toupper((int)*source);
550 : : }
551 : :
552 : 220 : acpi_ut_remove_reference(return_object);
553 : 220 : *return_object_ptr = new_string;
554 : 220 : 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 : 22 : acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
574 : : union acpi_operand_object **return_object_ptr)
575 : : {
576 : 22 : union acpi_operand_object *package_object = *return_object_ptr;
577 : 22 : union acpi_operand_object **top_object_list;
578 : 22 : union acpi_operand_object **sub_object_list;
579 : 22 : union acpi_operand_object *obj_desc;
580 : 22 : union acpi_operand_object *sub_package;
581 : 22 : u32 element_count;
582 : 22 : u32 index;
583 : :
584 : : /* Each element in the _PRT package is a subpackage */
585 : :
586 : 22 : top_object_list = package_object->package.elements;
587 : 22 : element_count = package_object->package.count;
588 : :
589 : : /* Examine each subpackage */
590 : :
591 [ + + ]: 2838 : for (index = 0; index < element_count; index++, top_object_list++) {
592 : 2816 : sub_package = *top_object_list;
593 : 2816 : sub_object_list = sub_package->package.elements;
594 : :
595 : : /* Check for minimum required element count */
596 : :
597 [ - + ]: 2816 : if (sub_package->package.count < 4) {
598 : 0 : 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 : 2816 : obj_desc = sub_object_list[3];
608 [ + - - + ]: 2816 : if (!obj_desc || (obj_desc->common.type != ACPI_TYPE_INTEGER)) {
609 : 0 : sub_object_list[3] = sub_object_list[2];
610 : 0 : sub_object_list[2] = obj_desc;
611 : 0 : info->return_flags |= ACPI_OBJECT_REPAIRED;
612 : :
613 : 0 : 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 : 22 : 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 : 0 : acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
643 : : union acpi_operand_object **return_object_ptr)
644 : : {
645 : 0 : union acpi_operand_object *return_object = *return_object_ptr;
646 : 0 : union acpi_operand_object **outer_elements;
647 : 0 : u32 outer_element_count;
648 : 0 : union acpi_operand_object **elements;
649 : 0 : union acpi_operand_object *obj_desc;
650 : 0 : u32 previous_value;
651 : 0 : acpi_status status;
652 : 0 : 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 : 0 : status = acpi_ns_check_sorted_list(info, return_object, 0, 6, 0,
661 : : ACPI_SORT_DESCENDING,
662 : : "CpuFrequency");
663 [ # # ]: 0 : 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 : 0 : previous_value = ACPI_UINT32_MAX;
672 : 0 : outer_elements = return_object->package.elements;
673 : 0 : outer_element_count = return_object->package.count;
674 : :
675 [ # # ]: 0 : for (i = 0; i < outer_element_count; i++) {
676 : 0 : elements = (*outer_elements)->package.elements;
677 : 0 : obj_desc = elements[1]; /* Index1 = power_dissipation */
678 : :
679 [ # # ]: 0 : if ((u32)obj_desc->integer.value > previous_value) {
680 : 0 : 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 : 0 : previous_value = (u32) obj_desc->integer.value;
688 : 0 : 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 : 0 : acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
711 : : union acpi_operand_object **return_object_ptr)
712 : : {
713 : 0 : union acpi_operand_object *return_object = *return_object_ptr;
714 : 0 : acpi_status status;
715 : 0 : 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 : 0 : status = acpi_ns_get_node(info->node, "^_PSS",
726 : : ACPI_NS_NO_UPSEARCH, &node);
727 [ # # ]: 0 : if (ACPI_SUCCESS(status)) {
728 : : return (AE_OK);
729 : : }
730 : :
731 : 0 : status = acpi_ns_check_sorted_list(info, return_object, 0, 5, 1,
732 : : ACPI_SORT_DESCENDING,
733 : : "PowerDissipation");
734 : :
735 : 0 : 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 : 0 : 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 : 0 : u32 outer_element_count;
767 : 0 : union acpi_operand_object **outer_elements;
768 : 0 : union acpi_operand_object **elements;
769 : 0 : union acpi_operand_object *obj_desc;
770 : 0 : u32 i;
771 : 0 : u32 previous_value;
772 : :
773 : 0 : ACPI_FUNCTION_NAME(ns_check_sorted_list);
774 : :
775 : : /* The top-level object must be a package */
776 : :
777 [ # # ]: 0 : 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 : 0 : outer_element_count = return_object->package.count;
787 [ # # ]: 0 : if (!outer_element_count || start_index >= outer_element_count) {
788 : : return (AE_AML_PACKAGE_LIMIT);
789 : : }
790 : :
791 : 0 : outer_elements = &return_object->package.elements[start_index];
792 : 0 : outer_element_count -= start_index;
793 : :
794 : 0 : previous_value = 0;
795 [ # # ]: 0 : if (sort_direction == ACPI_SORT_DESCENDING) {
796 : 0 : previous_value = ACPI_UINT32_MAX;
797 : : }
798 : :
799 : : /* Examine each subpackage */
800 : :
801 [ # # ]: 0 : for (i = 0; i < outer_element_count; i++) {
802 : :
803 : : /* Each element of the top-level package must also be a package */
804 : :
805 [ # # ]: 0 : 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 [ # # ]: 0 : if ((*outer_elements)->package.count < expected_count) {
812 : : return (AE_AML_PACKAGE_LIMIT);
813 : : }
814 : :
815 : 0 : elements = (*outer_elements)->package.elements;
816 : 0 : obj_desc = elements[sort_index];
817 : :
818 [ # # ]: 0 : 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 [ # # ]: 0 : if (((sort_direction == ACPI_SORT_ASCENDING) &&
827 [ # # # # ]: 0 : (obj_desc->integer.value < previous_value)) ||
828 : 0 : ((sort_direction == ACPI_SORT_DESCENDING) &&
829 [ # # ]: 0 : (obj_desc->integer.value > previous_value))) {
830 : 0 : acpi_ns_sort_list(&return_object->package.
831 : : elements[start_index],
832 : : outer_element_count, sort_index,
833 : : sort_direction);
834 : :
835 : 0 : 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 : 0 : info->full_pathname, sort_key_name));
840 : 0 : return (AE_OK);
841 : : }
842 : :
843 : 0 : previous_value = (u32) obj_desc->integer.value;
844 : 0 : 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 : 0 : acpi_ns_sort_list(union acpi_operand_object **elements,
870 : : u32 count, u32 index, u8 sort_direction)
871 : : {
872 : 0 : union acpi_operand_object *obj_desc1;
873 : 0 : union acpi_operand_object *obj_desc2;
874 : 0 : union acpi_operand_object *temp_obj;
875 : 0 : u32 i;
876 : 0 : u32 j;
877 : :
878 : : /* Simple bubble sort */
879 : :
880 [ # # ]: 0 : for (i = 1; i < count; i++) {
881 [ # # ]: 0 : for (j = (count - 1); j >= i; j--) {
882 : 0 : obj_desc1 = elements[j - 1]->package.elements[index];
883 : 0 : obj_desc2 = elements[j]->package.elements[index];
884 : :
885 [ # # ]: 0 : if (((sort_direction == ACPI_SORT_ASCENDING) &&
886 : 0 : (obj_desc1->integer.value >
887 [ # # ]: 0 : obj_desc2->integer.value))
888 [ # # ]: 0 : || ((sort_direction == ACPI_SORT_DESCENDING)
889 : 0 : && (obj_desc1->integer.value <
890 [ # # ]: 0 : obj_desc2->integer.value))) {
891 : 0 : temp_obj = elements[j - 1];
892 : 0 : elements[j - 1] = elements[j];
893 : 0 : elements[j] = temp_obj;
894 : : }
895 : : }
896 : : }
897 : 0 : }
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 : 0 : acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index)
914 : : {
915 : 0 : union acpi_operand_object **source;
916 : 0 : union acpi_operand_object **dest;
917 : 0 : u32 count;
918 : 0 : u32 new_count;
919 : 0 : u32 i;
920 : :
921 : 0 : ACPI_FUNCTION_NAME(ns_remove_element);
922 : :
923 : 0 : count = obj_desc->package.count;
924 : 0 : new_count = count - 1;
925 : :
926 : 0 : source = obj_desc->package.elements;
927 : 0 : dest = source;
928 : :
929 : : /* Examine all elements of the package object, remove matched index */
930 : :
931 [ # # ]: 0 : for (i = 0; i < count; i++) {
932 [ # # ]: 0 : if (i == index) {
933 : 0 : acpi_ut_remove_reference(*source); /* Remove one ref for being in pkg */
934 : 0 : acpi_ut_remove_reference(*source);
935 : : } else {
936 : 0 : *dest = *source;
937 : 0 : dest++;
938 : : }
939 : :
940 : 0 : source++;
941 : : }
942 : :
943 : : /* NULL terminate list and update the package count */
944 : :
945 : 0 : *dest = NULL;
946 : 0 : obj_desc->package.count = new_count;
947 : 0 : }
|