diff options
author | Lv Zheng <lv.zheng@intel.com> | 2013-06-07 21:01:07 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-06-19 19:39:09 -0400 |
commit | 5a9792f3be74bfad2985b3f4c7afc9e6f6a3f798 (patch) | |
tree | a022831452c1378dde4a952e081c787418ca672b /drivers/acpi | |
parent | aa6329c44bccedbd8b17094c1c1aee1d9a9de461 (diff) |
ACPICA: Add several repairs for _CST predefined name
Sort list based on the C-state, remove invalid/zero entries.
ACPICA BZ 890. Lv Zheng.
Fixes these possible problems with the _CST object:
1. Sort the list ascending by C state type.
2. Ensure type cannot be zero.
3. A sub-package count of zero means _CST is meaningless.
4. Count must match the number of C state sub-packages.
References: https://bugs.acpica.org/show_bug.cgi?id=890
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/acpica/nspredef.c | 5 | ||||
-rw-r--r-- | drivers/acpi/acpica/nsrepair2.c | 170 |
2 files changed, 163 insertions, 12 deletions
diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index 8d59ac2399e0..24b71a01bf93 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c | |||
@@ -159,9 +159,10 @@ acpi_ns_check_return_value(struct acpi_namespace_node *node, | |||
159 | status = acpi_ns_check_package(info, return_object_ptr); | 159 | status = acpi_ns_check_package(info, return_object_ptr); |
160 | if (ACPI_FAILURE(status)) { | 160 | if (ACPI_FAILURE(status)) { |
161 | 161 | ||
162 | /* We might be able to fix an operand type error (_PRT) */ | 162 | /* We might be able to fix some errors */ |
163 | 163 | ||
164 | if (status != AE_AML_OPERAND_TYPE) { | 164 | if ((status != AE_AML_OPERAND_TYPE) && |
165 | (status != AE_AML_OPERAND_VALUE)) { | ||
165 | goto exit; | 166 | goto exit; |
166 | } | 167 | } |
167 | } | 168 | } |
diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c index aca9bdf74e1f..029816edd392 100644 --- a/drivers/acpi/acpica/nsrepair2.c +++ b/drivers/acpi/acpica/nsrepair2.c | |||
@@ -79,6 +79,10 @@ acpi_ns_repair_CID(struct acpi_evaluate_info *info, | |||
79 | union acpi_operand_object **return_object_ptr); | 79 | union acpi_operand_object **return_object_ptr); |
80 | 80 | ||
81 | static acpi_status | 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 | ||
82 | acpi_ns_repair_FDE(struct acpi_evaluate_info *info, | 86 | acpi_ns_repair_FDE(struct acpi_evaluate_info *info, |
83 | union acpi_operand_object **return_object_ptr); | 87 | union acpi_operand_object **return_object_ptr); |
84 | 88 | ||
@@ -101,19 +105,23 @@ acpi_ns_repair_TSS(struct acpi_evaluate_info *info, | |||
101 | static acpi_status | 105 | static acpi_status |
102 | acpi_ns_check_sorted_list(struct acpi_evaluate_info *info, | 106 | acpi_ns_check_sorted_list(struct acpi_evaluate_info *info, |
103 | union acpi_operand_object *return_object, | 107 | union acpi_operand_object *return_object, |
108 | u32 start_index, | ||
104 | u32 expected_count, | 109 | u32 expected_count, |
105 | u32 sort_index, | 110 | u32 sort_index, |
106 | u8 sort_direction, char *sort_key_name); | 111 | u8 sort_direction, char *sort_key_name); |
107 | 112 | ||
108 | static void | ||
109 | acpi_ns_sort_list(union acpi_operand_object **elements, | ||
110 | u32 count, u32 index, u8 sort_direction); | ||
111 | |||
112 | /* Values for sort_direction above */ | 113 | /* Values for sort_direction above */ |
113 | 114 | ||
114 | #define ACPI_SORT_ASCENDING 0 | 115 | #define ACPI_SORT_ASCENDING 0 |
115 | #define ACPI_SORT_DESCENDING 1 | 116 | #define ACPI_SORT_DESCENDING 1 |
116 | 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 | |||
117 | /* | 125 | /* |
118 | * This table contains the names of the predefined methods for which we can | 126 | * This table contains the names of the predefined methods for which we can |
119 | * perform more complex repairs. | 127 | * perform more complex repairs. |
@@ -122,6 +130,7 @@ acpi_ns_sort_list(union acpi_operand_object **elements, | |||
122 | * | 130 | * |
123 | * _ALR: Sort the list ascending by ambient_illuminance | 131 | * _ALR: Sort the list ascending by ambient_illuminance |
124 | * _CID: Strings: uppercase all, remove any leading asterisk | 132 | * _CID: Strings: uppercase all, remove any leading asterisk |
133 | * _CST: Sort the list ascending by C state type | ||
125 | * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs | 134 | * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs |
126 | * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs | 135 | * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs |
127 | * _HID: Strings: uppercase all, remove any leading asterisk | 136 | * _HID: Strings: uppercase all, remove any leading asterisk |
@@ -139,6 +148,7 @@ acpi_ns_sort_list(union acpi_operand_object **elements, | |||
139 | static const struct acpi_repair_info acpi_ns_repairable_names[] = { | 148 | static const struct acpi_repair_info acpi_ns_repairable_names[] = { |
140 | {"_ALR", acpi_ns_repair_ALR}, | 149 | {"_ALR", acpi_ns_repair_ALR}, |
141 | {"_CID", acpi_ns_repair_CID}, | 150 | {"_CID", acpi_ns_repair_CID}, |
151 | {"_CST", acpi_ns_repair_CST}, | ||
142 | {"_FDE", acpi_ns_repair_FDE}, | 152 | {"_FDE", acpi_ns_repair_FDE}, |
143 | {"_GTM", acpi_ns_repair_FDE}, /* _GTM has same repair as _FDE */ | 153 | {"_GTM", acpi_ns_repair_FDE}, /* _GTM has same repair as _FDE */ |
144 | {"_HID", acpi_ns_repair_HID}, | 154 | {"_HID", acpi_ns_repair_HID}, |
@@ -243,7 +253,7 @@ acpi_ns_repair_ALR(struct acpi_evaluate_info *info, | |||
243 | union acpi_operand_object *return_object = *return_object_ptr; | 253 | union acpi_operand_object *return_object = *return_object_ptr; |
244 | acpi_status status; | 254 | acpi_status status; |
245 | 255 | ||
246 | status = acpi_ns_check_sorted_list(info, return_object, 2, 1, | 256 | status = acpi_ns_check_sorted_list(info, return_object, 0, 2, 1, |
247 | ACPI_SORT_ASCENDING, | 257 | ACPI_SORT_ASCENDING, |
248 | "AmbientIlluminance"); | 258 | "AmbientIlluminance"); |
249 | 259 | ||
@@ -411,6 +421,92 @@ acpi_ns_repair_CID(struct acpi_evaluate_info *info, | |||
411 | 421 | ||
412 | /****************************************************************************** | 422 | /****************************************************************************** |
413 | * | 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 sub-package count of zero means _CST is meaningless | ||
436 | * 4. Count must match the number of C state sub-packages | ||
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 | * Entries (subpackages) in the _CST Package must be sorted by the | ||
456 | * C-state type, in ascending order. | ||
457 | */ | ||
458 | status = acpi_ns_check_sorted_list(info, return_object, 1, 4, 1, | ||
459 | ACPI_SORT_ASCENDING, "C-State Type"); | ||
460 | if (ACPI_FAILURE(status)) { | ||
461 | return (status); | ||
462 | } | ||
463 | |||
464 | /* | ||
465 | * We now know the list is correctly sorted by C-state type. Check if | ||
466 | * the C-state type values are proportional. | ||
467 | */ | ||
468 | outer_element_count = return_object->package.count - 1; | ||
469 | i = 0; | ||
470 | while (i < outer_element_count) { | ||
471 | outer_elements = &return_object->package.elements[i + 1]; | ||
472 | removing = FALSE; | ||
473 | |||
474 | if ((*outer_elements)->package.count == 0) { | ||
475 | ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, | ||
476 | info->node_flags, | ||
477 | "SubPackage[%u] - removing entry due to zero count", | ||
478 | i)); | ||
479 | removing = TRUE; | ||
480 | goto remove_element; | ||
481 | } | ||
482 | |||
483 | obj_desc = (*outer_elements)->package.elements[1]; /* Index1 = Type */ | ||
484 | if ((u32)obj_desc->integer.value == 0) { | ||
485 | ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, | ||
486 | info->node_flags, | ||
487 | "SubPackage[%u] - removing entry due to invalid Type(0)", | ||
488 | i)); | ||
489 | removing = TRUE; | ||
490 | } | ||
491 | |||
492 | remove_element: | ||
493 | if (removing) { | ||
494 | acpi_ns_remove_element(return_object, i + 1); | ||
495 | outer_element_count--; | ||
496 | } else { | ||
497 | i++; | ||
498 | } | ||
499 | } | ||
500 | |||
501 | /* Update top-level package count, Type "Integer" checked elsewhere */ | ||
502 | |||
503 | obj_desc = return_object->package.elements[0]; | ||
504 | obj_desc->integer.value = outer_element_count; | ||
505 | return (AE_OK); | ||
506 | } | ||
507 | |||
508 | /****************************************************************************** | ||
509 | * | ||
414 | * FUNCTION: acpi_ns_repair_HID | 510 | * FUNCTION: acpi_ns_repair_HID |
415 | * | 511 | * |
416 | * PARAMETERS: info - Method execution information block | 512 | * PARAMETERS: info - Method execution information block |
@@ -588,7 +684,7 @@ acpi_ns_repair_PSS(struct acpi_evaluate_info *info, | |||
588 | * incorrectly sorted, sort it. We sort by cpu_frequency, since this | 684 | * incorrectly sorted, sort it. We sort by cpu_frequency, since this |
589 | * should be proportional to the power. | 685 | * should be proportional to the power. |
590 | */ | 686 | */ |
591 | status = acpi_ns_check_sorted_list(info, return_object, 6, 0, | 687 | status = acpi_ns_check_sorted_list(info, return_object, 0, 6, 0, |
592 | ACPI_SORT_DESCENDING, | 688 | ACPI_SORT_DESCENDING, |
593 | "CpuFrequency"); | 689 | "CpuFrequency"); |
594 | if (ACPI_FAILURE(status)) { | 690 | if (ACPI_FAILURE(status)) { |
@@ -658,7 +754,7 @@ acpi_ns_repair_TSS(struct acpi_evaluate_info *info, | |||
658 | return (AE_OK); | 754 | return (AE_OK); |
659 | } | 755 | } |
660 | 756 | ||
661 | status = acpi_ns_check_sorted_list(info, return_object, 5, 1, | 757 | status = acpi_ns_check_sorted_list(info, return_object, 0, 5, 1, |
662 | ACPI_SORT_DESCENDING, | 758 | ACPI_SORT_DESCENDING, |
663 | "PowerDissipation"); | 759 | "PowerDissipation"); |
664 | 760 | ||
@@ -671,6 +767,7 @@ acpi_ns_repair_TSS(struct acpi_evaluate_info *info, | |||
671 | * | 767 | * |
672 | * PARAMETERS: info - Method execution information block | 768 | * PARAMETERS: info - Method execution information block |
673 | * return_object - Pointer to the top-level returned object | 769 | * return_object - Pointer to the top-level returned object |
770 | * start_index - Index of the first sub-package | ||
674 | * expected_count - Minimum length of each sub-package | 771 | * expected_count - Minimum length of each sub-package |
675 | * sort_index - Sub-package entry to sort on | 772 | * sort_index - Sub-package entry to sort on |
676 | * sort_direction - Ascending or descending | 773 | * sort_direction - Ascending or descending |
@@ -687,6 +784,7 @@ acpi_ns_repair_TSS(struct acpi_evaluate_info *info, | |||
687 | static acpi_status | 784 | static acpi_status |
688 | acpi_ns_check_sorted_list(struct acpi_evaluate_info *info, | 785 | acpi_ns_check_sorted_list(struct acpi_evaluate_info *info, |
689 | union acpi_operand_object *return_object, | 786 | union acpi_operand_object *return_object, |
787 | u32 start_index, | ||
690 | u32 expected_count, | 788 | u32 expected_count, |
691 | u32 sort_index, | 789 | u32 sort_index, |
692 | u8 sort_direction, char *sort_key_name) | 790 | u8 sort_direction, char *sort_key_name) |
@@ -711,12 +809,14 @@ acpi_ns_check_sorted_list(struct acpi_evaluate_info *info, | |||
711 | * Any NULL elements should have been removed by earlier call | 809 | * Any NULL elements should have been removed by earlier call |
712 | * to acpi_ns_remove_null_elements. | 810 | * to acpi_ns_remove_null_elements. |
713 | */ | 811 | */ |
714 | outer_elements = return_object->package.elements; | ||
715 | outer_element_count = return_object->package.count; | 812 | outer_element_count = return_object->package.count; |
716 | if (!outer_element_count) { | 813 | if (!outer_element_count || start_index >= outer_element_count) { |
717 | return (AE_AML_PACKAGE_LIMIT); | 814 | return (AE_AML_PACKAGE_LIMIT); |
718 | } | 815 | } |
719 | 816 | ||
817 | outer_elements = &return_object->package.elements[start_index]; | ||
818 | outer_element_count -= start_index; | ||
819 | |||
720 | previous_value = 0; | 820 | previous_value = 0; |
721 | if (sort_direction == ACPI_SORT_DESCENDING) { | 821 | if (sort_direction == ACPI_SORT_DESCENDING) { |
722 | previous_value = ACPI_UINT32_MAX; | 822 | previous_value = ACPI_UINT32_MAX; |
@@ -753,7 +853,8 @@ acpi_ns_check_sorted_list(struct acpi_evaluate_info *info, | |||
753 | (obj_desc->integer.value < previous_value)) || | 853 | (obj_desc->integer.value < previous_value)) || |
754 | ((sort_direction == ACPI_SORT_DESCENDING) && | 854 | ((sort_direction == ACPI_SORT_DESCENDING) && |
755 | (obj_desc->integer.value > previous_value))) { | 855 | (obj_desc->integer.value > previous_value))) { |
756 | acpi_ns_sort_list(return_object->package.elements, | 856 | acpi_ns_sort_list(&return_object->package. |
857 | elements[start_index], | ||
757 | outer_element_count, sort_index, | 858 | outer_element_count, sort_index, |
758 | sort_direction); | 859 | sort_direction); |
759 | 860 | ||
@@ -820,3 +921,52 @@ acpi_ns_sort_list(union acpi_operand_object **elements, | |||
820 | } | 921 | } |
821 | } | 922 | } |
822 | } | 923 | } |
924 | |||
925 | /****************************************************************************** | ||
926 | * | ||
927 | * FUNCTION: acpi_ns_remove_element | ||
928 | * | ||
929 | * PARAMETERS: obj_desc - Package object element list | ||
930 | * index - Index of element to remove | ||
931 | * | ||
932 | * RETURN: None | ||
933 | * | ||
934 | * DESCRIPTION: Remove the requested element of a package and delete it. | ||
935 | * | ||
936 | *****************************************************************************/ | ||
937 | |||
938 | static void | ||
939 | acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index) | ||
940 | { | ||
941 | union acpi_operand_object **source; | ||
942 | union acpi_operand_object **dest; | ||
943 | u32 count; | ||
944 | u32 new_count; | ||
945 | u32 i; | ||
946 | |||
947 | ACPI_FUNCTION_NAME(ns_remove_element); | ||
948 | |||
949 | count = obj_desc->package.count; | ||
950 | new_count = count - 1; | ||
951 | |||
952 | source = obj_desc->package.elements; | ||
953 | dest = source; | ||
954 | |||
955 | /* Examine all elements of the package object, remove matched index */ | ||
956 | |||
957 | for (i = 0; i < count; i++) { | ||
958 | if (i == index) { | ||
959 | acpi_ut_remove_reference(*source); /* Remove one ref for being in pkg */ | ||
960 | acpi_ut_remove_reference(*source); | ||
961 | } else { | ||
962 | *dest = *source; | ||
963 | dest++; | ||
964 | } | ||
965 | source++; | ||
966 | } | ||
967 | |||
968 | /* NULL terminate list and update the package count */ | ||
969 | |||
970 | *dest = NULL; | ||
971 | obj_desc->package.count = new_count; | ||
972 | } | ||