Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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