1/****************************************************************************** 2 * 3 * Module Name: nsrepair2 - Repair for objects returned by specific 4 * predefined methods 5 * 6 *****************************************************************************/ 7 8/* 9 * Copyright (C) 2000 - 2010, Intel Corp. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions, and the following disclaimer, 17 * without modification. 18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 19 * substantially similar to the "NO WARRANTY" disclaimer below 20 * ("Disclaimer") and any redistribution must be conditioned upon 21 * including a substantially similar Disclaimer requirement for further 22 * binary redistribution. 23 * 3. Neither the names of the above-listed copyright holders nor the names 24 * of any contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * Alternatively, this software may be distributed under the terms of the 28 * GNU General Public License ("GPL") version 2 as published by the Free 29 * Software Foundation. 30 * 31 * NO WARRANTY 32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 35 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 36 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 41 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 42 * POSSIBILITY OF SUCH DAMAGES. 43 */ 44 45#include <acpi/acpi.h> 46#include "accommon.h" 47#include "acnamesp.h" 48 49#define _COMPONENT ACPI_NAMESPACE 50ACPI_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 */ 56typedef 57acpi_status(*acpi_repair_function) (struct acpi_predefined_data *data, 58 union acpi_operand_object **return_object_ptr); 59 60typedef struct acpi_repair_info { 61 char name[ACPI_NAME_SIZE]; 62 acpi_repair_function repair_function; 63 64} acpi_repair_info; 65 66/* Local prototypes */ 67 68static const struct acpi_repair_info *acpi_ns_match_repairable_name(struct 69 acpi_namespace_node 70 *node); 71 72static acpi_status 73acpi_ns_repair_ALR(struct acpi_predefined_data *data, 74 union acpi_operand_object **return_object_ptr); 75 76static acpi_status 77acpi_ns_repair_FDE(struct acpi_predefined_data *data, 78 union acpi_operand_object **return_object_ptr); 79 80static acpi_status 81acpi_ns_repair_PSS(struct acpi_predefined_data *data, 82 union acpi_operand_object **return_object_ptr); 83 84static acpi_status 85acpi_ns_repair_TSS(struct acpi_predefined_data *data, 86 union acpi_operand_object **return_object_ptr); 87 88static acpi_status 89acpi_ns_check_sorted_list(struct acpi_predefined_data *data, 90 union acpi_operand_object *return_object, 91 u32 expected_count, 92 u32 sort_index, 93 u8 sort_direction, char *sort_key_name); 94 95static void 96acpi_ns_sort_list(union acpi_operand_object **elements, 97 u32 count, u32 index, u8 sort_direction); 98 99/* Values for sort_direction above */ 100 101#define ACPI_SORT_ASCENDING 0 102#define ACPI_SORT_DESCENDING 1 103 104/* 105 * This table contains the names of the predefined methods for which we can 106 * perform more complex repairs. 107 * 108 * As necessary: 109 * 110 * _ALR: Sort the list ascending by ambient_illuminance 111 * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs 112 * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs 113 * _PSS: Sort the list descending by Power 114 * _TSS: Sort the list descending by Power 115 * 116 * Names that must be packages, but cannot be sorted: 117 * 118 * _BCL: Values are tied to the Package index where they appear, and cannot 119 * be moved or sorted. These index values are used for _BQC and _BCM. 120 * However, we can fix the case where a buffer is returned, by converting 121 * it to a Package of integers. 122 */ 123static const struct acpi_repair_info acpi_ns_repairable_names[] = { 124 {"_ALR", acpi_ns_repair_ALR}, 125 {"_FDE", acpi_ns_repair_FDE}, 126 {"_GTM", acpi_ns_repair_FDE}, /* _GTM has same repair as _FDE */ 127 {"_PSS", acpi_ns_repair_PSS}, 128 {"_TSS", acpi_ns_repair_TSS}, 129 {{0, 0, 0, 0}, NULL} /* Table terminator */ 130}; 131 132#define ACPI_FDE_FIELD_COUNT 5 133#define ACPI_FDE_BYTE_BUFFER_SIZE 5 134#define ACPI_FDE_DWORD_BUFFER_SIZE (ACPI_FDE_FIELD_COUNT * sizeof (u32)) 135 136/****************************************************************************** 137 * 138 * FUNCTION: acpi_ns_complex_repairs 139 * 140 * PARAMETERS: Data - Pointer to validation data structure 141 * Node - Namespace node for the method/object 142 * validate_status - Original status of earlier validation 143 * return_object_ptr - Pointer to the object returned from the 144 * evaluation of a method or object 145 * 146 * RETURN: Status. AE_OK if repair was successful. If name is not 147 * matched, validate_status is returned. 148 * 149 * DESCRIPTION: Attempt to repair/convert a return object of a type that was 150 * not expected. 151 * 152 *****************************************************************************/ 153 154acpi_status 155acpi_ns_complex_repairs(struct acpi_predefined_data *data, 156 struct acpi_namespace_node *node, 157 acpi_status validate_status, 158 union acpi_operand_object **return_object_ptr) 159{ 160 const struct acpi_repair_info *predefined; 161 acpi_status status; 162 163 /* Check if this name is in the list of repairable names */ 164 165 predefined = acpi_ns_match_repairable_name(node); 166 if (!predefined) { 167 return (validate_status); 168 } 169 170 status = predefined->repair_function(data, return_object_ptr); 171 return (status); 172} 173 174/****************************************************************************** 175 * 176 * FUNCTION: acpi_ns_match_repairable_name 177 * 178 * PARAMETERS: Node - Namespace node for the method/object 179 * 180 * RETURN: Pointer to entry in repair table. NULL indicates not found. 181 * 182 * DESCRIPTION: Check an object name against the repairable object list. 183 * 184 *****************************************************************************/ 185 186static const struct acpi_repair_info *acpi_ns_match_repairable_name(struct 187 acpi_namespace_node 188 *node) 189{ 190 const struct acpi_repair_info *this_name; 191 192 /* Search info table for a repairable predefined method/object name */ 193 194 this_name = acpi_ns_repairable_names; 195 while (this_name->repair_function) { 196 if (ACPI_COMPARE_NAME(node->name.ascii, this_name->name)) { 197 return (this_name); 198 } 199 this_name++; 200 } 201 202 return (NULL); /* Not found */ 203} 204 205/****************************************************************************** 206 * 207 * FUNCTION: acpi_ns_repair_ALR 208 * 209 * PARAMETERS: Data - Pointer to validation data structure 210 * return_object_ptr - Pointer to the object returned from the 211 * evaluation of a method or object 212 * 213 * RETURN: Status. AE_OK if object is OK or was repaired successfully 214 * 215 * DESCRIPTION: Repair for the _ALR object. If necessary, sort the object list 216 * ascending by the ambient illuminance values. 217 * 218 *****************************************************************************/ 219 220static acpi_status 221acpi_ns_repair_ALR(struct acpi_predefined_data *data, 222 union acpi_operand_object **return_object_ptr) 223{ 224 union acpi_operand_object *return_object = *return_object_ptr; 225 acpi_status status; 226 227 status = acpi_ns_check_sorted_list(data, return_object, 2, 1, 228 ACPI_SORT_ASCENDING, 229 "AmbientIlluminance"); 230 231 return (status); 232} 233 234/****************************************************************************** 235 * 236 * FUNCTION: acpi_ns_repair_FDE 237 * 238 * PARAMETERS: Data - Pointer to validation data structure 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 _FDE and _GTM objects. The expected return 245 * value is a Buffer of 5 DWORDs. This function repairs a common 246 * problem where the return value is a Buffer of BYTEs, not 247 * DWORDs. 248 * 249 *****************************************************************************/ 250 251static acpi_status 252acpi_ns_repair_FDE(struct acpi_predefined_data *data, 253 union acpi_operand_object **return_object_ptr) 254{ 255 union acpi_operand_object *return_object = *return_object_ptr; 256 union acpi_operand_object *buffer_object; 257 u8 *byte_buffer; 258 u32 *dword_buffer; 259 u32 i; 260 261 ACPI_FUNCTION_NAME(ns_repair_FDE); 262 263 switch (return_object->common.type) { 264 case ACPI_TYPE_BUFFER: 265 266 /* This is the expected type. Length should be (at least) 5 DWORDs */ 267 268 if (return_object->buffer.length >= ACPI_FDE_DWORD_BUFFER_SIZE) { 269 return (AE_OK); 270 } 271 272 /* We can only repair if we have exactly 5 BYTEs */ 273 274 if (return_object->buffer.length != ACPI_FDE_BYTE_BUFFER_SIZE) { 275 ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, 276 data->node_flags, 277 "Incorrect return buffer length %u, expected %u", 278 return_object->buffer.length, 279 ACPI_FDE_DWORD_BUFFER_SIZE)); 280 281 return (AE_AML_OPERAND_TYPE); 282 } 283 284 /* Create the new (larger) buffer object */ 285 286 buffer_object = 287 acpi_ut_create_buffer_object(ACPI_FDE_DWORD_BUFFER_SIZE); 288 if (!buffer_object) { 289 return (AE_NO_MEMORY); 290 } 291 292 /* Expand each byte to a DWORD */ 293 294 byte_buffer = return_object->buffer.pointer; 295 dword_buffer = 296 ACPI_CAST_PTR(u32, buffer_object->buffer.pointer); 297 298 for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++) { 299 *dword_buffer = (u32) *byte_buffer; 300 dword_buffer++; 301 byte_buffer++; 302 } 303 304 ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, 305 "%s Expanded Byte Buffer to expected DWord Buffer\n", 306 data->pathname)); 307 break; 308 309 default: 310 return (AE_AML_OPERAND_TYPE); 311 } 312 313 /* Delete the original return object, return the new buffer object */ 314 315 acpi_ut_remove_reference(return_object); 316 *return_object_ptr = buffer_object; 317 318 data->flags |= ACPI_OBJECT_REPAIRED; 319 return (AE_OK); 320} 321 322/****************************************************************************** 323 * 324 * FUNCTION: acpi_ns_repair_TSS 325 * 326 * PARAMETERS: Data - Pointer to validation data structure 327 * return_object_ptr - Pointer to the object returned from the 328 * evaluation of a method or object 329 * 330 * RETURN: Status. AE_OK if object is OK or was repaired successfully 331 * 332 * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list 333 * descending by the power dissipation values. 334 * 335 *****************************************************************************/ 336 337static acpi_status 338acpi_ns_repair_TSS(struct acpi_predefined_data *data, 339 union acpi_operand_object **return_object_ptr) 340{ 341 union acpi_operand_object *return_object = *return_object_ptr; 342 acpi_status status; 343 344 status = acpi_ns_check_sorted_list(data, return_object, 5, 1, 345 ACPI_SORT_DESCENDING, 346 "PowerDissipation"); 347 348 return (status); 349} 350 351/****************************************************************************** 352 * 353 * FUNCTION: acpi_ns_repair_PSS 354 * 355 * PARAMETERS: Data - Pointer to validation data structure 356 * return_object_ptr - Pointer to the object returned from the 357 * evaluation of a method or object 358 * 359 * RETURN: Status. AE_OK if object is OK or was repaired successfully 360 * 361 * DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list 362 * by the CPU frequencies. Check that the power dissipation values 363 * are all proportional to CPU frequency (i.e., sorting by 364 * frequency should be the same as sorting by power.) 365 * 366 *****************************************************************************/ 367 368static acpi_status 369acpi_ns_repair_PSS(struct acpi_predefined_data *data, 370 union acpi_operand_object **return_object_ptr) 371{ 372 union acpi_operand_object *return_object = *return_object_ptr; 373 union acpi_operand_object **outer_elements; 374 u32 outer_element_count; 375 union acpi_operand_object **elements; 376 union acpi_operand_object *obj_desc; 377 u32 previous_value; 378 acpi_status status; 379 u32 i; 380 381 /* 382 * Entries (sub-packages) in the _PSS Package must be sorted by power 383 * dissipation, in descending order. If it appears that the list is 384 * incorrectly sorted, sort it. We sort by cpu_frequency, since this 385 * should be proportional to the power. 386 */ 387 status = acpi_ns_check_sorted_list(data, return_object, 6, 0, 388 ACPI_SORT_DESCENDING, 389 "CpuFrequency"); 390 if (ACPI_FAILURE(status)) { 391 return (status); 392 } 393 394 /* 395 * We now know the list is correctly sorted by CPU frequency. Check if 396 * the power dissipation values are proportional. 397 */ 398 previous_value = ACPI_UINT32_MAX; 399 outer_elements = return_object->package.elements; 400 outer_element_count = return_object->package.count; 401 402 for (i = 0; i < outer_element_count; i++) { 403 elements = (*outer_elements)->package.elements; 404 obj_desc = elements[1]; /* Index1 = power_dissipation */ 405 406 if ((u32) obj_desc->integer.value > previous_value) { 407 ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, 408 data->node_flags, 409 "SubPackage[%u,%u] - suspicious power dissipation values", 410 i - 1, i)); 411 } 412 413 previous_value = (u32) obj_desc->integer.value; 414 outer_elements++; 415 } 416 417 return (AE_OK); 418} 419 420/****************************************************************************** 421 * 422 * FUNCTION: acpi_ns_check_sorted_list 423 * 424 * PARAMETERS: Data - Pointer to validation data structure 425 * return_object - Pointer to the top-level returned object 426 * expected_count - Minimum length of each sub-package 427 * sort_index - Sub-package entry to sort on 428 * sort_direction - Ascending or descending 429 * sort_key_name - Name of the sort_index field 430 * 431 * RETURN: Status. AE_OK if the list is valid and is sorted correctly or 432 * has been repaired by sorting the list. 433 * 434 * DESCRIPTION: Check if the package list is valid and sorted correctly by the 435 * sort_index. If not, then sort the list. 436 * 437 *****************************************************************************/ 438 439static acpi_status 440acpi_ns_check_sorted_list(struct acpi_predefined_data *data, 441 union acpi_operand_object *return_object, 442 u32 expected_count, 443 u32 sort_index, 444 u8 sort_direction, char *sort_key_name) 445{ 446 u32 outer_element_count; 447 union acpi_operand_object **outer_elements; 448 union acpi_operand_object **elements; 449 union acpi_operand_object *obj_desc; 450 u32 i; 451 u32 previous_value; 452 453 ACPI_FUNCTION_NAME(ns_check_sorted_list); 454 455 /* The top-level object must be a package */ 456 457 if (return_object->common.type != ACPI_TYPE_PACKAGE) { 458 return (AE_AML_OPERAND_TYPE); 459 } 460 461 /* 462 * NOTE: assumes list of sub-packages contains no NULL elements. 463 * Any NULL elements should have been removed by earlier call 464 * to acpi_ns_remove_null_elements. 465 */ 466 outer_elements = return_object->package.elements; 467 outer_element_count = return_object->package.count; 468 if (!outer_element_count) { 469 return (AE_AML_PACKAGE_LIMIT); 470 } 471 472 previous_value = 0; 473 if (sort_direction == ACPI_SORT_DESCENDING) { 474 previous_value = ACPI_UINT32_MAX; 475 } 476 477 /* Examine each subpackage */ 478 479 for (i = 0; i < outer_element_count; i++) { 480 481 /* Each element of the top-level package must also be a package */ 482 483 if ((*outer_elements)->common.type != ACPI_TYPE_PACKAGE) { 484 return (AE_AML_OPERAND_TYPE); 485 } 486 487 /* Each sub-package must have the minimum length */ 488 489 if ((*outer_elements)->package.count < expected_count) { 490 return (AE_AML_PACKAGE_LIMIT); 491 } 492 493 elements = (*outer_elements)->package.elements; 494 obj_desc = elements[sort_index]; 495 496 if (obj_desc->common.type != ACPI_TYPE_INTEGER) { 497 return (AE_AML_OPERAND_TYPE); 498 } 499 500 /* 501 * The list must be sorted in the specified order. If we detect a 502 * discrepancy, sort the entire list. 503 */ 504 if (((sort_direction == ACPI_SORT_ASCENDING) && 505 (obj_desc->integer.value < previous_value)) || 506 ((sort_direction == ACPI_SORT_DESCENDING) && 507 (obj_desc->integer.value > previous_value))) { 508 acpi_ns_sort_list(return_object->package.elements, 509 outer_element_count, sort_index, 510 sort_direction); 511 512 data->flags |= ACPI_OBJECT_REPAIRED; 513 514 ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, 515 "%s: Repaired unsorted list - now sorted by %s\n", 516 data->pathname, sort_key_name)); 517 return (AE_OK); 518 } 519 520 previous_value = (u32) obj_desc->integer.value; 521 outer_elements++; 522 } 523 524 return (AE_OK); 525} 526 527/****************************************************************************** 528 * 529 * FUNCTION: acpi_ns_sort_list 530 * 531 * PARAMETERS: Elements - Package object element list 532 * Count - Element count for above 533 * Index - Sort by which package element 534 * sort_direction - Ascending or Descending sort 535 * 536 * RETURN: None 537 * 538 * DESCRIPTION: Sort the objects that are in a package element list. 539 * 540 * NOTE: Assumes that all NULL elements have been removed from the package, 541 * and that all elements have been verified to be of type Integer. 542 * 543 *****************************************************************************/ 544 545static void 546acpi_ns_sort_list(union acpi_operand_object **elements, 547 u32 count, u32 index, u8 sort_direction) 548{ 549 union acpi_operand_object *obj_desc1; 550 union acpi_operand_object *obj_desc2; 551 union acpi_operand_object *temp_obj; 552 u32 i; 553 u32 j; 554 555 /* Simple bubble sort */ 556 557 for (i = 1; i < count; i++) { 558 for (j = (count - 1); j >= i; j--) { 559 obj_desc1 = elements[j - 1]->package.elements[index]; 560 obj_desc2 = elements[j]->package.elements[index]; 561 562 if (((sort_direction == ACPI_SORT_ASCENDING) && 563 (obj_desc1->integer.value > 564 obj_desc2->integer.value)) 565 || ((sort_direction == ACPI_SORT_DESCENDING) 566 && (obj_desc1->integer.value < 567 obj_desc2->integer.value))) { 568 temp_obj = elements[j - 1]; 569 elements[j - 1] = elements[j]; 570 elements[j] = temp_obj; 571 } 572 } 573 } 574} 575