diff options
Diffstat (limited to 'drivers')
1511 files changed, 38347 insertions, 17820 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index 1d034b680431..e06f7f633f73 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -105,6 +105,7 @@ obj-$(CONFIG_TC) += tc/ obj-$(CONFIG_UWB) += uwb/ obj-$(CONFIG_USB_PHY) += usb/ obj-$(CONFIG_USB) += usb/ +obj-$(CONFIG_USB_SUPPORT) += usb/ obj-$(CONFIG_PCI) += usb/ obj-$(CONFIG_USB_GADGET) += usb/ obj-$(CONFIG_OF) += usb/ diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 46505396869e..d650c5b6ec90 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -361,22 +361,6 @@ config ACPI_PCI_SLOT i.e., segment/bus/device/function tuples, with physical slots in the system. If you are unsure, say N. -config X86_PM_TIMER - bool "Power Management Timer Support" if EXPERT - depends on X86 - default y - help - The Power Management Timer is available on all ACPI-capable, - in most cases even if ACPI is unusable or blacklisted. - - This timing source is not affected by power management features - like aggressive processor idling, throttling, frequency and/or - voltage scaling, unlike the commonly used Time Stamp Counter - (TSC) timing source. - - You should nearly always say Y here because many modern - systems require this timer. - config ACPI_CONTAINER bool "Container and Module Devices" default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_CPU) @@ -564,3 +548,19 @@ config TPS68470_PMIC_OPREGION using this, are probed. endif # ACPI + +config X86_PM_TIMER + bool "Power Management Timer Support" if EXPERT + depends on X86 && (ACPI || JAILHOUSE_GUEST) + default y + help + The Power Management Timer is available on all ACPI-capable, + in most cases even if ACPI is unusable or blacklisted. + + This timing source is not affected by power management features + like aggressive processor idling, throttling, frequency and/or + voltage scaling, unlike the commonly used Time Stamp Counter + (TSC) timing source. + + You should nearly always say Y here because many modern + systems require this timer. diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 7f2b02cc8ea1..2bcffec8dbf0 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -427,6 +427,142 @@ out: return 0; } +struct lpss_device_links { + const char *supplier_hid; + const char *supplier_uid; + const char *consumer_hid; + const char *consumer_uid; + u32 flags; +}; + +/* + * The _DEP method is used to identify dependencies but instead of creating + * device links for every handle in _DEP, only links in the following list are + * created. That is necessary because, in the general case, _DEP can refer to + * devices that might not have drivers, or that are on different buses, or where + * the supplier is not enumerated until after the consumer is probed. + */ +static const struct lpss_device_links lpss_device_links[] = { + {"808622C1", "7", "80860F14", "3", DL_FLAG_PM_RUNTIME}, +}; + +static bool hid_uid_match(const char *hid1, const char *uid1, + const char *hid2, const char *uid2) +{ + return !strcmp(hid1, hid2) && uid1 && uid2 && !strcmp(uid1, uid2); +} + +static bool acpi_lpss_is_supplier(struct acpi_device *adev, + const struct lpss_device_links *link) +{ + return hid_uid_match(acpi_device_hid(adev), acpi_device_uid(adev), + link->supplier_hid, link->supplier_uid); +} + +static bool acpi_lpss_is_consumer(struct acpi_device *adev, + const struct lpss_device_links *link) +{ + return hid_uid_match(acpi_device_hid(adev), acpi_device_uid(adev), + link->consumer_hid, link->consumer_uid); +} + +struct hid_uid { + const char *hid; + const char *uid; +}; + +static int match_hid_uid(struct device *dev, void *data) +{ + struct acpi_device *adev = ACPI_COMPANION(dev); + struct hid_uid *id = data; + + if (!adev) + return 0; + + return hid_uid_match(acpi_device_hid(adev), acpi_device_uid(adev), + id->hid, id->uid); +} + +static struct device *acpi_lpss_find_device(const char *hid, const char *uid) +{ + struct hid_uid data = { + .hid = hid, + .uid = uid, + }; + + return bus_find_device(&platform_bus_type, NULL, &data, match_hid_uid); +} + +static bool acpi_lpss_dep(struct acpi_device *adev, acpi_handle handle) +{ + struct acpi_handle_list dep_devices; + acpi_status status; + int i; + + if (!acpi_has_method(adev->handle, "_DEP")) + return false; + + status = acpi_evaluate_reference(adev->handle, "_DEP", NULL, + &dep_devices); + if (ACPI_FAILURE(status)) { + dev_dbg(&adev->dev, "Failed to evaluate _DEP.\n"); + return false; + } + + for (i = 0; i < dep_devices.count; i++) { + if (dep_devices.handles[i] == handle) + return true; + } + + return false; +} + +static void acpi_lpss_link_consumer(struct device *dev1, + const struct lpss_device_links *link) +{ + struct device *dev2; + + dev2 = acpi_lpss_find_device(link->consumer_hid, link->consumer_uid); + if (!dev2) + return; + + if (acpi_lpss_dep(ACPI_COMPANION(dev2), ACPI_HANDLE(dev1))) + device_link_add(dev2, dev1, link->flags); + + put_device(dev2); +} + +static void acpi_lpss_link_supplier(struct device *dev1, + const struct lpss_device_links *link) +{ + struct device *dev2; + + dev2 = acpi_lpss_find_device(link->supplier_hid, link->supplier_uid); + if (!dev2) + return; + + if (acpi_lpss_dep(ACPI_COMPANION(dev1), ACPI_HANDLE(dev2))) + device_link_add(dev1, dev2, link->flags); + + put_device(dev2); +} + +static void acpi_lpss_create_device_links(struct acpi_device *adev, + struct platform_device *pdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(lpss_device_links); i++) { + const struct lpss_device_links *link = &lpss_device_links[i]; + + if (acpi_lpss_is_supplier(adev, link)) + acpi_lpss_link_consumer(&pdev->dev, link); + + if (acpi_lpss_is_consumer(adev, link)) + acpi_lpss_link_supplier(&pdev->dev, link); + } +} + static int acpi_lpss_create_device(struct acpi_device *adev, const struct acpi_device_id *id) { @@ -465,6 +601,8 @@ static int acpi_lpss_create_device(struct acpi_device *adev, acpi_dev_free_resource_list(&resource_list); if (!pdata->mmio_base) { + /* Avoid acpi_bus_attach() instantiating a pdev for this dev. */ + adev->pnp.type.platform_id = 0; /* Skip the device, but continue the namespace scan. */ ret = 0; goto err_out; @@ -500,6 +638,7 @@ static int acpi_lpss_create_device(struct acpi_device *adev, adev->driver_data = pdata; pdev = acpi_create_platform_device(adev, dev_desc->properties); if (!IS_ERR_OR_NULL(pdev)) { + acpi_lpss_create_device_links(adev, pdev); return 1; } diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 0972ec0e2eb8..f53ccc680238 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -80,8 +80,8 @@ MODULE_PARM_DESC(report_key_events, static bool device_id_scheme = false; module_param(device_id_scheme, bool, 0444); -static bool only_lcd = false; -module_param(only_lcd, bool, 0444); +static int only_lcd = -1; +module_param(only_lcd, int, 0444); static int register_count; static DEFINE_MUTEX(register_count_mutex); @@ -2136,6 +2136,16 @@ int acpi_video_register(void) goto leave; } + /* + * We're seeing a lot of bogus backlight interfaces on newer machines + * without a LCD such as desktops, servers and HDMI sticks. Checking + * the lcd flag fixes this, so enable this on any machines which are + * win8 ready (where we also prefer the native backlight driver, so + * normally the acpi_video code should not register there anyways). + */ + if (only_lcd == -1) + only_lcd = acpi_osi_is_win8(); + dmi_check_system(video_dmi_table); ret = acpi_bus_register_driver(&acpi_video_bus); diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h index 7a1a68b5ac5c..2243c8164b34 100644 --- a/drivers/acpi/acpica/acapps.h +++ b/drivers/acpi/acpica/acapps.h @@ -80,6 +80,9 @@ prefix, ACPICA_COPYRIGHT, \ prefix +#define ACPI_COMMON_BUILD_TIME \ + "Build date/time: %s %s\n", __DATE__, __TIME__ + /* Macros for usage messages */ #define ACPI_USAGE_HEADER(usage) \ diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index 71743e5252f5..54b8d9df9423 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -223,6 +223,10 @@ void acpi_db_execute(char *name, char **args, acpi_object_type *types, u32 flags); void +acpi_db_create_execution_thread(char *method_name_arg, + char **arguments, acpi_object_type *types); + +void acpi_db_create_execution_threads(char *num_threads_arg, char *num_loops_arg, char *method_name_arg); diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 95eed442703f..45ef3f5dc9ad 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -46,7 +46,7 @@ /***************************************************************************** * - * Globals related to the ACPI tables + * Globals related to the incoming ACPI tables * ****************************************************************************/ @@ -87,7 +87,7 @@ ACPI_GLOBAL(u8, acpi_gbl_integer_nybble_width); /***************************************************************************** * - * Mutual exclusion within ACPICA subsystem + * Mutual exclusion within the ACPICA subsystem * ****************************************************************************/ @@ -167,7 +167,7 @@ ACPI_GLOBAL(u8, acpi_gbl_next_owner_id_offset); ACPI_INIT_GLOBAL(u8, acpi_gbl_namespace_initialized, FALSE); -/* Misc */ +/* Miscellaneous */ ACPI_GLOBAL(u32, acpi_gbl_original_mode); ACPI_GLOBAL(u32, acpi_gbl_ns_lookup_count); @@ -191,10 +191,9 @@ extern const char acpi_gbl_lower_hex_digits[]; extern const char acpi_gbl_upper_hex_digits[]; extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES]; -#ifdef ACPI_DBG_TRACK_ALLOCATIONS - /* Lists for tracking memory allocations (debug only) */ +#ifdef ACPI_DBG_TRACK_ALLOCATIONS ACPI_GLOBAL(struct acpi_memory_list *, acpi_gbl_global_list); ACPI_GLOBAL(struct acpi_memory_list *, acpi_gbl_ns_node_list); ACPI_GLOBAL(u8, acpi_gbl_display_final_mem_stats); @@ -203,7 +202,7 @@ ACPI_GLOBAL(u8, acpi_gbl_disable_mem_tracking); /***************************************************************************** * - * Namespace globals + * ACPI Namespace * ****************************************************************************/ @@ -234,15 +233,20 @@ ACPI_INIT_GLOBAL(u32, acpi_gbl_nesting_level, 0); /***************************************************************************** * - * Interpreter globals + * Interpreter/Parser globals * ****************************************************************************/ -ACPI_GLOBAL(struct acpi_thread_state *, acpi_gbl_current_walk_list); - /* Control method single step flag */ ACPI_GLOBAL(u8, acpi_gbl_cm_single_step); +ACPI_GLOBAL(struct acpi_thread_state *, acpi_gbl_current_walk_list); +ACPI_INIT_GLOBAL(union acpi_parse_object, *acpi_gbl_current_scope, NULL); + +/* ASL/ASL+ converter */ + +ACPI_INIT_GLOBAL(u8, acpi_gbl_capture_comments, FALSE); +ACPI_INIT_GLOBAL(struct acpi_comment_node, *acpi_gbl_last_list_head, NULL); /***************************************************************************** * @@ -252,7 +256,6 @@ ACPI_GLOBAL(u8, acpi_gbl_cm_single_step); extern struct acpi_bit_register_info acpi_gbl_bit_register_info[ACPI_NUM_BITREG]; - ACPI_GLOBAL(u8, acpi_gbl_sleep_type_a); ACPI_GLOBAL(u8, acpi_gbl_sleep_type_b); @@ -263,7 +266,6 @@ ACPI_GLOBAL(u8, acpi_gbl_sleep_type_b); ****************************************************************************/ #if (!ACPI_REDUCED_HARDWARE) - ACPI_GLOBAL(u8, acpi_gbl_all_gpes_initialized); ACPI_GLOBAL(struct acpi_gpe_xrupt_info *, acpi_gbl_gpe_xrupt_list_head); ACPI_GLOBAL(struct acpi_gpe_block_info *, @@ -272,10 +274,8 @@ ACPI_GLOBAL(acpi_gbl_event_handler, acpi_gbl_global_event_handler); ACPI_GLOBAL(void *, acpi_gbl_global_event_handler_context); ACPI_GLOBAL(struct acpi_fixed_event_handler, acpi_gbl_fixed_event_handlers[ACPI_NUM_FIXED_EVENTS]); - extern struct acpi_fixed_event_info acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVENTS]; - #endif /* !ACPI_REDUCED_HARDWARE */ /***************************************************************************** @@ -291,14 +291,14 @@ ACPI_GLOBAL(u32, acpi_gpe_count); ACPI_GLOBAL(u32, acpi_sci_count); ACPI_GLOBAL(u32, acpi_fixed_event_count[ACPI_NUM_FIXED_EVENTS]); -/* Support for dynamic control method tracing mechanism */ +/* Dynamic control method tracing mechanism */ ACPI_GLOBAL(u32, acpi_gbl_original_dbg_level); ACPI_GLOBAL(u32, acpi_gbl_original_dbg_layer); /***************************************************************************** * - * Debugger and Disassembler globals + * Debugger and Disassembler * ****************************************************************************/ @@ -326,7 +326,6 @@ ACPI_GLOBAL(struct acpi_external_file *, acpi_gbl_external_file_list); #endif #ifdef ACPI_DEBUGGER - ACPI_INIT_GLOBAL(u8, acpi_gbl_abort_method, FALSE); ACPI_INIT_GLOBAL(acpi_thread_id, acpi_gbl_db_thread_id, ACPI_INVALID_THREAD_ID); @@ -340,7 +339,6 @@ ACPI_GLOBAL(u32, acpi_gbl_db_console_debug_level); ACPI_GLOBAL(struct acpi_namespace_node *, acpi_gbl_db_scope_node); ACPI_GLOBAL(u8, acpi_gbl_db_terminate_loop); ACPI_GLOBAL(u8, acpi_gbl_db_threads_terminated); - ACPI_GLOBAL(char *, acpi_gbl_db_args[ACPI_DEBUGGER_MAX_ARGS]); ACPI_GLOBAL(acpi_object_type, acpi_gbl_db_arg_types[ACPI_DEBUGGER_MAX_ARGS]); @@ -350,32 +348,33 @@ ACPI_GLOBAL(char, acpi_gbl_db_parsed_buf[ACPI_DB_LINE_BUFFER_SIZE]); ACPI_GLOBAL(char, acpi_gbl_db_scope_buf[ACPI_DB_LINE_BUFFER_SIZE]); ACPI_GLOBAL(char, acpi_gbl_db_debug_filename[ACPI_DB_LINE_BUFFER_SIZE]); -/* - * Statistic globals - */ +/* Statistics globals */ + ACPI_GLOBAL(u16, acpi_gbl_obj_type_count[ACPI_TOTAL_TYPES]); ACPI_GLOBAL(u16, acpi_gbl_node_type_count[ACPI_TOTAL_TYPES]); ACPI_GLOBAL(u16, acpi_gbl_obj_type_count_misc); ACPI_GLOBAL(u16, acpi_gbl_node_type_count_misc); ACPI_GLOBAL(u32, acpi_gbl_num_nodes); ACPI_GLOBAL(u32, acpi_gbl_num_objects); - #endif /* ACPI_DEBUGGER */ #if defined (ACPI_DISASSEMBLER) || defined (ACPI_ASL_COMPILER) - ACPI_GLOBAL(const char, *acpi_gbl_pld_panel_list[]); ACPI_GLOBAL(const char, *acpi_gbl_pld_vertical_position_list[]); ACPI_GLOBAL(const char, *acpi_gbl_pld_horizontal_position_list[]); ACPI_GLOBAL(const char, *acpi_gbl_pld_shape_list[]); - ACPI_INIT_GLOBAL(u8, acpi_gbl_disasm_flag, FALSE); - #endif -/* - * Meant for the -ca option. - */ +/***************************************************************************** + * + * ACPICA application-specific globals + * + ****************************************************************************/ + +/* ASL-to-ASL+ conversion utility (implemented within the iASL compiler) */ + +#ifdef ACPI_ASL_COMPILER ACPI_INIT_GLOBAL(char *, acpi_gbl_current_inline_comment, NULL); ACPI_INIT_GLOBAL(char *, acpi_gbl_current_end_node_comment, NULL); ACPI_INIT_GLOBAL(char *, acpi_gbl_current_open_brace_comment, NULL); @@ -386,23 +385,18 @@ ACPI_INIT_GLOBAL(char *, acpi_gbl_current_filename, NULL); ACPI_INIT_GLOBAL(char *, acpi_gbl_current_parent_filename, NULL); ACPI_INIT_GLOBAL(char *, acpi_gbl_current_include_filename, NULL); -ACPI_INIT_GLOBAL(struct acpi_comment_node, *acpi_gbl_last_list_head, NULL); - ACPI_INIT_GLOBAL(struct acpi_comment_node, *acpi_gbl_def_blk_comment_list_head, NULL); ACPI_INIT_GLOBAL(struct acpi_comment_node, *acpi_gbl_def_blk_comment_list_tail, NULL); - ACPI_INIT_GLOBAL(struct acpi_comment_node, *acpi_gbl_reg_comment_list_head, NULL); ACPI_INIT_GLOBAL(struct acpi_comment_node, *acpi_gbl_reg_comment_list_tail, NULL); - ACPI_INIT_GLOBAL(struct acpi_comment_node, *acpi_gbl_inc_comment_list_head, NULL); ACPI_INIT_GLOBAL(struct acpi_comment_node, *acpi_gbl_inc_comment_list_tail, NULL); - ACPI_INIT_GLOBAL(struct acpi_comment_node, *acpi_gbl_end_blk_comment_list_head, NULL); ACPI_INIT_GLOBAL(struct acpi_comment_node, *acpi_gbl_end_blk_comment_list_tail, @@ -410,30 +404,18 @@ ACPI_INIT_GLOBAL(struct acpi_comment_node, *acpi_gbl_end_blk_comment_list_tail, ACPI_INIT_GLOBAL(struct acpi_comment_addr_node, *acpi_gbl_comment_addr_list_head, NULL); - -ACPI_INIT_GLOBAL(union acpi_parse_object, *acpi_gbl_current_scope, NULL); - ACPI_INIT_GLOBAL(struct acpi_file_node, *acpi_gbl_file_tree_root, NULL); ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_reg_comment_cache); ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_comment_addr_cache); ACPI_GLOBAL(acpi_cache_t *, acpi_gbl_file_cache); -ACPI_INIT_GLOBAL(u8, gbl_capture_comments, FALSE); - ACPI_INIT_GLOBAL(u8, acpi_gbl_debug_asl_conversion, FALSE); ACPI_INIT_GLOBAL(ACPI_FILE, acpi_gbl_conv_debug_file, NULL); - ACPI_GLOBAL(char, acpi_gbl_table_sig[4]); - -/***************************************************************************** - * - * Application globals - * - ****************************************************************************/ +#endif #ifdef ACPI_APPLICATION - ACPI_INIT_GLOBAL(ACPI_FILE, acpi_gbl_debug_file, NULL); ACPI_INIT_GLOBAL(ACPI_FILE, acpi_gbl_output_file, NULL); ACPI_INIT_GLOBAL(u8, acpi_gbl_debug_timeout, FALSE); @@ -442,16 +424,6 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_debug_timeout, FALSE); ACPI_GLOBAL(acpi_spinlock, acpi_gbl_print_lock); /* For print buffer */ ACPI_GLOBAL(char, acpi_gbl_print_buffer[1024]); - #endif /* ACPI_APPLICATION */ -/***************************************************************************** - * - * Info/help support - * - ****************************************************************************/ - -extern const struct ah_predefined_name asl_predefined_info[]; -extern const struct ah_device_id asl_device_ids[]; - #endif /* __ACGLOBAL_H__ */ diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 0d45b8bb1678..a56675f0661e 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -622,7 +622,7 @@ struct acpi_control_state { union acpi_parse_object *predicate_op; u8 *aml_predicate_start; /* Start of if/while predicate */ u8 *package_end; /* End of if/while block */ - u32 loop_count; /* While() loop counter */ + u64 loop_timeout; /* While() loop timeout */ }; /* @@ -1218,16 +1218,17 @@ struct acpi_db_method_info { acpi_object_type *types; /* - * Arguments to be passed to method for the command - * Threads - - * the Number of threads, ID of current thread and - * Index of current thread inside all them created. + * Arguments to be passed to method for the commands Threads and + * Background. Note, ACPI specifies a maximum of 7 arguments (0 - 6). + * + * For the Threads command, the Number of threads, ID of current + * thread and Index of current thread inside all them created. */ char init_args; #ifdef ACPI_DEBUGGER - acpi_object_type arg_types[4]; + acpi_object_type arg_types[ACPI_METHOD_NUM_ARGS]; #endif - char *arguments[4]; + char *arguments[ACPI_METHOD_NUM_ARGS]; char num_threads_str[11]; char id_of_thread_str[11]; char index_of_thread_str[11]; diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index c7f0c96cc00f..128a3d71b598 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -455,7 +455,7 @@ * the plist contains a set of parens to allow variable-length lists. * These macros are used for both the debug and non-debug versions of the code. */ -#define ACPI_ERROR_NAMESPACE(s, e) acpi_ut_namespace_error (AE_INFO, s, e); +#define ACPI_ERROR_NAMESPACE(s, p, e) acpi_ut_prefixed_namespace_error (AE_INFO, s, p, e); #define ACPI_ERROR_METHOD(s, n, p, e) acpi_ut_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 diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 54a0c51b3e37..2fb1bb78d85c 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -289,6 +289,9 @@ acpi_ns_build_normalized_path(struct acpi_namespace_node *node, char *acpi_ns_get_normalized_pathname(struct acpi_namespace_node *node, u8 no_trailing); +char *acpi_ns_build_prefixed_pathname(union acpi_generic_state *prefix_scope, + const char *internal_path); + char *acpi_ns_name_of_current_scope(struct acpi_walk_state *walk_state); acpi_status diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 83b75e9db7ef..b6b29d717824 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -118,9 +118,6 @@ extern const char *acpi_gbl_ptyp_decode[]; #ifndef ACPI_MSG_ERROR #define ACPI_MSG_ERROR "ACPI Error: " #endif -#ifndef ACPI_MSG_EXCEPTION -#define ACPI_MSG_EXCEPTION "ACPI Exception: " -#endif #ifndef ACPI_MSG_WARNING #define ACPI_MSG_WARNING "ACPI Warning: " #endif @@ -129,10 +126,10 @@ extern const char *acpi_gbl_ptyp_decode[]; #endif #ifndef ACPI_MSG_BIOS_ERROR -#define ACPI_MSG_BIOS_ERROR "ACPI BIOS Error (bug): " +#define ACPI_MSG_BIOS_ERROR "Firmware Error (ACPI): " #endif #ifndef ACPI_MSG_BIOS_WARNING -#define ACPI_MSG_BIOS_WARNING "ACPI BIOS Warning (bug): " +#define ACPI_MSG_BIOS_WARNING "Firmware Warning (ACPI): " #endif /* @@ -233,10 +230,10 @@ u64 acpi_ut_implicit_strtoul64(char *string); */ acpi_status acpi_ut_init_globals(void); -#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) - const char *acpi_ut_get_mutex_name(u32 mutex_id); +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) + const char *acpi_ut_get_notify_name(u32 notify_value, acpi_object_type type); #endif @@ -641,9 +638,11 @@ void ut_convert_backslashes(char *pathname); void acpi_ut_repair_name(char *name); -#if defined (ACPI_DEBUGGER) || defined (ACPI_APPLICATION) +#if defined (ACPI_DEBUGGER) || defined (ACPI_APPLICATION) || defined (ACPI_DEBUG_OUTPUT) u8 acpi_ut_safe_strcpy(char *dest, acpi_size dest_size, char *source); +void acpi_ut_safe_strncpy(char *dest, char *source, acpi_size dest_size); + u8 acpi_ut_safe_strcat(char *dest, acpi_size dest_size, char *source); u8 @@ -737,9 +736,11 @@ acpi_ut_predefined_bios_error(const char *module_name, u8 node_flags, const char *format, ...); void -acpi_ut_namespace_error(const char *module_name, - u32 line_number, - const char *internal_name, acpi_status lookup_status); +acpi_ut_prefixed_namespace_error(const char *module_name, + u32 line_number, + union acpi_generic_state *prefix_scope, + const char *internal_name, + acpi_status lookup_status); void acpi_ut_method_error(const char *module_name, diff --git a/drivers/acpi/acpica/dbexec.c b/drivers/acpi/acpica/dbexec.c index 3b30319752f0..ed088fceb18d 100644 --- a/drivers/acpi/acpica/dbexec.c +++ b/drivers/acpi/acpica/dbexec.c @@ -67,6 +67,8 @@ static acpi_status acpi_db_execution_walk(acpi_handle obj_handle, u32 nesting_level, void *context, void **return_value); +static void ACPI_SYSTEM_XFACE acpi_db_single_execution_thread(void *context); + /******************************************************************************* * * FUNCTION: acpi_db_delete_objects @@ -229,7 +231,7 @@ static acpi_status acpi_db_execute_setup(struct acpi_db_method_info *info) ACPI_FUNCTION_NAME(db_execute_setup); - /* Catenate the current scope to the supplied name */ + /* Concatenate the current scope to the supplied name */ info->pathname[0] = 0; if ((info->name[0] != '\\') && (info->name[0] != '/')) { @@ -611,6 +613,112 @@ static void ACPI_SYSTEM_XFACE acpi_db_method_thread(void *context) /******************************************************************************* * + * FUNCTION: acpi_db_single_execution_thread + * + * PARAMETERS: context - Method info struct + * + * RETURN: None + * + * DESCRIPTION: Create one thread and execute a method + * + ******************************************************************************/ + +static void ACPI_SYSTEM_XFACE acpi_db_single_execution_thread(void *context) +{ + struct acpi_db_method_info *info = context; + acpi_status status; + struct acpi_buffer return_obj; + + acpi_os_printf("\n"); + + status = acpi_db_execute_method(info, &return_obj); + if (ACPI_FAILURE(status)) { + acpi_os_printf("%s During evaluation of %s\n", + acpi_format_exception(status), info->pathname); + return; + } + + /* Display a return object, if any */ + + if (return_obj.length) { + acpi_os_printf("Evaluation of %s returned object %p, " + "external buffer length %X\n", + acpi_gbl_db_method_info.pathname, + return_obj.pointer, (u32)return_obj.length); + + acpi_db_dump_external_object(return_obj.pointer, 1); + } + + acpi_os_printf("\nBackground thread completed\n%c ", + ACPI_DEBUGGER_COMMAND_PROMPT); +} + +/******************************************************************************* + * + * FUNCTION: acpi_db_create_execution_thread + * + * PARAMETERS: method_name_arg - Control method to execute + * arguments - Array of arguments to the method + * types - Corresponding array of object types + * + * RETURN: None + * + * DESCRIPTION: Create a single thread to evaluate a namespace object. Handles + * arguments passed on command line for control methods. + * + ******************************************************************************/ + +void +acpi_db_create_execution_thread(char *method_name_arg, + char **arguments, acpi_object_type *types) +{ + acpi_status status; + u32 i; + + memset(&acpi_gbl_db_method_info, 0, sizeof(struct acpi_db_method_info)); + acpi_gbl_db_method_info.name = method_name_arg; + acpi_gbl_db_method_info.init_args = 1; + acpi_gbl_db_method_info.args = acpi_gbl_db_method_info.arguments; + acpi_gbl_db_method_info.types = acpi_gbl_db_method_info.arg_types; + + /* Setup method arguments, up to 7 (0-6) */ + + for (i = 0; (i < ACPI_METHOD_NUM_ARGS) && *arguments; i++) { + acpi_gbl_db_method_info.arguments[i] = *arguments; + arguments++; + + acpi_gbl_db_method_info.arg_types[i] = *types; + types++; + } + + status = acpi_db_execute_setup(&acpi_gbl_db_method_info); + if (ACPI_FAILURE(status)) { + return; + } + + /* Get the NS node, determines existence also */ + + status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname, + &acpi_gbl_db_method_info.method); + if (ACPI_FAILURE(status)) { + acpi_os_printf("%s Could not get handle for %s\n", + acpi_format_exception(status), + acpi_gbl_db_method_info.pathname); + return; + } + + status = acpi_os_execute(OSL_DEBUGGER_EXEC_THREAD, + acpi_db_single_execution_thread, + &acpi_gbl_db_method_info); + if (ACPI_FAILURE(status)) { + return; + } + + acpi_os_printf("\nBackground thread started\n"); +} + +/******************************************************************************* + * * FUNCTION: acpi_db_create_execution_threads * * PARAMETERS: num_threads_arg - Number of threads to create diff --git a/drivers/acpi/acpica/dbfileio.c b/drivers/acpi/acpica/dbfileio.c index 4d81ea291d93..cf9607945704 100644 --- a/drivers/acpi/acpica/dbfileio.c +++ b/drivers/acpi/acpica/dbfileio.c @@ -99,8 +99,8 @@ void acpi_db_open_debug_file(char *name) } acpi_os_printf("Debug output file %s opened\n", name); - strncpy(acpi_gbl_db_debug_filename, name, - sizeof(acpi_gbl_db_debug_filename)); + acpi_ut_safe_strncpy(acpi_gbl_db_debug_filename, name, + sizeof(acpi_gbl_db_debug_filename)); acpi_gbl_db_output_to_file = TRUE; } #endif diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c index 2626d79db064..954ca3b981a7 100644 --- a/drivers/acpi/acpica/dbinput.c +++ b/drivers/acpi/acpica/dbinput.c @@ -136,6 +136,7 @@ enum acpi_ex_debugger_commands { CMD_UNLOAD, CMD_TERMINATE, + CMD_BACKGROUND, CMD_THREADS, CMD_TEST, @@ -212,6 +213,7 @@ static const struct acpi_db_command_info acpi_gbl_db_commands[] = { {"UNLOAD", 1}, {"TERMINATE", 0}, + {"BACKGROUND", 1}, {"THREADS", 3}, {"TEST", 1}, @@ -222,9 +224,56 @@ static const struct acpi_db_command_info acpi_gbl_db_commands[] = { /* * Help for all debugger commands. First argument is the number of lines * of help to output for the command. + * + * Note: Some commands are not supported by the kernel-level version of + * the debugger. */ static const struct acpi_db_command_help acpi_gbl_db_command_help[] = { - {0, "\nGeneral-Purpose Commands:", "\n"}, + {0, "\nNamespace Access:", "\n"}, + {1, " Businfo", "Display system bus info\n"}, + {1, " Disassemble <Method>", "Disassemble a control method\n"}, + {1, " Find <AcpiName> (? is wildcard)", + "Find ACPI name(s) with wildcards\n"}, + {1, " Integrity", "Validate namespace integrity\n"}, + {1, " Methods", "Display list of loaded control methods\n"}, + {1, " Namespace [Object] [Depth]", + "Display loaded namespace tree/subtree\n"}, + {1, " Notify <Object> <Value>", "Send a notification on Object\n"}, + {1, " Objects [ObjectType]", + "Display summary of all objects or just given type\n"}, + {1, " Owner <OwnerId> [Depth]", + "Display loaded namespace by object owner\n"}, + {1, " Paths", "Display full pathnames of namespace objects\n"}, + {1, " Predefined", "Check all predefined names\n"}, + {1, " Prefix [<Namepath>]", "Set or Get current execution prefix\n"}, + {1, " References <Addr>", "Find all references to object at addr\n"}, + {1, " Resources [DeviceName]", + "Display Device resources (no arg = all devices)\n"}, + {1, " Set N <NamedObject> <Value>", "Set value for named integer\n"}, + {1, " Template <Object>", "Format/dump a Buffer/ResourceTemplate\n"}, + {1, " Type <Object>", "Display object type\n"}, + + {0, "\nControl Method Execution:", "\n"}, + {1, " Evaluate <Namepath> [Arguments]", + "Evaluate object or control method\n"}, + {1, " Execute <Namepath> [Arguments]", "Synonym for Evaluate\n"}, +#ifdef ACPI_APPLICATION + {1, " Background <Namepath> [Arguments]", + "Evaluate object/method in a separate thread\n"}, + {1, " Thread <Threads><Loops><NamePath>", + "Spawn threads to execute method(s)\n"}, +#endif + {1, " Debug <Namepath> [Arguments]", "Single-Step a control method\n"}, + {7, " [Arguments] formats:", "Control method argument formats\n"}, + {1, " Hex Integer", "Integer\n"}, + {1, " \"Ascii String\"", "String\n"}, + {1, " (Hex Byte List)", "Buffer\n"}, + {1, " (01 42 7A BF)", "Buffer example (4 bytes)\n"}, + {1, " [Package Element List]", "Package\n"}, + {1, " [0x01 0x1234 \"string\"]", + "Package example (3 elements)\n"}, + + {0, "\nMiscellaneous:", "\n"}, {1, " Allocations", "Display list of current memory allocations\n"}, {2, " Dump <Address>|<Namepath>", "\n"}, {0, " [Byte|Word|Dword|Qword]", @@ -248,46 +297,30 @@ static const struct acpi_db_command_help acpi_gbl_db_command_help[] = { {1, " Stack", "Display CPU stack usage\n"}, {1, " Tables", "Info about current ACPI table(s)\n"}, {1, " Tables", "Display info about loaded ACPI tables\n"}, +#ifdef ACPI_APPLICATION + {1, " Terminate", "Delete namespace and all internal objects\n"}, +#endif {1, " ! <CommandNumber>", "Execute command from history buffer\n"}, {1, " !!", "Execute last command again\n"}, - {0, "\nNamespace Access Commands:", "\n"}, - {1, " Businfo", "Display system bus info\n"}, - {1, " Disassemble <Method>", "Disassemble a control method\n"}, - {1, " Find <AcpiName> (? is wildcard)", - "Find ACPI name(s) with wildcards\n"}, - {1, " Integrity", "Validate namespace integrity\n"}, - {1, " Methods", "Display list of loaded control methods\n"}, - {1, " Namespace [Object] [Depth]", - "Display loaded namespace tree/subtree\n"}, - {1, " Notify <Object> <Value>", "Send a notification on Object\n"}, - {1, " Objects [ObjectType]", - "Display summary of all objects or just given type\n"}, - {1, " Owner <OwnerId> [Depth]", - "Display loaded namespace by object owner\n"}, - {1, " Paths", "Display full pathnames of namespace objects\n"}, - {1, " Predefined", "Check all predefined names\n"}, - {1, " Prefix [<Namepath>]", "Set or Get current execution prefix\n"}, - {1, " References <Addr>", "Find all references to object at addr\n"}, - {1, " Resources [DeviceName]", - "Display Device resources (no arg = all devices)\n"}, - {1, " Set N <NamedObject> <Value>", "Set value for named integer\n"}, - {1, " Template <Object>", "Format/dump a Buffer/ResourceTemplate\n"}, - {1, " Type <Object>", "Display object type\n"}, + {0, "\nMethod and Namespace Debugging:", "\n"}, + {5, " Trace <State> [<Namepath>] [Once]", + "Trace control method execution\n"}, + {1, " Enable", "Enable all messages\n"}, + {1, " Disable", "Disable tracing\n"}, + {1, " Method", "Enable method execution messages\n"}, + {1, " Opcode", "Enable opcode execution messages\n"}, + {3, " Test <TestName>", "Invoke a debug test\n"}, + {1, " Objects", "Read/write/compare all namespace data objects\n"}, + {1, " Predefined", + "Validate all ACPI predefined names (_STA, etc.)\n"}, + {1, " Execute predefined", + "Execute all predefined (public) methods\n"}, - {0, "\nControl Method Execution Commands:", "\n"}, + {0, "\nControl Method Single-Step Execution:", "\n"}, {1, " Arguments (or Args)", "Display method arguments\n"}, {1, " Breakpoint <AmlOffset>", "Set an AML execution breakpoint\n"}, {1, " Call", "Run to next control method invocation\n"}, - {1, " Debug <Namepath> [Arguments]", "Single Step a control method\n"}, - {6, " Evaluate", "Synonym for Execute\n"}, - {5, " Execute <Namepath> [Arguments]", "Execute control method\n"}, - {1, " Hex Integer", "Integer method argument\n"}, - {1, " \"Ascii String\"", "String method argument\n"}, - {1, " (Hex Byte List)", "Buffer method argument\n"}, - {1, " [Package Element List]", "Package method argument\n"}, - {5, " Execute predefined", - "Execute all predefined (public) methods\n"}, {1, " Go", "Allow method to run to completion\n"}, {1, " Information", "Display info about the current method\n"}, {1, " Into", "Step into (not over) a method call\n"}, @@ -296,41 +329,24 @@ static const struct acpi_db_command_help acpi_gbl_db_command_help[] = { {1, " Results", "Display method result stack\n"}, {1, " Set <A|L> <#> <Value>", "Set method data (Arguments/Locals)\n"}, {1, " Stop", "Terminate control method\n"}, - {5, " Trace <State> [<Namepath>] [Once]", - "Trace control method execution\n"}, - {1, " Enable", "Enable all messages\n"}, - {1, " Disable", "Disable tracing\n"}, - {1, " Method", "Enable method execution messages\n"}, - {1, " Opcode", "Enable opcode execution messages\n"}, {1, " Tree", "Display control method calling tree\n"}, {1, " <Enter>", "Single step next AML opcode (over calls)\n"}, #ifdef ACPI_APPLICATION - {0, "\nHardware Simulation Commands:", "\n"}, - {1, " EnableAcpi", "Enable ACPI (hardware) mode\n"}, - {1, " Event <F|G> <Value>", "Generate AcpiEvent (Fixed/GPE)\n"}, - {1, " Gpe <GpeNum> [GpeBlockDevice]", "Simulate a GPE\n"}, - {1, " Gpes", "Display info on all GPE devices\n"}, - {1, " Sci", "Generate an SCI\n"}, - {1, " Sleep [SleepState]", "Simulate sleep/wake sequence(s) (0-5)\n"}, - - {0, "\nFile I/O Commands:", "\n"}, + {0, "\nFile Operations:", "\n"}, {1, " Close", "Close debug output file\n"}, {1, " Load <Input Filename>", "Load ACPI table from a file\n"}, {1, " Open <Output Filename>", "Open a file for debug output\n"}, {1, " Unload <Namepath>", "Unload an ACPI table via namespace object\n"}, - {0, "\nUser Space Commands:", "\n"}, - {1, " Terminate", "Delete namespace and all internal objects\n"}, - {1, " Thread <Threads><Loops><NamePath>", - "Spawn threads to execute method(s)\n"}, - - {0, "\nDebug Test Commands:", "\n"}, - {3, " Test <TestName>", "Invoke a debug test\n"}, - {1, " Objects", "Read/write/compare all namespace data objects\n"}, - {1, " Predefined", - "Execute all ACPI predefined names (_STA, etc.)\n"}, + {0, "\nHardware Simulation:", "\n"}, + {1, " EnableAcpi", "Enable ACPI (hardware) mode\n"}, + {1, " Event <F|G> <Value>", "Generate AcpiEvent (Fixed/GPE)\n"}, + {1, " Gpe <GpeNum> [GpeBlockDevice]", "Simulate a GPE\n"}, + {1, " Gpes", "Display info on all GPE devices\n"}, + {1, " Sci", "Generate an SCI\n"}, + {1, " Sleep [SleepState]", "Simulate sleep/wake sequence(s) (0-5)\n"}, #endif {0, NULL, NULL} }; @@ -442,11 +458,15 @@ static void acpi_db_display_help(char *command) /* No argument to help, display help for all commands */ + acpi_os_printf("\nSummary of AML Debugger Commands\n\n"); + while (next->invocation) { acpi_os_printf("%-38s%s", next->invocation, next->description); next++; } + acpi_os_printf("\n"); + } else { /* Display help for all commands that match the subtring */ @@ -1087,6 +1107,13 @@ acpi_db_command_dispatch(char *input_buffer, /* acpi_initialize (NULL); */ break; + case CMD_BACKGROUND: + + acpi_db_create_execution_thread(acpi_gbl_db_args[1], + &acpi_gbl_db_args[2], + &acpi_gbl_db_arg_types[2]); + break; + case CMD_THREADS: acpi_db_create_execution_threads(acpi_gbl_db_args[1], diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c index f470e81b0499..4b6ebc2a2851 100644 --- a/drivers/acpi/acpica/dscontrol.c +++ b/drivers/acpi/acpica/dscontrol.c @@ -118,6 +118,8 @@ acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state, control_state->control.package_end = walk_state->parser_state.pkg_end; control_state->control.opcode = op->common.aml_opcode; + control_state->control.loop_timeout = acpi_os_get_timer() + + (u64)(acpi_gbl_max_loop_iterations * ACPI_100NSEC_PER_SEC); /* Push the control state on this walk's control stack */ @@ -206,15 +208,15 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state *walk_state, /* Predicate was true, the body of the loop was just executed */ /* - * This loop counter mechanism allows the interpreter to escape - * possibly infinite loops. This can occur in poorly written AML - * when the hardware does not respond within a while loop and the - * loop does not implement a timeout. + * This infinite loop detection mechanism allows the interpreter + * to escape possibly infinite loops. This can occur in poorly + * written AML when the hardware does not respond within a while + * loop and the loop does not implement a timeout. */ - control_state->control.loop_count++; - if (control_state->control.loop_count > - acpi_gbl_max_loop_iterations) { - status = AE_AML_INFINITE_LOOP; + if (ACPI_TIME_AFTER(acpi_os_get_timer(), + control_state->control. + loop_timeout)) { + status = AE_AML_LOOP_TIMEOUT; break; } diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index 7bcf5f5ea029..0cab34a593d5 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -209,7 +209,8 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op, ACPI_IMODE_LOAD_PASS1, flags, walk_state, &node); if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(arg->common.value.string, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + arg->common.value.string, status); return_ACPI_STATUS(status); } } @@ -383,7 +384,9 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, walk_state, &info->connection_node); if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(child->common. + ACPI_ERROR_NAMESPACE(walk_state-> + scope_info, + child->common. value.name, status); return_ACPI_STATUS(status); @@ -402,7 +405,8 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, ACPI_NS_DONT_OPEN_SCOPE, walk_state, &info->field_node); if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE((char *)&arg->named.name, + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + (char *)&arg->named.name, status); return_ACPI_STATUS(status); } else { @@ -498,7 +502,8 @@ acpi_ds_create_field(union acpi_parse_object *op, ®ion_node); #endif if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(arg->common.value.name, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + arg->common.value.name, status); return_ACPI_STATUS(status); } } @@ -618,7 +623,8 @@ acpi_ds_init_field_objects(union acpi_parse_object *op, ACPI_IMODE_LOAD_PASS1, flags, walk_state, &node); if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE((char *)&arg->named.name, + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + (char *)&arg->named.name, status); if (status != AE_ALREADY_EXISTS) { return_ACPI_STATUS(status); @@ -681,7 +687,8 @@ acpi_ds_create_bank_field(union acpi_parse_object *op, ®ion_node); #endif if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(arg->common.value.name, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + arg->common.value.name, status); return_ACPI_STATUS(status); } } @@ -695,7 +702,8 @@ acpi_ds_create_bank_field(union acpi_parse_object *op, ACPI_NS_SEARCH_PARENT, walk_state, &info.register_node); if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(arg->common.value.string, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + arg->common.value.string, status); return_ACPI_STATUS(status); } @@ -765,7 +773,8 @@ acpi_ds_create_index_field(union acpi_parse_object *op, ACPI_NS_SEARCH_PARENT, walk_state, &info.register_node); if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(arg->common.value.string, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + arg->common.value.string, status); return_ACPI_STATUS(status); } @@ -778,7 +787,8 @@ acpi_ds_create_index_field(union acpi_parse_object *op, ACPI_NS_SEARCH_PARENT, walk_state, &info.data_register_node); if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(arg->common.value.string, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + arg->common.value.string, status); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index 82448551781b..b21fe084ffc8 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -112,7 +112,9 @@ acpi_ds_build_internal_object(struct acpi_walk_state *walk_state, acpi_namespace_node, &(op->common.node))); if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(op->common.value. + ACPI_ERROR_NAMESPACE(walk_state-> + scope_info, + op->common.value. string, status); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/dspkginit.c b/drivers/acpi/acpica/dspkginit.c index 6d487edfe2de..5a602b75084e 100644 --- a/drivers/acpi/acpica/dspkginit.c +++ b/drivers/acpi/acpica/dspkginit.c @@ -297,8 +297,10 @@ acpi_ds_init_package_element(u8 object_type, { union acpi_operand_object **element_ptr; + ACPI_FUNCTION_TRACE(ds_init_package_element); + if (!source_object) { - return (AE_OK); + return_ACPI_STATUS(AE_OK); } /* @@ -329,7 +331,7 @@ acpi_ds_init_package_element(u8 object_type, source_object->package.flags |= AOPOBJ_DATA_VALID; } - return (AE_OK); + return_ACPI_STATUS(AE_OK); } /******************************************************************************* @@ -352,6 +354,7 @@ acpi_ds_resolve_package_element(union acpi_operand_object **element_ptr) union acpi_generic_state scope_info; union acpi_operand_object *element = *element_ptr; struct acpi_namespace_node *resolved_node; + struct acpi_namespace_node *original_node; char *external_path = NULL; acpi_object_type type; @@ -441,6 +444,7 @@ acpi_ds_resolve_package_element(union acpi_operand_object **element_ptr) * will remain as named references. This behavior is not described * in the ACPI spec, but it appears to be an oversight. */ + original_node = resolved_node; status = acpi_ex_resolve_node_to_value(&resolved_node, NULL); if (ACPI_FAILURE(status)) { return_VOID; @@ -468,26 +472,27 @@ acpi_ds_resolve_package_element(union acpi_operand_object **element_ptr) */ case ACPI_TYPE_DEVICE: case ACPI_TYPE_THERMAL: - - /* TBD: This may not be necesssary */ - - acpi_ut_add_reference(resolved_node->object); + case ACPI_TYPE_METHOD: break; case ACPI_TYPE_MUTEX: - case ACPI_TYPE_METHOD: case ACPI_TYPE_POWER: case ACPI_TYPE_PROCESSOR: case ACPI_TYPE_EVENT: case ACPI_TYPE_REGION: + /* acpi_ex_resolve_node_to_value gave these an extra reference */ + + acpi_ut_remove_reference(original_node->object); break; default: /* * For all other types - the node was resolved to an actual - * operand object with a value, return the object + * operand object with a value, return the object. Remove + * a reference on the existing object. */ + acpi_ut_remove_reference(element); *element_ptr = (union acpi_operand_object *)resolved_node; break; } diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c index 0dabd9b95684..4c5faf629a83 100644 --- a/drivers/acpi/acpica/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -583,7 +583,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, } if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(name_string, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + name_string, status); } } diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index eaa859a89702..5771e4e4a99a 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -207,7 +207,8 @@ acpi_ds_load1_begin_op(struct acpi_walk_state *walk_state, } #endif if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(path, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, path, + status); return_ACPI_STATUS(status); } @@ -375,7 +376,8 @@ acpi_ds_load1_begin_op(struct acpi_walk_state *walk_state, } if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(path, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + path, status); return_ACPI_STATUS(status); } } diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c index aad83ef5a4ec..b3d0aaec8203 100644 --- a/drivers/acpi/acpica/dswload2.c +++ b/drivers/acpi/acpica/dswload2.c @@ -184,11 +184,14 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, if (status == AE_NOT_FOUND) { status = AE_OK; } else { - ACPI_ERROR_NAMESPACE(buffer_ptr, + ACPI_ERROR_NAMESPACE(walk_state-> + scope_info, + buffer_ptr, status); } #else - ACPI_ERROR_NAMESPACE(buffer_ptr, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + buffer_ptr, status); #endif return_ACPI_STATUS(status); } @@ -343,7 +346,8 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, } if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(buffer_ptr, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + buffer_ptr, status); return_ACPI_STATUS(status); } @@ -719,7 +723,8 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) */ op->common.node = new_node; } else { - ACPI_ERROR_NAMESPACE(arg->common.value.string, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, + arg->common.value.string, status); } break; diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 28b447ff92df..bb58419f0d61 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -298,6 +298,16 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, ACPI_EXCEPTION((AE_INFO, status, "Returned by Handler for [%s]", acpi_ut_get_region_name(region_obj->region. space_id))); + + /* + * Special case for an EC timeout. These are seen so frequently + * that an additional error message is helpful + */ + if ((region_obj->region.space_id == ACPI_ADR_SPACE_EC) && + (status == AE_TIME)) { + ACPI_ERROR((AE_INFO, + "Timeout from EC hardware or EC device driver")); + } } if (!(handler_desc->address_space.handler_flags & diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 83398dc4b7c2..b2ff61bdb9a8 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -617,10 +617,11 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth) u32 length; u32 index; - ACPI_FUNCTION_NAME(ex_dump_operand) + ACPI_FUNCTION_NAME(ex_dump_operand); - /* Check if debug output enabled */ - if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_EXEC, _COMPONENT)) { + /* Check if debug output enabled */ + + if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_EXEC, _COMPONENT)) { return; } @@ -904,7 +905,7 @@ void acpi_ex_dump_operands(union acpi_operand_object **operands, const char *opcode_name, u32 num_operands) { - ACPI_FUNCTION_NAME(ex_dump_operands); + ACPI_FUNCTION_TRACE(ex_dump_operands); if (!opcode_name) { opcode_name = "UNKNOWN"; @@ -928,7 +929,7 @@ acpi_ex_dump_operands(union acpi_operand_object **operands, ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "**** End operand dump for [%s]\n", opcode_name)); - return; + return_VOID; } /******************************************************************************* diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c index a2f4e25d45b1..5b4282902a83 100644 --- a/drivers/acpi/acpica/hwtimer.c +++ b/drivers/acpi/acpica/hwtimer.c @@ -150,10 +150,10 @@ ACPI_EXPORT_SYMBOL(acpi_get_timer) * ******************************************************************************/ acpi_status -acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed) +acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 *time_elapsed) { acpi_status status; - u32 delta_ticks; + u64 delta_ticks; u64 quotient; ACPI_FUNCTION_TRACE(acpi_get_timer_duration); @@ -168,30 +168,29 @@ acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed) return_ACPI_STATUS(AE_SUPPORT); } + if (start_ticks == end_ticks) { + *time_elapsed = 0; + return_ACPI_STATUS(AE_OK); + } + /* * Compute Tick Delta: * Handle (max one) timer rollovers on 24-bit versus 32-bit timers. */ - if (start_ticks < end_ticks) { - delta_ticks = end_ticks - start_ticks; - } else if (start_ticks > end_ticks) { + delta_ticks = end_ticks; + if (start_ticks > end_ticks) { if ((acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) == 0) { /* 24-bit Timer */ - delta_ticks = - (((0x00FFFFFF - start_ticks) + - end_ticks) & 0x00FFFFFF); + delta_ticks |= (u64)1 << 24; } else { /* 32-bit Timer */ - delta_ticks = (0xFFFFFFFF - start_ticks) + end_ticks; + delta_ticks |= (u64)1 << 32; } - } else { /* start_ticks == end_ticks */ - - *time_elapsed = 0; - return_ACPI_STATUS(AE_OK); } + delta_ticks -= start_ticks; /* * Compute Duration (Requires a 64-bit multiply and divide): @@ -199,10 +198,10 @@ acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed) * time_elapsed (microseconds) = * (delta_ticks * ACPI_USEC_PER_SEC) / ACPI_PM_TIMER_FREQUENCY; */ - status = acpi_ut_short_divide(((u64)delta_ticks) * ACPI_USEC_PER_SEC, + status = acpi_ut_short_divide(delta_ticks * ACPI_USEC_PER_SEC, ACPI_PM_TIMER_FREQUENCY, "ient, NULL); - *time_elapsed = (u32) quotient; + *time_elapsed = (u32)quotient; return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c index 3094cec4eab4..d1679035d5f3 100644 --- a/drivers/acpi/acpica/hwvalid.c +++ b/drivers/acpi/acpica/hwvalid.c @@ -128,14 +128,14 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) acpi_io_address last_address; const struct acpi_port_info *port_info; - ACPI_FUNCTION_NAME(hw_validate_io_request); + ACPI_FUNCTION_TRACE(hw_validate_io_request); /* Supported widths are 8/16/32 */ if ((bit_width != 8) && (bit_width != 16) && (bit_width != 32)) { ACPI_ERROR((AE_INFO, "Bad BitWidth parameter: %8.8X", bit_width)); - return (AE_BAD_PARAMETER); + return_ACPI_STATUS(AE_BAD_PARAMETER); } port_info = acpi_protected_ports; @@ -153,13 +153,13 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) ACPI_ERROR((AE_INFO, "Illegal I/O port address/length above 64K: %8.8X%8.8X/0x%X", ACPI_FORMAT_UINT64(address), byte_width)); - return (AE_LIMIT); + return_ACPI_STATUS(AE_LIMIT); } /* Exit if requested address is not within the protected port table */ if (address > acpi_protected_ports[ACPI_PORT_INFO_ENTRIES - 1].end) { - return (AE_OK); + return_ACPI_STATUS(AE_OK); } /* Check request against the list of protected I/O ports */ @@ -180,8 +180,8 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) /* Port illegality may depend on the _OSI calls made by the BIOS */ if (acpi_gbl_osi_data >= port_info->osi_dependency) { - ACPI_DEBUG_PRINT((ACPI_DB_IO, - "Denied AML access to port 0x%8.8X%8.8X/%X (%s 0x%.4X-0x%.4X)", + ACPI_DEBUG_PRINT((ACPI_DB_VALUES, + "Denied AML access to port 0x%8.8X%8.8X/%X (%s 0x%.4X-0x%.4X)\n", ACPI_FORMAT_UINT64(address), byte_width, port_info->name, port_info->start, @@ -198,7 +198,7 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) } } - return (AE_OK); + return_ACPI_STATUS(AE_OK); } /****************************************************************************** diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index f2733f51ca8d..33e652a12fca 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -644,17 +644,18 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, this_node->object; } } -#ifdef ACPI_ASL_COMPILER - if (!acpi_gbl_disasm_flag && - (this_node->flags & ANOBJ_IS_EXTERNAL)) { - this_node->flags |= IMPLICIT_EXTERNAL; - } -#endif } /* Special handling for the last segment (num_segments == 0) */ else { +#ifdef ACPI_ASL_COMPILER + if (!acpi_gbl_disasm_flag + && (this_node->flags & ANOBJ_IS_EXTERNAL)) { + this_node->flags &= ~IMPLICIT_EXTERNAL; + } +#endif + /* * Sanity typecheck of the target object: * diff --git a/drivers/acpi/acpica/nsconvert.c b/drivers/acpi/acpica/nsconvert.c index 539d775bbc92..d55dcc82f434 100644 --- a/drivers/acpi/acpica/nsconvert.c +++ b/drivers/acpi/acpica/nsconvert.c @@ -495,7 +495,8 @@ acpi_ns_convert_to_reference(struct acpi_namespace_node *scope, /* Check if we are resolving a named reference within a package */ - ACPI_ERROR_NAMESPACE(original_object->string.pointer, status); + ACPI_ERROR_NAMESPACE(&scope_info, + original_object->string.pointer, status); goto error_exit; } diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index a410760a0308..22c92d1a24d8 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -49,6 +49,9 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsnames") +/* Local Prototypes */ +static void acpi_ns_normalize_pathname(char *original_path); + /******************************************************************************* * * FUNCTION: acpi_ns_get_external_pathname @@ -63,6 +66,7 @@ ACPI_MODULE_NAME("nsnames") * for error and debug statements. * ******************************************************************************/ + char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node) { char *name_buffer; @@ -352,3 +356,148 @@ char *acpi_ns_get_normalized_pathname(struct acpi_namespace_node *node, return_PTR(name_buffer); } + +/******************************************************************************* + * + * FUNCTION: acpi_ns_build_prefixed_pathname + * + * PARAMETERS: prefix_scope - Scope/Path that prefixes the internal path + * internal_path - Name or path of the namespace node + * + * RETURN: None + * + * DESCRIPTION: Construct a fully qualified pathname from a concatenation of: + * 1) Path associated with the prefix_scope namespace node + * 2) External path representation of the Internal path + * + ******************************************************************************/ + +char *acpi_ns_build_prefixed_pathname(union acpi_generic_state *prefix_scope, + const char *internal_path) +{ + acpi_status status; + char *full_path = NULL; + char *external_path = NULL; + char *prefix_path = NULL; + u32 prefix_path_length = 0; + + /* If there is a prefix, get the pathname to it */ + + if (prefix_scope && prefix_scope->scope.node) { + prefix_path = + acpi_ns_get_normalized_pathname(prefix_scope->scope.node, + TRUE); + if (prefix_path) { + prefix_path_length = strlen(prefix_path); + } + } + + status = acpi_ns_externalize_name(ACPI_UINT32_MAX, internal_path, + NULL, &external_path); + if (ACPI_FAILURE(status)) { + goto cleanup; + } + + /* Merge the prefix path and the path. 2 is for one dot and trailing null */ + + full_path = + ACPI_ALLOCATE_ZEROED(prefix_path_length + strlen(external_path) + + 2); + if (!full_path) { + goto cleanup; + } + + /* Don't merge if the External path is already fully qualified */ + + if (prefix_path && (*external_path != '\\') && (*external_path != '^')) { + strcat(full_path, prefix_path); + if (prefix_path[1]) { + strcat(full_path, "."); + } + } + + acpi_ns_normalize_pathname(external_path); + strcat(full_path, external_path); + +cleanup: + if (prefix_path) { + ACPI_FREE(prefix_path); + } + if (external_path) { + ACPI_FREE(external_path); + } + + return (full_path); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ns_normalize_pathname + * + * PARAMETERS: original_path - Path to be normalized, in External format + * + * RETURN: The original path is processed in-place + * + * DESCRIPTION: Remove trailing underscores from each element of a path. + * + * For example: \A___.B___.C___ becomes \A.B.C + * + ******************************************************************************/ + +static void acpi_ns_normalize_pathname(char *original_path) +{ + char *input_path = original_path; + char *new_path_buffer; + char *new_path; + u32 i; + + /* Allocate a temp buffer in which to construct the new path */ + + new_path_buffer = ACPI_ALLOCATE_ZEROED(strlen(input_path) + 1); + new_path = new_path_buffer; + if (!new_path_buffer) { + return; + } + + /* Special characters may appear at the beginning of the path */ + + if (*input_path == '\\') { + *new_path = *input_path; + new_path++; + input_path++; + } + + while (*input_path == '^') { + *new_path = *input_path; + new_path++; + input_path++; + } + + /* Remainder of the path */ + + while (*input_path) { + + /* Do one nameseg at a time */ + + for (i = 0; (i < ACPI_NAME_SIZE) && *input_path; i++) { + if ((i == 0) || (*input_path != '_')) { /* First char is allowed to be underscore */ + *new_path = *input_path; + new_path++; + } + + input_path++; + } + + /* Dot means that there are more namesegs to come */ + + if (*input_path == '.') { + *new_path = *input_path; + new_path++; + input_path++; + } + } + + *new_path = 0; + strcpy(original_path, new_path_buffer); + ACPI_FREE(new_path_buffer); +} diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c index 5de8957f5ef0..e91dbee9235f 100644 --- a/drivers/acpi/acpica/nssearch.c +++ b/drivers/acpi/acpica/nssearch.c @@ -417,6 +417,7 @@ acpi_ns_search_and_enter(u32 target_name, if (flags & ACPI_NS_EXTERNAL || (walk_state && walk_state->opcode == AML_SCOPE_OP)) { new_node->flags |= ANOBJ_IS_EXTERNAL; + new_node->flags |= IMPLICIT_EXTERNAL; } #endif diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index 783f4c838aee..9b51f65823b2 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -61,10 +61,10 @@ static void acpi_ns_resolve_references(struct acpi_evaluate_info *info); * * PARAMETERS: handle - Object handle (optional) * pathname - Object pathname (optional) - * external_params - List of parameters to pass to method, + * external_params - List of parameters to pass to a method, * terminated by NULL. May be NULL * if no parameters are being passed. - * return_buffer - Where to put method's return value (if + * return_buffer - Where to put the object's return value (if * any). If NULL, no value is returned. * return_type - Expected type of return object * @@ -100,13 +100,14 @@ acpi_evaluate_object_typed(acpi_handle handle, free_buffer_on_error = TRUE; } + /* Get a handle here, in order to build an error message if needed */ + + target_handle = handle; if (pathname) { status = acpi_get_handle(handle, pathname, &target_handle); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } - } else { - target_handle = handle; } full_pathname = acpi_ns_get_external_pathname(target_handle); diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index eb9dfaca555f..171e2faa7c50 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -361,7 +361,7 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state, /* Final exception check (may have been changed from code above) */ if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(path, status); + ACPI_ERROR_NAMESPACE(walk_state->scope_info, path, status); if ((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) == ACPI_PARSE_EXECUTE) { diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c index 0bef6df71bba..c0b179883ff2 100644 --- a/drivers/acpi/acpica/psobject.c +++ b/drivers/acpi/acpica/psobject.c @@ -372,16 +372,10 @@ acpi_ps_create_op(struct acpi_walk_state *walk_state, * external declaration opcode. Setting walk_state->Aml to * walk_state->parser_state.Aml + 2 moves increments the * walk_state->Aml past the object type and the paramcount of the - * external opcode. For the error message, only print the AML - * offset. We could attempt to print the name but this may cause - * a segmentation fault when printing the namepath because the - * AML may be incorrect. + * external opcode. */ - acpi_os_printf - ("// Invalid external declaration at AML offset 0x%x.\n", - walk_state->aml - - walk_state->parser_state.aml_start); walk_state->aml = walk_state->parser_state.aml + 2; + walk_state->parser_state.aml = walk_state->aml; return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); } #endif diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c index 02642760cb93..cd59dfe6a47d 100644 --- a/drivers/acpi/acpica/psutils.c +++ b/drivers/acpi/acpica/psutils.c @@ -94,9 +94,11 @@ void acpi_ps_init_op(union acpi_parse_object *op, u16 opcode) op->common.descriptor_type = ACPI_DESC_TYPE_PARSER; op->common.aml_opcode = opcode; - ACPI_DISASM_ONLY_MEMBERS(strncpy(op->common.aml_op_name, - (acpi_ps_get_opcode_info(opcode))-> - name, sizeof(op->common.aml_op_name))); + ACPI_DISASM_ONLY_MEMBERS(acpi_ut_safe_strncpy(op->common.aml_op_name, + (acpi_ps_get_opcode_info + (opcode))->name, + sizeof(op->common. + aml_op_name))); } /******************************************************************************* @@ -158,10 +160,10 @@ union acpi_parse_object *acpi_ps_alloc_op(u16 opcode, u8 *aml) if (opcode == AML_SCOPE_OP) { acpi_gbl_current_scope = op; } - } - if (gbl_capture_comments) { - ASL_CV_TRANSFER_COMMENTS(op); + if (acpi_gbl_capture_comments) { + ASL_CV_TRANSFER_COMMENTS(op); + } } return (op); diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index 615a885e2ca3..cff7154b7fee 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -163,6 +163,9 @@ acpi_debug_print(u32 requested_debug_level, { acpi_thread_id thread_id; va_list args; +#ifdef ACPI_APPLICATION + int fill_count; +#endif /* Check if debug output enabled */ @@ -202,10 +205,21 @@ acpi_debug_print(u32 requested_debug_level, acpi_os_printf("[%u] ", (u32)thread_id); } - acpi_os_printf("[%02ld] ", acpi_gbl_nesting_level); -#endif + fill_count = 48 - acpi_gbl_nesting_level - + strlen(acpi_ut_trim_function_name(function_name)); + if (fill_count < 0) { + fill_count = 0; + } + + acpi_os_printf("[%02ld] %*s", + acpi_gbl_nesting_level, acpi_gbl_nesting_level + 1, " "); + acpi_os_printf("%s%*s: ", + acpi_ut_trim_function_name(function_name), fill_count, + " "); +#else acpi_os_printf("%-22.22s: ", acpi_ut_trim_function_name(function_name)); +#endif va_start(args, format); acpi_os_vprintf(format, args); diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c index 02cd2c2d961a..55debbad487d 100644 --- a/drivers/acpi/acpica/utdecode.c +++ b/drivers/acpi/acpica/utdecode.c @@ -395,11 +395,6 @@ const char *acpi_ut_get_reference_name(union acpi_operand_object *object) return (acpi_gbl_ref_class_names[object->reference.class]); } -#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) -/* - * Strings and procedures used for debug only - */ - /******************************************************************************* * * FUNCTION: acpi_ut_get_mutex_name @@ -433,6 +428,12 @@ const char *acpi_ut_get_mutex_name(u32 mutex_id) return (acpi_gbl_mutex_names[mutex_id]); } +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) + +/* + * Strings and procedures used for debug only + */ + /******************************************************************************* * * FUNCTION: acpi_ut_get_notify_name diff --git a/drivers/acpi/acpica/uterror.c b/drivers/acpi/acpica/uterror.c index e3368186e1c1..42388dcb5ccc 100644 --- a/drivers/acpi/acpica/uterror.c +++ b/drivers/acpi/acpica/uterror.c @@ -182,6 +182,78 @@ acpi_ut_predefined_bios_error(const char *module_name, /******************************************************************************* * + * FUNCTION: acpi_ut_prefixed_namespace_error + * + * PARAMETERS: module_name - Caller's module name (for error output) + * line_number - Caller's line number (for error output) + * prefix_scope - Scope/Path that prefixes the internal path + * internal_path - Name or path of the namespace node + * lookup_status - Exception code from NS lookup + * + * RETURN: None + * + * DESCRIPTION: Print error message with the full pathname constructed this way: + * + * prefix_scope_node_full_path.externalized_internal_path + * + * NOTE: 10/2017: Treat the major ns_lookup errors as firmware errors + * + ******************************************************************************/ + +void +acpi_ut_prefixed_namespace_error(const char *module_name, + u32 line_number, + union acpi_generic_state *prefix_scope, + const char *internal_path, + acpi_status lookup_status) +{ + char *full_path; + const char *message; + + /* + * Main cases: + * 1) Object creation, object must not already exist + * 2) Object lookup, object must exist + */ + switch (lookup_status) { + case AE_ALREADY_EXISTS: + + acpi_os_printf(ACPI_MSG_BIOS_ERROR); + message = "Failure creating"; + break; + + case AE_NOT_FOUND: + + acpi_os_printf(ACPI_MSG_BIOS_ERROR); + message = "Failure looking up"; + break; + + default: + + acpi_os_printf(ACPI_MSG_ERROR); + message = "Failure looking up"; + break; + } + + /* Concatenate the prefix path and the internal path */ + + full_path = + acpi_ns_build_prefixed_pathname(prefix_scope, internal_path); + + acpi_os_printf("%s [%s], %s", message, + full_path ? full_path : "Could not get pathname", + acpi_format_exception(lookup_status)); + + if (full_path) { + ACPI_FREE(full_path); + } + + ACPI_MSG_SUFFIX; +} + +#ifdef __OBSOLETE_FUNCTION +/******************************************************************************* + * * FUNCTION: acpi_ut_namespace_error * * PARAMETERS: module_name - Caller's module name (for error output) @@ -240,6 +312,7 @@ acpi_ut_namespace_error(const char *module_name, ACPI_MSG_SUFFIX; ACPI_MSG_REDIRECT_END; } +#endif /******************************************************************************* * diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c index 23e766d1691d..45eeb0dcf283 100644 --- a/drivers/acpi/acpica/utinit.c +++ b/drivers/acpi/acpica/utinit.c @@ -206,7 +206,6 @@ acpi_status acpi_ut_init_globals(void) acpi_gbl_next_owner_id_offset = 0; acpi_gbl_debugger_configuration = DEBUGGER_THREADING; acpi_gbl_osi_mutex = NULL; - acpi_gbl_max_loop_iterations = ACPI_MAX_LOOP_COUNT; /* Hardware oriented */ diff --git a/drivers/acpi/acpica/utmath.c b/drivers/acpi/acpica/utmath.c index 5f9c680076c4..2055a858e5f5 100644 --- a/drivers/acpi/acpica/utmath.c +++ b/drivers/acpi/acpica/utmath.c @@ -134,7 +134,7 @@ acpi_status acpi_ut_short_shift_left(u64 operand, u32 count, u64 *out_result) if ((count & 63) >= 32) { operand_ovl.part.hi = operand_ovl.part.lo; - operand_ovl.part.lo ^= operand_ovl.part.lo; + operand_ovl.part.lo = 0; count = (count & 63) - 32; } ACPI_SHIFT_LEFT_64_BY_32(operand_ovl.part.hi, @@ -171,7 +171,7 @@ acpi_status acpi_ut_short_shift_right(u64 operand, u32 count, u64 *out_result) if ((count & 63) >= 32) { operand_ovl.part.lo = operand_ovl.part.hi; - operand_ovl.part.hi ^= operand_ovl.part.hi; + operand_ovl.part.hi = 0; count = (count & 63) - 32; } ACPI_SHIFT_RIGHT_64_BY_32(operand_ovl.part.hi, diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c index 586354788018..524ba931d5e8 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c @@ -286,8 +286,9 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) acpi_gbl_mutex_info[mutex_id].thread_id = this_thread_id; } else { ACPI_EXCEPTION((AE_INFO, status, - "Thread %u could not acquire Mutex [0x%X]", - (u32)this_thread_id, mutex_id)); + "Thread %u could not acquire Mutex [%s] (0x%X)", + (u32)this_thread_id, + acpi_ut_get_mutex_name(mutex_id), mutex_id)); } return (status); @@ -322,8 +323,8 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id) */ if (acpi_gbl_mutex_info[mutex_id].thread_id == ACPI_MUTEX_NOT_ACQUIRED) { ACPI_ERROR((AE_INFO, - "Mutex [0x%X] is not acquired, cannot release", - mutex_id)); + "Mutex [%s] (0x%X) is not acquired, cannot release", + acpi_ut_get_mutex_name(mutex_id), mutex_id)); return (AE_NOT_ACQUIRED); } diff --git a/drivers/acpi/acpica/utnonansi.c b/drivers/acpi/acpica/utnonansi.c index 792664982ea3..33a0970646df 100644 --- a/drivers/acpi/acpica/utnonansi.c +++ b/drivers/acpi/acpica/utnonansi.c @@ -140,7 +140,7 @@ int acpi_ut_stricmp(char *string1, char *string2) return (c1 - c2); } -#if defined (ACPI_DEBUGGER) || defined (ACPI_APPLICATION) +#if defined (ACPI_DEBUGGER) || defined (ACPI_APPLICATION) || defined (ACPI_DEBUG_OUTPUT) /******************************************************************************* * * FUNCTION: acpi_ut_safe_strcpy, acpi_ut_safe_strcat, acpi_ut_safe_strncat @@ -199,4 +199,13 @@ acpi_ut_safe_strncat(char *dest, strncat(dest, source, max_transfer_length); return (FALSE); } + +void acpi_ut_safe_strncpy(char *dest, char *source, acpi_size dest_size) +{ + /* Always terminate destination string */ + + strncpy(dest, source, dest_size); + dest[dest_size - 1] = 0; +} + #endif diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c index 3175b133c0e4..f6b8dd24b006 100644 --- a/drivers/acpi/acpica/utosi.c +++ b/drivers/acpi/acpica/utosi.c @@ -101,6 +101,8 @@ static struct acpi_interface_info acpi_default_supported_interfaces[] = { {"Windows 2012", NULL, 0, ACPI_OSI_WIN_8}, /* Windows 8 and Server 2012 - Added 08/2012 */ {"Windows 2013", NULL, 0, ACPI_OSI_WIN_8}, /* Windows 8.1 and Server 2012 R2 - Added 01/2014 */ {"Windows 2015", NULL, 0, ACPI_OSI_WIN_10}, /* Windows 10 - Added 03/2015 */ + {"Windows 2016", NULL, 0, ACPI_OSI_WIN_10_RS1}, /* Windows 10 version 1607 - Added 12/2017 */ + {"Windows 2017", NULL, 0, ACPI_OSI_WIN_10_RS2}, /* Windows 10 version 1703 - Added 12/2017 */ /* Feature Group Strings */ diff --git a/drivers/acpi/acpica/utstrsuppt.c b/drivers/acpi/acpica/utstrsuppt.c index 965fb5cec94f..97f48d71f9e6 100644 --- a/drivers/acpi/acpica/utstrsuppt.c +++ b/drivers/acpi/acpica/utstrsuppt.c @@ -52,10 +52,9 @@ static acpi_status acpi_ut_insert_digit(u64 *accumulated_value, u32 base, int ascii_digit); static acpi_status -acpi_ut_strtoul_multiply64(u64 multiplicand, u64 multiplier, u64 *out_product); +acpi_ut_strtoul_multiply64(u64 multiplicand, u32 base, u64 *out_product); -static acpi_status -acpi_ut_strtoul_add64(u64 addend1, u64 addend2, u64 *out_sum); +static acpi_status acpi_ut_strtoul_add64(u64 addend1, u32 digit, u64 *out_sum); /******************************************************************************* * @@ -357,7 +356,7 @@ acpi_ut_insert_digit(u64 *accumulated_value, u32 base, int ascii_digit) * FUNCTION: acpi_ut_strtoul_multiply64 * * PARAMETERS: multiplicand - Current accumulated converted integer - * multiplier - Base/Radix + * base - Base/Radix * out_product - Where the product is returned * * RETURN: Status and 64-bit product @@ -369,33 +368,40 @@ acpi_ut_insert_digit(u64 *accumulated_value, u32 base, int ascii_digit) ******************************************************************************/ static acpi_status -acpi_ut_strtoul_multiply64(u64 multiplicand, u64 multiplier, u64 *out_product) +acpi_ut_strtoul_multiply64(u64 multiplicand, u32 base, u64 *out_product) { - u64 val; + u64 product; + u64 quotient; /* Exit if either operand is zero */ *out_product = 0; - if (!multiplicand || !multiplier) { + if (!multiplicand || !base) { return (AE_OK); } - /* Check for 64-bit overflow before the actual multiplication */ - - acpi_ut_short_divide(ACPI_UINT64_MAX, (u32)multiplier, &val, NULL); - if (multiplicand > val) { + /* + * Check for 64-bit overflow before the actual multiplication. + * + * Notes: 64-bit division is often not supported on 32-bit platforms + * (it requires a library function), Therefore ACPICA has a local + * 64-bit divide function. Also, Multiplier is currently only used + * as the radix (8/10/16), to the 64/32 divide will always work. + */ + acpi_ut_short_divide(ACPI_UINT64_MAX, base, "ient, NULL); + if (multiplicand > quotient) { return (AE_NUMERIC_OVERFLOW); } - val = multiplicand * multiplier; + product = multiplicand * base; /* Check for 32-bit overflow if necessary */ - if ((acpi_gbl_integer_bit_width == 32) && (val > ACPI_UINT32_MAX)) { + if ((acpi_gbl_integer_bit_width == 32) && (product > ACPI_UINT32_MAX)) { return (AE_NUMERIC_OVERFLOW); } - *out_product = val; + *out_product = product; return (AE_OK); } @@ -404,7 +410,7 @@ acpi_ut_strtoul_multiply64(u64 multiplicand, u64 multiplier, u64 *out_product) * FUNCTION: acpi_ut_strtoul_add64 * * PARAMETERS: addend1 - Current accumulated converted integer - * addend2 - New hex value/char + * digit - New hex value/char * out_sum - Where sum is returned (Accumulator) * * RETURN: Status and 64-bit sum @@ -415,17 +421,17 @@ acpi_ut_strtoul_multiply64(u64 multiplicand, u64 multiplier, u64 *out_product) * ******************************************************************************/ -static acpi_status acpi_ut_strtoul_add64(u64 addend1, u64 addend2, u64 *out_sum) +static acpi_status acpi_ut_strtoul_add64(u64 addend1, u32 digit, u64 *out_sum) { u64 sum; /* Check for 64-bit overflow before the actual addition */ - if ((addend1 > 0) && (addend2 > (ACPI_UINT64_MAX - addend1))) { + if ((addend1 > 0) && (digit > (ACPI_UINT64_MAX - addend1))) { return (AE_NUMERIC_OVERFLOW); } - sum = addend1 + addend2; + sum = addend1 + digit; /* Check for 32-bit overflow if necessary */ diff --git a/drivers/acpi/acpica/uttrack.c b/drivers/acpi/acpica/uttrack.c index 3c8de88ecbd5..633b4e2c669f 100644 --- a/drivers/acpi/acpica/uttrack.c +++ b/drivers/acpi/acpica/uttrack.c @@ -402,8 +402,8 @@ acpi_ut_track_allocation(struct acpi_debug_mem_block *allocation, allocation->component = component; allocation->line = line; - strncpy(allocation->module, module, ACPI_MAX_MODULE_NAME); - allocation->module[ACPI_MAX_MODULE_NAME - 1] = 0; + acpi_ut_safe_strncpy(allocation->module, (char *)module, + ACPI_MAX_MODULE_NAME); if (!element) { @@ -717,7 +717,7 @@ exit: if (!num_outstanding) { ACPI_INFO(("No outstanding allocations")); } else { - ACPI_ERROR((AE_INFO, "%u(0x%X) Outstanding allocations", + ACPI_ERROR((AE_INFO, "%u (0x%X) Outstanding cache allocations", num_outstanding, num_outstanding)); } diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c index 950a1e500bfa..9da4f8ef2e77 100644 --- a/drivers/acpi/acpica/utxferror.c +++ b/drivers/acpi/acpica/utxferror.c @@ -96,8 +96,8 @@ ACPI_EXPORT_SYMBOL(acpi_error) * * RETURN: None * - * DESCRIPTION: Print "ACPI Exception" message with module/line/version info - * and decoded acpi_status. + * DESCRIPTION: Print an "ACPI Error" message with module/line/version + * info as well as decoded acpi_status. * ******************************************************************************/ void ACPI_INTERNAL_VAR_XFACE @@ -111,10 +111,10 @@ acpi_exception(const char *module_name, /* For AE_OK, just print the message */ if (ACPI_SUCCESS(status)) { - acpi_os_printf(ACPI_MSG_EXCEPTION); + acpi_os_printf(ACPI_MSG_ERROR); } else { - acpi_os_printf(ACPI_MSG_EXCEPTION "%s, ", + acpi_os_printf(ACPI_MSG_ERROR "%s, ", acpi_format_exception(status)); } diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 6742f6c68034..9bff853e85f3 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -1007,7 +1007,7 @@ skip: /* The record may be cleared by others, try read next record */ if (len == -ENOENT) goto skip; - else if (len < sizeof(*rcd)) { + else if (len < 0 || len < sizeof(*rcd)) { rc = -EIO; goto out; } diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 6402f7fad3bb..1efefe919555 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -410,7 +410,52 @@ static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int flags = 0; if (flags != -1) - memory_failure_queue(pfn, 0, flags); + memory_failure_queue(pfn, flags); +#endif +} + +/* + * PCIe AER errors need to be sent to the AER driver for reporting and + * recovery. The GHES severities map to the following AER severities and + * require the following handling: + * + * GHES_SEV_CORRECTABLE -> AER_CORRECTABLE + * These need to be reported by the AER driver but no recovery is + * necessary. + * GHES_SEV_RECOVERABLE -> AER_NONFATAL + * GHES_SEV_RECOVERABLE && CPER_SEC_RESET -> AER_FATAL + * These both need to be reported and recovered from by the AER driver. + * GHES_SEV_PANIC does not make it to this handling since the kernel must + * panic. + */ +static void ghes_handle_aer(struct acpi_hest_generic_data *gdata) +{ +#ifdef CONFIG_ACPI_APEI_PCIEAER + struct cper_sec_pcie *pcie_err = acpi_hest_get_payload(gdata); + + if (pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID && + pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) { + unsigned int devfn; + int aer_severity; + + devfn = PCI_DEVFN(pcie_err->device_id.device, + pcie_err->device_id.function); + aer_severity = cper_severity_to_aer(gdata->error_severity); + + /* + * If firmware reset the component to contain + * the error, we must reinitialize it before + * use, so treat it as a fatal AER error. + */ + if (gdata->flags & CPER_SEC_RESET) + aer_severity = AER_FATAL; + + aer_recover_queue(pcie_err->device_id.segment, + pcie_err->device_id.bus, + devfn, aer_severity, + (struct aer_capability_regs *) + pcie_err->aer_info); + } #endif } @@ -441,38 +486,9 @@ static void ghes_do_proc(struct ghes *ghes, arch_apei_report_mem_error(sev, mem_err); ghes_handle_memory_failure(gdata, sev); } -#ifdef CONFIG_ACPI_APEI_PCIEAER else if (guid_equal(sec_type, &CPER_SEC_PCIE)) { - struct cper_sec_pcie *pcie_err = acpi_hest_get_payload(gdata); - - if (sev == GHES_SEV_RECOVERABLE && - sec_sev == GHES_SEV_RECOVERABLE && - pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID && - pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) { - unsigned int devfn; - int aer_severity; - - devfn = PCI_DEVFN(pcie_err->device_id.device, - pcie_err->device_id.function); - aer_severity = cper_severity_to_aer(gdata->error_severity); - - /* - * If firmware reset the component to contain - * the error, we must reinitialize it before - * use, so treat it as a fatal AER error. - */ - if (gdata->flags & CPER_SEC_RESET) - aer_severity = AER_FATAL; - - aer_recover_queue(pcie_err->device_id.segment, - pcie_err->device_id.bus, - devfn, aer_severity, - (struct aer_capability_regs *) - pcie_err->aer_info); - } - + ghes_handle_aer(gdata); } -#endif else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) { struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata); @@ -870,7 +886,6 @@ static void ghes_print_queued_estatus(void) struct ghes_estatus_node *estatus_node; struct acpi_hest_generic *generic; struct acpi_hest_generic_status *estatus; - u32 len, node_len; llnode = llist_del_all(&ghes_estatus_llist); /* @@ -882,8 +897,6 @@ static void ghes_print_queued_estatus(void) estatus_node = llist_entry(llnode, struct ghes_estatus_node, llnode); estatus = GHES_ESTATUS_FROM_NODE(estatus_node); - len = cper_estatus_len(estatus); - node_len = GHES_ESTATUS_NODE_LEN(len); generic = estatus_node->generic; ghes_print_estatus(NULL, generic, estatus); llnode = llnode->next; diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 13e7b56e33ae..19bc440820e6 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -70,6 +70,7 @@ static async_cookie_t async_cookie; static bool battery_driver_registered; static int battery_bix_broken_package; static int battery_notification_delay_ms; +static int battery_full_discharging; static unsigned int cache_time = 1000; module_param(cache_time, uint, 0644); MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); @@ -214,9 +215,12 @@ static int acpi_battery_get_property(struct power_supply *psy, return -ENODEV; switch (psp) { case POWER_SUPPLY_PROP_STATUS: - if (battery->state & ACPI_BATTERY_STATE_DISCHARGING) - val->intval = POWER_SUPPLY_STATUS_DISCHARGING; - else if (battery->state & ACPI_BATTERY_STATE_CHARGING) + if (battery->state & ACPI_BATTERY_STATE_DISCHARGING) { + if (battery_full_discharging && battery->rate_now == 0) + val->intval = POWER_SUPPLY_STATUS_FULL; + else + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + } else if (battery->state & ACPI_BATTERY_STATE_CHARGING) val->intval = POWER_SUPPLY_STATUS_CHARGING; else if (acpi_battery_is_charged(battery)) val->intval = POWER_SUPPLY_STATUS_FULL; @@ -1166,6 +1170,12 @@ battery_notification_delay_quirk(const struct dmi_system_id *d) return 0; } +static int __init battery_full_discharging_quirk(const struct dmi_system_id *d) +{ + battery_full_discharging = 1; + return 0; +} + static const struct dmi_system_id bat_dmi_table[] __initconst = { { .callback = battery_bix_broken_package_quirk, @@ -1183,6 +1193,22 @@ static const struct dmi_system_id bat_dmi_table[] __initconst = { DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-573G"), }, }, + { + .callback = battery_full_discharging_quirk, + .ident = "ASUS GL502VSK", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "GL502VSK"), + }, + }, + { + .callback = battery_full_discharging_quirk, + .ident = "ASUS UX305LA", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "UX305LA"), + }, + }, {}, }; @@ -1237,13 +1263,11 @@ static int acpi_battery_add(struct acpi_device *device) #ifdef CONFIG_ACPI_PROCFS_POWER result = acpi_battery_add_fs(device); -#endif if (result) { -#ifdef CONFIG_ACPI_PROCFS_POWER acpi_battery_remove_fs(device); -#endif goto fail; } +#endif printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index bf8e4d371fa7..e1eee7a60fad 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -30,6 +30,7 @@ #include <linux/input.h> #include <linux/slab.h> #include <linux/acpi.h> +#include <linux/dmi.h> #include <acpi/button.h> #define PREFIX "ACPI: " @@ -76,6 +77,22 @@ static const struct acpi_device_id button_device_ids[] = { }; MODULE_DEVICE_TABLE(acpi, button_device_ids); +/* + * Some devices which don't even have a lid in anyway have a broken _LID + * method (e.g. pointing to a floating gpio pin) causing spurious LID events. + */ +static const struct dmi_system_id lid_blacklst[] = { + { + /* GP-electronic T701 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_MATCH(DMI_PRODUCT_NAME, "T701"), + DMI_MATCH(DMI_BIOS_VERSION, "BYT70A.YNCHENG.WIN.007"), + }, + }, + {} +}; + static int acpi_button_add(struct acpi_device *device); static int acpi_button_remove(struct acpi_device *device); static void acpi_button_notify(struct acpi_device *device, u32 event); @@ -210,6 +227,8 @@ static int acpi_lid_notify_state(struct acpi_device *device, int state) } /* Send the platform triggered reliable event */ if (do_update) { + acpi_handle_debug(device->handle, "ACPI LID %s\n", + state ? "open" : "closed"); input_report_switch(button->input, SW_LID, !state); input_sync(button->input); button->last_state = !!state; @@ -473,6 +492,9 @@ static int acpi_button_add(struct acpi_device *device) char *name, *class; int error; + if (!strcmp(hid, ACPI_BUTTON_HID_LID) && dmi_check_system(lid_blacklst)) + return -ENODEV; + button = kzalloc(sizeof(struct acpi_button), GFP_KERNEL); if (!button) return -ENOMEM; diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 21c28433c590..06ea4749ebd9 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -949,7 +949,7 @@ static int cpc_read(int cpu, struct cpc_register_resource *reg_res, u64 *val) } *val = 0; - if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) + if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM && pcc_ss_id >= 0) vaddr = GET_PCC_VADDR(reg->address, pcc_ss_id); else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) vaddr = reg_res->sys_mem_vaddr; @@ -988,7 +988,7 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val) int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu); struct cpc_reg *reg = ®_res->cpc_entry.reg; - if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) + if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM && pcc_ss_id >= 0) vaddr = GET_PCC_VADDR(reg->address, pcc_ss_id); else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) vaddr = reg_res->sys_mem_vaddr; @@ -1035,14 +1035,15 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) *lowest_non_linear_reg, *nominal_reg; u64 high, low, nom, min_nonlinear; int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum); - struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id]; + struct cppc_pcc_data *pcc_ss_data; int ret = 0, regs_in_pcc = 0; - if (!cpc_desc) { + if (!cpc_desc || pcc_ss_id < 0) { pr_debug("No CPC descriptor for CPU:%d\n", cpunum); return -ENODEV; } + pcc_ss_data = pcc_data[pcc_ss_id]; highest_reg = &cpc_desc->cpc_regs[HIGHEST_PERF]; lowest_reg = &cpc_desc->cpc_regs[LOWEST_PERF]; lowest_non_linear_reg = &cpc_desc->cpc_regs[LOW_NON_LINEAR_PERF]; @@ -1095,15 +1096,16 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs) struct cpc_register_resource *delivered_reg, *reference_reg, *ref_perf_reg, *ctr_wrap_reg; int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum); - struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id]; + struct cppc_pcc_data *pcc_ss_data; u64 delivered, reference, ref_perf, ctr_wrap_time; int ret = 0, regs_in_pcc = 0; - if (!cpc_desc) { + if (!cpc_desc || pcc_ss_id < 0) { pr_debug("No CPC descriptor for CPU:%d\n", cpunum); return -ENODEV; } + pcc_ss_data = pcc_data[pcc_ss_id]; delivered_reg = &cpc_desc->cpc_regs[DELIVERED_CTR]; reference_reg = &cpc_desc->cpc_regs[REFERENCE_CTR]; ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF]; @@ -1169,14 +1171,15 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu); struct cpc_register_resource *desired_reg; int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu); - struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id]; + struct cppc_pcc_data *pcc_ss_data; int ret = 0; - if (!cpc_desc) { + if (!cpc_desc || pcc_ss_id < 0) { pr_debug("No CPC descriptor for CPU:%d\n", cpu); return -ENODEV; } + pcc_ss_data = pcc_data[pcc_ss_id]; desired_reg = &cpc_desc->cpc_regs[DESIRED_PERF]; /* @@ -1301,7 +1304,7 @@ unsigned int cppc_get_transition_latency(int cpu_num) struct cpc_desc *cpc_desc; struct cpc_register_resource *desired_reg; int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu_num); - struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id]; + struct cppc_pcc_data *pcc_ss_data; cpc_desc = per_cpu(cpc_desc_ptr, cpu_num); if (!cpc_desc) @@ -1311,6 +1314,10 @@ unsigned int cppc_get_transition_latency(int cpu_num) if (!CPC_IN_PCC(desired_reg)) return CPUFREQ_ETERNAL; + if (pcc_ss_id < 0) + return CPUFREQ_ETERNAL; + + pcc_ss_data = pcc_data[pcc_ss_id]; if (pcc_ss_data->pcc_mpar) latency_ns = 60 * (1000 * 1000 * 1000 / pcc_ss_data->pcc_mpar); diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index e4ffaeec9ec2..c4d0a1c912f0 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -990,7 +990,7 @@ void acpi_subsys_complete(struct device *dev) * the sleep state it is going out of and it has never been resumed till * now, resume it in case the firmware powered it up. */ - if (dev->power.direct_complete && pm_resume_via_firmware()) + if (pm_runtime_suspended(dev) && pm_resume_via_firmware()) pm_request_resume(dev); } EXPORT_SYMBOL_GPL(acpi_subsys_complete); @@ -1039,10 +1039,28 @@ EXPORT_SYMBOL_GPL(acpi_subsys_suspend_late); */ int acpi_subsys_suspend_noirq(struct device *dev) { - if (dev_pm_smart_suspend_and_suspended(dev)) + int ret; + + if (dev_pm_smart_suspend_and_suspended(dev)) { + dev->power.may_skip_resume = true; return 0; + } + + ret = pm_generic_suspend_noirq(dev); + if (ret) + return ret; + + /* + * If the target system sleep state is suspend-to-idle, it is sufficient + * to check whether or not the device's wakeup settings are good for + * runtime PM. Otherwise, the pm_resume_via_firmware() check will cause + * acpi_subsys_complete() to take care of fixing up the device's state + * anyway, if need be. + */ + dev->power.may_skip_resume = device_may_wakeup(dev) || + !device_can_wakeup(dev); - return pm_generic_suspend_noirq(dev); + return 0; } EXPORT_SYMBOL_GPL(acpi_subsys_suspend_noirq); @@ -1052,6 +1070,9 @@ EXPORT_SYMBOL_GPL(acpi_subsys_suspend_noirq); */ int acpi_subsys_resume_noirq(struct device *dev) { + if (dev_pm_may_skip_resume(dev)) + return 0; + /* * Devices with DPM_FLAG_SMART_SUSPEND may be left in runtime suspend * during system suspend, so update their runtime PM status to "active" @@ -1138,7 +1159,7 @@ int acpi_subsys_thaw_noirq(struct device *dev) * skip all of the subsequent "thaw" callbacks for the device. */ if (dev_pm_smart_suspend_and_suspended(dev)) { - dev->power.direct_complete = true; + dev_pm_skip_next_resume_phases(dev); return 0; } diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c index 24418932612e..a041689e5701 100644 --- a/drivers/acpi/device_sysfs.c +++ b/drivers/acpi/device_sysfs.c @@ -146,6 +146,10 @@ static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias, int count; struct acpi_hardware_id *id; + /* Avoid unnecessarily loading modules for non present devices. */ + if (!acpi_device_is_present(acpi_dev)) + return 0; + /* * Since we skip ACPI_DT_NAMESPACE_HID from the modalias below, 0 should * be returned if ACPI_DT_NAMESPACE_HID is the only ACPI/PNP ID in the diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index da176c95aa2c..d9f38c645e4a 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1516,7 +1516,7 @@ static int acpi_ec_setup(struct acpi_ec *ec, bool handle_events) } acpi_handle_info(ec->handle, - "GPE=0x%lx, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n", + "GPE=0x%x, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n", ec->gpe, ec->command_addr, ec->data_addr); return ret; } @@ -1597,32 +1597,41 @@ static int acpi_ec_add(struct acpi_device *device) { struct acpi_ec *ec = NULL; int ret; + bool is_ecdt = false; + acpi_status status; strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_EC_CLASS); - ec = acpi_ec_alloc(); - if (!ec) - return -ENOMEM; - if (ec_parse_device(device->handle, 0, ec, NULL) != - AE_CTRL_TERMINATE) { + if (!strcmp(acpi_device_hid(device), ACPI_ECDT_HID)) { + is_ecdt = true; + ec = boot_ec; + } else { + ec = acpi_ec_alloc(); + if (!ec) + return -ENOMEM; + status = ec_parse_device(device->handle, 0, ec, NULL); + if (status != AE_CTRL_TERMINATE) { ret = -EINVAL; goto err_alloc; + } } if (acpi_is_boot_ec(ec)) { - boot_ec_is_ecdt = false; - /* - * Trust PNP0C09 namespace location rather than ECDT ID. - * - * But trust ECDT GPE rather than _GPE because of ASUS quirks, - * so do not change boot_ec->gpe to ec->gpe. - */ - boot_ec->handle = ec->handle; - acpi_handle_debug(ec->handle, "duplicated.\n"); - acpi_ec_free(ec); - ec = boot_ec; - ret = acpi_config_boot_ec(ec, ec->handle, true, false); + boot_ec_is_ecdt = is_ecdt; + if (!is_ecdt) { + /* + * Trust PNP0C09 namespace location rather than + * ECDT ID. But trust ECDT GPE rather than _GPE + * because of ASUS quirks, so do not change + * boot_ec->gpe to ec->gpe. + */ + boot_ec->handle = ec->handle; + acpi_handle_debug(ec->handle, "duplicated.\n"); + acpi_ec_free(ec); + ec = boot_ec; + } + ret = acpi_config_boot_ec(ec, ec->handle, true, is_ecdt); } else ret = acpi_ec_setup(ec, true); if (ret) @@ -1635,8 +1644,10 @@ static int acpi_ec_add(struct acpi_device *device) ret = !!request_region(ec->command_addr, 1, "EC cmd"); WARN(!ret, "Could not request EC cmd io port 0x%lx", ec->command_addr); - /* Reprobe devices depending on the EC */ - acpi_walk_dep_device_list(ec->handle); + if (!is_ecdt) { + /* Reprobe devices depending on the EC */ + acpi_walk_dep_device_list(ec->handle); + } acpi_handle_debug(ec->handle, "enumerated.\n"); return 0; @@ -1692,6 +1703,7 @@ ec_parse_io_ports(struct acpi_resource *resource, void *context) static const struct acpi_device_id ec_device_ids[] = { {"PNP0C09", 0}, + {ACPI_ECDT_HID, 0}, {"", 0}, }; @@ -1764,11 +1776,14 @@ static int __init acpi_ec_ecdt_start(void) * Note: ec->handle can be valid if this function is called after * acpi_ec_add(), hence the fast path. */ - if (boot_ec->handle != ACPI_ROOT_OBJECT) - handle = boot_ec->handle; - else if (!acpi_ec_ecdt_get_handle(&handle)) - return -ENODEV; - return acpi_config_boot_ec(boot_ec, handle, true, true); + if (boot_ec->handle == ACPI_ROOT_OBJECT) { + if (!acpi_ec_ecdt_get_handle(&handle)) + return -ENODEV; + boot_ec->handle = handle; + } + + /* Register to ACPI bus with PM ops attached */ + return acpi_bus_register_early_device(ACPI_BUS_TYPE_ECDT_EC); } #if 0 @@ -2022,6 +2037,12 @@ int __init acpi_ec_init(void) /* Drivers must be started after acpi_ec_query_init() */ dsdt_fail = acpi_bus_register_driver(&acpi_ec_driver); + /* + * Register ECDT to ACPI bus only when PNP0C09 probe fails. This is + * useful for platforms (confirmed on ASUS X550ZE) with valid ECDT + * settings but invalid DSDT settings. + * https://bugzilla.kernel.org/show_bug.cgi?id=196847 + */ ecdt_fail = acpi_ec_ecdt_start(); return ecdt_fail && dsdt_fail ? -ENODEV : 0; } diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c index 6c7dd7af789e..dd70d6c2bca0 100644 --- a/drivers/acpi/ec_sys.c +++ b/drivers/acpi/ec_sys.c @@ -128,7 +128,7 @@ static int acpi_ec_add_debugfs(struct acpi_ec *ec, unsigned int ec_device_count) return -ENOMEM; } - if (!debugfs_create_x32("gpe", 0444, dev_dir, (u32 *)&first_ec->gpe)) + if (!debugfs_create_x32("gpe", 0444, dev_dir, &first_ec->gpe)) goto error; if (!debugfs_create_bool("use_global_lock", 0444, dev_dir, &first_ec->global_lock)) diff --git a/drivers/acpi/evged.c b/drivers/acpi/evged.c index 46f060356a22..f13ba2c07667 100644 --- a/drivers/acpi/evged.c +++ b/drivers/acpi/evged.c @@ -49,6 +49,11 @@ #define MODULE_NAME "acpi-ged" +struct acpi_ged_device { + struct device *dev; + struct list_head event_list; +}; + struct acpi_ged_event { struct list_head node; struct device *dev; @@ -76,7 +81,8 @@ static acpi_status acpi_ged_request_interrupt(struct acpi_resource *ares, unsigned int irq; unsigned int gsi; unsigned int irqflags = IRQF_ONESHOT; - struct device *dev = context; + struct acpi_ged_device *geddev = context; + struct device *dev = geddev->dev; acpi_handle handle = ACPI_HANDLE(dev); acpi_handle evt_handle; struct resource r; @@ -102,8 +108,6 @@ static acpi_status acpi_ged_request_interrupt(struct acpi_resource *ares, return AE_ERROR; } - dev_info(dev, "GED listening GSI %u @ IRQ %u\n", gsi, irq); - event = devm_kzalloc(dev, sizeof(*event), GFP_KERNEL); if (!event) return AE_ERROR; @@ -116,29 +120,58 @@ static acpi_status acpi_ged_request_interrupt(struct acpi_resource *ares, if (r.flags & IORESOURCE_IRQ_SHAREABLE) irqflags |= IRQF_SHARED; - if (devm_request_threaded_irq(dev, irq, NULL, acpi_ged_irq_handler, - irqflags, "ACPI:Ged", event)) { + if (request_threaded_irq(irq, NULL, acpi_ged_irq_handler, + irqflags, "ACPI:Ged", event)) { dev_err(dev, "failed to setup event handler for irq %u\n", irq); return AE_ERROR; } + dev_dbg(dev, "GED listening GSI %u @ IRQ %u\n", gsi, irq); + list_add_tail(&event->node, &geddev->event_list); return AE_OK; } static int ged_probe(struct platform_device *pdev) { + struct acpi_ged_device *geddev; acpi_status acpi_ret; + geddev = devm_kzalloc(&pdev->dev, sizeof(*geddev), GFP_KERNEL); + if (!geddev) + return -ENOMEM; + + geddev->dev = &pdev->dev; + INIT_LIST_HEAD(&geddev->event_list); acpi_ret = acpi_walk_resources(ACPI_HANDLE(&pdev->dev), "_CRS", - acpi_ged_request_interrupt, &pdev->dev); + acpi_ged_request_interrupt, geddev); if (ACPI_FAILURE(acpi_ret)) { dev_err(&pdev->dev, "unable to parse the _CRS record\n"); return -EINVAL; } + platform_set_drvdata(pdev, geddev); return 0; } +static void ged_shutdown(struct platform_device *pdev) +{ + struct acpi_ged_device *geddev = platform_get_drvdata(pdev); + struct acpi_ged_event *event, *next; + + list_for_each_entry_safe(event, next, &geddev->event_list, node) { + free_irq(event->irq, event); + list_del(&event->node); + dev_dbg(geddev->dev, "GED releasing GSI %u @ IRQ %u\n", + event->gsi, event->irq); + } +} + +static int ged_remove(struct platform_device *pdev) +{ + ged_shutdown(pdev); + return 0; +} + static const struct acpi_device_id ged_acpi_ids[] = { {"ACPI0013"}, {}, @@ -146,6 +179,8 @@ static const struct acpi_device_id ged_acpi_ids[] = { static struct platform_driver ged_driver = { .probe = ged_probe, + .remove = ged_remove, + .shutdown = ged_shutdown, .driver = { .name = MODULE_NAME, .acpi_match_table = ACPI_PTR(ged_acpi_ids), diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index fc8c43e76707..1d0a501bc7f0 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -115,6 +115,7 @@ bool acpi_device_is_present(const struct acpi_device *adev); bool acpi_device_is_battery(struct acpi_device *adev); bool acpi_device_is_first_physical_node(struct acpi_device *adev, const struct device *dev); +int acpi_bus_register_early_device(int type); /* -------------------------------------------------------------------------- Device Matching and Notification @@ -158,7 +159,7 @@ static inline void acpi_early_processor_osc(void) {} -------------------------------------------------------------------------- */ struct acpi_ec { acpi_handle handle; - unsigned long gpe; + u32 gpe; unsigned long command_addr; unsigned long data_addr; bool global_lock; diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index ff2580e7611d..abeb4df4f22e 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -1670,6 +1670,11 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, dev_name(&adev_dimm->dev)); return -ENXIO; } + /* + * Record nfit_mem for the notification path to track back to + * the nfit sysfs attributes for this dimm device object. + */ + dev_set_drvdata(&adev_dimm->dev, nfit_mem); /* * Until standardization materializes we need to consider 4 @@ -1752,9 +1757,11 @@ static void shutdown_dimm_notify(void *data) sysfs_put(nfit_mem->flags_attr); nfit_mem->flags_attr = NULL; } - if (adev_dimm) + if (adev_dimm) { acpi_remove_notify_handler(adev_dimm->handle, ACPI_DEVICE_NOTIFY, acpi_nvdimm_notify); + dev_set_drvdata(&adev_dimm->dev, NULL); + } } mutex_unlock(&acpi_desc->init_mutex); } diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 917f1cc0fda4..8ccaae3550d2 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -460,8 +460,7 @@ int __init acpi_numa_init(void) srat_proc, ARRAY_SIZE(srat_proc), 0); cnt = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY, - acpi_parse_memory_affinity, - NR_NODE_MEMBLKS); + acpi_parse_memory_affinity, 0); } /* SLIT: System Locality Information Table */ diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index bc3d914dfc3e..85ad679390e3 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -612,7 +612,7 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link) acpi_isa_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING; - printk(KERN_WARNING PREFIX "%s [%s] enabled at IRQ %d\n", + pr_info("%s [%s] enabled at IRQ %d\n", acpi_device_name(link->device), acpi_device_bid(link->device), link->irq.active); } diff --git a/drivers/acpi/pmic/intel_pmic_bxtwc.c b/drivers/acpi/pmic/intel_pmic_bxtwc.c index 90011aad4d20..886ac8b93cd0 100644 --- a/drivers/acpi/pmic/intel_pmic_bxtwc.c +++ b/drivers/acpi/pmic/intel_pmic_bxtwc.c @@ -400,7 +400,7 @@ static int intel_bxtwc_pmic_opregion_probe(struct platform_device *pdev) &intel_bxtwc_pmic_opregion_data); } -static struct platform_device_id bxt_wc_opregion_id_table[] = { +static const struct platform_device_id bxt_wc_opregion_id_table[] = { { .name = "bxt_wcove_region" }, {}, }; @@ -412,9 +412,4 @@ static struct platform_driver intel_bxtwc_pmic_opregion_driver = { }, .id_table = bxt_wc_opregion_id_table, }; - -static int __init intel_bxtwc_pmic_opregion_driver_init(void) -{ - return platform_driver_register(&intel_bxtwc_pmic_opregion_driver); -} -device_initcall(intel_bxtwc_pmic_opregion_driver_init); +builtin_platform_driver(intel_bxtwc_pmic_opregion_driver); diff --git a/drivers/acpi/pmic/intel_pmic_chtdc_ti.c b/drivers/acpi/pmic/intel_pmic_chtdc_ti.c index 109c1e9c9c7a..f6d73a243d80 100644 --- a/drivers/acpi/pmic/intel_pmic_chtdc_ti.c +++ b/drivers/acpi/pmic/intel_pmic_chtdc_ti.c @@ -131,7 +131,4 @@ static struct platform_driver chtdc_ti_pmic_opregion_driver = { }, .id_table = chtdc_ti_pmic_opregion_id_table, }; -module_platform_driver(chtdc_ti_pmic_opregion_driver); - -MODULE_DESCRIPTION("Dollar Cove TI PMIC opregion driver"); -MODULE_LICENSE("GPL v2"); +builtin_platform_driver(chtdc_ti_pmic_opregion_driver); diff --git a/drivers/acpi/pmic/intel_pmic_chtwc.c b/drivers/acpi/pmic/intel_pmic_chtwc.c index 85636d7a9d39..9912422c8185 100644 --- a/drivers/acpi/pmic/intel_pmic_chtwc.c +++ b/drivers/acpi/pmic/intel_pmic_chtwc.c @@ -260,11 +260,10 @@ static int intel_cht_wc_pmic_opregion_probe(struct platform_device *pdev) &intel_cht_wc_pmic_opregion_data); } -static struct platform_device_id cht_wc_opregion_id_table[] = { +static const struct platform_device_id cht_wc_opregion_id_table[] = { { .name = "cht_wcove_region" }, {}, }; -MODULE_DEVICE_TABLE(platform, cht_wc_opregion_id_table); static struct platform_driver intel_cht_wc_pmic_opregion_driver = { .probe = intel_cht_wc_pmic_opregion_probe, @@ -273,8 +272,4 @@ static struct platform_driver intel_cht_wc_pmic_opregion_driver = { }, .id_table = cht_wc_opregion_id_table, }; -module_platform_driver(intel_cht_wc_pmic_opregion_driver); - -MODULE_DESCRIPTION("Intel CHT Whiskey Cove PMIC operation region driver"); -MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); -MODULE_LICENSE("GPL"); +builtin_platform_driver(intel_cht_wc_pmic_opregion_driver); diff --git a/drivers/acpi/pmic/intel_pmic_crc.c b/drivers/acpi/pmic/intel_pmic_crc.c index d7f1761ab1bc..7ffa74048107 100644 --- a/drivers/acpi/pmic/intel_pmic_crc.c +++ b/drivers/acpi/pmic/intel_pmic_crc.c @@ -201,9 +201,4 @@ static struct platform_driver intel_crc_pmic_opregion_driver = { .name = "crystal_cove_pmic", }, }; - -static int __init intel_crc_pmic_opregion_driver_init(void) -{ - return platform_driver_register(&intel_crc_pmic_opregion_driver); -} -device_initcall(intel_crc_pmic_opregion_driver_init); +builtin_platform_driver(intel_crc_pmic_opregion_driver); diff --git a/drivers/acpi/pmic/intel_pmic_xpower.c b/drivers/acpi/pmic/intel_pmic_xpower.c index 6c99d3f81095..316e55174aa9 100644 --- a/drivers/acpi/pmic/intel_pmic_xpower.c +++ b/drivers/acpi/pmic/intel_pmic_xpower.c @@ -278,9 +278,4 @@ static struct platform_driver intel_xpower_pmic_opregion_driver = { .name = "axp288_pmic_acpi", }, }; - -static int __init intel_xpower_pmic_opregion_driver_init(void) -{ - return platform_driver_register(&intel_xpower_pmic_opregion_driver); -} -device_initcall(intel_xpower_pmic_opregion_driver_init); +builtin_platform_driver(intel_xpower_pmic_opregion_driver); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index d50a7b6ccddd..5f0071c7e2e1 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -207,6 +207,7 @@ static void tsc_check_state(int state) switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: case X86_VENDOR_INTEL: + case X86_VENDOR_CENTAUR: /* * AMD Fam10h TSC will tick in all * C/P/S0/S1 states when this bit is set. diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index e14e964bfe6d..b0fe5272c76a 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1024,6 +1024,9 @@ static void acpi_device_get_busid(struct acpi_device *device) case ACPI_BUS_TYPE_SLEEP_BUTTON: strcpy(device->pnp.bus_id, "SLPF"); break; + case ACPI_BUS_TYPE_ECDT_EC: + strcpy(device->pnp.bus_id, "ECDT"); + break; default: acpi_get_name(device->handle, ACPI_SINGLE_NAME, &buffer); /* Clean up trailing underscores (if any) */ @@ -1304,6 +1307,9 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp, case ACPI_BUS_TYPE_SLEEP_BUTTON: acpi_add_id(pnp, ACPI_BUTTON_HID_SLEEPF); break; + case ACPI_BUS_TYPE_ECDT_EC: + acpi_add_id(pnp, ACPI_ECDT_HID); + break; } } @@ -2046,6 +2052,21 @@ void acpi_bus_trim(struct acpi_device *adev) } EXPORT_SYMBOL_GPL(acpi_bus_trim); +int acpi_bus_register_early_device(int type) +{ + struct acpi_device *device = NULL; + int result; + + result = acpi_add_single_object(&device, NULL, + type, ACPI_STA_DEFAULT); + if (result) + return result; + + device->flags.match_driver = true; + return device_attach(&device->dev); +} +EXPORT_SYMBOL_GPL(acpi_bus_register_early_device); + static int acpi_bus_scan_fixed(void) { int result = 0; diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 8082871b409a..46cde0912762 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -367,10 +367,20 @@ static const struct dmi_system_id acpisleep_dmi_table[] __initconst = { {}, }; +static bool ignore_blacklist; + +void __init acpi_sleep_no_blacklist(void) +{ + ignore_blacklist = true; +} + static void __init acpi_sleep_dmi_check(void) { int year; + if (ignore_blacklist) + return; + if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && year >= 2012) acpi_nvs_nosave_s3(); @@ -697,7 +707,8 @@ static const struct acpi_device_id lps0_device_ids[] = { #define ACPI_LPS0_ENTRY 5 #define ACPI_LPS0_EXIT 6 -#define ACPI_S2IDLE_FUNC_MASK ((1 << ACPI_LPS0_ENTRY) | (1 << ACPI_LPS0_EXIT)) +#define ACPI_LPS0_SCREEN_MASK ((1 << ACPI_LPS0_SCREEN_OFF) | (1 << ACPI_LPS0_SCREEN_ON)) +#define ACPI_LPS0_PLATFORM_MASK ((1 << ACPI_LPS0_ENTRY) | (1 << ACPI_LPS0_EXIT)) static acpi_handle lps0_device_handle; static guid_t lps0_dsm_guid; @@ -900,7 +911,8 @@ static int lps0_device_attach(struct acpi_device *adev, if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) { char bitmask = *(char *)out_obj->buffer.pointer; - if ((bitmask & ACPI_S2IDLE_FUNC_MASK) == ACPI_S2IDLE_FUNC_MASK) { + if ((bitmask & ACPI_LPS0_PLATFORM_MASK) == ACPI_LPS0_PLATFORM_MASK || + (bitmask & ACPI_LPS0_SCREEN_MASK) == ACPI_LPS0_SCREEN_MASK) { lps0_dsm_func_mask = bitmask; lps0_device_handle = adev->handle; /* diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 06a150bb35bf..4fc59c3bc673 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -816,14 +816,8 @@ end: * interface: * echo unmask > /sys/firmware/acpi/interrupts/gpe00 */ - -/* - * Currently, the GPE flooding prevention only supports to mask the GPEs - * numbered from 00 to 7f. - */ -#define ACPI_MASKABLE_GPE_MAX 0x80 - -static u64 __initdata acpi_masked_gpes; +#define ACPI_MASKABLE_GPE_MAX 0xFF +static DECLARE_BITMAP(acpi_masked_gpes_map, ACPI_MASKABLE_GPE_MAX) __initdata; static int __init acpi_gpe_set_masked_gpes(char *val) { @@ -831,7 +825,7 @@ static int __init acpi_gpe_set_masked_gpes(char *val) if (kstrtou8(val, 0, &gpe) || gpe > ACPI_MASKABLE_GPE_MAX) return -EINVAL; - acpi_masked_gpes |= ((u64)1<<gpe); + set_bit(gpe, acpi_masked_gpes_map); return 1; } @@ -843,15 +837,11 @@ void __init acpi_gpe_apply_masked_gpes(void) acpi_status status; u8 gpe; - for (gpe = 0; - gpe < min_t(u8, ACPI_MASKABLE_GPE_MAX, acpi_current_gpe_count); - gpe++) { - if (acpi_masked_gpes & ((u64)1<<gpe)) { - status = acpi_get_gpe_device(gpe, &handle); - if (ACPI_SUCCESS(status)) { - pr_info("Masking GPE 0x%x.\n", gpe); - (void)acpi_mask_gpe(handle, gpe, TRUE); - } + for_each_set_bit(gpe, acpi_masked_gpes_map, ACPI_MASKABLE_GPE_MAX) { + status = acpi_get_gpe_device(gpe, &handle); + if (ACPI_SUCCESS(status)) { + pr_info("Masking GPE 0x%x.\n", gpe); + (void)acpi_mask_gpe(handle, gpe, TRUE); } } } diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 9d49a1acebe3..78db97687f26 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -737,16 +737,17 @@ bool acpi_dev_found(const char *hid) } EXPORT_SYMBOL(acpi_dev_found); -struct acpi_dev_present_info { +struct acpi_dev_match_info { + const char *dev_name; struct acpi_device_id hid[2]; const char *uid; s64 hrv; }; -static int acpi_dev_present_cb(struct device *dev, void *data) +static int acpi_dev_match_cb(struct device *dev, void *data) { struct acpi_device *adev = to_acpi_device(dev); - struct acpi_dev_present_info *match = data; + struct acpi_dev_match_info *match = data; unsigned long long hrv; acpi_status status; @@ -757,6 +758,8 @@ static int acpi_dev_present_cb(struct device *dev, void *data) strcmp(adev->pnp.unique_id, match->uid))) return 0; + match->dev_name = acpi_dev_name(adev); + if (match->hrv == -1) return 1; @@ -789,20 +792,44 @@ static int acpi_dev_present_cb(struct device *dev, void *data) */ bool acpi_dev_present(const char *hid, const char *uid, s64 hrv) { - struct acpi_dev_present_info match = {}; + struct acpi_dev_match_info match = {}; struct device *dev; strlcpy(match.hid[0].id, hid, sizeof(match.hid[0].id)); match.uid = uid; match.hrv = hrv; - dev = bus_find_device(&acpi_bus_type, NULL, &match, - acpi_dev_present_cb); - + dev = bus_find_device(&acpi_bus_type, NULL, &match, acpi_dev_match_cb); return !!dev; } EXPORT_SYMBOL(acpi_dev_present); +/** + * acpi_dev_get_first_match_name - Return name of first match of ACPI device + * @hid: Hardware ID of the device. + * @uid: Unique ID of the device, pass NULL to not check _UID + * @hrv: Hardware Revision of the device, pass -1 to not check _HRV + * + * Return device name if a matching device was present + * at the moment of invocation, or NULL otherwise. + * + * See additional information in acpi_dev_present() as well. + */ +const char * +acpi_dev_get_first_match_name(const char *hid, const char *uid, s64 hrv) +{ + struct acpi_dev_match_info match = {}; + struct device *dev; + + strlcpy(match.hid[0].id, hid, sizeof(match.hid[0].id)); + match.uid = uid; + match.hrv = hrv; + + dev = bus_find_device(&acpi_bus_type, NULL, &match, acpi_dev_match_cb); + return dev ? match.dev_name : NULL; +} +EXPORT_SYMBOL(acpi_dev_get_first_match_name); + /* * acpi_backlight= handling, this is done here rather then in video_detect.c * because __setup cannot be used in modules. diff --git a/drivers/android/binder.c b/drivers/android/binder.c index a73596a4f804..a7ecfde66b7b 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -482,7 +482,8 @@ enum binder_deferred_state { * @tsk task_struct for group_leader of process * (invariant after initialized) * @files files_struct for process - * (invariant after initialized) + * (protected by @files_lock) + * @files_lock mutex to protect @files * @deferred_work_node: element for binder_deferred_list * (protected by binder_deferred_lock) * @deferred_work: bitmap of deferred work to perform @@ -530,6 +531,7 @@ struct binder_proc { int pid; struct task_struct *tsk; struct files_struct *files; + struct mutex files_lock; struct hlist_node deferred_work_node; int deferred_work; bool is_dead; @@ -877,20 +879,26 @@ static void binder_inc_node_tmpref_ilocked(struct binder_node *node); static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) { - struct files_struct *files = proc->files; unsigned long rlim_cur; unsigned long irqs; + int ret; - if (files == NULL) - return -ESRCH; - - if (!lock_task_sighand(proc->tsk, &irqs)) - return -EMFILE; - + mutex_lock(&proc->files_lock); + if (proc->files == NULL) { + ret = -ESRCH; + goto err; + } + if (!lock_task_sighand(proc->tsk, &irqs)) { + ret = -EMFILE; + goto err; + } rlim_cur = task_rlimit(proc->tsk, RLIMIT_NOFILE); unlock_task_sighand(proc->tsk, &irqs); - return __alloc_fd(files, 0, rlim_cur, flags); + ret = __alloc_fd(proc->files, 0, rlim_cur, flags); +err: + mutex_unlock(&proc->files_lock); + return ret; } /* @@ -899,8 +907,10 @@ static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) static void task_fd_install( struct binder_proc *proc, unsigned int fd, struct file *file) { + mutex_lock(&proc->files_lock); if (proc->files) __fd_install(proc->files, fd, file); + mutex_unlock(&proc->files_lock); } /* @@ -910,9 +920,11 @@ static long task_close_fd(struct binder_proc *proc, unsigned int fd) { int retval; - if (proc->files == NULL) - return -ESRCH; - + mutex_lock(&proc->files_lock); + if (proc->files == NULL) { + retval = -ESRCH; + goto err; + } retval = __close_fd(proc->files, fd); /* can't restart close syscall because file table entry was cleared */ if (unlikely(retval == -ERESTARTSYS || @@ -920,7 +932,8 @@ static long task_close_fd(struct binder_proc *proc, unsigned int fd) retval == -ERESTARTNOHAND || retval == -ERESTART_RESTARTBLOCK)) retval = -EINTR; - +err: + mutex_unlock(&proc->files_lock); return retval; } @@ -1948,6 +1961,26 @@ static void binder_send_failed_reply(struct binder_transaction *t, } /** + * binder_cleanup_transaction() - cleans up undelivered transaction + * @t: transaction that needs to be cleaned up + * @reason: reason the transaction wasn't delivered + * @error_code: error to return to caller (if synchronous call) + */ +static void binder_cleanup_transaction(struct binder_transaction *t, + const char *reason, + uint32_t error_code) +{ + if (t->buffer->target_node && !(t->flags & TF_ONE_WAY)) { + binder_send_failed_reply(t, error_code); + } else { + binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, + "undelivered transaction %d, %s\n", + t->debug_id, reason); + binder_free_transaction(t); + } +} + +/** * binder_validate_object() - checks for a valid metadata object in a buffer. * @buffer: binder_buffer that we're parsing. * @offset: offset in the buffer at which to validate an object. @@ -4015,12 +4048,20 @@ retry: if (put_user(cmd, (uint32_t __user *)ptr)) { if (t_from) binder_thread_dec_tmpref(t_from); + + binder_cleanup_transaction(t, "put_user failed", + BR_FAILED_REPLY); + return -EFAULT; } ptr += sizeof(uint32_t); if (copy_to_user(ptr, &tr, sizeof(tr))) { if (t_from) binder_thread_dec_tmpref(t_from); + + binder_cleanup_transaction(t, "copy_to_user failed", + BR_FAILED_REPLY); + return -EFAULT; } ptr += sizeof(tr); @@ -4090,15 +4131,9 @@ static void binder_release_work(struct binder_proc *proc, struct binder_transaction *t; t = container_of(w, struct binder_transaction, work); - if (t->buffer->target_node && - !(t->flags & TF_ONE_WAY)) { - binder_send_failed_reply(t, BR_DEAD_REPLY); - } else { - binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, - "undelivered transaction %d\n", - t->debug_id); - binder_free_transaction(t); - } + + binder_cleanup_transaction(t, "process died.", + BR_DEAD_REPLY); } break; case BINDER_WORK_RETURN_ERROR: { struct binder_error *e = container_of( @@ -4605,7 +4640,9 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) ret = binder_alloc_mmap_handler(&proc->alloc, vma); if (ret) return ret; + mutex_lock(&proc->files_lock); proc->files = get_files_struct(current); + mutex_unlock(&proc->files_lock); return 0; err_bad_arg: @@ -4629,6 +4666,7 @@ static int binder_open(struct inode *nodp, struct file *filp) spin_lock_init(&proc->outer_lock); get_task_struct(current->group_leader); proc->tsk = current->group_leader; + mutex_init(&proc->files_lock); INIT_LIST_HEAD(&proc->todo); proc->default_priority = task_nice(current); binder_dev = container_of(filp->private_data, struct binder_device, @@ -4881,9 +4919,11 @@ static void binder_deferred_func(struct work_struct *work) files = NULL; if (defer & BINDER_DEFERRED_PUT_FILES) { + mutex_lock(&proc->files_lock); files = proc->files; if (files) proc->files = NULL; + mutex_unlock(&proc->files_lock); } if (defer & BINDER_DEFERRED_FLUSH) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 8193b38a1cae..3c09122bf038 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4449,6 +4449,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { * https://bugzilla.kernel.org/show_bug.cgi?id=121671 */ { "LITEON CX1-JB*-HP", NULL, ATA_HORKAGE_MAX_SEC_1024 }, + { "LITEON EP1-*", NULL, ATA_HORKAGE_MAX_SEC_1024 }, /* Devices we expect to fail diagnostics */ diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c index dd286ad404f8..9287ec958b70 100644 --- a/drivers/atm/ambassador.c +++ b/drivers/atm/ambassador.c @@ -2258,7 +2258,7 @@ static int amb_probe(struct pci_dev *pci_dev, PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p", dev->atm_dev->number, dev, dev->atm_dev); - dev->atm_dev->dev_data = (void *) dev; + dev->atm_dev->dev_data = (void *) dev; // register our address amb_esi (dev, dev->atm_dev->esi); diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 126855e6cb7d..6ebc4e4820fc 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -3083,8 +3083,8 @@ fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page) ASSERT(fore200e_vcc); len = sprintf(page, - " %08x %03d %05d %1d %09lu %05d/%05d %09lu %05d/%05d\n", - (u32)(unsigned long)vcc, + " %pK %03d %05d %1d %09lu %05d/%05d %09lu %05d/%05d\n", + vcc, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), fore200e_vcc->tx_pdu, fore200e_vcc->tx_min_pdu > 0xFFFF ? 0 : fore200e_vcc->tx_min_pdu, diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c index 6664aa50789e..5f8e009b2da1 100644 --- a/drivers/atm/lanai.c +++ b/drivers/atm/lanai.c @@ -1586,8 +1586,8 @@ static int service_buffer_allocate(struct lanai_dev *lanai) lanai->pci); if (unlikely(lanai->service.start == NULL)) return -ENOMEM; - DPRINTK("allocated service buffer at 0x%08lX, size %zu(%d)\n", - (unsigned long) lanai->service.start, + DPRINTK("allocated service buffer at %p, size %zu(%d)\n", + lanai->service.start, lanai_buf_size(&lanai->service), lanai_buf_size_cardorder(&lanai->service)); /* Clear ServWrite register to be safe */ @@ -2218,9 +2218,9 @@ static int lanai_dev_open(struct atm_dev *atmdev) #endif memcpy(atmdev->esi, eeprom_mac(lanai), ESI_LEN); lanai_timed_poll_start(lanai); - printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d, base=0x%lx, irq=%u " + printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d, base=%p, irq=%u " "(%pMF)\n", lanai->number, (int) lanai->pci->revision, - (unsigned long) lanai->base, lanai->pci->irq, atmdev->esi); + lanai->base, lanai->pci->irq, atmdev->esi); printk(KERN_NOTICE DEV_LABEL "(itf %d): LANAI%s, serialno=%u(0x%X), " "board_rev=%d\n", lanai->number, lanai->type==lanai2 ? "2" : "HB", (unsigned int) lanai->serialno, diff --git a/drivers/atm/suni.c b/drivers/atm/suni.c index b8825f2d79e0..4b044710a8cf 100644 --- a/drivers/atm/suni.c +++ b/drivers/atm/suni.c @@ -177,7 +177,7 @@ static int set_loopback(struct atm_dev *dev,int mode) default: return -EINVAL; } - dev->ops->phy_put(dev, control, reg); + dev->ops->phy_put(dev, control, reg); PRIV(dev)->loop_mode = mode; return 0; } diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig index d7d21118d3e0..2c2ed9cf8796 100644 --- a/drivers/auxdisplay/Kconfig +++ b/drivers/auxdisplay/Kconfig @@ -136,6 +136,7 @@ config CFAG12864B_RATE config IMG_ASCII_LCD tristate "Imagination Technologies ASCII LCD Display" + depends on HAS_IOMEM default y if MIPS_MALTA || MIPS_SEAD3 select SYSCON help diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 2f6614c9a229..2415ad9f6dd4 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -91,22 +91,23 @@ config FIRMWARE_IN_KERNEL depends on FW_LOADER default y help - The kernel source tree includes a number of firmware 'blobs' - that are used by various drivers. The recommended way to - use these is to run "make firmware_install", which, after - converting ihex files to binary, copies all of the needed - binary files in firmware/ to /lib/firmware/ on your system so - that they can be loaded by userspace helpers on request. + Various drivers in the kernel source tree may require firmware, + which is generally available in your distribution's linux-firmware + package. + + The linux-firmware package should install firmware into + /lib/firmware/ on your system, so they can be loaded by userspace + helpers on request. Enabling this option will build each required firmware blob - into the kernel directly, where request_firmware() will find - them without having to call out to userspace. This may be - useful if your root file system requires a device that uses - such firmware and do not wish to use an initrd. + specified by EXTRA_FIRMWARE into the kernel directly, where + request_firmware() will find them without having to call out to + userspace. This may be useful if your root file system requires a + device that uses such firmware and you do not wish to use an + initrd. This single option controls the inclusion of firmware for - every driver that uses request_firmware() and ships its - firmware in the kernel source tree, which avoids a + every driver that uses request_firmware(), which avoids a proliferation of 'Include firmware for xxx device' options. Say 'N' and let firmware be loaded from userspace. @@ -235,6 +236,9 @@ config GENERIC_CPU_DEVICES config GENERIC_CPU_AUTOPROBE bool +config GENERIC_CPU_VULNERABILITIES + bool + config SOC_BUS bool select GLOB diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index eb3af2739537..07532d83be0b 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -186,6 +186,11 @@ static void cache_associativity(struct cacheinfo *this_leaf) this_leaf->ways_of_associativity = (size / nr_sets) / line_size; } +static bool cache_node_is_unified(struct cacheinfo *this_leaf) +{ + return of_property_read_bool(this_leaf->of_node, "cache-unified"); +} + static void cache_of_override_properties(unsigned int cpu) { int index; @@ -194,6 +199,14 @@ static void cache_of_override_properties(unsigned int cpu) for (index = 0; index < cache_leaves(cpu); index++) { this_leaf = this_cpu_ci->info_list + index; + /* + * init_cache_level must setup the cache level correctly + * overriding the architecturally specified levels, so + * if type is NONE at this stage, it should be unified + */ + if (this_leaf->type == CACHE_TYPE_NOCACHE && + cache_node_is_unified(this_leaf)) + this_leaf->type = CACHE_TYPE_UNIFIED; cache_size(this_leaf); cache_get_line_size(this_leaf); cache_nr_sets(this_leaf); diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 58a9b608d821..d99038487a0d 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -511,10 +511,58 @@ static void __init cpu_dev_register_generic(void) #endif } +#ifdef CONFIG_GENERIC_CPU_VULNERABILITIES + +ssize_t __weak cpu_show_meltdown(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "Not affected\n"); +} + +ssize_t __weak cpu_show_spectre_v1(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "Not affected\n"); +} + +ssize_t __weak cpu_show_spectre_v2(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "Not affected\n"); +} + +static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL); +static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL); +static DEVICE_ATTR(spectre_v2, 0444, cpu_show_spectre_v2, NULL); + +static struct attribute *cpu_root_vulnerabilities_attrs[] = { + &dev_attr_meltdown.attr, + &dev_attr_spectre_v1.attr, + &dev_attr_spectre_v2.attr, + NULL +}; + +static const struct attribute_group cpu_root_vulnerabilities_group = { + .name = "vulnerabilities", + .attrs = cpu_root_vulnerabilities_attrs, +}; + +static void __init cpu_register_vulnerabilities(void) +{ + if (sysfs_create_group(&cpu_subsys.dev_root->kobj, + &cpu_root_vulnerabilities_group)) + pr_err("Unable to register CPU vulnerabilities\n"); +} + +#else +static inline void cpu_register_vulnerabilities(void) { } +#endif + void __init cpu_dev_init(void) { if (subsys_system_register(&cpu_subsys, cpu_root_attr_groups)) panic("Failed to register CPU subsystem"); cpu_dev_register_generic(); + cpu_register_vulnerabilities(); } diff --git a/drivers/base/isa.c b/drivers/base/isa.c index cd6ccdcf9df0..372d10af2600 100644 --- a/drivers/base/isa.c +++ b/drivers/base/isa.c @@ -39,7 +39,7 @@ static int isa_bus_probe(struct device *dev) { struct isa_driver *isa_driver = dev->platform_data; - if (isa_driver->probe) + if (isa_driver && isa_driver->probe) return isa_driver->probe(dev, to_isa_dev(dev)->id); return 0; @@ -49,7 +49,7 @@ static int isa_bus_remove(struct device *dev) { struct isa_driver *isa_driver = dev->platform_data; - if (isa_driver->remove) + if (isa_driver && isa_driver->remove) return isa_driver->remove(dev, to_isa_dev(dev)->id); return 0; @@ -59,7 +59,7 @@ static void isa_bus_shutdown(struct device *dev) { struct isa_driver *isa_driver = dev->platform_data; - if (isa_driver->shutdown) + if (isa_driver && isa_driver->shutdown) isa_driver->shutdown(dev, to_isa_dev(dev)->id); } @@ -67,7 +67,7 @@ static int isa_bus_suspend(struct device *dev, pm_message_t state) { struct isa_driver *isa_driver = dev->platform_data; - if (isa_driver->suspend) + if (isa_driver && isa_driver->suspend) return isa_driver->suspend(dev, to_isa_dev(dev)->id, state); return 0; @@ -77,7 +77,7 @@ static int isa_bus_resume(struct device *dev) { struct isa_driver *isa_driver = dev->platform_data; - if (isa_driver->resume) + if (isa_driver && isa_driver->resume) return isa_driver->resume(dev, to_isa_dev(dev)->id); return 0; diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 1d60b58a8c19..fe4b24f05f6a 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -569,7 +569,7 @@ store_hard_offline_page(struct device *dev, if (kstrtoull(buf, 0, &pfn) < 0) return -EINVAL; pfn >>= PAGE_SHIFT; - ret = memory_failure(pfn, 0, 0); + ret = memory_failure(pfn, 0); return ret ? ret : count; } diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 0c80bea05bcb..528b24149bc7 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1032,15 +1032,12 @@ static int genpd_prepare(struct device *dev) static int genpd_finish_suspend(struct device *dev, bool poweroff) { struct generic_pm_domain *genpd; - int ret; + int ret = 0; genpd = dev_to_genpd(dev); if (IS_ERR(genpd)) return -EINVAL; - if (dev->power.wakeup_path && genpd_is_active_wakeup(genpd)) - return 0; - if (poweroff) ret = pm_generic_poweroff_noirq(dev); else @@ -1048,10 +1045,19 @@ static int genpd_finish_suspend(struct device *dev, bool poweroff) if (ret) return ret; - if (genpd->dev_ops.stop && genpd->dev_ops.start) { - ret = pm_runtime_force_suspend(dev); - if (ret) + if (dev->power.wakeup_path && genpd_is_active_wakeup(genpd)) + return 0; + + if (genpd->dev_ops.stop && genpd->dev_ops.start && + !pm_runtime_status_suspended(dev)) { + ret = genpd_stop_dev(genpd, dev); + if (ret) { + if (poweroff) + pm_generic_restore_noirq(dev); + else + pm_generic_resume_noirq(dev); return ret; + } } genpd_lock(genpd); @@ -1085,7 +1091,7 @@ static int genpd_suspend_noirq(struct device *dev) static int genpd_resume_noirq(struct device *dev) { struct generic_pm_domain *genpd; - int ret = 0; + int ret; dev_dbg(dev, "%s()\n", __func__); @@ -1094,21 +1100,21 @@ static int genpd_resume_noirq(struct device *dev) return -EINVAL; if (dev->power.wakeup_path && genpd_is_active_wakeup(genpd)) - return 0; + return pm_generic_resume_noirq(dev); genpd_lock(genpd); genpd_sync_power_on(genpd, true, 0); genpd->suspended_count--; genpd_unlock(genpd); - if (genpd->dev_ops.stop && genpd->dev_ops.start) - ret = pm_runtime_force_resume(dev); - - ret = pm_generic_resume_noirq(dev); - if (ret) - return ret; + if (genpd->dev_ops.stop && genpd->dev_ops.start && + !pm_runtime_status_suspended(dev)) { + ret = genpd_start_dev(genpd, dev); + if (ret) + return ret; + } - return ret; + return pm_generic_resume_noirq(dev); } /** @@ -1135,8 +1141,9 @@ static int genpd_freeze_noirq(struct device *dev) if (ret) return ret; - if (genpd->dev_ops.stop && genpd->dev_ops.start) - ret = pm_runtime_force_suspend(dev); + if (genpd->dev_ops.stop && genpd->dev_ops.start && + !pm_runtime_status_suspended(dev)) + ret = genpd_stop_dev(genpd, dev); return ret; } @@ -1159,8 +1166,9 @@ static int genpd_thaw_noirq(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - if (genpd->dev_ops.stop && genpd->dev_ops.start) { - ret = pm_runtime_force_resume(dev); + if (genpd->dev_ops.stop && genpd->dev_ops.start && + !pm_runtime_status_suspended(dev)) { + ret = genpd_start_dev(genpd, dev); if (ret) return ret; } @@ -1217,8 +1225,9 @@ static int genpd_restore_noirq(struct device *dev) genpd_sync_power_on(genpd, true, 0); genpd_unlock(genpd); - if (genpd->dev_ops.stop && genpd->dev_ops.start) { - ret = pm_runtime_force_resume(dev); + if (genpd->dev_ops.stop && genpd->dev_ops.start && + !pm_runtime_status_suspended(dev)) { + ret = genpd_start_dev(genpd, dev); if (ret) return ret; } @@ -2199,20 +2208,8 @@ int genpd_dev_pm_attach(struct device *dev) ret = of_parse_phandle_with_args(dev->of_node, "power-domains", "#power-domain-cells", 0, &pd_args); - if (ret < 0) { - if (ret != -ENOENT) - return ret; - - /* - * Try legacy Samsung-specific bindings - * (for backwards compatibility of DT ABI) - */ - pd_args.args_count = 0; - pd_args.np = of_parse_phandle(dev->of_node, - "samsung,power-domain", 0); - if (!pd_args.np) - return -ENOENT; - } + if (ret < 0) + return ret; mutex_lock(&gpd_list_lock); pd = genpd_get_from_provider(&pd_args); diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index db2f04415927..02a497e7c785 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -18,7 +18,6 @@ */ #include <linux/device.h> -#include <linux/kallsyms.h> #include <linux/export.h> #include <linux/mutex.h> #include <linux/pm.h> @@ -526,6 +525,88 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd) /*------------------------- Resume routines -------------------------*/ /** + * dev_pm_skip_next_resume_phases - Skip next system resume phases for device. + * @dev: Target device. + * + * Make the core skip the "early resume" and "resume" phases for @dev. + * + * This function can be called by middle-layer code during the "noirq" phase of + * system resume if necessary, but not by device drivers. + */ +void dev_pm_skip_next_resume_phases(struct device *dev) +{ + dev->power.is_late_suspended = false; + dev->power.is_suspended = false; +} + +/** + * suspend_event - Return a "suspend" message for given "resume" one. + * @resume_msg: PM message representing a system-wide resume transition. + */ +static pm_message_t suspend_event(pm_message_t resume_msg) +{ + switch (resume_msg.event) { + case PM_EVENT_RESUME: + return PMSG_SUSPEND; + case PM_EVENT_THAW: + case PM_EVENT_RESTORE: + return PMSG_FREEZE; + case PM_EVENT_RECOVER: + return PMSG_HIBERNATE; + } + return PMSG_ON; +} + +/** + * dev_pm_may_skip_resume - System-wide device resume optimization check. + * @dev: Target device. + * + * Checks whether or not the device may be left in suspend after a system-wide + * transition to the working state. + */ +bool dev_pm_may_skip_resume(struct device *dev) +{ + return !dev->power.must_resume && pm_transition.event != PM_EVENT_RESTORE; +} + +static pm_callback_t dpm_subsys_resume_noirq_cb(struct device *dev, + pm_message_t state, + const char **info_p) +{ + pm_callback_t callback; + const char *info; + + if (dev->pm_domain) { + info = "noirq power domain "; + callback = pm_noirq_op(&dev->pm_domain->ops, state); + } else if (dev->type && dev->type->pm) { + info = "noirq type "; + callback = pm_noirq_op(dev->type->pm, state); + } else if (dev->class && dev->class->pm) { + info = "noirq class "; + callback = pm_noirq_op(dev->class->pm, state); + } else if (dev->bus && dev->bus->pm) { + info = "noirq bus "; + callback = pm_noirq_op(dev->bus->pm, state); + } else { + return NULL; + } + + if (info_p) + *info_p = info; + + return callback; +} + +static pm_callback_t dpm_subsys_suspend_noirq_cb(struct device *dev, + pm_message_t state, + const char **info_p); + +static pm_callback_t dpm_subsys_suspend_late_cb(struct device *dev, + pm_message_t state, + const char **info_p); + +/** * device_resume_noirq - Execute a "noirq resume" callback for given device. * @dev: Device to handle. * @state: PM transition of the system being carried out. @@ -536,8 +617,9 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd) */ static int device_resume_noirq(struct device *dev, pm_message_t state, bool async) { - pm_callback_t callback = NULL; - const char *info = NULL; + pm_callback_t callback; + const char *info; + bool skip_resume; int error = 0; TRACE_DEVICE(dev); @@ -551,29 +633,61 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn dpm_wait_for_superior(dev, async); - if (dev->pm_domain) { - info = "noirq power domain "; - callback = pm_noirq_op(&dev->pm_domain->ops, state); - } else if (dev->type && dev->type->pm) { - info = "noirq type "; - callback = pm_noirq_op(dev->type->pm, state); - } else if (dev->class && dev->class->pm) { - info = "noirq class "; - callback = pm_noirq_op(dev->class->pm, state); - } else if (dev->bus && dev->bus->pm) { - info = "noirq bus "; - callback = pm_noirq_op(dev->bus->pm, state); + skip_resume = dev_pm_may_skip_resume(dev); + + callback = dpm_subsys_resume_noirq_cb(dev, state, &info); + if (callback) + goto Run; + + if (skip_resume) + goto Skip; + + if (dev_pm_smart_suspend_and_suspended(dev)) { + pm_message_t suspend_msg = suspend_event(state); + + /* + * If "freeze" callbacks have been skipped during a transition + * related to hibernation, the subsequent "thaw" callbacks must + * be skipped too or bad things may happen. Otherwise, resume + * callbacks are going to be run for the device, so its runtime + * PM status must be changed to reflect the new state after the + * transition under way. + */ + if (!dpm_subsys_suspend_late_cb(dev, suspend_msg, NULL) && + !dpm_subsys_suspend_noirq_cb(dev, suspend_msg, NULL)) { + if (state.event == PM_EVENT_THAW) { + skip_resume = true; + goto Skip; + } else { + pm_runtime_set_active(dev); + } + } } - if (!callback && dev->driver && dev->driver->pm) { + if (dev->driver && dev->driver->pm) { info = "noirq driver "; callback = pm_noirq_op(dev->driver->pm, state); } +Run: error = dpm_run_callback(callback, dev, state, info); + +Skip: dev->power.is_noirq_suspended = false; - Out: + if (skip_resume) { + /* + * The device is going to be left in suspend, but it might not + * have been in runtime suspend before the system suspended, so + * its runtime PM status needs to be updated to avoid confusing + * the runtime PM framework when runtime PM is enabled for the + * device again. + */ + pm_runtime_set_suspended(dev); + dev_pm_skip_next_resume_phases(dev); + } + +Out: complete_all(&dev->power.completion); TRACE_RESUME(error); return error; @@ -666,6 +780,35 @@ void dpm_resume_noirq(pm_message_t state) dpm_noirq_end(); } +static pm_callback_t dpm_subsys_resume_early_cb(struct device *dev, + pm_message_t state, + const char **info_p) +{ + pm_callback_t callback; + const char *info; + + if (dev->pm_domain) { + info = "early power domain "; + callback = pm_late_early_op(&dev->pm_domain->ops, state); + } else if (dev->type && dev->type->pm) { + info = "early type "; + callback = pm_late_early_op(dev->type->pm, state); + } else if (dev->class && dev->class->pm) { + info = "early class "; + callback = pm_late_early_op(dev->class->pm, state); + } else if (dev->bus && dev->bus->pm) { + info = "early bus "; + callback = pm_late_early_op(dev->bus->pm, state); + } else { + return NULL; + } + + if (info_p) + *info_p = info; + + return callback; +} + /** * device_resume_early - Execute an "early resume" callback for given device. * @dev: Device to handle. @@ -676,8 +819,8 @@ void dpm_resume_noirq(pm_message_t state) */ static int device_resume_early(struct device *dev, pm_message_t state, bool async) { - pm_callback_t callback = NULL; - const char *info = NULL; + pm_callback_t callback; + const char *info; int error = 0; TRACE_DEVICE(dev); @@ -691,19 +834,7 @@ static int device_resume_early(struct device *dev, pm_message_t state, bool asyn dpm_wait_for_superior(dev, async); - if (dev->pm_domain) { - info = "early power domain "; - callback = pm_late_early_op(&dev->pm_domain->ops, state); - } else if (dev->type && dev->type->pm) { - info = "early type "; - callback = pm_late_early_op(dev->type->pm, state); - } else if (dev->class && dev->class->pm) { - info = "early class "; - callback = pm_late_early_op(dev->class->pm, state); - } else if (dev->bus && dev->bus->pm) { - info = "early bus "; - callback = pm_late_early_op(dev->bus->pm, state); - } + callback = dpm_subsys_resume_early_cb(dev, state, &info); if (!callback && dev->driver && dev->driver->pm) { info = "early driver "; @@ -1074,6 +1205,77 @@ static pm_message_t resume_event(pm_message_t sleep_state) return PMSG_ON; } +static void dpm_superior_set_must_resume(struct device *dev) +{ + struct device_link *link; + int idx; + + if (dev->parent) + dev->parent->power.must_resume = true; + + idx = device_links_read_lock(); + + list_for_each_entry_rcu(link, &dev->links.suppliers, c_node) + link->supplier->power.must_resume = true; + + device_links_read_unlock(idx); +} + +static pm_callback_t dpm_subsys_suspend_noirq_cb(struct device *dev, + pm_message_t state, + const char **info_p) +{ + pm_callback_t callback; + const char *info; + + if (dev->pm_domain) { + info = "noirq power domain "; + callback = pm_noirq_op(&dev->pm_domain->ops, state); + } else if (dev->type && dev->type->pm) { + info = "noirq type "; + callback = pm_noirq_op(dev->type->pm, state); + } else if (dev->class && dev->class->pm) { + info = "noirq class "; + callback = pm_noirq_op(dev->class->pm, state); + } else if (dev->bus && dev->bus->pm) { + info = "noirq bus "; + callback = pm_noirq_op(dev->bus->pm, state); + } else { + return NULL; + } + + if (info_p) + *info_p = info; + + return callback; +} + +static bool device_must_resume(struct device *dev, pm_message_t state, + bool no_subsys_suspend_noirq) +{ + pm_message_t resume_msg = resume_event(state); + + /* + * If all of the device driver's "noirq", "late" and "early" callbacks + * are invoked directly by the core, the decision to allow the device to + * stay in suspend can be based on its current runtime PM status and its + * wakeup settings. + */ + if (no_subsys_suspend_noirq && + !dpm_subsys_suspend_late_cb(dev, state, NULL) && + !dpm_subsys_resume_early_cb(dev, resume_msg, NULL) && + !dpm_subsys_resume_noirq_cb(dev, resume_msg, NULL)) + return !pm_runtime_status_suspended(dev) && + (resume_msg.event != PM_EVENT_RESUME || + (device_can_wakeup(dev) && !device_may_wakeup(dev))); + + /* + * The only safe strategy here is to require that if the device may not + * be left in suspend, resume callbacks must be invoked for it. + */ + return !dev->power.may_skip_resume; +} + /** * __device_suspend_noirq - Execute a "noirq suspend" callback for given device. * @dev: Device to handle. @@ -1085,8 +1287,9 @@ static pm_message_t resume_event(pm_message_t sleep_state) */ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool async) { - pm_callback_t callback = NULL; - const char *info = NULL; + pm_callback_t callback; + const char *info; + bool no_subsys_cb = false; int error = 0; TRACE_DEVICE(dev); @@ -1105,30 +1308,40 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a if (dev->power.syscore || dev->power.direct_complete) goto Complete; - if (dev->pm_domain) { - info = "noirq power domain "; - callback = pm_noirq_op(&dev->pm_domain->ops, state); - } else if (dev->type && dev->type->pm) { - info = "noirq type "; - callback = pm_noirq_op(dev->type->pm, state); - } else if (dev->class && dev->class->pm) { - info = "noirq class "; - callback = pm_noirq_op(dev->class->pm, state); - } else if (dev->bus && dev->bus->pm) { - info = "noirq bus "; - callback = pm_noirq_op(dev->bus->pm, state); - } + callback = dpm_subsys_suspend_noirq_cb(dev, state, &info); + if (callback) + goto Run; - if (!callback && dev->driver && dev->driver->pm) { + no_subsys_cb = !dpm_subsys_suspend_late_cb(dev, state, NULL); + + if (dev_pm_smart_suspend_and_suspended(dev) && no_subsys_cb) + goto Skip; + + if (dev->driver && dev->driver->pm) { info = "noirq driver "; callback = pm_noirq_op(dev->driver->pm, state); } +Run: error = dpm_run_callback(callback, dev, state, info); - if (!error) - dev->power.is_noirq_suspended = true; - else + if (error) { async_error = error; + goto Complete; + } + +Skip: + dev->power.is_noirq_suspended = true; + + if (dev_pm_test_driver_flags(dev, DPM_FLAG_LEAVE_SUSPENDED)) { + dev->power.must_resume = dev->power.must_resume || + atomic_read(&dev->power.usage_count) > 1 || + device_must_resume(dev, state, no_subsys_cb); + } else { + dev->power.must_resume = true; + } + + if (dev->power.must_resume) + dpm_superior_set_must_resume(dev); Complete: complete_all(&dev->power.completion); @@ -1234,6 +1447,50 @@ int dpm_suspend_noirq(pm_message_t state) return ret; } +static void dpm_propagate_wakeup_to_parent(struct device *dev) +{ + struct device *parent = dev->parent; + + if (!parent) + return; + + spin_lock_irq(&parent->power.lock); + + if (dev->power.wakeup_path && !parent->power.ignore_children) + parent->power.wakeup_path = true; + + spin_unlock_irq(&parent->power.lock); +} + +static pm_callback_t dpm_subsys_suspend_late_cb(struct device *dev, + pm_message_t state, + const char **info_p) +{ + pm_callback_t callback; + const char *info; + + if (dev->pm_domain) { + info = "late power domain "; + callback = pm_late_early_op(&dev->pm_domain->ops, state); + } else if (dev->type && dev->type->pm) { + info = "late type "; + callback = pm_late_early_op(dev->type->pm, state); + } else if (dev->class && dev->class->pm) { + info = "late class "; + callback = pm_late_early_op(dev->class->pm, state); + } else if (dev->bus && dev->bus->pm) { + info = "late bus "; + callback = pm_late_early_op(dev->bus->pm, state); + } else { + return NULL; + } + + if (info_p) + *info_p = info; + + return callback; +} + /** * __device_suspend_late - Execute a "late suspend" callback for given device. * @dev: Device to handle. @@ -1244,8 +1501,8 @@ int dpm_suspend_noirq(pm_message_t state) */ static int __device_suspend_late(struct device *dev, pm_message_t state, bool async) { - pm_callback_t callback = NULL; - const char *info = NULL; + pm_callback_t callback; + const char *info; int error = 0; TRACE_DEVICE(dev); @@ -1266,30 +1523,29 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as if (dev->power.syscore || dev->power.direct_complete) goto Complete; - if (dev->pm_domain) { - info = "late power domain "; - callback = pm_late_early_op(&dev->pm_domain->ops, state); - } else if (dev->type && dev->type->pm) { - info = "late type "; - callback = pm_late_early_op(dev->type->pm, state); - } else if (dev->class && dev->class->pm) { - info = "late class "; - callback = pm_late_early_op(dev->class->pm, state); - } else if (dev->bus && dev->bus->pm) { - info = "late bus "; - callback = pm_late_early_op(dev->bus->pm, state); - } + callback = dpm_subsys_suspend_late_cb(dev, state, &info); + if (callback) + goto Run; - if (!callback && dev->driver && dev->driver->pm) { + if (dev_pm_smart_suspend_and_suspended(dev) && + !dpm_subsys_suspend_noirq_cb(dev, state, NULL)) + goto Skip; + + if (dev->driver && dev->driver->pm) { info = "late driver "; callback = pm_late_early_op(dev->driver->pm, state); } +Run: error = dpm_run_callback(callback, dev, state, info); - if (!error) - dev->power.is_late_suspended = true; - else + if (error) { async_error = error; + goto Complete; + } + dpm_propagate_wakeup_to_parent(dev); + +Skip: + dev->power.is_late_suspended = true; Complete: TRACE_SUSPEND(error); @@ -1420,11 +1676,17 @@ static int legacy_suspend(struct device *dev, pm_message_t state, return error; } -static void dpm_clear_suppliers_direct_complete(struct device *dev) +static void dpm_clear_superiors_direct_complete(struct device *dev) { struct device_link *link; int idx; + if (dev->parent) { + spin_lock_irq(&dev->parent->power.lock); + dev->parent->power.direct_complete = false; + spin_unlock_irq(&dev->parent->power.lock); + } + idx = device_links_read_lock(); list_for_each_entry_rcu(link, &dev->links.suppliers, c_node) { @@ -1485,6 +1747,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) dev->power.direct_complete = false; } + dev->power.may_skip_resume = false; + dev->power.must_resume = false; + dpm_watchdog_set(&wd, dev); device_lock(dev); @@ -1528,20 +1793,12 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) End: if (!error) { - struct device *parent = dev->parent; - dev->power.is_suspended = true; - if (parent) { - spin_lock_irq(&parent->power.lock); - - dev->parent->power.direct_complete = false; - if (dev->power.wakeup_path - && !dev->parent->power.ignore_children) - dev->parent->power.wakeup_path = true; + if (device_may_wakeup(dev)) + dev->power.wakeup_path = true; - spin_unlock_irq(&parent->power.lock); - } - dpm_clear_suppliers_direct_complete(dev); + dpm_propagate_wakeup_to_parent(dev); + dpm_clear_superiors_direct_complete(dev); } device_unlock(dev); @@ -1650,8 +1907,9 @@ static int device_prepare(struct device *dev, pm_message_t state) if (dev->power.syscore) return 0; - WARN_ON(dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) && - !pm_runtime_enabled(dev)); + WARN_ON(!pm_runtime_enabled(dev) && + dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND | + DPM_FLAG_LEAVE_SUSPENDED)); /* * If a device's parent goes into runtime suspend at the wrong time, @@ -1663,7 +1921,7 @@ static int device_prepare(struct device *dev, pm_message_t state) device_lock(dev); - dev->power.wakeup_path = device_may_wakeup(dev); + dev->power.wakeup_path = false; if (dev->power.no_pm_callbacks) { ret = 1; /* Let device go direct_complete */ diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 7beee75399d4..21244c53e377 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -41,20 +41,15 @@ extern void dev_pm_disable_wake_irq_check(struct device *dev); #ifdef CONFIG_PM_SLEEP -extern int device_wakeup_attach_irq(struct device *dev, - struct wake_irq *wakeirq); +extern void device_wakeup_attach_irq(struct device *dev, struct wake_irq *wakeirq); extern void device_wakeup_detach_irq(struct device *dev); extern void device_wakeup_arm_wake_irqs(void); extern void device_wakeup_disarm_wake_irqs(void); #else -static inline int -device_wakeup_attach_irq(struct device *dev, - struct wake_irq *wakeirq) -{ - return 0; -} +static inline void device_wakeup_attach_irq(struct device *dev, + struct wake_irq *wakeirq) {} static inline void device_wakeup_detach_irq(struct device *dev) { diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 027d159ac381..8bef3cb2424d 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -276,7 +276,8 @@ static int rpm_get_suppliers(struct device *dev) continue; retval = pm_runtime_get_sync(link->supplier); - if (retval < 0) { + /* Ignore suppliers with disabled runtime PM. */ + if (retval < 0 && retval != -EACCES) { pm_runtime_put_noidle(link->supplier); return retval; } @@ -1612,22 +1613,34 @@ void pm_runtime_drop_link(struct device *dev) spin_unlock_irq(&dev->power.lock); } +static bool pm_runtime_need_not_resume(struct device *dev) +{ + return atomic_read(&dev->power.usage_count) <= 1 && + (atomic_read(&dev->power.child_count) == 0 || + dev->power.ignore_children); +} + /** * pm_runtime_force_suspend - Force a device into suspend state if needed. * @dev: Device to suspend. * * Disable runtime PM so we safely can check the device's runtime PM status and - * if it is active, invoke it's .runtime_suspend callback to bring it into - * suspend state. Keep runtime PM disabled to preserve the state unless we - * encounter errors. + * if it is active, invoke its ->runtime_suspend callback to suspend it and + * change its runtime PM status field to RPM_SUSPENDED. Also, if the device's + * usage and children counters don't indicate that the device was in use before + * the system-wide transition under way, decrement its parent's children counter + * (if there is a parent). Keep runtime PM disabled to preserve the state + * unless we encounter errors. * * Typically this function may be invoked from a system suspend callback to make - * sure the device is put into low power state. + * sure the device is put into low power state and it should only be used during + * system-wide PM transitions to sleep states. It assumes that the analogous + * pm_runtime_force_resume() will be used to resume the device. */ int pm_runtime_force_suspend(struct device *dev) { int (*callback)(struct device *); - int ret = 0; + int ret; pm_runtime_disable(dev); if (pm_runtime_status_suspended(dev)) @@ -1635,27 +1648,23 @@ int pm_runtime_force_suspend(struct device *dev) callback = RPM_GET_CALLBACK(dev, runtime_suspend); - if (!callback) { - ret = -ENOSYS; - goto err; - } - - ret = callback(dev); + ret = callback ? callback(dev) : 0; if (ret) goto err; /* - * Increase the runtime PM usage count for the device's parent, in case - * when we find the device being used when system suspend was invoked. - * This informs pm_runtime_force_resume() to resume the parent - * immediately, which is needed to be able to resume its children, - * when not deferring the resume to be managed via runtime PM. + * If the device can stay in suspend after the system-wide transition + * to the working state that will follow, drop the children counter of + * its parent, but set its status to RPM_SUSPENDED anyway in case this + * function will be called again for it in the meantime. */ - if (dev->parent && atomic_read(&dev->power.usage_count) > 1) - pm_runtime_get_noresume(dev->parent); + if (pm_runtime_need_not_resume(dev)) + pm_runtime_set_suspended(dev); + else + __update_runtime_status(dev, RPM_SUSPENDED); - pm_runtime_set_suspended(dev); return 0; + err: pm_runtime_enable(dev); return ret; @@ -1668,13 +1677,9 @@ EXPORT_SYMBOL_GPL(pm_runtime_force_suspend); * * Prior invoking this function we expect the user to have brought the device * into low power state by a call to pm_runtime_force_suspend(). Here we reverse - * those actions and brings the device into full power, if it is expected to be - * used on system resume. To distinguish that, we check whether the runtime PM - * usage count is greater than 1 (the PM core increases the usage count in the - * system PM prepare phase), as that indicates a real user (such as a subsystem, - * driver, userspace, etc.) is using it. If that is the case, the device is - * expected to be used on system resume as well, so then we resume it. In the - * other case, we defer the resume to be managed via runtime PM. + * those actions and bring the device into full power, if it is expected to be + * used on system resume. In the other case, we defer the resume to be managed + * via runtime PM. * * Typically this function may be invoked from a system resume callback. */ @@ -1683,32 +1688,18 @@ int pm_runtime_force_resume(struct device *dev) int (*callback)(struct device *); int ret = 0; - callback = RPM_GET_CALLBACK(dev, runtime_resume); - - if (!callback) { - ret = -ENOSYS; - goto out; - } - - if (!pm_runtime_status_suspended(dev)) + if (!pm_runtime_status_suspended(dev) || pm_runtime_need_not_resume(dev)) goto out; /* |