diff options
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/acpi_lpss.c | 3 | ||||
-rw-r--r-- | drivers/acpi/acpica/exstore.c | 166 | ||||
-rw-r--r-- | drivers/acpi/glue.c | 35 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 15 |
4 files changed, 134 insertions, 85 deletions
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 6a382188fa20..fb78bb9ad8f6 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -257,12 +257,13 @@ static int acpi_lpss_create_device(struct acpi_device *adev, pdata->mmio_size = resource_size(&rentry->res); pdata->mmio_base = ioremap(rentry->res.start, pdata->mmio_size); - pdata->dev_desc = dev_desc; break; } acpi_dev_free_resource_list(&resource_list); + pdata->dev_desc = dev_desc; + if (dev_desc->clk_required) { ret = register_device_clock(adev, pdata); if (ret) { diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c index 2bdba6f7d762..f0b09bf9887d 100644 --- a/drivers/acpi/acpica/exstore.c +++ b/drivers/acpi/acpica/exstore.c @@ -57,6 +57,11 @@ acpi_ex_store_object_to_index(union acpi_operand_object *val_desc, union acpi_operand_object *dest_desc, struct acpi_walk_state *walk_state); +static acpi_status +acpi_ex_store_direct_to_node(union acpi_operand_object *source_desc, + struct acpi_namespace_node *node, + struct acpi_walk_state *walk_state); + /******************************************************************************* * * FUNCTION: acpi_ex_store @@ -375,7 +380,11 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc, * When storing into an object the data is converted to the * target object type then stored in the object. This means * that the target object type (for an initialized target) will - * not be changed by a store operation. + * not be changed by a store operation. A copy_object can change + * the target type, however. + * + * The implicit_conversion flag is set to NO/FALSE only when + * storing to an arg_x -- as per the rules of the ACPI spec. * * Assumes parameters are already validated. * @@ -399,7 +408,7 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc, target_type = acpi_ns_get_type(node); target_desc = acpi_ns_get_attached_object(node); - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Storing %p(%s) into node %p(%s)\n", + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Storing %p (%s) to node %p (%s)\n", source_desc, acpi_ut_get_object_type_name(source_desc), node, acpi_ut_get_type_name(target_type))); @@ -413,45 +422,30 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc, return_ACPI_STATUS(status); } - /* If no implicit conversion, drop into the default case below */ - - if ((!implicit_conversion) || - ((walk_state->opcode == AML_COPY_OP) && - (target_type != ACPI_TYPE_LOCAL_REGION_FIELD) && - (target_type != ACPI_TYPE_LOCAL_BANK_FIELD) && - (target_type != ACPI_TYPE_LOCAL_INDEX_FIELD))) { - /* - * Force execution of default (no implicit conversion). Note: - * copy_object does not perform an implicit conversion, as per the ACPI - * spec -- except in case of region/bank/index fields -- because these - * objects must retain their original type permanently. - */ - target_type = ACPI_TYPE_ANY; - } - /* Do the actual store operation */ switch (target_type) { - case ACPI_TYPE_BUFFER_FIELD: - case ACPI_TYPE_LOCAL_REGION_FIELD: - case ACPI_TYPE_LOCAL_BANK_FIELD: - case ACPI_TYPE_LOCAL_INDEX_FIELD: - - /* For fields, copy the source data to the target field. */ - - status = acpi_ex_write_data_to_field(source_desc, target_desc, - &walk_state->result_obj); - break; - case ACPI_TYPE_INTEGER: case ACPI_TYPE_STRING: case ACPI_TYPE_BUFFER: /* - * These target types are all of type Integer/String/Buffer, and - * therefore support implicit conversion before the store. - * - * Copy and/or convert the source object to a new target object + * The simple data types all support implicit source operand + * conversion before the store. */ + + if ((walk_state->opcode == AML_COPY_OP) || !implicit_conversion) { + /* + * However, copy_object and Stores to arg_x do not perform + * an implicit conversion, as per the ACPI specification. + * A direct store is performed instead. + */ + status = acpi_ex_store_direct_to_node(source_desc, node, + walk_state); + break; + } + + /* Store with implicit source operand conversion support */ + status = acpi_ex_store_object_to_object(source_desc, target_desc, &new_desc, walk_state); @@ -465,13 +459,12 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc, * the Name's type to that of the value being stored in it. * source_desc reference count is incremented by attach_object. * - * Note: This may change the type of the node if an explicit store - * has been performed such that the node/object type has been - * changed. + * Note: This may change the type of the node if an explicit + * store has been performed such that the node/object type + * has been changed. */ - status = - acpi_ns_attach_object(node, new_desc, - new_desc->common.type); + status = acpi_ns_attach_object(node, new_desc, + new_desc->common.type); ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Store %s into %s via Convert/Attach\n", @@ -482,38 +475,83 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc, } break; - default: - - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Storing [%s] (%p) directly into node [%s] (%p)" - " with no implicit conversion\n", - acpi_ut_get_object_type_name(source_desc), - source_desc, - acpi_ut_get_object_type_name(target_desc), - node)); + case ACPI_TYPE_BUFFER_FIELD: + case ACPI_TYPE_LOCAL_REGION_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + /* + * For all fields, always write the source data to the target + * field. Any required implicit source operand conversion is + * performed in the function below as necessary. Note, field + * objects must retain their original type permanently. + */ + status = acpi_ex_write_data_to_field(source_desc, target_desc, + &walk_state->result_obj); + break; + default: /* * No conversions for all other types. Directly store a copy of - * the source object. NOTE: This is a departure from the ACPI - * spec, which states "If conversion is impossible, abort the - * running control method". + * the source object. This is the ACPI spec-defined behavior for + * the copy_object operator. * - * This code implements "If conversion is impossible, treat the - * Store operation as a CopyObject". + * NOTE: For the Store operator, this is a departure from the + * ACPI spec, which states "If conversion is impossible, abort + * the running control method". Instead, this code implements + * "If conversion is impossible, treat the Store operation as + * a CopyObject". */ - status = - acpi_ut_copy_iobject_to_iobject(source_desc, &new_desc, - walk_state); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - status = - acpi_ns_attach_object(node, new_desc, - new_desc->common.type); - acpi_ut_remove_reference(new_desc); + status = acpi_ex_store_direct_to_node(source_desc, node, + walk_state); break; } return_ACPI_STATUS(status); } + +/******************************************************************************* + * + * FUNCTION: acpi_ex_store_direct_to_node + * + * PARAMETERS: source_desc - Value to be stored + * node - Named object to receive the value + * walk_state - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: "Store" an object directly to a node. This involves a copy + * and an attach. + * + ******************************************************************************/ + +static acpi_status +acpi_ex_store_direct_to_node(union acpi_operand_object *source_desc, + struct acpi_namespace_node *node, + struct acpi_walk_state *walk_state) +{ + acpi_status status; + union acpi_operand_object *new_desc; + + ACPI_FUNCTION_TRACE(ex_store_direct_to_node); + + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Storing [%s] (%p) directly into node [%s] (%p)" + " with no implicit conversion\n", + acpi_ut_get_object_type_name(source_desc), + source_desc, acpi_ut_get_type_name(node->type), + node)); + + /* Copy the source object to a new object */ + + status = + acpi_ut_copy_iobject_to_iobject(source_desc, &new_desc, walk_state); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* Attach the new object to the node */ + + status = acpi_ns_attach_object(node, new_desc, new_desc->common.type); + acpi_ut_remove_reference(new_desc); + return_ACPI_STATUS(status); +} diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 94672297e1b1..10f0f40587bb 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -79,6 +79,9 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev) return ret; } +#define FIND_CHILD_MIN_SCORE 1 +#define FIND_CHILD_MAX_SCORE 2 + static acpi_status acpi_dev_present(acpi_handle handle, u32 lvl_not_used, void *not_used, void **ret_p) { @@ -92,14 +95,17 @@ static acpi_status acpi_dev_present(acpi_handle handle, u32 lvl_not_used, return AE_OK; } -static bool acpi_extra_checks_passed(acpi_handle handle, bool is_bridge) +static int do_find_child_checks(acpi_handle handle, bool is_bridge) { + bool sta_present = true; unsigned long long sta; acpi_status status; - status = acpi_bus_get_status_handle(handle, &sta); - if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED)) - return false; + status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); + if (status == AE_NOT_FOUND) + sta_present = false; + else if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED)) + return -ENODEV; if (is_bridge) { void *test = NULL; @@ -107,16 +113,17 @@ static bool acpi_extra_checks_passed(acpi_handle handle, bool is_bridge) /* Check if this object has at least one child device. */ acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, acpi_dev_present, NULL, NULL, &test); - return !!test; + if (!test) + return -ENODEV; } - return true; + return sta_present ? FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE; } struct find_child_context { u64 addr; bool is_bridge; acpi_handle ret; - bool ret_checked; + int ret_score; }; static acpi_status do_find_child(acpi_handle handle, u32 lvl_not_used, @@ -125,6 +132,7 @@ static acpi_status do_find_child(acpi_handle handle, u32 lvl_not_used, struct find_child_context *context = data; unsigned long long addr; acpi_status status; + int score; status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &addr); if (ACPI_FAILURE(status) || addr != context->addr) @@ -144,15 +152,20 @@ static acpi_status do_find_child(acpi_handle handle, u32 lvl_not_used, * its handle if so. Second, check the same for the object that we've * just found. */ - if (!context->ret_checked) { - if (acpi_extra_checks_passed(context->ret, context->is_bridge)) + if (!context->ret_score) { + score = do_find_child_checks(context->ret, context->is_bridge); + if (score == FIND_CHILD_MAX_SCORE) return AE_CTRL_TERMINATE; else - context->ret_checked = true; + context->ret_score = score; } - if (acpi_extra_checks_passed(handle, context->is_bridge)) { + score = do_find_child_checks(handle, context->is_bridge); + if (score == FIND_CHILD_MAX_SCORE) { context->ret = handle; return AE_CTRL_TERMINATE; + } else if (score > context->ret_score) { + context->ret = handle; + context->ret_score = score; } return AE_OK; } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 61d090b6ce25..fbdb82e70d10 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -204,8 +204,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device) return -EINVAL; } - lock_device_hotplug(); - /* * Carry out two passes here and ignore errors in the first pass, * because if the devices in question are memory blocks and @@ -236,9 +234,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device) ACPI_UINT32_MAX, acpi_bus_online_companions, NULL, NULL, NULL); - - unlock_device_hotplug(); - put_device(&device->dev); return -EBUSY; } @@ -249,8 +244,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device) acpi_bus_trim(device); - unlock_device_hotplug(); - /* Device node has been unregistered. */ put_device(&device->dev); device = NULL; @@ -289,6 +282,7 @@ static void acpi_bus_device_eject(void *context) u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; int error; + lock_device_hotplug(); mutex_lock(&acpi_scan_lock); acpi_bus_get_device(handle, &device); @@ -312,6 +306,7 @@ static void acpi_bus_device_eject(void *context) out: mutex_unlock(&acpi_scan_lock); + unlock_device_hotplug(); return; err_out: @@ -326,8 +321,8 @@ static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source) u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; int error; - mutex_lock(&acpi_scan_lock); lock_device_hotplug(); + mutex_lock(&acpi_scan_lock); if (ost_source != ACPI_NOTIFY_BUS_CHECK) { acpi_bus_get_device(handle, &device); @@ -353,9 +348,9 @@ static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source) kobject_uevent(&device->dev.kobj, KOBJ_ONLINE); out: - unlock_device_hotplug(); acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL); mutex_unlock(&acpi_scan_lock); + unlock_device_hotplug(); } static void acpi_scan_bus_check(void *context) @@ -446,6 +441,7 @@ void acpi_bus_hot_remove_device(void *context) acpi_handle handle = device->handle; int error; + lock_device_hotplug(); mutex_lock(&acpi_scan_lock); error = acpi_scan_hot_remove(device); @@ -455,6 +451,7 @@ void acpi_bus_hot_remove_device(void *context) NULL); mutex_unlock(&acpi_scan_lock); + unlock_device_hotplug(); kfree(context); } EXPORT_SYMBOL(acpi_bus_hot_remove_device); |