nsrepair2.c 23.8 KB
Newer Older
1 2 3 4 5 6 7 8
/******************************************************************************
 *
 * Module Name: nsrepair2 - Repair for objects returned by specific
 *                          predefined methods
 *
 *****************************************************************************/

/*
9
 * Copyright (C) 2000 - 2013, Intel Corp.
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer,
 *    without modification.
 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
 *    substantially similar to the "NO WARRANTY" disclaimer below
 *    ("Disclaimer") and any redistribution must be conditioned upon
 *    including a substantially similar Disclaimer requirement for further
 *    binary redistribution.
 * 3. Neither the names of the above-listed copyright holders nor the names
 *    of any contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * Alternatively, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") version 2 as published by the Free
 * Software Foundation.
 *
 * NO WARRANTY
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 */

#include <acpi/acpi.h>
#include "accommon.h"
#include "acnamesp.h"

#define _COMPONENT          ACPI_NAMESPACE
ACPI_MODULE_NAME("nsrepair2")

/*
 * Information structure and handler for ACPI predefined names that can
 * be repaired on a per-name basis.
 */
typedef
57
acpi_status(*acpi_repair_function) (struct acpi_evaluate_info * info,
58 59
				    union acpi_operand_object
				    **return_object_ptr);
60 61 62 63 64 65 66 67 68

typedef struct acpi_repair_info {
	char name[ACPI_NAME_SIZE];
	acpi_repair_function repair_function;

} acpi_repair_info;

/* Local prototypes */

69 70 71
static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
								   acpi_namespace_node
								   *node);
72 73

static acpi_status
74
acpi_ns_repair_ALR(struct acpi_evaluate_info *info,
75 76
		   union acpi_operand_object **return_object_ptr);

77
static acpi_status
78
acpi_ns_repair_CID(struct acpi_evaluate_info *info,
79 80
		   union acpi_operand_object **return_object_ptr);

81
static acpi_status
82
acpi_ns_repair_FDE(struct acpi_evaluate_info *info,
83 84
		   union acpi_operand_object **return_object_ptr);

85
static acpi_status
86
acpi_ns_repair_HID(struct acpi_evaluate_info *info,
87 88
		   union acpi_operand_object **return_object_ptr);

89
static acpi_status
90
acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
91 92 93
		   union acpi_operand_object **return_object_ptr);

static acpi_status
94
acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
95 96 97
		   union acpi_operand_object **return_object_ptr);

static acpi_status
98
acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
99 100 101 102 103
			  union acpi_operand_object *return_object,
			  u32 expected_count,
			  u32 sort_index,
			  u8 sort_direction, char *sort_key_name);

104
static void
105 106 107 108 109 110 111 112 113 114 115 116
acpi_ns_sort_list(union acpi_operand_object **elements,
		  u32 count, u32 index, u8 sort_direction);

/* Values for sort_direction above */

#define ACPI_SORT_ASCENDING     0
#define ACPI_SORT_DESCENDING    1

/*
 * This table contains the names of the predefined methods for which we can
 * perform more complex repairs.
 *
117 118 119
 * As necessary:
 *
 * _ALR: Sort the list ascending by ambient_illuminance
120
 * _CID: Strings: uppercase all, remove any leading asterisk
121 122
 * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs
 * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs
123
 * _HID: Strings: uppercase all, remove any leading asterisk
124 125
 * _PSS: Sort the list descending by Power
 * _TSS: Sort the list descending by Power
126 127 128 129 130 131 132
 *
 * Names that must be packages, but cannot be sorted:
 *
 * _BCL: Values are tied to the Package index where they appear, and cannot
 * be moved or sorted. These index values are used for _BQC and _BCM.
 * However, we can fix the case where a buffer is returned, by converting
 * it to a Package of integers.
133 134 135
 */
static const struct acpi_repair_info acpi_ns_repairable_names[] = {
	{"_ALR", acpi_ns_repair_ALR},
136
	{"_CID", acpi_ns_repair_CID},
137 138
	{"_FDE", acpi_ns_repair_FDE},
	{"_GTM", acpi_ns_repair_FDE},	/* _GTM has same repair as _FDE */
139
	{"_HID", acpi_ns_repair_HID},
140 141 142 143 144
	{"_PSS", acpi_ns_repair_PSS},
	{"_TSS", acpi_ns_repair_TSS},
	{{0, 0, 0, 0}, NULL}	/* Table terminator */
};

145 146 147 148
#define ACPI_FDE_FIELD_COUNT        5
#define ACPI_FDE_BYTE_BUFFER_SIZE   5
#define ACPI_FDE_DWORD_BUFFER_SIZE  (ACPI_FDE_FIELD_COUNT * sizeof (u32))

149 150 151 152
/******************************************************************************
 *
 * FUNCTION:    acpi_ns_complex_repairs
 *
153
 * PARAMETERS:  info                - Method execution information block
154
 *              node                - Namespace node for the method/object
155 156 157 158 159 160 161 162 163 164 165 166 167
 *              validate_status     - Original status of earlier validation
 *              return_object_ptr   - Pointer to the object returned from the
 *                                    evaluation of a method or object
 *
 * RETURN:      Status. AE_OK if repair was successful. If name is not
 *              matched, validate_status is returned.
 *
 * DESCRIPTION: Attempt to repair/convert a return object of a type that was
 *              not expected.
 *
 *****************************************************************************/

acpi_status
168
acpi_ns_complex_repairs(struct acpi_evaluate_info *info,
169 170 171 172 173 174 175 176 177
			struct acpi_namespace_node *node,
			acpi_status validate_status,
			union acpi_operand_object **return_object_ptr)
{
	const struct acpi_repair_info *predefined;
	acpi_status status;

	/* Check if this name is in the list of repairable names */

178
	predefined = acpi_ns_match_complex_repair(node);
179 180 181 182
	if (!predefined) {
		return (validate_status);
	}

183
	status = predefined->repair_function(info, return_object_ptr);
184 185 186 187 188
	return (status);
}

/******************************************************************************
 *
189
 * FUNCTION:    acpi_ns_match_complex_repair
190
 *
191
 * PARAMETERS:  node                - Namespace node for the method/object
192 193 194 195 196 197 198
 *
 * RETURN:      Pointer to entry in repair table. NULL indicates not found.
 *
 * DESCRIPTION: Check an object name against the repairable object list.
 *
 *****************************************************************************/

199 200 201
static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
								   acpi_namespace_node
								   *node)
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
{
	const struct acpi_repair_info *this_name;

	/* Search info table for a repairable predefined method/object name */

	this_name = acpi_ns_repairable_names;
	while (this_name->repair_function) {
		if (ACPI_COMPARE_NAME(node->name.ascii, this_name->name)) {
			return (this_name);
		}
		this_name++;
	}

	return (NULL);		/* Not found */
}

/******************************************************************************
 *
 * FUNCTION:    acpi_ns_repair_ALR
 *
222
 * PARAMETERS:  info                - Method execution information block
223 224 225 226 227 228 229 230 231 232 233
 *              return_object_ptr   - Pointer to the object returned from the
 *                                    evaluation of a method or object
 *
 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 *
 * DESCRIPTION: Repair for the _ALR object. If necessary, sort the object list
 *              ascending by the ambient illuminance values.
 *
 *****************************************************************************/

static acpi_status
234
acpi_ns_repair_ALR(struct acpi_evaluate_info *info,
235 236 237 238 239
		   union acpi_operand_object **return_object_ptr)
{
	union acpi_operand_object *return_object = *return_object_ptr;
	acpi_status status;

240
	status = acpi_ns_check_sorted_list(info, return_object, 2, 1,
241 242 243 244 245 246
					   ACPI_SORT_ASCENDING,
					   "AmbientIlluminance");

	return (status);
}

247 248 249 250
/******************************************************************************
 *
 * FUNCTION:    acpi_ns_repair_FDE
 *
251
 * PARAMETERS:  info                - Method execution information block
252 253 254 255 256 257
 *              return_object_ptr   - Pointer to the object returned from the
 *                                    evaluation of a method or object
 *
 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 *
 * DESCRIPTION: Repair for the _FDE and _GTM objects. The expected return
258 259 260
 *              value is a Buffer of 5 DWORDs. This function repairs a common
 *              problem where the return value is a Buffer of BYTEs, not
 *              DWORDs.
261 262 263 264
 *
 *****************************************************************************/

static acpi_status
265
acpi_ns_repair_FDE(struct acpi_evaluate_info *info,
266 267 268 269 270 271 272 273
		   union acpi_operand_object **return_object_ptr)
{
	union acpi_operand_object *return_object = *return_object_ptr;
	union acpi_operand_object *buffer_object;
	u8 *byte_buffer;
	u32 *dword_buffer;
	u32 i;

274 275
	ACPI_FUNCTION_NAME(ns_repair_FDE);

276 277 278 279 280 281 282 283 284 285 286 287
	switch (return_object->common.type) {
	case ACPI_TYPE_BUFFER:

		/* This is the expected type. Length should be (at least) 5 DWORDs */

		if (return_object->buffer.length >= ACPI_FDE_DWORD_BUFFER_SIZE) {
			return (AE_OK);
		}

		/* We can only repair if we have exactly 5 BYTEs */

		if (return_object->buffer.length != ACPI_FDE_BYTE_BUFFER_SIZE) {
288 289
			ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
					      info->node_flags,
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
					      "Incorrect return buffer length %u, expected %u",
					      return_object->buffer.length,
					      ACPI_FDE_DWORD_BUFFER_SIZE));

			return (AE_AML_OPERAND_TYPE);
		}

		/* Create the new (larger) buffer object */

		buffer_object =
		    acpi_ut_create_buffer_object(ACPI_FDE_DWORD_BUFFER_SIZE);
		if (!buffer_object) {
			return (AE_NO_MEMORY);
		}

		/* Expand each byte to a DWORD */

		byte_buffer = return_object->buffer.pointer;
		dword_buffer =
		    ACPI_CAST_PTR(u32, buffer_object->buffer.pointer);

		for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++) {
			*dword_buffer = (u32) *byte_buffer;
			dword_buffer++;
			byte_buffer++;
		}

317 318
		ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
				  "%s Expanded Byte Buffer to expected DWord Buffer\n",
319
				  info->full_pathname));
320 321 322
		break;

	default:
323

324 325 326 327 328 329 330 331
		return (AE_AML_OPERAND_TYPE);
	}

	/* Delete the original return object, return the new buffer object */

	acpi_ut_remove_reference(return_object);
	*return_object_ptr = buffer_object;

332
	info->return_flags |= ACPI_OBJECT_REPAIRED;
333
	return (AE_OK);
334 335 336 337 338 339
}

/******************************************************************************
 *
 * FUNCTION:    acpi_ns_repair_CID
 *
340
 * PARAMETERS:  info                - Method execution information block
341 342 343 344 345 346 347 348 349 350 351 352
 *              return_object_ptr   - Pointer to the object returned from the
 *                                    evaluation of a method or object
 *
 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 *
 * DESCRIPTION: Repair for the _CID object. If a string, ensure that all
 *              letters are uppercase and that there is no leading asterisk.
 *              If a Package, ensure same for all string elements.
 *
 *****************************************************************************/

static acpi_status
353
acpi_ns_repair_CID(struct acpi_evaluate_info *info,
354 355 356 357 358 359 360 361 362 363 364 365
		   union acpi_operand_object **return_object_ptr)
{
	acpi_status status;
	union acpi_operand_object *return_object = *return_object_ptr;
	union acpi_operand_object **element_ptr;
	union acpi_operand_object *original_element;
	u16 original_ref_count;
	u32 i;

	/* Check for _CID as a simple string */

	if (return_object->common.type == ACPI_TYPE_STRING) {
366
		status = acpi_ns_repair_HID(info, return_object_ptr);
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
		return (status);
	}

	/* Exit if not a Package */

	if (return_object->common.type != ACPI_TYPE_PACKAGE) {
		return (AE_OK);
	}

	/* Examine each element of the _CID package */

	element_ptr = return_object->package.elements;
	for (i = 0; i < return_object->package.count; i++) {
		original_element = *element_ptr;
		original_ref_count = original_element->common.reference_count;

383
		status = acpi_ns_repair_HID(info, element_ptr);
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
		if (ACPI_FAILURE(status)) {
			return (status);
		}

		/* Take care with reference counts */

		if (original_element != *element_ptr) {

			/* Element was replaced */

			(*element_ptr)->common.reference_count =
			    original_ref_count;

			acpi_ut_remove_reference(original_element);
		}

		element_ptr++;
	}

	return (AE_OK);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_ns_repair_HID
 *
410
 * PARAMETERS:  info                - Method execution information block
411 412 413 414 415 416 417 418 419 420 421
 *              return_object_ptr   - Pointer to the object returned from the
 *                                    evaluation of a method or object
 *
 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 *
 * DESCRIPTION: Repair for the _HID object. If a string, ensure that all
 *              letters are uppercase and that there is no leading asterisk.
 *
 *****************************************************************************/

static acpi_status
422
acpi_ns_repair_HID(struct acpi_evaluate_info *info,
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
		   union acpi_operand_object **return_object_ptr)
{
	union acpi_operand_object *return_object = *return_object_ptr;
	union acpi_operand_object *new_string;
	char *source;
	char *dest;

	ACPI_FUNCTION_NAME(ns_repair_HID);

	/* We only care about string _HID objects (not integers) */

	if (return_object->common.type != ACPI_TYPE_STRING) {
		return (AE_OK);
	}

	if (return_object->string.length == 0) {
439 440
		ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
				      info->node_flags,
441 442 443 444
				      "Invalid zero-length _HID or _CID string"));

		/* Return AE_OK anyway, let driver handle it */

445
		info->return_flags |= ACPI_OBJECT_REPAIRED;
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
		return (AE_OK);
	}

	/* It is simplest to always create a new string object */

	new_string = acpi_ut_create_string_object(return_object->string.length);
	if (!new_string) {
		return (AE_NO_MEMORY);
	}

	/*
	 * Remove a leading asterisk if present. For some unknown reason, there
	 * are many machines in the field that contains IDs like this.
	 *
	 * Examples: "*PNP0C03", "*ACPI0003"
	 */
	source = return_object->string.pointer;
	if (*source == '*') {
		source++;
		new_string->string.length--;

		ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
				  "%s: Removed invalid leading asterisk\n",
469
				  info->full_pathname));
470 471 472
	}

	/*
B
Bob Moore 已提交
473
	 * Copy and uppercase the string. From the ACPI 5.0 specification:
474 475 476
	 *
	 * A valid PNP ID must be of the form "AAA####" where A is an uppercase
	 * letter and # is a hex digit. A valid ACPI ID must be of the form
B
Bob Moore 已提交
477 478
	 * "NNNN####" where N is an uppercase letter or decimal digit, and
	 * # is a hex digit.
479 480 481 482 483 484 485 486
	 */
	for (dest = new_string->string.pointer; *source; dest++, source++) {
		*dest = (char)ACPI_TOUPPER(*source);
	}

	acpi_ut_remove_reference(return_object);
	*return_object_ptr = new_string;
	return (AE_OK);
487 488
}

489 490 491 492
/******************************************************************************
 *
 * FUNCTION:    acpi_ns_repair_TSS
 *
493
 * PARAMETERS:  info                - Method execution information block
494 495 496 497 498 499 500 501 502 503 504
 *              return_object_ptr   - Pointer to the object returned from the
 *                                    evaluation of a method or object
 *
 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 *
 * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list
 *              descending by the power dissipation values.
 *
 *****************************************************************************/

static acpi_status
505
acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
506 507 508 509
		   union acpi_operand_object **return_object_ptr)
{
	union acpi_operand_object *return_object = *return_object_ptr;
	acpi_status status;
510 511 512 513 514 515 516 517 518 519
	struct acpi_namespace_node *node;

	/*
	 * We can only sort the _TSS return package if there is no _PSS in the
	 * same scope. This is because if _PSS is present, the ACPI specification
	 * dictates that the _TSS Power Dissipation field is to be ignored, and
	 * therefore some BIOSs leave garbage values in the _TSS Power field(s).
	 * In this case, it is best to just return the _TSS package as-is.
	 * (May, 2011)
	 */
520 521
	status = acpi_ns_get_node(info->node, "^_PSS",
				  ACPI_NS_NO_UPSEARCH, &node);
522 523 524
	if (ACPI_SUCCESS(status)) {
		return (AE_OK);
	}
525

526
	status = acpi_ns_check_sorted_list(info, return_object, 5, 1,
527 528 529 530 531 532 533 534 535 536
					   ACPI_SORT_DESCENDING,
					   "PowerDissipation");

	return (status);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_ns_repair_PSS
 *
537
 * PARAMETERS:  info                - Method execution information block
538 539 540 541 542 543 544 545 546 547 548 549 550
 *              return_object_ptr   - Pointer to the object returned from the
 *                                    evaluation of a method or object
 *
 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 *
 * DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list
 *              by the CPU frequencies. Check that the power dissipation values
 *              are all proportional to CPU frequency (i.e., sorting by
 *              frequency should be the same as sorting by power.)
 *
 *****************************************************************************/

static acpi_status
551
acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
		   union acpi_operand_object **return_object_ptr)
{
	union acpi_operand_object *return_object = *return_object_ptr;
	union acpi_operand_object **outer_elements;
	u32 outer_element_count;
	union acpi_operand_object **elements;
	union acpi_operand_object *obj_desc;
	u32 previous_value;
	acpi_status status;
	u32 i;

	/*
	 * Entries (sub-packages) in the _PSS Package must be sorted by power
	 * dissipation, in descending order. If it appears that the list is
	 * incorrectly sorted, sort it. We sort by cpu_frequency, since this
	 * should be proportional to the power.
	 */
569
	status = acpi_ns_check_sorted_list(info, return_object, 6, 0,
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
					   ACPI_SORT_DESCENDING,
					   "CpuFrequency");
	if (ACPI_FAILURE(status)) {
		return (status);
	}

	/*
	 * We now know the list is correctly sorted by CPU frequency. Check if
	 * the power dissipation values are proportional.
	 */
	previous_value = ACPI_UINT32_MAX;
	outer_elements = return_object->package.elements;
	outer_element_count = return_object->package.count;

	for (i = 0; i < outer_element_count; i++) {
		elements = (*outer_elements)->package.elements;
		obj_desc = elements[1];	/* Index1 = power_dissipation */

		if ((u32) obj_desc->integer.value > previous_value) {
589 590
			ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
					      info->node_flags,
591 592 593 594 595 596 597 598 599 600 601 602 603 604 605
					      "SubPackage[%u,%u] - suspicious power dissipation values",
					      i - 1, i));
		}

		previous_value = (u32) obj_desc->integer.value;
		outer_elements++;
	}

	return (AE_OK);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_ns_check_sorted_list
 *
606
 * PARAMETERS:  info                - Method execution information block
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621
 *              return_object       - Pointer to the top-level returned object
 *              expected_count      - Minimum length of each sub-package
 *              sort_index          - Sub-package entry to sort on
 *              sort_direction      - Ascending or descending
 *              sort_key_name       - Name of the sort_index field
 *
 * RETURN:      Status. AE_OK if the list is valid and is sorted correctly or
 *              has been repaired by sorting the list.
 *
 * DESCRIPTION: Check if the package list is valid and sorted correctly by the
 *              sort_index. If not, then sort the list.
 *
 *****************************************************************************/

static acpi_status
622
acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
623 624 625 626 627 628 629 630 631 632 633 634
			  union acpi_operand_object *return_object,
			  u32 expected_count,
			  u32 sort_index,
			  u8 sort_direction, char *sort_key_name)
{
	u32 outer_element_count;
	union acpi_operand_object **outer_elements;
	union acpi_operand_object **elements;
	union acpi_operand_object *obj_desc;
	u32 i;
	u32 previous_value;

635 636
	ACPI_FUNCTION_NAME(ns_check_sorted_list);

637 638 639 640 641 642 643
	/* The top-level object must be a package */

	if (return_object->common.type != ACPI_TYPE_PACKAGE) {
		return (AE_AML_OPERAND_TYPE);
	}

	/*
644 645 646
	 * NOTE: assumes list of sub-packages contains no NULL elements.
	 * Any NULL elements should have been removed by earlier call
	 * to acpi_ns_remove_null_elements.
647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683
	 */
	outer_elements = return_object->package.elements;
	outer_element_count = return_object->package.count;
	if (!outer_element_count) {
		return (AE_AML_PACKAGE_LIMIT);
	}

	previous_value = 0;
	if (sort_direction == ACPI_SORT_DESCENDING) {
		previous_value = ACPI_UINT32_MAX;
	}

	/* Examine each subpackage */

	for (i = 0; i < outer_element_count; i++) {

		/* Each element of the top-level package must also be a package */

		if ((*outer_elements)->common.type != ACPI_TYPE_PACKAGE) {
			return (AE_AML_OPERAND_TYPE);
		}

		/* Each sub-package must have the minimum length */

		if ((*outer_elements)->package.count < expected_count) {
			return (AE_AML_PACKAGE_LIMIT);
		}

		elements = (*outer_elements)->package.elements;
		obj_desc = elements[sort_index];

		if (obj_desc->common.type != ACPI_TYPE_INTEGER) {
			return (AE_AML_OPERAND_TYPE);
		}

		/*
		 * The list must be sorted in the specified order. If we detect a
684
		 * discrepancy, sort the entire list.
685 686 687 688 689
		 */
		if (((sort_direction == ACPI_SORT_ASCENDING) &&
		     (obj_desc->integer.value < previous_value)) ||
		    ((sort_direction == ACPI_SORT_DESCENDING) &&
		     (obj_desc->integer.value > previous_value))) {
690 691 692
			acpi_ns_sort_list(return_object->package.elements,
					  outer_element_count, sort_index,
					  sort_direction);
693

694
			info->return_flags |= ACPI_OBJECT_REPAIRED;
695

696 697
			ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
					  "%s: Repaired unsorted list - now sorted by %s\n",
698
					  info->full_pathname, sort_key_name));
699 700 701 702 703 704 705 706 707 708 709 710 711 712
			return (AE_OK);
		}

		previous_value = (u32) obj_desc->integer.value;
		outer_elements++;
	}

	return (AE_OK);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_ns_sort_list
 *
713 714 715
 * PARAMETERS:  elements            - Package object element list
 *              count               - Element count for above
 *              index               - Sort by which package element
716 717
 *              sort_direction      - Ascending or Descending sort
 *
718
 * RETURN:      None
719 720 721
 *
 * DESCRIPTION: Sort the objects that are in a package element list.
 *
722 723
 * NOTE: Assumes that all NULL elements have been removed from the package,
 *       and that all elements have been verified to be of type Integer.
724 725 726
 *
 *****************************************************************************/

727
static void
728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756
acpi_ns_sort_list(union acpi_operand_object **elements,
		  u32 count, u32 index, u8 sort_direction)
{
	union acpi_operand_object *obj_desc1;
	union acpi_operand_object *obj_desc2;
	union acpi_operand_object *temp_obj;
	u32 i;
	u32 j;

	/* Simple bubble sort */

	for (i = 1; i < count; i++) {
		for (j = (count - 1); j >= i; j--) {
			obj_desc1 = elements[j - 1]->package.elements[index];
			obj_desc2 = elements[j]->package.elements[index];

			if (((sort_direction == ACPI_SORT_ASCENDING) &&
			     (obj_desc1->integer.value >
			      obj_desc2->integer.value))
			    || ((sort_direction == ACPI_SORT_DESCENDING)
				&& (obj_desc1->integer.value <
				    obj_desc2->integer.value))) {
				temp_obj = elements[j - 1];
				elements[j - 1] = elements[j];
				elements[j] = temp_obj;
			}
		}
	}
}