aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/ec.c68
-rw-r--r--drivers/acpi/internal.h1
2 files changed, 66 insertions, 3 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index a6179b71c573..1fa14634c3f6 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -145,6 +145,11 @@ static bool acpi_ec_started(struct acpi_ec *ec)
145 !test_bit(EC_FLAGS_STOPPED, &ec->flags); 145 !test_bit(EC_FLAGS_STOPPED, &ec->flags);
146} 146}
147 147
148static bool acpi_ec_flushed(struct acpi_ec *ec)
149{
150 return ec->reference_count == 1;
151}
152
148/* -------------------------------------------------------------------------- 153/* --------------------------------------------------------------------------
149 * EC Registers 154 * EC Registers
150 * -------------------------------------------------------------------------- */ 155 * -------------------------------------------------------------------------- */
@@ -266,6 +271,44 @@ static inline void acpi_ec_clear_gpe(struct acpi_ec *ec)
266 * Transaction Management 271 * Transaction Management
267 * -------------------------------------------------------------------------- */ 272 * -------------------------------------------------------------------------- */
268 273
274static void acpi_ec_submit_request(struct acpi_ec *ec)
275{
276 ec->reference_count++;
277 if (ec->reference_count == 1)
278 acpi_ec_enable_gpe(ec, true);
279}
280
281static void acpi_ec_complete_request(struct acpi_ec *ec)
282{
283 bool flushed = false;
284
285 ec->reference_count--;
286 if (ec->reference_count == 0)
287 acpi_ec_disable_gpe(ec, true);
288 flushed = acpi_ec_flushed(ec);
289 if (flushed)
290 wake_up(&ec->wait);
291}
292
293/*
294 * acpi_ec_submit_flushable_request() - Increase the reference count unless
295 * the flush operation is not in
296 * progress
297 * @ec: the EC device
298 *
299 * This function must be used before taking a new action that should hold
300 * the reference count. If this function returns false, then the action
301 * must be discarded or it will prevent the flush operation from being
302 * completed.
303 */
304static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec)
305{
306 if (!acpi_ec_started(ec))
307 return false;
308 acpi_ec_submit_request(ec);
309 return true;
310}
311
269static void acpi_ec_submit_query(struct acpi_ec *ec) 312static void acpi_ec_submit_query(struct acpi_ec *ec)
270{ 313{
271 if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { 314 if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
@@ -426,7 +469,8 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
426 udelay(ACPI_EC_MSI_UDELAY); 469 udelay(ACPI_EC_MSI_UDELAY);
427 /* start transaction */ 470 /* start transaction */
428 spin_lock_irqsave(&ec->lock, tmp); 471 spin_lock_irqsave(&ec->lock, tmp);
429 if (!acpi_ec_started(ec)) { 472 /* Enable GPE for command processing (IBF=0/OBF=1) */
473 if (!acpi_ec_submit_flushable_request(ec)) {
430 ret = -EINVAL; 474 ret = -EINVAL;
431 goto unlock; 475 goto unlock;
432 } 476 }
@@ -441,6 +485,8 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
441 pr_debug("***** Command(%s) stopped *****\n", 485 pr_debug("***** Command(%s) stopped *****\n",
442 acpi_ec_cmd_string(t->command)); 486 acpi_ec_cmd_string(t->command));
443 ec->curr = NULL; 487 ec->curr = NULL;
488 /* Disable GPE for command processing (IBF=0/OBF=1) */
489 acpi_ec_complete_request(ec);
444unlock: 490unlock:
445 spin_unlock_irqrestore(&ec->lock, tmp); 491 spin_unlock_irqrestore(&ec->lock, tmp);
446 return ret; 492 return ret;
@@ -614,13 +660,25 @@ static void acpi_ec_start(struct acpi_ec *ec, bool resuming)
614 spin_lock_irqsave(&ec->lock, flags); 660 spin_lock_irqsave(&ec->lock, flags);
615 if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags)) { 661 if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags)) {
616 pr_debug("+++++ Starting EC +++++\n"); 662 pr_debug("+++++ Starting EC +++++\n");
663 /* Enable GPE for event processing (SCI_EVT=1) */
617 if (!resuming) 664 if (!resuming)
618 acpi_ec_enable_gpe(ec, true); 665 acpi_ec_submit_request(ec);
619 pr_info("+++++ EC started +++++\n"); 666 pr_info("+++++ EC started +++++\n");
620 } 667 }
621 spin_unlock_irqrestore(&ec->lock, flags); 668 spin_unlock_irqrestore(&ec->lock, flags);
622} 669}
623 670
671static bool acpi_ec_stopped(struct acpi_ec *ec)
672{
673 unsigned long flags;
674 bool flushed;
675
676 spin_lock_irqsave(&ec->lock, flags);
677 flushed = acpi_ec_flushed(ec);
678 spin_unlock_irqrestore(&ec->lock, flags);
679 return flushed;
680}
681
624static void acpi_ec_stop(struct acpi_ec *ec, bool suspending) 682static void acpi_ec_stop(struct acpi_ec *ec, bool suspending)
625{ 683{
626 unsigned long flags; 684 unsigned long flags;
@@ -629,8 +687,12 @@ static void acpi_ec_stop(struct acpi_ec *ec, bool suspending)
629 if (acpi_ec_started(ec)) { 687 if (acpi_ec_started(ec)) {
630 pr_debug("+++++ Stopping EC +++++\n"); 688 pr_debug("+++++ Stopping EC +++++\n");
631 set_bit(EC_FLAGS_STOPPED, &ec->flags); 689 set_bit(EC_FLAGS_STOPPED, &ec->flags);
690 spin_unlock_irqrestore(&ec->lock, flags);
691 wait_event(ec->wait, acpi_ec_stopped(ec));
692 spin_lock_irqsave(&ec->lock, flags);
693 /* Disable GPE for event processing (SCI_EVT=1) */
632 if (!suspending) 694 if (!suspending)
633 acpi_ec_disable_gpe(ec, true); 695 acpi_ec_complete_request(ec);
634 clear_bit(EC_FLAGS_STARTED, &ec->flags); 696 clear_bit(EC_FLAGS_STARTED, &ec->flags);
635 clear_bit(EC_FLAGS_STOPPED, &ec->flags); 697 clear_bit(EC_FLAGS_STOPPED, &ec->flags);
636 pr_info("+++++ EC stopped +++++\n"); 698 pr_info("+++++ EC stopped +++++\n");
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index dc420787ffcd..7dc69d82f658 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -122,6 +122,7 @@ struct acpi_ec {
122 unsigned long data_addr; 122 unsigned long data_addr;
123 unsigned long global_lock; 123 unsigned long global_lock;
124 unsigned long flags; 124 unsigned long flags;
125 unsigned long reference_count;
125 struct mutex mutex; 126 struct mutex mutex;
126 wait_queue_head_t wait; 127 wait_queue_head_t wait;
127 struct list_head list; 128 struct list_head list;