diff options
Diffstat (limited to 'drivers/acpi/ec.c')
-rw-r--r-- | drivers/acpi/ec.c | 134 |
1 files changed, 88 insertions, 46 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index cb6066c809ea..5f9b74b9b71f 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
@@ -126,14 +126,16 @@ static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */ | |||
126 | static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */ | 126 | static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */ |
127 | static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */ | 127 | static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */ |
128 | static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */ | 128 | static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */ |
129 | static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */ | ||
129 | 130 | ||
130 | /* -------------------------------------------------------------------------- | 131 | /* -------------------------------------------------------------------------- |
131 | Transaction Management | 132 | * Transaction Management |
132 | -------------------------------------------------------------------------- */ | 133 | * -------------------------------------------------------------------------- */ |
133 | 134 | ||
134 | static inline u8 acpi_ec_read_status(struct acpi_ec *ec) | 135 | static inline u8 acpi_ec_read_status(struct acpi_ec *ec) |
135 | { | 136 | { |
136 | u8 x = inb(ec->command_addr); | 137 | u8 x = inb(ec->command_addr); |
138 | |||
137 | pr_debug("EC_SC(R) = 0x%2.2x " | 139 | pr_debug("EC_SC(R) = 0x%2.2x " |
138 | "SCI_EVT=%d BURST=%d CMD=%d IBF=%d OBF=%d\n", | 140 | "SCI_EVT=%d BURST=%d CMD=%d IBF=%d OBF=%d\n", |
139 | x, | 141 | x, |
@@ -148,6 +150,7 @@ static inline u8 acpi_ec_read_status(struct acpi_ec *ec) | |||
148 | static inline u8 acpi_ec_read_data(struct acpi_ec *ec) | 150 | static inline u8 acpi_ec_read_data(struct acpi_ec *ec) |
149 | { | 151 | { |
150 | u8 x = inb(ec->data_addr); | 152 | u8 x = inb(ec->data_addr); |
153 | |||
151 | pr_debug("EC_DATA(R) = 0x%2.2x\n", x); | 154 | pr_debug("EC_DATA(R) = 0x%2.2x\n", x); |
152 | return x; | 155 | return x; |
153 | } | 156 | } |
@@ -164,10 +167,32 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data) | |||
164 | outb(data, ec->data_addr); | 167 | outb(data, ec->data_addr); |
165 | } | 168 | } |
166 | 169 | ||
170 | #ifdef DEBUG | ||
171 | static const char *acpi_ec_cmd_string(u8 cmd) | ||
172 | { | ||
173 | switch (cmd) { | ||
174 | case 0x80: | ||
175 | return "RD_EC"; | ||
176 | case 0x81: | ||
177 | return "WR_EC"; | ||
178 | case 0x82: | ||
179 | return "BE_EC"; | ||
180 | case 0x83: | ||
181 | return "BD_EC"; | ||
182 | case 0x84: | ||
183 | return "QR_EC"; | ||
184 | } | ||
185 | return "UNKNOWN"; | ||
186 | } | ||
187 | #else | ||
188 | #define acpi_ec_cmd_string(cmd) "UNDEF" | ||
189 | #endif | ||
190 | |||
167 | static int ec_transaction_completed(struct acpi_ec *ec) | 191 | static int ec_transaction_completed(struct acpi_ec *ec) |
168 | { | 192 | { |
169 | unsigned long flags; | 193 | unsigned long flags; |
170 | int ret = 0; | 194 | int ret = 0; |
195 | |||
171 | spin_lock_irqsave(&ec->lock, flags); | 196 | spin_lock_irqsave(&ec->lock, flags); |
172 | if (ec->curr && (ec->curr->flags & ACPI_EC_COMMAND_COMPLETE)) | 197 | if (ec->curr && (ec->curr->flags & ACPI_EC_COMMAND_COMPLETE)) |
173 | ret = 1; | 198 | ret = 1; |
@@ -181,7 +206,8 @@ static bool advance_transaction(struct acpi_ec *ec) | |||
181 | u8 status; | 206 | u8 status; |
182 | bool wakeup = false; | 207 | bool wakeup = false; |
183 | 208 | ||
184 | pr_debug("===== %s =====\n", in_interrupt() ? "IRQ" : "TASK"); | 209 | pr_debug("===== %s (%d) =====\n", |
210 | in_interrupt() ? "IRQ" : "TASK", smp_processor_id()); | ||
185 | status = acpi_ec_read_status(ec); | 211 | status = acpi_ec_read_status(ec); |
186 | t = ec->curr; | 212 | t = ec->curr; |
187 | if (!t) | 213 | if (!t) |
@@ -198,7 +224,8 @@ static bool advance_transaction(struct acpi_ec *ec) | |||
198 | if (t->rlen == t->ri) { | 224 | if (t->rlen == t->ri) { |
199 | t->flags |= ACPI_EC_COMMAND_COMPLETE; | 225 | t->flags |= ACPI_EC_COMMAND_COMPLETE; |
200 | if (t->command == ACPI_EC_COMMAND_QUERY) | 226 | if (t->command == ACPI_EC_COMMAND_QUERY) |
201 | pr_debug("hardware QR_EC completion\n"); | 227 | pr_debug("***** Command(%s) hardware completion *****\n", |
228 | acpi_ec_cmd_string(t->command)); | ||
202 | wakeup = true; | 229 | wakeup = true; |
203 | } | 230 | } |
204 | } else | 231 | } else |
@@ -210,18 +237,14 @@ static bool advance_transaction(struct acpi_ec *ec) | |||
210 | } | 237 | } |
211 | return wakeup; | 238 | return wakeup; |
212 | } else { | 239 | } else { |
213 | /* | 240 | if (EC_FLAGS_QUERY_HANDSHAKE && |
214 | * There is firmware refusing to respond QR_EC when SCI_EVT | 241 | !(status & ACPI_EC_FLAG_SCI) && |
215 | * is not set, for which case, we complete the QR_EC | ||
216 | * without issuing it to the firmware. | ||
217 | * https://bugzilla.kernel.org/show_bug.cgi?id=86211 | ||
218 | */ | ||
219 | if (!(status & ACPI_EC_FLAG_SCI) && | ||
220 | (t->command == ACPI_EC_COMMAND_QUERY)) { | 242 | (t->command == ACPI_EC_COMMAND_QUERY)) { |
221 | t->flags |= ACPI_EC_COMMAND_POLL; | 243 | t->flags |= ACPI_EC_COMMAND_POLL; |
222 | t->rdata[t->ri++] = 0x00; | 244 | t->rdata[t->ri++] = 0x00; |
223 | t->flags |= ACPI_EC_COMMAND_COMPLETE; | 245 | t->flags |= ACPI_EC_COMMAND_COMPLETE; |
224 | pr_debug("software QR_EC completion\n"); | 246 | pr_debug("***** Command(%s) software completion *****\n", |
247 | acpi_ec_cmd_string(t->command)); | ||
225 | wakeup = true; | 248 | wakeup = true; |
226 | } else if ((status & ACPI_EC_FLAG_IBF) == 0) { | 249 | } else if ((status & ACPI_EC_FLAG_IBF) == 0) { |
227 | acpi_ec_write_cmd(ec, t->command); | 250 | acpi_ec_write_cmd(ec, t->command); |
@@ -264,6 +287,7 @@ static int ec_poll(struct acpi_ec *ec) | |||
264 | { | 287 | { |
265 | unsigned long flags; | 288 | unsigned long flags; |
266 | int repeat = 5; /* number of command restarts */ | 289 | int repeat = 5; /* number of command restarts */ |
290 | |||
267 | while (repeat--) { | 291 | while (repeat--) { |
268 | unsigned long delay = jiffies + | 292 | unsigned long delay = jiffies + |
269 | msecs_to_jiffies(ec_delay); | 293 | msecs_to_jiffies(ec_delay); |
@@ -296,18 +320,25 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, | |||
296 | { | 320 | { |
297 | unsigned long tmp; | 321 | unsigned long tmp; |
298 | int ret = 0; | 322 | int ret = 0; |
323 | |||
299 | if (EC_FLAGS_MSI) | 324 | if (EC_FLAGS_MSI) |
300 | udelay(ACPI_EC_MSI_UDELAY); | 325 | udelay(ACPI_EC_MSI_UDELAY); |
301 | /* start transaction */ | 326 | /* start transaction */ |
302 | spin_lock_irqsave(&ec->lock, tmp); | 327 | spin_lock_irqsave(&ec->lock, tmp); |
303 | /* following two actions should be kept atomic */ | 328 | /* following two actions should be kept atomic */ |
304 | ec->curr = t; | 329 | ec->curr = t; |
330 | pr_debug("***** Command(%s) started *****\n", | ||
331 | acpi_ec_cmd_string(t->command)); | ||
305 | start_transaction(ec); | 332 | start_transaction(ec); |
333 | if (ec->curr->command == ACPI_EC_COMMAND_QUERY) { | ||
334 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); | ||
335 | pr_debug("***** Event stopped *****\n"); | ||
336 | } | ||
306 | spin_unlock_irqrestore(&ec->lock, tmp); | 337 | spin_unlock_irqrestore(&ec->lock, tmp); |
307 | ret = ec_poll(ec); | 338 | ret = ec_poll(ec); |
308 | spin_lock_irqsave(&ec->lock, tmp); | 339 | spin_lock_irqsave(&ec->lock, tmp); |
309 | if (ec->curr->command == ACPI_EC_COMMAND_QUERY) | 340 | pr_debug("***** Command(%s) stopped *****\n", |
310 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); | 341 | acpi_ec_cmd_string(t->command)); |
311 | ec->curr = NULL; | 342 | ec->curr = NULL; |
312 | spin_unlock_irqrestore(&ec->lock, tmp); | 343 | spin_unlock_irqrestore(&ec->lock, tmp); |
313 | return ret; | 344 | return ret; |
@@ -317,6 +348,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) | |||
317 | { | 348 | { |
318 | int status; | 349 | int status; |
319 | u32 glk; | 350 | u32 glk; |
351 | |||
320 | if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata)) | 352 | if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata)) |
321 | return -EINVAL; | 353 | return -EINVAL; |
322 | if (t->rdata) | 354 | if (t->rdata) |
@@ -333,8 +365,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) | |||
333 | goto unlock; | 365 | goto unlock; |
334 | } | 366 | } |
335 | } | 367 | } |
336 | pr_debug("transaction start (cmd=0x%02x, addr=0x%02x)\n", | ||
337 | t->command, t->wdata ? t->wdata[0] : 0); | ||
338 | /* disable GPE during transaction if storm is detected */ | 368 | /* disable GPE during transaction if storm is detected */ |
339 | if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { | 369 | if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { |
340 | /* It has to be disabled, so that it doesn't trigger. */ | 370 | /* It has to be disabled, so that it doesn't trigger. */ |
@@ -355,7 +385,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) | |||
355 | t->irq_count); | 385 | t->irq_count); |
356 | set_bit(EC_FLAGS_GPE_STORM, &ec->flags); | 386 | set_bit(EC_FLAGS_GPE_STORM, &ec->flags); |
357 | } | 387 | } |
358 | pr_debug("transaction end\n"); | ||
359 | if (ec->global_lock) | 388 | if (ec->global_lock) |
360 | acpi_release_global_lock(glk); | 389 | acpi_release_global_lock(glk); |
361 | unlock: | 390 | unlock: |
@@ -383,7 +412,7 @@ static int acpi_ec_burst_disable(struct acpi_ec *ec) | |||
383 | acpi_ec_transaction(ec, &t) : 0; | 412 | acpi_ec_transaction(ec, &t) : 0; |
384 | } | 413 | } |
385 | 414 | ||
386 | static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data) | 415 | static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data) |
387 | { | 416 | { |
388 | int result; | 417 | int result; |
389 | u8 d; | 418 | u8 d; |
@@ -419,10 +448,9 @@ int ec_read(u8 addr, u8 *val) | |||
419 | if (!err) { | 448 | if (!err) { |
420 | *val = temp_data; | 449 | *val = temp_data; |
421 | return 0; | 450 | return 0; |
422 | } else | 451 | } |
423 | return err; | 452 | return err; |
424 | } | 453 | } |
425 | |||
426 | EXPORT_SYMBOL(ec_read); | 454 | EXPORT_SYMBOL(ec_read); |
427 | 455 | ||
428 | int ec_write(u8 addr, u8 val) | 456 | int ec_write(u8 addr, u8 val) |
@@ -436,22 +464,21 @@ int ec_write(u8 addr, u8 val) | |||
436 | 464 | ||
437 | return err; | 465 | return err; |
438 | } | 466 | } |
439 | |||
440 | EXPORT_SYMBOL(ec_write); | 467 | EXPORT_SYMBOL(ec_write); |
441 | 468 | ||
442 | int ec_transaction(u8 command, | 469 | int ec_transaction(u8 command, |
443 | const u8 * wdata, unsigned wdata_len, | 470 | const u8 *wdata, unsigned wdata_len, |
444 | u8 * rdata, unsigned rdata_len) | 471 | u8 *rdata, unsigned rdata_len) |
445 | { | 472 | { |
446 | struct transaction t = {.command = command, | 473 | struct transaction t = {.command = command, |
447 | .wdata = wdata, .rdata = rdata, | 474 | .wdata = wdata, .rdata = rdata, |
448 | .wlen = wdata_len, .rlen = rdata_len}; | 475 | .wlen = wdata_len, .rlen = rdata_len}; |
476 | |||
449 | if (!first_ec) | 477 | if (!first_ec) |
450 | return -ENODEV; | 478 | return -ENODEV; |
451 | 479 | ||
452 | return acpi_ec_transaction(first_ec, &t); | 480 | return acpi_ec_transaction(first_ec, &t); |
453 | } | 481 | } |
454 | |||
455 | EXPORT_SYMBOL(ec_transaction); | 482 | EXPORT_SYMBOL(ec_transaction); |
456 | 483 | ||
457 | /* Get the handle to the EC device */ | 484 | /* Get the handle to the EC device */ |
@@ -461,7 +488,6 @@ acpi_handle ec_get_handle(void) | |||
461 | return NULL; | 488 | return NULL; |
462 | return first_ec->handle; | 489 | return first_ec->handle; |
463 | } | 490 | } |
464 | |||
465 | EXPORT_SYMBOL(ec_get_handle); | 491 | EXPORT_SYMBOL(ec_get_handle); |
466 | 492 | ||
467 | /* | 493 | /* |
@@ -525,13 +551,14 @@ void acpi_ec_unblock_transactions_early(void) | |||
525 | clear_bit(EC_FLAGS_BLOCKED, &first_ec->flags); | 551 | clear_bit(EC_FLAGS_BLOCKED, &first_ec->flags); |
526 | } | 552 | } |
527 | 553 | ||
528 | static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data) | 554 | static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 *data) |
529 | { | 555 | { |
530 | int result; | 556 | int result; |
531 | u8 d; | 557 | u8 d; |
532 | struct transaction t = {.command = ACPI_EC_COMMAND_QUERY, | 558 | struct transaction t = {.command = ACPI_EC_COMMAND_QUERY, |
533 | .wdata = NULL, .rdata = &d, | 559 | .wdata = NULL, .rdata = &d, |
534 | .wlen = 0, .rlen = 1}; | 560 | .wlen = 0, .rlen = 1}; |
561 | |||
535 | if (!ec || !data) | 562 | if (!ec || !data) |
536 | return -EINVAL; | 563 | return -EINVAL; |
537 | /* | 564 | /* |
@@ -557,6 +584,7 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, | |||
557 | { | 584 | { |
558 | struct acpi_ec_query_handler *handler = | 585 | struct acpi_ec_query_handler *handler = |
559 | kzalloc(sizeof(struct acpi_ec_query_handler), GFP_KERNEL); | 586 | kzalloc(sizeof(struct acpi_ec_query_handler), GFP_KERNEL); |
587 | |||
560 | if (!handler) | 588 | if (!handler) |
561 | return -ENOMEM; | 589 | return -ENOMEM; |
562 | 590 | ||
@@ -569,12 +597,12 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, | |||
569 | mutex_unlock(&ec->mutex); | 597 | mutex_unlock(&ec->mutex); |
570 | return 0; | 598 | return 0; |
571 | } | 599 | } |
572 | |||
573 | EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler); | 600 | EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler); |
574 | 601 | ||
575 | void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) | 602 | void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) |
576 | { | 603 | { |
577 | struct acpi_ec_query_handler *handler, *tmp; | 604 | struct acpi_ec_query_handler *handler, *tmp; |
605 | |||
578 | mutex_lock(&ec->mutex); | 606 | mutex_lock(&ec->mutex); |
579 | list_for_each_entry_safe(handler, tmp, &ec->list, node) { | 607 | list_for_each_entry_safe(handler, tmp, &ec->list, node) { |
580 | if (query_bit == handler->query_bit) { | 608 | if (query_bit == handler->query_bit) { |
@@ -584,20 +612,20 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) | |||
584 | } | 612 | } |
585 | mutex_unlock(&ec->mutex); | 613 | mutex_unlock(&ec->mutex); |
586 | } | 614 | } |
587 | |||
588 | EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); | 615 | EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); |
589 | 616 | ||
590 | static void acpi_ec_run(void *cxt) | 617 | static void acpi_ec_run(void *cxt) |
591 | { | 618 | { |
592 | struct acpi_ec_query_handler *handler = cxt; | 619 | struct acpi_ec_query_handler *handler = cxt; |
620 | |||
593 | if (!handler) | 621 | if (!handler) |
594 | return; | 622 | return; |
595 | pr_debug("start query execution\n"); | 623 | pr_debug("##### Query(0x%02x) started #####\n", handler->query_bit); |
596 | if (handler->func) | 624 | if (handler->func) |
597 | handler->func(handler->data); | 625 | handler->func(handler->data); |
598 | else if (handler->handle) | 626 | else if (handler->handle) |
599 | acpi_evaluate_object(handler->handle, NULL, NULL, NULL); | 627 | acpi_evaluate_object(handler->handle, NULL, NULL, NULL); |
600 | pr_debug("stop query execution\n"); | 628 | pr_debug("##### Query(0x%02x) stopped #####\n", handler->query_bit); |
601 | kfree(handler); | 629 | kfree(handler); |
602 | } | 630 | } |
603 | 631 | ||
@@ -620,8 +648,8 @@ static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data) | |||
620 | if (!copy) | 648 | if (!copy) |
621 | return -ENOMEM; | 649 | return -ENOMEM; |
622 | memcpy(copy, handler, sizeof(*copy)); | 650 | memcpy(copy, handler, sizeof(*copy)); |
623 | pr_debug("push query execution (0x%2x) on queue\n", | 651 | pr_debug("##### Query(0x%02x) scheduled #####\n", |
624 | value); | 652 | handler->query_bit); |
625 | return acpi_os_execute((copy->func) ? | 653 | return acpi_os_execute((copy->func) ? |
626 | OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER, | 654 | OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER, |
627 | acpi_ec_run, copy); | 655 | acpi_ec_run, copy); |
@@ -633,6 +661,7 @@ static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data) | |||
633 | static void acpi_ec_gpe_query(void *ec_cxt) | 661 | static void acpi_ec_gpe_query(void *ec_cxt) |
634 | { | 662 | { |
635 | struct acpi_ec *ec = ec_cxt; | 663 | struct acpi_ec *ec = ec_cxt; |
664 | |||
636 | if (!ec) | 665 | if (!ec) |
637 | return; | 666 | return; |
638 | mutex_lock(&ec->mutex); | 667 | mutex_lock(&ec->mutex); |
@@ -644,7 +673,7 @@ static int ec_check_sci(struct acpi_ec *ec, u8 state) | |||
644 | { | 673 | { |
645 | if (state & ACPI_EC_FLAG_SCI) { | 674 | if (state & ACPI_EC_FLAG_SCI) { |
646 | if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { | 675 | if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { |
647 | pr_debug("push gpe query to the queue\n"); | 676 | pr_debug("***** Event started *****\n"); |
648 | return acpi_os_execute(OSL_NOTIFY_HANDLER, | 677 | return acpi_os_execute(OSL_NOTIFY_HANDLER, |
649 | acpi_ec_gpe_query, ec); | 678 | acpi_ec_gpe_query, ec); |
650 | } | 679 | } |
@@ -667,8 +696,8 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, | |||
667 | } | 696 | } |
668 | 697 | ||
669 | /* -------------------------------------------------------------------------- | 698 | /* -------------------------------------------------------------------------- |
670 | Address Space Management | 699 | * Address Space Management |
671 | -------------------------------------------------------------------------- */ | 700 | * -------------------------------------------------------------------------- */ |
672 | 701 | ||
673 | static acpi_status | 702 | static acpi_status |
674 | acpi_ec_space_handler(u32 function, acpi_physical_address address, | 703 | acpi_ec_space_handler(u32 function, acpi_physical_address address, |
@@ -699,27 +728,26 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, | |||
699 | switch (result) { | 728 | switch (result) { |
700 | case -EINVAL: | 729 | case -EINVAL: |
701 | return AE_BAD_PARAMETER; | 730 | return AE_BAD_PARAMETER; |
702 | break; | ||
703 | case -ENODEV: | 731 | case -ENODEV: |
704 | return AE_NOT_FOUND; | 732 | return AE_NOT_FOUND; |
705 | break; | ||
706 | case -ETIME: | 733 | case -ETIME: |
707 | return AE_TIME; | 734 | return AE_TIME; |
708 | break; | ||
709 | default: | 735 | default: |
710 | return AE_OK; | 736 | return AE_OK; |
711 | } | 737 | } |
712 | } | 738 | } |
713 | 739 | ||
714 | /* -------------------------------------------------------------------------- | 740 | /* -------------------------------------------------------------------------- |
715 | Driver Interface | 741 | * Driver Interface |
716 | -------------------------------------------------------------------------- */ | 742 | * -------------------------------------------------------------------------- */ |
743 | |||
717 | static acpi_status | 744 | static acpi_status |
718 | ec_parse_io_ports(struct acpi_resource *resource, void *context); | 745 | ec_parse_io_ports(struct acpi_resource *resource, void *context); |
719 | 746 | ||
720 | static struct acpi_ec *make_acpi_ec(void) | 747 | static struct acpi_ec *make_acpi_ec(void) |
721 | { | 748 | { |
722 | struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL); | 749 | struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL); |
750 | |||
723 | if (!ec) | 751 | if (!ec) |
724 | return NULL; | 752 | return NULL; |
725 | ec->flags = 1 << EC_FLAGS_QUERY_PENDING; | 753 | ec->flags = 1 << EC_FLAGS_QUERY_PENDING; |
@@ -742,9 +770,8 @@ acpi_ec_register_query_methods(acpi_handle handle, u32 level, | |||
742 | 770 | ||
743 | status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); | 771 | status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); |
744 | 772 | ||
745 | if (ACPI_SUCCESS(status) && sscanf(node_name, "_Q%x", &value) == 1) { | 773 | if (ACPI_SUCCESS(status) && sscanf(node_name, "_Q%x", &value) == 1) |
746 | acpi_ec_add_query_handler(ec, value, handle, NULL, NULL); | 774 | acpi_ec_add_query_handler(ec, value, handle, NULL, NULL); |
747 | } | ||
748 | return AE_OK; | 775 | return AE_OK; |
749 | } | 776 | } |
750 | 777 | ||
@@ -753,7 +780,6 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) | |||
753 | { | 780 | { |
754 | acpi_status status; | 781 | acpi_status status; |
755 | unsigned long long tmp = 0; | 782 | unsigned long long tmp = 0; |
756 | |||
757 | struct acpi_ec *ec = context; | 783 | struct acpi_ec *ec = context; |
758 | 784 | ||
759 | /* clear addr values, ec_parse_io_ports depend on it */ | 785 | /* clear addr values, ec_parse_io_ports depend on it */ |
@@ -781,6 +807,7 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) | |||
781 | static int ec_install_handlers(struct acpi_ec *ec) | 807 | static int ec_install_handlers(struct acpi_ec *ec) |
782 | { | 808 | { |
783 | acpi_status status; | 809 | acpi_status status; |
810 | |||
784 | if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags)) | 811 | if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags)) |
785 | return 0; | 812 | return 0; |
786 | status = acpi_install_gpe_handler(NULL, ec->gpe, | 813 | status = acpi_install_gpe_handler(NULL, ec->gpe, |
@@ -981,6 +1008,18 @@ static int ec_enlarge_storm_threshold(const struct dmi_system_id *id) | |||
981 | } | 1008 | } |
982 | 1009 | ||
983 | /* | 1010 | /* |
1011 | * Acer EC firmware refuses to respond QR_EC when SCI_EVT is not set, for | ||
1012 | * which case, we complete the QR_EC without issuing it to the firmware. | ||
1013 | * https://bugzilla.kernel.org/show_bug.cgi?id=86211 | ||
1014 | */ | ||
1015 | static int ec_flag_query_handshake(const struct dmi_system_id *id) | ||
1016 | { | ||
1017 | pr_debug("Detected the EC firmware requiring QR_EC issued when SCI_EVT set\n"); | ||
1018 | EC_FLAGS_QUERY_HANDSHAKE = 1; | ||
1019 | return 0; | ||
1020 | } | ||
1021 | |||
1022 | /* | ||
984 | * On some hardware it is necessary to clear events accumulated by the EC during | 1023 | * On some hardware it is necessary to clear events accumulated by the EC during |
985 | * sleep. These ECs stop reporting GPEs until they are manually polled, if too | 1024 | * sleep. These ECs stop reporting GPEs until they are manually polled, if too |
986 | * many events are accumulated. (e.g. Samsung Series 5/9 notebooks) | 1025 | * many events are accumulated. (e.g. Samsung Series 5/9 notebooks) |
@@ -1054,6 +1093,9 @@ static struct dmi_system_id ec_dmi_table[] __initdata = { | |||
1054 | { | 1093 | { |
1055 | ec_clear_on_resume, "Samsung hardware", { | 1094 | ec_clear_on_resume, "Samsung hardware", { |
1056 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL}, | 1095 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL}, |
1096 | { | ||
1097 | ec_flag_query_handshake, "Acer hardware", { | ||
1098 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), }, NULL}, | ||
1057 | {}, | 1099 | {}, |
1058 | }; | 1100 | }; |
1059 | 1101 | ||
@@ -1078,7 +1120,8 @@ int __init acpi_ec_ecdt_probe(void) | |||
1078 | boot_ec->data_addr = ecdt_ptr->data.address; | 1120 | boot_ec->data_addr = ecdt_ptr->data.address; |
1079 | boot_ec->gpe = ecdt_ptr->gpe; | 1121 | boot_ec->gpe = ecdt_ptr->gpe; |
1080 | boot_ec->handle = ACPI_ROOT_OBJECT; | 1122 | boot_ec->handle = ACPI_ROOT_OBJECT; |
1081 | acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle); | 1123 | acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, |
1124 | &boot_ec->handle); | ||
1082 | /* Don't trust ECDT, which comes from ASUSTek */ | 1125 | /* Don't trust ECDT, which comes from ASUSTek */ |
1083 | if (!EC_FLAGS_VALIDATE_ECDT) | 1126 | if (!EC_FLAGS_VALIDATE_ECDT) |
1084 | goto install; | 1127 | goto install; |
@@ -1162,6 +1205,5 @@ static void __exit acpi_ec_exit(void) | |||
1162 | { | 1205 | { |
1163 | 1206 | ||
1164 | acpi_bus_unregister_driver(&acpi_ec_driver); | 1207 | acpi_bus_unregister_driver(&acpi_ec_driver); |
1165 | return; | ||
1166 | } | 1208 | } |
1167 | #endif /* 0 */ | 1209 | #endif /* 0 */ |