aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/ec.c
diff options
context:
space:
mode:
authorLv Zheng <lv.zheng@intel.com>2015-06-11 01:21:32 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-06-15 08:35:59 -0400
commit9d8993be2d9149bc8b3132dad030ff5960f5abcc (patch)
treec1f8582120cb66910739a0a62b66a3cd57a8090e /drivers/acpi/ec.c
parentf8b8eb71533338654f39211a87efeca35055566b (diff)
ACPI / EC: Convert event handling work queue into loop style.
During the period that a work queue is scheduled (queued up for run) but hasn't been run, second schedule_work() could fail. This may not lead to the loss of queries because QR_EC is always ensured to be submitted after the work queue has been in the running state. The event handling work queue can be changed into the loop style to allow us to control the code in a more flexible way: 1. Makes it possible to add event=0x00 termination condition in the loop. 2. Increases the thoughput of the QR_EC transactions as the 2nd+ QR_EC transactions may be handled in the same work item used for the 1st QR_EC transaction, thus the delay caused by the 2nd+ work item scheduling can be eliminated. Except the logging message changes and the throughput improvement, this patch is just a funcitonal no-op. Signed-off-by: Lv Zheng <lv.zheng@intel.com> Tested-by: Gabriele Mazzotta <gabriele.mzt@gmail.com> Tested-by: Tigran Gabrielyan <tigrangab@gmail.com> Tested-by: Adrien D <ghbdtn@openmailbox.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/ec.c')
-rw-r--r--drivers/acpi/ec.c33
1 files changed, 24 insertions, 9 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 0ce8b6e8c3e8..824f3e85023e 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -384,7 +384,9 @@ static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec)
384static void acpi_ec_submit_query(struct acpi_ec *ec) 384static void acpi_ec_submit_query(struct acpi_ec *ec)
385{ 385{
386 if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { 386 if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
387 ec_dbg_req("Event started"); 387 ec_dbg_evt("Command(%s) submitted/blocked",
388 acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
389 ec->nr_pending_queries++;
388 schedule_work(&ec->work); 390 schedule_work(&ec->work);
389 } 391 }
390} 392}
@@ -393,7 +395,8 @@ static void acpi_ec_complete_query(struct acpi_ec *ec)
393{ 395{
394 if (test_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { 396 if (test_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
395 clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); 397 clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
396 ec_dbg_req("Event stopped"); 398 ec_dbg_evt("Command(%s) unblocked",
399 acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
397 } 400 }
398} 401}
399 402
@@ -460,8 +463,8 @@ static void advance_transaction(struct acpi_ec *ec)
460 if (t->rlen == t->ri) { 463 if (t->rlen == t->ri) {
461 ec_transaction_transition(ec, ACPI_EC_COMMAND_COMPLETE); 464 ec_transaction_transition(ec, ACPI_EC_COMMAND_COMPLETE);
462 if (t->command == ACPI_EC_COMMAND_QUERY) 465 if (t->command == ACPI_EC_COMMAND_QUERY)
463 ec_dbg_req("Command(%s) hardware completion", 466 ec_dbg_evt("Command(%s) completed by hardware",
464 acpi_ec_cmd_string(t->command)); 467 acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
465 wakeup = true; 468 wakeup = true;
466 } 469 }
467 } else 470 } else
@@ -479,8 +482,8 @@ static void advance_transaction(struct acpi_ec *ec)
479 ec_transaction_transition(ec, ACPI_EC_COMMAND_POLL); 482 ec_transaction_transition(ec, ACPI_EC_COMMAND_POLL);
480 t->rdata[t->ri++] = 0x00; 483 t->rdata[t->ri++] = 0x00;
481 ec_transaction_transition(ec, ACPI_EC_COMMAND_COMPLETE); 484 ec_transaction_transition(ec, ACPI_EC_COMMAND_COMPLETE);
482 ec_dbg_req("Command(%s) software completion", 485 ec_dbg_evt("Command(%s) completed by software",
483 acpi_ec_cmd_string(t->command)); 486 acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
484 wakeup = true; 487 wakeup = true;
485 } else if ((status & ACPI_EC_FLAG_IBF) == 0) { 488 } else if ((status & ACPI_EC_FLAG_IBF) == 0) {
486 acpi_ec_write_cmd(ec, t->command); 489 acpi_ec_write_cmd(ec, t->command);
@@ -961,11 +964,23 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
961 return result; 964 return result;
962} 965}
963 966
964static void acpi_ec_gpe_poller(struct work_struct *work) 967static void acpi_ec_event_handler(struct work_struct *work)
965{ 968{
969 unsigned long flags;
966 struct acpi_ec *ec = container_of(work, struct acpi_ec, work); 970 struct acpi_ec *ec = container_of(work, struct acpi_ec, work);
967 971
968 acpi_ec_query(ec, NULL); 972 ec_dbg_evt("Event started");
973
974 spin_lock_irqsave(&ec->lock, flags);
975 while (ec->nr_pending_queries) {
976 spin_unlock_irqrestore(&ec->lock, flags);
977 (void)acpi_ec_query(ec, NULL);
978 spin_lock_irqsave(&ec->lock, flags);
979 ec->nr_pending_queries--;
980 }
981 spin_unlock_irqrestore(&ec->lock, flags);
982
983 ec_dbg_evt("Event stopped");
969} 984}
970 985
971static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, 986static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
@@ -1040,7 +1055,7 @@ static struct acpi_ec *make_acpi_ec(void)
1040 init_waitqueue_head(&ec->wait); 1055 init_waitqueue_head(&ec->wait);
1041 INIT_LIST_HEAD(&ec->list); 1056 INIT_LIST_HEAD(&ec->list);
1042 spin_lock_init(&ec->lock); 1057 spin_lock_init(&ec->lock);
1043 INIT_WORK(&ec->work, acpi_ec_gpe_poller); 1058 INIT_WORK(&ec->work, acpi_ec_event_handler);
1044 ec->timestamp = jiffies; 1059 ec->timestamp = jiffies;
1045 return ec; 1060 return ec;
1046} 1061}