diff options
| -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"); |
