diff options
author | Lv Zheng <lv.zheng@intel.com> | 2015-02-05 19:57:52 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-02-06 09:48:09 -0500 |
commit | ad479e7f47ca09c3f3190603ead4d01cf8fe6fa8 (patch) | |
tree | b9a5d11f9b458363e610c28ad83f98e886a3b2b5 | |
parent | a8d4fc227f312edea06bb4ebbeeb6db89c798e91 (diff) |
ACPI / EC: Introduce STARTED/STOPPED flags to replace BLOCKED flag
By using the 2 flags, we can indicate an inter-mediate state where the
current transactions should be completed while the new transactions should
be dropped.
The comparison of the old flag and the new flags:
Old New
about to set BLOCKED STOPPED set / STARTED set
BLOCKED set STOPPED clear / STARTED clear
BLOCKED clear STOPPED clear / STARTED set
A new period can be indicated by the 2 flags. The new period is between the
point where we are about to set BLOCKED and the point when the BLOCKED is
set. The new flags facilitate us with acpi_ec_started() check to allow the
EC transaction to be submitted during the new period. This period thus can
be used as a grace period for the EC transaction flushing.
The only functional change after applying this patch is:
1. The GPE enabling/disabling is protected by the EC specific lock. We can
do this because of recent ACPICA GPE API enhancement. This is reasonable
as the GPE disabling/enabling state should only be determined by the EC
driver's state machine which is protected by the EC spinlock.
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Tested-by: Ortwin Glück <odi@odi.ch>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r-- | drivers/acpi/ec.c | 65 |
1 files changed, 54 insertions, 11 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 55632539392d..a6179b71c573 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
@@ -80,7 +80,8 @@ enum { | |||
80 | EC_FLAGS_GPE_STORM, /* GPE storm detected */ | 80 | EC_FLAGS_GPE_STORM, /* GPE storm detected */ |
81 | EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and | 81 | EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and |
82 | * OpReg are installed */ | 82 | * OpReg are installed */ |
83 | EC_FLAGS_BLOCKED, /* Transactions are blocked */ | 83 | EC_FLAGS_STARTED, /* Driver is started */ |
84 | EC_FLAGS_STOPPED, /* Driver is stopped */ | ||
84 | }; | 85 | }; |
85 | 86 | ||
86 | #define ACPI_EC_COMMAND_POLL 0x01 /* Available for command byte */ | 87 | #define ACPI_EC_COMMAND_POLL 0x01 /* Available for command byte */ |
@@ -135,6 +136,16 @@ static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */ | |||
135 | static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */ | 136 | static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */ |
136 | 137 | ||
137 | /* -------------------------------------------------------------------------- | 138 | /* -------------------------------------------------------------------------- |
139 | * Device Flags | ||
140 | * -------------------------------------------------------------------------- */ | ||
141 | |||
142 | static bool acpi_ec_started(struct acpi_ec *ec) | ||
143 | { | ||
144 | return test_bit(EC_FLAGS_STARTED, &ec->flags) && | ||
145 | !test_bit(EC_FLAGS_STOPPED, &ec->flags); | ||
146 | } | ||
147 | |||
148 | /* -------------------------------------------------------------------------- | ||
138 | * EC Registers | 149 | * EC Registers |
139 | * -------------------------------------------------------------------------- */ | 150 | * -------------------------------------------------------------------------- */ |
140 | 151 | ||
@@ -415,6 +426,10 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, | |||
415 | udelay(ACPI_EC_MSI_UDELAY); | 426 | udelay(ACPI_EC_MSI_UDELAY); |
416 | /* start transaction */ | 427 | /* start transaction */ |
417 | spin_lock_irqsave(&ec->lock, tmp); | 428 | spin_lock_irqsave(&ec->lock, tmp); |
429 | if (!acpi_ec_started(ec)) { | ||
430 | ret = -EINVAL; | ||
431 | goto unlock; | ||
432 | } | ||
418 | /* following two actions should be kept atomic */ | 433 | /* following two actions should be kept atomic */ |
419 | ec->curr = t; | 434 | ec->curr = t; |
420 | pr_debug("***** Command(%s) started *****\n", | 435 | pr_debug("***** Command(%s) started *****\n", |
@@ -426,6 +441,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, | |||
426 | pr_debug("***** Command(%s) stopped *****\n", | 441 | pr_debug("***** Command(%s) stopped *****\n", |
427 | acpi_ec_cmd_string(t->command)); | 442 | acpi_ec_cmd_string(t->command)); |
428 | ec->curr = NULL; | 443 | ec->curr = NULL; |
444 | unlock: | ||
429 | spin_unlock_irqrestore(&ec->lock, tmp); | 445 | spin_unlock_irqrestore(&ec->lock, tmp); |
430 | return ret; | 446 | return ret; |
431 | } | 447 | } |
@@ -440,10 +456,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) | |||
440 | if (t->rdata) | 456 | if (t->rdata) |
441 | memset(t->rdata, 0, t->rlen); | 457 | memset(t->rdata, 0, t->rlen); |
442 | mutex_lock(&ec->mutex); | 458 | mutex_lock(&ec->mutex); |
443 | if (test_bit(EC_FLAGS_BLOCKED, &ec->flags)) { | ||
444 | status = -EINVAL; | ||
445 | goto unlock; | ||
446 | } | ||
447 | if (ec->global_lock) { | 459 | if (ec->global_lock) { |
448 | status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); | 460 | status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); |
449 | if (ACPI_FAILURE(status)) { | 461 | if (ACPI_FAILURE(status)) { |
@@ -595,6 +607,37 @@ static void acpi_ec_clear(struct acpi_ec *ec) | |||
595 | pr_info("%d stale EC events cleared\n", i); | 607 | pr_info("%d stale EC events cleared\n", i); |
596 | } | 608 | } |
597 | 609 | ||
610 | static void acpi_ec_start(struct acpi_ec *ec, bool resuming) | ||
611 | { | ||
612 | unsigned long flags; | ||
613 | |||
614 | spin_lock_irqsave(&ec->lock, flags); | ||
615 | if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags)) { | ||
616 | pr_debug("+++++ Starting EC +++++\n"); | ||
617 | if (!resuming) | ||
618 | acpi_ec_enable_gpe(ec, true); | ||
619 | pr_info("+++++ EC started +++++\n"); | ||
620 | } | ||
621 | spin_unlock_irqrestore(&ec->lock, flags); | ||
622 | } | ||
623 | |||
624 | static void acpi_ec_stop(struct acpi_ec *ec, bool suspending) | ||
625 | { | ||
626 | unsigned long flags; | ||
627 | |||
628 | spin_lock_irqsave(&ec->lock, flags); | ||
629 | if (acpi_ec_started(ec)) { | ||
630 | pr_debug("+++++ Stopping EC +++++\n"); | ||
631 | set_bit(EC_FLAGS_STOPPED, &ec->flags); | ||
632 | if (!suspending) | ||
633 | acpi_ec_disable_gpe(ec, true); | ||
634 | clear_bit(EC_FLAGS_STARTED, &ec->flags); | ||
635 | clear_bit(EC_FLAGS_STOPPED, &ec->flags); | ||
636 | pr_info("+++++ EC stopped +++++\n"); | ||
637 | } | ||
638 | spin_unlock_irqrestore(&ec->lock, flags); | ||
639 | } | ||
640 | |||
598 | void acpi_ec_block_transactions(void) | 641 | void acpi_ec_block_transactions(void) |
599 | { | 642 | { |
600 | struct acpi_ec *ec = first_ec; | 643 | struct acpi_ec *ec = first_ec; |
@@ -604,7 +647,7 @@ void acpi_ec_block_transactions(void) | |||
604 | 647 | ||
605 | mutex_lock(&ec->mutex); | 648 | mutex_lock(&ec->mutex); |
606 | /* Prevent transactions from being carried out */ | 649 | /* Prevent transactions from being carried out */ |
607 | set_bit(EC_FLAGS_BLOCKED, &ec->flags); | 650 | acpi_ec_stop(ec, true); |
608 | mutex_unlock(&ec->mutex); | 651 | mutex_unlock(&ec->mutex); |
609 | } | 652 | } |
610 | 653 | ||
@@ -616,7 +659,7 @@ void acpi_ec_unblock_transactions(void) | |||
616 | return; | 659 | return; |
617 | 660 | ||
618 | /* Allow transactions to be carried out again */ | 661 | /* Allow transactions to be carried out again */ |
619 | clear_bit(EC_FLAGS_BLOCKED, &ec->flags); | 662 | acpi_ec_start(ec, true); |
620 | 663 | ||
621 | if (EC_FLAGS_CLEAR_ON_RESUME) | 664 | if (EC_FLAGS_CLEAR_ON_RESUME) |
622 | acpi_ec_clear(ec); | 665 | acpi_ec_clear(ec); |
@@ -629,7 +672,7 @@ void acpi_ec_unblock_transactions_early(void) | |||
629 | * atomic context during wakeup, so we don't need to acquire the mutex). | 672 | * atomic context during wakeup, so we don't need to acquire the mutex). |
630 | */ | 673 | */ |
631 | if (first_ec) | 674 | if (first_ec) |
632 | clear_bit(EC_FLAGS_BLOCKED, &first_ec->flags); | 675 | acpi_ec_start(first_ec, true); |
633 | } | 676 | } |
634 | 677 | ||
635 | /* -------------------------------------------------------------------------- | 678 | /* -------------------------------------------------------------------------- |
@@ -894,7 +937,7 @@ static int ec_install_handlers(struct acpi_ec *ec) | |||
894 | if (ACPI_FAILURE(status)) | 937 | if (ACPI_FAILURE(status)) |
895 | return -ENODEV; | 938 | return -ENODEV; |
896 | 939 | ||
897 | acpi_ec_enable_gpe(ec, true); | 940 | acpi_ec_start(ec, false); |
898 | status = acpi_install_address_space_handler(ec->handle, | 941 | status = acpi_install_address_space_handler(ec->handle, |
899 | ACPI_ADR_SPACE_EC, | 942 | ACPI_ADR_SPACE_EC, |
900 | &acpi_ec_space_handler, | 943 | &acpi_ec_space_handler, |
@@ -909,7 +952,7 @@ static int ec_install_handlers(struct acpi_ec *ec) | |||
909 | pr_err("Fail in evaluating the _REG object" | 952 | pr_err("Fail in evaluating the _REG object" |
910 | " of EC device. Broken bios is suspected.\n"); | 953 | " of EC device. Broken bios is suspected.\n"); |
911 | } else { | 954 | } else { |
912 | acpi_ec_disable_gpe(ec, true); | 955 | acpi_ec_stop(ec, false); |
913 | acpi_remove_gpe_handler(NULL, ec->gpe, | 956 | acpi_remove_gpe_handler(NULL, ec->gpe, |
914 | &acpi_ec_gpe_handler); | 957 | &acpi_ec_gpe_handler); |
915 | return -ENODEV; | 958 | return -ENODEV; |
@@ -924,7 +967,7 @@ static void ec_remove_handlers(struct acpi_ec *ec) | |||
924 | { | 967 | { |
925 | if (!test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags)) | 968 | if (!test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags)) |
926 | return; | 969 | return; |
927 | acpi_ec_disable_gpe(ec, true); | 970 | acpi_ec_stop(ec, false); |
928 | if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, | 971 | if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, |
929 | ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) | 972 | ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) |
930 | pr_err("failed to remove space handler\n"); | 973 | pr_err("failed to remove space handler\n"); |