diff options
author | Lv Zheng <lv.zheng@intel.com> | 2016-08-03 04:01:24 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-08-30 18:32:10 -0400 |
commit | 750f628be68e8b8e1624d8abd003b9f1fc758ed6 (patch) | |
tree | fe4ea4b8c29a0448420106ed5a7e4ed2ec793464 | |
parent | df45db6177f8dde380d44149cca46ad800a00575 (diff) |
ACPI / EC: Add EC_FLAGS_QUERY_ENABLED to reveal a hidden logic
There is a hidden logic in the EC driver:
1. During boot, EC_FLAGS_QUERY_PENDING is responsible for blocking event
handling;
2. During suspend, EC_FLAGS_STARTED is responsible for blocking event
handling.
This patch uses a new EC_FLAGS_QUERY_ENABLED flag to make this hidden
logic explicit and have code cleaned up. No functional change.
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.c | 103 |
1 files changed, 71 insertions, 32 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 6f6c7d1eaf8c..4ab34d7dd943 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
@@ -104,6 +104,7 @@ enum ec_command { | |||
104 | #define ACPI_EC_MAX_QUERIES 16 /* Maximum number of parallel queries */ | 104 | #define ACPI_EC_MAX_QUERIES 16 /* Maximum number of parallel queries */ |
105 | 105 | ||
106 | enum { | 106 | enum { |
107 | EC_FLAGS_QUERY_ENABLED, /* Query is enabled */ | ||
107 | EC_FLAGS_QUERY_PENDING, /* Query is pending */ | 108 | EC_FLAGS_QUERY_PENDING, /* Query is pending */ |
108 | EC_FLAGS_QUERY_GUARDING, /* Guard for SCI_EVT check */ | 109 | EC_FLAGS_QUERY_GUARDING, /* Guard for SCI_EVT check */ |
109 | EC_FLAGS_GPE_HANDLER_INSTALLED, /* GPE handler installed */ | 110 | EC_FLAGS_GPE_HANDLER_INSTALLED, /* GPE handler installed */ |
@@ -239,6 +240,22 @@ static bool acpi_ec_started(struct acpi_ec *ec) | |||
239 | !test_bit(EC_FLAGS_STOPPED, &ec->flags); | 240 | !test_bit(EC_FLAGS_STOPPED, &ec->flags); |
240 | } | 241 | } |
241 | 242 | ||
243 | static bool acpi_ec_event_enabled(struct acpi_ec *ec) | ||
244 | { | ||
245 | /* | ||
246 | * There is an OSPM early stage logic. During the early stages | ||
247 | * (boot/resume), OSPMs shouldn't enable the event handling, only | ||
248 | * the EC transactions are allowed to be performed. | ||
249 | */ | ||
250 | if (!test_bit(EC_FLAGS_QUERY_ENABLED, &ec->flags)) | ||
251 | return false; | ||
252 | /* | ||
253 | * The EC event handling is automatically disabled as soon as the | ||
254 | * EC driver is stopped. | ||
255 | */ | ||
256 | return test_bit(EC_FLAGS_STARTED, &ec->flags); | ||
257 | } | ||
258 | |||
242 | static bool acpi_ec_flushed(struct acpi_ec *ec) | 259 | static bool acpi_ec_flushed(struct acpi_ec *ec) |
243 | { | 260 | { |
244 | return ec->reference_count == 1; | 261 | return ec->reference_count == 1; |
@@ -429,7 +446,8 @@ static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec) | |||
429 | 446 | ||
430 | static void acpi_ec_submit_query(struct acpi_ec *ec) | 447 | static void acpi_ec_submit_query(struct acpi_ec *ec) |
431 | { | 448 | { |
432 | if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { | 449 | if (acpi_ec_event_enabled(ec) && |
450 | !test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { | ||
433 | ec_dbg_evt("Command(%s) submitted/blocked", | 451 | ec_dbg_evt("Command(%s) submitted/blocked", |
434 | acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY)); | 452 | acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY)); |
435 | ec->nr_pending_queries++; | 453 | ec->nr_pending_queries++; |
@@ -446,6 +464,52 @@ static void acpi_ec_complete_query(struct acpi_ec *ec) | |||
446 | } | 464 | } |
447 | } | 465 | } |
448 | 466 | ||
467 | static inline void __acpi_ec_enable_event(struct acpi_ec *ec) | ||
468 | { | ||
469 | if (!test_and_set_bit(EC_FLAGS_QUERY_ENABLED, &ec->flags)) | ||
470 | ec_log_drv("event unblocked"); | ||
471 | } | ||
472 | |||
473 | static inline void __acpi_ec_disable_event(struct acpi_ec *ec) | ||
474 | { | ||
475 | if (test_and_clear_bit(EC_FLAGS_QUERY_ENABLED, &ec->flags)) | ||
476 | ec_log_drv("event blocked"); | ||
477 | } | ||
478 | |||
479 | /* | ||
480 | * Process _Q events that might have accumulated in the EC. | ||
481 | * Run with locked ec mutex. | ||
482 | */ | ||
483 | static void acpi_ec_clear(struct acpi_ec *ec) | ||
484 | { | ||
485 | int i, status; | ||
486 | u8 value = 0; | ||
487 | |||
488 | for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) { | ||
489 | status = acpi_ec_query(ec, &value); | ||
490 | if (status || !value) | ||
491 | break; | ||
492 | } | ||
493 | if (unlikely(i == ACPI_EC_CLEAR_MAX)) | ||
494 | pr_warn("Warning: Maximum of %d stale EC events cleared\n", i); | ||
495 | else | ||
496 | pr_info("%d stale EC events cleared\n", i); | ||
497 | } | ||
498 | |||
499 | static void acpi_ec_enable_event(struct acpi_ec *ec) | ||
500 | { | ||
501 | unsigned long flags; | ||
502 | |||
503 | spin_lock_irqsave(&ec->lock, flags); | ||
504 | if (acpi_ec_started(ec)) | ||
505 | __acpi_ec_enable_event(ec); | ||
506 | spin_unlock_irqrestore(&ec->lock, flags); | ||
507 | |||
508 | /* Drain additional events if hardware requires that */ | ||
509 | if (EC_FLAGS_CLEAR_ON_RESUME) | ||
510 | acpi_ec_clear(ec); | ||
511 | } | ||
512 | |||
449 | static bool acpi_ec_guard_event(struct acpi_ec *ec) | 513 | static bool acpi_ec_guard_event(struct acpi_ec *ec) |
450 | { | 514 | { |
451 | bool guarded = true; | 515 | bool guarded = true; |
@@ -832,27 +896,6 @@ acpi_handle ec_get_handle(void) | |||
832 | } | 896 | } |
833 | EXPORT_SYMBOL(ec_get_handle); | 897 | EXPORT_SYMBOL(ec_get_handle); |
834 | 898 | ||
835 | /* | ||
836 | * Process _Q events that might have accumulated in the EC. | ||
837 | * Run with locked ec mutex. | ||
838 | */ | ||
839 | static void acpi_ec_clear(struct acpi_ec *ec) | ||
840 | { | ||
841 | int i, status; | ||
842 | u8 value = 0; | ||
843 | |||
844 | for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) { | ||
845 | status = acpi_ec_query(ec, &value); | ||
846 | if (status || !value) | ||
847 | break; | ||
848 | } | ||
849 | |||
850 | if (unlikely(i == ACPI_EC_CLEAR_MAX)) | ||
851 | pr_warn("Warning: Maximum of %d stale EC events cleared\n", i); | ||
852 | else | ||
853 | pr_info("%d stale EC events cleared\n", i); | ||
854 | } | ||
855 | |||
856 | static void acpi_ec_start(struct acpi_ec *ec, bool resuming) | 899 | static void acpi_ec_start(struct acpi_ec *ec, bool resuming) |
857 | { | 900 | { |
858 | unsigned long flags; | 901 | unsigned long flags; |
@@ -864,7 +907,8 @@ static void acpi_ec_start(struct acpi_ec *ec, bool resuming) | |||
864 | if (!resuming) { | 907 | if (!resuming) { |
865 | acpi_ec_submit_request(ec); | 908 | acpi_ec_submit_request(ec); |
866 | ec_dbg_ref(ec, "Increase driver"); | 909 | ec_dbg_ref(ec, "Increase driver"); |
867 | } | 910 | } else |
911 | __acpi_ec_enable_event(ec); | ||
868 | ec_log_drv("EC started"); | 912 | ec_log_drv("EC started"); |
869 | } | 913 | } |
870 | spin_unlock_irqrestore(&ec->lock, flags); | 914 | spin_unlock_irqrestore(&ec->lock, flags); |
@@ -896,7 +940,8 @@ static void acpi_ec_stop(struct acpi_ec *ec, bool suspending) | |||
896 | if (!suspending) { | 940 | if (!suspending) { |
897 | acpi_ec_complete_request(ec); | 941 | acpi_ec_complete_request(ec); |
898 | ec_dbg_ref(ec, "Decrease driver"); | 942 | ec_dbg_ref(ec, "Decrease driver"); |
899 | } | 943 | } else |
944 | __acpi_ec_disable_event(ec); | ||
900 | clear_bit(EC_FLAGS_STARTED, &ec->flags); | 945 | clear_bit(EC_FLAGS_STARTED, &ec->flags); |
901 | clear_bit(EC_FLAGS_STOPPED, &ec->flags); | 946 | clear_bit(EC_FLAGS_STOPPED, &ec->flags); |
902 | ec_log_drv("EC stopped"); | 947 | ec_log_drv("EC stopped"); |
@@ -927,8 +972,7 @@ void acpi_ec_unblock_transactions(void) | |||
927 | /* Allow transactions to be carried out again */ | 972 | /* Allow transactions to be carried out again */ |
928 | acpi_ec_start(ec, true); | 973 | acpi_ec_start(ec, true); |
929 | 974 | ||
930 | if (EC_FLAGS_CLEAR_ON_RESUME) | 975 | acpi_ec_enable_event(ec); |
931 | acpi_ec_clear(ec); | ||
932 | } | 976 | } |
933 | 977 | ||
934 | void acpi_ec_unblock_transactions_early(void) | 978 | void acpi_ec_unblock_transactions_early(void) |
@@ -1234,7 +1278,6 @@ static struct acpi_ec *make_acpi_ec(void) | |||
1234 | 1278 | ||
1235 | if (!ec) | 1279 | if (!ec) |
1236 | return NULL; | 1280 | return NULL; |
1237 | ec->flags = 1 << EC_FLAGS_QUERY_PENDING; | ||
1238 | mutex_init(&ec->mutex); | 1281 | mutex_init(&ec->mutex); |
1239 | init_waitqueue_head(&ec->wait); | 1282 | init_waitqueue_head(&ec->wait); |
1240 | INIT_LIST_HEAD(&ec->list); | 1283 | INIT_LIST_HEAD(&ec->list); |
@@ -1421,11 +1464,7 @@ static int acpi_ec_add(struct acpi_device *device) | |||
1421 | acpi_walk_dep_device_list(ec->handle); | 1464 | acpi_walk_dep_device_list(ec->handle); |
1422 | 1465 | ||
1423 | /* EC is fully operational, allow queries */ | 1466 | /* EC is fully operational, allow queries */ |
1424 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); | 1467 | acpi_ec_enable_event(ec); |
1425 | |||
1426 | /* Clear stale _Q events if hardware might require that */ | ||
1427 | if (EC_FLAGS_CLEAR_ON_RESUME) | ||
1428 | acpi_ec_clear(ec); | ||
1429 | return ret; | 1468 | return ret; |
1430 | } | 1469 | } |
1431 | 1470 | ||