diff options
Diffstat (limited to 'drivers/acpi/ec.c')
| -rw-r--r-- | drivers/acpi/ec.c | 97 |
1 files changed, 65 insertions, 32 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index ef42316f89f5..cf41f9fc24a7 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
| @@ -70,7 +70,7 @@ enum ec_command { | |||
| 70 | #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ | 70 | #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ |
| 71 | #define ACPI_EC_UDELAY 100 /* Wait 100us before polling EC again */ | 71 | #define ACPI_EC_UDELAY 100 /* Wait 100us before polling EC again */ |
| 72 | 72 | ||
| 73 | #define ACPI_EC_STORM_THRESHOLD 20 /* number of false interrupts | 73 | #define ACPI_EC_STORM_THRESHOLD 8 /* number of false interrupts |
| 74 | per one transaction */ | 74 | per one transaction */ |
| 75 | 75 | ||
| 76 | enum { | 76 | enum { |
| @@ -100,8 +100,11 @@ struct transaction { | |||
| 100 | u8 *rdata; | 100 | u8 *rdata; |
| 101 | unsigned short irq_count; | 101 | unsigned short irq_count; |
| 102 | u8 command; | 102 | u8 command; |
| 103 | u8 wi; | ||
| 104 | u8 ri; | ||
| 103 | u8 wlen; | 105 | u8 wlen; |
| 104 | u8 rlen; | 106 | u8 rlen; |
| 107 | bool done; | ||
| 105 | }; | 108 | }; |
| 106 | 109 | ||
| 107 | static struct acpi_ec { | 110 | static struct acpi_ec { |
| @@ -178,34 +181,45 @@ static int ec_transaction_done(struct acpi_ec *ec) | |||
| 178 | unsigned long flags; | 181 | unsigned long flags; |
| 179 | int ret = 0; | 182 | int ret = 0; |
| 180 | spin_lock_irqsave(&ec->curr_lock, flags); | 183 | spin_lock_irqsave(&ec->curr_lock, flags); |
| 181 | if (!ec->curr || (!ec->curr->wlen && !ec->curr->rlen)) | 184 | if (!ec->curr || ec->curr->done) |
| 182 | ret = 1; | 185 | ret = 1; |
| 183 | spin_unlock_irqrestore(&ec->curr_lock, flags); | 186 | spin_unlock_irqrestore(&ec->curr_lock, flags); |
| 184 | return ret; | 187 | return ret; |
| 185 | } | 188 | } |
| 186 | 189 | ||
| 190 | static void start_transaction(struct acpi_ec *ec) | ||
| 191 | { | ||
| 192 | ec->curr->irq_count = ec->curr->wi = ec->curr->ri = 0; | ||
| 193 | ec->curr->done = false; | ||
| 194 | acpi_ec_write_cmd(ec, ec->curr->command); | ||
| 195 | } | ||
| 196 | |||
| 187 | static void gpe_transaction(struct acpi_ec *ec, u8 status) | 197 | static void gpe_transaction(struct acpi_ec *ec, u8 status) |
| 188 | { | 198 | { |
| 189 | unsigned long flags; | 199 | unsigned long flags; |
| 190 | spin_lock_irqsave(&ec->curr_lock, flags); | 200 | spin_lock_irqsave(&ec->curr_lock, flags); |
| 191 | if (!ec->curr) | 201 | if (!ec->curr) |
| 192 | goto unlock; | 202 | goto unlock; |
| 193 | if (ec->curr->wlen > 0) { | 203 | if (ec->curr->wlen > ec->curr->wi) { |
| 194 | if ((status & ACPI_EC_FLAG_IBF) == 0) { | 204 | if ((status & ACPI_EC_FLAG_IBF) == 0) |
| 195 | acpi_ec_write_data(ec, *(ec->curr->wdata++)); | 205 | acpi_ec_write_data(ec, |
| 196 | --ec->curr->wlen; | 206 | ec->curr->wdata[ec->curr->wi++]); |
| 197 | } else | 207 | else |
| 198 | /* false interrupt, state didn't change */ | 208 | goto err; |
| 199 | ++ec->curr->irq_count; | 209 | } else if (ec->curr->rlen > ec->curr->ri) { |
| 200 | |||
| 201 | } else if (ec->curr->rlen > 0) { | ||
| 202 | if ((status & ACPI_EC_FLAG_OBF) == 1) { | 210 | if ((status & ACPI_EC_FLAG_OBF) == 1) { |
| 203 | *(ec->curr->rdata++) = acpi_ec_read_data(ec); | 211 | ec->curr->rdata[ec->curr->ri++] = acpi_ec_read_data(ec); |
| 204 | --ec->curr->rlen; | 212 | if (ec->curr->rlen == ec->curr->ri) |
| 213 | ec->curr->done = true; | ||
| 205 | } else | 214 | } else |
| 206 | /* false interrupt, state didn't change */ | 215 | goto err; |
| 207 | ++ec->curr->irq_count; | 216 | } else if (ec->curr->wlen == ec->curr->wi && |
| 208 | } | 217 | (status & ACPI_EC_FLAG_IBF) == 0) |
| 218 | ec->curr->done = true; | ||
| 219 | goto unlock; | ||
| 220 | err: | ||
| 221 | /* false interrupt, state didn't change */ | ||
| 222 | ++ec->curr->irq_count; | ||
| 209 | unlock: | 223 | unlock: |
| 210 | spin_unlock_irqrestore(&ec->curr_lock, flags); | 224 | spin_unlock_irqrestore(&ec->curr_lock, flags); |
| 211 | } | 225 | } |
| @@ -215,6 +229,15 @@ static int acpi_ec_wait(struct acpi_ec *ec) | |||
| 215 | if (wait_event_timeout(ec->wait, ec_transaction_done(ec), | 229 | if (wait_event_timeout(ec->wait, ec_transaction_done(ec), |
| 216 | msecs_to_jiffies(ACPI_EC_DELAY))) | 230 | msecs_to_jiffies(ACPI_EC_DELAY))) |
| 217 | return 0; | 231 | return 0; |
| 232 | /* try restart command if we get any false interrupts */ | ||
| 233 | if (ec->curr->irq_count && | ||
| 234 | (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) { | ||
| 235 | pr_debug(PREFIX "controller reset, restart transaction\n"); | ||
| 236 | start_transaction(ec); | ||
| 237 | if (wait_event_timeout(ec->wait, ec_transaction_done(ec), | ||
| 238 | msecs_to_jiffies(ACPI_EC_DELAY))) | ||
| 239 | return 0; | ||
| 240 | } | ||
| 218 | /* missing GPEs, switch back to poll mode */ | 241 | /* missing GPEs, switch back to poll mode */ |
| 219 | if (printk_ratelimit()) | 242 | if (printk_ratelimit()) |
| 220 | pr_info(PREFIX "missing confirmations, " | 243 | pr_info(PREFIX "missing confirmations, " |
| @@ -239,10 +262,10 @@ static int ec_check_sci(struct acpi_ec *ec, u8 state) | |||
| 239 | static int ec_poll(struct acpi_ec *ec) | 262 | static int ec_poll(struct acpi_ec *ec) |
| 240 | { | 263 | { |
| 241 | unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); | 264 | unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); |
| 242 | msleep(1); | 265 | udelay(ACPI_EC_UDELAY); |
| 243 | while (time_before(jiffies, delay)) { | 266 | while (time_before(jiffies, delay)) { |
| 244 | gpe_transaction(ec, acpi_ec_read_status(ec)); | 267 | gpe_transaction(ec, acpi_ec_read_status(ec)); |
| 245 | msleep(1); | 268 | udelay(ACPI_EC_UDELAY); |
| 246 | if (ec_transaction_done(ec)) | 269 | if (ec_transaction_done(ec)) |
| 247 | return 0; | 270 | return 0; |
| 248 | } | 271 | } |
| @@ -259,14 +282,13 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, | |||
| 259 | /* disable GPE during transaction if storm is detected */ | 282 | /* disable GPE during transaction if storm is detected */ |
| 260 | if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { | 283 | if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { |
| 261 | clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); | 284 | clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); |
| 262 | acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); | 285 | acpi_disable_gpe(NULL, ec->gpe); |
| 263 | } | 286 | } |
| 264 | /* start transaction */ | 287 | /* start transaction */ |
| 265 | spin_lock_irqsave(&ec->curr_lock, tmp); | 288 | spin_lock_irqsave(&ec->curr_lock, tmp); |
| 266 | /* following two actions should be kept atomic */ | 289 | /* following two actions should be kept atomic */ |
| 267 | t->irq_count = 0; | ||
| 268 | ec->curr = t; | 290 | ec->curr = t; |
| 269 | acpi_ec_write_cmd(ec, ec->curr->command); | 291 | start_transaction(ec); |
| 270 | if (ec->curr->command == ACPI_EC_COMMAND_QUERY) | 292 | if (ec->curr->command == ACPI_EC_COMMAND_QUERY) |
| 271 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); | 293 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); |
| 272 | spin_unlock_irqrestore(&ec->curr_lock, tmp); | 294 | spin_unlock_irqrestore(&ec->curr_lock, tmp); |
| @@ -283,10 +305,11 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, | |||
| 283 | /* check if we received SCI during transaction */ | 305 | /* check if we received SCI during transaction */ |
| 284 | ec_check_sci(ec, acpi_ec_read_status(ec)); | 306 | ec_check_sci(ec, acpi_ec_read_status(ec)); |
| 285 | /* it is safe to enable GPE outside of transaction */ | 307 | /* it is safe to enable GPE outside of transaction */ |
| 286 | acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); | 308 | acpi_enable_gpe(NULL, ec->gpe); |
| 287 | } else if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags) && | 309 | } else if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags) && |
| 288 | t->irq_count > ACPI_EC_STORM_THRESHOLD) { | 310 | t->irq_count > ACPI_EC_STORM_THRESHOLD) { |
| 289 | pr_debug(PREFIX "GPE storm detected\n"); | 311 | pr_info(PREFIX "GPE storm detected, " |
| 312 | "transactions will use polling mode\n"); | ||
| 290 | set_bit(EC_FLAGS_GPE_STORM, &ec->flags); | 313 | set_bit(EC_FLAGS_GPE_STORM, &ec->flags); |
| 291 | } | 314 | } |
| 292 | return ret; | 315 | return ret; |
| @@ -558,17 +581,26 @@ static u32 acpi_ec_gpe_handler(void *data) | |||
| 558 | pr_debug(PREFIX "~~~> interrupt\n"); | 581 | pr_debug(PREFIX "~~~> interrupt\n"); |
| 559 | status = acpi_ec_read_status(ec); | 582 | status = acpi_ec_read_status(ec); |
| 560 | 583 | ||
| 561 | gpe_transaction(ec, status); | 584 | if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) { |
| 562 | if (ec_transaction_done(ec) && (status & ACPI_EC_FLAG_IBF) == 0) | 585 | gpe_transaction(ec, status); |
| 563 | wake_up(&ec->wait); | 586 | if (ec_transaction_done(ec) && |
| 587 | (status & ACPI_EC_FLAG_IBF) == 0) | ||
| 588 | wake_up(&ec->wait); | ||
| 589 | } | ||
| 564 | 590 | ||
| 565 | ec_check_sci(ec, status); | 591 | ec_check_sci(ec, status); |
| 566 | if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) && | 592 | if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) && |
| 567 | !test_bit(EC_FLAGS_NO_GPE, &ec->flags)) { | 593 | !test_bit(EC_FLAGS_NO_GPE, &ec->flags)) { |
| 568 | /* this is non-query, must be confirmation */ | 594 | /* this is non-query, must be confirmation */ |
| 569 | if (printk_ratelimit()) | 595 | if (!test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { |
| 570 | pr_info(PREFIX "non-query interrupt received," | 596 | if (printk_ratelimit()) |
| 597 | pr_info(PREFIX "non-query interrupt received," | ||
| 598 | " switching to interrupt mode\n"); | ||
| 599 | } else { | ||
| 600 | /* hush, STORM switches the mode every transaction */ | ||
| 601 | pr_debug(PREFIX "non-query interrupt received," | ||
| 571 | " switching to interrupt mode\n"); | 602 | " switching to interrupt mode\n"); |
| 603 | } | ||
| 572 | set_bit(EC_FLAGS_GPE_MODE, &ec->flags); | 604 | set_bit(EC_FLAGS_GPE_MODE, &ec->flags); |
| 573 | } | 605 | } |
| 574 | return ACPI_INTERRUPT_HANDLED; | 606 | return ACPI_INTERRUPT_HANDLED; |
| @@ -736,7 +768,7 @@ static acpi_status | |||
| 736 | ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) | 768 | ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) |
| 737 | { | 769 | { |
| 738 | acpi_status status; | 770 | acpi_status status; |
| 739 | unsigned long long tmp; | 771 | unsigned long long tmp = 0; |
| 740 | 772 | ||
| 741 | struct acpi_ec *ec = context; | 773 | struct acpi_ec *ec = context; |
| 742 | status = acpi_walk_resources(handle, METHOD_NAME__CRS, | 774 | status = acpi_walk_resources(handle, METHOD_NAME__CRS, |
| @@ -751,6 +783,7 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) | |||
| 751 | return status; | 783 | return status; |
| 752 | ec->gpe = tmp; | 784 | ec->gpe = tmp; |
| 753 | /* Use the global lock for all EC transactions? */ | 785 | /* Use the global lock for all EC transactions? */ |
| 786 | tmp = 0; | ||
| 754 | acpi_evaluate_integer(handle, "_GLK", NULL, &tmp); | 787 | acpi_evaluate_integer(handle, "_GLK", NULL, &tmp); |
| 755 | ec->global_lock = tmp; | 788 | ec->global_lock = tmp; |
| 756 | ec->handle = handle; | 789 | ec->handle = handle; |
| @@ -868,7 +901,7 @@ static int ec_install_handlers(struct acpi_ec *ec) | |||
| 868 | if (ACPI_FAILURE(status)) | 901 | if (ACPI_FAILURE(status)) |
| 869 | return -ENODEV; | 902 | return -ENODEV; |
| 870 | acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); | 903 | acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); |
| 871 | acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); | 904 | acpi_enable_gpe(NULL, ec->gpe); |
| 872 | status = acpi_install_address_space_handler(ec->handle, | 905 | status = acpi_install_address_space_handler(ec->handle, |
| 873 | ACPI_ADR_SPACE_EC, | 906 | ACPI_ADR_SPACE_EC, |
| 874 | &acpi_ec_space_handler, | 907 | &acpi_ec_space_handler, |
| @@ -1007,7 +1040,7 @@ static int acpi_ec_suspend(struct acpi_device *device, pm_message_t state) | |||
| 1007 | /* Stop using GPE */ | 1040 | /* Stop using GPE */ |
| 1008 | set_bit(EC_FLAGS_NO_GPE, &ec->flags); | 1041 | set_bit(EC_FLAGS_NO_GPE, &ec->flags); |
| 1009 | clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); | 1042 | clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); |
| 1010 | acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); | 1043 | acpi_disable_gpe(NULL, ec->gpe); |
| 1011 | return 0; | 1044 | return 0; |
| 1012 | } | 1045 | } |
| 1013 | 1046 | ||
| @@ -1016,7 +1049,7 @@ static int acpi_ec_resume(struct acpi_device *device) | |||
| 1016 | struct acpi_ec *ec = acpi_driver_data(device); | 1049 | struct acpi_ec *ec = acpi_driver_data(device); |
| 1017 | /* Enable use of GPE back */ | 1050 | /* Enable use of GPE back */ |
| 1018 | clear_bit(EC_FLAGS_NO_GPE, &ec->flags); | 1051 | clear_bit(EC_FLAGS_NO_GPE, &ec->flags); |
| 1019 | acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); | 1052 | acpi_enable_gpe(NULL, ec->gpe); |
| 1020 | return 0; | 1053 | return 0; |
| 1021 | } | 1054 | } |
| 1022 | 1055 | ||
