diff options
Diffstat (limited to 'drivers/acpi')
90 files changed, 3274 insertions, 1285 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 7702118509a..66cc3f36a95 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -19,6 +19,7 @@ obj-y += acpi.o \ # All the builtin files are in the "acpi." module_param namespace. acpi-y += osl.o utils.o reboot.o +acpi-y += hest.o # sleep related files acpi-y += wakeup.o @@ -31,6 +32,7 @@ acpi-$(CONFIG_ACPI_SLEEP) += proc.o # acpi-y += bus.o glue.o acpi-y += scan.o +acpi-y += processor_pdc.o acpi-y += ec.o acpi-$(CONFIG_ACPI_DOCK) += dock.o acpi-y += pci_root.o pci_link.o pci_irq.o pci_bind.o diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index 28ccdbc05ac..3597d73f28f 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -537,7 +537,7 @@ static int __init acpi_memory_device_init(void) status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, - acpi_memory_register_notify_handler, + acpi_memory_register_notify_handler, NULL, NULL, NULL); if (ACPI_FAILURE(status)) { @@ -561,7 +561,7 @@ static void __exit acpi_memory_device_exit(void) */ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, - acpi_memory_deregister_notify_handler, + acpi_memory_deregister_notify_handler, NULL, NULL, NULL); if (ACPI_FAILURE(status)) diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 0d2cdb86158..7e52295f1ec 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -100,7 +100,8 @@ static void round_robin_cpu(unsigned int tsk_index) struct cpumask *pad_busy_cpus = to_cpumask(pad_busy_cpus_bits); cpumask_var_t tmp; int cpu; - unsigned long min_weight = -1, preferred_cpu; + unsigned long min_weight = -1; + unsigned long uninitialized_var(preferred_cpu); if (!alloc_cpumask_var(&tmp, GFP_KERNEL)) return; @@ -207,7 +208,7 @@ static int power_saving_thread(void *data) * the mechanism only works when all CPUs have RT task running, * as if one CPU hasn't RT task, RT task from other CPUs will * borrow CPU time from this CPU and cause RT task use > 95% - * CPU time. To make 'avoid staration' work, takes a nap here. + * CPU time. To make 'avoid starvation' work, takes a nap here. */ if (do_sleep) schedule_timeout_killable(HZ * idle_pct / 100); @@ -221,14 +222,18 @@ static struct task_struct *ps_tsks[NR_CPUS]; static unsigned int ps_tsk_num; static int create_power_saving_task(void) { + int rc = -ENOMEM; + ps_tsks[ps_tsk_num] = kthread_run(power_saving_thread, (void *)(unsigned long)ps_tsk_num, "power_saving/%d", ps_tsk_num); - if (ps_tsks[ps_tsk_num]) { + rc = IS_ERR(ps_tsks[ps_tsk_num]) ? PTR_ERR(ps_tsks[ps_tsk_num]) : 0; + if (!rc) ps_tsk_num++; - return 0; - } - return -EINVAL; + else + ps_tsks[ps_tsk_num] = NULL; + + return rc; } static void destroy_power_saving_task(void) @@ -236,6 +241,7 @@ static void destroy_power_saving_task(void) if (ps_tsk_num > 0) { ps_tsk_num--; kthread_stop(ps_tsks[ps_tsk_num]); + ps_tsks[ps_tsk_num] = NULL; } } @@ -252,7 +258,7 @@ static void set_power_saving_task_num(unsigned int num) } } -static int acpi_pad_idle_cpus(unsigned int num_cpus) +static void acpi_pad_idle_cpus(unsigned int num_cpus) { get_online_cpus(); @@ -260,7 +266,6 @@ static int acpi_pad_idle_cpus(unsigned int num_cpus) set_power_saving_task_num(num_cpus); put_online_cpus(); - return 0; } static uint32_t acpi_pad_idle_cpus_num(void) @@ -368,19 +373,21 @@ static void acpi_pad_remove_sysfs(struct acpi_device *device) static int acpi_pad_pur(acpi_handle handle, int *num_cpus) { struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - acpi_status status; union acpi_object *package; int rev, num, ret = -EINVAL; - status = acpi_evaluate_object(handle, "_PUR", NULL, &buffer); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(acpi_evaluate_object(handle, "_PUR", NULL, &buffer))) + return -EINVAL; + + if (!buffer.length || !buffer.pointer) return -EINVAL; + package = buffer.pointer; if (package->type != ACPI_TYPE_PACKAGE || package->package.count != 2) goto out; rev = package->package.elements[0].integer.value; num = package->package.elements[1].integer.value; - if (rev != 1) + if (rev != 1 || num < 0) goto out; *num_cpus = num; ret = 0; @@ -409,7 +416,7 @@ static void acpi_pad_ost(acpi_handle handle, int stat, static void acpi_pad_handle_notify(acpi_handle handle) { - int num_cpus, ret; + int num_cpus; uint32_t idle_cpus; mutex_lock(&isolated_cpus_lock); @@ -417,12 +424,9 @@ static void acpi_pad_handle_notify(acpi_handle handle) mutex_unlock(&isolated_cpus_lock); return; } - ret = acpi_pad_idle_cpus(num_cpus); + acpi_pad_idle_cpus(num_cpus); idle_cpus = acpi_pad_idle_cpus_num(); - if (!ret) - acpi_pad_ost(handle, 0, idle_cpus); - else - acpi_pad_ost(handle, 1, 0); + acpi_pad_ost(handle, 0, idle_cpus); mutex_unlock(&isolated_cpus_lock); } diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index e7973bc1684..7423052ece5 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -28,7 +28,7 @@ acpi-$(ACPI_FUTURE_USAGE) += hwtimer.o acpi-y += nsaccess.o nsload.o nssearch.o nsxfeval.o \ nsalloc.o nseval.o nsnames.o nsutils.o nsxfname.o \ nsdump.o nsinit.o nsobject.o nswalk.o nsxfobj.o \ - nsparse.o nspredef.o nsrepair.o + nsparse.o nspredef.o nsrepair.o nsrepair2.o acpi-$(ACPI_FUTURE_USAGE) += nsdumpdv.o diff --git a/drivers/acpi/acpica/acconfig.h b/drivers/acpi/acpica/acconfig.h index 8e679ef5b23..a4471e3d385 100644 --- a/drivers/acpi/acpica/acconfig.h +++ b/drivers/acpi/acpica/acconfig.h @@ -103,9 +103,9 @@ #define ACPI_MAX_REFERENCE_COUNT 0x1000 -/* Size of cached memory mapping for system memory operation region */ +/* Default page size for use in mapping memory for operation regions */ -#define ACPI_SYSMEM_REGION_WINDOW_SIZE 4096 +#define ACPI_DEFAULT_PAGE_SIZE 4096 /* Must be power of 2 */ /* owner_id tracking. 8 entries allows for 255 owner_ids */ diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 0bba148a2c6..4ced54f7a5d 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -76,12 +76,9 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node *node, * evgpe - GPE handling and dispatch */ acpi_status -acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info, - u8 type); +acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info); -acpi_status -acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info, - u8 write_to_hardware); +acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info); acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info); @@ -122,9 +119,6 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list); acpi_status -acpi_ev_set_gpe_type(struct acpi_gpe_event_info *gpe_event_info, u8 type); - -acpi_status acpi_ev_check_for_wake_only_gpe(struct acpi_gpe_event_info *gpe_event_info); acpi_status acpi_ev_gpe_initialize(void); diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 81e64f47867..13cb80caacd 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -426,6 +426,8 @@ struct acpi_gpe_event_info { struct acpi_gpe_register_info *register_info; /* Backpointer to register info */ u8 flags; /* Misc info about this GPE */ u8 gpe_number; /* This GPE */ + u8 runtime_count; + u8 wakeup_count; }; /* Information about a GPE register pair, one per each status/enable pair in an array */ diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index 3acd9c6760e..7d9ba6e5755 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -341,6 +341,7 @@ #define ACPI_ERROR_NAMESPACE(s, e) acpi_ns_report_error (AE_INFO, s, e); #define ACPI_ERROR_METHOD(s, n, p, e) acpi_ns_report_method_error (AE_INFO, s, n, p, e); #define ACPI_WARN_PREDEFINED(plist) acpi_ut_predefined_warning plist +#define ACPI_INFO_PREDEFINED(plist) acpi_ut_predefined_info plist #else @@ -349,6 +350,8 @@ #define ACPI_ERROR_NAMESPACE(s, e) #define ACPI_ERROR_METHOD(s, n, p, e) #define ACPI_WARN_PREDEFINED(plist) +#define ACPI_INFO_PREDEFINED(plist) + #endif /* ACPI_NO_ERROR_MESSAGES */ /* diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 09a2764c734..61edb156e8d 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -104,7 +104,8 @@ acpi_ns_walk_namespace(acpi_object_type type, acpi_handle start_object, u32 max_depth, u32 flags, - acpi_walk_callback user_function, + acpi_walk_callback pre_order_visit, + acpi_walk_callback post_order_visit, void *context, void **return_value); struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node @@ -272,7 +273,8 @@ acpi_ns_get_attached_data(struct acpi_namespace_node *node, acpi_object_handler handler, void **data); /* - * nsrepair - return object repair for predefined methods/objects + * nsrepair - General return object repair for all + * predefined methods/objects */ acpi_status acpi_ns_repair_object(struct acpi_predefined_data *data, @@ -285,6 +287,21 @@ acpi_ns_repair_package_list(struct acpi_predefined_data *data, union acpi_operand_object **obj_desc_ptr); /* + * nsrepair2 - Return object repair for specific + * predefined methods/objects + */ +acpi_status +acpi_ns_complex_repairs(struct acpi_predefined_data *data, + struct acpi_namespace_node *node, + acpi_status validate_status, + union acpi_operand_object **return_object_ptr); + +void +acpi_ns_remove_null_elements(struct acpi_predefined_data *data, + u8 package_type, + union acpi_operand_object *obj_desc); + +/* * nssearch - Namespace searching and entry */ acpi_status @@ -342,9 +359,7 @@ acpi_ns_externalize_name(u32 internal_name_length, const char *internal_name, u32 * converted_name_length, char **converted_name); -struct acpi_namespace_node *acpi_ns_map_handle_to_node(acpi_handle handle); - -acpi_handle acpi_ns_convert_entry_to_handle(struct acpi_namespace_node *node); +struct acpi_namespace_node *acpi_ns_validate_handle(acpi_handle handle); void acpi_ns_terminate(void); diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index b39d682a214..07f6e2ea2ee 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -180,7 +180,11 @@ struct acpi_object_method { u8 sync_level; union acpi_operand_object *mutex; u8 *aml_start; - ACPI_INTERNAL_METHOD implementation; + union { + ACPI_INTERNAL_METHOD implementation; + union acpi_operand_object *handler; + } extra; + u32 aml_length; u8 thread_count; acpi_owner_id owner_id; @@ -283,8 +287,10 @@ struct acpi_object_buffer_field { struct acpi_object_notify_handler { ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *node; /* Parent device */ + u32 handler_type; acpi_notify_handler handler; void *context; + struct acpi_object_notify_handler *next; }; struct acpi_object_addr_handler { diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h index cd80d1dd195..57bdaf6ffab 100644 --- a/drivers/acpi/acpica/acpredef.h +++ b/drivers/acpi/acpica/acpredef.h @@ -203,8 +203,9 @@ static const union acpi_predefined_info predefined_names[] = {{"_BCT", 1, ACPI_RTYPE_INTEGER}}, {{"_BDN", 0, ACPI_RTYPE_INTEGER}}, {{"_BFS", 1, 0}}, - {{"_BIF", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (9 Int),(4 Str) */ - {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 9, ACPI_RTYPE_STRING}, 4,0}}, + {{"_BIF", 0, ACPI_RTYPE_PACKAGE} }, /* Fixed-length (9 Int),(4 Str/Buf) */ + {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 9, + ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER}, 4, 0} }, {{"_BIX", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (16 Int),(4 Str) */ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16, ACPI_RTYPE_STRING}, 4, diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 863a264b829..3a451a21a3f 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -386,6 +386,8 @@ u8 acpi_ut_valid_internal_object(void *object); union acpi_operand_object *acpi_ut_create_package_object(u32 count); +union acpi_operand_object *acpi_ut_create_integer_object(u64 value); + union acpi_operand_object *acpi_ut_create_buffer_object(acpi_size buffer_size); union acpi_operand_object *acpi_ut_create_string_object(acpi_size string_size); @@ -481,6 +483,11 @@ acpi_ut_predefined_warning(const char *module_name, char *pathname, u8 node_flags, const char *format, ...); +void ACPI_INTERNAL_VAR_XFACE +acpi_ut_predefined_info(const char *module_name, + u32 line_number, + char *pathname, u8 node_flags, const char *format, ...); + /* Values for Base above (16=Hex, 10=Decimal) */ #define ACPI_ANY_BASE 0 diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c index 3aae13f30c5..f23fa0be6fc 100644 --- a/drivers/acpi/acpica/dsinit.c +++ b/drivers/acpi/acpica/dsinit.c @@ -192,7 +192,7 @@ acpi_ds_initialize_objects(u32 table_index, status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, start_node, ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ds_init_one_object, - &info, NULL); + NULL, &info, NULL); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace")); } diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 567a4899a01..e786f9fd767 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -414,7 +414,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, /* Invoke an internal method if necessary */ if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { - status = obj_desc->method.implementation(next_walk_state); + status = obj_desc->method.extra.implementation(next_walk_state); if (status == AE_OK) { status = AE_CTRL_TERMINATE; } diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c index 7d077bb2f52..0ba19f84ad8 100644 --- a/drivers/acpi/acpica/dsmthdat.c +++ b/drivers/acpi/acpica/dsmthdat.c @@ -409,13 +409,11 @@ acpi_ds_method_data_get_value(u8 type, /* If slack enabled, init the local_x/arg_x to an Integer of value zero */ if (acpi_gbl_enable_interpreter_slack) { - object = - acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); + object = acpi_ut_create_integer_object((u64) 0); if (!object) { return_ACPI_STATUS(AE_NO_MEMORY); } - object->integer.value = 0; node->object = object; } diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index 507e1f0bbdf..9bc1ba07634 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -486,7 +486,7 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, * * Note: technically, this is an error, from ACPI spec: "It is an error * for NumElements to be less than the number of elements in the - * PackageList". However, we just print an error message and + * PackageList". However, we just print a message and * no exception is returned. This provides Windows compatibility. Some * BIOSs will alter the num_elements on the fly, creating this type * of ill-formed package object. @@ -510,9 +510,9 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, arg = arg->common.next; } - ACPI_WARNING((AE_INFO, - "Package List length (0x%X) larger than NumElements count (0x%X), truncated\n", - i, element_count)); + ACPI_INFO((AE_INFO, + "Actual Package length (0x%X) is larger than NumElements field (0x%X), truncated\n", + i, element_count)); } else if (i < element_count) { /* * Arg list (elements) was exhausted, but we did not reach num_elements count. diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index 6de3a99d4cd..b40513dd6a6 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -212,18 +212,19 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state, case ACPI_TYPE_BUFFER: /* - * These types we will allow, but we will change the type. This - * enables some existing code of the form: + * These types we will allow, but we will change the type. + * This enables some existing code of the form: * * Name (DEB, 0) * Scope (DEB) { ... } * - * Note: silently change the type here. On the second pass, we will report - * a warning + * Note: silently change the type here. On the second pass, + * we will report a warning */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n", - path, + "Type override - [%4.4s] had invalid type (%s) " + "for Scope operator, changed to type ANY\n", + acpi_ut_get_node_name(node), acpi_ut_get_type_name(node->type))); node->type = ACPI_TYPE_ANY; @@ -235,8 +236,10 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state, /* All other types are an error */ ACPI_ERROR((AE_INFO, - "Invalid type (%s) for target of Scope operator [%4.4s] (Cannot override)", - acpi_ut_get_type_name(node->type), path)); + "Invalid type (%s) for target of " + "Scope operator [%4.4s] (Cannot override)", + acpi_ut_get_type_name(node->type), + acpi_ut_get_node_name(node))); return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } @@ -639,26 +642,42 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, break; case AML_SCOPE_OP: - /* - * The Path is an object reference to an existing object. - * Don't enter the name into the namespace, but look it up - * for use later. - */ - status = - acpi_ns_lookup(walk_state->scope_info, buffer_ptr, - object_type, ACPI_IMODE_EXECUTE, - ACPI_NS_SEARCH_PARENT, walk_state, &(node)); - if (ACPI_FAILURE(status)) { -#ifdef ACPI_ASL_COMPILER - if (status == AE_NOT_FOUND) { - status = AE_OK; - } else { - ACPI_ERROR_NAMESPACE(buffer_ptr, status); + + /* Special case for Scope(\) -> refers to the Root node */ + + if (op && (op->named.node == acpi_gbl_root_node)) { + node = op->named.node; + + status = + acpi_ds_scope_stack_push(node, object_type, + walk_state); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); } + } else { + /* + * The Path is an object reference to an existing object. + * Don't enter the name into the namespace, but look it up + * for use later. + */ + status = + acpi_ns_lookup(walk_state->scope_info, buffer_ptr, + object_type, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT, walk_state, + &(node)); + if (ACPI_FAILURE(status)) { +#ifdef ACPI_ASL_COMPILER + if (status == AE_NOT_FOUND) { + status = AE_OK; + } else { + ACPI_ERROR_NAMESPACE(buffer_ptr, + status); + } #else - ACPI_ERROR_NAMESPACE(buffer_ptr, status); + ACPI_ERROR_NAMESPACE(buffer_ptr, status); #endif - return_ACPI_STATUS(status); + return_ACPI_STATUS(status); + } } /* @@ -681,15 +700,16 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, case ACPI_TYPE_BUFFER: /* - * These types we will allow, but we will change the type. This - * enables some existing code of the form: + * These types we will allow, but we will change the type. + * This enables some existing code of the form: * * Name (DEB, 0) * Scope (DEB) { ... } */ ACPI_WARNING((AE_INFO, - "Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)", - buffer_ptr, + "Type override - [%4.4s] had invalid type (%s) " + "for Scope operator, changed to type ANY\n", + acpi_ut_get_node_name(node), acpi_ut_get_type_name(node->type))); node->type = ACPI_TYPE_ANY; @@ -701,9 +721,10 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, /* All other types are an error */ ACPI_ERROR((AE_INFO, - "Invalid type (%s) for target of Scope operator [%4.4s]", + "Invalid type (%s) for target of " + "Scope operator [%4.4s] (Cannot override)", acpi_ut_get_type_name(node->type), - buffer_ptr)); + acpi_ut_get_node_name(node))); return (AE_AML_OPERAND_TYPE); } @@ -1031,9 +1052,22 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) } /* - * If we are executing a method, initialize the region + * The op_region is not fully parsed at this time. The only valid + * argument is the space_id. (We must save the address of the + * AML of the address and length operands) + * + * If we have a valid region, initialize it. The namespace is + * unlocked at this point. + * + * Need to unlock interpreter if it is locked (if we are running + * a control method), in order to allow _REG methods to be run + * during acpi_ev_initialize_region. */ if (walk_state->method_node) { + /* + * Executing a method: initialize the region and unlock + * the interpreter + */ status = acpi_ex_create_region(op->named.data, op->named.length, @@ -1042,21 +1076,17 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) if (ACPI_FAILURE(status)) { return (status); } - } - /* - * The op_region is not fully parsed at this time. Only valid - * argument is the space_id. (We must save the address of the - * AML of the address and length operands) - */ + acpi_ex_exit_interpreter(); + } - /* - * If we have a valid region, initialize it - * Namespace is NOT locked at this point. - */ status = acpi_ev_initialize_region (acpi_ns_get_attached_object(node), FALSE); + if (walk_state->method_node) { + acpi_ex_enter_interpreter(); + } + if (ACPI_FAILURE(status)) { /* * If AE_NOT_EXIST is returned, it is not fatal diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index afacf4416c7..0b453467a5a 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -54,54 +54,9 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context); /******************************************************************************* * - * FUNCTION: acpi_ev_set_gpe_type - * - * PARAMETERS: gpe_event_info - GPE to set - * Type - New type - * - * RETURN: Status - * - * DESCRIPTION: Sets the new type for the GPE (wake, run, or wake/run) - * - ******************************************************************************/ - -acpi_status -acpi_ev_set_gpe_type(struct acpi_gpe_event_info *gpe_event_info, u8 type) -{ - acpi_status status; - - ACPI_FUNCTION_TRACE(ev_set_gpe_type); - - /* Validate type and update register enable masks */ - - switch (type) { - case ACPI_GPE_TYPE_WAKE: - case ACPI_GPE_TYPE_RUNTIME: - case ACPI_GPE_TYPE_WAKE_RUN: - break; - - default: - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* Disable the GPE if currently enabled */ - - status = acpi_ev_disable_gpe(gpe_event_info); - - /* Clear the type bits and insert the new Type */ - - gpe_event_info->flags &= ~ACPI_GPE_TYPE_MASK; - gpe_event_info->flags |= type; - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * * FUNCTION: acpi_ev_update_gpe_enable_masks * * PARAMETERS: gpe_event_info - GPE to update - * Type - What to do: ACPI_GPE_DISABLE or - * ACPI_GPE_ENABLE * * RETURN: Status * @@ -110,8 +65,7 @@ acpi_ev_set_gpe_type(struct acpi_gpe_event_info *gpe_event_info, u8 type) ******************************************************************************/ acpi_status -acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info, - u8 type) +acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info) { struct acpi_gpe_register_info *gpe_register_info; u8 register_bit; @@ -127,37 +81,14 @@ acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info, (1 << (gpe_event_info->gpe_number - gpe_register_info->base_gpe_number)); - /* 1) Disable case. Simply clear all enable bits */ - - if (type == ACPI_GPE_DISABLE) { - ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake, - register_bit); - ACPI_CLEAR_BIT(gpe_register_info->enable_for_run, register_bit); - return_ACPI_STATUS(AE_OK); - } - - /* 2) Enable case. Set/Clear the appropriate enable bits */ + ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake, register_bit); + ACPI_CLEAR_BIT(gpe_register_info->enable_for_run, register_bit); - switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) { - case ACPI_GPE_TYPE_WAKE: - ACPI_SET_BIT(gpe_register_info->enable_for_wake, register_bit); - ACPI_CLEAR_BIT(gpe_register_info->enable_for_run, register_bit); - break; - - case ACPI_GPE_TYPE_RUNTIME: - ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake, - register_bit); + if (gpe_event_info->runtime_count) ACPI_SET_BIT(gpe_register_info->enable_for_run, register_bit); - break; - case ACPI_GPE_TYPE_WAKE_RUN: + if (gpe_event_info->wakeup_count) ACPI_SET_BIT(gpe_register_info->enable_for_wake, register_bit); - ACPI_SET_BIT(gpe_register_info->enable_for_run, register_bit); - break; - - default: - return_ACPI_STATUS(AE_BAD_PARAMETER); - } return_ACPI_STATUS(AE_OK); } @@ -167,8 +98,6 @@ acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info, * FUNCTION: acpi_ev_enable_gpe * * PARAMETERS: gpe_event_info - GPE to enable - * write_to_hardware - Enable now, or just mark data structs - * (WAKE GPEs should be deferred) * * RETURN: Status * @@ -176,9 +105,7 @@ acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info, * ******************************************************************************/ -acpi_status -acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info, - u8 write_to_hardware) +acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) { acpi_status status; @@ -186,47 +113,20 @@ acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info, /* Make sure HW enable masks are updated */ - status = - acpi_ev_update_gpe_enable_masks(gpe_event_info, ACPI_GPE_ENABLE); - if (ACPI_FAILURE(status)) { + status = acpi_ev_update_gpe_enable_masks(gpe_event_info); + if (ACPI_FAILURE(status)) return_ACPI_STATUS(status); - } /* Mark wake-enabled or HW enable, or both */ - switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) { - case ACPI_GPE_TYPE_WAKE: - - ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED); - break; - - case ACPI_GPE_TYPE_WAKE_RUN: - - ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED); - - /*lint -fallthrough */ - - case ACPI_GPE_TYPE_RUNTIME: - - ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED); - - if (write_to_hardware) { - - /* Clear the GPE (of stale events), then enable it */ - - status = acpi_hw_clear_gpe(gpe_event_info); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Enable the requested runtime GPE */ - - status = acpi_hw_write_gpe_enable_reg(gpe_event_info); - } - break; + if (gpe_event_info->runtime_count) { + /* Clear the GPE (of stale events), then enable it */ + status = acpi_hw_clear_gpe(gpe_event_info); + if (ACPI_FAILURE(status)) + return_ACPI_STATUS(status); - default: - return_ACPI_STATUS(AE_BAD_PARAMETER); + /* Enable the requested runtime GPE */ + status = acpi_hw_write_gpe_enable_reg(gpe_event_info); } return_ACPI_STATUS(AE_OK); @@ -252,34 +152,9 @@ acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info) /* Make sure HW enable masks are updated */ - status = - acpi_ev_update_gpe_enable_masks(gpe_event_info, ACPI_GPE_DISABLE); - if (ACPI_FAILURE(status)) { + status = acpi_ev_update_gpe_enable_masks(gpe_event_info); + if (ACPI_FAILURE(status)) return_ACPI_STATUS(status); - } - - /* Clear the appropriate enabled flags for this GPE */ - - switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) { - case ACPI_GPE_TYPE_WAKE: - ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED); - break; - - case ACPI_GPE_TYPE_WAKE_RUN: - ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED); - - /* fallthrough */ - - case ACPI_GPE_TYPE_RUNTIME: - - /* Disable the requested runtime GPE */ - - ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED); - break; - - default: - break; - } /* * Even if we don't know the GPE type, make sure that we always @@ -521,7 +396,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) /* Set the GPE flags for return to enabled state */ - (void)acpi_ev_enable_gpe(gpe_event_info, FALSE); + (void)acpi_ev_update_gpe_enable_masks(gpe_event_info); /* * Take a snapshot of the GPE info for this level - we copy the info to diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index a60aaa7635f..3d4c4aca11c 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -258,7 +258,6 @@ acpi_ev_save_method_info(acpi_handle obj_handle, u32 gpe_number; char name[ACPI_NAME_SIZE + 1]; u8 type; - acpi_status status; ACPI_FUNCTION_TRACE(ev_save_method_info); @@ -325,26 +324,20 @@ acpi_ev_save_method_info(acpi_handle obj_handle, /* * Now we can add this information to the gpe_event_info block for use - * during dispatch of this GPE. Default type is RUNTIME, although this may - * change when the _PRW methods are executed later. + * during dispatch of this GPE. */ gpe_event_info = &gpe_block->event_info[gpe_number - gpe_block->block_base_number]; - gpe_event_info->flags = (u8) - (type | ACPI_GPE_DISPATCH_METHOD | ACPI_GPE_TYPE_RUNTIME); + gpe_event_info->flags = (u8) (type | ACPI_GPE_DISPATCH_METHOD); gpe_event_info->dispatch.method_node = (struct acpi_namespace_node *)obj_handle; - /* Update enable mask, but don't enable the HW GPE as of yet */ - - status = acpi_ev_enable_gpe(gpe_event_info, FALSE); - ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "Registered GPE method %s as GPE number 0x%.2X\n", name, gpe_number)); - return_ACPI_STATUS(status); + return_ACPI_STATUS(AE_OK); } /******************************************************************************* @@ -454,20 +447,7 @@ acpi_ev_match_prw_and_gpe(acpi_handle obj_handle, gpe_block-> block_base_number]; - /* Mark GPE for WAKE-ONLY but WAKE_DISABLED */ - - gpe_event_info->flags &= - ~(ACPI_GPE_WAKE_ENABLED | ACPI_GPE_RUN_ENABLED); - - status = - acpi_ev_set_gpe_type(gpe_event_info, ACPI_GPE_TYPE_WAKE); - if (ACPI_FAILURE(status)) { - goto cleanup; - } - - status = - acpi_ev_update_gpe_enable_masks(gpe_event_info, - ACPI_GPE_DISABLE); + gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; } cleanup: @@ -945,8 +925,8 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, status = acpi_ns_walk_namespace(ACPI_TYPE_METHOD, gpe_device, ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK, - acpi_ev_save_method_info, gpe_block, - NULL); + acpi_ev_save_method_info, NULL, + gpe_block, NULL); /* Return the new block */ @@ -989,7 +969,6 @@ acpi_status acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device, struct acpi_gpe_block_info *gpe_block) { - acpi_status status; struct acpi_gpe_event_info *gpe_event_info; struct acpi_gpe_walk_info gpe_info; u32 wake_gpe_count; @@ -1019,42 +998,50 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device, gpe_info.gpe_block = gpe_block; gpe_info.gpe_device = gpe_device; - status = - acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, - acpi_ev_match_prw_and_gpe, &gpe_info, - NULL); + acpi_ev_match_prw_and_gpe, NULL, + &gpe_info, NULL); } /* - * Enable all GPEs in this block that have these attributes: - * 1) are "runtime" or "run/wake" GPEs, and - * 2) have a corresponding _Lxx or _Exx method - * - * Any other GPEs within this block must be enabled via the - * acpi_enable_gpe() external interface. + * Enable all GPEs that have a corresponding method and aren't + * capable of generating wakeups. Any other GPEs within this block + * must be enabled via the acpi_enable_gpe() interface. */ wake_gpe_count = 0; gpe_enabled_count = 0; + if (gpe_device == acpi_gbl_fadt_gpe_device) + gpe_device = NULL; for (i = 0; i < gpe_block->register_count; i++) { - for (j = 0; j < 8; j++) { + for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { + acpi_status status; + acpi_size gpe_index; + int gpe_number; /* Get the info block for this particular GPE */ + gpe_index = (acpi_size)i * ACPI_GPE_REGISTER_WIDTH + j; + gpe_event_info = &gpe_block->event_info[gpe_index]; - gpe_event_info = &gpe_block->event_info[((acpi_size) i * - ACPI_GPE_REGISTER_WIDTH) - + j]; - - if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == - ACPI_GPE_DISPATCH_METHOD) && - (gpe_event_info->flags & ACPI_GPE_TYPE_RUNTIME)) { - gpe_enabled_count++; - } - - if (gpe_event_info->flags & ACPI_GPE_TYPE_WAKE) { + if (gpe_event_info->flags & ACPI_GPE_CAN_WAKE) { wake_gpe_count++; + if (acpi_gbl_leave_wake_gpes_disabled) + continue; } + + if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD)) + continue; + + gpe_number = gpe_index + gpe_block->block_base_number; + status = acpi_enable_gpe(gpe_device, gpe_number, + ACPI_GPE_TYPE_RUNTIME); + if (ACPI_FAILURE(status)) + ACPI_ERROR((AE_INFO, + "Failed to enable GPE %02X\n", + gpe_number)); + else + gpe_enabled_count++; } } @@ -1062,15 +1049,7 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device, "Found %u Wake, Enabled %u Runtime GPEs in this block\n", wake_gpe_count, gpe_enabled_count)); - /* Enable all valid runtime GPEs found above */ - - status = acpi_hw_enable_runtime_gpe_block(NULL, gpe_block, NULL); - if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, "Could not enable GPEs in GpeBlock %p", - gpe_block)); - } - - return_ACPI_STATUS(status); + return_ACPI_STATUS(AE_OK); } /******************************************************************************* diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c index ce224e1eaa8..8f0fac6c436 100644 --- a/drivers/acpi/acpica/evmisc.c +++ b/drivers/acpi/acpica/evmisc.c @@ -259,9 +259,15 @@ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context) handler_obj = notify_info->notify.handler_obj; if (handler_obj) { - handler_obj->notify.handler(notify_info->notify.node, - notify_info->notify.value, - handler_obj->notify.context); + struct acpi_object_notify_handler *notifier; + + notifier = &handler_obj->notify; + while (notifier) { + notifier->handler(notify_info->notify.node, + notify_info->notify.value, + notifier->context); + notifier = notifier->next; + } } /* All done with the info object */ diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 98c7f9c6265..5336d911fbf 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -51,6 +51,10 @@ ACPI_MODULE_NAME("evregion") /* Local prototypes */ +static u8 +acpi_ev_has_default_handler(struct acpi_namespace_node *node, + acpi_adr_space_type space_id); + static acpi_status acpi_ev_reg_run(acpi_handle obj_handle, u32 level, void *context, void **return_value); @@ -142,6 +146,50 @@ acpi_status acpi_ev_install_region_handlers(void) /******************************************************************************* * + * FUNCTION: acpi_ev_has_default_handler + * + * PARAMETERS: Node - Namespace node for the device + * space_id - The address space ID + * + * RETURN: TRUE if default handler is installed, FALSE otherwise + * + * DESCRIPTION: Check if the default handler is installed for the requested + * space ID. + * + ******************************************************************************/ + +static u8 +acpi_ev_has_default_handler(struct acpi_namespace_node *node, + acpi_adr_space_type space_id) +{ + union acpi_operand_object *obj_desc; + union acpi_operand_object *handler_obj; + + /* Must have an existing internal object */ + + obj_desc = acpi_ns_get_attached_object(node); + if (obj_desc) { + handler_obj = obj_desc->device.handler; + + /* Walk the linked list of handlers for this object */ + + while (handler_obj) { + if (handler_obj->address_space.space_id == space_id) { + if (handler_obj->address_space.handler_flags & + ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) { + return (TRUE); + } + } + + handler_obj = handler_obj->address_space.next; + } + } + + return (FALSE); +} + +/******************************************************************************* + * * FUNCTION: acpi_ev_initialize_op_regions * * PARAMETERS: None @@ -169,12 +217,18 @@ acpi_status acpi_ev_initialize_op_regions(void) for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) { /* - * TBD: Make sure handler is the DEFAULT handler, otherwise - * _REG will have already been run. + * Make sure the installed handler is the DEFAULT handler. If not the + * default, the _REG methods will have already been run (when the + * handler was installed) */ - status = acpi_ev_execute_reg_methods(acpi_gbl_root_node, - acpi_gbl_default_address_spaces - [i]); + if (acpi_ev_has_default_handler(acpi_gbl_root_node, + acpi_gbl_default_address_spaces + [i])) { + status = + acpi_ev_execute_reg_methods(acpi_gbl_root_node, + acpi_gbl_default_address_spaces + [i]); + } } (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); @@ -235,23 +289,20 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) * connection status 1 for connecting the handler, 0 for disconnecting * the handler (Passed as a parameter) */ - args[0] = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); + args[0] = + acpi_ut_create_integer_object((u64) region_obj->region.space_id); if (!args[0]) { status = AE_NO_MEMORY; goto cleanup1; } - args[1] = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); + args[1] = acpi_ut_create_integer_object((u64) function); if (!args[1]) { status = AE_NO_MEMORY; goto cleanup2; } - /* Setup the parameter objects */ - - args[0]->integer.value = region_obj->region.space_id; - args[1]->integer.value = function; - args[2] = NULL; + args[2] = NULL; /* Terminate list */ /* Execute the method, no return value */ @@ -667,7 +718,7 @@ acpi_ev_install_handler(acpi_handle obj_handle, /* Convert and validate the device handle */ - node = acpi_ns_map_handle_to_node(obj_handle); + node = acpi_ns_validate_handle(obj_handle); if (!node) { return (AE_BAD_PARAMETER); } @@ -971,8 +1022,8 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node, */ status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, - acpi_ev_install_handler, handler_obj, - NULL); + acpi_ev_install_handler, NULL, + handler_obj, NULL); unlock_and_exit: return_ACPI_STATUS(status); @@ -1008,7 +1059,7 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, */ status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, - &space_id, NULL); + NULL, &space_id, NULL); return_ACPI_STATUS(status); } @@ -1036,7 +1087,7 @@ acpi_ev_reg_run(acpi_handle obj_handle, /* Convert and validate the device handle */ - node = acpi_ns_map_handle_to_node(obj_handle); + node = acpi_ns_validate_handle(obj_handle); if (!node) { return (AE_BAD_PARAMETER); } diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index cf29c495302..ff168052a33 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -575,6 +575,21 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, handler_obj = obj_desc->thermal_zone.handler; break; + case ACPI_TYPE_METHOD: + /* + * If we are executing module level code, the original + * Node's object was replaced by this Method object and we + * saved the handler in the method object. + * + * See acpi_ns_exec_module_code + */ + if (obj_desc->method. + flags & AOPOBJ_MODULE_LEVEL) { + handler_obj = + obj_desc->method.extra.handler; + } + break; + default: /* Ignore other objects */ break; diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index 10b8543dd46..474e2cab603 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -218,6 +218,72 @@ ACPI_EXPORT_SYMBOL(acpi_remove_fixed_event_handler) /******************************************************************************* * + * FUNCTION: acpi_populate_handler_object + * + * PARAMETERS: handler_obj - Handler object to populate + * handler_type - The type of handler: + * ACPI_SYSTEM_NOTIFY: system_handler (00-7f) + * ACPI_DEVICE_NOTIFY: driver_handler (80-ff) + * ACPI_ALL_NOTIFY: both system and device + * handler - Address of the handler + * context - Value passed to the handler on each GPE + * next - Address of a handler object to link to + * + * RETURN: None + * + * DESCRIPTION: Populate a handler object. + * + ******************************************************************************/ +static void +acpi_populate_handler_object(struct acpi_object_notify_handler *handler_obj, + u32 handler_type, + acpi_notify_handler handler, void *context, + struct acpi_object_notify_handler *next) +{ + handler_obj->handler_type = handler_type; + handler_obj->handler = handler; + handler_obj->context = context; + handler_obj->next = next; +} + +/******************************************************************************* + * + * FUNCTION: acpi_add_handler_object + * + * PARAMETERS: parent_obj - Parent of the new object + * handler - Address of the handler + * context - Value passed to the handler on each GPE + * + * RETURN: Status + * + * DESCRIPTION: Create a new handler object and populate it. + * + ******************************************************************************/ +static acpi_status +acpi_add_handler_object(struct acpi_object_notify_handler *parent_obj, + acpi_notify_handler handler, void *context) +{ + struct acpi_object_notify_handler *handler_obj; + + /* The parent must not be a defice notify handler object. */ + if (parent_obj->handler_type & ACPI_DEVICE_NOTIFY) + return AE_BAD_PARAMETER; + + handler_obj = ACPI_ALLOCATE_ZEROED(sizeof(*handler_obj)); + if (!handler_obj) + return AE_NO_MEMORY; + + acpi_populate_handler_object(handler_obj, + ACPI_SYSTEM_NOTIFY, + handler, context, + parent_obj->next); + parent_obj->next = handler_obj; + + return AE_OK; +} + +/******************************************************************************* + * * FUNCTION: acpi_install_notify_handler * * PARAMETERS: Device - The device for which notifies will be handled @@ -259,7 +325,7 @@ acpi_install_notify_handler(acpi_handle device, /* Convert and validate the device handle */ - node = acpi_ns_map_handle_to_node(device); + node = acpi_ns_validate_handle(device); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; @@ -316,15 +382,32 @@ acpi_install_notify_handler(acpi_handle device, obj_desc = acpi_ns_get_attached_object(node); if (obj_desc) { - /* Object exists - make sure there's no handler */ + /* Object exists. */ - if (((handler_type & ACPI_SYSTEM_NOTIFY) && - obj_desc->common_notify.system_notify) || - ((handler_type & ACPI_DEVICE_NOTIFY) && - obj_desc->common_notify.device_notify)) { + /* For a device notify, make sure there's no handler. */ + if ((handler_type & ACPI_DEVICE_NOTIFY) && + obj_desc->common_notify.device_notify) { status = AE_ALREADY_EXISTS; goto unlock_and_exit; } + + /* System notifies may have more handlers installed. */ + notify_obj = obj_desc->common_notify.system_notify; + + if ((handler_type & ACPI_SYSTEM_NOTIFY) && notify_obj) { + struct acpi_object_notify_handler *parent_obj; + + if (handler_type & ACPI_DEVICE_NOTIFY) { + status = AE_ALREADY_EXISTS; + goto unlock_and_exit; + } + + parent_obj = ¬ify_obj->notify; + status = acpi_add_handler_object(parent_obj, + handler, + context); + goto unlock_and_exit; + } } else { /* Create a new object */ @@ -356,9 +439,10 @@ acpi_install_notify_handler(acpi_handle device, goto unlock_and_exit; } - notify_obj->notify.node = node; - notify_obj->notify.handler = handler; - notify_obj->notify.context = context; + acpi_populate_handler_object(¬ify_obj->notify, + handler_type, + handler, context, + NULL); if (handler_type & ACPI_SYSTEM_NOTIFY) { obj_desc->common_notify.system_notify = notify_obj; @@ -418,6 +502,10 @@ acpi_remove_notify_handler(acpi_handle device, goto exit; } + + /* Make sure all deferred tasks are completed */ + acpi_os_wait_events_complete(NULL); + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { goto exit; @@ -425,7 +513,7 @@ acpi_remove_notify_handler(acpi_handle device, /* Convert and validate the device handle */ - node = acpi_ns_map_handle_to_node(device); + node = acpi_ns_validate_handle(device); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; @@ -445,15 +533,6 @@ acpi_remove_notify_handler(acpi_handle device, goto unlock_and_exit; } - /* Make sure all deferred tasks are completed */ - - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - acpi_os_wait_events_complete(NULL); - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - goto exit; - } - if (handler_type & ACPI_SYSTEM_NOTIFY) { acpi_gbl_system_notify.node = NULL; acpi_gbl_system_notify.handler = NULL; @@ -488,28 +567,60 @@ acpi_remove_notify_handler(acpi_handle device, /* Object exists - make sure there's an existing handler */ if (handler_type & ACPI_SYSTEM_NOTIFY) { + struct acpi_object_notify_handler *handler_obj; + struct acpi_object_notify_handler *parent_obj; + notify_obj = obj_desc->common_notify.system_notify; if (!notify_obj) { status = AE_NOT_EXIST; goto unlock_and_exit; } - if (notify_obj->notify.handler != handler) { + handler_obj = ¬ify_obj->notify; + parent_obj = NULL; + while (handler_obj->handler != handler) { + if (handler_obj->next) { + parent_obj = handler_obj; + handler_obj = handler_obj->next; + } else { + break; + } + } + + if (handler_obj->handler != handler) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } - /* Make sure all deferred tasks are completed */ - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - acpi_os_wait_events_complete(NULL); - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - goto exit; + /* + * Remove the handler. There are three possible cases. + * First, we may need to remove a non-embedded object. + * Second, we may need to remove the embedded object's + * handler data, while non-embedded objects exist. + * Finally, we may need to remove the embedded object + * entirely along with its container. + */ + if (parent_obj) { + /* Non-embedded object is being removed. */ + parent_obj->next = handler_obj->next; + ACPI_FREE(handler_obj); + } else if (notify_obj->notify.next) { + /* + * The handler matches the embedded object, but + * there are more handler objects in the list. + * Replace the embedded object's data with the + * first next object's data and remove that + * object. + */ + parent_obj = ¬ify_obj->notify; + handler_obj = notify_obj->notify.next; + *parent_obj = *handler_obj; + ACPI_FREE(handler_obj); + } else { + /* No more handler objects in the list. */ + obj_desc->common_notify.system_notify = NULL; + acpi_ut_remove_reference(notify_obj); } - - /* Remove the handler */ - obj_desc->common_notify.system_notify = NULL; - acpi_ut_remove_reference(notify_obj); } if (handler_type & ACPI_DEVICE_NOTIFY) { @@ -523,14 +634,6 @@ acpi_remove_notify_handler(acpi_handle device, status = AE_BAD_PARAMETER; goto unlock_and_exit; } - /* Make sure all deferred tasks are completed */ - - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - acpi_os_wait_events_complete(NULL); - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - goto exit; - } /* Remove the handler */ obj_desc->common_notify.device_notify = NULL; @@ -617,13 +720,6 @@ acpi_install_gpe_handler(acpi_handle gpe_device, handler->context = context; handler->method_node = gpe_event_info->dispatch.method_node; - /* Disable the GPE before installing the handler */ - - status = acpi_ev_disable_gpe(gpe_event_info); - if (ACPI_FAILURE(status)) { - goto unlock_and_exit; - } - /* Install the handler */ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); @@ -707,13 +803,6 @@ acpi_remove_gpe_handler(acpi_handle gpe_device, goto unlock_and_exit; } - /* Disable the GPE before removing the handler */ - - status = acpi_ev_disable_gpe(gpe_event_info); - if (ACPI_FAILURE(status)) { - goto unlock_and_exit; - } - /* Make sure all deferred tasks are completed */ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index 4721f58fe42..124c157215b 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -201,23 +201,27 @@ ACPI_EXPORT_SYMBOL(acpi_enable_event) /******************************************************************************* * - * FUNCTION: acpi_set_gpe_type + * FUNCTION: acpi_set_gpe * * PARAMETERS: gpe_device - Parent GPE Device * gpe_number - GPE level within the GPE block - * Type - New GPE type + * action - Enable or disable + * Called from ISR or not * * RETURN: Status * - * DESCRIPTION: Set the type of an individual GPE + * DESCRIPTION: Enable or disable an ACPI event (general purpose) * ******************************************************************************/ -acpi_status acpi_set_gpe_type(acpi_handle gpe_device, u32 gpe_number, u8 type) +acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action) { acpi_status status = AE_OK; + acpi_cpu_flags flags; struct acpi_gpe_event_info *gpe_event_info; - ACPI_FUNCTION_TRACE(acpi_set_gpe_type); + ACPI_FUNCTION_TRACE(acpi_set_gpe); + + flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); /* Ensure that we have a valid GPE number */ @@ -227,19 +231,29 @@ acpi_status acpi_set_gpe_type(acpi_handle gpe_device, u32 gpe_number, u8 type) goto unlock_and_exit; } - if ((gpe_event_info->flags & ACPI_GPE_TYPE_MASK) == type) { - return_ACPI_STATUS(AE_OK); - } + /* Perform the action */ + + switch (action) { + case ACPI_GPE_ENABLE: + status = acpi_ev_enable_gpe(gpe_event_info); + break; - /* Set the new type (will disable GPE if currently enabled) */ + case ACPI_GPE_DISABLE: + status = acpi_ev_disable_gpe(gpe_event_info); + break; - status = acpi_ev_set_gpe_type(gpe_event_info, type); + default: + ACPI_ERROR((AE_INFO, "Invalid action\n")); + status = AE_BAD_PARAMETER; + break; + } unlock_and_exit: + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return_ACPI_STATUS(status); } -ACPI_EXPORT_SYMBOL(acpi_set_gpe_type) +ACPI_EXPORT_SYMBOL(acpi_set_gpe) /******************************************************************************* * @@ -247,15 +261,14 @@ ACPI_EXPORT_SYMBOL(acpi_set_gpe_type) * * PARAMETERS: gpe_device - Parent GPE Device * gpe_number - GPE level within the GPE block - * Flags - Just enable, or also wake enable? - * Called from ISR or not + * type - Purpose the GPE will be used for * * RETURN: Status * - * DESCRIPTION: Enable an ACPI event (general purpose) + * DESCRIPTION: Take a reference to a GPE and enable it if necessary * ******************************************************************************/ -acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number) +acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 type) { acpi_status status = AE_OK; acpi_cpu_flags flags; @@ -263,6 +276,9 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number) ACPI_FUNCTION_TRACE(acpi_enable_gpe); + if (type & ~ACPI_GPE_TYPE_WAKE_RUN) + return_ACPI_STATUS(AE_BAD_PARAMETER); + flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); /* Ensure that we have a valid GPE number */ @@ -273,15 +289,32 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number) goto unlock_and_exit; } - /* Perform the enable */ + if (type & ACPI_GPE_TYPE_RUNTIME) { + if (++gpe_event_info->runtime_count == 1) { + status = acpi_ev_enable_gpe(gpe_event_info); + if (ACPI_FAILURE(status)) + gpe_event_info->runtime_count--; + } + } + + if (type & ACPI_GPE_TYPE_WAKE) { + if (!(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } - status = acpi_ev_enable_gpe(gpe_event_info, TRUE); + /* + * Wake-up GPEs are only enabled right prior to putting the + * system into a sleep state. + */ + if (++gpe_event_info->wakeup_count == 1) + acpi_ev_update_gpe_enable_masks(gpe_event_info); + } - unlock_and_exit: +unlock_and_exit: acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return_ACPI_STATUS(status); } - ACPI_EXPORT_SYMBOL(acpi_enable_gpe) /******************************************************************************* @@ -290,15 +323,14 @@ ACPI_EXPORT_SYMBOL(acpi_enable_gpe) * * PARAMETERS: gpe_device - Parent GPE Device * gpe_number - GPE level within the GPE block - * Flags - Just disable, or also wake disable? - * Called from ISR or not + * type - Purpose the GPE won't be used for any more * * RETURN: Status * - * DESCRIPTION: Disable an ACPI event (general purpose) + * DESCRIPTION: Release a reference to a GPE and disable it if necessary * ******************************************************************************/ -acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number) +acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 type) { acpi_status status = AE_OK; acpi_cpu_flags flags; @@ -306,6 +338,9 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number) ACPI_FUNCTION_TRACE(acpi_disable_gpe); + if (type & ~ACPI_GPE_TYPE_WAKE_RUN) + return_ACPI_STATUS(AE_BAD_PARAMETER); + flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); /* Ensure that we have a valid GPE number */ @@ -315,13 +350,24 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number) goto unlock_and_exit; } - status = acpi_ev_disable_gpe(gpe_event_info); + if ((type & ACPI_GPE_TYPE_RUNTIME) && gpe_event_info->runtime_count) { + if (--gpe_event_info->runtime_count == 0) + status = acpi_ev_disable_gpe(gpe_event_info); + } + + if ((type & ACPI_GPE_TYPE_WAKE) && gpe_event_info->wakeup_count) { + /* + * Wake-up GPEs are not enabled after leaving system sleep + * states, so we don't need to disable them here. + */ + if (--gpe_event_info->wakeup_count == 0) + acpi_ev_update_gpe_enable_masks(gpe_event_info); + } unlock_and_exit: acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return_ACPI_STATUS(status); } - ACPI_EXPORT_SYMBOL(acpi_disable_gpe) /******************************************************************************* @@ -610,7 +656,7 @@ acpi_install_gpe_block(acpi_handle gpe_device, return (status); } - node = acpi_ns_map_handle_to_node(gpe_device); + node = acpi_ns_validate_handle(gpe_device); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; @@ -698,7 +744,7 @@ acpi_status acpi_remove_gpe_block(acpi_handle gpe_device) return (status); } - node = acpi_ns_map_handle_to_node(gpe_device); + node = acpi_ns_validate_handle(gpe_device); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c index 7c3d2d356ff..c98aa7c2d67 100644 --- a/drivers/acpi/acpica/evxfregn.c +++ b/drivers/acpi/acpica/evxfregn.c @@ -89,7 +89,7 @@ acpi_install_address_space_handler(acpi_handle device, /* Convert and validate the device handle */ - node = acpi_ns_map_handle_to_node(device); + node = acpi_ns_validate_handle(device); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; @@ -155,7 +155,7 @@ acpi_remove_address_space_handler(acpi_handle device, /* Convert and validate the device handle */ - node = acpi_ns_map_handle_to_node(device); + node = acpi_ns_validate_handle(device); if (!node || ((node->type != ACPI_TYPE_DEVICE) && (node->type != ACPI_TYPE_PROCESSOR) && diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 24afef81af3..46adfa541cb 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -170,14 +170,12 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, /* Table not found, return an Integer=0 and AE_OK */ - ddb_handle = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); + ddb_handle = acpi_ut_create_integer_object((u64) 0); if (!ddb_handle) { return_ACPI_STATUS(AE_NO_MEMORY); } - ddb_handle->integer.value = 0; *return_desc = ddb_handle; - return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c index 37d0d39e60a..51d5f224f9f 100644 --- a/drivers/acpi/acpica/exconvrt.c +++ b/drivers/acpi/acpica/exconvrt.c @@ -167,7 +167,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc, /* Create a new integer */ - return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); + return_desc = acpi_ut_create_integer_object(result); if (!return_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -177,7 +177,6 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc, /* Save the Result */ - return_desc->integer.value = result; acpi_ex_truncate_for32bit_table(return_desc); *result_desc = return_desc; return_ACPI_STATUS(AE_OK); diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index 0b33d6c887b..1588a2d660e 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -162,13 +162,12 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, } else { /* Field will fit within an Integer (normal case) */ - buffer_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); + buffer_desc = acpi_ut_create_integer_object((u64) 0); if (!buffer_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } length = acpi_gbl_integer_byte_width; - buffer_desc->integer.value = 0; buffer = &buffer_desc->integer.value; } diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index 2f0114202b0..3c456bd575d 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -375,6 +375,15 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED); } + /* Must have a valid thread ID */ + + if (!walk_state->thread) { + ACPI_ERROR((AE_INFO, + "Cannot release Mutex [%4.4s], null thread info", + acpi_ut_get_node_name(obj_desc->mutex.node))); + return_ACPI_STATUS(AE_AML_INTERNAL); + } + /* * The Mutex is owned, but this thread must be the owner. * Special case for Global Lock, any thread can release @@ -392,15 +401,6 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, return_ACPI_STATUS(AE_AML_NOT_OWNER); } - /* Must have a valid thread ID */ - - if (!walk_state->thread) { - ACPI_ERROR((AE_INFO, - "Cannot release Mutex [%4.4s], null thread info", - acpi_ut_get_node_name(obj_desc->mutex.node))); - return_ACPI_STATUS(AE_AML_INTERNAL); - } - /* * The sync level of the mutex must be equal to the current sync level. In * other words, the current level means that at least one mutex at that diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c index 9635d21e568..752fe48b2d2 100644 --- a/drivers/acpi/acpica/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -100,12 +100,12 @@ acpi_status acpi_ex_opcode_0A_0T_1R(struct acpi_walk_state *walk_state) /* Create a return object of type Integer */ - return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); + return_desc = + acpi_ut_create_integer_object(acpi_os_get_timer()); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } - return_desc->integer.value = acpi_os_get_timer(); break; default: /* Unknown opcode */ @@ -599,7 +599,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) switch (walk_state->opcode) { case AML_LNOT_OP: /* LNot (Operand) */ - return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); + return_desc = acpi_ut_create_integer_object((u64) 0); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; @@ -702,13 +702,11 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) /* Allocate a descriptor to hold the type. */ - return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); + return_desc = acpi_ut_create_integer_object((u64) type); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } - - return_desc->integer.value = type; break; case AML_SIZE_OF_OP: /* size_of (source_object) */ @@ -777,13 +775,11 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) * Now that we have the size of the object, create a result * object to hold the value */ - return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); + return_desc = acpi_ut_create_integer_object(value); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } - - return_desc->integer.value = value; break; case AML_REF_OF_OP: /* ref_of (source_object) */ @@ -946,24 +942,24 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) * NOTE: index into a buffer is NOT a pointer to a * sub-buffer of the main buffer, it is only a pointer to a * single element (byte) of the buffer! + * + * Since we are returning the value of the buffer at the + * indexed location, we don't need to add an additional + * reference to the buffer itself. */ return_desc = - acpi_ut_create_internal_object - (ACPI_TYPE_INTEGER); + acpi_ut_create_integer_object((u64) + temp_desc-> + buffer. + pointer + [operand + [0]-> + reference. + value]); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } - - /* - * Since we are returning the value of the buffer at the - * indexed location, we don't need to add an additional - * reference to the buffer itself. - */ - return_desc->integer.value = - temp_desc->buffer. - pointer[operand[0]->reference. - value]; break; case ACPI_TYPE_PACKAGE: diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c index ae43f7670a6..295542e6bd5 100644 --- a/drivers/acpi/acpica/exoparg6.c +++ b/drivers/acpi/acpica/exoparg6.c @@ -253,18 +253,15 @@ acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state) } /* Create an integer for the return value */ + /* Default return value is ACPI_INTEGER_MAX if no match found */ - return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); + return_desc = acpi_ut_create_integer_object(ACPI_INTEGER_MAX); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } - /* Default return value if no match found */ - - return_desc->integer.value = ACPI_INTEGER_MAX; - /* * Examine each element until a match is found. Both match conditions * must be satisfied for a match to occur. Within the loop, diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c index 3a54b737d2d..2bd83ac57c3 100644 --- a/drivers/acpi/acpica/exregion.c +++ b/drivers/acpi/acpica/exregion.c @@ -77,7 +77,8 @@ acpi_ex_system_memory_space_handler(u32 function, void *logical_addr_ptr = NULL; struct acpi_mem_space_context *mem_info = region_context; u32 length; - acpi_size window_size; + acpi_size map_length; + acpi_size page_boundary_map_length; #ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED u32 remainder; #endif @@ -144,25 +145,39 @@ acpi_ex_system_memory_space_handler(u32 function, } /* - * Don't attempt to map memory beyond the end of the region, and - * constrain the maximum mapping size to something reasonable. + * Attempt to map from the requested address to the end of the region. + * However, we will never map more than one page, nor will we cross + * a page boundary. */ - window_size = (acpi_size) + map_length = (acpi_size) ((mem_info->address + mem_info->length) - address); - if (window_size > ACPI_SYSMEM_REGION_WINDOW_SIZE) { - window_size = ACPI_SYSMEM_REGION_WINDOW_SIZE; + /* + * If mapping the entire remaining portion of the region will cross + * a page boundary, just map up to the page boundary, do not cross. + * On some systems, crossing a page boundary while mapping regions + * can cause warnings if the pages have different attributes + * due to resource management + */ + page_boundary_map_length = + ACPI_ROUND_UP(address, ACPI_DEFAULT_PAGE_SIZE) - address; + + if (!page_boundary_map_length) { + page_boundary_map_length = ACPI_DEFAULT_PAGE_SIZE; + } + + if (map_length > page_boundary_map_length) { + map_length = page_boundary_map_length; } /* Create a new mapping starting at the address given */ - mem_info->mapped_logical_address = - acpi_os_map_memory((acpi_physical_address) address, window_size); + mem_info->mapped_logical_address = acpi_os_map_memory((acpi_physical_address) address, map_length); if (!mem_info->mapped_logical_address) { ACPI_ERROR((AE_INFO, "Could not map memory at %8.8X%8.8X, size %X", ACPI_FORMAT_NATIVE_UINT(address), - (u32) window_size)); + (u32) map_length)); mem_info->mapped_length = 0; return_ACPI_STATUS(AE_NO_MEMORY); } @@ -170,7 +185,7 @@ acpi_ex_system_memory_space_handler(u32 function, /* Save the physical address and mapping size */ mem_info->mapped_physical_address = address; - mem_info->mapped_length = window_size; + mem_info->mapped_length = map_length; } /* diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index 9c3cdbe2d82..d622ba77000 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -165,7 +165,7 @@ acpi_status acpi_ns_root_initialize(void) obj_desc->method.method_flags = AML_METHOD_INTERNAL_ONLY; - obj_desc->method.implementation = + obj_desc->method.extra.implementation = acpi_ut_osi_implementation; #endif break; diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c index 2bad613db73..e37836e27e2 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -180,7 +180,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle, return (AE_OK); } - this_node = acpi_ns_map_handle_to_node(obj_handle); + this_node = acpi_ns_validate_handle(obj_handle); if (!this_node) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid object handle %p\n", obj_handle)); @@ -634,8 +634,8 @@ acpi_ns_dump_objects(acpi_object_type type, (void)acpi_ns_walk_namespace(type, start_handle, max_depth, ACPI_NS_WALK_NO_UNLOCK | ACPI_NS_WALK_TEMP_NODES, - acpi_ns_dump_one_object, (void *)&info, - NULL); + acpi_ns_dump_one_object, NULL, + (void *)&info, NULL); } #endif /* ACPI_FUTURE_USAGE */ diff --git a/drivers/acpi/acpica/nsdumpdv.c b/drivers/acpi/acpica/nsdumpdv.c index 0fe87f1aef1..36be7f0e97e 100644 --- a/drivers/acpi/acpica/nsdumpdv.c +++ b/drivers/acpi/acpica/nsdumpdv.c @@ -131,7 +131,8 @@ void acpi_ns_dump_root_devices(void) status = acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, sys_bus_handle, ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK, - acpi_ns_dump_one_device, NULL, NULL); + acpi_ns_dump_one_device, NULL, NULL, + NULL); } #endif diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c index 846d1132feb..af9fe910373 100644 --- a/drivers/acpi/acpica/nseval.c +++ b/drivers/acpi/acpica/nseval.c @@ -366,50 +366,88 @@ static void acpi_ns_exec_module_code(union acpi_operand_object *method_obj, struct acpi_evaluate_info *info) { - union acpi_operand_object *root_obj; + union acpi_operand_object *parent_obj; + struct acpi_namespace_node *parent_node; + acpi_object_type type; acpi_status status; ACPI_FUNCTION_TRACE(ns_exec_module_code); + /* + * Get the parent node. We cheat by using the next_object field + * of the method object descriptor. + */ + parent_node = ACPI_CAST_PTR(struct acpi_namespace_node, + method_obj->method.next_object); + type = acpi_ns_get_type(parent_node); + + /* + * Get the region handler and save it in the method object. We may need + * this if an operation region declaration causes a _REG method to be run. + * + * We can't do this in acpi_ps_link_module_code because + * acpi_gbl_root_node->Object is NULL at PASS1. + */ + if ((type == ACPI_TYPE_DEVICE) && parent_node->object) { + method_obj->method.extra.handler = + parent_node->object->device.handler; + } + + /* Must clear next_object (acpi_ns_attach_object needs the field) */ + + method_obj->method.next_object = NULL; + /* Initialize the evaluation information block */ ACPI_MEMSET(info, 0, sizeof(struct acpi_evaluate_info)); - info->prefix_node = acpi_gbl_root_node; + info->prefix_node = parent_node; /* - * Get the currently attached root object. Add a reference, because the + * Get the currently attached parent object. Add a reference, because the * ref count will be decreased when the method object is installed to - * the root node. + * the parent node. */ - root_obj = acpi_ns_get_attached_object(acpi_gbl_root_node); - acpi_ut_add_reference(root_obj); + parent_obj = acpi_ns_get_attached_object(parent_node); + if (parent_obj) { + acpi_ut_add_reference(parent_obj); + } - /* Install the method (module-level code) in the root node */ + /* Install the method (module-level code) in the parent node */ - status = acpi_ns_attach_object(acpi_gbl_root_node, method_obj, + status = acpi_ns_attach_object(parent_node, method_obj, ACPI_TYPE_METHOD); if (ACPI_FAILURE(status)) { goto exit; } - /* Execute the root node as a control method */ + /* Execute the parent node as a control method */ status = acpi_ns_evaluate(info); ACPI_DEBUG_PRINT((ACPI_DB_INIT, "Executed module-level code at %p\n", method_obj->method.aml_start)); + /* Delete a possible implicit return value (in slack mode) */ + + if (info->return_object) { + acpi_ut_remove_reference(info->return_object); + } + /* Detach the temporary method object */ - acpi_ns_detach_object(acpi_gbl_root_node); + acpi_ns_detach_object(parent_node); - /* Restore the original root object */ + /* Restore the original parent object */ - status = - acpi_ns_attach_object(acpi_gbl_root_node, root_obj, - ACPI_TYPE_DEVICE); + if (parent_obj) { + status = acpi_ns_attach_object(parent_node, parent_obj, type); + } else { + parent_node->type = (u8)type; + } exit: - acpi_ut_remove_reference(root_obj); + if (parent_obj) { + acpi_ut_remove_reference(parent_obj); + } return_VOID; } diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c index 1d5b360eb25..4f8abac231d 100644 --- a/drivers/acpi/acpica/nsinit.c +++ b/drivers/acpi/acpica/nsinit.c @@ -96,7 +96,7 @@ acpi_status acpi_ns_initialize_objects(void) /* Walk entire namespace from the supplied root */ status = acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, acpi_ns_init_one_object, + ACPI_UINT32_MAX, acpi_ns_init_one_object, NULL, &info, NULL); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace")); @@ -156,7 +156,8 @@ acpi_status acpi_ns_initialize_devices(void) status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, FALSE, - acpi_ns_find_ini_methods, &info, NULL); + acpi_ns_find_ini_methods, NULL, &info, + NULL); if (ACPI_FAILURE(status)) { goto error_exit; } @@ -189,7 +190,8 @@ acpi_status acpi_ns_initialize_devices(void) status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, FALSE, - acpi_ns_init_one_device, &info, NULL); + acpi_ns_init_one_device, NULL, &info, + NULL); ACPI_FREE(info.evaluate_info); if (ACPI_FAILURE(status)) { diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index af8e6bcee07..8f9a4875ce2 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -232,7 +232,7 @@ acpi_ns_handle_to_pathname(acpi_handle target_handle, ACPI_FUNCTION_TRACE_PTR(ns_handle_to_pathname, target_handle); - node = acpi_ns_map_handle_to_node(target_handle); + node = acpi_ns_validate_handle(target_handle); if (!node) { return_ACPI_STATUS(AE_BAD_PARAMETER); } diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index f8427afeebd..d34fa59548f 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -216,23 +216,38 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, data->pathname = pathname; /* - * Check that the type of the return object is what is expected for - * this predefined name + * Check that the type of the main return object is what is expected + * for this predefined name */ status = acpi_ns_check_object_type(data, return_object_ptr, predefined->info.expected_btypes, ACPI_NOT_PACKAGE_ELEMENT); if (ACPI_FAILURE(status)) { - goto check_validation_status; + goto exit; } - /* For returned Package objects, check the type of all sub-objects */ - - if (return_object->common.type == ACPI_TYPE_PACKAGE) { + /* + * For returned Package objects, check the type of all sub-objects. + * Note: Package may have been newly created by call above. + */ + if ((*return_object_ptr)->common.type == ACPI_TYPE_PACKAGE) { status = acpi_ns_check_package(data, return_object_ptr); + if (ACPI_FAILURE(status)) { + goto exit; + } } -check_validation_status: + /* + * The return object was OK, or it was successfully repaired above. + * Now make some additional checks such as verifying that package + * objects are sorted correctly (if required) or buffer objects have + * the correct data width (bytes vs. dwords). These repairs are + * performed on a per-name basis, i.e., the code is specific to + * particular predefined names. + */ + status = acpi_ns_complex_repairs(data, node, status, return_object_ptr); + +exit: /* * If the object validation failed or if we successfully repaired one * or more objects, mark the parent node to suppress further warning @@ -421,6 +436,13 @@ acpi_ns_check_package(struct acpi_predefined_data *data, data->pathname, package->ret_info.type, return_object->package.count)); + /* + * For variable-length Packages, we can safely remove all embedded + * and trailing NULL package elements + */ + acpi_ns_remove_null_elements(data, package->ret_info.type, + return_object); + /* Extract package count and elements array */ elements = return_object->package.elements; @@ -455,11 +477,11 @@ acpi_ns_check_package(struct acpi_predefined_data *data, if (count < expected_count) { goto package_too_small; } else if (count > expected_count) { - ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, - data->node_flags, - "Return Package is larger than needed - " - "found %u, expected %u", count, - expected_count)); + ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, + "%s: Return Package is larger than needed - " + "found %u, expected %u\n", + data->pathname, count, + expected_count)); } /* Validate all elements of the returned package */ @@ -601,7 +623,8 @@ acpi_ns_check_package(struct acpi_predefined_data *data, * there is only one entry). We may be able to repair this by * wrapping the returned Package with a new outer Package. */ - if ((*elements)->common.type != ACPI_TYPE_PACKAGE) { + if (*elements + && ((*elements)->common.type != ACPI_TYPE_PACKAGE)) { /* Create the new outer package and populate it */ @@ -677,8 +700,13 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data, u32 i; u32 j; - /* Validate each sub-Package in the parent Package */ - + /* + * Validate each sub-Package in the parent Package + * + * 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. + */ for (i = 0; i < count; i++) { sub_package = *elements; sub_elements = sub_package->package.elements; diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c index db2b2a99c3a..4fd1bdb056b 100644 --- a/drivers/acpi/acpica/nsrepair.c +++ b/drivers/acpi/acpica/nsrepair.c @@ -44,13 +44,53 @@ #include <acpi/acpi.h> #include "accommon.h" #include "acnamesp.h" -#include "acpredef.h" +#include "acinterp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsrepair") /******************************************************************************* * + * This module attempts to repair or convert objects returned by the + * predefined methods to an object type that is expected, as per the ACPI + * specification. The need for this code is dictated by the many machines that + * return incorrect types for the standard predefined methods. Performing these + * conversions here, in one place, eliminates the need for individual ACPI + * device drivers to do the same. Note: Most of these conversions are different + * than the internal object conversion routines used for implicit object + * conversion. + * + * The following conversions can be performed as necessary: + * + * Integer -> String + * Integer -> Buffer + * String -> Integer + * String -> Buffer + * Buffer -> Integer + * Buffer -> String + * Buffer -> Package of Integers + * Package -> Package of one Package + * + ******************************************************************************/ +/* Local prototypes */ +static acpi_status +acpi_ns_convert_to_integer(union acpi_operand_object *original_object, + union acpi_operand_object **return_object); + +static acpi_status +acpi_ns_convert_to_string(union acpi_operand_object *original_object, + union acpi_operand_object **return_object); + +static acpi_status +acpi_ns_convert_to_buffer(union acpi_operand_object *original_object, + union acpi_operand_object **return_object); + +static acpi_status +acpi_ns_convert_to_package(union acpi_operand_object *original_object, + union acpi_operand_object **return_object); + +/******************************************************************************* + * * FUNCTION: acpi_ns_repair_object * * PARAMETERS: Data - Pointer to validation data structure @@ -67,6 +107,7 @@ ACPI_MODULE_NAME("nsrepair") * not expected. * ******************************************************************************/ + acpi_status acpi_ns_repair_object(struct acpi_predefined_data *data, u32 expected_btypes, @@ -75,26 +116,206 @@ acpi_ns_repair_object(struct acpi_predefined_data *data, { union acpi_operand_object *return_object = *return_object_ptr; union acpi_operand_object *new_object; - acpi_size length; + acpi_status status; + + ACPI_FUNCTION_NAME(ns_repair_object); + + /* + * At this point, we know that the type of the returned object was not + * one of the expected types for this predefined name. Attempt to + * repair the object by converting it to one of the expected object + * types for this predefined name. + */ + if (expected_btypes & ACPI_RTYPE_INTEGER) { + status = acpi_ns_convert_to_integer(return_object, &new_object); + if (ACPI_SUCCESS(status)) { + goto object_repaired; + } + } + if (expected_btypes & ACPI_RTYPE_STRING) { + status = acpi_ns_convert_to_string(return_object, &new_object); + if (ACPI_SUCCESS(status)) { + goto object_repaired; + } + } + if (expected_btypes & ACPI_RTYPE_BUFFER) { + status = acpi_ns_convert_to_buffer(return_object, &new_object); + if (ACPI_SUCCESS(status)) { + goto object_repaired; + } + } + if (expected_btypes & ACPI_RTYPE_PACKAGE) { + status = acpi_ns_convert_to_package(return_object, &new_object); + if (ACPI_SUCCESS(status)) { + goto object_repaired; + } + } + + /* We cannot repair this object */ + + return (AE_AML_OPERAND_TYPE); + + object_repaired: + + /* Object was successfully repaired */ + + /* + * If the original object is a package element, we need to: + * 1. Set the reference count of the new object to match the + * reference count of the old object. + * 2. Decrement the reference count of the original object. + */ + if (package_index != ACPI_NOT_PACKAGE_ELEMENT) { + new_object->common.reference_count = + return_object->common.reference_count; + + if (return_object->common.reference_count > 1) { + return_object->common.reference_count--; + } + + ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, + "%s: Converted %s to expected %s at index %u\n", + data->pathname, + acpi_ut_get_object_type_name(return_object), + acpi_ut_get_object_type_name(new_object), + package_index)); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, + "%s: Converted %s to expected %s\n", + data->pathname, + acpi_ut_get_object_type_name(return_object), + acpi_ut_get_object_type_name(new_object))); + } + + /* Delete old object, install the new return object */ + + acpi_ut_remove_reference(return_object); + *return_object_ptr = new_object; + data->flags |= ACPI_OBJECT_REPAIRED; + return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ns_convert_to_integer + * + * PARAMETERS: original_object - Object to be converted + * return_object - Where the new converted object is returned + * + * RETURN: Status. AE_OK if conversion was successful. + * + * DESCRIPTION: Attempt to convert a String/Buffer object to an Integer. + * + ******************************************************************************/ + +static acpi_status +acpi_ns_convert_to_integer(union acpi_operand_object *original_object, + union acpi_operand_object **return_object) +{ + union acpi_operand_object *new_object; + acpi_status status; + u64 value = 0; + u32 i; + + switch (original_object->common.type) { + case ACPI_TYPE_STRING: + + /* String-to-Integer conversion */ + + status = acpi_ut_strtoul64(original_object->string.pointer, + ACPI_ANY_BASE, &value); + if (ACPI_FAILURE(status)) { + return (status); + } + break; - switch (return_object->common.type) { case ACPI_TYPE_BUFFER: - /* Does the method/object legally return a string? */ + /* Buffer-to-Integer conversion. Max buffer size is 64 bits. */ - if (!(expected_btypes & ACPI_RTYPE_STRING)) { + if (original_object->buffer.length > 8) { return (AE_AML_OPERAND_TYPE); } + /* Extract each buffer byte to create the integer */ + + for (i = 0; i < original_object->buffer.length; i++) { + value |= + ((u64) original_object->buffer. + pointer[i] << (i * 8)); + } + break; + + default: + return (AE_AML_OPERAND_TYPE); + } + + new_object = acpi_ut_create_integer_object(value); + if (!new_object) { + return (AE_NO_MEMORY); + } + + *return_object = new_object; + return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ns_convert_to_string + * + * PARAMETERS: original_object - Object to be converted + * return_object - Where the new converted object is returned + * + * RETURN: Status. AE_OK if conversion was successful. + * + * DESCRIPTION: Attempt to convert a Integer/Buffer object to a String. + * + ******************************************************************************/ + +static acpi_status +acpi_ns_convert_to_string(union acpi_operand_object *original_object, + union acpi_operand_object **return_object) +{ + union acpi_operand_object *new_object; + acpi_size length; + acpi_status status; + + switch (original_object->common.type) { + case ACPI_TYPE_INTEGER: + /* + * Integer-to-String conversion. Commonly, convert + * an integer of value 0 to a NULL string. The last element of + * _BIF and _BIX packages occasionally need this fix. + */ + if (original_object->integer.value == 0) { + + /* Allocate a new NULL string object */ + + new_object = acpi_ut_create_string_object(0); + if (!new_object) { + return (AE_NO_MEMORY); + } + } else { + status = + acpi_ex_convert_to_string(original_object, + &new_object, + ACPI_IMPLICIT_CONVERT_HEX); + if (ACPI_FAILURE(status)) { + return (status); + } + } + break; + + case ACPI_TYPE_BUFFER: /* - * Have a Buffer, expected a String, convert. Use a to_string + * Buffer-to-String conversion. Use a to_string * conversion, no transform performed on the buffer data. The best * example of this is the _BIF method, where the string data from * the battery is often (incorrectly) returned as buffer object(s). */ length = 0; - while ((length < return_object->buffer.length) && - (return_object->buffer.pointer[length])) { + while ((length < original_object->buffer.length) && + (original_object->buffer.pointer[length])) { length++; } @@ -110,44 +331,177 @@ acpi_ns_repair_object(struct acpi_predefined_data *data, * terminated at Length+1. */ ACPI_MEMCPY(new_object->string.pointer, - return_object->buffer.pointer, length); + original_object->buffer.pointer, length); + break; + + default: + return (AE_AML_OPERAND_TYPE); + } + + *return_object = new_object; + return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ns_convert_to_buffer + * + * PARAMETERS: original_object - Object to be converted + * return_object - Where the new converted object is returned + * + * RETURN: Status. AE_OK if conversion was successful. + * + * DESCRIPTION: Attempt to convert a Integer/String/Package object to a Buffer. + * + ******************************************************************************/ +static acpi_status +acpi_ns_convert_to_buffer(union acpi_operand_object *original_object, + union acpi_operand_object **return_object) +{ + union acpi_operand_object *new_object; + acpi_status status; + union acpi_operand_object **elements; + u32 *dword_buffer; + u32 count; + u32 i; + + switch (original_object->common.type) { + case ACPI_TYPE_INTEGER: /* - * If the original object is a package element, we need to: - * 1. Set the reference count of the new object to match the - * reference count of the old object. - * 2. Decrement the reference count of the original object. + * Integer-to-Buffer conversion. + * Convert the Integer to a packed-byte buffer. _MAT and other + * objects need this sometimes, if a read has been performed on a + * Field object that is less than or equal to the global integer + * size (32 or 64 bits). */ - if (package_index != ACPI_NOT_PACKAGE_ELEMENT) { - new_object->common.reference_count = - return_object->common.reference_count; + status = + acpi_ex_convert_to_buffer(original_object, &new_object); + if (ACPI_FAILURE(status)) { + return (status); + } + break; + + case ACPI_TYPE_STRING: + + /* String-to-Buffer conversion. Simple data copy */ + + new_object = + acpi_ut_create_buffer_object(original_object->string. + length); + if (!new_object) { + return (AE_NO_MEMORY); + } + + ACPI_MEMCPY(new_object->buffer.pointer, + original_object->string.pointer, + original_object->string.length); + break; + + case ACPI_TYPE_PACKAGE: + /* + * This case is often seen for predefined names that must return a + * Buffer object with multiple DWORD integers within. For example, + * _FDE and _GTM. The Package can be converted to a Buffer. + */ + + /* All elements of the Package must be integers */ - if (return_object->common.reference_count > 1) { - return_object->common.reference_count--; + elements = original_object->package.elements; + count = original_object->package.count; + + for (i = 0; i < count; i++) { + if ((!*elements) || + ((*elements)->common.type != ACPI_TYPE_INTEGER)) { + return (AE_AML_OPERAND_TYPE); } + elements++; + } - ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, - data->node_flags, - "Converted Buffer to expected String at index %u", - package_index)); - } else { - ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, - data->node_flags, - "Converted Buffer to expected String")); + /* Create the new buffer object to replace the Package */ + + new_object = acpi_ut_create_buffer_object(ACPI_MUL_4(count)); + if (!new_object) { + return (AE_NO_MEMORY); } - /* Delete old object, install the new return object */ + /* Copy the package elements (integers) to the buffer as DWORDs */ - acpi_ut_remove_reference(return_object); - *return_object_ptr = new_object; - data->flags |= ACPI_OBJECT_REPAIRED; - return (AE_OK); + elements = original_object->package.elements; + dword_buffer = ACPI_CAST_PTR(u32, new_object->buffer.pointer); + + for (i = 0; i < count; i++) { + *dword_buffer = (u32) (*elements)->integer.value; + dword_buffer++; + elements++; + } + break; default: + return (AE_AML_OPERAND_TYPE); + } + + *return_object = new_object; + return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ns_convert_to_package + * + * PARAMETERS: original_object - Object to be converted + * return_object - Where the new converted object is returned + * + * RETURN: Status. AE_OK if conversion was successful. + * + * DESCRIPTION: Attempt to convert a Buffer object to a Package. Each byte of + * the buffer is converted to a single integer package element. + * + ******************************************************************************/ + +static acpi_status +acpi_ns_convert_to_package(union acpi_operand_object *original_object, + union acpi_operand_object **return_object) +{ + union acpi_operand_object *new_object; + union acpi_operand_object **elements; + u32 length; + u8 *buffer; + + switch (original_object->common.type) { + case ACPI_TYPE_BUFFER: + + /* Buffer-to-Package conversion */ + + length = original_object->buffer.length; + new_object = acpi_ut_create_package_object(length); + if (!new_object) { + return (AE_NO_MEMORY); + } + + /* Convert each buffer byte to an integer package element */ + + elements = new_object->package.elements; + buffer = original_object->buffer.pointer; + + while (length--) { + *elements = + acpi_ut_create_integer_object((u64) *buffer); + if (!*elements) { + acpi_ut_remove_reference(new_object); + return (AE_NO_MEMORY); + } + elements++; + buffer++; + } break; + + default: + return (AE_AML_OPERAND_TYPE); } - return (AE_AML_OPERAND_TYPE); + *return_object = new_object; + return (AE_OK); } /******************************************************************************* @@ -180,6 +534,8 @@ acpi_ns_repair_package_list(struct acpi_predefined_data *data, { union acpi_operand_object *pkg_obj_desc; + ACPI_FUNCTION_NAME(ns_repair_package_list); + /* * Create the new outer package and populate it. The new package will * have a single element, the lone subpackage. @@ -196,8 +552,9 @@ acpi_ns_repair_package_list(struct acpi_predefined_data *data, *obj_desc_ptr = pkg_obj_desc; data->flags |= ACPI_OBJECT_REPAIRED; - ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags, - "Incorrectly formed Package, attempting repair")); + ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, + "%s: Repaired incorrectly formed Package\n", + data->pathname)); return (AE_OK); } diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c new file mode 100644 index 00000000000..f13691c1cca --- /dev/null +++ b/drivers/acpi/acpica/nsrepair2.c @@ -0,0 +1,657 @@ +/****************************************************************************** + * + * Module Name: nsrepair2 - Repair for objects returned by specific + * predefined methods + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2009, Intel Corp. + * 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" +#include "acpredef.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 +acpi_status(*acpi_repair_function) (struct acpi_predefined_data *data, + union acpi_operand_object **return_object_ptr); + +typedef struct acpi_repair_info { + char name[ACPI_NAME_SIZE]; + acpi_repair_function repair_function; + +} acpi_repair_info; + +/* Local prototypes */ + +static const struct acpi_repair_info *acpi_ns_match_repairable_name(struct + acpi_namespace_node + *node); + +static acpi_status +acpi_ns_repair_ALR(struct acpi_predefined_data *data, + union acpi_operand_object **return_object_ptr); + +static acpi_status +acpi_ns_repair_FDE(struct acpi_predefined_data *data, + union acpi_operand_object **return_object_ptr); + +static acpi_status +acpi_ns_repair_PSS(struct acpi_predefined_data *data, + union acpi_operand_object **return_object_ptr); + +static acpi_status +acpi_ns_repair_TSS(struct acpi_predefined_data *data, + union acpi_operand_object **return_object_ptr); + +static acpi_status +acpi_ns_check_sorted_list(struct acpi_predefined_data *data, + union acpi_operand_object *return_object, + u32 expected_count, + u32 sort_index, + u8 sort_direction, char *sort_key_name); + +static acpi_status +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. + * + * As necessary: + * + * _ALR: Sort the list ascending by ambient_illuminance + * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs + * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs + * _PSS: Sort the list descending by Power + * _TSS: Sort the list descending by Power + */ +static const struct acpi_repair_info acpi_ns_repairable_names[] = { + {"_ALR", acpi_ns_repair_ALR}, + {"_FDE", acpi_ns_repair_FDE}, + {"_GTM", acpi_ns_repair_FDE}, /* _GTM has same repair as _FDE */ + {"_PSS", acpi_ns_repair_PSS}, + {"_TSS", acpi_ns_repair_TSS}, + {{0, 0, 0, 0}, NULL} /* Table terminator */ +}; + +#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)) + +/****************************************************************************** + * + * FUNCTION: acpi_ns_complex_repairs + * + * PARAMETERS: Data - Pointer to validation data structure + * Node - Namespace node for the method/object + * 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 +acpi_ns_complex_repairs(struct acpi_predefined_data *data, + 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 */ + + predefined = acpi_ns_match_repairable_name(node); + if (!predefined) { + return (validate_status); + } + + status = predefined->repair_function(data, return_object_ptr); + return (status); +} + +/****************************************************************************** + * + * FUNCTION: acpi_ns_match_repairable_name + * + * PARAMETERS: Node - Namespace node for the method/object + * + * RETURN: Pointer to entry in repair table. NULL indicates not found. + * + * DESCRIPTION: Check an object name against the repairable object list. + * + *****************************************************************************/ + +static const struct acpi_repair_info *acpi_ns_match_repairable_name(struct + acpi_namespace_node + *node) +{ + 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 + * + * PARAMETERS: Data - Pointer to validation data structure + * 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 +acpi_ns_repair_ALR(struct acpi_predefined_data *data, + union acpi_operand_object **return_object_ptr) +{ + union acpi_operand_object *return_object = *return_object_ptr; + acpi_status status; + + status = acpi_ns_check_sorted_list(data, return_object, 2, 1, + ACPI_SORT_ASCENDING, + "AmbientIlluminance"); + + return (status); +} + +/****************************************************************************** + * + * FUNCTION: acpi_ns_repair_FDE + * + * PARAMETERS: Data - Pointer to validation data structure + * 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 + * value is a Buffer of 5 DWORDs. This function repairs a common + * problem where the return value is a Buffer of BYTEs, not + * DWORDs. + * + *****************************************************************************/ + +static acpi_status +acpi_ns_repair_FDE(struct acpi_predefined_data *data, + 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; + + ACPI_FUNCTION_NAME(ns_repair_FDE); + + 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) { + ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, + data->node_flags, + "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++; + } + + ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, + "%s Expanded Byte Buffer to expected DWord Buffer\n", + data->pathname)); + break; + + default: + 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; + + data->flags |= ACPI_OBJECT_REPAIRED; + return (AE_OK); +} + +/****************************************************************************** + * + * FUNCTION: acpi_ns_repair_TSS + * + * PARAMETERS: Data - Pointer to validation data structure + * 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 +acpi_ns_repair_TSS(struct acpi_predefined_data *data, + union acpi_operand_object **return_object_ptr) +{ + union acpi_operand_object *return_object = *return_object_ptr; + acpi_status status; + + status = acpi_ns_check_sorted_list(data, return_object, 5, 1, + ACPI_SORT_DESCENDING, + "PowerDissipation"); + + return (status); +} + +/****************************************************************************** + * + * FUNCTION: acpi_ns_repair_PSS + * + * PARAMETERS: Data - Pointer to validation data structure + * 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 +acpi_ns_repair_PSS(struct acpi_predefined_data *data, + 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. + */ + status = acpi_ns_check_sorted_list(data, return_object, 6, 0, + 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) { + ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, + data->node_flags, + "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 + * + * PARAMETERS: Data - Pointer to validation data structure + * 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 +acpi_ns_check_sorted_list(struct acpi_predefined_data *data, + 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; + acpi_status status; + + ACPI_FUNCTION_NAME(ns_check_sorted_list); + + /* The top-level object must be a package */ + + if (return_object->common.type != ACPI_TYPE_PACKAGE) { + return (AE_AML_OPERAND_TYPE); + } + + /* + * 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. + */ + 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 + * discrepancy, issue a warning and sort the entire list + */ + if (((sort_direction == ACPI_SORT_ASCENDING) && + (obj_desc->integer.value < previous_value)) || + ((sort_direction == ACPI_SORT_DESCENDING) && + (obj_desc->integer.value > previous_value))) { + status = + acpi_ns_sort_list(return_object->package.elements, + outer_element_count, sort_index, + sort_direction); + if (ACPI_FAILURE(status)) { + return (status); + } + + data->flags |= ACPI_OBJECT_REPAIRED; + + ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, + "%s: Repaired unsorted list - now sorted by %s\n", + data->pathname, sort_key_name)); + return (AE_OK); + } + + previous_value = (u32) obj_desc->integer.value; + outer_elements++; + } + + return (AE_OK); +} + +/****************************************************************************** + * + * FUNCTION: acpi_ns_remove_null_elements + * + * PARAMETERS: Data - Pointer to validation data structure + * package_type - An acpi_return_package_types value + * obj_desc - A Package object + * + * RETURN: None. + * + * DESCRIPTION: Remove all NULL package elements from packages that contain + * a variable number of sub-packages. + * + *****************************************************************************/ + +void +acpi_ns_remove_null_elements(struct acpi_predefined_data *data, + u8 package_type, + union acpi_operand_object *obj_desc) +{ + union acpi_operand_object **source; + union acpi_operand_object **dest; + u32 count; + u32 new_count; + u32 i; + + ACPI_FUNCTION_NAME(ns_remove_null_elements); + + /* + * PTYPE1 packages contain no subpackages. + * PTYPE2 packages contain a variable number of sub-packages. We can + * safely remove all NULL elements from the PTYPE2 packages. + */ + switch (package_type) { + case ACPI_PTYPE1_FIXED: + case ACPI_PTYPE1_VAR: + case ACPI_PTYPE1_OPTION: + return; + + case ACPI_PTYPE2: + case ACPI_PTYPE2_COUNT: + case ACPI_PTYPE2_PKG_COUNT: + case ACPI_PTYPE2_FIXED: + case ACPI_PTYPE2_MIN: + case ACPI_PTYPE2_REV_FIXED: + break; + + default: + return; + } + + count = obj_desc->package.count; + new_count = count; + + source = obj_desc->package.elements; + dest = source; + + /* Examine all elements of the package object, remove nulls */ + + for (i = 0; i < count; i++) { + if (!*source) { + new_count--; + } else { + *dest = *source; + dest++; + } + source++; + } + + /* Update parent package if any null elements were removed */ + + if (new_count < count) { + ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, + "%s: Found and removed %u NULL elements\n", + data->pathname, (count - new_count))); + + /* NULL terminate list and update the package count */ + + *dest = NULL; + obj_desc->package.count = new_count; + } +} + +/****************************************************************************** + * + * FUNCTION: acpi_ns_sort_list + * + * PARAMETERS: Elements - Package object element list + * Count - Element count for above + * Index - Sort by which package element + * sort_direction - Ascending or Descending sort + * + * RETURN: Status + * + * DESCRIPTION: Sort the objects that are in a package element list. + * + * NOTE: Assumes that all NULL elements have been removed from the package. + * + *****************************************************************************/ + +static acpi_status +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; + } + } + } + + return (AE_OK); +} diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index ea55ab4f984..47d91e668a1 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -671,24 +671,25 @@ acpi_ns_externalize_name(u32 internal_name_length, /******************************************************************************* * - * FUNCTION: acpi_ns_map_handle_to_node + * FUNCTION: acpi_ns_validate_handle * - * PARAMETERS: Handle - Handle to be converted to an Node + * PARAMETERS: Handle - Handle to be validated and typecast to a + * namespace node. * - * RETURN: A Name table entry pointer + * RETURN: A pointer to a namespace node * - * DESCRIPTION: Convert a namespace handle to a real Node + * DESCRIPTION: Convert a namespace handle to a namespace node. Handles special + * cases for the root node. * - * Note: Real integer handles would allow for more verification + * NOTE: Real integer handles would allow for more verification * and keep all pointers within this subsystem - however this introduces - * more (and perhaps unnecessary) overhead. - * - * The current implemenation is basically a placeholder until such time comes - * that it is needed. + * more overhead and has not been necessary to this point. Drivers + * holding handles are typically notified before a node becomes invalid + * due to a table unload. * ******************************************************************************/ -struct acpi_namespace_node *acpi_ns_map_handle_to_node(acpi_handle handle) +struct acpi_namespace_node *acpi_ns_validate_handle(acpi_handle handle) { ACPI_FUNCTION_ENTRY(); @@ -710,42 +711,6 @@ struct acpi_namespace_node *acpi_ns_map_handle_to_node(acpi_handle handle) /******************************************************************************* * - * FUNCTION: acpi_ns_convert_entry_to_handle - * - * PARAMETERS: Node - Node to be converted to a Handle - * - * RETURN: A user handle - * - * DESCRIPTION: Convert a real Node to a namespace handle - * - ******************************************************************************/ - -acpi_handle acpi_ns_convert_entry_to_handle(struct acpi_namespace_node *node) -{ - - /* - * Simple implementation for now; - */ - return ((acpi_handle) node); - -/* Example future implementation --------------------- - - if (!Node) - { - return (NULL); - } - - if (Node == acpi_gbl_root_node) - { - return (ACPI_ROOT_OBJECT); - } - - return ((acpi_handle) Node); -------------------------------------------------------*/ -} - -/******************************************************************************* - * * FUNCTION: acpi_ns_terminate * * PARAMETERS: none diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c index 35539df5c75..d7e6b52b448 100644 --- a/drivers/acpi/acpica/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -165,24 +165,27 @@ struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type, * max_depth - Depth to which search is to reach * Flags - Whether to unlock the NS before invoking * the callback routine - * user_function - Called when an object of "Type" is found - * Context - Passed to user function - * return_value - from the user_function if terminated early. - * Otherwise, returns NULL. + * pre_order_visit - Called during tree pre-order visit + * when an object of "Type" is found + * post_order_visit - Called during tree post-order visit + * when an object of "Type" is found + * Context - Passed to user function(s) above + * return_value - from the user_function if terminated + * early. Otherwise, returns NULL. * RETURNS: Status * * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, * starting (and ending) at the node specified by start_handle. - * The user_function is called whenever a node that matches - * the type parameter is found. If the user function returns + * The callback function is called whenever a node that matches + * the type parameter is found. If the callback function returns * a non-zero value, the search is terminated immediately and * this value is returned to the caller. * * The point of this procedure is to provide a generic namespace * walk routine that can be called from multiple places to - * provide multiple services; the User Function can be tailored - * to each task, whether it is a print function, a compare - * function, etc. + * provide multiple services; the callback function(s) can be + * tailored to each task, whether it is a print function, + * a compare function, etc. * ******************************************************************************/ @@ -191,7 +194,8 @@ acpi_ns_walk_namespace(acpi_object_type type, acpi_handle start_node, u32 max_depth, u32 flags, - acpi_walk_callback user_function, + acpi_walk_callback pre_order_visit, + acpi_walk_callback post_order_visit, void *context, void **return_value) { acpi_status status; @@ -200,6 +204,7 @@ acpi_ns_walk_namespace(acpi_object_type type, struct acpi_namespace_node *parent_node; acpi_object_type child_type; u32 level; + u8 node_previously_visited = FALSE; ACPI_FUNCTION_TRACE(ns_walk_namespace); @@ -212,7 +217,7 @@ acpi_ns_walk_namespace(acpi_object_type type, /* Null child means "get first node" */ parent_node = start_node; - child_node = NULL; + child_node = acpi_ns_get_next_node(parent_node, NULL); child_type = ACPI_TYPE_ANY; level = 1; @@ -221,102 +226,129 @@ acpi_ns_walk_namespace(acpi_object_type type, * started. When Level is zero, the loop is done because we have * bubbled up to (and passed) the original parent handle (start_entry) */ - while (level > 0) { + while (level > 0 && child_node) { + status = AE_OK; - /* Get the next node in this scope. Null if not found */ + /* Found next child, get the type if we are not searching for ANY */ - status = AE_OK; - child_node = acpi_ns_get_next_node(parent_node, child_node); - if (child_node) { + if (type != ACPI_TYPE_ANY) { + child_type = child_node->type; + } - /* Found next child, get the type if we are not searching for ANY */ + /* + * Ignore all temporary namespace nodes (created during control + * method execution) unless told otherwise. These temporary nodes + * can cause a race condition because they can be deleted during + * the execution of the user function (if the namespace is + * unlocked before invocation of the user function.) Only the + * debugger namespace dump will examine the temporary nodes. + */ + if ((child_node->flags & ANOBJ_TEMPORARY) && + !(flags & ACPI_NS_WALK_TEMP_NODES)) { + status = AE_CTRL_DEPTH; + } - if (type != ACPI_TYPE_ANY) { - child_type = child_node->type; - } + /* Type must match requested type */ + else if (child_type == type) { /* - * Ignore all temporary namespace nodes (created during control - * method execution) unless told otherwise. These temporary nodes - * can cause a race condition because they can be deleted during - * the execution of the user function (if the namespace is - * unlocked before invocation of the user function.) Only the - * debugger namespace dump will examine the temporary nodes. + * Found a matching node, invoke the user callback function. + * Unlock the namespace if flag is set. */ - if ((child_node->flags & ANOBJ_TEMPORARY) && - !(flags & ACPI_NS_WALK_TEMP_NODES)) { - status = AE_CTRL_DEPTH; + if (flags & ACPI_NS_WALK_UNLOCK) { + mutex_status = + acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(mutex_status)) { + return_ACPI_STATUS(mutex_status); + } } - /* Type must match requested type */ - - else if (child_type == type) { - /* - * Found a matching node, invoke the user callback function. - * Unlock the namespace if flag is set. - */ - if (flags & ACPI_NS_WALK_UNLOCK) { - mutex_status = - acpi_ut_release_mutex - (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(mutex_status)) { - return_ACPI_STATUS - (mutex_status); - } + /* + * Invoke the user function, either pre-order or post-order + * or both. + */ + if (!node_previously_visited) { + if (pre_order_visit) { + status = + pre_order_visit(child_node, level, + context, + return_value); } + } else { + if (post_order_visit) { + status = + post_order_visit(child_node, level, + context, + return_value); + } + } - status = - user_function(child_node, level, context, - return_value); - - if (flags & ACPI_NS_WALK_UNLOCK) { - mutex_status = - acpi_ut_acquire_mutex - (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(mutex_status)) { - return_ACPI_STATUS - (mutex_status); - } + if (flags & ACPI_NS_WALK_UNLOCK) { + mutex_status = + acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(mutex_status)) { + return_ACPI_STATUS(mutex_status); } + } - switch (status) { - case AE_OK: - case AE_CTRL_DEPTH: + switch (status) { + case AE_OK: + case AE_CTRL_DEPTH: - /* Just keep going */ - break; + /* Just keep going */ + break; - case AE_CTRL_TERMINATE: + case AE_CTRL_TERMINATE: - /* Exit now, with OK status */ + /* Exit now, with OK status */ - return_ACPI_STATUS(AE_OK); + return_ACPI_STATUS(AE_OK); - default: + default: - /* All others are valid exceptions */ + /* All others are valid exceptions */ - return_ACPI_STATUS(status); - } + return_ACPI_STATUS(status); + } + } + + /* + * Depth first search: Attempt to go down another level in the + * namespace if we are allowed to. Don't go any further if we have + * reached the caller specified maximum depth or if the user + * function has specified that the maximum depth has been reached. + */ + if (!node_previously_visited && + (level < max_depth) && (status != AE_CTRL_DEPTH)) { + if (child_node->child) { + + /* There is at least one child of this node, visit it */ + + level++; + parent_node = child_node; + child_node = + acpi_ns_get_next_node(parent_node, NULL); + continue; } + } - /* - * Depth first search: Attempt to go down another level in the - * namespace if we are allowed to. Don't go any further if we have - * reached the caller specified maximum depth or if the user - * function has specified that the maximum depth has been reached. - */ - if ((level < max_depth) && (status != AE_CTRL_DEPTH)) { - if (child_node->child) { + /* No more children, re-visit this node */ - /* There is at least one child of this node, visit it */ + if (!node_previously_visited) { + node_previously_visited = TRUE; + continue; + } - level++; - parent_node = child_node; - child_node = NULL; - } - } - } else { + /* No more children, visit peers */ + + child_node = acpi_ns_get_next_node(parent_node, child_node); + if (child_node) { + node_previously_visited = FALSE; + } + + /* No peers, re-visit parent */ + + else { /* * No more children of this node (acpi_ns_get_next_node failed), go * back upwards in the namespace tree to the node's parent. @@ -324,6 +356,8 @@ acpi_ns_walk_namespace(acpi_object_type type, level--; child_node = parent_node; parent_node = acpi_ns_get_parent_node(parent_node); + + node_previously_visited = TRUE; } } diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index 4929dbdbc8f..f0c0892bc7e 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -190,7 +190,7 @@ acpi_evaluate_object(acpi_handle handle, /* Convert and validate the device handle */ - info->prefix_node = acpi_ns_map_handle_to_node(handle); + info->prefix_node = acpi_ns_validate_handle(handle); if (!info->prefix_node) { status = AE_BAD_PARAMETER; goto cleanup; @@ -433,8 +433,11 @@ static void acpi_ns_resolve_references(struct acpi_evaluate_info *info) * PARAMETERS: Type - acpi_object_type to search for * start_object - Handle in namespace where search begins * max_depth - Depth to which search is to reach - * user_function - Called when an object of "Type" is found - * Context - Passed to user function + * pre_order_visit - Called during tree pre-order visit + * when an object of "Type" is found + * post_order_visit - Called during tree post-order visit + * when an object of "Type" is found + * Context - Passed to user function(s) above * return_value - Location where return value of * user_function is put if terminated early * @@ -443,16 +446,16 @@ static void acpi_ns_resolve_references(struct acpi_evaluate_info *info) * * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, * starting (and ending) at the object specified by start_handle. - * The user_function is called whenever an object that matches - * the type parameter is found. If the user function returns + * The callback function is called whenever an object that matches + * the type parameter is found. If the callback function returns * a non-zero value, the search is terminated immediately and this * value is returned to the caller. * * The point of this procedure is to provide a generic namespace * walk routine that can be called from multiple places to - * provide multiple services; the User Function can be tailored - * to each task, whether it is a print function, a compare - * function, etc. + * provide multiple services; the callback function(s) can be + * tailored to each task, whether it is a print function, + * a compare function, etc. * ******************************************************************************/ @@ -460,7 +463,8 @@ acpi_status acpi_walk_namespace(acpi_object_type type, acpi_handle start_object, u32 max_depth, - acpi_walk_callback user_function, + acpi_walk_callback pre_order_visit, + acpi_walk_callback post_order_visit, void *context, void **return_value) { acpi_status status; @@ -469,7 +473,8 @@ acpi_walk_namespace(acpi_object_type type, /* Parameter validation */ - if ((type > ACPI_TYPE_LOCAL_MAX) || (!max_depth) || (!user_function)) { + if ((type > ACPI_TYPE_LOCAL_MAX) || + (!max_depth) || (!pre_order_visit && !post_order_visit)) { return_ACPI_STATUS(AE_BAD_PARAMETER); } @@ -501,8 +506,9 @@ acpi_walk_namespace(acpi_object_type type, } status = acpi_ns_walk_namespace(type, start_object, max_depth, - ACPI_NS_WALK_UNLOCK, user_function, - context, return_value); + ACPI_NS_WALK_UNLOCK, pre_order_visit, + post_order_visit, context, + return_value); (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); @@ -546,7 +552,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle, return (status); } - node = acpi_ns_map_handle_to_node(obj_handle); + node = acpi_ns_validate_handle(obj_handle); status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return (status); @@ -681,8 +687,8 @@ acpi_get_devices(const char *HID, status = acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, - acpi_ns_get_device_callback, &info, - return_value); + acpi_ns_get_device_callback, NULL, + &info, return_value); (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_ACPI_STATUS(status); @@ -723,7 +729,7 @@ acpi_attach_data(acpi_handle obj_handle, /* Convert and validate the handle */ - node = acpi_ns_map_handle_to_node(obj_handle); + node = acpi_ns_validate_handle(obj_handle); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; @@ -769,7 +775,7 @@ acpi_detach_data(acpi_handle obj_handle, acpi_object_handler handler) /* Convert and validate the handle */ - node = acpi_ns_map_handle_to_node(obj_handle); + node = acpi_ns_validate_handle(obj_handle); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; @@ -816,7 +822,7 @@ acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data) /* Convert and validate the handle */ - node = acpi_ns_map_handle_to_node(obj_handle); + node = acpi_ns_validate_handle(obj_handle); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index ddc84af6336..e611dd961b2 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -93,7 +93,7 @@ acpi_get_handle(acpi_handle parent, /* Convert a parent handle to a prefix node */ if (parent) { - prefix_node = acpi_ns_map_handle_to_node(parent); + prefix_node = acpi_ns_validate_handle(parent); if (!prefix_node) { return (AE_BAD_PARAMETER); } @@ -114,7 +114,7 @@ acpi_get_handle(acpi_handle parent, if (!ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH)) { *ret_handle = - acpi_ns_convert_entry_to_handle(acpi_gbl_root_node); + ACPI_CAST_PTR(acpi_handle, acpi_gbl_root_node); return (AE_OK); } } else if (!prefix_node) { @@ -129,7 +129,7 @@ acpi_get_handle(acpi_handle parent, status = acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, &node); if (ACPI_SUCCESS(status)) { - *ret_handle = acpi_ns_convert_entry_to_handle(node); + *ret_handle = ACPI_CAST_PTR(acpi_handle, node); } return (status); @@ -186,7 +186,7 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer) return (status); } - node = acpi_ns_map_handle_to_node(handle); + node = acpi_ns_validate_handle(handle); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; @@ -291,7 +291,7 @@ acpi_get_object_info(acpi_handle handle, goto cleanup; } - node = acpi_ns_map_handle_to_node(handle); + node = acpi_ns_validate_handle(handle); if (!node) { (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return (AE_BAD_PARAMETER); diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c index 4071bad4458..0cc6ba01a49 100644 --- a/drivers/acpi/acpica/nsxfobj.c +++ b/drivers/acpi/acpica/nsxfobj.c @@ -79,7 +79,7 @@ acpi_status acpi_get_id(acpi_handle handle, acpi_owner_id * ret_id) /* Convert and validate the handle */ - node = acpi_ns_map_handle_to_node(handle); + node = acpi_ns_validate_handle(handle); if (!node) { (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return (AE_BAD_PARAMETER); @@ -132,7 +132,7 @@ acpi_status acpi_get_type(acpi_handle handle, acpi_object_type * ret_type) /* Convert and validate the handle */ - node = acpi_ns_map_handle_to_node(handle); + node = acpi_ns_validate_handle(handle); if (!node) { (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return (AE_BAD_PARAMETER); @@ -182,7 +182,7 @@ acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle) /* Convert and validate the handle */ - node = acpi_ns_map_handle_to_node(handle); + node = acpi_ns_validate_handle(handle); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; @@ -191,7 +191,7 @@ acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle) /* Get the parent entry */ parent_node = acpi_ns_get_parent_node(node); - *ret_handle = acpi_ns_convert_entry_to_handle(parent_node); + *ret_handle = ACPI_CAST_PTR(acpi_handle, parent_node); /* Return exception if parent is null */ @@ -251,7 +251,7 @@ acpi_get_next_object(acpi_object_type type, /* Start search at the beginning of the specified scope */ - parent_node = acpi_ns_map_handle_to_node(parent); + parent_node = acpi_ns_validate_handle(parent); if (!parent_node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; @@ -260,7 +260,7 @@ acpi_get_next_object(acpi_object_type type, /* Non-null handle, ignore the parent */ /* Convert and validate the handle */ - child_node = acpi_ns_map_handle_to_node(child); + child_node = acpi_ns_validate_handle(child); if (!child_node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; @@ -276,7 +276,7 @@ acpi_get_next_object(acpi_object_type type, } if (ret_handle) { - *ret_handle = acpi_ns_convert_entry_to_handle(node); + *ret_handle = ACPI_CAST_PTR(acpi_handle, node); } unlock_and_exit: diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index cd7995b3aed..0988e4a8901 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -87,7 +87,8 @@ acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, union acpi_parse_object *op, acpi_status status); static void -acpi_ps_link_module_code(u8 *aml_start, u32 aml_length, acpi_owner_id owner_id); +acpi_ps_link_module_code(union acpi_parse_object *parent_op, + u8 *aml_start, u32 aml_length, acpi_owner_id owner_id); /******************************************************************************* * @@ -479,11 +480,14 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, */ if (walk_state->pass_number == ACPI_IMODE_LOAD_PASS1) { - acpi_ps_link_module_code(aml_op_start, - walk_state-> + acpi_ps_link_module_code(op->common. + parent, + aml_op_start, + (u32) + (walk_state-> parser_state. pkg_end - - aml_op_start, + aml_op_start), walk_state-> owner_id); } @@ -598,7 +602,8 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, * * FUNCTION: acpi_ps_link_module_code * - * PARAMETERS: aml_start - Pointer to the AML + * PARAMETERS: parent_op - Parent parser op + * aml_start - Pointer to the AML * aml_length - Length of executable AML * owner_id - owner_id of module level code * @@ -611,11 +616,13 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, ******************************************************************************/ static void -acpi_ps_link_module_code(u8 *aml_start, u32 aml_length, acpi_owner_id owner_id) +acpi_ps_link_module_code(union acpi_parse_object *parent_op, + u8 *aml_start, u32 aml_length, acpi_owner_id owner_id) { union acpi_operand_object *prev; union acpi_operand_object *next; union acpi_operand_object *method_obj; + struct acpi_namespace_node *parent_node; /* Get the tail of the list */ @@ -639,11 +646,24 @@ acpi_ps_link_module_code(u8 *aml_start, u32 aml_length, acpi_owner_id owner_id) return; } + if (parent_op->common.node) { + parent_node = parent_op->common.node; + } else { + parent_node = acpi_gbl_root_node; + } + method_obj->method.aml_start = aml_start; method_obj->method.aml_length = aml_length; method_obj->method.owner_id = owner_id; method_obj->method.flags |= AOPOBJ_MODULE_LEVEL; + /* + * Save the parent node in next_object. This is cheating, but we + * don't want to expand the method object. + */ + method_obj->method.next_object = + ACPI_CAST_PTR(union acpi_operand_object, parent_node); + if (!prev) { acpi_gbl_module_code_list = method_obj; } else { diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index 70838e9b608..4df8f139026 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -610,17 +610,13 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) implicit_return_obj) { previous_walk_state-> implicit_return_obj = - acpi_ut_create_internal_object - (ACPI_TYPE_INTEGER); + acpi_ut_create_integer_object + ((u64) 0); if (!previous_walk_state-> implicit_return_obj) { return_ACPI_STATUS (AE_NO_MEMORY); } - - previous_walk_state-> - implicit_return_obj-> - integer.value = 0; } /* Restart the calling control method */ diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c index dd9731c29a7..d0c1b91eb8c 100644 --- a/drivers/acpi/acpica/psxface.c +++ b/drivers/acpi/acpica/psxface.c @@ -287,7 +287,8 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) /* Invoke an internal method if necessary */ if (info->obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { - status = info->obj_desc->method.implementation(walk_state); + status = + info->obj_desc->method.extra.implementation(walk_state); info->return_object = walk_state->return_desc; /* Cleanup states */ @@ -306,14 +307,12 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) */ if (acpi_gbl_enable_interpreter_slack) { walk_state->implicit_return_obj = - acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); + acpi_ut_create_integer_object((u64) 0); if (!walk_state->implicit_return_obj) { status = AE_NO_MEMORY; acpi_ds_delete_walk_state(walk_state); goto cleanup; } - - walk_state->implicit_return_obj->integer.value = 0; } /* Parse the AML */ diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c index 395212bcd19..f27feb4772f 100644 --- a/drivers/acpi/acpica/rsxface.c +++ b/drivers/acpi/acpica/rsxface.c @@ -104,7 +104,7 @@ acpi_rs_validate_parameters(acpi_handle device_handle, return_ACPI_STATUS(AE_BAD_PARAMETER); } - node = acpi_ns_map_handle_to_node(device_handle); + node = acpi_ns_validate_handle(device_handle); if (!node) { return_ACPI_STATUS(AE_BAD_PARAMETER); } diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c index 0f0c64bf8ac..f857c5efb79 100644 --- a/drivers/acpi/acpica/utcopy.c +++ b/drivers/acpi/acpica/utcopy.c @@ -323,11 +323,11 @@ acpi_ut_copy_ielement_to_eelement(u8 object_type, * RETURN: Status * * DESCRIPTION: This function is called to place a package object in a user - * buffer. A package object by definition contains other objects. + * buffer. A package object by definition contains other objects. * * The buffer is assumed to have sufficient space for the object. - * The caller must have verified the buffer length needed using the - * acpi_ut_get_object_size function before calling this function. + * The caller must have verified the buffer length needed using + * the acpi_ut_get_object_size function before calling this function. * ******************************************************************************/ @@ -382,12 +382,12 @@ acpi_ut_copy_ipackage_to_epackage(union acpi_operand_object *internal_object, * FUNCTION: acpi_ut_copy_iobject_to_eobject * * PARAMETERS: internal_object - The internal object to be converted - * buffer_ptr - Where the object is returned + * ret_buffer - Where the object is returned * * RETURN: Status * - * DESCRIPTION: This function is called to build an API object to be returned to - * the caller. + * DESCRIPTION: This function is called to build an API object to be returned + * to the caller. * ******************************************************************************/ @@ -626,7 +626,7 @@ acpi_ut_copy_epackage_to_ipackage(union acpi_object *external_object, * PARAMETERS: external_object - The external object to be converted * internal_object - Where the internal object is returned * - * RETURN: Status - the status of the call + * RETURN: Status * * DESCRIPTION: Converts an external object to an internal object. * @@ -665,7 +665,7 @@ acpi_ut_copy_eobject_to_iobject(union acpi_object *external_object, * * RETURN: Status * - * DESCRIPTION: Simple copy of one internal object to another. Reference count + * DESCRIPTION: Simple copy of one internal object to another. Reference count * of the destination object is preserved. * ******************************************************************************/ @@ -897,10 +897,11 @@ acpi_ut_copy_ielement_to_ielement(u8 object_type, * * FUNCTION: acpi_ut_copy_ipackage_to_ipackage * - * PARAMETERS: *source_obj - Pointer to the source package object - * *dest_obj - Where the internal object is returned + * PARAMETERS: source_obj - Pointer to the source package object + * dest_obj - Where the internal object is returned + * walk_state - Current Walk state descriptor * - * RETURN: Status - the status of the call + * RETURN: Status * * DESCRIPTION: This function is called to copy an internal package object * into another internal package object. @@ -953,9 +954,9 @@ acpi_ut_copy_ipackage_to_ipackage(union acpi_operand_object *source_obj, * * FUNCTION: acpi_ut_copy_iobject_to_iobject * - * PARAMETERS: walk_state - Current walk state - * source_desc - The internal object to be copied + * PARAMETERS: source_desc - The internal object to be copied * dest_desc - Where the copied object is returned + * walk_state - Current walk state * * RETURN: Status * diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index 61f6315fce9..6c6a5137b72 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -1161,3 +1161,45 @@ acpi_ut_predefined_warning(const char *module_name, ACPI_COMMON_MSG_SUFFIX; va_end(args); } + +/******************************************************************************* + * + * FUNCTION: acpi_ut_predefined_info + * + * PARAMETERS: module_name - Caller's module name (for error output) + * line_number - Caller's line number (for error output) + * Pathname - Full pathname to the node + * node_flags - From Namespace node for the method/object + * Format - Printf format string + additional args + * + * RETURN: None + * + * DESCRIPTION: Info messages for the predefined validation module. Messages + * are only emitted the first time a problem with a particular + * method/object is detected. This prevents a flood of + * messages for methods that are repeatedly evaluated. + * + ******************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +acpi_ut_predefined_info(const char *module_name, + u32 line_number, + char *pathname, u8 node_flags, const char *format, ...) +{ + va_list args; + + /* + * Warning messages for this method/object will be disabled after the + * first time a validation fails or an object is successfully repaired. + */ + if (node_flags & ANOBJ_EVALUATED) { + return; + } + + acpi_os_printf("ACPI Info for %s: ", pathname); + + va_start(args, format); + acpi_os_vprintf(format, args); + ACPI_COMMON_MSG_SUFFIX; + va_end(args); +} diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c index 0207b625274..42e658b543f 100644 --- a/drivers/acpi/acpica/utobject.c +++ b/drivers/acpi/acpica/utobject.c @@ -190,6 +190,35 @@ union acpi_operand_object *acpi_ut_create_package_object(u32 count) /******************************************************************************* * + * FUNCTION: acpi_ut_create_integer_object + * + * PARAMETERS: initial_value - Initial value for the integer + * + * RETURN: Pointer to a new Integer object, null on failure + * + * DESCRIPTION: Create an initialized integer object + * + ******************************************************************************/ + +union acpi_operand_object *acpi_ut_create_integer_object(u64 initial_value) +{ + union acpi_operand_object *integer_desc; + + ACPI_FUNCTION_TRACE(ut_create_integer_object); + + /* Create and initialize a new integer object */ + + integer_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); + if (!integer_desc) { + return_PTR(NULL); + } + + integer_desc->integer.value = initial_value; + return_PTR(integer_desc); +} + +/******************************************************************************* + * * FUNCTION: acpi_ut_create_buffer_object * * PARAMETERS: buffer_size - Size of buffer to be created diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 3f4602b8f28..cada73ffdfa 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -831,7 +831,7 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event) dev_name(&device->dev), event, acpi_battery_present(battery)); #ifdef CONFIG_ACPI_SYSFS_POWER - /* acpi_batter_update could remove power_supply object */ + /* acpi_battery_update could remove power_supply object */ if (battery->bat.dev) kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE); #endif diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index e56b2a7b53d..2815df66f6f 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -185,6 +185,12 @@ static int __init dmi_disable_osi_vista(const struct dmi_system_id *d) acpi_osi_setup("!Windows 2006"); return 0; } +static int __init dmi_disable_osi_win7(const struct dmi_system_id *d) +{ + printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident); + acpi_osi_setup("!Windows 2009"); + return 0; +} static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { { @@ -211,6 +217,14 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "Sony VGN-SR290J"), }, }, + { + .callback = dmi_disable_osi_win7, + .ident = "ASUS K50IJ", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "K50IJ"), + }, + }, /* * BIOS invocation of _OSI(Linux) is almost always a BIOS bug. @@ -224,6 +238,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { * _OSI(Linux) helps sound * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad R61"), * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T61"), + * T400, T500 * _OSI(Linux) has Linux specific hooks * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X61"), * _OSI(Linux) is a NOP: @@ -254,6 +269,22 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X61"), }, }, + { + .callback = dmi_enable_osi_linux, + .ident = "Lenovo ThinkPad T400", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T400"), + }, + }, + { + .callback = dmi_enable_osi_linux, + .ident = "Lenovo ThinkPad T500", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T500"), + }, + }, {} }; diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 74119152435..a52126e4630 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -344,6 +344,167 @@ bool acpi_bus_can_wakeup(acpi_handle handle) EXPORT_SYMBOL(acpi_bus_can_wakeup); +static void acpi_print_osc_error(acpi_handle handle, + struct acpi_osc_context *context, char *error) +{ + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER}; + int i; + + if (ACPI_FAILURE(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer))) + printk(KERN_DEBUG "%s\n", error); + else { + printk(KERN_DEBUG "%s:%s\n", (char *)buffer.pointer, error); + kfree(buffer.pointer); + } + printk(KERN_DEBUG"_OSC request data:"); + for (i = 0; i < context->cap.length; i += sizeof(u32)) + printk("%x ", *((u32 *)(context->cap.pointer + i))); + printk("\n"); +} + +static u8 hex_val(unsigned char c) +{ + return isdigit(c) ? c - '0' : toupper(c) - 'A' + 10; +} + +static acpi_status acpi_str_to_uuid(char *str, u8 *uuid) +{ + int i; + static int opc_map_to_uuid[16] = {6, 4, 2, 0, 11, 9, 16, 14, 19, 21, + 24, 26, 28, 30, 32, 34}; + + if (strlen(str) != 36) + return AE_BAD_PARAMETER; + for (i = 0; i < 36; i++) { + if (i == 8 || i == 13 || i == 18 || i == 23) { + if (str[i] != '-') + return AE_BAD_PARAMETER; + } else if (!isxdigit(str[i])) + return AE_BAD_PARAMETER; + } + for (i = 0; i < 16; i++) { + uuid[i] = hex_val(str[opc_map_to_uuid[i]]) << 4; + uuid[i] |= hex_val(str[opc_map_to_uuid[i] + 1]); + } + return AE_OK; +} + +acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context) +{ + acpi_status status; + struct acpi_object_list input; + union acpi_object in_params[4]; + union acpi_object *out_obj; + u8 uuid[16]; + u32 errors; + struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; + + if (!context) + return AE_ERROR; + if (ACPI_FAILURE(acpi_str_to_uuid(context->uuid_str, uuid))) + return AE_ERROR; + context->ret.length = ACPI_ALLOCATE_BUFFER; + context->ret.pointer = NULL; + + /* Setting up input parameters */ + input.count = 4; + input.pointer = in_params; + in_params[0].type = ACPI_TYPE_BUFFER; + in_params[0].buffer.length = 16; + in_params[0].buffer.pointer = uuid; + in_params[1].type = ACPI_TYPE_INTEGER; + in_params[1].integer.value = context->rev; + in_params[2].type = ACPI_TYPE_INTEGER; + in_params[2].integer.value = context->cap.length/sizeof(u32); + in_params[3].type = ACPI_TYPE_BUFFER; + in_params[3].buffer.length = context->cap.length; + in_params[3].buffer.pointer = context->cap.pointer; + + status = acpi_evaluate_object(handle, "_OSC", &input, &output); + if (ACPI_FAILURE(status)) + return status; + + if (!output.length) + return AE_NULL_OBJECT; + + out_obj = output.pointer; + if (out_obj->type != ACPI_TYPE_BUFFER + || out_obj->buffer.length != context->cap.length) { + acpi_print_osc_error(handle, context, + "_OSC evaluation returned wrong type"); + status = AE_TYPE; + goto out_kfree; + } + /* Need to ignore the bit0 in result code */ + errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0); + if (errors) { + if (errors & OSC_REQUEST_ERROR) + acpi_print_osc_error(handle, context, + "_OSC request failed"); + if (errors & OSC_INVALID_UUID_ERROR) + acpi_print_osc_error(handle, context, + "_OSC invalid UUID"); + if (errors & OSC_INVALID_REVISION_ERROR) + acpi_print_osc_error(handle, context, + "_OSC invalid revision"); + if (errors & OSC_CAPABILITIES_MASK_ERROR) { + if (((u32 *)context->cap.pointer)[OSC_QUERY_TYPE] + & OSC_QUERY_ENABLE) + goto out_success; + status = AE_SUPPORT; + goto out_kfree; + } + status = AE_ERROR; + goto out_kfree; + } +out_success: + context->ret.length = out_obj->buffer.length; + context->ret.pointer = kmalloc(context->ret.length, GFP_KERNEL); + if (!context->ret.pointer) { + status = AE_NO_MEMORY; + goto out_kfree; + } + memcpy(context->ret.pointer, out_obj->buffer.pointer, + context->ret.length); + status = AE_OK; + +out_kfree: + kfree(output.pointer); + if (status != AE_OK) + context->ret.pointer = NULL; + return status; +} +EXPORT_SYMBOL(acpi_run_osc); + +static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48"; +static void acpi_bus_osc_support(void) +{ + u32 capbuf[2]; + struct acpi_osc_context context = { + .uuid_str = sb_uuid_str, + .rev = 1, + .cap.length = 8, + .cap.pointer = capbuf, + }; + acpi_handle handle; + + capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; + capbuf[OSC_SUPPORT_TYPE] = OSC_SB_PR3_SUPPORT; /* _PR3 is in use */ +#if defined(CONFIG_ACPI_PROCESSOR_AGGREGATOR) ||\ + defined(CONFIG_ACPI_PROCESSOR_AGGREGATOR_MODULE) + capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_PAD_SUPPORT; +#endif + +#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) + capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_PPC_OST_SUPPORT; +#endif + if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle))) + return; + if (ACPI_SUCCESS(acpi_run_osc(handle, &context))) + kfree(context.ret.pointer); + /* do we need to check the returned cap? Sounds no */ +} + /* -------------------------------------------------------------------------- Event Management -------------------------------------------------------------------------- */ @@ -734,12 +895,16 @@ static int __init acpi_bus_init(void) status = acpi_ec_ecdt_probe(); /* Ignore result. Not having an ECDT is not fatal. */ + acpi_bus_osc_support(); + status = acpi_initialize_objects(ACPI_FULL_INITIALIZATION); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX "Unable to initialize ACPI objects\n"); goto error1; } + acpi_early_processor_set_pdc(); + /* * Maybe EC region is required at bus_scan/acpi_get_devices. So it * is necessary to enable it as early as possible. diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 0c9c6a9a002..f53fbe307c9 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -282,6 +282,13 @@ static int acpi_lid_send_state(struct acpi_device *device) if (ret == NOTIFY_DONE) ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device); + if (ret == NOTIFY_DONE || ret == NOTIFY_OK) { + /* + * It is also regarded as success if the notifier_chain + * returns NOTIFY_OK or NOTIFY_DONE. + */ + ret = 0; + } return ret; } @@ -415,11 +422,10 @@ static int acpi_button_add(struct acpi_device *device) if (device->wakeup.flags.valid) { /* Button's GPE is run-wake GPE */ - acpi_set_gpe_type(device->wakeup.gpe_device, - device->wakeup.gpe_number, - ACPI_GPE_TYPE_WAKE_RUN); acpi_enable_gpe(device->wakeup.gpe_device, - device->wakeup.gpe_number); + device->wakeup.gpe_number, + ACPI_GPE_TYPE_WAKE_RUN); + device->wakeup.run_wake_count++; device->wakeup.state.enabled = 1; } @@ -439,6 +445,14 @@ static int acpi_button_remove(struct acpi_device *device, int type) { struct acpi_button *button = acpi_driver_data(device); + if (device->wakeup.flags.valid) { + acpi_disable_gpe(device->wakeup.gpe_device, + device->wakeup.gpe_number, + ACPI_GPE_TYPE_WAKE_RUN); + device->wakeup.run_wake_count--; + device->wakeup.state.enabled = 0; + } + acpi_button_remove_fs(device); input_unregister_device(button->input); kfree(button); diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 642bb305cb6..5faf6c21257 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -258,7 +258,7 @@ static int __init acpi_container_init(void) acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, - container_walk_namespace_cb, &action, NULL); + container_walk_namespace_cb, NULL, &action, NULL); return (0); } @@ -271,7 +271,7 @@ static void __exit acpi_container_exit(void) acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, - container_walk_namespace_cb, &action, NULL); + container_walk_namespace_cb, NULL, &action, NULL); acpi_bus_unregister_driver(&acpi_container_driver); diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c index 8a690c3b8e2..cc421b7ae16 100644 --- a/drivers/acpi/debug.c +++ b/drivers/acpi/debug.c @@ -8,6 +8,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/moduleparam.h> +#include <linux/debugfs.h> #include <asm/uaccess.h> #include <acpi/acpi_drivers.h> @@ -196,6 +197,80 @@ module_param_call(trace_state, param_set_trace_state, param_get_trace_state, NULL, 0644); /* -------------------------------------------------------------------------- + DebugFS Interface + -------------------------------------------------------------------------- */ + +static ssize_t cm_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + static char *buf; + static int uncopied_bytes; + struct acpi_table_header table; + acpi_status status; + + if (!(*ppos)) { + /* parse the table header to get the table length */ + if (count <= sizeof(struct acpi_table_header)) + return -EINVAL; + if (copy_from_user(&table, user_buf, + sizeof(struct acpi_table_header))) + return -EFAULT; + uncopied_bytes = table.length; + buf = kzalloc(uncopied_bytes, GFP_KERNEL); + if (!buf) + return -ENOMEM; + } + + if (uncopied_bytes < count) { + kfree(buf); + return -EINVAL; + } + + if (copy_from_user(buf + (*ppos), user_buf, count)) { + kfree(buf); + return -EFAULT; + } + + uncopied_bytes -= count; + *ppos += count; + + if (!uncopied_bytes) { + status = acpi_install_method(buf); + kfree(buf); + if (ACPI_FAILURE(status)) + return -EINVAL; + add_taint(TAINT_OVERRIDDEN_ACPI_TABLE); + } + + return count; +} + +static const struct file_operations cm_fops = { + .write = cm_write, +}; + +static int acpi_debugfs_init(void) +{ + struct dentry *acpi_dir, *cm_dentry; + + acpi_dir = debugfs_create_dir("acpi", NULL); + if (!acpi_dir) + goto err; + + cm_dentry = debugfs_create_file("custom_method", S_IWUGO, + acpi_dir, NULL, &cm_fops); + if (!cm_dentry) + goto err; + + return 0; + +err: + if (acpi_dir) + debugfs_remove(acpi_dir); + return -EINVAL; +} + +/* -------------------------------------------------------------------------- FS Interface (/proc) -------------------------------------------------------------------------- */ #ifdef CONFIG_ACPI_PROCFS @@ -286,7 +361,7 @@ static const struct file_operations acpi_system_debug_proc_fops = { }; #endif -int __init acpi_debug_init(void) +int __init acpi_procfs_init(void) { #ifdef CONFIG_ACPI_PROCFS struct proc_dir_entry *entry; @@ -321,3 +396,10 @@ int __init acpi_debug_init(void) return 0; #endif } + +int __init acpi_debug_init(void) +{ + acpi_debugfs_init(); + acpi_procfs_init(); + return 0; +} diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 7338b6a3e04..b2586f57e1f 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -50,7 +50,6 @@ MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to " " before undocking"); static struct atomic_notifier_head dock_notifier_list; -static char dock_device_name[] = "dock"; static const struct acpi_device_id dock_device_ids[] = { {"LNXDOCK", 0}, @@ -93,40 +92,30 @@ struct dock_dependent_device { * Dock Dependent device functions * *****************************************************************************/ /** - * alloc_dock_dependent_device - allocate and init a dependent device - * @handle: the acpi_handle of the dependent device + * add_dock_dependent_device - associate a device with the dock station + * @ds: The dock station + * @handle: handle of the dependent device * - * Allocate memory for a dependent device structure for a device referenced - * by the acpi handle + * Add the dependent device to the dock's dependent device list. */ -static struct dock_dependent_device * -alloc_dock_dependent_device(acpi_handle handle) +static int +add_dock_dependent_device(struct dock_station *ds, acpi_handle handle) { struct dock_dependent_device *dd; dd = kzalloc(sizeof(*dd), GFP_KERNEL); - if (dd) { - dd->handle = handle; - INIT_LIST_HEAD(&dd->list); - INIT_LIST_HEAD(&dd->hotplug_list); - } - return dd; -} + if (!dd) + return -ENOMEM; + + dd->handle = handle; + INIT_LIST_HEAD(&dd->list); + INIT_LIST_HEAD(&dd->hotplug_list); -/** - * add_dock_dependent_device - associate a device with the dock station - * @ds: The dock station - * @dd: The dependent device - * - * Add the dependent device to the dock's dependent device list. - */ -static void -add_dock_dependent_device(struct dock_station *ds, - struct dock_dependent_device *dd) -{ spin_lock(&ds->dd_lock); list_add_tail(&dd->list, &ds->dependent_devices); spin_unlock(&ds->dd_lock); + + return 0; } /** @@ -249,6 +238,7 @@ static int is_battery(acpi_handle handle) static int is_ejectable_bay(acpi_handle handle) { acpi_handle phandle; + if (!is_ejectable(handle)) return 0; if (is_battery(handle) || is_ata(handle)) @@ -275,14 +265,13 @@ int is_dock_device(acpi_handle handle) if (is_dock(handle)) return 1; - list_for_each_entry(dock_station, &dock_stations, sibling) { + + list_for_each_entry(dock_station, &dock_stations, sibling) if (find_dock_dependent_device(dock_station, handle)) return 1; - } return 0; } - EXPORT_SYMBOL_GPL(is_dock_device); /** @@ -305,8 +294,6 @@ static int dock_present(struct dock_station *ds) return 0; } - - /** * dock_create_acpi_device - add new devices to acpi * @handle - handle of the device to add @@ -320,7 +307,7 @@ static int dock_present(struct dock_station *ds) */ static struct acpi_device * dock_create_acpi_device(acpi_handle handle) { - struct acpi_device *device = NULL; + struct acpi_device *device; struct acpi_device *parent_device; acpi_handle parent; int ret; @@ -337,8 +324,7 @@ static struct acpi_device * dock_create_acpi_device(acpi_handle handle) ret = acpi_bus_add(&device, parent_device, handle, ACPI_BUS_TYPE_DEVICE); if (ret) { - pr_debug("error adding bus, %x\n", - -ret); + pr_debug("error adding bus, %x\n", -ret); return NULL; } } @@ -364,7 +350,6 @@ static void dock_remove_acpi_device(acpi_handle handle) } } - /** * hotplug_dock_devices - insert or remove devices on the dock station * @ds: the dock station @@ -384,10 +369,9 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) /* * First call driver specific hotplug functions */ - list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) { + list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) if (dd->ops && dd->ops->handler) dd->ops->handler(dd->handle, event, dd->context); - } /* * Now make sure that an acpi_device is created for each @@ -426,6 +410,7 @@ static void dock_event(struct dock_station *ds, u32 event, int num) list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) if (dd->ops && dd->ops->uevent) dd->ops->uevent(dd->handle, event, dd->context); + if (num != DOCK_EVENT) kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); } @@ -456,8 +441,8 @@ static void eject_dock(struct dock_station *ds) arg.type = ACPI_TYPE_INTEGER; arg.integer.value = 1; - if (ACPI_FAILURE(acpi_evaluate_object(ds->handle, "_EJ0", - &arg_list, NULL))) + status = acpi_evaluate_object(ds->handle, "_EJ0", &arg_list, NULL); + if (ACPI_FAILURE(status)) pr_debug("Failed to evaluate _EJ0!\n"); } @@ -577,7 +562,6 @@ int register_dock_notifier(struct notifier_block *nb) return atomic_notifier_chain_register(&dock_notifier_list, nb); } - EXPORT_SYMBOL_GPL(register_dock_notifier); /** @@ -591,7 +575,6 @@ void unregister_dock_notifier(struct notifier_block *nb) atomic_notifier_chain_unregister(&dock_notifier_list, nb); } - EXPORT_SYMBOL_GPL(unregister_dock_notifier); /** @@ -636,7 +619,6 @@ register_hotplug_dock_device(acpi_handle handle, struct acpi_dock_ops *ops, return ret; } - EXPORT_SYMBOL_GPL(register_hotplug_dock_device); /** @@ -657,7 +639,6 @@ void unregister_hotplug_dock_device(acpi_handle handle) dock_del_hotplug_device(dock_station, dd); } } - EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); /** @@ -772,7 +753,7 @@ struct dock_data { static void acpi_dock_deferred_cb(void *context) { - struct dock_data *data = (struct dock_data *)context; + struct dock_data *data = context; dock_notify(data->handle, data->event, data->ds); kfree(data); @@ -782,23 +763,22 @@ static int acpi_dock_notifier_call(struct notifier_block *this, unsigned long event, void *data) { struct dock_station *dock_station; - acpi_handle handle = (acpi_handle)data; + acpi_handle handle = data; if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK && event != ACPI_NOTIFY_EJECT_REQUEST) return 0; list_for_each_entry(dock_station, &dock_stations, sibling) { if (dock_station->handle == handle) { - struct dock_data *dock_data; + struct dock_data *dd; - dock_data = kmalloc(sizeof(*dock_data), GFP_KERNEL); - if (!dock_data) + dd = kmalloc(sizeof(*dd), GFP_KERNEL); + if (!dd) return 0; - dock_data->handle = handle; - dock_data->event = event; - dock_data->ds = dock_station; - acpi_os_hotplug_execute(acpi_dock_deferred_cb, - dock_data); + dd->handle = handle; + dd->event = event; + dd->ds = dock_station; + acpi_os_hotplug_execute(acpi_dock_deferred_cb, dd); return 0 ; } } @@ -826,7 +806,6 @@ find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv) acpi_status status; acpi_handle tmp, parent; struct dock_station *ds = context; - struct dock_dependent_device *dd; status = acpi_bus_get_ejd(handle, &tmp); if (ACPI_FAILURE(status)) { @@ -840,11 +819,9 @@ find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv) goto fdd_out; } - if (tmp == ds->handle) { - dd = alloc_dock_dependent_device(handle); - if (dd) - add_dock_dependent_device(ds, dd); - } + if (tmp == ds->handle) + add_dock_dependent_device(ds, handle); + fdd_out: return AE_OK; } @@ -857,8 +834,7 @@ static ssize_t show_docked(struct device *dev, { struct acpi_device *tmp; - struct dock_station *dock_station = *((struct dock_station **) - dev->platform_data); + struct dock_station *dock_station = dev->platform_data; if (ACPI_SUCCESS(acpi_bus_get_device(dock_station->handle, &tmp))) return snprintf(buf, PAGE_SIZE, "1\n"); @@ -872,8 +848,7 @@ static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); static ssize_t show_flags(struct device *dev, struct device_attribute *attr, char *buf) { - struct dock_station *dock_station = *((struct dock_station **) - dev->platform_data); + struct dock_station *dock_station = dev->platform_data; return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags); } @@ -886,8 +861,7 @@ static ssize_t write_undock(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret; - struct dock_station *dock_station = *((struct dock_station **) - dev->platform_data); + struct dock_station *dock_station = dev->platform_data; if (!count) return -EINVAL; @@ -905,8 +879,7 @@ static ssize_t show_dock_uid(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long long lbuf; - struct dock_station *dock_station = *((struct dock_station **) - dev->platform_data); + struct dock_station *dock_station = dev->platform_data; acpi_status status = acpi_evaluate_integer(dock_station->handle, "_UID", NULL, &lbuf); if (ACPI_FAILURE(status)) @@ -919,8 +892,7 @@ static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL); static ssize_t show_dock_type(struct device *dev, struct device_attribute *attr, char *buf) { - struct dock_station *dock_station = *((struct dock_station **) - dev->platform_data); + struct dock_station *dock_station = dev->platform_data; char *type; if (dock_station->flags & DOCK_IS_DOCK) @@ -936,6 +908,19 @@ static ssize_t show_dock_type(struct device *dev, } static DEVICE_ATTR(type, S_IRUGO, show_dock_type, NULL); +static struct attribute *dock_attributes[] = { + &dev_attr_docked.attr, + &dev_attr_flags.attr, + &dev_attr_undock.attr, + &dev_attr_uid.attr, + &dev_attr_type.attr, + NULL +}; + +static struct attribute_group dock_attribute_group = { + .attrs = dock_attributes +}; + /** * dock_add - add a new dock station * @handle: the dock station handle @@ -945,39 +930,31 @@ static DEVICE_ATTR(type, S_IRUGO, show_dock_type, NULL); */ static int dock_add(acpi_handle handle) { - int ret; - struct dock_dependent_device *dd; - struct dock_station *dock_station; - struct platform_device *dock_device; + int ret, id; + struct dock_station ds, *dock_station; + struct platform_device *dd; + + id = dock_station_count; + memset(&ds, 0, sizeof(ds)); + dd = platform_device_register_data(NULL, "dock", id, &ds, sizeof(ds)); + if (IS_ERR(dd)) + return PTR_ERR(dd); + + dock_station = dd->dev.platform_data; - /* allocate & initialize the dock_station private data */ - dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL); - if (!dock_station) - return -ENOMEM; dock_station->handle = handle; + dock_station->dock_device = dd; dock_station->last_dock_time = jiffies - HZ; - INIT_LIST_HEAD(&dock_station->dependent_devices); - INIT_LIST_HEAD(&dock_station->hotplug_devices); - INIT_LIST_HEAD(&dock_station->sibling); - spin_lock_init(&dock_station->dd_lock); + mutex_init(&dock_station->hp_lock); + spin_lock_init(&dock_station->dd_lock); + INIT_LIST_HEAD(&dock_station->sibling); + INIT_LIST_HEAD(&dock_station->hotplug_devices); ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); - - /* initialize platform device stuff */ - dock_station->dock_device = - platform_device_register_simple(dock_device_name, - dock_station_count, NULL, 0); - dock_device = dock_station->dock_device; - if (IS_ERR(dock_device)) { - kfree(dock_station); - dock_station = NULL; - return PTR_ERR(dock_device); - } - platform_device_add_data(dock_device, &dock_station, - sizeof(struct dock_station *)); + INIT_LIST_HEAD(&dock_station->dependent_devices); /* we want the dock device to send uevents */ - dev_set_uevent_suppress(&dock_device->dev, 0); + dev_set_uevent_suppress(&dd->dev, 0); if (is_dock(handle)) dock_station->flags |= DOCK_IS_DOCK; @@ -986,106 +963,53 @@ static int dock_add(acpi_handle handle) if (is_battery(handle)) dock_station->flags |= DOCK_IS_BAT; - ret = device_create_file(&dock_device->dev, &dev_attr_docked); - if (ret) { - printk(KERN_ERR "Error %d adding sysfs file\n", ret); - platform_device_unregister(dock_device); - kfree(dock_station); - dock_station = NULL; - return ret; - } - ret = device_create_file(&dock_device->dev, &dev_attr_undock); - if (ret) { - printk(KERN_ERR "Error %d adding sysfs file\n", ret); - device_remove_file(&dock_device->dev, &dev_attr_docked); - platform_device_unregister(dock_device); - kfree(dock_station); - dock_station = NULL; - return ret; - } - ret = device_create_file(&dock_device->dev, &dev_attr_uid); - if (ret) { - printk(KERN_ERR "Error %d adding sysfs file\n", ret); - device_remove_file(&dock_device->dev, &dev_attr_docked); - device_remove_file(&dock_device->dev, &dev_attr_undock); - platform_device_unregister(dock_device); - kfree(dock_station); - dock_station = NULL; - return ret; - } - ret = device_create_file(&dock_device->dev, &dev_attr_flags); - if (ret) { - printk(KERN_ERR "Error %d adding sysfs file\n", ret); - device_remove_file(&dock_device->dev, &dev_attr_docked); - device_remove_file(&dock_device->dev, &dev_attr_undock); - device_remove_file(&dock_device->dev, &dev_attr_uid); - platform_device_unregister(dock_device); - kfree(dock_station); - dock_station = NULL; - return ret; - } - ret = device_create_file(&dock_device->dev, &dev_attr_type); + ret = sysfs_create_group(&dd->dev.kobj, &dock_attribute_group); if (ret) - printk(KERN_ERR"Error %d adding sysfs file\n", ret); + goto err_unregister; /* Find dependent devices */ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, find_dock_devices, dock_station, - NULL); + ACPI_UINT32_MAX, find_dock_devices, NULL, + dock_station, NULL); /* add the dock station as a device dependent on itself */ - dd = alloc_dock_dependent_device(handle); - if (!dd) { - kfree(dock_station); - dock_station = NULL; - ret = -ENOMEM; - goto dock_add_err_unregister; - } - add_dock_dependent_device(dock_station, dd); + ret = add_dock_dependent_device(dock_station, handle); + if (ret) + goto err_rmgroup; dock_station_count++; list_add(&dock_station->sibling, &dock_stations); return 0; -dock_add_err_unregister: - device_remove_file(&dock_device->dev, &dev_attr_type); - device_remove_file(&dock_device->dev, &dev_attr_docked); - device_remove_file(&dock_device->dev, &dev_attr_undock); - device_remove_file(&dock_device->dev, &dev_attr_uid); - device_remove_file(&dock_device->dev, &dev_attr_flags); - platform_device_unregister(dock_device); - kfree(dock_station); - dock_station = NULL; +err_rmgroup: + sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group); +err_unregister: + platform_device_unregister(dd); + printk(KERN_ERR "%s encountered error %d\n", __func__, ret); return ret; } /** * dock_remove - free up resources related to the dock station */ -static int dock_remove(struct dock_station *dock_station) +static int dock_remove(struct dock_station *ds) { struct dock_dependent_device *dd, *tmp; - struct platform_device *dock_device = dock_station->dock_device; + struct platform_device *dock_device = ds->dock_device; if (!dock_station_count) return 0; /* remove dependent devices */ - list_for_each_entry_safe(dd, tmp, &dock_station->dependent_devices, - list) - kfree(dd); + list_for_each_entry_safe(dd, tmp, &ds->dependent_devices, list) + kfree(dd); + + list_del(&ds->sibling); /* cleanup sysfs */ - device_remove_file(&dock_device->dev, &dev_attr_type); - device_remove_file(&dock_device->dev, &dev_attr_docked); - device_remove_file(&dock_device->dev, &dev_attr_undock); - device_remove_file(&dock_device->dev, &dev_attr_uid); - device_remove_file(&dock_device->dev, &dev_attr_flags); + sysfs_remove_group(&dock_device->dev.kobj, &dock_attribute_group); platform_device_unregister(dock_device); - /* free dock station memory */ - kfree(dock_station); - dock_station = NULL; return 0; } @@ -1103,11 +1027,10 @@ find_dock(acpi_handle handle, u32 lvl, void *context, void **rv) { acpi_status status = AE_OK; - if (is_dock(handle)) { - if (dock_add(handle) >= 0) { + if (is_dock(handle)) + if (dock_add(handle) >= 0) status = AE_CTRL_TERMINATE; - } - } + return status; } @@ -1127,11 +1050,11 @@ static int __init dock_init(void) /* look for a dock station */ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, find_dock, NULL, NULL); + ACPI_UINT32_MAX, find_dock, NULL, NULL, NULL); /* look for bay */ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, find_bay, NULL, NULL); + ACPI_UINT32_MAX, find_bay, NULL, NULL, NULL); if (!dock_station_count) { printk(KERN_INFO PREFIX "No dock devices found.\n"); return 0; @@ -1145,8 +1068,7 @@ static int __init dock_init(void) static void __exit dock_exit(void) { - struct dock_station *dock_station; - struct dock_station *tmp; + struct dock_station *tmp, *dock_station; unregister_acpi_bus_notifier(&dock_acpi_notifier); list_for_each_entry_safe(dock_station, tmp, &dock_stations, sibling) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index baef28c1e63..27e0b92b2e3 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -201,14 +201,13 @@ unlock: spin_unlock_irqrestore(&ec->curr_lock, flags); } -static void acpi_ec_gpe_query(void *ec_cxt); +static int acpi_ec_sync_query(struct acpi_ec *ec); -static int ec_check_sci(struct acpi_ec *ec, u8 state) +static int ec_check_sci_sync(struct acpi_ec *ec, u8 state) { if (state & ACPI_EC_FLAG_SCI) { if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) - return acpi_os_execute(OSL_EC_BURST_HANDLER, - acpi_ec_gpe_query, ec); + return acpi_ec_sync_query(ec); } return 0; } @@ -249,11 +248,6 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, { unsigned long tmp; int ret = 0; - pr_debug(PREFIX "transaction start\n"); - /* disable GPE during transaction if storm is detected */ - if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { - acpi_disable_gpe(NULL, ec->gpe); - } if (EC_FLAGS_MSI) udelay(ACPI_EC_MSI_UDELAY); /* start transaction */ @@ -265,20 +259,9 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); spin_unlock_irqrestore(&ec->curr_lock, tmp); ret = ec_poll(ec); - pr_debug(PREFIX "transaction end\n"); spin_lock_irqsave(&ec->curr_lock, tmp); ec->curr = NULL; spin_unlock_irqrestore(&ec->curr_lock, tmp); - if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { - /* check if we received SCI during transaction */ - ec_check_sci(ec, acpi_ec_read_status(ec)); - /* it is safe to enable GPE outside of transaction */ - acpi_enable_gpe(NULL, ec->gpe); - } else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) { - pr_info(PREFIX "GPE storm detected, " - "transactions will use polling mode\n"); - set_bit(EC_FLAGS_GPE_STORM, &ec->flags); - } return ret; } @@ -321,7 +304,34 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) status = -ETIME; goto end; } + pr_debug(PREFIX "transaction start\n"); + /* disable GPE during transaction if storm is detected */ + if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { + /* + * It has to be disabled at the hardware level regardless of the + * GPE reference counting, so that it doesn't trigger. + */ + acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE); + } + status = acpi_ec_transaction_unlocked(ec, t); + + /* check if we received SCI during transaction */ + ec_check_sci_sync(ec, acpi_ec_read_status(ec)); + if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { + msleep(1); + /* + * It is safe to enable the GPE outside of the transaction. Use + * acpi_set_gpe() for that, since we used it to disable the GPE + * above. + */ + acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE); + } else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) { + pr_info(PREFIX "GPE storm detected, " + "transactions will use polling mode\n"); + set_bit(EC_FLAGS_GPE_STORM, &ec->flags); + } + pr_debug(PREFIX "transaction end\n"); end: if (ec->global_lock) acpi_release_global_lock(glk); @@ -443,7 +453,7 @@ int ec_transaction(u8 command, EXPORT_SYMBOL(ec_transaction); -static int acpi_ec_query(struct acpi_ec *ec, u8 * data) +static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data) { int result; u8 d; @@ -452,20 +462,16 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data) .wlen = 0, .rlen = 1}; if (!ec || !data) return -EINVAL; - /* * Query the EC to find out which _Qxx method we need to evaluate. * Note that successful completion of the query causes the ACPI_EC_SCI * bit to be cleared (and thus clearing the interrupt source). */ - - result = acpi_ec_transaction(ec, &t); + result = acpi_ec_transaction_unlocked(ec, &t); if (result) return result; - if (!d) return -ENODATA; - *data = d; return 0; } @@ -509,43 +515,79 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); -static void acpi_ec_gpe_query(void *ec_cxt) +static void acpi_ec_run(void *cxt) { - struct acpi_ec *ec = ec_cxt; - u8 value = 0; - struct acpi_ec_query_handler *handler, copy; - - if (!ec || acpi_ec_query(ec, &value)) + struct acpi_ec_query_handler *handler = cxt; + if (!handler) return; - mutex_lock(&ec->lock); + pr_debug(PREFIX "start query execution\n"); + if (handler->func) + handler->func(handler->data); + else if (handler->handle) + acpi_evaluate_object(handler->handle, NULL, NULL, NULL); + pr_debug(PREFIX "stop query execution\n"); + kfree(handler); +} + +static int acpi_ec_sync_query(struct acpi_ec *ec) +{ + u8 value = 0; + int status; + struct acpi_ec_query_handler *handler, *copy; + if ((status = acpi_ec_query_unlocked(ec, &value))) + return status; list_for_each_entry(handler, &ec->list, node) { if (value == handler->query_bit) { /* have custom handler for this bit */ - memcpy(©, handler, sizeof(copy)); - mutex_unlock(&ec->lock); - if (copy.func) { - copy.func(copy.data); - } else if (copy.handle) { - acpi_evaluate_object(copy.handle, NULL, NULL, NULL); - } - return; + copy = kmalloc(sizeof(*handler), GFP_KERNEL); + if (!copy) + return -ENOMEM; + memcpy(copy, handler, sizeof(*copy)); + pr_debug(PREFIX "push query execution (0x%2x) on queue\n", value); + return acpi_os_execute((copy->func) ? + OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER, + acpi_ec_run, copy); } } + return 0; +} + +static void acpi_ec_gpe_query(void *ec_cxt) +{ + struct acpi_ec *ec = ec_cxt; + if (!ec) + return; + mutex_lock(&ec->lock); + acpi_ec_sync_query(ec); mutex_unlock(&ec->lock); } +static void acpi_ec_gpe_query(void *ec_cxt); + +static int ec_check_sci(struct acpi_ec *ec, u8 state) +{ + if (state & ACPI_EC_FLAG_SCI) { + if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { + pr_debug(PREFIX "push gpe query to the queue\n"); + return acpi_os_execute(OSL_NOTIFY_HANDLER, + acpi_ec_gpe_query, ec); + } + } + return 0; +} + static u32 acpi_ec_gpe_handler(void *data) { struct acpi_ec *ec = data; - u8 status; pr_debug(PREFIX "~~~> interrupt\n"); - status = acpi_ec_read_status(ec); - advance_transaction(ec, status); - if (ec_transaction_done(ec) && (status & ACPI_EC_FLAG_IBF) == 0) + advance_transaction(ec, acpi_ec_read_status(ec)); + if (ec_transaction_done(ec) && + (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) { wake_up(&ec->wait); - ec_check_sci(ec, status); + ec_check_sci(ec, acpi_ec_read_status(ec)); + } return ACPI_INTERRUPT_HANDLED; } @@ -754,8 +796,8 @@ static int ec_install_handlers(struct acpi_ec *ec) &acpi_ec_gpe_handler, ec); if (ACPI_FAILURE(status)) return -ENODEV; - acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); - acpi_enable_gpe(NULL, ec->gpe); + + acpi_enable_gpe(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); status = acpi_install_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler, @@ -772,6 +814,7 @@ static int ec_install_handlers(struct acpi_ec *ec) } else { acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler); + acpi_disable_gpe(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); return -ENODEV; } } @@ -782,6 +825,7 @@ static int ec_install_handlers(struct acpi_ec *ec) static void ec_remove_handlers(struct acpi_ec *ec) { + acpi_disable_gpe(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) pr_err(PREFIX "failed to remove space handler\n"); @@ -820,7 +864,7 @@ static int acpi_ec_add(struct acpi_device *device) /* Find and register all query methods */ acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1, - acpi_ec_register_query_methods, ec, NULL); + acpi_ec_register_query_methods, NULL, ec, NULL); if (!first_ec) first_ec = ec; @@ -916,6 +960,7 @@ static int ec_validate_ecdt(const struct dmi_system_id *id) /* MSI EC needs special treatment, enable it */ static int ec_flag_msi(const struct dmi_system_id *id) { + printk(KERN_DEBUG PREFIX "Detected MSI hardware, enabling workarounds.\n"); EC_FLAGS_MSI = 1; EC_FLAGS_VALIDATE_ECDT = 1; return 0; @@ -928,8 +973,13 @@ static struct dmi_system_id __initdata ec_dmi_table[] = { DMI_MATCH(DMI_BOARD_NAME, "JFL92") }, NULL}, { ec_flag_msi, "MSI hardware", { - DMI_MATCH(DMI_BIOS_VENDOR, "Micro-Star"), - DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-Star") }, NULL}, + DMI_MATCH(DMI_BIOS_VENDOR, "Micro-Star")}, NULL}, + { + ec_flag_msi, "MSI hardware", { + DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star")}, NULL}, + { + ec_flag_msi, "MSI hardware", { + DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-Star")}, NULL}, { ec_validate_ecdt, "ASUS hardware", { DMI_MATCH(DMI_BIOS_VENDOR, "ASUS") }, NULL}, @@ -1017,16 +1067,16 @@ error: static int acpi_ec_suspend(struct acpi_device *device, pm_message_t state) { struct acpi_ec *ec = acpi_driver_data(device); - /* Stop using GPE */ - acpi_disable_gpe(NULL, ec->gpe); + /* Stop using the GPE, but keep it reference counted. */ + acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE); return 0; } static int acpi_ec_resume(struct acpi_device *device) { struct acpi_ec *ec = acpi_driver_data(device); - /* Enable use of GPE back */ - acpi_enable_gpe(NULL, ec->gpe); + /* Enable the GPE again, but don't reference count it once more. */ + acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE); return 0; } diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index f419849a0d3..acf2ab24984 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -267,7 +267,7 @@ static int acpi_fan_add(struct acpi_device *device) goto end; } - dev_info(&device->dev, "registered as cooling_device%d\n", cdev->id); + dev_dbg(&device->dev, "registered as cooling_device%d\n", cdev->id); device->driver_data = cdev; result = sysfs_create_link(&device->dev.kobj, diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index c6645f26224..4c8fcff662c 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -113,7 +113,7 @@ acpi_handle acpi_get_child(acpi_handle parent, acpi_integer address) if (!parent) return NULL; acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, - 1, do_acpi_find_child, &find, NULL); + 1, do_acpi_find_child, NULL, &find, NULL); return find.handle; } diff --git a/drivers/acpi/hest.c b/drivers/acpi/hest.c new file mode 100644 index 00000000000..4bb18c980ac --- /dev/null +++ b/drivers/acpi/hest.c @@ -0,0 +1,135 @@ +#include <linux/acpi.h> +#include <linux/pci.h> + +#define PREFIX "ACPI: " + +static inline unsigned long parse_acpi_hest_ia_machine_check(struct acpi_hest_ia_machine_check *p) +{ + return sizeof(*p) + + (sizeof(struct acpi_hest_ia_error_bank) * p->num_hardware_banks); +} + +static inline unsigned long parse_acpi_hest_ia_corrected(struct acpi_hest_ia_corrected *p) +{ + return sizeof(*p) + + (sizeof(struct acpi_hest_ia_error_bank) * p->num_hardware_banks); +} + +static inline unsigned long parse_acpi_hest_ia_nmi(struct acpi_hest_ia_nmi *p) +{ + return sizeof(*p); +} + +static inline unsigned long parse_acpi_hest_generic(struct acpi_hest_generic *p) +{ + return sizeof(*p); +} + +static inline unsigned int hest_match_pci(struct acpi_hest_aer_common *p, struct pci_dev *pci) +{ + return (0 == pci_domain_nr(pci->bus) && + p->bus == pci->bus->number && + p->device == PCI_SLOT(pci->devfn) && + p->function == PCI_FUNC(pci->devfn)); +} + +static unsigned long parse_acpi_hest_aer(void *hdr, int type, struct pci_dev *pci, int *firmware_first) +{ + struct acpi_hest_aer_common *p = hdr + sizeof(struct acpi_hest_header); + unsigned long rc=0; + u8 pcie_type = 0; + u8 bridge = 0; + switch (type) { + case ACPI_HEST_TYPE_AER_ROOT_PORT: + rc = sizeof(struct acpi_hest_aer_root); + pcie_type = PCI_EXP_TYPE_ROOT_PORT; + break; + case ACPI_HEST_TYPE_AER_ENDPOINT: + rc = sizeof(struct acpi_hest_aer); + pcie_type = PCI_EXP_TYPE_ENDPOINT; + break; + case ACPI_HEST_TYPE_AER_BRIDGE: + rc = sizeof(struct acpi_hest_aer_bridge); + if ((pci->class >> 16) == PCI_BASE_CLASS_BRIDGE) + bridge = 1; + break; + } + + if (p->flags & ACPI_HEST_GLOBAL) { + if ((pci->is_pcie && (pci->pcie_type == pcie_type)) || bridge) + *firmware_first = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST); + } + else + if (hest_match_pci(p, pci)) + *firmware_first = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST); + return rc; +} + +static int acpi_hest_firmware_first(struct acpi_table_header *stdheader, struct pci_dev *pci) +{ + struct acpi_table_hest *hest = (struct acpi_table_hest *)stdheader; + void *p = (void *)hest + sizeof(*hest); /* defined by the ACPI 4.0 spec */ + struct acpi_hest_header *hdr = p; + + int i; + int firmware_first = 0; + static unsigned char printed_unused = 0; + static unsigned char printed_reserved = 0; + + for (i=0, hdr=p; p < (((void *)hest) + hest->header.length) && i < hest->error_source_count; i++) { + switch (hdr->type) { + case ACPI_HEST_TYPE_IA32_CHECK: + p += parse_acpi_hest_ia_machine_check(p); + break; + case ACPI_HEST_TYPE_IA32_CORRECTED_CHECK: + p += parse_acpi_hest_ia_corrected(p); + break; + case ACPI_HEST_TYPE_IA32_NMI: + p += parse_acpi_hest_ia_nmi(p); + break; + /* These three should never appear */ + case ACPI_HEST_TYPE_NOT_USED3: + case ACPI_HEST_TYPE_NOT_USED4: + case ACPI_HEST_TYPE_NOT_USED5: + if (!printed_unused) { + printk(KERN_DEBUG PREFIX + "HEST Error Source list contains an obsolete type (%d).\n", hdr->type); + printed_unused = 1; + } + break; + case ACPI_HEST_TYPE_AER_ROOT_PORT: + case ACPI_HEST_TYPE_AER_ENDPOINT: + case ACPI_HEST_TYPE_AER_BRIDGE: + p += parse_acpi_hest_aer(p, hdr->type, pci, &firmware_first); + break; + case ACPI_HEST_TYPE_GENERIC_ERROR: + p += parse_acpi_hest_generic(p); + break; + /* These should never appear either */ + case ACPI_HEST_TYPE_RESERVED: + default: + if (!printed_reserved) { + printk(KERN_DEBUG PREFIX + "HEST Error Source list contains a reserved type (%d).\n", hdr->type); + printed_reserved = 1; + } + break; + } + } + return firmware_first; +} + +int acpi_hest_firmware_first_pci(struct pci_dev *pci) +{ + acpi_status status = AE_NOT_FOUND; + struct acpi_table_header *hest = NULL; + status = acpi_get_table(ACPI_SIG_HEST, 1, &hest); + + if (ACPI_SUCCESS(status)) { + if (acpi_hest_firmware_first(hest, pci)) { + return 1; + } + } + return 0; +} +EXPORT_SYMBOL_GPL(acpi_hest_firmware_first_pci); diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 074cf8682d5..9c4c962e46e 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -36,13 +36,12 @@ static inline int acpi_debug_init(void) { return 0; } int acpi_power_init(void); int acpi_device_sleep_wake(struct acpi_device *dev, int enable, int sleep_state, int dev_state); -int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state); -int acpi_disable_wakeup_device_power(struct acpi_device *dev); int acpi_power_get_inferred_state(struct acpi_device *device); int acpi_power_transition(struct acpi_device *device, int state); extern int acpi_power_nocheck; int acpi_wakeup_device_init(void); +void acpi_early_processor_set_pdc(void); /* -------------------------------------------------------------------------- Embedded Controller diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 202dd0c976a..7ad48dfc12d 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -28,6 +28,7 @@ #include <linux/types.h> #include <linux/errno.h> #include <linux/acpi.h> +#include <linux/numa.h> #include <acpi/acpi_bus.h> #define PREFIX "ACPI: " @@ -40,14 +41,14 @@ static nodemask_t nodes_found_map = NODE_MASK_NONE; /* maps to convert between proximity domain and logical node ID */ static int pxm_to_node_map[MAX_PXM_DOMAINS] - = { [0 ... MAX_PXM_DOMAINS - 1] = NID_INVAL }; + = { [0 ... MAX_PXM_DOMAINS - 1] = NUMA_NO_NODE }; static int node_to_pxm_map[MAX_NUMNODES] - = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; + = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; int pxm_to_node(int pxm) { if (pxm < 0) - return NID_INVAL; + return NUMA_NO_NODE; return pxm_to_node_map[pxm]; } @@ -68,9 +69,9 @@ int acpi_map_pxm_to_node(int pxm) { int node = pxm_to_node_map[pxm]; - if (node < 0){ + if (node < 0) { if (nodes_weight(nodes_found_map) >= MAX_NUMNODES) - return NID_INVAL; + return NUMA_NO_NODE; node = first_unset_node(nodes_found_map); __acpi_map_pxm_to_node(pxm, node); node_set(node, nodes_found_map); @@ -79,16 +80,6 @@ int acpi_map_pxm_to_node(int pxm) return node; } -#if 0 -void __cpuinit acpi_unmap_pxm_to_node(int node) -{ - int pxm = node_to_pxm_map[node]; - pxm_to_node_map[pxm] = NID_INVAL; - node_to_pxm_map[node] = PXM_INVAL; - node_clear(node, nodes_found_map); -} -#endif /* 0 */ - static void __init acpi_table_print_srat_entry(struct acpi_subtable_header *header) { @@ -283,22 +274,24 @@ acpi_table_parse_srat(enum acpi_srat_type id, int __init acpi_numa_init(void) { + int ret = 0; + /* SRAT: Static Resource Affinity Table */ if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) { acpi_table_parse_srat(ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY, acpi_parse_x2apic_affinity, NR_CPUS); acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY, acpi_parse_processor_affinity, NR_CPUS); - acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY, - acpi_parse_memory_affinity, - NR_NODE_MEMBLKS); + ret = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY, + acpi_parse_memory_affinity, + NR_NODE_MEMBLKS); } /* SLIT: System Locality Information Table */ acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit); acpi_numa_arch_fixup(); - return 0; + return ret; } int acpi_get_pxm(acpi_handle h) diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 7c1c59ea9ec..02e8464e480 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1118,7 +1118,7 @@ __setup("acpi_enforce_resources=", acpi_enforce_resources_setup); /* Check for resource conflicts between ACPI OperationRegions and native * drivers */ -int acpi_check_resource_conflict(struct resource *res) +int acpi_check_resource_conflict(const struct resource *res) { struct acpi_res_list *res_list_elem; int ioport; diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c index a5a77b78a72..2ef04098cc1 100644 --- a/drivers/acpi/pci_bind.c +++ b/drivers/acpi/pci_bind.c @@ -26,7 +26,9 @@ #include <linux/kernel.h> #include <linux/types.h> #include <linux/pci.h> +#include <linux/pci-acpi.h> #include <linux/acpi.h> +#include <linux/pm_runtime.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> @@ -38,7 +40,13 @@ static int acpi_pci_unbind(struct acpi_device *device) struct pci_dev *dev; dev = acpi_get_pci_dev(device->handle); - if (!dev || !dev->subordinate) + if (!dev) + goto out; + + device_set_run_wake(&dev->dev, false); + pci_acpi_remove_pm_notifier(device); + + if (!dev->subordinate) goto out; acpi_pci_irq_del_prt(dev->subordinate); @@ -62,6 +70,10 @@ static int acpi_pci_bind(struct acpi_device *device) if (!dev) return 0; + pci_acpi_add_pm_notifier(device, dev); + if (device->wakeup.flags.run_wake) + device_set_run_wake(&dev->dev, true); + /* * Install the 'bind' function to facilitate callbacks for * children of the P2P bridge. diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 394ae89409c..04b0f007c9b 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -56,7 +56,7 @@ ACPI_MODULE_NAME("pci_link"); static int acpi_pci_link_add(struct acpi_device *device); static int acpi_pci_link_remove(struct acpi_device *device, int type); -static struct acpi_device_id link_device_ids[] = { +static const struct acpi_device_id link_device_ids[] = { {"PNP0C0F", 0}, {"", 0}, }; diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 1af808171d4..d724736d56c 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -30,6 +30,7 @@ #include <linux/proc_fs.h> #include <linux/spinlock.h> #include <linux/pm.h> +#include <linux/pm_runtime.h> #include <linux/pci.h> #include <linux/pci-acpi.h> #include <linux/acpi.h> @@ -46,7 +47,7 @@ static int acpi_pci_root_add(struct acpi_device *device); static int acpi_pci_root_remove(struct acpi_device *device, int type); static int acpi_pci_root_start(struct acpi_device *device); -static struct acpi_device_id root_device_ids[] = { +static const struct acpi_device_id root_device_ids[] = { {"PNP0A03", 0}, {"", 0}, }; @@ -202,72 +203,24 @@ static void acpi_pci_bridge_scan(struct acpi_device *device) } } -static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, - 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66}; +static u8 pci_osc_uuid_str[] = "33DB4D5B-1FF7-401C-9657-7441C03DD766"; static acpi_status acpi_pci_run_osc(acpi_handle handle, const u32 *capbuf, u32 *retval) { + struct acpi_osc_context context = { + .uuid_str = pci_osc_uuid_str, + .rev = 1, + .cap.length = 12, + .cap.pointer = (void *)capbuf, + }; acpi_status status; - struct acpi_object_list input; - union acpi_object in_params[4]; - struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; - union acpi_object *out_obj; - u32 errors; - - /* Setting up input parameters */ - input.count = 4; - input.pointer = in_params; - in_params[0].type = ACPI_TYPE_BUFFER; - in_params[0].buffer.length = 16; - in_params[0].buffer.pointer = OSC_UUID; - in_params[1].type = ACPI_TYPE_INTEGER; - in_params[1].integer.value = 1; - in_params[2].type = ACPI_TYPE_INTEGER; - in_params[2].integer.value = 3; - in_params[3].type = ACPI_TYPE_BUFFER; - in_params[3].buffer.length = 12; - in_params[3].buffer.pointer = (u8 *)capbuf; - - status = acpi_evaluate_object(handle, "_OSC", &input, &output); - if (ACPI_FAILURE(status)) - return status; - - if (!output.length) - return AE_NULL_OBJECT; - out_obj = output.pointer; - if (out_obj->type != ACPI_TYPE_BUFFER) { - printk(KERN_DEBUG "_OSC evaluation returned wrong type\n"); - status = AE_TYPE; - goto out_kfree; - } - /* Need to ignore the bit0 in result code */ - errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0); - if (errors) { - if (errors & OSC_REQUEST_ERROR) - printk(KERN_DEBUG "_OSC request failed\n"); - if (errors & OSC_INVALID_UUID_ERROR) - printk(KERN_DEBUG "_OSC invalid UUID\n"); - if (errors & OSC_INVALID_REVISION_ERROR) - printk(KERN_DEBUG "_OSC invalid revision\n"); - if (errors & OSC_CAPABILITIES_MASK_ERROR) { - if (capbuf[OSC_QUERY_TYPE] & OSC_QUERY_ENABLE) - goto out_success; - printk(KERN_DEBUG - "Firmware did not grant requested _OSC control\n"); - status = AE_SUPPORT; - goto out_kfree; - } - status = AE_ERROR; - goto out_kfree; + status = acpi_run_osc(handle, &context); + if (ACPI_SUCCESS(status)) { + *retval = *((u32 *)(context.ret.pointer + 8)); + kfree(context.ret.pointer); } -out_success: - *retval = *((u32 *)(out_obj->buffer.pointer + 8)); - status = AE_OK; - -out_kfree: - kfree(output.pointer); return status; } @@ -277,10 +230,10 @@ static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, u32 flags) u32 support_set, result, capbuf[3]; /* do _OSC query for all possible controls */ - support_set = root->osc_support_set | (flags & OSC_SUPPORT_MASKS); + support_set = root->osc_support_set | (flags & OSC_PCI_SUPPORT_MASKS); capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; capbuf[OSC_SUPPORT_TYPE] = support_set; - capbuf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS; + capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS; status = acpi_pci_run_osc(root->device->handle, capbuf, &result); if (ACPI_SUCCESS(status)) { @@ -427,7 +380,7 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags) if (ACPI_FAILURE(status)) return status; - control_req = (flags & OSC_CONTROL_MASKS); + control_req = (flags & OSC_PCI_CONTROL_MASKS); if (!control_req) return AE_TYPE; @@ -576,6 +529,10 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) if (flags != base_flags) acpi_pci_osc_support(root, flags); + pci_acpi_add_bus_pm_notifier(device, root->bus); + if (device->wakeup.flags.run_wake) + device_set_run_wake(root->bus->bridge, true); + return 0; end: @@ -597,6 +554,9 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type) { struct acpi_pci_root *root = acpi_driver_data(device); + device_set_run_wake(root->bus->bridge, false); + pci_acpi_remove_bus_pm_notifier(device); + kfree(root); return 0; } @@ -606,6 +566,7 @@ static int __init acpi_pci_root_init(void) if (acpi_pci_disabled) return 0; + pci_acpi_crs_quirks(); if (acpi_bus_register_driver(&acpi_pci_root_driver) < 0) return -ENODEV; diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index 45da2bae36c..11f21974320 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c @@ -219,12 +219,12 @@ walk_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) dbg("p2p bridge walk, pci_bus = %x\n", dev->subordinate->number); status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, - user_function, &child_context, NULL); + user_function, NULL, &child_context, NULL); if (ACPI_FAILURE(status)) goto out; status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, - walk_p2p_bridge, &child_context, NULL); + walk_p2p_bridge, NULL, &child_context, NULL); out: pci_dev_put(dev); return AE_OK; @@ -277,12 +277,12 @@ walk_root_bridge(acpi_handle handle, acpi_walk_callback user_function) dbg("root bridge walk, pci_bus = %x\n", pci_bus->number); status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, - user_function, &context, NULL); + user_function, NULL, &context, NULL); if (ACPI_FAILURE(status)) return status; status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, - walk_p2p_bridge, &context, NULL); + walk_p2p_bridge, NULL, &context, NULL); if (ACPI_FAILURE(status)) err("%s: walk_p2p_bridge failure - %d\n", __func__, status); diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 22b29791651..0f30c3c1eea 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -65,7 +65,7 @@ static int acpi_power_remove(struct acpi_device *device, int type); static int acpi_power_resume(struct acpi_device *device); static int acpi_power_open_fs(struct inode *inode, struct file *file); -static struct acpi_device_id power_device_ids[] = { +static const struct acpi_device_id power_device_ids[] = { {ACPI_POWER_HID, 0}, {"", 0}, }; diff --git a/drivers/acpi/power_meter.c b/drivers/acpi/power_meter.c index e6bfd77986b..dc4ffadf812 100644 --- a/drivers/acpi/power_meter.c +++ b/drivers/acpi/power_meter.c @@ -64,7 +64,7 @@ static int can_cap_in_hardware(void) return force_cap_on || cap_in_hardware; } -static struct acpi_device_id power_meter_ids[] = { +static const struct acpi_device_id power_meter_ids[] = { {"ACPI000D", 0}, {"", 0}, }; @@ -294,7 +294,11 @@ static int set_acpi_trip(struct acpi_power_meter_resource *resource) return -EINVAL; } - return data; + /* _PTP returns 0 on success, nonzero otherwise */ + if (data) + return -EINVAL; + + return 0; } static ssize_t set_trip(struct device *dev, struct device_attribute *devattr, @@ -530,6 +534,7 @@ static void remove_domain_devices(struct acpi_power_meter_resource *resource) kfree(resource->domain_devices); kobject_put(resource->holders_dir); + resource->num_domain_devices = 0; } static int read_domain_devices(struct acpi_power_meter_resource *resource) @@ -736,7 +741,6 @@ skip_unsafe_cap: return res; error: - remove_domain_devices(resource); remove_attrs(resource); return res; } diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c index f8b6f555ba5..d0d25e2e1ce 100644 --- a/drivers/acpi/proc.c +++ b/drivers/acpi/proc.c @@ -393,7 +393,7 @@ acpi_system_write_wakeup_device(struct file *file, struct list_head *node, *next; char strbuf[5]; char str[5] = ""; - int len = count; + unsigned int len = count; struct acpi_device *found_dev = NULL; if (len > 4) diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index c567b46dfa0..9863c98c81b 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -124,29 +124,6 @@ static const struct file_operations acpi_processor_info_fops = { DEFINE_PER_CPU(struct acpi_processor *, processors); struct acpi_processor_errata errata __read_mostly; -static int set_no_mwait(const struct dmi_system_id *id) -{ - printk(KERN_NOTICE PREFIX "%s detected - " - "disabling mwait for CPU C-states\n", id->ident); - idle_nomwait = 1; - return 0; -} - -static struct dmi_system_id __cpuinitdata processor_idle_dmi_table[] = { - { - set_no_mwait, "IFL91 board", { - DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"), - DMI_MATCH(DMI_SYS_VENDOR, "ZEPTO"), - DMI_MATCH(DMI_PRODUCT_VERSION, "3215W"), - DMI_MATCH(DMI_BOARD_NAME, "IFL91") }, NULL}, - { - set_no_mwait, "Extensa 5220", { - DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_VERSION, "0100"), - DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL}, - {}, -}; /* -------------------------------------------------------------------------- Errata Handling @@ -277,45 +254,6 @@ static int acpi_processor_errata(struct acpi_processor *pr) } /* -------------------------------------------------------------------------- - Common ACPI processor functions - -------------------------------------------------------------------------- */ - -/* - * _PDC is required for a BIOS-OS handshake for most of the newer - * ACPI processor features. - */ -static int acpi_processor_set_pdc(struct acpi_processor *pr) -{ - struct acpi_object_list *pdc_in = pr->pdc; - acpi_status status = AE_OK; - - - if (!pdc_in) - return status; - if (idle_nomwait) { - /* - * If mwait is disabled for CPU C-states, the C2C3_FFH access - * mode will be disabled in the parameter of _PDC object. - * Of course C1_FFH access mode will also be disabled. - */ - union acpi_object *obj; - u32 *buffer = NULL; - - obj = pdc_in->pointer; - buffer = (u32 *)(obj->buffer.pointer); - buffer[2] &= ~(ACPI_PDC_C_C2C3_FFH | ACPI_PDC_C_C1_FFH); - - } - status = acpi_evaluate_object(pr->handle, "_PDC", pdc_in, NULL); - - if (ACPI_FAILURE(status)) - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Could not evaluate _PDC, using legacy perf. control...\n")); - - return status; -} - -/* -------------------------------------------------------------------------- FS Interface (/proc) -------------------------------------------------------------------------- */ @@ -353,7 +291,7 @@ static int acpi_processor_info_open_fs(struct inode *inode, struct file *file) PDE(inode)->data); } -static int acpi_processor_add_fs(struct acpi_device *device) +static int __cpuinit acpi_processor_add_fs(struct acpi_device *device) { struct proc_dir_entry *entry = NULL; @@ -722,7 +660,7 @@ static void acpi_processor_notify(struct acpi_device *device, u32 event) switch (event) { case ACPI_PROCESSOR_NOTIFY_PERFORMANCE: saved = pr->performance_platform_limit; - acpi_processor_ppc_has_changed(pr); + acpi_processor_ppc_has_changed(pr, 1); if (saved == pr->performance_platform_limit) break; acpi_bus_generate_proc_event(device, event, @@ -758,7 +696,7 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb, struct acpi_processor *pr = per_cpu(processors, cpu); if (action == CPU_ONLINE && pr) { - acpi_processor_ppc_has_changed(pr); + acpi_processor_ppc_has_changed(pr, 0); acpi_processor_cst_has_changed(pr); acpi_processor_tstate_has_changed(pr); } @@ -770,7 +708,7 @@ static struct notifier_block acpi_cpu_notifier = .notifier_call = acpi_cpu_soft_notify, }; -static int acpi_processor_add(struct acpi_device *device) +static int __cpuinit acpi_processor_add(struct acpi_device *device) { struct acpi_processor *pr = NULL; int result = 0; @@ -825,12 +763,10 @@ static int acpi_processor_add(struct acpi_device *device) } /* _PDC call should be done before doing anything else (if reqd.). */ - arch_acpi_processor_init_pdc(pr); - acpi_processor_set_pdc(pr); - arch_acpi_processor_cleanup_pdc(pr); + acpi_processor_set_pdc(pr->handle); #ifdef CONFIG_CPU_FREQ - acpi_processor_ppc_has_changed(pr); + acpi_processor_ppc_has_changed(pr, 0); #endif acpi_processor_get_throttling_info(pr); acpi_processor_get_limit_info(pr); @@ -845,7 +781,7 @@ static int acpi_processor_add(struct acpi_device *device) goto err_power_exit; } - dev_info(&device->dev, "registered as cooling_device%d\n", + dev_dbg(&device->dev, "registered as cooling_device%d\n", pr->cdev->id); result = sysfs_create_link(&device->dev.kobj, @@ -1102,7 +1038,7 @@ void acpi_processor_install_hotplug_notify(void) acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, - processor_walk_namespace_cb, &action, NULL); + processor_walk_namespace_cb, NULL, &action, NULL); #endif register_hotcpu_notifier(&acpi_cpu_notifier); } @@ -1115,7 +1051,7 @@ void acpi_processor_uninstall_hotplug_notify(void) acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, - processor_walk_namespace_cb, &action, NULL); + processor_walk_namespace_cb, NULL, &action, NULL); #endif unregister_hotcpu_notifier(&acpi_cpu_notifier); } @@ -1145,11 +1081,6 @@ static int __init acpi_processor_init(void) if (!acpi_processor_dir) return -ENOMEM; #endif - /* - * Check whether the system is DMI table. If yes, OSPM - * should not use mwait for CPU-states. - */ - dmi_check_system(processor_idle_dmi_table); result = cpuidle_register_driver(&acpi_idle_driver); if (result < 0) goto out_proc; diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index bbd066e7f85..cc978a8c00b 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -110,6 +110,14 @@ static struct dmi_system_id __cpuinitdata processor_power_dmi_table[] = { DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"), DMI_MATCH(DMI_BIOS_VERSION,"SHE845M0.86C.0013.D.0302131307")}, (void *)2}, + { set_max_cstate, "Pavilion zv5000", { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME,"Pavilion zv5000 (DS502A#ABA)")}, + (void *)1}, + { set_max_cstate, "Asus L8400B", { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME,"L8400B series Notebook PC")}, + (void *)1}, {}, }; @@ -164,7 +172,7 @@ static void lapic_timer_check_state(int state, struct acpi_processor *pr, pr->power.timer_broadcast_on_state = state; } -static void lapic_timer_propagate_broadcast(void *arg) +static void __lapic_timer_propagate_broadcast(void *arg) { struct acpi_processor *pr = (struct acpi_processor *) arg; unsigned long reason; @@ -175,6 +183,12 @@ static void lapic_timer_propagate_broadcast(void *arg) clockevents_notify(reason, &pr->id); } +static void lapic_timer_propagate_broadcast(struct acpi_processor *pr) +{ + smp_call_function_single(pr->id, __lapic_timer_propagate_broadcast, + (void *)pr, 1); +} + /* Power(C) State timer broadcast control */ static void lapic_timer_state_broadcast(struct acpi_processor *pr, struct acpi_processor_cx *cx, @@ -299,6 +313,28 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr) pr->power.states[ACPI_STATE_C2].latency = acpi_gbl_FADT.C2latency; pr->power.states[ACPI_STATE_C3].latency = acpi_gbl_FADT.C3latency; + /* + * FADT specified C2 latency must be less than or equal to + * 100 microseconds. + */ + if (acpi_gbl_FADT.C2latency > ACPI_PROCESSOR_MAX_C2_LATENCY) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "C2 latency too large [%d]\n", acpi_gbl_FADT.C2latency)); + /* invalidate C2 */ + pr->power.states[ACPI_STATE_C2].address = 0; + } + + /* + * FADT supplied C3 latency must be less than or equal to + * 1000 microseconds. + */ + if (acpi_gbl_FADT.C3latency > ACPI_PROCESSOR_MAX_C3_LATENCY) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "C3 latency too large [%d]\n", acpi_gbl_FADT.C3latency)); + /* invalidate C3 */ + pr->power.states[ACPI_STATE_C3].address = 0; + } + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "lvl2[0x%08x] lvl3[0x%08x]\n", pr->power.states[ACPI_STATE_C2].address, @@ -488,33 +524,6 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) return status; } -static void acpi_processor_power_verify_c2(struct acpi_processor_cx *cx) -{ - - if (!cx->address) - return; - - /* - * C2 latency must be less than or equal to 100 - * microseconds. - */ - else if (cx->latency > ACPI_PROCESSOR_MAX_C2_LATENCY) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "latency too large [%d]\n", cx->latency)); - return; - } - - /* - * Otherwise we've met all of our C2 requirements. - * Normalize the C2 latency to expidite policy - */ - cx->valid = 1; - - cx->latency_ticks = cx->latency; - - return; -} - static void acpi_processor_power_verify_c3(struct acpi_processor *pr, struct acpi_processor_cx *cx) { @@ -526,16 +535,6 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr, return; /* - * C3 latency must be less than or equal to 1000 - * microseconds. - */ - else if (cx->latency > ACPI_PROCESSOR_MAX_C3_LATENCY) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "latency too large [%d]\n", cx->latency)); - return; - } - - /* * PIIX4 Erratum #18: We don't support C3 when Type-F (fast) * DMA transfers are used by any ISA device to avoid livelock. * Note that we could disable Type-F DMA (as recommended by @@ -623,7 +622,10 @@ static int acpi_processor_power_verify(struct acpi_processor *pr) break; case ACPI_STATE_C2: - acpi_processor_power_verify_c2(cx); + if (!cx->address) + break; + cx->valid = 1; + cx->latency_ticks = cx->latency; /* Normalize latency */ break; case ACPI_STATE_C3: @@ -638,8 +640,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr) working++; } - smp_call_function_single(pr->id, lapic_timer_propagate_broadcast, - pr, 1); + lapic_timer_propagate_broadcast(pr); return (working); } @@ -879,12 +880,14 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, return(acpi_idle_enter_c1(dev, state)); local_irq_disable(); - current_thread_info()->status &= ~TS_POLLING; - /* - * TS_POLLING-cleared state must be visible before we test - * NEED_RESCHED: - */ - smp_mb(); + if (cx->entry_method != ACPI_CSTATE_FFH) { + current_thread_info()->status &= ~TS_POLLING; + /* + * TS_POLLING-cleared state must be visible before we test + * NEED_RESCHED: + */ + smp_mb(); + } if (unlikely(need_resched())) { current_thread_info()->status |= TS_POLLING; @@ -964,12 +967,14 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, } local_irq_disable(); - current_thread_info()->status &= ~TS_POLLING; - /* - * TS_POLLING-cleared state must be visible before we test - * NEED_RESCHED: - */ - smp_mb(); + if (cx->entry_method != ACPI_CSTATE_FFH) { + current_thread_info()->status &= ~TS_POLLING; + /* + * TS_POLLING-cleared state must be visible before we test + * NEED_RESCHED: + */ + smp_mb(); + } if (unlikely(need_resched())) { current_thread_info()->status |= TS_POLLING; diff --git a/drivers/acpi/processor_pdc.c b/drivers/acpi/processor_pdc.c new file mode 100644 index 00000000000..e306ba9aa34 --- /dev/null +++ b/drivers/acpi/processor_pdc.c @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2005 Intel Corporation + * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. + * + * Alex Chiang <achiang@hp.com> + * - Unified x86/ia64 implementations + * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> + * - Added _PDC for platforms with Intel CPUs + */ +#include <linux/dmi.h> + +#include <acpi/acpi_drivers.h> +#include <acpi/processor.h> + +#include "internal.h" + +#define PREFIX "ACPI: " +#define _COMPONENT ACPI_PROCESSOR_COMPONENT +ACPI_MODULE_NAME("processor_pdc"); + +static int set_no_mwait(const struct dmi_system_id *id) +{ + printk(KERN_NOTICE PREFIX "%s detected - " + "disabling mwait for CPU C-states\n", id->ident); + idle_nomwait = 1; + return 0; +} + +static struct dmi_system_id __cpuinitdata processor_idle_dmi_table[] = { + { + set_no_mwait, "IFL91 board", { + DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"), + DMI_MATCH(DMI_SYS_VENDOR, "ZEPTO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "3215W"), + DMI_MATCH(DMI_BOARD_NAME, "IFL91") }, NULL}, + { + set_no_mwait, "Extensa 5220", { + DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_VERSION, "0100"), + DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL}, + {}, +}; + +static void acpi_set_pdc_bits(u32 *buf) +{ + buf[0] = ACPI_PDC_REVISION_ID; + buf[1] = 1; + + /* Enable coordination with firmware's _TSD info */ + buf[2] = ACPI_PDC_SMP_T_SWCOORD; + + /* Twiddle arch-specific bits needed for _PDC */ + arch_acpi_set_pdc_bits(buf); +} + +static struct acpi_object_list *acpi_processor_alloc_pdc(void) +{ + struct acpi_object_list *obj_list; + union acpi_object *obj; + u32 *buf; + + /* allocate and initialize pdc. It will be used later. */ + obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL); + if (!obj_list) { + printk(KERN_ERR "Memory allocation error\n"); + return NULL; + } + + obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL); + if (!obj) { + printk(KERN_ERR "Memory allocation error\n"); + kfree(obj_list); + return NULL; + } + + buf = kmalloc(12, GFP_KERNEL); + if (!buf) { + printk(KERN_ERR "Memory allocation error\n"); + kfree(obj); + kfree(obj_list); + return NULL; + } + + acpi_set_pdc_bits(buf); + + obj->type = ACPI_TYPE_BUFFER; + obj->buffer.length = 12; + obj->buffer.pointer = (u8 *) buf; + obj_list->count = 1; + obj_list->pointer = obj; + + return obj_list; +} + +/* + * _PDC is required for a BIOS-OS handshake for most of the newer + * ACPI processor features. + */ +static int +acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in) +{ + acpi_status status = AE_OK; + + if (idle_nomwait) { + /* + * If mwait is disabled for CPU C-states, the C2C3_FFH access + * mode will be disabled in the parameter of _PDC object. + * Of course C1_FFH access mode will also be disabled. + */ + union acpi_object *obj; + u32 *buffer = NULL; + + obj = pdc_in->pointer; + buffer = (u32 *)(obj->buffer.pointer); + buffer[2] &= ~(ACPI_PDC_C_C2C3_FFH | ACPI_PDC_C_C1_FFH); + + } + status = acpi_evaluate_object(handle, "_PDC", pdc_in, NULL); + + if (ACPI_FAILURE(status)) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Could not evaluate _PDC, using legacy perf. control.\n")); + + return status; +} + +static int early_pdc_done; + +void acpi_processor_set_pdc(acpi_handle handle) +{ + struct acpi_object_list *obj_list; + + if (arch_has_acpi_pdc() == false) + return; + + if (early_pdc_done) + return; + + obj_list = acpi_processor_alloc_pdc(); + if (!obj_list) + return; + + acpi_processor_eval_pdc(handle, obj_list); + + kfree(obj_list->pointer->buffer.pointer); + kfree(obj_list->pointer); + kfree(obj_list); +} +EXPORT_SYMBOL_GPL(acpi_processor_set_pdc); + +static int early_pdc_optin; +static int set_early_pdc_optin(const struct dmi_system_id *id) +{ + early_pdc_optin = 1; + return 0; +} + +static int param_early_pdc_optin(char *s) +{ + early_pdc_optin = 1; + return 1; +} +__setup("acpi_early_pdc_eval", param_early_pdc_optin); + +static struct dmi_system_id __cpuinitdata early_pdc_optin_table[] = { + { + set_early_pdc_optin, "HP Envy", { + DMI_MATCH(DMI_BIOS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Envy") }, NULL}, + { + set_early_pdc_optin, "HP Pavilion dv6", { + DMI_MATCH(DMI_BIOS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv6") }, NULL}, + { + set_early_pdc_optin, "HP Pavilion dv7", { + DMI_MATCH(DMI_BIOS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv7") }, NULL}, + {}, +}; + +static acpi_status +early_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + acpi_processor_set_pdc(handle); + return AE_OK; +} + +void __init acpi_early_processor_set_pdc(void) +{ + /* + * Check whether the system is DMI table. If yes, OSPM + * should not use mwait for CPU-states. + */ + dmi_check_system(processor_idle_dmi_table); + + /* + * Allow systems to opt-in to early _PDC evaluation. + */ + dmi_check_system(early_pdc_optin_table); + if (!early_pdc_optin) + return; + + acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, + early_init_pdc, NULL, NULL, NULL); + + early_pdc_done = 1; +} diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 8ba0ed0b9dd..a959f6a0750 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -152,21 +152,78 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr) return 0; } -int acpi_processor_ppc_has_changed(struct acpi_processor *pr) +#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80 +/* + * acpi_processor_ppc_ost: Notify firmware the _PPC evaluation status + * @handle: ACPI processor handle + * @status: the status code of _PPC evaluation + * 0: success. OSPM is now using the performance state specificed. + * 1: failure. OSPM has not changed the number of P-states in use + */ +static void acpi_processor_ppc_ost(acpi_handle handle, int status) +{ + union acpi_object params[2] = { + {.type = ACPI_TYPE_INTEGER,}, + {.type = ACPI_TYPE_INTEGER,}, + }; + struct acpi_object_list arg_list = {2, params}; + acpi_handle temp; + + params[0].integer.value = ACPI_PROCESSOR_NOTIFY_PERFORMANCE; + params[1].integer.value = status; + + /* when there is no _OST , skip it */ + if (ACPI_FAILURE(acpi_get_handle(handle, "_OST", &temp))) + return; + + acpi_evaluate_object(handle, "_OST", &arg_list, NULL); + return; +} + +int acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag) { int ret; - if (ignore_ppc) + if (ignore_ppc) { + /* + * Only when it is notification event, the _OST object + * will be evaluated. Otherwise it is skipped. + */ + if (event_flag) + acpi_processor_ppc_ost(pr->handle, 1); return 0; + } ret = acpi_processor_get_platform_limit(pr); - + /* + * Only when it is notification event, the _OST object + * will be evaluated. Otherwise it is skipped. + */ + if (event_flag) { + if (ret < 0) + acpi_processor_ppc_ost(pr->handle, 1); + else + acpi_processor_ppc_ost(pr->handle, 0); + } if (ret < 0) return (ret); else return cpufreq_update_policy(pr->id); } +int acpi_processor_get_bios_limit(int cpu, unsigned int *limit) +{ + struct acpi_processor *pr; + + pr = per_cpu(processors, cpu); + if (!pr || !pr->performance || !pr->performance->state_count) + return -ENODEV; + *limit = pr->performance->states[pr->performance_platform_limit]. + core_frequency * 1000; + return 0; +} +EXPORT_SYMBOL(acpi_processor_get_bios_limit); + void acpi_processor_ppc_init(void) { if (!cpufreq_register_notifier @@ -356,7 +413,11 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr) if (result) goto update_bios; - return 0; + /* We need to call _PPC once when cpufreq starts */ + if (ignore_ppc != 1) + result = acpi_processor_get_platform_limit(pr); + + return result; /* * Having _PPC but missing frequencies (_PSS, _PCT) is a very good hint that diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index 140c5c5b423..6deafb4aa0d 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -443,8 +443,7 @@ struct thermal_cooling_device_ops processor_cooling_ops = { #ifdef CONFIG_ACPI_PROCFS static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset) { - struct acpi_processor *pr = (struct acpi_processor *)seq->private; - + struct acpi_processor *pr = seq->private; if (!pr) goto end; diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 4c6c14c1e30..1c5d7a8b2fd 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -1133,15 +1133,15 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr) int result = 0; struct acpi_processor_throttling *pthrottling; + if (!pr) + return -EINVAL; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n", pr->throttling.address, pr->throttling.duty_offset, pr->throttling.duty_width)); - if (!pr) - return -EINVAL; - /* * Evaluate _PTC, _TSS and _TPC * They must all be present or none of them can be used. diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 52b9db8afc2..b16ddbf23a9 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -822,7 +822,10 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id) static void acpi_battery_remove(struct acpi_sbs *sbs, int id) { +#if defined(CONFIG_ACPI_SYSFS_POWER) || defined(CONFIG_ACPI_PROCFS_POWER) struct acpi_battery *battery = &sbs->battery[id]; +#endif + #ifdef CONFIG_ACPI_SYSFS_POWER if (battery->bat.dev) { if (battery->have_sysfs_alarm) diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index d9339806df4..fd09229282e 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c @@ -242,7 +242,7 @@ static int smbus_alarm(void *context) case ACPI_SBS_CHARGER: case ACPI_SBS_MANAGER: case ACPI_SBS_BATTERY: - acpi_os_execute(OSL_GPE_HANDLER, + acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_smbus_callback, hc); default:; } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 14a7481c97d..fb7fc24fe72 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -741,19 +741,40 @@ acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device, return AE_OK; } -static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) +static void acpi_bus_set_run_wake_flags(struct acpi_device *device) { - acpi_status status = 0; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *package = NULL; - int psw_error; - struct acpi_device_id button_device_ids[] = { {"PNP0C0D", 0}, {"PNP0C0C", 0}, {"PNP0C0E", 0}, {"", 0}, }; + acpi_status status; + acpi_event_status event_status; + + device->wakeup.run_wake_count = 0; + device->wakeup.flags.notifier_present = 0; + + /* Power button, Lid switch always enable wakeup */ + if (!acpi_match_device_ids(device, button_device_ids)) { + device->wakeup.flags.run_wake = 1; + device->wakeup.flags.always_enabled = 1; + return; + } + + status = acpi_get_gpe_status(NULL, device->wakeup.gpe_number, + ACPI_NOT_ISR, &event_status); + if (status == AE_OK) + device->wakeup.flags.run_wake = + !!(event_status & ACPI_EVENT_FLAG_HANDLE); +} + +static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) +{ + acpi_status status = 0; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *package = NULL; + int psw_error; /* _PRW */ status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer); @@ -773,6 +794,7 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) device->wakeup.flags.valid = 1; device->wakeup.prepare_count = 0; + acpi_bus_set_run_wake_flags(device); /* Call _PSW/_DSW object to disable its ability to wake the sleeping * system for the ACPI device with the _PRW object. * The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW. @@ -784,10 +806,6 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "error in _DSW or _PSW evaluation\n")); - /* Power button, Lid switch always enable wakeup */ - if (!acpi_match_device_ids(device, button_device_ids)) - device->wakeup.flags.run_wake = 1; - end: if (ACPI_FAILURE(status)) device->flags.wake_capable = 0; @@ -1332,13 +1350,29 @@ static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops, status = acpi_bus_check_add(handle, 0, ops, &device); if (ACPI_SUCCESS(status)) acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, - acpi_bus_check_add, ops, &device); + acpi_bus_check_add, NULL, ops, &device); if (child) *child = device; - return 0; + + if (device) + return 0; + else + return -ENODEV; } +/* + * acpi_bus_add and acpi_bus_start + * + * scan a given ACPI tree and (probably recently hot-plugged) + * create and add or starts found devices. + * + * If no devices were found -ENODEV is returned which does not + * mean that this is a real error, there just have been no suitable + * ACPI objects in the table trunk from which the kernel could create + * a device and add/start an appropriate driver. + */ + int acpi_bus_add(struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, int type) @@ -1348,8 +1382,7 @@ acpi_bus_add(struct acpi_device **child, memset(&ops, 0, sizeof(ops)); ops.acpi_op_add = 1; - acpi_bus_scan(handle, &ops, child); - return 0; + return acpi_bus_scan(handle, &ops, child); } EXPORT_SYMBOL(acpi_bus_add); @@ -1357,11 +1390,13 @@ int acpi_bus_start(struct acpi_device *device) { struct acpi_bus_ops ops; + if (!device) + return -EINVAL; + memset(&ops, 0, sizeof(ops)); ops.acpi_op_start = 1; - acpi_bus_scan(device->handle, &ops, NULL); - return 0; + return acpi_bus_scan(device->handle, &ops, NULL); } EXPORT_SYMBOL(acpi_bus_start); diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index a90afcc723a..3bde594a997 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -81,6 +81,23 @@ static int acpi_sleep_prepare(u32 acpi_state) #ifdef CONFIG_ACPI_SLEEP static u32 acpi_target_sleep_state = ACPI_STATE_S0; /* + * According to the ACPI specification the BIOS should make sure that ACPI is + * enabled and SCI_EN bit is set on wake-up from S1 - S3 sleep states. Still, + * some BIOSes don't do that and therefore we use acpi_enable() to enable ACPI + * on such systems during resume. Unfortunately that doesn't help in + * particularly pathological cases in which SCI_EN has to be set directly on + * resume, although the specification states very clearly that this flag is + * owned by the hardware. The set_sci_en_on_resume variable will be set in such + * cases. + */ +static bool set_sci_en_on_resume; + +void __init acpi_set_sci_en_on_resume(void) +{ + set_sci_en_on_resume = true; +} + +/* * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the * user to request that behavior by using the 'acpi_old_suspend_ordering' * kernel command line option that causes the following variable to be set. @@ -170,18 +187,6 @@ static void acpi_pm_end(void) #endif /* CONFIG_ACPI_SLEEP */ #ifdef CONFIG_SUSPEND -/* - * According to the ACPI specification the BIOS should make sure that ACPI is - * enabled and SCI_EN bit is set on wake-up from S1 - S3 sleep states. Still, - * some BIOSes don't do that and therefore we use acpi_enable() to enable ACPI - * on such systems during resume. Unfortunately that doesn't help in - * particularly pathological cases in which SCI_EN has to be set directly on - * resume, although the specification states very clearly that this flag is - * owned by the hardware. The set_sci_en_on_resume variable will be set in such - * cases. - */ -static bool set_sci_en_on_resume; - extern void do_suspend_lowlevel(void); static u32 acpi_suspend_states[] = { @@ -413,6 +418,38 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { }, }, { + .callback = init_set_sci_en_on_resume, + .ident = "Hewlett-Packard Pavilion dv4", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv4"), + }, + }, + { + .callback = init_set_sci_en_on_resume, + .ident = "Hewlett-Packard Pavilion dv7", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv7"), + }, + }, + { + .callback = init_set_sci_en_on_resume, + .ident = "Hewlett-Packard Compaq Presario C700 Notebook PC", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "Compaq Presario C700 Notebook PC"), + }, + }, + { + .callback = init_set_sci_en_on_resume, + .ident = "Hewlett-Packard Compaq Presario CQ40 Notebook PC", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "Compaq Presario CQ40 Notebook PC"), + }, + }, + { .callback = init_old_suspend_ordering, .ident = "Panasonic CF51-2L", .matches = { @@ -708,9 +745,18 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable) return -ENODEV; } - error = enable ? - acpi_enable_wakeup_device_power(adev, acpi_target_sleep_state) : - acpi_disable_wakeup_device_power(adev); + if (enable) { + error = acpi_enable_wakeup_device_power(adev, + acpi_target_sleep_state); + if (!error) + acpi_enable_gpe(adev->wakeup.gpe_device, + adev->wakeup.gpe_number, + ACPI_GPE_TYPE_WAKE); + } else { + acpi_disable_gpe(adev->wakeup.gpe_device, adev->wakeup.gpe_number, + ACPI_GPE_TYPE_WAKE); + error = acpi_disable_wakeup_device_power(adev); + } if (!error) dev_info(dev, "wake-up capability %s by ACPI\n", enable ? "enabled" : "disabled"); diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index d11282975f3..a206a12da78 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -387,10 +387,10 @@ static ssize_t counter_set(struct kobject *kobj, if (index < num_gpes) { if (!strcmp(buf, "disable\n") && (status & ACPI_EVENT_FLAG_ENABLED)) - result = acpi_disable_gpe(handle, index); + result = acpi_set_gpe(handle, index, ACPI_GPE_DISABLE); else if (!strcmp(buf, "enable\n") && !(status & ACPI_EVENT_FLAG_ENABLED)) - result = acpi_enable_gpe(handle, index); + result = acpi_set_gpe(handle, index, ACPI_GPE_ENABLE); else if (!strcmp(buf, "clear\n") && (status & ACPI_EVENT_FLAG_SET)) result = acpi_clear_gpe(handle, index, ACPI_NOT_ISR); diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index f336bca7c45..8a0ed2800e6 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -213,7 +213,7 @@ acpi_table_parse_entries(char *id, unsigned long table_end; acpi_size tbl_size; - if (acpi_disabled) + if (acpi_disabled && !acpi_ht) return -ENODEV; if (!handler) @@ -280,7 +280,7 @@ int __init acpi_table_parse(char *id, acpi_table_handler handler) struct acpi_table_header *table = NULL; acpi_size tbl_size; - if (acpi_disabled) + if (acpi_disabled && !acpi_ht) return -ENODEV; if (!handler) diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 65f67815902..9073ada8883 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -1052,6 +1052,13 @@ static int acpi_thermal_trip_seq_show(struct seq_file *seq, void *offset) acpi_device_bid(device)); } seq_puts(seq, "\n"); + } else { + seq_printf(seq, "passive (forced):"); + if (tz->thermal_zone->forced_passive) + seq_printf(seq, " %i C\n", + tz->thermal_zone->forced_passive / 1000); + else + seq_printf(seq, "<not set>\n"); } for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 64e3c581b7a..b765790b32b 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -78,6 +78,13 @@ MODULE_LICENSE("GPL"); static int brightness_switch_enabled = 1; module_param(brightness_switch_enabled, bool, 0644); +/* + * By default, we don't allow duplicate ACPI video bus devices + * under the same VGA controller + */ +static int allow_duplicates; +module_param(allow_duplicates, bool, 0644); + static int register_count = 0; static int acpi_video_bus_add(struct acpi_device *device); static int acpi_video_bus_remove(struct acpi_device *device, int type); @@ -999,8 +1006,10 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) sprintf(name, "acpi_video%d", count++); device->backlight = backlight_device_register(name, NULL, device, &acpi_backlight_ops); - device->backlight->props.max_brightness = device->brightness->count-3; kfree(name); + if (IS_ERR(device->backlight)) + return; + device->backlight->props.max_brightness = device->brightness->count-3; result = sysfs_create_link(&device->backlight->dev.kobj, &device->dev->dev.kobj, "device"); @@ -1223,7 +1232,7 @@ acpi_video_device_write_state(struct file *file, u32 state = 0; - if (!dev || count + 1 > sizeof str) + if (!dev || count >= sizeof(str)) return -EINVAL; if (copy_from_user(str, buffer, count)) @@ -1280,7 +1289,7 @@ acpi_video_device_write_brightness(struct file *file, int i; - if (!dev || !dev->brightness || count + 1 > sizeof str) + if (!dev || !dev->brightness || count >= sizeof(str)) return -EINVAL; if (copy_from_user(str, buffer, count)) @@ -1562,7 +1571,7 @@ acpi_video_bus_write_POST(struct file *file, unsigned long long opt, options; - if (!video || count + 1 > sizeof str) + if (!video || count >= sizeof(str)) return -EINVAL; status = acpi_video_bus_POST_options(video, &options); @@ -1602,7 +1611,7 @@ acpi_video_bus_write_DOS(struct file *file, unsigned long opt; - if (!video || count + 1 > sizeof str) + if (!video || count >= sizeof(str)) return -EINVAL; if (copy_from_user(str, buffer, count)) @@ -1979,6 +1988,10 @@ acpi_video_switch_brightness(struct acpi_video_device *device, int event) unsigned long long level_current, level_next; int result = -EINVAL; + /* no warning message if acpi_backlight=vendor is used */ + if (!acpi_video_backlight_support()) + return 0; + if (!device->brightness) goto out; @@ -2233,11 +2246,47 @@ static int acpi_video_resume(struct acpi_device *device) return AE_OK; } +static acpi_status +acpi_video_bus_match(acpi_handle handle, u32 level, void *context, + void **return_value) +{ + struct acpi_device *device = context; + struct acpi_device *sibling; + int result; + + if (handle == device->handle) + return AE_CTRL_TERMINATE; + + result = acpi_bus_get_device(handle, &sibling); + if (result) + return AE_OK; + + if (!strcmp(acpi_device_name(sibling), ACPI_VIDEO_BUS_NAME)) + return AE_ALREADY_EXISTS; + + return AE_OK; +} + static int acpi_video_bus_add(struct acpi_device *device) { struct acpi_video_bus *video; struct input_dev *input; int error; + acpi_status status; + + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, + device->parent->handle, 1, + acpi_video_bus_match, NULL, + device, NULL); + if (status == AE_ALREADY_EXISTS) { + printk(KERN_WARNING FW_BUG + "Duplicate ACPI video bus devices for the" + " same VGA controller, please try module " + "parameter \"video.allow_duplicates=1\"" + "if the current driver doesn't work.\n"); + if (!allow_duplicates) + return -ENODEV; + } video = kzalloc(sizeof(struct acpi_video_bus), GFP_KERNEL); if (!video) diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 575593a8b4e..fc2f26b9b40 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -7,7 +7,7 @@ * video_detect.c: * Provides acpi_is_video_device() for early scanning of ACPI devices in scan.c * There a Linux specific (Spec does not provide a HID for video devices) is - * assinged + * assigned * * After PCI devices are glued with ACPI devices * acpi_get_pci_dev() can be called to identify ACPI graphics @@ -83,16 +83,16 @@ long acpi_is_video_device(struct acpi_device *device) if (!device) return 0; - /* Does this device able to support video switching ? */ + /* Is this device able to support video switching ? */ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) || ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy))) video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING; - /* Does this device able to retrieve a video ROM ? */ + /* Is this device able to retrieve a video ROM ? */ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy))) video_caps |= ACPI_VIDEO_ROM_AVAILABLE; - /* Does this device able to configure which video head to be POSTed ? */ + /* Is this device able to configure which video head to be POSTed ? */ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) && ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) && ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy))) @@ -101,7 +101,7 @@ long acpi_is_video_device(struct acpi_device *device) /* Only check for backlight functionality if one of the above hit. */ if (video_caps) acpi_walk_namespace(ACPI_TYPE_DEVICE, device->handle, - ACPI_UINT32_MAX, acpi_backlight_cap_match, + ACPI_UINT32_MAX, acpi_backlight_cap_match, NULL, &video_caps, NULL); return video_caps; @@ -137,7 +137,7 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv) * * if NULL is passed as argument all ACPI devices are enumerated and * all graphics capabilities of physically present devices are - * summerized and returned. This is cached and done only once. + * summarized and returned. This is cached and done only once. */ long acpi_video_get_capabilities(acpi_handle graphics_handle) { @@ -151,7 +151,7 @@ long acpi_video_get_capabilities(acpi_handle graphics_handle) if (!graphics_handle) { /* Only do the global walk through all graphics devices once */ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, find_video, + ACPI_UINT32_MAX, find_video, NULL, &caps, NULL); /* There might be boot param flags set already... */ acpi_video_support |= caps; @@ -173,7 +173,7 @@ long acpi_video_get_capabilities(acpi_handle graphics_handle) return 0; } acpi_walk_namespace(ACPI_TYPE_DEVICE, graphics_handle, - ACPI_UINT32_MAX, find_video, + ACPI_UINT32_MAX, find_video, NULL, &caps, NULL); } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "We have 0x%lX video support %s %s\n", diff --git a/drivers/acpi/wakeup.c b/drivers/acpi/wakeup.c index e0ee0c036f5..4b9d339a6e2 100644 --- a/drivers/acpi/wakeup.c +++ b/drivers/acpi/wakeup.c @@ -21,12 +21,12 @@ ACPI_MODULE_NAME("wakeup_devices") /** - * acpi_enable_wakeup_device_prep - prepare wakeup devices - * @sleep_state: ACPI state - * Enable all wakup devices power if the devices' wakeup level - * is higher than requested sleep level + * acpi_enable_wakeup_device_prep - Prepare wake-up devices. + * @sleep_state: ACPI system sleep state. + * + * Enable all wake-up devices' power, unless the requested system sleep state is + * too deep. */ - void acpi_enable_wakeup_device_prep(u8 sleep_state) { struct list_head *node, *next; @@ -36,9 +36,8 @@ void acpi_enable_wakeup_device_prep(u8 sleep_state) struct acpi_device, wakeup_list); - if (!dev->wakeup.flags.valid || - !dev->wakeup.state.enabled || - (sleep_state > (u32) dev->wakeup.sleep_state)) + if (!dev->wakeup.flags.valid || !dev->wakeup.state.enabled + || (sleep_state > (u32) dev->wakeup.sleep_state)) continue; acpi_enable_wakeup_device_power(dev, sleep_state); @@ -46,9 +45,12 @@ void acpi_enable_wakeup_device_prep(u8 sleep_state) } /** - * acpi_enable_wakeup_device - enable wakeup devices - * @sleep_state: ACPI state - * Enable all wakup devices's GPE + * acpi_enable_wakeup_device - Enable wake-up device GPEs. + * @sleep_state: ACPI system sleep state. + * + * Enable all wake-up devices' GPEs, with the assumption that + * acpi_disable_all_gpes() was executed before, so we don't need to disable any + * GPEs here. */ void acpi_enable_wakeup_device(u8 sleep_state) { @@ -65,29 +67,22 @@ void acpi_enable_wakeup_device(u8 sleep_state) if (!dev->wakeup.flags.valid) continue; - /* If users want to disable run-wake GPE, - * we only disable it for wake and leave it for runtime - */ if ((!dev->wakeup.state.enabled && !dev->wakeup.prepare_count) - || sleep_state > (u32) dev->wakeup.sleep_state) { - if (dev->wakeup.flags.run_wake) { - /* set_gpe_type will disable GPE, leave it like that */ - acpi_set_gpe_type(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, - ACPI_GPE_TYPE_RUNTIME); - } + || sleep_state > (u32) dev->wakeup.sleep_state) continue; - } - if (!dev->wakeup.flags.run_wake) - acpi_enable_gpe(dev->wakeup.gpe_device, - dev->wakeup.gpe_number); + + /* The wake-up power should have been enabled already. */ + acpi_set_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number, + ACPI_GPE_ENABLE); } } /** - * acpi_disable_wakeup_device - disable devices' wakeup capability - * @sleep_state: ACPI state - * Disable all wakup devices's GPE and wakeup capability + * acpi_disable_wakeup_device - Disable devices' wakeup capability. + * @sleep_state: ACPI system sleep state. + * + * This function only affects devices with wakeup.state.enabled set, which means + * that it reverses the changes made by acpi_enable_wakeup_device_prep(). */ void acpi_disable_wakeup_device(u8 sleep_state) { @@ -97,30 +92,11 @@ void acpi_disable_wakeup_device(u8 sleep_state) struct acpi_device *dev = container_of(node, struct acpi_device, wakeup_list); - if (!dev->wakeup.flags.valid) - continue; - - if ((!dev->wakeup.state.enabled && !dev->wakeup.prepare_count) - || sleep_state > (u32) dev->wakeup.sleep_state) { - if (dev->wakeup.flags.run_wake) { - acpi_set_gpe_type(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, - ACPI_GPE_TYPE_WAKE_RUN); - /* Re-enable it, since set_gpe_type will disable it */ - acpi_enable_gpe(dev->wakeup.gpe_device, - dev->wakeup.gpe_number); - } + if (!dev->wakeup.flags.valid || !dev->wakeup.state.enabled + || (sleep_state > (u32) dev->wakeup.sleep_state)) continue; - } acpi_disable_wakeup_device_power(dev); - /* Never disable run-wake GPE */ - if (!dev->wakeup.flags.run_wake) { - acpi_disable_gpe(dev->wakeup.gpe_device, - dev->wakeup.gpe_number); - acpi_clear_gpe(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, ACPI_NOT_ISR); - } } } @@ -134,13 +110,11 @@ int __init acpi_wakeup_device_init(void) struct acpi_device, wakeup_list); /* In case user doesn't load button driver */ - if (!dev->wakeup.flags.run_wake || dev->wakeup.state.enabled) + if (!dev->wakeup.flags.always_enabled || + dev->wakeup.state.enabled) continue; - acpi_set_gpe_type(dev->wakeup.gpe_device, - dev->wakeup.gpe_number, - ACPI_GPE_TYPE_WAKE_RUN); - acpi_enable_gpe(dev->wakeup.gpe_device, - dev->wakeup.gpe_number); + acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number, + ACPI_GPE_TYPE_WAKE); dev->wakeup.state.enabled = 1; } mutex_unlock(&acpi_device_lock); |