From 4c237371f290d1ed3b2071dd43554362137b1cce Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 4 Jan 2017 11:17:17 +0800 Subject: ACPI / EC: Remove old CLEAR_ON_RESUME quirk IRQ polling logic has been implemented to drain the post-boot/resume EC events: 1. Triggered by the following code, invoked from acpi_ec_enable_event(): if (!test_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) advance_transaction(ec); 2. Drained by the following code, invoked after acpi_ec_complete_query(): if (status & ACPI_EC_FLAG_SCI) acpi_ec_submit_query(ec); This facility is safer than the old CLEAR_ON_RESUME quirk as the CLEAR_ON_RESUME quirk sends EC query commands unconditionally. The behavior is apparently not suitable for firmware that requires QUERY_HANDSHAKE quirk. Though the QUERY_HANDSHAKE quirk isn't used now because of the improvement done in the EC transaction state machine (ec_event_clearing=QUERY), it is the proof that we cannot send EC query command unconditionally. So it's time to delete the out-dated CLEAR_ON_RESUME quirk to let the users to try the newer approach. Link: https://bugzilla.kernel.org/show_bug.cgi?id=191211 Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 53 ----------------------------------------------------- 1 file changed, 53 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 48e19d013170..6a32cd4ec9da 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -188,7 +188,6 @@ EXPORT_SYMBOL(first_ec); static bool boot_ec_is_ecdt = false; static struct workqueue_struct *ec_query_wq; -static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */ 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 */ @@ -492,26 +491,6 @@ static inline void __acpi_ec_disable_event(struct acpi_ec *ec) ec_log_drv("event blocked"); } -/* - * Process _Q events that might have accumulated in the EC. - * Run with locked ec mutex. - */ -static void acpi_ec_clear(struct acpi_ec *ec) -{ - int i, status; - u8 value = 0; - - for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) { - status = acpi_ec_query(ec, &value); - if (status || !value) - break; - } - if (unlikely(i == ACPI_EC_CLEAR_MAX)) - pr_warn("Warning: Maximum of %d stale EC events cleared\n", i); - else - pr_info("%d stale EC events cleared\n", i); -} - static void acpi_ec_enable_event(struct acpi_ec *ec) { unsigned long flags; @@ -520,10 +499,6 @@ static void acpi_ec_enable_event(struct acpi_ec *ec) if (acpi_ec_started(ec)) __acpi_ec_enable_event(ec); spin_unlock_irqrestore(&ec->lock, flags); - - /* Drain additional events if hardware requires that */ - if (EC_FLAGS_CLEAR_ON_RESUME) - acpi_ec_clear(ec); } #ifdef CONFIG_PM_SLEEP @@ -1740,31 +1715,6 @@ static int ec_flag_query_handshake(const struct dmi_system_id *id) } #endif -/* - * On some hardware it is necessary to clear events accumulated by the EC during - * sleep. These ECs stop reporting GPEs until they are manually polled, if too - * many events are accumulated. (e.g. Samsung Series 5/9 notebooks) - * - * https://bugzilla.kernel.org/show_bug.cgi?id=44161 - * - * Ideally, the EC should also be instructed NOT to accumulate events during - * sleep (which Windows seems to do somehow), but the interface to control this - * behaviour is not known at this time. - * - * Models known to be affected are Samsung 530Uxx/535Uxx/540Uxx/550Pxx/900Xxx, - * however it is very likely that other Samsung models are affected. - * - * On systems which don't accumulate _Q events during sleep, this extra check - * should be harmless. - */ -static int ec_clear_on_resume(const struct dmi_system_id *id) -{ - pr_debug("Detected system needing EC poll on resume.\n"); - EC_FLAGS_CLEAR_ON_RESUME = 1; - ec_event_clearing = ACPI_EC_EVT_TIMING_STATUS; - return 0; -} - /* * Some ECDTs contain wrong register addresses. * MSI MS-171F @@ -1782,9 +1732,6 @@ static struct dmi_system_id ec_dmi_table[] __initdata = { ec_correct_ecdt, "MSI MS-171F", { DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star"), DMI_MATCH(DMI_PRODUCT_NAME, "MS-171F"),}, NULL}, - { - ec_clear_on_resume, "Samsung hardware", { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL}, {}, }; -- cgit From c3a696b6e8f8f75f9f75e556a9f9f6472eae2655 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 20 Jan 2017 16:42:48 +0800 Subject: ACPI / EC: Use busy polling mode when GPE is not enabled When GPE is not enabled, it is not efficient to use the wait polling mode as it introduces an unexpected scheduler delay. So before the GPE handler is installed, this patch uses busy polling mode for all EC(s) and the logic can be applied to non boot EC(s) during the suspend/resume process. Link: https://bugzilla.kernel.org/show_bug.cgi?id=191561 Tested-by: Jakobus Schurz Tested-by: Chen Yu Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 62 ++++++++++++++++++++++++------------------------- drivers/acpi/internal.h | 4 ++-- 2 files changed, 32 insertions(+), 34 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 6a32cd4ec9da..c24235d8fb52 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -704,12 +704,12 @@ static void start_transaction(struct acpi_ec *ec) static int ec_guard(struct acpi_ec *ec) { - unsigned long guard = usecs_to_jiffies(ec_polling_guard); + unsigned long guard = usecs_to_jiffies(ec->polling_guard); unsigned long timeout = ec->timestamp + guard; /* Ensure guarding period before polling EC status */ do { - if (ec_busy_polling) { + if (ec->busy_polling) { /* Perform busy polling */ if (ec_transaction_completed(ec)) return 0; @@ -973,6 +973,28 @@ static void acpi_ec_stop(struct acpi_ec *ec, bool suspending) spin_unlock_irqrestore(&ec->lock, flags); } +static void acpi_ec_enter_noirq(struct acpi_ec *ec) +{ + unsigned long flags; + + spin_lock_irqsave(&ec->lock, flags); + ec->busy_polling = true; + ec->polling_guard = 0; + ec_log_drv("interrupt blocked"); + spin_unlock_irqrestore(&ec->lock, flags); +} + +static void acpi_ec_leave_noirq(struct acpi_ec *ec) +{ + unsigned long flags; + + spin_lock_irqsave(&ec->lock, flags); + ec->busy_polling = ec_busy_polling; + ec->polling_guard = ec_polling_guard; + ec_log_drv("interrupt unblocked"); + spin_unlock_irqrestore(&ec->lock, flags); +} + void acpi_ec_block_transactions(void) { struct acpi_ec *ec = first_ec; @@ -1253,7 +1275,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, if (function != ACPI_READ && function != ACPI_WRITE) return AE_BAD_PARAMETER; - if (ec_busy_polling || bits > 8) + if (ec->busy_polling || bits > 8) acpi_ec_burst_enable(ec); for (i = 0; i < bytes; ++i, ++address, ++value) @@ -1261,7 +1283,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, acpi_ec_read(ec, address, value) : acpi_ec_write(ec, address, *value); - if (ec_busy_polling || bits > 8) + if (ec->busy_polling || bits > 8) acpi_ec_burst_disable(ec); switch (result) { @@ -1304,6 +1326,8 @@ static struct acpi_ec *acpi_ec_alloc(void) spin_lock_init(&ec->lock); INIT_WORK(&ec->work, acpi_ec_event_handler); ec->timestamp = jiffies; + ec->busy_polling = true; + ec->polling_guard = 0; return ec; } @@ -1365,6 +1389,7 @@ static int ec_install_handlers(struct acpi_ec *ec, bool handle_events) acpi_ec_start(ec, false); if (!test_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags)) { + acpi_ec_enter_noirq(ec); status = acpi_install_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler, @@ -1404,6 +1429,7 @@ static int ec_install_handlers(struct acpi_ec *ec, bool handle_events) /* This is not fatal as we can poll EC events */ if (ACPI_SUCCESS(status)) { set_bit(EC_FLAGS_GPE_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); @@ -1786,34 +1812,6 @@ error: } #ifdef CONFIG_PM_SLEEP -static void acpi_ec_enter_noirq(struct acpi_ec *ec) -{ - unsigned long flags; - - if (ec == first_ec) { - spin_lock_irqsave(&ec->lock, flags); - ec->saved_busy_polling = ec_busy_polling; - ec->saved_polling_guard = ec_polling_guard; - ec_busy_polling = true; - ec_polling_guard = 0; - ec_log_drv("interrupt blocked"); - spin_unlock_irqrestore(&ec->lock, flags); - } -} - -static void acpi_ec_leave_noirq(struct acpi_ec *ec) -{ - unsigned long flags; - - if (ec == first_ec) { - spin_lock_irqsave(&ec->lock, flags); - ec_busy_polling = ec->saved_busy_polling; - ec_polling_guard = ec->saved_polling_guard; - ec_log_drv("interrupt unblocked"); - spin_unlock_irqrestore(&ec->lock, flags); - } -} - static int acpi_ec_suspend_noirq(struct device *dev) { struct acpi_ec *ec = diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 0c452265c111..219b90bc0922 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -172,8 +172,8 @@ struct acpi_ec { struct work_struct work; unsigned long timestamp; unsigned long nr_pending_queries; - bool saved_busy_polling; - unsigned int saved_polling_guard; + bool busy_polling; + unsigned int polling_guard; }; extern struct acpi_ec *first_ec; -- cgit From 77e9a4aa9de10cc1418bf9a892366988802a8025 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 12 Jan 2017 15:47:34 +0800 Subject: ACPI / button: Change default behavior to lid_init_state=open More and more platforms need the button.lid_init_state=open quirk. This patch sets it the default behavior. If a platform doesn't send lid open event or lid open event is lost due to the underlying system problems, then we can compare various combinations: 1. systemd/acpid is used to suspend system or not, systemd has a special logic forcing open event after resuming; 2. _LID returns a cached value or not. The result is as follows: 1. lid_init_state=method 1. cached 1. resumed by lid: (x) event=close (x) systemd=suspends again (x) acpid=suspends again (x) state=close 2. resumed by other: (o) event=close (x) systemd=suspends again (x) acpid=suspends again (o) state=close 2. non-cached 1. resumed by lid: (o) event=open (o) systemd=resumes (o) acpid=resumes (o) state=open 2. resumed by other: (o) event=close (x) systemd=suspends again (x) acpid=suspends again (o) state=close 2. lid_init_state=open 1. cached 1. resumed by lid: (o) event=open (o) systemd=resumes (o) acpid=resumes (x) state=close 2. resumed by other: (x) event=open (o) systemd=resumes (o) acpid=resumes (o) state=close 2. non-cached 1. resumed by lid: (o) event=open (o) systemd=resumes (o) acpid=resumes (o) state=open 2. resumed by other: (x) event=open (o) systemd=resumes (o) acpid=resumes (o) state=close 3. lid_init_state=ignore 1. cached 1. resumed by lid: (o) event=none (x) systemd=suspends again (o) acpid=resumes (x) state=close 2. resumed by other: (o) event=none (x) systemd=suspends again (o) acpid=resumes (o) state=close 2. non-cached 1. resumed by lid: (o) event=none (x) systemd=suspends again (o) acpid=resumes (o) state=open 2. resumed by other: (o) event=none (x) systemd=suspends again (o) acpid=resumes (o) state=close As a conclusion: 1. With systemd changed, lid_init_state=ignore has only one problem and the problem comes from an underlying issue, not userspace and kernel lid handling. 2. Without systemd changed, lid_init_state=open can be the default behavior as the pass ratio is not much worse than lid_init_state=ignore. 3. lid_init_state=method is buggy, we can have a separate patch to make it deprectated. Link: https://bugzilla.kernel.org/show_bug.cgi?id=187271 Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/button.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index e19f530f1083..6d5a8c1d3132 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -113,7 +113,7 @@ struct acpi_button { static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier); static struct acpi_device *lid_device; -static u8 lid_init_state = ACPI_BUTTON_LID_INIT_METHOD; +static u8 lid_init_state = ACPI_BUTTON_LID_INIT_OPEN; static unsigned long lid_report_interval __read_mostly = 500; module_param(lid_report_interval, ulong, 0644); -- cgit From ecb10b694b72ca5ea51b3c90a71ff2a11963425a Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 12 Jan 2017 15:47:40 +0800 Subject: ACPI / button: Remove lid_init_state=method mode The mode is buggy, and lid_init__state=open is more useful than this mode, so this patch makes it deprecated. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/button.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 6d5a8c1d3132..668137e4a069 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -57,7 +57,6 @@ #define ACPI_BUTTON_LID_INIT_IGNORE 0x00 #define ACPI_BUTTON_LID_INIT_OPEN 0x01 -#define ACPI_BUTTON_LID_INIT_METHOD 0x02 #define _COMPONENT ACPI_BUTTON_COMPONENT ACPI_MODULE_NAME("button"); @@ -377,9 +376,6 @@ static void acpi_lid_initialize_state(struct acpi_device *device) case ACPI_BUTTON_LID_INIT_OPEN: (void)acpi_lid_notify_state(device, 1); break; - case ACPI_BUTTON_LID_INIT_METHOD: - (void)acpi_lid_update_state(device); - break; case ACPI_BUTTON_LID_INIT_IGNORE: default: break; @@ -563,9 +559,6 @@ static int param_set_lid_init_state(const char *val, struct kernel_param *kp) if (!strncmp(val, "open", sizeof("open") - 1)) { lid_init_state = ACPI_BUTTON_LID_INIT_OPEN; pr_info("Notify initial lid state as open\n"); - } else if (!strncmp(val, "method", sizeof("method") - 1)) { - lid_init_state = ACPI_BUTTON_LID_INIT_METHOD; - pr_info("Notify initial lid state with _LID return value\n"); } else if (!strncmp(val, "ignore", sizeof("ignore") - 1)) { lid_init_state = ACPI_BUTTON_LID_INIT_IGNORE; pr_info("Do not notify initial lid state\n"); @@ -579,8 +572,6 @@ static int param_get_lid_init_state(char *buffer, struct kernel_param *kp) switch (lid_init_state) { case ACPI_BUTTON_LID_INIT_OPEN: return sprintf(buffer, "open"); - case ACPI_BUTTON_LID_INIT_METHOD: - return sprintf(buffer, "method"); case ACPI_BUTTON_LID_INIT_IGNORE: return sprintf(buffer, "ignore"); default: -- cgit From d222678426faa5b0a5c14a468f78c32beb089937 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 17 Jan 2017 14:57:20 +0000 Subject: ACPI, APEI, EINJ: fix malformed newline escape The pr_warn message has a malformed newline escape, add in the missing \ Signed-off-by: Colin Ian King Reviewed-by: Borislav Petkov Signed-off-by: Rafael J. Wysocki --- drivers/acpi/apei/einj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index eebb7e39c49c..ec50c32ea3da 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c @@ -711,7 +711,7 @@ static int __init einj_init(void) rc = einj_check_table(einj_tab); if (rc) { - pr_warn(FW_BUG "Invalid EINJ table.n"); + pr_warn(FW_BUG "Invalid EINJ table.\n"); return -EINVAL; } -- cgit