xref: /openbmc/linux/drivers/acpi/acpica/nsrepair2.c (revision 7dd65feb)
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 #include "acpredef.h"
49 
50 #define _COMPONENT          ACPI_NAMESPACE
51 ACPI_MODULE_NAME("nsrepair2")
52 
53 /*
54  * Information structure and handler for ACPI predefined names that can
55  * be repaired on a per-name basis.
56  */
57 typedef
58 acpi_status(*acpi_repair_function) (struct acpi_predefined_data *data,
59 				    union acpi_operand_object **return_object_ptr);
60 
61 typedef struct acpi_repair_info {
62 	char name[ACPI_NAME_SIZE];
63 	acpi_repair_function repair_function;
64 
65 } acpi_repair_info;
66 
67 /* Local prototypes */
68 
69 static const struct acpi_repair_info *acpi_ns_match_repairable_name(struct
70 								    acpi_namespace_node
71 								    *node);
72 
73 static acpi_status
74 acpi_ns_repair_ALR(struct acpi_predefined_data *data,
75 		   union acpi_operand_object **return_object_ptr);
76 
77 static acpi_status
78 acpi_ns_repair_FDE(struct acpi_predefined_data *data,
79 		   union acpi_operand_object **return_object_ptr);
80 
81 static acpi_status
82 acpi_ns_repair_PSS(struct acpi_predefined_data *data,
83 		   union acpi_operand_object **return_object_ptr);
84 
85 static acpi_status
86 acpi_ns_repair_TSS(struct acpi_predefined_data *data,
87 		   union acpi_operand_object **return_object_ptr);
88 
89 static acpi_status
90 acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
91 			  union acpi_operand_object *return_object,
92 			  u32 expected_count,
93 			  u32 sort_index,
94 			  u8 sort_direction, char *sort_key_name);
95 
96 static acpi_status
97 acpi_ns_sort_list(union acpi_operand_object **elements,
98 		  u32 count, u32 index, u8 sort_direction);
99 
100 /* Values for sort_direction above */
101 
102 #define ACPI_SORT_ASCENDING     0
103 #define ACPI_SORT_DESCENDING    1
104 
105 /*
106  * This table contains the names of the predefined methods for which we can
107  * perform more complex repairs.
108  *
109  * As necessary:
110  *
111  * _ALR: Sort the list ascending by ambient_illuminance
112  * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs
113  * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs
114  * _PSS: Sort the list descending by Power
115  * _TSS: Sort the list descending by Power
116  */
117 static const struct acpi_repair_info acpi_ns_repairable_names[] = {
118 	{"_ALR", acpi_ns_repair_ALR},
119 	{"_FDE", acpi_ns_repair_FDE},
120 	{"_GTM", acpi_ns_repair_FDE},	/* _GTM has same repair as _FDE */
121 	{"_PSS", acpi_ns_repair_PSS},
122 	{"_TSS", acpi_ns_repair_TSS},
123 	{{0, 0, 0, 0}, NULL}	/* Table terminator */
124 };
125 
126 #define ACPI_FDE_FIELD_COUNT        5
127 #define ACPI_FDE_BYTE_BUFFER_SIZE   5
128 #define ACPI_FDE_DWORD_BUFFER_SIZE  (ACPI_FDE_FIELD_COUNT * sizeof (u32))
129 
130 /******************************************************************************
131  *
132  * FUNCTION:    acpi_ns_complex_repairs
133  *
134  * PARAMETERS:  Data                - Pointer to validation data structure
135  *              Node                - Namespace node for the method/object
136  *              validate_status     - Original status of earlier validation
137  *              return_object_ptr   - Pointer to the object returned from the
138  *                                    evaluation of a method or object
139  *
140  * RETURN:      Status. AE_OK if repair was successful. If name is not
141  *              matched, validate_status is returned.
142  *
143  * DESCRIPTION: Attempt to repair/convert a return object of a type that was
144  *              not expected.
145  *
146  *****************************************************************************/
147 
148 acpi_status
149 acpi_ns_complex_repairs(struct acpi_predefined_data *data,
150 			struct acpi_namespace_node *node,
151 			acpi_status validate_status,
152 			union acpi_operand_object **return_object_ptr)
153 {
154 	const struct acpi_repair_info *predefined;
155 	acpi_status status;
156 
157 	/* Check if this name is in the list of repairable names */
158 
159 	predefined = acpi_ns_match_repairable_name(node);
160 	if (!predefined) {
161 		return (validate_status);
162 	}
163 
164 	status = predefined->repair_function(data, return_object_ptr);
165 	return (status);
166 }
167 
168 /******************************************************************************
169  *
170  * FUNCTION:    acpi_ns_match_repairable_name
171  *
172  * PARAMETERS:  Node                - Namespace node for the method/object
173  *
174  * RETURN:      Pointer to entry in repair table. NULL indicates not found.
175  *
176  * DESCRIPTION: Check an object name against the repairable object list.
177  *
178  *****************************************************************************/
179 
180 static const struct acpi_repair_info *acpi_ns_match_repairable_name(struct
181 								    acpi_namespace_node
182 								    *node)
183 {
184 	const struct acpi_repair_info *this_name;
185 
186 	/* Search info table for a repairable predefined method/object name */
187 
188 	this_name = acpi_ns_repairable_names;
189 	while (this_name->repair_function) {
190 		if (ACPI_COMPARE_NAME(node->name.ascii, this_name->name)) {
191 			return (this_name);
192 		}
193 		this_name++;
194 	}
195 
196 	return (NULL);		/* Not found */
197 }
198 
199 /******************************************************************************
200  *
201  * FUNCTION:    acpi_ns_repair_ALR
202  *
203  * PARAMETERS:  Data                - Pointer to validation data structure
204  *              return_object_ptr   - Pointer to the object returned from the
205  *                                    evaluation of a method or object
206  *
207  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
208  *
209  * DESCRIPTION: Repair for the _ALR object. If necessary, sort the object list
210  *              ascending by the ambient illuminance values.
211  *
212  *****************************************************************************/
213 
214 static acpi_status
215 acpi_ns_repair_ALR(struct acpi_predefined_data *data,
216 		   union acpi_operand_object **return_object_ptr)
217 {
218 	union acpi_operand_object *return_object = *return_object_ptr;
219 	acpi_status status;
220 
221 	status = acpi_ns_check_sorted_list(data, return_object, 2, 1,
222 					   ACPI_SORT_ASCENDING,
223 					   "AmbientIlluminance");
224 
225 	return (status);
226 }
227 
228 /******************************************************************************
229  *
230  * FUNCTION:    acpi_ns_repair_FDE
231  *
232  * PARAMETERS:  Data                - Pointer to validation data structure
233  *              return_object_ptr   - Pointer to the object returned from the
234  *                                    evaluation of a method or object
235  *
236  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
237  *
238  * DESCRIPTION: Repair for the _FDE and _GTM objects. The expected return
239  *              value is a Buffer of 5 DWORDs. This function repairs a common
240  *              problem where the return value is a Buffer of BYTEs, not
241  *              DWORDs.
242  *
243  *****************************************************************************/
244 
245 static acpi_status
246 acpi_ns_repair_FDE(struct acpi_predefined_data *data,
247 		   union acpi_operand_object **return_object_ptr)
248 {
249 	union acpi_operand_object *return_object = *return_object_ptr;
250 	union acpi_operand_object *buffer_object;
251 	u8 *byte_buffer;
252 	u32 *dword_buffer;
253 	u32 i;
254 
255 	ACPI_FUNCTION_NAME(ns_repair_FDE);
256 
257 	switch (return_object->common.type) {
258 	case ACPI_TYPE_BUFFER:
259 
260 		/* This is the expected type. Length should be (at least) 5 DWORDs */
261 
262 		if (return_object->buffer.length >= ACPI_FDE_DWORD_BUFFER_SIZE) {
263 			return (AE_OK);
264 		}
265 
266 		/* We can only repair if we have exactly 5 BYTEs */
267 
268 		if (return_object->buffer.length != ACPI_FDE_BYTE_BUFFER_SIZE) {
269 			ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
270 					      data->node_flags,
271 					      "Incorrect return buffer length %u, expected %u",
272 					      return_object->buffer.length,
273 					      ACPI_FDE_DWORD_BUFFER_SIZE));
274 
275 			return (AE_AML_OPERAND_TYPE);
276 		}
277 
278 		/* Create the new (larger) buffer object */
279 
280 		buffer_object =
281 		    acpi_ut_create_buffer_object(ACPI_FDE_DWORD_BUFFER_SIZE);
282 		if (!buffer_object) {
283 			return (AE_NO_MEMORY);
284 		}
285 
286 		/* Expand each byte to a DWORD */
287 
288 		byte_buffer = return_object->buffer.pointer;
289 		dword_buffer =
290 		    ACPI_CAST_PTR(u32, buffer_object->buffer.pointer);
291 
292 		for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++) {
293 			*dword_buffer = (u32) *byte_buffer;
294 			dword_buffer++;
295 			byte_buffer++;
296 		}
297 
298 		ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
299 				  "%s Expanded Byte Buffer to expected DWord Buffer\n",
300 				  data->pathname));
301 		break;
302 
303 	default:
304 		return (AE_AML_OPERAND_TYPE);
305 	}
306 
307 	/* Delete the original return object, return the new buffer object */
308 
309 	acpi_ut_remove_reference(return_object);
310 	*return_object_ptr = buffer_object;
311 
312 	data->flags |= ACPI_OBJECT_REPAIRED;
313 	return (AE_OK);
314 }
315 
316 /******************************************************************************
317  *
318  * FUNCTION:    acpi_ns_repair_TSS
319  *
320  * PARAMETERS:  Data                - Pointer to validation data structure
321  *              return_object_ptr   - Pointer to the object returned from the
322  *                                    evaluation of a method or object
323  *
324  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
325  *
326  * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list
327  *              descending by the power dissipation values.
328  *
329  *****************************************************************************/
330 
331 static acpi_status
332 acpi_ns_repair_TSS(struct acpi_predefined_data *data,
333 		   union acpi_operand_object **return_object_ptr)
334 {
335 	union acpi_operand_object *return_object = *return_object_ptr;
336 	acpi_status status;
337 
338 	status = acpi_ns_check_sorted_list(data, return_object, 5, 1,
339 					   ACPI_SORT_DESCENDING,
340 					   "PowerDissipation");
341 
342 	return (status);
343 }
344 
345 /******************************************************************************
346  *
347  * FUNCTION:    acpi_ns_repair_PSS
348  *
349  * PARAMETERS:  Data                - Pointer to validation data structure
350  *              return_object_ptr   - Pointer to the object returned from the
351  *                                    evaluation of a method or object
352  *
353  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
354  *
355  * DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list
356  *              by the CPU frequencies. Check that the power dissipation values
357  *              are all proportional to CPU frequency (i.e., sorting by
358  *              frequency should be the same as sorting by power.)
359  *
360  *****************************************************************************/
361 
362 static acpi_status
363 acpi_ns_repair_PSS(struct acpi_predefined_data *data,
364 		   union acpi_operand_object **return_object_ptr)
365 {
366 	union acpi_operand_object *return_object = *return_object_ptr;
367 	union acpi_operand_object **outer_elements;
368 	u32 outer_element_count;
369 	union acpi_operand_object **elements;
370 	union acpi_operand_object *obj_desc;
371 	u32 previous_value;
372 	acpi_status status;
373 	u32 i;
374 
375 	/*
376 	 * Entries (sub-packages) in the _PSS Package must be sorted by power
377 	 * dissipation, in descending order. If it appears that the list is
378 	 * incorrectly sorted, sort it. We sort by cpu_frequency, since this
379 	 * should be proportional to the power.
380 	 */
381 	status = acpi_ns_check_sorted_list(data, return_object, 6, 0,
382 					   ACPI_SORT_DESCENDING,
383 					   "CpuFrequency");
384 	if (ACPI_FAILURE(status)) {
385 		return (status);
386 	}
387 
388 	/*
389 	 * We now know the list is correctly sorted by CPU frequency. Check if
390 	 * the power dissipation values are proportional.
391 	 */
392 	previous_value = ACPI_UINT32_MAX;
393 	outer_elements = return_object->package.elements;
394 	outer_element_count = return_object->package.count;
395 
396 	for (i = 0; i < outer_element_count; i++) {
397 		elements = (*outer_elements)->package.elements;
398 		obj_desc = elements[1];	/* Index1 = power_dissipation */
399 
400 		if ((u32) obj_desc->integer.value > previous_value) {
401 			ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
402 					      data->node_flags,
403 					      "SubPackage[%u,%u] - suspicious power dissipation values",
404 					      i - 1, i));
405 		}
406 
407 		previous_value = (u32) obj_desc->integer.value;
408 		outer_elements++;
409 	}
410 
411 	return (AE_OK);
412 }
413 
414 /******************************************************************************
415  *
416  * FUNCTION:    acpi_ns_check_sorted_list
417  *
418  * PARAMETERS:  Data                - Pointer to validation data structure
419  *              return_object       - Pointer to the top-level returned object
420  *              expected_count      - Minimum length of each sub-package
421  *              sort_index          - Sub-package entry to sort on
422  *              sort_direction      - Ascending or descending
423  *              sort_key_name       - Name of the sort_index field
424  *
425  * RETURN:      Status. AE_OK if the list is valid and is sorted correctly or
426  *              has been repaired by sorting the list.
427  *
428  * DESCRIPTION: Check if the package list is valid and sorted correctly by the
429  *              sort_index. If not, then sort the list.
430  *
431  *****************************************************************************/
432 
433 static acpi_status
434 acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
435 			  union acpi_operand_object *return_object,
436 			  u32 expected_count,
437 			  u32 sort_index,
438 			  u8 sort_direction, char *sort_key_name)
439 {
440 	u32 outer_element_count;
441 	union acpi_operand_object **outer_elements;
442 	union acpi_operand_object **elements;
443 	union acpi_operand_object *obj_desc;
444 	u32 i;
445 	u32 previous_value;
446 	acpi_status status;
447 
448 	ACPI_FUNCTION_NAME(ns_check_sorted_list);
449 
450 	/* The top-level object must be a package */
451 
452 	if (return_object->common.type != ACPI_TYPE_PACKAGE) {
453 		return (AE_AML_OPERAND_TYPE);
454 	}
455 
456 	/*
457 	 * NOTE: assumes list of sub-packages contains no NULL elements.
458 	 * Any NULL elements should have been removed by earlier call
459 	 * to acpi_ns_remove_null_elements.
460 	 */
461 	outer_elements = return_object->package.elements;
462 	outer_element_count = return_object->package.count;
463 	if (!outer_element_count) {
464 		return (AE_AML_PACKAGE_LIMIT);
465 	}
466 
467 	previous_value = 0;
468 	if (sort_direction == ACPI_SORT_DESCENDING) {
469 		previous_value = ACPI_UINT32_MAX;
470 	}
471 
472 	/* Examine each subpackage */
473 
474 	for (i = 0; i < outer_element_count; i++) {
475 
476 		/* Each element of the top-level package must also be a package */
477 
478 		if ((*outer_elements)->common.type != ACPI_TYPE_PACKAGE) {
479 			return (AE_AML_OPERAND_TYPE);
480 		}
481 
482 		/* Each sub-package must have the minimum length */
483 
484 		if ((*outer_elements)->package.count < expected_count) {
485 			return (AE_AML_PACKAGE_LIMIT);
486 		}
487 
488 		elements = (*outer_elements)->package.elements;
489 		obj_desc = elements[sort_index];
490 
491 		if (obj_desc->common.type != ACPI_TYPE_INTEGER) {
492 			return (AE_AML_OPERAND_TYPE);
493 		}
494 
495 		/*
496 		 * The list must be sorted in the specified order. If we detect a
497 		 * discrepancy, issue a warning and sort the entire list
498 		 */
499 		if (((sort_direction == ACPI_SORT_ASCENDING) &&
500 		     (obj_desc->integer.value < previous_value)) ||
501 		    ((sort_direction == ACPI_SORT_DESCENDING) &&
502 		     (obj_desc->integer.value > previous_value))) {
503 			status =
504 			    acpi_ns_sort_list(return_object->package.elements,
505 					      outer_element_count, sort_index,
506 					      sort_direction);
507 			if (ACPI_FAILURE(status)) {
508 				return (status);
509 			}
510 
511 			data->flags |= ACPI_OBJECT_REPAIRED;
512 
513 			ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
514 					  "%s: Repaired unsorted list - now sorted by %s\n",
515 					  data->pathname, sort_key_name));
516 			return (AE_OK);
517 		}
518 
519 		previous_value = (u32) obj_desc->integer.value;
520 		outer_elements++;
521 	}
522 
523 	return (AE_OK);
524 }
525 
526 /******************************************************************************
527  *
528  * FUNCTION:    acpi_ns_remove_null_elements
529  *
530  * PARAMETERS:  Data                - Pointer to validation data structure
531  *              package_type        - An acpi_return_package_types value
532  *              obj_desc            - A Package object
533  *
534  * RETURN:      None.
535  *
536  * DESCRIPTION: Remove all NULL package elements from packages that contain
537  *              a variable number of sub-packages.
538  *
539  *****************************************************************************/
540 
541 void
542 acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
543 			     u8 package_type,
544 			     union acpi_operand_object *obj_desc)
545 {
546 	union acpi_operand_object **source;
547 	union acpi_operand_object **dest;
548 	u32 count;
549 	u32 new_count;
550 	u32 i;
551 
552 	ACPI_FUNCTION_NAME(ns_remove_null_elements);
553 
554 	/*
555 	 * PTYPE1 packages contain no subpackages.
556 	 * PTYPE2 packages contain a variable number of sub-packages. We can
557 	 * safely remove all NULL elements from the PTYPE2 packages.
558 	 */
559 	switch (package_type) {
560 	case ACPI_PTYPE1_FIXED:
561 	case ACPI_PTYPE1_VAR:
562 	case ACPI_PTYPE1_OPTION:
563 		return;
564 
565 	case ACPI_PTYPE2:
566 	case ACPI_PTYPE2_COUNT:
567 	case ACPI_PTYPE2_PKG_COUNT:
568 	case ACPI_PTYPE2_FIXED:
569 	case ACPI_PTYPE2_MIN:
570 	case ACPI_PTYPE2_REV_FIXED:
571 		break;
572 
573 	default:
574 		return;
575 	}
576 
577 	count = obj_desc->package.count;
578 	new_count = count;
579 
580 	source = obj_desc->package.elements;
581 	dest = source;
582 
583 	/* Examine all elements of the package object, remove nulls */
584 
585 	for (i = 0; i < count; i++) {
586 		if (!*source) {
587 			new_count--;
588 		} else {
589 			*dest = *source;
590 			dest++;
591 		}
592 		source++;
593 	}
594 
595 	/* Update parent package if any null elements were removed */
596 
597 	if (new_count < count) {
598 		ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
599 				  "%s: Found and removed %u NULL elements\n",
600 				  data->pathname, (count - new_count)));
601 
602 		/* NULL terminate list and update the package count */
603 
604 		*dest = NULL;
605 		obj_desc->package.count = new_count;
606 	}
607 }
608 
609 /******************************************************************************
610  *
611  * FUNCTION:    acpi_ns_sort_list
612  *
613  * PARAMETERS:  Elements            - Package object element list
614  *              Count               - Element count for above
615  *              Index               - Sort by which package element
616  *              sort_direction      - Ascending or Descending sort
617  *
618  * RETURN:      Status
619  *
620  * DESCRIPTION: Sort the objects that are in a package element list.
621  *
622  * NOTE: Assumes that all NULL elements have been removed from the package.
623  *
624  *****************************************************************************/
625 
626 static acpi_status
627 acpi_ns_sort_list(union acpi_operand_object **elements,
628 		  u32 count, u32 index, u8 sort_direction)
629 {
630 	union acpi_operand_object *obj_desc1;
631 	union acpi_operand_object *obj_desc2;
632 	union acpi_operand_object *temp_obj;
633 	u32 i;
634 	u32 j;
635 
636 	/* Simple bubble sort */
637 
638 	for (i = 1; i < count; i++) {
639 		for (j = (count - 1); j >= i; j--) {
640 			obj_desc1 = elements[j - 1]->package.elements[index];
641 			obj_desc2 = elements[j]->package.elements[index];
642 
643 			if (((sort_direction == ACPI_SORT_ASCENDING) &&
644 			     (obj_desc1->integer.value >
645 			      obj_desc2->integer.value))
646 			    || ((sort_direction == ACPI_SORT_DESCENDING)
647 				&& (obj_desc1->integer.value <
648 				    obj_desc2->integer.value))) {
649 				temp_obj = elements[j - 1];
650 				elements[j - 1] = elements[j];
651 				elements[j] = temp_obj;
652 			}
653 		}
654 	}
655 
656 	return (AE_OK);
657 }
658