diff options
Diffstat (limited to 'drivers/acpi/ec.c')
-rw-r--r-- | drivers/acpi/ec.c | 97 |
1 files changed, 53 insertions, 44 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index a51df9681319..354007d490d1 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
@@ -158,10 +158,10 @@ static int ec_transaction_done(struct acpi_ec *ec) | |||
158 | { | 158 | { |
159 | unsigned long flags; | 159 | unsigned long flags; |
160 | int ret = 0; | 160 | int ret = 0; |
161 | spin_lock_irqsave(&ec->curr_lock, flags); | 161 | spin_lock_irqsave(&ec->lock, flags); |
162 | if (!ec->curr || ec->curr->done) | 162 | if (!ec->curr || ec->curr->done) |
163 | ret = 1; | 163 | ret = 1; |
164 | spin_unlock_irqrestore(&ec->curr_lock, flags); | 164 | spin_unlock_irqrestore(&ec->lock, flags); |
165 | return ret; | 165 | return ret; |
166 | } | 166 | } |
167 | 167 | ||
@@ -175,32 +175,38 @@ static void start_transaction(struct acpi_ec *ec) | |||
175 | static void advance_transaction(struct acpi_ec *ec, u8 status) | 175 | static void advance_transaction(struct acpi_ec *ec, u8 status) |
176 | { | 176 | { |
177 | unsigned long flags; | 177 | unsigned long flags; |
178 | spin_lock_irqsave(&ec->curr_lock, flags); | 178 | struct transaction *t = ec->curr; |
179 | if (!ec->curr) | 179 | |
180 | spin_lock_irqsave(&ec->lock, flags); | ||
181 | if (!t) | ||
180 | goto unlock; | 182 | goto unlock; |
181 | if (ec->curr->wlen > ec->curr->wi) { | 183 | if (t->wlen > t->wi) { |
182 | if ((status & ACPI_EC_FLAG_IBF) == 0) | 184 | if ((status & ACPI_EC_FLAG_IBF) == 0) |
183 | acpi_ec_write_data(ec, | 185 | acpi_ec_write_data(ec, |
184 | ec->curr->wdata[ec->curr->wi++]); | 186 | t->wdata[t->wi++]); |
185 | else | 187 | else |
186 | goto err; | 188 | goto err; |
187 | } else if (ec->curr->rlen > ec->curr->ri) { | 189 | } else if (t->rlen > t->ri) { |
188 | if ((status & ACPI_EC_FLAG_OBF) == 1) { | 190 | if ((status & ACPI_EC_FLAG_OBF) == 1) { |
189 | ec->curr->rdata[ec->curr->ri++] = acpi_ec_read_data(ec); | 191 | t->rdata[t->ri++] = acpi_ec_read_data(ec); |
190 | if (ec->curr->rlen == ec->curr->ri) | 192 | if (t->rlen == t->ri) |
191 | ec->curr->done = true; | 193 | t->done = true; |
192 | } else | 194 | } else |
193 | goto err; | 195 | goto err; |
194 | } else if (ec->curr->wlen == ec->curr->wi && | 196 | } else if (t->wlen == t->wi && |
195 | (status & ACPI_EC_FLAG_IBF) == 0) | 197 | (status & ACPI_EC_FLAG_IBF) == 0) |
196 | ec->curr->done = true; | 198 | t->done = true; |
197 | goto unlock; | 199 | goto unlock; |
198 | err: | 200 | err: |
199 | /* false interrupt, state didn't change */ | 201 | /* |
200 | if (in_interrupt()) | 202 | * If SCI bit is set, then don't think it's a false IRQ |
201 | ++ec->curr->irq_count; | 203 | * otherwise will take a not handled IRQ as a false one. |
204 | */ | ||
205 | if (in_interrupt() && !(status & ACPI_EC_FLAG_SCI)) | ||
206 | ++t->irq_count; | ||
207 | |||
202 | unlock: | 208 | unlock: |
203 | spin_unlock_irqrestore(&ec->curr_lock, flags); | 209 | spin_unlock_irqrestore(&ec->lock, flags); |
204 | } | 210 | } |
205 | 211 | ||
206 | static int acpi_ec_sync_query(struct acpi_ec *ec); | 212 | static int acpi_ec_sync_query(struct acpi_ec *ec); |
@@ -238,9 +244,9 @@ static int ec_poll(struct acpi_ec *ec) | |||
238 | if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) | 244 | if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) |
239 | break; | 245 | break; |
240 | pr_debug(PREFIX "controller reset, restart transaction\n"); | 246 | pr_debug(PREFIX "controller reset, restart transaction\n"); |
241 | spin_lock_irqsave(&ec->curr_lock, flags); | 247 | spin_lock_irqsave(&ec->lock, flags); |
242 | start_transaction(ec); | 248 | start_transaction(ec); |
243 | spin_unlock_irqrestore(&ec->curr_lock, flags); | 249 | spin_unlock_irqrestore(&ec->lock, flags); |
244 | } | 250 | } |
245 | return -ETIME; | 251 | return -ETIME; |
246 | } | 252 | } |
@@ -253,17 +259,17 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, | |||
253 | if (EC_FLAGS_MSI) | 259 | if (EC_FLAGS_MSI) |
254 | udelay(ACPI_EC_MSI_UDELAY); | 260 | udelay(ACPI_EC_MSI_UDELAY); |
255 | /* start transaction */ | 261 | /* start transaction */ |
256 | spin_lock_irqsave(&ec->curr_lock, tmp); | 262 | spin_lock_irqsave(&ec->lock, tmp); |
257 | /* following two actions should be kept atomic */ | 263 | /* following two actions should be kept atomic */ |
258 | ec->curr = t; | 264 | ec->curr = t; |
259 | start_transaction(ec); | 265 | start_transaction(ec); |
260 | if (ec->curr->command == ACPI_EC_COMMAND_QUERY) | 266 | if (ec->curr->command == ACPI_EC_COMMAND_QUERY) |
261 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); | 267 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); |
262 | spin_unlock_irqrestore(&ec->curr_lock, tmp); | 268 | spin_unlock_irqrestore(&ec->lock, tmp); |
263 | ret = ec_poll(ec); | 269 | ret = ec_poll(ec); |
264 | spin_lock_irqsave(&ec->curr_lock, tmp); | 270 | spin_lock_irqsave(&ec->lock, tmp); |
265 | ec->curr = NULL; | 271 | ec->curr = NULL; |
266 | spin_unlock_irqrestore(&ec->curr_lock, tmp); | 272 | spin_unlock_irqrestore(&ec->lock, tmp); |
267 | return ret; | 273 | return ret; |
268 | } | 274 | } |
269 | 275 | ||
@@ -292,7 +298,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) | |||
292 | return -EINVAL; | 298 | return -EINVAL; |
293 | if (t->rdata) | 299 | if (t->rdata) |
294 | memset(t->rdata, 0, t->rlen); | 300 | memset(t->rdata, 0, t->rlen); |
295 | mutex_lock(&ec->lock); | 301 | mutex_lock(&ec->mutex); |
296 | if (test_bit(EC_FLAGS_BLOCKED, &ec->flags)) { | 302 | if (test_bit(EC_FLAGS_BLOCKED, &ec->flags)) { |
297 | status = -EINVAL; | 303 | status = -EINVAL; |
298 | goto unlock; | 304 | goto unlock; |
@@ -310,7 +316,8 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) | |||
310 | status = -ETIME; | 316 | status = -ETIME; |
311 | goto end; | 317 | goto end; |
312 | } | 318 | } |
313 | pr_debug(PREFIX "transaction start\n"); | 319 | pr_debug(PREFIX "transaction start (cmd=0x%02x, addr=0x%02x)\n", |
320 | t->command, t->wdata ? t->wdata[0] : 0); | ||
314 | /* disable GPE during transaction if storm is detected */ | 321 | /* disable GPE during transaction if storm is detected */ |
315 | if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { | 322 | if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { |
316 | /* It has to be disabled, so that it doesn't trigger. */ | 323 | /* It has to be disabled, so that it doesn't trigger. */ |
@@ -326,8 +333,9 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) | |||
326 | /* It is safe to enable the GPE outside of the transaction. */ | 333 | /* It is safe to enable the GPE outside of the transaction. */ |
327 | acpi_enable_gpe(NULL, ec->gpe); | 334 | acpi_enable_gpe(NULL, ec->gpe); |
328 | } else if (t->irq_count > ec_storm_threshold) { | 335 | } else if (t->irq_count > ec_storm_threshold) { |
329 | pr_info(PREFIX "GPE storm detected, " | 336 | pr_info(PREFIX "GPE storm detected(%d GPEs), " |
330 | "transactions will use polling mode\n"); | 337 | "transactions will use polling mode\n", |
338 | t->irq_count); | ||
331 | set_bit(EC_FLAGS_GPE_STORM, &ec->flags); | 339 | set_bit(EC_FLAGS_GPE_STORM, &ec->flags); |
332 | } | 340 | } |
333 | pr_debug(PREFIX "transaction end\n"); | 341 | pr_debug(PREFIX "transaction end\n"); |
@@ -335,7 +343,7 @@ end: | |||
335 | if (ec->global_lock) | 343 | if (ec->global_lock) |
336 | acpi_release_global_lock(glk); | 344 | acpi_release_global_lock(glk); |
337 | unlock: | 345 | unlock: |
338 | mutex_unlock(&ec->lock); | 346 | mutex_unlock(&ec->mutex); |
339 | return status; | 347 | return status; |
340 | } | 348 | } |
341 | 349 | ||
@@ -403,7 +411,7 @@ int ec_burst_disable(void) | |||
403 | 411 | ||
404 | EXPORT_SYMBOL(ec_burst_disable); | 412 | EXPORT_SYMBOL(ec_burst_disable); |
405 | 413 | ||
406 | int ec_read(u8 addr, u8 * val) | 414 | int ec_read(u8 addr, u8 *val) |
407 | { | 415 | { |
408 | int err; | 416 | int err; |
409 | u8 temp_data; | 417 | u8 temp_data; |
@@ -468,10 +476,10 @@ void acpi_ec_block_transactions(void) | |||
468 | if (!ec) | 476 | if (!ec) |
469 | return; | 477 | return; |
470 | 478 | ||
471 | mutex_lock(&ec->lock); | 479 | mutex_lock(&ec->mutex); |
472 | /* Prevent transactions from being carried out */ | 480 | /* Prevent transactions from being carried out */ |
473 | set_bit(EC_FLAGS_BLOCKED, &ec->flags); | 481 | set_bit(EC_FLAGS_BLOCKED, &ec->flags); |
474 | mutex_unlock(&ec->lock); | 482 | mutex_unlock(&ec->mutex); |
475 | } | 483 | } |
476 | 484 | ||
477 | void acpi_ec_unblock_transactions(void) | 485 | void acpi_ec_unblock_transactions(void) |
@@ -481,10 +489,10 @@ void acpi_ec_unblock_transactions(void) | |||
481 | if (!ec) | 489 | if (!ec) |
482 | return; | 490 | return; |
483 | 491 | ||
484 | mutex_lock(&ec->lock); | 492 | mutex_lock(&ec->mutex); |
485 | /* Allow transactions to be carried out again */ | 493 | /* Allow transactions to be carried out again */ |
486 | clear_bit(EC_FLAGS_BLOCKED, &ec->flags); | 494 | clear_bit(EC_FLAGS_BLOCKED, &ec->flags); |
487 | mutex_unlock(&ec->lock); | 495 | mutex_unlock(&ec->mutex); |
488 | } | 496 | } |
489 | 497 | ||
490 | void acpi_ec_unblock_transactions_early(void) | 498 | void acpi_ec_unblock_transactions_early(void) |
@@ -536,9 +544,9 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, | |||
536 | handler->handle = handle; | 544 | handler->handle = handle; |
537 | handler->func = func; | 545 | handler->func = func; |
538 | handler->data = data; | 546 | handler->data = data; |
539 | mutex_lock(&ec->lock); | 547 | mutex_lock(&ec->mutex); |
540 | list_add(&handler->node, &ec->list); | 548 | list_add(&handler->node, &ec->list); |
541 | mutex_unlock(&ec->lock); | 549 | mutex_unlock(&ec->mutex); |
542 | return 0; | 550 | return 0; |
543 | } | 551 | } |
544 | 552 | ||
@@ -547,14 +555,14 @@ EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler); | |||
547 | void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) | 555 | void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) |
548 | { | 556 | { |
549 | struct acpi_ec_query_handler *handler, *tmp; | 557 | struct acpi_ec_query_handler *handler, *tmp; |
550 | mutex_lock(&ec->lock); | 558 | mutex_lock(&ec->mutex); |
551 | list_for_each_entry_safe(handler, tmp, &ec->list, node) { | 559 | list_for_each_entry_safe(handler, tmp, &ec->list, node) { |
552 | if (query_bit == handler->query_bit) { | 560 | if (query_bit == handler->query_bit) { |
553 | list_del(&handler->node); | 561 | list_del(&handler->node); |
554 | kfree(handler); | 562 | kfree(handler); |
555 | } | 563 | } |
556 | } | 564 | } |
557 | mutex_unlock(&ec->lock); | 565 | mutex_unlock(&ec->mutex); |
558 | } | 566 | } |
559 | 567 | ||
560 | EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); | 568 | EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); |
@@ -601,9 +609,9 @@ static void acpi_ec_gpe_query(void *ec_cxt) | |||
601 | struct acpi_ec *ec = ec_cxt; | 609 | struct acpi_ec *ec = ec_cxt; |
602 | if (!ec) | 610 | if (!ec) |
603 | return; | 611 | return; |
604 | mutex_lock(&ec->lock); | 612 | mutex_lock(&ec->mutex); |
605 | acpi_ec_sync_query(ec); | 613 | acpi_ec_sync_query(ec); |
606 | mutex_unlock(&ec->lock); | 614 | mutex_unlock(&ec->mutex); |
607 | } | 615 | } |
608 | 616 | ||
609 | static int ec_check_sci(struct acpi_ec *ec, u8 state) | 617 | static int ec_check_sci(struct acpi_ec *ec, u8 state) |
@@ -622,10 +630,11 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, | |||
622 | u32 gpe_number, void *data) | 630 | u32 gpe_number, void *data) |
623 | { | 631 | { |
624 | struct acpi_ec *ec = data; | 632 | struct acpi_ec *ec = data; |
633 | u8 status = acpi_ec_read_status(ec); | ||
625 | 634 | ||
626 | pr_debug(PREFIX "~~~> interrupt\n"); | 635 | pr_debug(PREFIX "~~~> interrupt, status:0x%02x\n", status); |
627 | 636 | ||
628 | advance_transaction(ec, acpi_ec_read_status(ec)); | 637 | advance_transaction(ec, status); |
629 | if (ec_transaction_done(ec) && | 638 | if (ec_transaction_done(ec) && |
630 | (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) { | 639 | (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) { |
631 | wake_up(&ec->wait); | 640 | wake_up(&ec->wait); |
@@ -691,10 +700,10 @@ static struct acpi_ec *make_acpi_ec(void) | |||
691 | if (!ec) | 700 | if (!ec) |
692 | return NULL; | 701 | return NULL; |
693 | ec->flags = 1 << EC_FLAGS_QUERY_PENDING; | 702 | ec->flags = 1 << EC_FLAGS_QUERY_PENDING; |
694 | mutex_init(&ec->lock); | 703 | mutex_init(&ec->mutex); |
695 | init_waitqueue_head(&ec->wait); | 704 | init_waitqueue_head(&ec->wait); |
696 | INIT_LIST_HEAD(&ec->list); | 705 | INIT_LIST_HEAD(&ec->list); |
697 | spin_lock_init(&ec->curr_lock); | 706 | spin_lock_init(&ec->lock); |
698 | return ec; | 707 | return ec; |
699 | } | 708 | } |
700 | 709 | ||
@@ -853,12 +862,12 @@ static int acpi_ec_remove(struct acpi_device *device, int type) | |||
853 | 862 | ||
854 | ec = acpi_driver_data(device); | 863 | ec = acpi_driver_data(device); |
855 | ec_remove_handlers(ec); | 864 | ec_remove_handlers(ec); |
856 | mutex_lock(&ec->lock); | 865 | mutex_lock(&ec->mutex); |
857 | list_for_each_entry_safe(handler, tmp, &ec->list, node) { | 866 | list_for_each_entry_safe(handler, tmp, &ec->list, node) { |
858 | list_del(&handler->node); | 867 | list_del(&handler->node); |
859 | kfree(handler); | 868 | kfree(handler); |
860 | } | 869 | } |
861 | mutex_unlock(&ec->lock); | 870 | mutex_unlock(&ec->mutex); |
862 | release_region(ec->data_addr, 1); | 871 | release_region(ec->data_addr, 1); |
863 | release_region(ec->command_addr, 1); | 872 | release_region(ec->command_addr, 1); |
864 | device->driver_data = NULL; | 873 | device->driver_data = NULL; |