diff options
| -rw-r--r-- | drivers/acpi/acpica/evregion.c | 121 | ||||
| -rw-r--r-- | drivers/acpi/acpica/evrgnini.c | 2 | ||||
| -rw-r--r-- | drivers/acpi/acpica/evxfregn.c | 13 | ||||
| -rw-r--r-- | include/acpi/actypes.h | 5 |
4 files changed, 132 insertions, 9 deletions
diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index bea7223d7a71..f0edf5c43c03 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c | |||
| @@ -55,6 +55,8 @@ static u8 | |||
| 55 | acpi_ev_has_default_handler(struct acpi_namespace_node *node, | 55 | acpi_ev_has_default_handler(struct acpi_namespace_node *node, |
| 56 | acpi_adr_space_type space_id); | 56 | acpi_adr_space_type space_id); |
| 57 | 57 | ||
| 58 | static void acpi_ev_orphan_ec_reg_method(void); | ||
| 59 | |||
| 58 | static acpi_status | 60 | static acpi_status |
| 59 | acpi_ev_reg_run(acpi_handle obj_handle, | 61 | acpi_ev_reg_run(acpi_handle obj_handle, |
| 60 | u32 level, void *context, void **return_value); | 62 | u32 level, void *context, void **return_value); |
| @@ -561,7 +563,9 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj, | |||
| 561 | 563 | ||
| 562 | /* Now stop region accesses by executing the _REG method */ | 564 | /* Now stop region accesses by executing the _REG method */ |
| 563 | 565 | ||
| 564 | status = acpi_ev_execute_reg_method(region_obj, 0); | 566 | status = |
| 567 | acpi_ev_execute_reg_method(region_obj, | ||
| 568 | ACPI_REG_DISCONNECT); | ||
| 565 | if (ACPI_FAILURE(status)) { | 569 | if (ACPI_FAILURE(status)) { |
| 566 | ACPI_EXCEPTION((AE_INFO, status, | 570 | ACPI_EXCEPTION((AE_INFO, status, |
| 567 | "from region _REG, [%s]", | 571 | "from region _REG, [%s]", |
| @@ -1062,6 +1066,12 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, | |||
| 1062 | ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, | 1066 | ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, |
| 1063 | NULL, &space_id, NULL); | 1067 | NULL, &space_id, NULL); |
| 1064 | 1068 | ||
| 1069 | /* Special case for EC: handle "orphan" _REG methods with no region */ | ||
| 1070 | |||
| 1071 | if (space_id == ACPI_ADR_SPACE_EC) { | ||
| 1072 | acpi_ev_orphan_ec_reg_method(); | ||
| 1073 | } | ||
| 1074 | |||
| 1065 | return_ACPI_STATUS(status); | 1075 | return_ACPI_STATUS(status); |
| 1066 | } | 1076 | } |
| 1067 | 1077 | ||
| @@ -1120,6 +1130,113 @@ acpi_ev_reg_run(acpi_handle obj_handle, | |||
| 1120 | return (AE_OK); | 1130 | return (AE_OK); |
| 1121 | } | 1131 | } |
| 1122 | 1132 | ||
| 1123 | status = acpi_ev_execute_reg_method(obj_desc, 1); | 1133 | status = acpi_ev_execute_reg_method(obj_desc, ACPI_REG_CONNECT); |
| 1124 | return (status); | 1134 | return (status); |
| 1125 | } | 1135 | } |
| 1136 | |||
| 1137 | /******************************************************************************* | ||
| 1138 | * | ||
| 1139 | * FUNCTION: acpi_ev_orphan_ec_reg_method | ||
| 1140 | * | ||
| 1141 | * PARAMETERS: None | ||
| 1142 | * | ||
| 1143 | * RETURN: None | ||
| 1144 | * | ||
| 1145 | * DESCRIPTION: Execute an "orphan" _REG method that appears under the EC | ||
| 1146 | * device. This is a _REG method that has no corresponding region | ||
| 1147 | * within the EC device scope. The orphan _REG method appears to | ||
| 1148 | * have been enabled by the description of the ECDT in the ACPI | ||
| 1149 | * specification: "The availability of the region space can be | ||
| 1150 | * detected by providing a _REG method object underneath the | ||
| 1151 | * Embedded Controller device." | ||
| 1152 | * | ||
| 1153 | * To quickly access the EC device, we use the EC_ID that appears | ||
| 1154 | * within the ECDT. Otherwise, we would need to perform a time- | ||
| 1155 | * consuming namespace walk, executing _HID methods to find the | ||
| 1156 | * EC device. | ||
| 1157 | * | ||
| 1158 | ******************************************************************************/ | ||
| 1159 | |||
| 1160 | static void acpi_ev_orphan_ec_reg_method(void) | ||
| 1161 | { | ||
| 1162 | struct acpi_table_ecdt *table; | ||
| 1163 | acpi_status status; | ||
| 1164 | struct acpi_object_list args; | ||
| 1165 | union acpi_object objects[2]; | ||
| 1166 | struct acpi_namespace_node *ec_device_node; | ||
| 1167 | struct acpi_namespace_node *reg_method; | ||
| 1168 | struct acpi_namespace_node *next_node; | ||
| 1169 | |||
| 1170 | ACPI_FUNCTION_TRACE(ev_orphan_ec_reg_method); | ||
| 1171 | |||
| 1172 | /* Get the ECDT (if present in system) */ | ||
| 1173 | |||
| 1174 | status = acpi_get_table(ACPI_SIG_ECDT, 0, | ||
| 1175 | ACPI_CAST_INDIRECT_PTR(struct acpi_table_header, | ||
| 1176 | &table)); | ||
| 1177 | if (ACPI_FAILURE(status)) { | ||
| 1178 | return_VOID; | ||
| 1179 | } | ||
| 1180 | |||
| 1181 | /* We need a valid EC_ID string */ | ||
| 1182 | |||
| 1183 | if (!(*table->id)) { | ||
| 1184 | return_VOID; | ||
| 1185 | } | ||
| 1186 | |||
| 1187 | /* Namespace is currently locked, must release */ | ||
| 1188 | |||
| 1189 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); | ||
| 1190 | |||
| 1191 | /* Get a handle to the EC device referenced in the ECDT */ | ||
| 1192 | |||
| 1193 | status = acpi_get_handle(NULL, | ||
| 1194 | ACPI_CAST_PTR(char, table->id), | ||
| 1195 | ACPI_CAST_PTR(acpi_handle, &ec_device_node)); | ||
| 1196 | if (ACPI_FAILURE(status)) { | ||
| 1197 | goto exit; | ||
| 1198 | } | ||
| 1199 | |||
| 1200 | /* Get a handle to a _REG method immediately under the EC device */ | ||
| 1201 | |||
| 1202 | status = acpi_get_handle(ec_device_node, | ||
| 1203 | METHOD_NAME__REG, ACPI_CAST_PTR(acpi_handle, | ||
| 1204 | ®_method)); | ||
| 1205 | if (ACPI_FAILURE(status)) { | ||
| 1206 | goto exit; | ||
| 1207 | } | ||
| 1208 | |||
| 1209 | /* | ||
| 1210 | * Execute the _REG method only if there is no Operation Region in | ||
| 1211 | * this scope with the Embedded Controller space ID. Otherwise, it | ||
| 1212 | * will already have been executed. Note, this allows for Regions | ||
| 1213 | * with other space IDs to be present; but the code below will then | ||
| 1214 | * execute the _REG method with the EC space ID argument. | ||
| 1215 | */ | ||
| 1216 | next_node = acpi_ns_get_next_node(ec_device_node, NULL); | ||
| 1217 | while (next_node) { | ||
| 1218 | if ((next_node->type == ACPI_TYPE_REGION) && | ||
| 1219 | (next_node->object) && | ||
| 1220 | (next_node->object->region.space_id == ACPI_ADR_SPACE_EC)) { | ||
| 1221 | goto exit; /* Do not execute _REG */ | ||
| 1222 | } | ||
| 1223 | next_node = acpi_ns_get_next_node(ec_device_node, next_node); | ||
| 1224 | } | ||
| 1225 | |||
| 1226 | /* Evaluate the _REG(EC,Connect) method */ | ||
| 1227 | |||
| 1228 | args.count = 2; | ||
| 1229 | args.pointer = objects; | ||
| 1230 | objects[0].type = ACPI_TYPE_INTEGER; | ||
| 1231 | objects[0].integer.value = ACPI_ADR_SPACE_EC; | ||
| 1232 | objects[1].type = ACPI_TYPE_INTEGER; | ||
| 1233 | objects[1].integer.value = ACPI_REG_CONNECT; | ||
| 1234 | |||
| 1235 | status = acpi_evaluate_object(reg_method, NULL, &args, NULL); | ||
| 1236 | |||
| 1237 | exit: | ||
| 1238 | /* We ignore all errors from above, don't care */ | ||
| 1239 | |||
| 1240 | status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); | ||
| 1241 | return_VOID; | ||
| 1242 | } | ||
diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index 9659cee6093e..55a5d35ef34a 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c | |||
| @@ -637,7 +637,7 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, | |||
| 637 | 637 | ||
| 638 | status = | 638 | status = |
| 639 | acpi_ev_execute_reg_method | 639 | acpi_ev_execute_reg_method |
| 640 | (region_obj, 1); | 640 | (region_obj, ACPI_REG_CONNECT); |
| 641 | 641 | ||
| 642 | if (acpi_ns_locked) { | 642 | if (acpi_ns_locked) { |
| 643 | status = | 643 | status = |
diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c index c85c8c45599d..00cd95692a91 100644 --- a/drivers/acpi/acpica/evxfregn.c +++ b/drivers/acpi/acpica/evxfregn.c | |||
| @@ -130,20 +130,21 @@ acpi_install_address_space_handler(acpi_handle device, | |||
| 130 | case ACPI_ADR_SPACE_PCI_CONFIG: | 130 | case ACPI_ADR_SPACE_PCI_CONFIG: |
| 131 | case ACPI_ADR_SPACE_DATA_TABLE: | 131 | case ACPI_ADR_SPACE_DATA_TABLE: |
| 132 | 132 | ||
| 133 | if (acpi_gbl_reg_methods_executed) { | 133 | if (!acpi_gbl_reg_methods_executed) { |
| 134 | 134 | ||
| 135 | /* Run all _REG methods for this address space */ | 135 | /* We will defer execution of the _REG methods for this space */ |
| 136 | 136 | goto unlock_and_exit; | |
| 137 | status = acpi_ev_execute_reg_methods(node, space_id); | ||
| 138 | } | 137 | } |
| 139 | break; | 138 | break; |
| 140 | 139 | ||
| 141 | default: | 140 | default: |
| 142 | |||
| 143 | status = acpi_ev_execute_reg_methods(node, space_id); | ||
| 144 | break; | 141 | break; |
| 145 | } | 142 | } |
| 146 | 143 | ||
| 144 | /* Run all _REG methods for this address space */ | ||
| 145 | |||
| 146 | status = acpi_ev_execute_reg_methods(node, space_id); | ||
| 147 | |||
| 147 | unlock_and_exit: | 148 | unlock_and_exit: |
| 148 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); | 149 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
| 149 | return_ACPI_STATUS(status); | 150 | return_ACPI_STATUS(status); |
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index f3b29fa5654e..a6412b82a572 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h | |||
| @@ -726,6 +726,11 @@ typedef u8 acpi_adr_space_type; | |||
| 726 | #define ACPI_ADR_SPACE_DATA_TABLE (acpi_adr_space_type) 0x7E /* Internal to ACPICA only */ | 726 | #define ACPI_ADR_SPACE_DATA_TABLE (acpi_adr_space_type) 0x7E /* Internal to ACPICA only */ |
| 727 | #define ACPI_ADR_SPACE_FIXED_HARDWARE (acpi_adr_space_type) 0x7F | 727 | #define ACPI_ADR_SPACE_FIXED_HARDWARE (acpi_adr_space_type) 0x7F |
| 728 | 728 | ||
| 729 | /* Values for _REG connection code */ | ||
| 730 | |||
| 731 | #define ACPI_REG_DISCONNECT 0 | ||
| 732 | #define ACPI_REG_CONNECT 1 | ||
| 733 | |||
| 729 | /* | 734 | /* |
| 730 | * bit_register IDs | 735 | * bit_register IDs |
| 731 | * | 736 | * |
