aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLv Zheng <lv.zheng@intel.com>2016-08-03 04:01:36 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-08-30 18:32:10 -0400
commitc2b46d679b30c5c0d7eb47a21085943242bdd8dc (patch)
tree5e9503c6931ef99015e9ded039d9b4d0519dbc93
parente923e8e79e18fd6be9162f1be6b99a002e9df2cb (diff)
ACPI / EC: Add PM operations to improve event handling for resume process
This patch makes 2 changes: 1. Restore old behavior Originally, EC driver stops handling both events and transactions in acpi_ec_block_transactions(), and restarts to handle transactions in acpi_ec_unblock_transactions_early(), restarts to handle both events and transactions in acpi_ec_unblock_transactions(). While currently, EC driver still stops handling both events and transactions in acpi_ec_block_transactions(), but restarts to handle both events and transactions in acpi_ec_unblock_transactions_early(). This patch tries to restore the old behavior by dropping __acpi_ec_enable_event() from acpi_unblock_transactions_early(). 2. Improve old behavior However this still cannot fix the real issue as both of the acpi_ec_unblock_xxx() functions are invoked in the noirq stage. Since the EC driver actually doesn't implement the event handling in the polling mode, re-enabling the event handling too early in the noirq stage could result in the problem that if there is no triggering source causing advance_transaction() to be invoked, pending SCI_EVT cannot be detected by the EC driver and _Qxx cannot be triggered. It actually makes sense to restart the event handling in any point during resuming after the noirq stage. Just like the boot stage where the event handling is enabled in .add(), this patch further moves acpi_ec_enable_event() to .resume(). After doing that, the following 2 functions can be combined: acpi_ec_unblock_transactions_early()/acpi_ec_unblock_transactions(). The differences of the event handling availability between the old behavior (this patch isn't applied) and the new behavior (this patch is applied) are as follows: !Applied Applied before suspend Y Y suspend before EC Y Y suspend after EC Y Y suspend_late Y Y suspend_noirq Y (actually N) Y (actually N) resume_noirq Y (actually N) Y (actually N) resume_late Y (actually N) Y (actually N) resume before EC Y (actually N) Y (actually N) resume after EC Y (actually N) Y after resume Y (actually N) Y Where "actually N" means if there is no triggering source, the EC driver is actually not able to notice the pending SCI_EVT occurred in the noirq stage. So we can clearly see that this patch has improved the situation. Signed-off-by: Lv Zheng <lv.zheng@intel.com> Tested-by: Todd E Brandt <todd.e.brandt@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/acpi/ec.c26
-rw-r--r--drivers/acpi/internal.h1
-rw-r--r--drivers/acpi/sleep.c4
3 files changed, 13 insertions, 18 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 79305bed4164..8d5444defd7e 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -909,8 +909,7 @@ static void acpi_ec_start(struct acpi_ec *ec, bool resuming)
909 if (!resuming) { 909 if (!resuming) {
910 acpi_ec_submit_request(ec); 910 acpi_ec_submit_request(ec);
911 ec_dbg_ref(ec, "Increase driver"); 911 ec_dbg_ref(ec, "Increase driver");
912 } else 912 }
913 __acpi_ec_enable_event(ec);
914 ec_log_drv("EC started"); 913 ec_log_drv("EC started");
915 } 914 }
916 spin_unlock_irqrestore(&ec->lock, flags); 915 spin_unlock_irqrestore(&ec->lock, flags);
@@ -966,19 +965,6 @@ void acpi_ec_block_transactions(void)
966 965
967void acpi_ec_unblock_transactions(void) 966void acpi_ec_unblock_transactions(void)
968{ 967{
969 struct acpi_ec *ec = first_ec;
970
971 if (!ec)
972 return;
973
974 /* Allow transactions to be carried out again */
975 acpi_ec_start(ec, true);
976
977 acpi_ec_enable_event(ec);
978}
979
980void acpi_ec_unblock_transactions_early(void)
981{
982 /* 968 /*
983 * Allow transactions to happen again (this function is called from 969 * Allow transactions to happen again (this function is called from
984 * atomic context during wakeup, so we don't need to acquire the mutex). 970 * atomic context during wakeup, so we don't need to acquire the mutex).
@@ -1706,10 +1692,20 @@ static int acpi_ec_resume_noirq(struct device *dev)
1706 acpi_ec_leave_noirq(ec); 1692 acpi_ec_leave_noirq(ec);
1707 return 0; 1693 return 0;
1708} 1694}
1695
1696static int acpi_ec_resume(struct device *dev)
1697{
1698 struct acpi_ec *ec =
1699 acpi_driver_data(to_acpi_device(dev));
1700
1701 acpi_ec_enable_event(ec);
1702 return 0;
1703}
1709#endif 1704#endif
1710 1705
1711static const struct dev_pm_ops acpi_ec_pm = { 1706static const struct dev_pm_ops acpi_ec_pm = {
1712 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(acpi_ec_suspend_noirq, acpi_ec_resume_noirq) 1707 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(acpi_ec_suspend_noirq, acpi_ec_resume_noirq)
1708 SET_SYSTEM_SLEEP_PM_OPS(NULL, acpi_ec_resume)
1713}; 1709};
1714 1710
1715static int param_set_event_clearing(const char *val, struct kernel_param *kp) 1711static int param_set_event_clearing(const char *val, struct kernel_param *kp)
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 6996121ee003..29f206318d3d 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -189,7 +189,6 @@ int acpi_ec_ecdt_probe(void);
189int acpi_ec_dsdt_probe(void); 189int acpi_ec_dsdt_probe(void);
190void acpi_ec_block_transactions(void); 190void acpi_ec_block_transactions(void);
191void acpi_ec_unblock_transactions(void); 191void acpi_ec_unblock_transactions(void);
192void acpi_ec_unblock_transactions_early(void);
193int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, 192int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
194 acpi_handle handle, acpi_ec_query_func func, 193 acpi_handle handle, acpi_ec_query_func func,
195 void *data); 194 void *data);
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 2b38c1bb0446..bb1e0d21f828 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -586,7 +586,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
586 */ 586 */
587 acpi_disable_all_gpes(); 587 acpi_disable_all_gpes();
588 /* Allow EC transactions to happen. */ 588 /* Allow EC transactions to happen. */
589 acpi_ec_unblock_transactions_early(); 589 acpi_ec_unblock_transactions();
590 590
591 suspend_nvs_restore(); 591 suspend_nvs_restore();
592 592
@@ -784,7 +784,7 @@ static void acpi_hibernation_leave(void)
784 /* Restore the NVS memory area */ 784 /* Restore the NVS memory area */
785 suspend_nvs_restore(); 785 suspend_nvs_restore();
786 /* Allow EC transactions to happen. */ 786 /* Allow EC transactions to happen. */
787 acpi_ec_unblock_transactions_early(); 787 acpi_ec_unblock_transactions();
788} 788}
789 789
790static void acpi_pm_thaw(void) 790static void acpi_pm_thaw(void)