diff options
Diffstat (limited to 'drivers/acpi')
30 files changed, 566 insertions, 307 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index cc57bab146b5..ce2730d61a8f 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -190,6 +190,30 @@ config ACPI_BUTTON To compile this driver as a module, choose M here: the module will be called button. +config ACPI_TINY_POWER_BUTTON + tristate "Tiny Power Button Driver" + depends on !ACPI_BUTTON + help + This driver provides a tiny alternative to the ACPI Button driver. + The tiny power button driver only handles the power button. Rather + than notifying userspace via the input layer or a netlink event, this + driver directly signals the init process to shut down. + + This driver is particularly suitable for cloud and VM environments, + which use a simulated power button to initiate a controlled poweroff, + but which may not want to run a separate userspace daemon to process + input events. + +config ACPI_TINY_POWER_BUTTON_SIGNAL + int "Tiny Power Button Signal" + depends on ACPI_TINY_POWER_BUTTON + default 38 + help + Default signal to send to init in response to the power button. + + Likely values here include 38 (SIGRTMIN+4) to power off, or 2 + (SIGINT) to simulate Ctrl+Alt+Del. + config ACPI_VIDEO tristate "Video" depends on X86 && BACKLIGHT_CLASS_DEVICE diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 33fdaf67454e..e81e1ebbfb32 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_ACPI_IPMI) += acpi_ipmi.o obj-$(CONFIG_ACPI_AC) += ac.o obj-$(CONFIG_ACPI_BUTTON) += button.o +obj-$(CONFIG_ACPI_TINY_POWER_BUTTON) += tiny-power-button.o obj-$(CONFIG_ACPI_FAN) += fan.o obj-$(CONFIG_ACPI_VIDEO) += video.o obj-$(CONFIG_ACPI_TAD) += acpi_tad.o diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 829f37d36b9f..69d2db13886b 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -293,29 +293,30 @@ static int __init ac_do_not_check_pmic_quirk(const struct dmi_system_id *d) return 0; } +/* Please keep this list alphabetically sorted */ static const struct dmi_system_id ac_dmi_table[] __initconst = { { - /* Thinkpad e530 */ - .callback = thinkpad_e530_quirk, - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "32597CG"), + /* ECS EF20EA, AXP288 PMIC but uses separate fuel-gauge */ + .callback = ac_do_not_check_pmic_quirk, + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "EF20EA"), }, }, { - /* ECS EF20EA */ + /* Lenovo Ideapad Miix 320, AXP288 PMIC, separate fuel-gauge */ .callback = ac_do_not_check_pmic_quirk, .matches = { - DMI_MATCH(DMI_PRODUCT_NAME, "EF20EA"), + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "80XF"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"), }, }, { - /* Lenovo Ideapad Miix 320 */ - .callback = ac_do_not_check_pmic_quirk, + /* Lenovo Thinkpad e530, see comment in acpi_ac_notify() */ + .callback = thinkpad_e530_quirk, .matches = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "80XF"), - DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"), + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "32597CG"), }, }, {}, diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index db18df6cb330..dee999938213 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -306,11 +306,9 @@ static const struct lpss_device_desc bsw_spi_dev_desc = { .setup = lpss_deassert_reset, }; -#define ICPU(model) { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, } - static const struct x86_cpu_id lpss_cpu_ids[] = { - ICPU(INTEL_FAM6_ATOM_SILVERMONT), /* Valleyview, Bay Trail */ - ICPU(INTEL_FAM6_ATOM_AIRMONT), /* Braswell, Cherry Trail */ + X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT, NULL), + X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT, NULL), {} }; diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 15c5b272e698..bc96457c9e25 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -943,7 +943,7 @@ acpi_video_init_brightness(struct acpi_video_device *device) int i, max_level = 0; unsigned long long level, level_old; struct acpi_video_device_brightness *br = NULL; - int result = -EINVAL; + int result; result = acpi_video_get_levels(device->dev, &br, &max_level); if (result) diff --git a/drivers/acpi/acpi_watchdog.c b/drivers/acpi/acpi_watchdog.c index b5516b04ffc0..6e9ec6e3fe47 100644 --- a/drivers/acpi/acpi_watchdog.c +++ b/drivers/acpi/acpi_watchdog.c @@ -55,12 +55,14 @@ static bool acpi_watchdog_uses_rtc(const struct acpi_table_wdat *wdat) } #endif +static bool acpi_no_watchdog; + static const struct acpi_table_wdat *acpi_watchdog_get_wdat(void) { const struct acpi_table_wdat *wdat = NULL; acpi_status status; - if (acpi_disabled) + if (acpi_disabled || acpi_no_watchdog) return NULL; status = acpi_get_table(ACPI_SIG_WDAT, 0, @@ -88,6 +90,14 @@ bool acpi_has_watchdog(void) } EXPORT_SYMBOL_GPL(acpi_has_watchdog); +/* ACPI watchdog can be disabled on boot command line */ +static int __init disable_acpi_watchdog(char *str) +{ + acpi_no_watchdog = true; + return 1; +} +__setup("acpi_no_watchdog", disable_acpi_watchdog); + void __init acpi_watchdog_init(void) { const struct acpi_wdat_entry *entries; @@ -126,12 +136,11 @@ void __init acpi_watchdog_init(void) gas = &entries[i].register_region; res.start = gas->address; + res.end = res.start + ACPI_ACCESS_BYTE_WIDTH(gas->access_width) - 1; if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { res.flags = IORESOURCE_MEM; - res.end = res.start + ALIGN(gas->access_width, 4) - 1; } else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { res.flags = IORESOURCE_IO; - res.end = res.start + gas->access_width - 1; } else { pr_warn("Unsupported address space: %u\n", gas->space_id); diff --git a/drivers/acpi/acpica/acconvert.h b/drivers/acpi/acpica/acconvert.h index ede4b9cc9e85..cf85d66da6e7 100644 --- a/drivers/acpi/acpica/acconvert.h +++ b/drivers/acpi/acpica/acconvert.h @@ -65,9 +65,7 @@ void cg_write_aml_comment(union acpi_parse_object *op); /* * cvparser */ -void -cv_init_file_tree(struct acpi_table_header *table, - u8 *aml_start, u32 aml_length); +void cv_init_file_tree(struct acpi_table_header *table, FILE * root_file); void cv_clear_op_comments(union acpi_parse_object *op); diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h index 67f282e9e0af..ebf6453d0e21 100644 --- a/drivers/acpi/acpica/achware.h +++ b/drivers/acpi/acpica/achware.h @@ -101,6 +101,8 @@ acpi_status acpi_hw_enable_all_runtime_gpes(void); acpi_status acpi_hw_enable_all_wakeup_gpes(void); +u8 acpi_hw_check_all_gpes(acpi_handle gpe_skip_device, u32 gpe_skip_number); + acpi_status acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block, diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index 2269e10bc21b..168904ba3086 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -477,7 +477,7 @@ #define ASL_CV_PRINT_ONE_COMMENT(a,b,c,d) cv_print_one_comment_type (a,b,c,d); #define ASL_CV_PRINT_ONE_COMMENT_LIST(a,b) cv_print_one_comment_list (a,b); #define ASL_CV_FILE_HAS_SWITCHED(a) cv_file_has_switched(a) -#define ASL_CV_INIT_FILETREE(a,b,c) cv_init_file_tree(a,b,c); +#define ASL_CV_INIT_FILETREE(a,b) cv_init_file_tree(a,b); #else @@ -492,7 +492,7 @@ #define ASL_CV_PRINT_ONE_COMMENT(a,b,c,d) #define ASL_CV_PRINT_ONE_COMMENT_LIST(a,b) #define ASL_CV_FILE_HAS_SWITCHED(a) 0 -#define ASL_CV_INIT_FILETREE(a,b,c) +#define ASL_CV_INIT_FILETREE(a,b) #endif diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c index 8c83d8c620dc..9efca54c51ac 100644 --- a/drivers/acpi/acpica/evevent.c +++ b/drivers/acpi/acpica/evevent.c @@ -130,7 +130,7 @@ static acpi_status acpi_ev_fixed_event_initialize(void) /* * Initialize the structure that keeps track of fixed event handlers and - * enable the fixed events. + * disable all of the fixed events. */ for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { acpi_gbl_fixed_event_handlers[i].handler = NULL; @@ -265,4 +265,49 @@ static u32 acpi_ev_fixed_event_dispatch(u32 event) handler) (acpi_gbl_fixed_event_handlers[event].context)); } +/******************************************************************************* + * + * FUNCTION: acpi_any_fixed_event_status_set + * + * PARAMETERS: None + * + * RETURN: TRUE or FALSE + * + * DESCRIPTION: Checks the PM status register for active fixed events + * + ******************************************************************************/ + +u32 acpi_any_fixed_event_status_set(void) +{ + acpi_status status; + u32 in_status; + u32 in_enable; + u32 i; + + status = acpi_hw_register_read(ACPI_REGISTER_PM1_ENABLE, &in_enable); + if (ACPI_FAILURE(status)) { + return (FALSE); + } + + status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &in_status); + if (ACPI_FAILURE(status)) { + return (FALSE); + } + + /* + * Check for all possible Fixed Events and dispatch those that are active + */ + for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { + + /* Both the status and enable bits must be on for this event */ + + if ((in_status & acpi_gbl_fixed_event_info[i].status_bit_mask) && + (in_enable & acpi_gbl_fixed_event_info[i].enable_bit_mask)) { + return (TRUE); + } + } + + return (FALSE); +} + #endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index 2c39ff2a7406..3be60673e461 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -795,6 +795,45 @@ acpi_status acpi_enable_all_wakeup_gpes(void) ACPI_EXPORT_SYMBOL(acpi_enable_all_wakeup_gpes) +/****************************************************************************** + * + * FUNCTION: acpi_any_gpe_status_set + * + * PARAMETERS: gpe_skip_number - Number of the GPE to skip + * + * RETURN: Whether or not the status bit is set for any GPE + * + * DESCRIPTION: Check the status bits of all enabled GPEs, except for the one + * represented by the "skip" argument, and return TRUE if any of + * them is set or FALSE otherwise. + * + ******************************************************************************/ +u32 acpi_any_gpe_status_set(u32 gpe_skip_number) +{ + acpi_status status; + acpi_handle gpe_device; + u8 ret; + + ACPI_FUNCTION_TRACE(acpi_any_gpe_status_set); + + status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); + if (ACPI_FAILURE(status)) { + return (FALSE); + } + + status = acpi_get_gpe_device(gpe_skip_number, &gpe_device); + if (ACPI_FAILURE(status)) { + gpe_device = NULL; + } + + ret = acpi_hw_check_all_gpes(gpe_device, gpe_skip_number); + (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); + + return (ret); +} + +ACPI_EXPORT_SYMBOL(acpi_any_gpe_status_set) + /******************************************************************************* * * FUNCTION: acpi_install_gpe_block diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index 1b4252bdcd0b..49c46d4dd070 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -444,6 +444,65 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, return (AE_OK); } +struct acpi_gpe_block_status_context { + struct acpi_gpe_register_info *gpe_skip_register_info; + u8 gpe_skip_mask; + u8 retval; +}; + +/****************************************************************************** + * + * FUNCTION: acpi_hw_get_gpe_block_status + * + * PARAMETERS: gpe_xrupt_info - GPE Interrupt info + * gpe_block - Gpe Block info + * context - GPE list walk context data + * + * RETURN: Success + * + * DESCRIPTION: Produce a combined GPE status bits mask for the given block. + * + ******************************************************************************/ + +static acpi_status +acpi_hw_get_gpe_block_status(struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block, + void *context) +{ + struct acpi_gpe_block_status_context *c = context; + struct acpi_gpe_register_info *gpe_register_info; + u64 in_enable, in_status; + acpi_status status; + u8 ret_mask; + u32 i; + + /* Examine each GPE Register within the block */ + + for (i = 0; i < gpe_block->register_count; i++) { + gpe_register_info = &gpe_block->register_info[i]; + + status = acpi_hw_read(&in_enable, + &gpe_register_info->enable_address); + if (ACPI_FAILURE(status)) { + continue; + } + + status = acpi_hw_read(&in_status, + &gpe_register_info->status_address); + if (ACPI_FAILURE(status)) { + continue; + } + + ret_mask = in_enable & in_status; + if (ret_mask && c->gpe_skip_register_info == gpe_register_info) { + ret_mask &= ~c->gpe_skip_mask; + } + c->retval |= ret_mask; + } + + return (AE_OK); +} + /****************************************************************************** * * FUNCTION: acpi_hw_disable_all_gpes @@ -510,4 +569,45 @@ acpi_status acpi_hw_enable_all_wakeup_gpes(void) return_ACPI_STATUS(status); } +/****************************************************************************** + * + * FUNCTION: acpi_hw_check_all_gpes + * + * PARAMETERS: gpe_skip_device - GPE devoce of the GPE to skip + * gpe_skip_number - Number of the GPE to skip + * + * RETURN: Combined status of all GPEs + * + * DESCRIPTION: Check all enabled GPEs in all GPE blocks, except for the one + * represented by the "skip" arguments, and return TRUE if the + * status bit is set for at least one of them of FALSE otherwise. + * + ******************************************************************************/ + +u8 acpi_hw_check_all_gpes(acpi_handle gpe_skip_device, u32 gpe_skip_number) +{ + struct acpi_gpe_block_status_context context = { + .gpe_skip_register_info = NULL, + .retval = 0, + }; + struct acpi_gpe_event_info *gpe_event_info; + acpi_cpu_flags flags; + + ACPI_FUNCTION_TRACE(acpi_hw_check_all_gpes); + + flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); + + gpe_event_info = acpi_ev_get_gpe_event_info(gpe_skip_device, + gpe_skip_number); + if (gpe_event_info) { + context.gpe_skip_register_info = gpe_event_info->register_info; + context.gpe_skip_mask = acpi_hw_get_gpe_register_bit(gpe_event_info); + } + + acpi_os_release_lock(acpi_gbl_gpe_lock, flags); + + (void)acpi_ev_walk_gpe_list(acpi_hw_get_gpe_block_status, &context); + return (context.retval != 0); +} + #endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index 243a25add28f..317ae870336b 100644 --- a/drivers/acpi/acpica/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -300,6 +300,18 @@ acpi_status acpi_hw_legacy_wake(u8 sleep_state) [ACPI_EVENT_POWER_BUTTON]. status_register_id, ACPI_CLEAR_STATUS); + /* Enable sleep button */ + + (void) + acpi_write_bit_register(acpi_gbl_fixed_event_info + [ACPI_EVENT_SLEEP_BUTTON]. + enable_register_id, ACPI_ENABLE_EVENT); + + (void) + acpi_write_bit_register(acpi_gbl_fixed_event_info + [ACPI_EVENT_SLEEP_BUTTON]. + status_register_id, ACPI_CLEAR_STATUS); + acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WORKING); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index 370bbc867745..d4d26147610e 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -164,7 +164,7 @@ acpi_ns_handle_to_pathname(acpi_handle target_handle, /* Build the path in the caller buffer */ (void)acpi_ns_build_normalized_path(node, buffer->pointer, - required_size, no_trailing); + (u32)required_size, no_trailing); ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%s [%X]\n", (char *)buffer->pointer, (u32) required_size)); @@ -315,7 +315,7 @@ char *acpi_ns_get_normalized_pathname(struct acpi_namespace_node *node, /* Build the path in the allocated buffer */ - (void)acpi_ns_build_normalized_path(node, name_buffer, size, + (void)acpi_ns_build_normalized_path(node, name_buffer, (u32)size, no_trailing); ACPI_DEBUG_PRINT_RAW((ACPI_DB_NAMES, "%s: Path \"%s\"\n", @@ -346,7 +346,7 @@ char *acpi_ns_build_prefixed_pathname(union acpi_generic_state *prefix_scope, char *full_path = NULL; char *external_path = NULL; char *prefix_path = NULL; - u32 prefix_path_length = 0; + acpi_size prefix_path_length = 0; /* If there is a prefix, get the pathname to it */ diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 984129dcaa0c..0e6aba81605b 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -516,7 +516,7 @@ acpi_status acpi_install_method(u8 *buffer) method_flags = *parser_state.aml++; aml_start = parser_state.aml; - aml_length = ACPI_PTR_DIFF(parser_state.pkg_end, aml_start); + aml_length = (u32)ACPI_PTR_DIFF(parser_state.pkg_end, aml_start); /* * Allocate resources up-front. We don't want to have to delete a new diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index f8403d480318..7490429ddbf6 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -202,14 +202,14 @@ ACPI_EXPORT_SYMBOL_INIT(acpi_reallocate_root_table) * * PARAMETERS: signature - ACPI signature of needed table * instance - Which instance (for SSDTs) - * out_table_header - The pointer to the table header to fill + * out_table_header - The pointer to the where the table header + * is returned * - * RETURN: Status and pointer to mapped table header + * RETURN: Status and a copy of the table header * - * DESCRIPTION: Finds an ACPI table header. - * - * NOTE: Caller is responsible in unmapping the header with - * acpi_os_unmap_memory + * DESCRIPTION: Finds and returns an ACPI table header. Caller provides the + * memory where a copy of the header is to be returned + * (fixed length). * ******************************************************************************/ acpi_status diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c index 3e60bdac2200..bbec04c291d2 100644 --- a/drivers/acpi/acpica/utobject.c +++ b/drivers/acpi/acpica/utobject.c @@ -44,7 +44,7 @@ acpi_ut_get_element_length(u8 object_type, * * NOTE: We always allocate the worst-case object descriptor because * these objects are cached, and we want them to be - * one-size-satisifies-any-request. This in itself may not be + * one-size-satisfies-any-request. This in itself may not be * the most memory efficient, but the efficiency of the object * cache should more than make up for this! * diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 103acbbfcf9a..24c9642e8fc7 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -171,7 +171,7 @@ int ghes_estatus_pool_init(int num_ghes) * New allocation must be visible in all pgd before it can be found by * an NMI allocating from the pool. */ - vmalloc_sync_all(); + vmalloc_sync_mappings(); rc = gen_pool_add(ghes_estatus_pool, addr, PAGE_ALIGN(len), -1); if (rc) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 111a407dcc77..366c389175d8 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -1365,19 +1365,19 @@ static const struct dmi_system_id bat_dmi_table[] __initconst = { }, }, { - /* ECS EF20EA */ + /* ECS EF20EA, AXP288 PMIC but uses separate fuel-gauge */ .callback = battery_do_not_check_pmic_quirk, .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "EF20EA"), }, }, { - /* Lenovo Ideapad Miix 320 */ + /* Lenovo Ideapad Miix 320, AXP288 PMIC, separate fuel-gauge */ .callback = battery_do_not_check_pmic_quirk, .matches = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "80XF"), - DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"), + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "80XF"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"), }, }, {}, diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index f6925f16c4a2..00112cf15322 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -30,17 +30,14 @@ #define ACPI_BUTTON_NOTIFY_STATUS 0x80 #define ACPI_BUTTON_SUBCLASS_POWER "power" -#define ACPI_BUTTON_HID_POWER "PNP0C0C" #define ACPI_BUTTON_DEVICE_NAME_POWER "Power Button" #define ACPI_BUTTON_TYPE_POWER 0x01 #define ACPI_BUTTON_SUBCLASS_SLEEP "sleep" -#define ACPI_BUTTON_HID_SLEEP "PNP0C0E" #define ACPI_BUTTON_DEVICE_NAME_SLEEP "Sleep Button" #define ACPI_BUTTON_TYPE_SLEEP 0x03 #define ACPI_BUTTON_SUBCLASS_LID "lid" -#define ACPI_BUTTON_HID_LID "PNP0C0D" #define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch" #define ACPI_BUTTON_TYPE_LID 0x05 diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 08bc9751fe66..4816df520f72 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -179,9 +179,9 @@ EXPORT_SYMBOL(first_ec); static struct acpi_ec *boot_ec; static bool boot_ec_is_ecdt = false; +static struct workqueue_struct *ec_wq; static struct workqueue_struct *ec_query_wq; -static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */ static int EC_FLAGS_CORRECT_ECDT; /* Needs ECDT port address correction */ static int EC_FLAGS_IGNORE_DSDT_GPE; /* Needs ECDT GPE as correction setting */ static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */ @@ -469,7 +469,7 @@ static void acpi_ec_submit_query(struct acpi_ec *ec) ec_dbg_evt("Command(%s) submitted/blocked", acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY)); ec->nr_pending_queries++; - schedule_work(&ec->work); + queue_work(ec_wq, &ec->work); } } @@ -535,7 +535,7 @@ static void acpi_ec_enable_event(struct acpi_ec *ec) #ifdef CONFIG_PM_SLEEP static void __acpi_ec_flush_work(void) { - flush_scheduled_work(); /* flush ec->work */ + drain_workqueue(ec_wq); /* flush ec->work */ flush_workqueue(ec_query_wq); /* flush queries */ } @@ -556,8 +556,8 @@ static void acpi_ec_disable_event(struct acpi_ec *ec) void acpi_ec_flush_work(void) { - /* Without ec_query_wq there is nothing to flush. */ - if (!ec_query_wq) + /* Without ec_wq there is nothing to flush. */ + if (!ec_wq) return; __acpi_ec_flush_work(); @@ -689,21 +689,9 @@ static void advance_transaction(struct acpi_ec *ec) wakeup = true; } goto out; - } else { - if (EC_FLAGS_QUERY_HANDSHAKE && - !(status & ACPI_EC_FLAG_SCI) && - (t->command == ACPI_EC_COMMAND_QUERY)) { - ec_transaction_transition(ec, ACPI_EC_COMMAND_POLL); - t->rdata[t->ri++] = 0x00; - ec_transaction_transition(ec, ACPI_EC_COMMAND_COMPLETE); - ec_dbg_evt("Command(%s) completed by software", - acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY)); - wakeup = true; - } else if ((status & ACPI_EC_FLAG_IBF) == 0) { - acpi_ec_write_cmd(ec, t->command); - ec_transaction_transition(ec, ACPI_EC_COMMAND_POLL); - } else - goto err; + } else if (!(status & ACPI_EC_FLAG_IBF)) { + acpi_ec_write_cmd(ec, t->command); + ec_transaction_transition(ec, ACPI_EC_COMMAND_POLL); goto out; } err: @@ -1426,57 +1414,45 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) return AE_CTRL_TERMINATE; } -static void install_gpe_event_handler(struct acpi_ec *ec) -{ - acpi_status status = - acpi_install_gpe_raw_handler(NULL, ec->gpe, - ACPI_GPE_EDGE_TRIGGERED, - &acpi_ec_gpe_handler, - ec); - if (ACPI_SUCCESS(status)) { - /* This is not fatal as we can poll EC events */ - set_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags); - acpi_ec_leave_noirq(ec); - if (test_bit(EC_FLAGS_STARTED, &ec->flags) && - ec->reference_count >= 1) - acpi_ec_enable_gpe(ec, true); - } -} - -/* ACPI reduced hardware platforms use a GpioInt specified in _CRS. */ -static int install_gpio_irq_event_handler(struct acpi_ec *ec, - struct acpi_device *device) +static bool install_gpe_event_handler(struct acpi_ec *ec) { - int irq = acpi_dev_gpio_irq_get(device, 0); - int ret; - - if (irq < 0) - return irq; + acpi_status status; - ret = request_irq(irq, acpi_ec_irq_handler, IRQF_SHARED, - "ACPI EC", ec); + status = acpi_install_gpe_raw_handler(NULL, ec->gpe, + ACPI_GPE_EDGE_TRIGGERED, + &acpi_ec_gpe_handler, ec); + if (ACPI_FAILURE(status)) + return false; - /* - * Unlike the GPE case, we treat errors here as fatal, we'll only - * implement GPIO polling if we find a case that needs it. - */ - if (ret < 0) - return ret; + if (test_bit(EC_FLAGS_STARTED, &ec->flags) && ec->reference_count >= 1) + acpi_ec_enable_gpe(ec, true); - ec->irq = irq; - set_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags); - acpi_ec_leave_noirq(ec); + return true; +} - return 0; +static bool install_gpio_irq_event_handler(struct acpi_ec *ec) +{ + return request_irq(ec->irq, acpi_ec_irq_handler, IRQF_SHARED, + "ACPI EC", ec) >= 0; } -/* - * Note: This function returns an error code only when the address space - * handler is not installed, which means "not able to handle - * transactions". +/** + * ec_install_handlers - Install service callbacks and register query methods. + * @ec: Target EC. + * @device: ACPI device object corresponding to @ec. + * + * Install a handler for the EC address space type unless it has been installed + * already. If @device is not NULL, also look for EC query methods in the + * namespace and register them, and install an event (either GPE or GPIO IRQ) + * handler for the EC, if possible. + * + * Return: + * -ENODEV if the address space handler cannot be installed, which means + * "unable to handle transactions", + * -EPROBE_DEFER if GPIO IRQ acquisition needs to be deferred, + * or 0 (success) otherwise. */ -static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device, - bool handle_events) +static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device) { acpi_status status; @@ -1489,26 +1465,28 @@ static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device, &acpi_ec_space_handler, NULL, ec); if (ACPI_FAILURE(status)) { - if (status == AE_NOT_FOUND) { - /* - * Maybe OS fails in evaluating the _REG - * object. The AE_NOT_FOUND error will be - * ignored and OS * continue to initialize - * EC. - */ - pr_err("Fail in evaluating the _REG object" - " of EC device. Broken bios is suspected.\n"); - } else { - acpi_ec_stop(ec, false); - return -ENODEV; - } + acpi_ec_stop(ec, false); + return -ENODEV; } set_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags); } - if (!handle_events) + if (!device) return 0; + if (ec->gpe < 0) { + /* ACPI reduced hardware platforms use a GpioInt from _CRS. */ + int irq = acpi_dev_gpio_irq_get(device, 0); + /* + * Bail out right away for deferred probing or complete the + * initialization regardless of any other errors. + */ + if (irq == -EPROBE_DEFER) + return -EPROBE_DEFER; + else if (irq >= 0) + ec->irq = irq; + } + if (!test_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags)) { /* Find and register all query methods */ acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1, @@ -1517,16 +1495,21 @@ static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device, set_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags); } if (!test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags)) { - if (ec->gpe >= 0) { - install_gpe_event_handler(ec); - } else if (device) { - int ret = install_gpio_irq_event_handler(ec, device); - - if (ret) - return ret; - } else { /* No GPE and no GpioInt? */ - return -ENODEV; + bool ready = false; + + if (ec->gpe >= 0) + ready = install_gpe_event_handler(ec); + else if (ec->irq >= 0) + ready = install_gpio_irq_event_handler(ec); + + if (ready) { + set_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags); + acpi_ec_leave_noirq(ec); } + /* + * Failures to install an event handler are not fatal, because + * the EC can be polled for events. + */ } /* EC is fully operational, allow queries */ acpi_ec_enable_event(ec); @@ -1573,61 +1556,46 @@ static void ec_remove_handlers(struct acpi_ec *ec) } } -static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device, - bool handle_events) +static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device) { int ret; - ret = ec_install_handlers(ec, device, handle_events); + ret = ec_install_handlers(ec, device); if (ret) return ret; /* First EC capable of handling transactions */ - if (!first_ec) { + if (!first_ec) first_ec = ec; - acpi_handle_info(first_ec->handle, "Used as first EC\n"); - } - acpi_handle_info(ec->handle, - "GPE=0x%x, IRQ=%d, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n", - ec->gpe, ec->irq, ec->command_addr, ec->data_addr); - return ret; -} - -static bool acpi_ec_ecdt_get_handle(acpi_handle *phandle) -{ - struct acpi_table_ecdt *ecdt_ptr; - acpi_status status; - acpi_handle handle; + pr_info("EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n", ec->command_addr, + ec->data_addr); - status = acpi_get_table(ACPI_SIG_ECDT, 1, - (struct acpi_table_header **)&ecdt_ptr); - if (ACPI_FAILURE(status)) - return false; - - status = acpi_get_handle(NULL, ecdt_ptr->id, &handle); - if (ACPI_FAILURE(status)) - return false; + if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags)) { + if (ec->gpe >= 0) + pr_info("GPE=0x%x\n", ec->gpe); + else + pr_info("IRQ=%d\n", ec->irq); + } - *phandle = handle; - return true; + return ret; } static int acpi_ec_add(struct acpi_device *device) { - struct acpi_ec *ec = NULL; - bool dep_update = true; - acpi_status status; + struct acpi_ec *ec; int ret; strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_EC_CLASS); - if (!strcmp(acpi_device_hid(device), ACPI_ECDT_HID)) { - boot_ec_is_ecdt = true; + if ((boot_ec && boot_ec->handle == device->handle) || + !strcmp(acpi_device_hid(device), ACPI_ECDT_HID)) { + /* Fast path: this device corresponds to the boot EC. */ ec = boot_ec; - dep_update = false; } else { + acpi_status status; + ec = acpi_ec_alloc(); if (!ec) return -ENOMEM; @@ -1635,12 +1603,11 @@ static int acpi_ec_add(struct acpi_device *device) status = ec_parse_device(device->handle, 0, ec, NULL); if (status != AE_CTRL_TERMINATE) { ret = -EINVAL; - goto err_alloc; + goto err; } if (boot_ec && ec->command_addr == boot_ec->command_addr && ec->data_addr == boot_ec->data_addr) { - boot_ec_is_ecdt = false; /* * Trust PNP0C09 namespace location rather than * ECDT ID. But trust ECDT GPE rather than _GPE @@ -1654,15 +1621,18 @@ static int acpi_ec_add(struct acpi_device *device) } } - ret = acpi_ec_setup(ec, device, true); + ret = acpi_ec_setup(ec, device); if (ret) - goto err_query; + goto err; if (ec == boot_ec) acpi_handle_info(boot_ec->handle, - "Boot %s EC used to handle transactions and events\n", + "Boot %s EC initialization complete\n", boot_ec_is_ecdt ? "ECDT" : "DSDT"); + acpi_handle_info(ec->handle, + "EC: Used to handle transactions and events\n"); + device->driver_data = ec; ret = !!request_region(ec->data_addr, 1, "EC data"); @@ -1670,19 +1640,16 @@ 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); - if (dep_update) { - /* Reprobe devices depending on the EC */ - acpi_walk_dep_device_list(ec->handle); - } + /* Reprobe devices depending on the EC */ + acpi_walk_dep_device_list(ec->handle); + acpi_handle_debug(ec->handle, "enumerated.\n"); return 0; -err_query: - if (ec != boot_ec) - acpi_ec_remove_query_handlers(ec, true, 0); -err_alloc: +err: if (ec != boot_ec) acpi_ec_free(ec); + return ret; } @@ -1774,7 +1741,7 @@ void __init acpi_ec_dsdt_probe(void) * At this point, the GPE is not fully initialized, so do not to * handle the events. */ - ret = acpi_ec_setup(ec, NULL, false); + ret = acpi_ec_setup(ec, NULL); if (ret) { acpi_ec_free(ec); return; @@ -1787,52 +1754,43 @@ void __init acpi_ec_dsdt_probe(void) } /* - * If the DSDT EC is not functioning, we still need to prepare a fully - * functioning ECDT EC first in order to handle the events. - * https://bugzilla.kernel.org/show_bug.cgi?id=115021 + * acpi_ec_ecdt_start - Finalize the boot ECDT EC initialization. + * + * First, look for an ACPI handle for the boot ECDT EC if acpi_ec_add() has not + * found a matching object in the namespace. + * + * Next, in case the DSDT EC is not functioning, it is still necessary to + * provide a functional ECDT EC to handle events, so add an extra device object + * to represent it (see https://bugzilla.kernel.org/show_bug.cgi?id=115021). + * + * This is useful on platforms with valid ECDT and invalid DSDT EC settings, + * like ASUS X550ZE (see https://bugzilla.kernel.org/show_bug.cgi?id=196847). */ -static int __init acpi_ec_ecdt_start(void) +static void __init acpi_ec_ecdt_start(void) { + struct acpi_table_ecdt *ecdt_ptr; acpi_handle handle; + acpi_status status; - if (!boot_ec) - return -ENODEV; - /* In case acpi_ec_ecdt_start() is called after acpi_ec_add() */ - if (!boot_ec_is_ecdt) - return -ENODEV; + /* Bail out if a matching EC has been found in the namespace. */ + if (!boot_ec || boot_ec->handle != ACPI_ROOT_OBJECT) + return; - /* - * At this point, the namespace and the GPE is initialized, so - * start to find the namespace objects and handle the events. - * - * 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) { - if (!acpi_ec_ecdt_get_handle(&handle)) - return -ENODEV; - boot_ec->handle = handle; - } + /* Look up the object pointed to from the ECDT in the namespace. */ + status = acpi_get_table(ACPI_SIG_ECDT, 1, + (struct acpi_table_header **)&ecdt_ptr); + if (ACPI_FAILURE(status)) + return; - /* Register to ACPI bus with PM ops attached */ - return acpi_bus_register_early_device(ACPI_BUS_TYPE_ECDT_EC); -} + status = acpi_get_handle(NULL, ecdt_ptr->id, &handle); + if (ACPI_FAILURE(status)) + return; -#if 0 -/* - * Some EC firmware variations refuses to respond QR_EC when SCI_EVT is not - * set, for which case, we complete the QR_EC without issuing it to the - * firmware. - * https://bugzilla.kernel.org/show_bug.cgi?id=82611 - * https://bugzilla.kernel.org/show_bug.cgi?id=97381 - */ -static int ec_flag_query_handshake(const struct dmi_system_id *id) -{ - pr_debug("Detected the EC firmware requiring QR_EC issued when SCI_EVT set\n"); - EC_FLAGS_QUERY_HANDSHAKE = 1; - return 0; + boot_ec->handle = handle; + + /* Add a special ACPI device object to represent the boot EC. */ + acpi_bus_register_early_device(ACPI_BUS_TYPE_ECDT_EC); } -#endif /* * On some hardware it is necessary to clear events accumulated by the EC during @@ -1961,7 +1919,7 @@ void __init acpi_ec_ecdt_probe(void) * At this point, the namespace is not initialized, so do not find * the namespace objects, or handle the events. */ - ret = acpi_ec_setup(ec, NULL, false); + ret = acpi_ec_setup(ec, NULL); if (ret) { acpi_ec_free(ec); return; @@ -2036,6 +1994,11 @@ void acpi_ec_set_gpe_wake_mask(u8 action) acpi_set_gpe_wake_mask(NULL, first_ec->gpe, action); } +bool acpi_ec_other_gpes_active(void) +{ + return acpi_any_gpe_status_set(first_ec ? first_ec->gpe : U32_MAX); +} + bool acpi_ec_dispatch_gpe(void) { u32 ret; @@ -2107,25 +2070,33 @@ static struct acpi_driver acpi_ec_driver = { .drv.pm = &acpi_ec_pm, }; -static inline int acpi_ec_query_init(void) +static void acpi_ec_destroy_workqueues(void) { - if (!ec_query_wq) { - ec_query_wq = alloc_workqueue("kec_query", 0, - ec_max_queries); - if (!ec_query_wq) - return -ENODEV; + if (ec_wq) { + destroy_workqueue(ec_wq); + ec_wq = NULL; } - return 0; -} - -static inline void acpi_ec_query_exit(void) -{ if (ec_query_wq) { destroy_workqueue(ec_query_wq); ec_query_wq = NULL; } } +static int acpi_ec_init_workqueues(void) +{ + if (!ec_wq) + ec_wq = alloc_ordered_workqueue("kec", 0); + + if (!ec_query_wq) + ec_query_wq = alloc_workqueue("kec_query", 0, ec_max_queries); + + if (!ec_wq || !ec_query_wq) { + acpi_ec_destroy_workqueues(); + return -ENODEV; + } + return 0; +} + static const struct dmi_system_id acpi_ec_no_wakeup[] = { { .ident = "Thinkpad X1 Carbon 6th", @@ -2151,15 +2122,13 @@ static const struct dmi_system_id acpi_ec_no_wakeup[] = { { }, }; -int __init acpi_ec_init(void) +void __init acpi_ec_init(void) { int result; - int ecdt_fail, dsdt_fail; - /* register workqueue for _Qxx evaluations */ - result = acpi_ec_query_init(); + result = acpi_ec_init_workqueues(); if (result) - return result; + return; /* * Disable EC wakeup on following systems to prevent periodic @@ -2170,16 +2139,10 @@ int __init acpi_ec_init(void) pr_debug("Disabling EC wakeup on suspend-to-idle\n"); } - /* 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; + /* Driver must be registered after acpi_ec_init_workqueues(). */ + acpi_bus_register_driver(&acpi_ec_driver); + + acpi_ec_ecdt_start(); } /* EC driver currently not unloadable */ @@ -2188,6 +2151,6 @@ static void __exit acpi_ec_exit(void) { acpi_bus_unregister_driver(&acpi_ec_driver); - acpi_ec_query_exit(); + acpi_ec_destroy_workqueues(); } #endif /* 0 */ diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index aaf4e8f348cf..873e039ad4b7 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -276,29 +276,29 @@ static ssize_t show_state(struct device *dev, struct device_attribute *attr, cha int count; if (fps->control == 0xFFFFFFFF || fps->control > 100) - count = snprintf(buf, PAGE_SIZE, "not-defined:"); + count = scnprintf(buf, PAGE_SIZE, "not-defined:"); else - count = snprintf(buf, PAGE_SIZE, "%lld:", fps->control); + count = scnprintf(buf, PAGE_SIZE, "%lld:", fps->control); if (fps->trip_point == 0xFFFFFFFF || fps->trip_point > 9) - count += snprintf(&buf[count], PAGE_SIZE, "not-defined:"); + count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined:"); else - count += snprintf(&buf[count], PAGE_SIZE, "%lld:", fps->trip_point); + count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld:", fps->trip_point); if (fps->speed == 0xFFFFFFFF) - count += snprintf(&buf[count], PAGE_SIZE, "not-defined:"); + count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined:"); else - count += snprintf(&buf[count], PAGE_SIZE, "%lld:", fps->speed); + count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld:", fps->speed); if (fps->noise_level == 0xFFFFFFFF) - count += snprintf(&buf[count], PAGE_SIZE, "not-defined:"); + count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined:"); else - count += snprintf(&buf[count], PAGE_SIZE, "%lld:", fps->noise_level * 100); + count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld:", fps->noise_level * 100); if (fps->power == 0xFFFFFFFF) - count += snprintf(&buf[count], PAGE_SIZE, "not-defined\n"); + count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined\n"); else - count += snprintf(&buf[count], PAGE_SIZE, "%lld\n", fps->power); + count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld\n", fps->power); return count; } diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 3616daec650b..e387517d3354 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -190,7 +190,7 @@ extern struct acpi_ec *first_ec; /* External interfaces use first EC only, so remember */ typedef int (*acpi_ec_query_func) (void *data); -int acpi_ec_init(void); +void acpi_ec_init(void); void acpi_ec_ecdt_probe(void); void acpi_ec_dsdt_probe(void); void acpi_ec_block_transactions(void); @@ -202,6 +202,7 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit); #ifdef CONFIG_PM_SLEEP void acpi_ec_flush_work(void); +bool acpi_ec_other_gpes_active(void); bool acpi_ec_dispatch_gpe(void); #endif diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 41168c027a5a..762c5d50b8fe 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1598,6 +1598,7 @@ void acpi_os_delete_lock(acpi_spinlock handle) */ acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp) + __acquires(lockp) { acpi_cpu_flags flags; spin_lock_irqsave(lockp, flags); @@ -1609,6 +1610,7 @@ acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp) */ void acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags flags) + __releases(lockp) { spin_unlock_irqrestore(lockp, flags); } diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 0cb9df5462c3..ac8ad6cb82aa 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -155,7 +155,7 @@ static void decode_osc_bits(struct acpi_pci_root *root, char *msg, u32 word, buf[0] = '\0'; for (i = 0, entry = table; i < size; i++, entry++) if (word & entry->bit) - len += snprintf(buf + len, sizeof(buf) - len, "%s%s", + len += scnprintf(buf + len, sizeof(buf) - len, "%s%s", len ? " " : "", entry->desc); dev_info(&root->device->dev, "_OSC: %s [%s]\n", msg, buf); diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c index 0e62ef265ce4..7892980b3ce4 100644 --- a/drivers/acpi/proc.c +++ b/drivers/acpi/proc.c @@ -22,14 +22,13 @@ ACPI_MODULE_NAME("sleep") static int acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset) { - struct list_head *node, *next; + struct acpi_device *dev, *tmp; seq_printf(seq, "Device\tS-state\t Status Sysfs node\n"); mutex_lock(&acpi_device_lock); - list_for_each_safe(node, next, &acpi_wakeup_device_list) { - struct acpi_device *dev = - container_of(node, struct acpi_device, wakeup_list); + list_for_each_entry_safe(dev, tmp, &acpi_wakeup_device_list, + wakeup_list) { struct acpi_device_physical_node *entry; if (!dev->wakeup.flags.valid) @@ -96,7 +95,7 @@ acpi_system_write_wakeup_device(struct file *file, const char __user * buffer, size_t count, loff_t * ppos) { - struct list_head *node, *next; + struct acpi_device *dev, *tmp; char strbuf[5]; char str[5] = ""; @@ -109,9 +108,8 @@ acpi_system_write_wakeup_device(struct file *file, sscanf(strbuf, "%s", str); mutex_lock(&acpi_device_lock); - list_for_each_safe(node, next, &acpi_wakeup_device_list) { - struct acpi_device *dev = - container_of(node, struct acpi_device, wakeup_list); + list_for_each_entry_safe(dev, tmp, &acpi_wakeup_device_list, + wakeup_list) { if (!dev->wakeup.flags.valid) continue; diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 439880629839..bb1ae400ec1f 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -982,29 +982,47 @@ static int acpi_s2idle_prepare_late(void) static void acpi_s2idle_sync(void) { - /* - * The EC driver uses the system workqueue and an additional special - * one, so those need to be flushed too. - */ + /* The EC driver uses special workqueues that need to be flushed. */ acpi_ec_flush_work(); acpi_os_wait_events_complete(); /* synchronize Notify handling */ } -static void acpi_s2idle_wake(void) +static bool acpi_s2idle_wake(void) { - /* - * If IRQD_WAKEUP_ARMED is set for the SCI at this point, the SCI has - * not triggered while suspended, so bail out. - */ - if (!acpi_sci_irq_valid() || - irqd_is_wakeup_armed(irq_get_irq_data(acpi_sci_irq))) - return; + if (!acpi_sci_irq_valid()) + return pm_wakeup_pending(); + + while (pm_wakeup_pending()) { + /* + * If IRQD_WAKEUP_ARMED is set for the SCI at this point, the + * SCI has not triggered while suspended, so bail out (the + * wakeup is pending anyway and the SCI is not the source of + * it). + */ + if (irqd_is_wakeup_armed(irq_get_irq_data(acpi_sci_irq))) + return true; + + /* + * If the status bit of any enabled fixed event is set, the + * wakeup is regarded as valid. + */ + if (acpi_any_fixed_event_status_set()) + return true; + + /* + * If the status bit is set for any enabled GPE other than the + * EC one, the wakeup is regarded as a genuine one. + */ + if (acpi_ec_other_gpes_active()) + return true; + + /* + * If the EC GPE status bit has not been set, the wakeup is + * regarded as a spurious one. + */ + if (!acpi_ec_dispatch_gpe()) + return false; - /* - * If there are EC events to process, the wakeup may be a spurious one - * coming from the EC. - */ - if (acpi_ec_dispatch_gpe()) { /* * Cancel the wakeup and process all pending events in case * there are any wakeup ones in there. @@ -1017,8 +1035,19 @@ static void acpi_s2idle_wake(void) acpi_s2idle_sync(); + /* + * The SCI is in the "suspended" state now and it cannot produce + * new wakeup events till the rearming below, so if any of them + * are pending here, they must be resulting from the processing + * of EC events above or coming from somewhere else. + */ + if (pm_wakeup_pending()) + return true; + rearm_wake_irq(acpi_sci_irq); } + + return false; } static void acpi_s2idle_restore_early(void) diff --git a/drivers/acpi/tiny-power-button.c b/drivers/acpi/tiny-power-button.c new file mode 100644 index 000000000000..6273d73c0b59 --- /dev/null +++ b/drivers/acpi/tiny-power-button.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include <linux/module.h> +#include <linux/sched/signal.h> +#include <linux/acpi.h> +#include <acpi/button.h> + +ACPI_MODULE_NAME("tiny-power-button"); +MODULE_AUTHOR("Josh Triplett"); +MODULE_DESCRIPTION("ACPI Tiny Power Button Driver"); +MODULE_LICENSE("GPL"); + +static int power_signal __read_mostly = CONFIG_ACPI_TINY_POWER_BUTTON_SIGNAL; +module_param(power_signal, int, 0644); +MODULE_PARM_DESC(power_signal, "Power button sends this signal to init"); + +static const struct acpi_device_id tiny_power_button_device_ids[] = { + { ACPI_BUTTON_HID_POWER, 0 }, + { ACPI_BUTTON_HID_POWERF, 0 }, + { "", 0 }, +}; +MODULE_DEVICE_TABLE(acpi, tiny_power_button_device_ids); + +static int acpi_noop_add_remove(struct acpi_device *device) +{ + return 0; +} + +static void acpi_tiny_power_button_notify(struct acpi_device *device, u32 event) +{ + kill_cad_pid(power_signal, 1); +} + +static struct acpi_driver acpi_tiny_power_button_driver = { + .name = "tiny-power-button", + .class = "tiny-power-button", + .ids = tiny_power_button_device_ids, + .ops = { + .add = acpi_noop_add_remove, + .remove = acpi_noop_add_remove, + .notify = acpi_tiny_power_button_notify, + }, +}; + +module_driver(acpi_tiny_power_button_driver, + acpi_bus_register_driver, + acpi_bus_unregister_driver); diff --git a/drivers/acpi/wakeup.c b/drivers/acpi/wakeup.c index 9614126bf56e..c28244df56a5 100644 --- a/drivers/acpi/wakeup.c +++ b/drivers/acpi/wakeup.c @@ -30,12 +30,10 @@ ACPI_MODULE_NAME("wakeup_devices") */ void acpi_enable_wakeup_devices(u8 sleep_state) { - struct list_head *node, *next; - - list_for_each_safe(node, next, &acpi_wakeup_device_list) { - struct acpi_device *dev = - container_of(node, struct acpi_device, wakeup_list); + struct acpi_device *dev, *tmp; + list_for_each_entry_safe(dev, tmp, &acpi_wakeup_device_list, + wakeup_list) { if (!dev->wakeup.flags.valid || sleep_state > (u32) dev->wakeup.sleep_state || !(device_may_wakeup(&dev->dev) @@ -57,12 +55,10 @@ void acpi_enable_wakeup_devices(u8 sleep_state) */ void acpi_disable_wakeup_devices(u8 sleep_state) { - struct list_head *node, *next; - - list_for_each_safe(node, next, &acpi_wakeup_device_list) { - struct acpi_device *dev = - container_of(node, struct acpi_device, wakeup_list); + struct acpi_device *dev, *tmp; + list_for_each_entry_safe(dev, tmp, &acpi_wakeup_device_list, + wakeup_list) { if (!dev->wakeup.flags.valid || sleep_state > (u32) dev->wakeup.sleep_state || !(device_may_wakeup(&dev->dev) @@ -79,13 +75,11 @@ void acpi_disable_wakeup_devices(u8 sleep_state) int __init acpi_wakeup_device_init(void) { - struct list_head *node, *next; + struct acpi_device *dev, *tmp; mutex_lock(&acpi_device_lock); - list_for_each_safe(node, next, &acpi_wakeup_device_list) { - struct acpi_device *dev = container_of(node, - struct acpi_device, - wakeup_list); + list_for_each_entry_safe(dev, tmp, &acpi_wakeup_device_list, + wakeup_list) { if (device_can_wakeup(&dev->dev)) { /* Button GPEs are supposed to be always enabled. */ acpi_enable_gpe(dev->wakeup.gpe_device, diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c index 697a6b12d6b9..bdc1ba00aee9 100644 --- a/drivers/acpi/x86/utils.c +++ b/drivers/acpi/x86/utils.c @@ -37,7 +37,7 @@ struct always_present_id { const char *uid; }; -#define ICPU(model) { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, } +#define X86_MATCH(model) X86_MATCH_INTEL_FAM6_MODEL(model, NULL) #define ENTRY(hid, uid, cpu_models, dmi...) { \ { { hid, }, {} }, \ @@ -51,29 +51,29 @@ static const struct always_present_id always_present_ids[] = { * Bay / Cherry Trail PWM directly poked by GPU driver in win10, * but Linux uses a separate PWM driver, harmless if not used. */ - ENTRY("80860F09", "1", ICPU(INTEL_FAM6_ATOM_SILVERMONT), {}), - ENTRY("80862288", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {}), + ENTRY("80860F09", "1", X86_MATCH(ATOM_SILVERMONT), {}), + ENTRY("80862288", "1", X86_MATCH(ATOM_AIRMONT), {}), /* Lenovo Yoga Book uses PWM2 for keyboard backlight control */ - ENTRY("80862289", "2", ICPU(INTEL_FAM6_ATOM_AIRMONT), { + ENTRY("80862289", "2", X86_MATCH(ATOM_AIRMONT), { DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X9"), }), /* * The INT0002 device is necessary to clear wakeup interrupt sources * on Cherry Trail devices, without it we get nobody cared IRQ msgs. */ - ENTRY("INT0002", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {}), + ENTRY("INT0002", "1", X86_MATCH(ATOM_AIRMONT), {}), /* * On the Dell Venue 11 Pro 7130 and 7139, the DSDT hides * the touchscreen ACPI device until a certain time * after _SB.PCI0.GFX0.LCD.LCD1._ON gets called has passed * *and* _STA has been called at least 3 times since. */ - ENTRY("SYNA7500", "1", ICPU(INTEL_FAM6_HASWELL_L), { + ENTRY("SYNA7500", "1", X86_MATCH(HASWELL_L), { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "Venue 11 Pro 7130"), }), - ENTRY("SYNA7500", "1", ICPU(INTEL_FAM6_HASWELL_L), { + ENTRY("SYNA7500", "1", X86_MATCH(HASWELL_L), { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "Venue 11 Pro 7139"), }), @@ -89,19 +89,19 @@ static const struct always_present_id always_present_ids[] = { * was copy-pasted from the GPD win, so it has a disabled KIOX000A * node which we should not enable, thus we also check the BIOS date. */ - ENTRY("KIOX000A", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), { + ENTRY("KIOX000A", "1", X86_MATCH(ATOM_AIRMONT), { DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), DMI_MATCH(DMI_BOARD_NAME, "Default string"), DMI_MATCH(DMI_PRODUCT_NAME, "Default string"), DMI_MATCH(DMI_BIOS_DATE, "02/21/2017") }), - ENTRY("KIOX000A", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), { + ENTRY("KIOX000A", "1", X86_MATCH(ATOM_AIRMONT), { DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), DMI_MATCH(DMI_BOARD_NAME, "Default string"), DMI_MATCH(DMI_PRODUCT_NAME, "Default string"), DMI_MATCH(DMI_BIOS_DATE, "03/20/2017") }), - ENTRY("KIOX000A", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), { + ENTRY("KIOX000A", "1", X86_MATCH(ATOM_AIRMONT), { DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), DMI_MATCH(DMI_BOARD_NAME, "Default string"), DMI_MATCH(DMI_PRODUCT_NAME, "Default string"), |