.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * ec.c - ACPI Embedded Controller Driver (v3) |
---|
3 | 4 | * |
---|
.. | .. |
---|
9 | 10 | * 2001, 2002 Andy Grover <andrew.grover@intel.com> |
---|
10 | 11 | * 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> |
---|
11 | 12 | * Copyright (C) 2008 Alexey Starikovskiy <astarikovskiy@suse.de> |
---|
12 | | - * |
---|
13 | | - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
---|
14 | | - * |
---|
15 | | - * This program is free software; you can redistribute it and/or modify |
---|
16 | | - * it under the terms of the GNU General Public License as published by |
---|
17 | | - * the Free Software Foundation; either version 2 of the License, or (at |
---|
18 | | - * your option) any later version. |
---|
19 | | - * |
---|
20 | | - * This program is distributed in the hope that it will be useful, but |
---|
21 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
22 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
23 | | - * General Public License for more details. |
---|
24 | | - * |
---|
25 | | - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
---|
26 | 13 | */ |
---|
27 | 14 | |
---|
28 | 15 | /* Uncomment next line to get verbose printout */ |
---|
.. | .. |
---|
38 | 25 | #include <linux/list.h> |
---|
39 | 26 | #include <linux/spinlock.h> |
---|
40 | 27 | #include <linux/slab.h> |
---|
| 28 | +#include <linux/suspend.h> |
---|
41 | 29 | #include <linux/acpi.h> |
---|
42 | 30 | #include <linux/dmi.h> |
---|
43 | 31 | #include <asm/io.h> |
---|
.. | .. |
---|
46 | 34 | |
---|
47 | 35 | #define ACPI_EC_CLASS "embedded_controller" |
---|
48 | 36 | #define ACPI_EC_DEVICE_NAME "Embedded Controller" |
---|
49 | | -#define ACPI_EC_FILE_INFO "info" |
---|
50 | 37 | |
---|
51 | 38 | /* EC status register */ |
---|
52 | 39 | #define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */ |
---|
.. | .. |
---|
107 | 94 | EC_FLAGS_QUERY_ENABLED, /* Query is enabled */ |
---|
108 | 95 | EC_FLAGS_QUERY_PENDING, /* Query is pending */ |
---|
109 | 96 | EC_FLAGS_QUERY_GUARDING, /* Guard for SCI_EVT check */ |
---|
110 | | - EC_FLAGS_GPE_HANDLER_INSTALLED, /* GPE handler installed */ |
---|
| 97 | + EC_FLAGS_EVENT_HANDLER_INSTALLED, /* Event handler installed */ |
---|
111 | 98 | EC_FLAGS_EC_HANDLER_INSTALLED, /* OpReg handler installed */ |
---|
112 | | - EC_FLAGS_EVT_HANDLER_INSTALLED, /* _Qxx handlers installed */ |
---|
| 99 | + EC_FLAGS_QUERY_METHODS_INSTALLED, /* _Qxx handlers installed */ |
---|
113 | 100 | EC_FLAGS_STARTED, /* Driver is started */ |
---|
114 | 101 | EC_FLAGS_STOPPED, /* Driver is stopped */ |
---|
115 | | - EC_FLAGS_GPE_MASKED, /* GPE masked */ |
---|
| 102 | + EC_FLAGS_EVENTS_MASKED, /* Events masked */ |
---|
116 | 103 | }; |
---|
117 | 104 | |
---|
118 | 105 | #define ACPI_EC_COMMAND_POLL 0x01 /* Available for command byte */ |
---|
.. | .. |
---|
179 | 166 | struct transaction transaction; |
---|
180 | 167 | struct work_struct work; |
---|
181 | 168 | struct acpi_ec_query_handler *handler; |
---|
| 169 | + struct acpi_ec *ec; |
---|
182 | 170 | }; |
---|
183 | 171 | |
---|
184 | 172 | static int acpi_ec_query(struct acpi_ec *ec, u8 *data); |
---|
.. | .. |
---|
186 | 174 | static void acpi_ec_event_handler(struct work_struct *work); |
---|
187 | 175 | static void acpi_ec_event_processor(struct work_struct *work); |
---|
188 | 176 | |
---|
189 | | -struct acpi_ec *boot_ec, *first_ec; |
---|
| 177 | +struct acpi_ec *first_ec; |
---|
190 | 178 | EXPORT_SYMBOL(first_ec); |
---|
| 179 | + |
---|
| 180 | +static struct acpi_ec *boot_ec; |
---|
191 | 181 | static bool boot_ec_is_ecdt = false; |
---|
| 182 | +static struct workqueue_struct *ec_wq; |
---|
192 | 183 | static struct workqueue_struct *ec_query_wq; |
---|
193 | 184 | |
---|
194 | | -static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */ |
---|
195 | 185 | static int EC_FLAGS_CORRECT_ECDT; /* Needs ECDT port address correction */ |
---|
196 | | -static int EC_FLAGS_IGNORE_DSDT_GPE; /* Needs ECDT GPE as correction setting */ |
---|
| 186 | +static int EC_FLAGS_TRUST_DSDT_GPE; /* Needs DSDT GPE as correction setting */ |
---|
197 | 187 | static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */ |
---|
198 | 188 | |
---|
199 | 189 | /* -------------------------------------------------------------------------- |
---|
.. | .. |
---|
407 | 397 | static void acpi_ec_submit_request(struct acpi_ec *ec) |
---|
408 | 398 | { |
---|
409 | 399 | ec->reference_count++; |
---|
410 | | - if (test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags) && |
---|
411 | | - ec->reference_count == 1) |
---|
| 400 | + if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags) && |
---|
| 401 | + ec->gpe >= 0 && ec->reference_count == 1) |
---|
412 | 402 | acpi_ec_enable_gpe(ec, true); |
---|
413 | 403 | } |
---|
414 | 404 | |
---|
.. | .. |
---|
417 | 407 | bool flushed = false; |
---|
418 | 408 | |
---|
419 | 409 | ec->reference_count--; |
---|
420 | | - if (test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags) && |
---|
421 | | - ec->reference_count == 0) |
---|
| 410 | + if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags) && |
---|
| 411 | + ec->gpe >= 0 && ec->reference_count == 0) |
---|
422 | 412 | acpi_ec_disable_gpe(ec, true); |
---|
423 | 413 | flushed = acpi_ec_flushed(ec); |
---|
424 | 414 | if (flushed) |
---|
425 | 415 | wake_up(&ec->wait); |
---|
426 | 416 | } |
---|
427 | 417 | |
---|
428 | | -static void acpi_ec_mask_gpe(struct acpi_ec *ec) |
---|
| 418 | +static void acpi_ec_mask_events(struct acpi_ec *ec) |
---|
429 | 419 | { |
---|
430 | | - if (!test_bit(EC_FLAGS_GPE_MASKED, &ec->flags)) { |
---|
431 | | - acpi_ec_disable_gpe(ec, false); |
---|
| 420 | + if (!test_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags)) { |
---|
| 421 | + if (ec->gpe >= 0) |
---|
| 422 | + acpi_ec_disable_gpe(ec, false); |
---|
| 423 | + else |
---|
| 424 | + disable_irq_nosync(ec->irq); |
---|
| 425 | + |
---|
432 | 426 | ec_dbg_drv("Polling enabled"); |
---|
433 | | - set_bit(EC_FLAGS_GPE_MASKED, &ec->flags); |
---|
| 427 | + set_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags); |
---|
434 | 428 | } |
---|
435 | 429 | } |
---|
436 | 430 | |
---|
437 | | -static void acpi_ec_unmask_gpe(struct acpi_ec *ec) |
---|
| 431 | +static void acpi_ec_unmask_events(struct acpi_ec *ec) |
---|
438 | 432 | { |
---|
439 | | - if (test_bit(EC_FLAGS_GPE_MASKED, &ec->flags)) { |
---|
440 | | - clear_bit(EC_FLAGS_GPE_MASKED, &ec->flags); |
---|
441 | | - acpi_ec_enable_gpe(ec, false); |
---|
| 433 | + if (test_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags)) { |
---|
| 434 | + clear_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags); |
---|
| 435 | + if (ec->gpe >= 0) |
---|
| 436 | + acpi_ec_enable_gpe(ec, false); |
---|
| 437 | + else |
---|
| 438 | + enable_irq(ec->irq); |
---|
| 439 | + |
---|
442 | 440 | ec_dbg_drv("Polling disabled"); |
---|
443 | 441 | } |
---|
444 | 442 | } |
---|
.. | .. |
---|
464 | 462 | |
---|
465 | 463 | static void acpi_ec_submit_query(struct acpi_ec *ec) |
---|
466 | 464 | { |
---|
467 | | - acpi_ec_mask_gpe(ec); |
---|
| 465 | + acpi_ec_mask_events(ec); |
---|
468 | 466 | if (!acpi_ec_event_enabled(ec)) |
---|
469 | 467 | return; |
---|
470 | 468 | if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { |
---|
471 | 469 | ec_dbg_evt("Command(%s) submitted/blocked", |
---|
472 | 470 | acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY)); |
---|
473 | 471 | ec->nr_pending_queries++; |
---|
474 | | - schedule_work(&ec->work); |
---|
| 472 | + ec->events_in_progress++; |
---|
| 473 | + queue_work(ec_wq, &ec->work); |
---|
475 | 474 | } |
---|
476 | 475 | } |
---|
477 | 476 | |
---|
.. | .. |
---|
480 | 479 | if (test_and_clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) |
---|
481 | 480 | ec_dbg_evt("Command(%s) unblocked", |
---|
482 | 481 | acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY)); |
---|
483 | | - acpi_ec_unmask_gpe(ec); |
---|
| 482 | + acpi_ec_unmask_events(ec); |
---|
484 | 483 | } |
---|
485 | 484 | |
---|
486 | 485 | static inline void __acpi_ec_enable_event(struct acpi_ec *ec) |
---|
.. | .. |
---|
535 | 534 | } |
---|
536 | 535 | |
---|
537 | 536 | #ifdef CONFIG_PM_SLEEP |
---|
538 | | -static bool acpi_ec_query_flushed(struct acpi_ec *ec) |
---|
| 537 | +static void __acpi_ec_flush_work(void) |
---|
539 | 538 | { |
---|
540 | | - bool flushed; |
---|
541 | | - unsigned long flags; |
---|
542 | | - |
---|
543 | | - spin_lock_irqsave(&ec->lock, flags); |
---|
544 | | - flushed = !ec->nr_pending_queries; |
---|
545 | | - spin_unlock_irqrestore(&ec->lock, flags); |
---|
546 | | - return flushed; |
---|
547 | | -} |
---|
548 | | - |
---|
549 | | -static void __acpi_ec_flush_event(struct acpi_ec *ec) |
---|
550 | | -{ |
---|
551 | | - /* |
---|
552 | | - * When ec_freeze_events is true, we need to flush events in |
---|
553 | | - * the proper position before entering the noirq stage. |
---|
554 | | - */ |
---|
555 | | - wait_event(ec->wait, acpi_ec_query_flushed(ec)); |
---|
556 | | - if (ec_query_wq) |
---|
557 | | - flush_workqueue(ec_query_wq); |
---|
| 539 | + flush_workqueue(ec_wq); /* flush ec->work */ |
---|
| 540 | + flush_workqueue(ec_query_wq); /* flush queries */ |
---|
558 | 541 | } |
---|
559 | 542 | |
---|
560 | 543 | static void acpi_ec_disable_event(struct acpi_ec *ec) |
---|
.. | .. |
---|
564 | 547 | spin_lock_irqsave(&ec->lock, flags); |
---|
565 | 548 | __acpi_ec_disable_event(ec); |
---|
566 | 549 | spin_unlock_irqrestore(&ec->lock, flags); |
---|
567 | | - __acpi_ec_flush_event(ec); |
---|
| 550 | + |
---|
| 551 | + /* |
---|
| 552 | + * When ec_freeze_events is true, we need to flush events in |
---|
| 553 | + * the proper position before entering the noirq stage. |
---|
| 554 | + */ |
---|
| 555 | + __acpi_ec_flush_work(); |
---|
568 | 556 | } |
---|
569 | 557 | |
---|
570 | 558 | void acpi_ec_flush_work(void) |
---|
571 | 559 | { |
---|
572 | | - if (first_ec) |
---|
573 | | - __acpi_ec_flush_event(first_ec); |
---|
| 560 | + /* Without ec_wq there is nothing to flush. */ |
---|
| 561 | + if (!ec_wq) |
---|
| 562 | + return; |
---|
574 | 563 | |
---|
575 | | - flush_scheduled_work(); |
---|
| 564 | + __acpi_ec_flush_work(); |
---|
576 | 565 | } |
---|
577 | 566 | #endif /* CONFIG_PM_SLEEP */ |
---|
578 | 567 | |
---|
.. | .. |
---|
658 | 647 | * ensure a hardware STS 0->1 change after this clearing can always |
---|
659 | 648 | * trigger a GPE interrupt. |
---|
660 | 649 | */ |
---|
661 | | - acpi_ec_clear_gpe(ec); |
---|
| 650 | + if (ec->gpe >= 0) |
---|
| 651 | + acpi_ec_clear_gpe(ec); |
---|
| 652 | + |
---|
662 | 653 | status = acpi_ec_read_status(ec); |
---|
663 | 654 | t = ec->curr; |
---|
664 | 655 | /* |
---|
.. | .. |
---|
699 | 690 | wakeup = true; |
---|
700 | 691 | } |
---|
701 | 692 | goto out; |
---|
702 | | - } else { |
---|
703 | | - if (EC_FLAGS_QUERY_HANDSHAKE && |
---|
704 | | - !(status & ACPI_EC_FLAG_SCI) && |
---|
705 | | - (t->command == ACPI_EC_COMMAND_QUERY)) { |
---|
706 | | - ec_transaction_transition(ec, ACPI_EC_COMMAND_POLL); |
---|
707 | | - t->rdata[t->ri++] = 0x00; |
---|
708 | | - ec_transaction_transition(ec, ACPI_EC_COMMAND_COMPLETE); |
---|
709 | | - ec_dbg_evt("Command(%s) completed by software", |
---|
710 | | - acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY)); |
---|
711 | | - wakeup = true; |
---|
712 | | - } else if ((status & ACPI_EC_FLAG_IBF) == 0) { |
---|
713 | | - acpi_ec_write_cmd(ec, t->command); |
---|
714 | | - ec_transaction_transition(ec, ACPI_EC_COMMAND_POLL); |
---|
715 | | - } else |
---|
716 | | - goto err; |
---|
| 693 | + } else if (!(status & ACPI_EC_FLAG_IBF)) { |
---|
| 694 | + acpi_ec_write_cmd(ec, t->command); |
---|
| 695 | + ec_transaction_transition(ec, ACPI_EC_COMMAND_POLL); |
---|
717 | 696 | goto out; |
---|
718 | 697 | } |
---|
719 | 698 | err: |
---|
.. | .. |
---|
727 | 706 | ++t->irq_count; |
---|
728 | 707 | /* Allow triggering on 0 threshold */ |
---|
729 | 708 | if (t->irq_count == ec_storm_threshold) |
---|
730 | | - acpi_ec_mask_gpe(ec); |
---|
| 709 | + acpi_ec_mask_events(ec); |
---|
731 | 710 | } |
---|
732 | 711 | } |
---|
733 | 712 | out: |
---|
.. | .. |
---|
825 | 804 | |
---|
826 | 805 | spin_lock_irqsave(&ec->lock, tmp); |
---|
827 | 806 | if (t->irq_count == ec_storm_threshold) |
---|
828 | | - acpi_ec_unmask_gpe(ec); |
---|
| 807 | + acpi_ec_unmask_events(ec); |
---|
829 | 808 | ec_dbg_req("Command(%s) stopped", acpi_ec_cmd_string(t->command)); |
---|
830 | 809 | ec->curr = NULL; |
---|
831 | 810 | /* Disable GPE for command processing (IBF=0/OBF=1) */ |
---|
.. | .. |
---|
1059 | 1038 | acpi_ec_start(first_ec, true); |
---|
1060 | 1039 | } |
---|
1061 | 1040 | |
---|
1062 | | -void acpi_ec_mark_gpe_for_wake(void) |
---|
1063 | | -{ |
---|
1064 | | - if (first_ec && !ec_no_wakeup) |
---|
1065 | | - acpi_mark_gpe_for_wake(NULL, first_ec->gpe); |
---|
1066 | | -} |
---|
1067 | | - |
---|
1068 | | -void acpi_ec_set_gpe_wake_mask(u8 action) |
---|
1069 | | -{ |
---|
1070 | | - if (first_ec && !ec_no_wakeup) |
---|
1071 | | - acpi_set_gpe_wake_mask(NULL, first_ec->gpe, action); |
---|
1072 | | -} |
---|
1073 | | - |
---|
1074 | | -void acpi_ec_dispatch_gpe(void) |
---|
1075 | | -{ |
---|
1076 | | - if (first_ec) |
---|
1077 | | - acpi_dispatch_gpe(NULL, first_ec->gpe); |
---|
1078 | | -} |
---|
1079 | | - |
---|
1080 | 1041 | /* -------------------------------------------------------------------------- |
---|
1081 | 1042 | Event Management |
---|
1082 | 1043 | -------------------------------------------------------------------------- */ |
---|
.. | .. |
---|
1153 | 1114 | void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) |
---|
1154 | 1115 | { |
---|
1155 | 1116 | acpi_ec_remove_query_handlers(ec, false, query_bit); |
---|
| 1117 | + flush_workqueue(ec_query_wq); |
---|
1156 | 1118 | } |
---|
1157 | 1119 | EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); |
---|
1158 | 1120 | |
---|
1159 | | -static struct acpi_ec_query *acpi_ec_create_query(u8 *pval) |
---|
| 1121 | +static struct acpi_ec_query *acpi_ec_create_query(struct acpi_ec *ec, u8 *pval) |
---|
1160 | 1122 | { |
---|
1161 | 1123 | struct acpi_ec_query *q; |
---|
1162 | 1124 | struct transaction *t; |
---|
.. | .. |
---|
1164 | 1126 | q = kzalloc(sizeof (struct acpi_ec_query), GFP_KERNEL); |
---|
1165 | 1127 | if (!q) |
---|
1166 | 1128 | return NULL; |
---|
| 1129 | + |
---|
1167 | 1130 | INIT_WORK(&q->work, acpi_ec_event_processor); |
---|
1168 | 1131 | t = &q->transaction; |
---|
1169 | 1132 | t->command = ACPI_EC_COMMAND_QUERY; |
---|
1170 | 1133 | t->rdata = pval; |
---|
1171 | 1134 | t->rlen = 1; |
---|
| 1135 | + q->ec = ec; |
---|
1172 | 1136 | return q; |
---|
1173 | 1137 | } |
---|
1174 | 1138 | |
---|
.. | .. |
---|
1185 | 1149 | { |
---|
1186 | 1150 | struct acpi_ec_query *q = container_of(work, struct acpi_ec_query, work); |
---|
1187 | 1151 | struct acpi_ec_query_handler *handler = q->handler; |
---|
| 1152 | + struct acpi_ec *ec = q->ec; |
---|
1188 | 1153 | |
---|
1189 | 1154 | ec_dbg_evt("Query(0x%02x) started", handler->query_bit); |
---|
| 1155 | + |
---|
1190 | 1156 | if (handler->func) |
---|
1191 | 1157 | handler->func(handler->data); |
---|
1192 | 1158 | else if (handler->handle) |
---|
1193 | 1159 | acpi_evaluate_object(handler->handle, NULL, NULL, NULL); |
---|
| 1160 | + |
---|
1194 | 1161 | ec_dbg_evt("Query(0x%02x) stopped", handler->query_bit); |
---|
| 1162 | + |
---|
| 1163 | + spin_lock_irq(&ec->lock); |
---|
| 1164 | + ec->queries_in_progress--; |
---|
| 1165 | + spin_unlock_irq(&ec->lock); |
---|
| 1166 | + |
---|
1195 | 1167 | acpi_ec_delete_query(q); |
---|
1196 | 1168 | } |
---|
1197 | 1169 | |
---|
.. | .. |
---|
1201 | 1173 | int result; |
---|
1202 | 1174 | struct acpi_ec_query *q; |
---|
1203 | 1175 | |
---|
1204 | | - q = acpi_ec_create_query(&value); |
---|
| 1176 | + q = acpi_ec_create_query(ec, &value); |
---|
1205 | 1177 | if (!q) |
---|
1206 | 1178 | return -ENOMEM; |
---|
1207 | 1179 | |
---|
.. | .. |
---|
1223 | 1195 | } |
---|
1224 | 1196 | |
---|
1225 | 1197 | /* |
---|
1226 | | - * It is reported that _Qxx are evaluated in a parallel way on |
---|
1227 | | - * Windows: |
---|
| 1198 | + * It is reported that _Qxx are evaluated in a parallel way on Windows: |
---|
1228 | 1199 | * https://bugzilla.kernel.org/show_bug.cgi?id=94411 |
---|
1229 | 1200 | * |
---|
1230 | | - * Put this log entry before schedule_work() in order to make |
---|
1231 | | - * it appearing before any other log entries occurred during the |
---|
1232 | | - * work queue execution. |
---|
| 1201 | + * Put this log entry before queue_work() to make it appear in the log |
---|
| 1202 | + * before any other messages emitted during workqueue handling. |
---|
1233 | 1203 | */ |
---|
1234 | 1204 | ec_dbg_evt("Query(0x%02x) scheduled", value); |
---|
1235 | | - if (!queue_work(ec_query_wq, &q->work)) { |
---|
1236 | | - ec_dbg_evt("Query(0x%02x) overlapped", value); |
---|
1237 | | - result = -EBUSY; |
---|
1238 | | - } |
---|
| 1205 | + |
---|
| 1206 | + spin_lock_irq(&ec->lock); |
---|
| 1207 | + |
---|
| 1208 | + ec->queries_in_progress++; |
---|
| 1209 | + queue_work(ec_query_wq, &q->work); |
---|
| 1210 | + |
---|
| 1211 | + spin_unlock_irq(&ec->lock); |
---|
1239 | 1212 | |
---|
1240 | 1213 | err_exit: |
---|
1241 | 1214 | if (result) |
---|
.. | .. |
---|
1293 | 1266 | ec_dbg_evt("Event stopped"); |
---|
1294 | 1267 | |
---|
1295 | 1268 | acpi_ec_check_event(ec); |
---|
| 1269 | + |
---|
| 1270 | + spin_lock_irqsave(&ec->lock, flags); |
---|
| 1271 | + ec->events_in_progress--; |
---|
| 1272 | + spin_unlock_irqrestore(&ec->lock, flags); |
---|
1296 | 1273 | } |
---|
1297 | 1274 | |
---|
1298 | | -static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, |
---|
1299 | | - u32 gpe_number, void *data) |
---|
| 1275 | +static void acpi_ec_handle_interrupt(struct acpi_ec *ec) |
---|
1300 | 1276 | { |
---|
1301 | 1277 | unsigned long flags; |
---|
1302 | | - struct acpi_ec *ec = data; |
---|
1303 | 1278 | |
---|
1304 | 1279 | spin_lock_irqsave(&ec->lock, flags); |
---|
1305 | 1280 | advance_transaction(ec); |
---|
1306 | 1281 | spin_unlock_irqrestore(&ec->lock, flags); |
---|
| 1282 | +} |
---|
| 1283 | + |
---|
| 1284 | +static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, |
---|
| 1285 | + u32 gpe_number, void *data) |
---|
| 1286 | +{ |
---|
| 1287 | + acpi_ec_handle_interrupt(data); |
---|
1307 | 1288 | return ACPI_INTERRUPT_HANDLED; |
---|
| 1289 | +} |
---|
| 1290 | + |
---|
| 1291 | +static irqreturn_t acpi_ec_irq_handler(int irq, void *data) |
---|
| 1292 | +{ |
---|
| 1293 | + acpi_ec_handle_interrupt(data); |
---|
| 1294 | + return IRQ_HANDLED; |
---|
1308 | 1295 | } |
---|
1309 | 1296 | |
---|
1310 | 1297 | /* -------------------------------------------------------------------------- |
---|
.. | .. |
---|
1379 | 1366 | ec->timestamp = jiffies; |
---|
1380 | 1367 | ec->busy_polling = true; |
---|
1381 | 1368 | ec->polling_guard = 0; |
---|
| 1369 | + ec->gpe = -1; |
---|
| 1370 | + ec->irq = -1; |
---|
1382 | 1371 | return ec; |
---|
1383 | 1372 | } |
---|
1384 | 1373 | |
---|
.. | .. |
---|
1416 | 1405 | if (ec->data_addr == 0 || ec->command_addr == 0) |
---|
1417 | 1406 | return AE_OK; |
---|
1418 | 1407 | |
---|
1419 | | - if (boot_ec && boot_ec_is_ecdt && EC_FLAGS_IGNORE_DSDT_GPE) { |
---|
1420 | | - /* |
---|
1421 | | - * Always inherit the GPE number setting from the ECDT |
---|
1422 | | - * EC. |
---|
1423 | | - */ |
---|
1424 | | - ec->gpe = boot_ec->gpe; |
---|
1425 | | - } else { |
---|
1426 | | - /* Get GPE bit assignment (EC events). */ |
---|
1427 | | - /* TODO: Add support for _GPE returning a package */ |
---|
1428 | | - status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp); |
---|
1429 | | - if (ACPI_FAILURE(status)) |
---|
1430 | | - return status; |
---|
| 1408 | + /* Get GPE bit assignment (EC events). */ |
---|
| 1409 | + /* TODO: Add support for _GPE returning a package */ |
---|
| 1410 | + status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp); |
---|
| 1411 | + if (ACPI_SUCCESS(status)) |
---|
1431 | 1412 | ec->gpe = tmp; |
---|
1432 | | - } |
---|
| 1413 | + /* |
---|
| 1414 | + * Errors are non-fatal, allowing for ACPI Reduced Hardware |
---|
| 1415 | + * platforms which use GpioInt instead of GPE. |
---|
| 1416 | + */ |
---|
| 1417 | + |
---|
1433 | 1418 | /* Use the global lock for all EC transactions? */ |
---|
1434 | 1419 | tmp = 0; |
---|
1435 | 1420 | acpi_evaluate_integer(handle, "_GLK", NULL, &tmp); |
---|
.. | .. |
---|
1438 | 1423 | return AE_CTRL_TERMINATE; |
---|
1439 | 1424 | } |
---|
1440 | 1425 | |
---|
1441 | | -/* |
---|
1442 | | - * Note: This function returns an error code only when the address space |
---|
1443 | | - * handler is not installed, which means "not able to handle |
---|
1444 | | - * transactions". |
---|
| 1426 | +static bool install_gpe_event_handler(struct acpi_ec *ec) |
---|
| 1427 | +{ |
---|
| 1428 | + acpi_status status; |
---|
| 1429 | + |
---|
| 1430 | + status = acpi_install_gpe_raw_handler(NULL, ec->gpe, |
---|
| 1431 | + ACPI_GPE_EDGE_TRIGGERED, |
---|
| 1432 | + &acpi_ec_gpe_handler, ec); |
---|
| 1433 | + if (ACPI_FAILURE(status)) |
---|
| 1434 | + return false; |
---|
| 1435 | + |
---|
| 1436 | + if (test_bit(EC_FLAGS_STARTED, &ec->flags) && ec->reference_count >= 1) |
---|
| 1437 | + acpi_ec_enable_gpe(ec, true); |
---|
| 1438 | + |
---|
| 1439 | + return true; |
---|
| 1440 | +} |
---|
| 1441 | + |
---|
| 1442 | +static bool install_gpio_irq_event_handler(struct acpi_ec *ec) |
---|
| 1443 | +{ |
---|
| 1444 | + return request_irq(ec->irq, acpi_ec_irq_handler, IRQF_SHARED, |
---|
| 1445 | + "ACPI EC", ec) >= 0; |
---|
| 1446 | +} |
---|
| 1447 | + |
---|
| 1448 | +/** |
---|
| 1449 | + * ec_install_handlers - Install service callbacks and register query methods. |
---|
| 1450 | + * @ec: Target EC. |
---|
| 1451 | + * @device: ACPI device object corresponding to @ec. |
---|
| 1452 | + * |
---|
| 1453 | + * Install a handler for the EC address space type unless it has been installed |
---|
| 1454 | + * already. If @device is not NULL, also look for EC query methods in the |
---|
| 1455 | + * namespace and register them, and install an event (either GPE or GPIO IRQ) |
---|
| 1456 | + * handler for the EC, if possible. |
---|
| 1457 | + * |
---|
| 1458 | + * Return: |
---|
| 1459 | + * -ENODEV if the address space handler cannot be installed, which means |
---|
| 1460 | + * "unable to handle transactions", |
---|
| 1461 | + * -EPROBE_DEFER if GPIO IRQ acquisition needs to be deferred, |
---|
| 1462 | + * or 0 (success) otherwise. |
---|
1445 | 1463 | */ |
---|
1446 | | -static int ec_install_handlers(struct acpi_ec *ec, bool handle_events) |
---|
| 1464 | +static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device) |
---|
1447 | 1465 | { |
---|
1448 | 1466 | acpi_status status; |
---|
1449 | 1467 | |
---|
.. | .. |
---|
1456 | 1474 | &acpi_ec_space_handler, |
---|
1457 | 1475 | NULL, ec); |
---|
1458 | 1476 | if (ACPI_FAILURE(status)) { |
---|
1459 | | - if (status == AE_NOT_FOUND) { |
---|
1460 | | - /* |
---|
1461 | | - * Maybe OS fails in evaluating the _REG |
---|
1462 | | - * object. The AE_NOT_FOUND error will be |
---|
1463 | | - * ignored and OS * continue to initialize |
---|
1464 | | - * EC. |
---|
1465 | | - */ |
---|
1466 | | - pr_err("Fail in evaluating the _REG object" |
---|
1467 | | - " of EC device. Broken bios is suspected.\n"); |
---|
1468 | | - } else { |
---|
1469 | | - acpi_ec_stop(ec, false); |
---|
1470 | | - return -ENODEV; |
---|
1471 | | - } |
---|
| 1477 | + acpi_ec_stop(ec, false); |
---|
| 1478 | + return -ENODEV; |
---|
1472 | 1479 | } |
---|
1473 | 1480 | set_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags); |
---|
1474 | 1481 | } |
---|
1475 | 1482 | |
---|
1476 | | - if (!handle_events) |
---|
| 1483 | + if (!device) |
---|
1477 | 1484 | return 0; |
---|
1478 | 1485 | |
---|
1479 | | - if (!test_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags)) { |
---|
| 1486 | + if (ec->gpe < 0) { |
---|
| 1487 | + /* ACPI reduced hardware platforms use a GpioInt from _CRS. */ |
---|
| 1488 | + int irq = acpi_dev_gpio_irq_get(device, 0); |
---|
| 1489 | + /* |
---|
| 1490 | + * Bail out right away for deferred probing or complete the |
---|
| 1491 | + * initialization regardless of any other errors. |
---|
| 1492 | + */ |
---|
| 1493 | + if (irq == -EPROBE_DEFER) |
---|
| 1494 | + return -EPROBE_DEFER; |
---|
| 1495 | + else if (irq >= 0) |
---|
| 1496 | + ec->irq = irq; |
---|
| 1497 | + } |
---|
| 1498 | + |
---|
| 1499 | + if (!test_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags)) { |
---|
1480 | 1500 | /* Find and register all query methods */ |
---|
1481 | 1501 | acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1, |
---|
1482 | 1502 | acpi_ec_register_query_methods, |
---|
1483 | 1503 | NULL, ec, NULL); |
---|
1484 | | - set_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags); |
---|
| 1504 | + set_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags); |
---|
1485 | 1505 | } |
---|
1486 | | - if (!test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags)) { |
---|
1487 | | - status = acpi_install_gpe_raw_handler(NULL, ec->gpe, |
---|
1488 | | - ACPI_GPE_EDGE_TRIGGERED, |
---|
1489 | | - &acpi_ec_gpe_handler, ec); |
---|
1490 | | - /* This is not fatal as we can poll EC events */ |
---|
1491 | | - if (ACPI_SUCCESS(status)) { |
---|
1492 | | - set_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags); |
---|
| 1506 | + if (!test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags)) { |
---|
| 1507 | + bool ready = false; |
---|
| 1508 | + |
---|
| 1509 | + if (ec->gpe >= 0) |
---|
| 1510 | + ready = install_gpe_event_handler(ec); |
---|
| 1511 | + else if (ec->irq >= 0) |
---|
| 1512 | + ready = install_gpio_irq_event_handler(ec); |
---|
| 1513 | + |
---|
| 1514 | + if (ready) { |
---|
| 1515 | + set_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags); |
---|
1493 | 1516 | acpi_ec_leave_noirq(ec); |
---|
1494 | | - if (test_bit(EC_FLAGS_STARTED, &ec->flags) && |
---|
1495 | | - ec->reference_count >= 1) |
---|
1496 | | - acpi_ec_enable_gpe(ec, true); |
---|
1497 | 1517 | } |
---|
| 1518 | + /* |
---|
| 1519 | + * Failures to install an event handler are not fatal, because |
---|
| 1520 | + * the EC can be polled for events. |
---|
| 1521 | + */ |
---|
1498 | 1522 | } |
---|
1499 | 1523 | /* EC is fully operational, allow queries */ |
---|
1500 | 1524 | acpi_ec_enable_event(ec); |
---|
.. | .. |
---|
1524 | 1548 | */ |
---|
1525 | 1549 | acpi_ec_stop(ec, false); |
---|
1526 | 1550 | |
---|
1527 | | - if (test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags)) { |
---|
1528 | | - if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe, |
---|
1529 | | - &acpi_ec_gpe_handler))) |
---|
| 1551 | + if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags)) { |
---|
| 1552 | + if (ec->gpe >= 0 && |
---|
| 1553 | + ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe, |
---|
| 1554 | + &acpi_ec_gpe_handler))) |
---|
1530 | 1555 | pr_err("failed to remove gpe handler\n"); |
---|
1531 | | - clear_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags); |
---|
| 1556 | + |
---|
| 1557 | + if (ec->irq >= 0) |
---|
| 1558 | + free_irq(ec->irq, ec); |
---|
| 1559 | + |
---|
| 1560 | + clear_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags); |
---|
1532 | 1561 | } |
---|
1533 | | - if (test_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags)) { |
---|
| 1562 | + if (test_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags)) { |
---|
1534 | 1563 | acpi_ec_remove_query_handlers(ec, true, 0); |
---|
1535 | | - clear_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags); |
---|
| 1564 | + clear_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags); |
---|
1536 | 1565 | } |
---|
1537 | 1566 | } |
---|
1538 | 1567 | |
---|
1539 | | -static int acpi_ec_setup(struct acpi_ec *ec, bool handle_events) |
---|
| 1568 | +static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device) |
---|
1540 | 1569 | { |
---|
1541 | 1570 | int ret; |
---|
1542 | 1571 | |
---|
1543 | | - ret = ec_install_handlers(ec, handle_events); |
---|
| 1572 | + ret = ec_install_handlers(ec, device); |
---|
1544 | 1573 | if (ret) |
---|
1545 | 1574 | return ret; |
---|
1546 | 1575 | |
---|
1547 | 1576 | /* First EC capable of handling transactions */ |
---|
1548 | | - if (!first_ec) { |
---|
| 1577 | + if (!first_ec) |
---|
1549 | 1578 | first_ec = ec; |
---|
1550 | | - acpi_handle_info(first_ec->handle, "Used as first EC\n"); |
---|
| 1579 | + |
---|
| 1580 | + pr_info("EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n", ec->command_addr, |
---|
| 1581 | + ec->data_addr); |
---|
| 1582 | + |
---|
| 1583 | + if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags)) { |
---|
| 1584 | + if (ec->gpe >= 0) |
---|
| 1585 | + pr_info("GPE=0x%x\n", ec->gpe); |
---|
| 1586 | + else |
---|
| 1587 | + pr_info("IRQ=%d\n", ec->irq); |
---|
1551 | 1588 | } |
---|
1552 | 1589 | |
---|
1553 | | - acpi_handle_info(ec->handle, |
---|
1554 | | - "GPE=0x%x, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n", |
---|
1555 | | - ec->gpe, ec->command_addr, ec->data_addr); |
---|
1556 | 1590 | return ret; |
---|
1557 | | -} |
---|
1558 | | - |
---|
1559 | | -static int acpi_config_boot_ec(struct acpi_ec *ec, acpi_handle handle, |
---|
1560 | | - bool handle_events, bool is_ecdt) |
---|
1561 | | -{ |
---|
1562 | | - int ret; |
---|
1563 | | - |
---|
1564 | | - /* |
---|
1565 | | - * Changing the ACPI handle results in a re-configuration of the |
---|
1566 | | - * boot EC. And if it happens after the namespace initialization, |
---|
1567 | | - * it causes _REG evaluations. |
---|
1568 | | - */ |
---|
1569 | | - if (boot_ec && boot_ec->handle != handle) |
---|
1570 | | - ec_remove_handlers(boot_ec); |
---|
1571 | | - |
---|
1572 | | - /* Unset old boot EC */ |
---|
1573 | | - if (boot_ec != ec) |
---|
1574 | | - acpi_ec_free(boot_ec); |
---|
1575 | | - |
---|
1576 | | - /* |
---|
1577 | | - * ECDT device creation is split into acpi_ec_ecdt_probe() and |
---|
1578 | | - * acpi_ec_ecdt_start(). This function takes care of completing the |
---|
1579 | | - * ECDT parsing logic as the handle update should be performed |
---|
1580 | | - * between the installation/uninstallation of the handlers. |
---|
1581 | | - */ |
---|
1582 | | - if (ec->handle != handle) |
---|
1583 | | - ec->handle = handle; |
---|
1584 | | - |
---|
1585 | | - ret = acpi_ec_setup(ec, handle_events); |
---|
1586 | | - if (ret) |
---|
1587 | | - return ret; |
---|
1588 | | - |
---|
1589 | | - /* Set new boot EC */ |
---|
1590 | | - if (!boot_ec) { |
---|
1591 | | - boot_ec = ec; |
---|
1592 | | - boot_ec_is_ecdt = is_ecdt; |
---|
1593 | | - } |
---|
1594 | | - |
---|
1595 | | - acpi_handle_info(boot_ec->handle, |
---|
1596 | | - "Used as boot %s EC to handle transactions%s\n", |
---|
1597 | | - is_ecdt ? "ECDT" : "DSDT", |
---|
1598 | | - handle_events ? " and events" : ""); |
---|
1599 | | - return ret; |
---|
1600 | | -} |
---|
1601 | | - |
---|
1602 | | -static bool acpi_ec_ecdt_get_handle(acpi_handle *phandle) |
---|
1603 | | -{ |
---|
1604 | | - struct acpi_table_ecdt *ecdt_ptr; |
---|
1605 | | - acpi_status status; |
---|
1606 | | - acpi_handle handle; |
---|
1607 | | - |
---|
1608 | | - status = acpi_get_table(ACPI_SIG_ECDT, 1, |
---|
1609 | | - (struct acpi_table_header **)&ecdt_ptr); |
---|
1610 | | - if (ACPI_FAILURE(status)) |
---|
1611 | | - return false; |
---|
1612 | | - |
---|
1613 | | - status = acpi_get_handle(NULL, ecdt_ptr->id, &handle); |
---|
1614 | | - if (ACPI_FAILURE(status)) |
---|
1615 | | - return false; |
---|
1616 | | - |
---|
1617 | | - *phandle = handle; |
---|
1618 | | - return true; |
---|
1619 | | -} |
---|
1620 | | - |
---|
1621 | | -static bool acpi_is_boot_ec(struct acpi_ec *ec) |
---|
1622 | | -{ |
---|
1623 | | - if (!boot_ec) |
---|
1624 | | - return false; |
---|
1625 | | - if (ec->command_addr == boot_ec->command_addr && |
---|
1626 | | - ec->data_addr == boot_ec->data_addr) |
---|
1627 | | - return true; |
---|
1628 | | - return false; |
---|
1629 | 1591 | } |
---|
1630 | 1592 | |
---|
1631 | 1593 | static int acpi_ec_add(struct acpi_device *device) |
---|
1632 | 1594 | { |
---|
1633 | | - struct acpi_ec *ec = NULL; |
---|
| 1595 | + struct acpi_ec *ec; |
---|
1634 | 1596 | int ret; |
---|
1635 | | - bool is_ecdt = false; |
---|
1636 | | - acpi_status status; |
---|
1637 | 1597 | |
---|
1638 | 1598 | strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); |
---|
1639 | 1599 | strcpy(acpi_device_class(device), ACPI_EC_CLASS); |
---|
1640 | 1600 | |
---|
1641 | | - if (!strcmp(acpi_device_hid(device), ACPI_ECDT_HID)) { |
---|
1642 | | - is_ecdt = true; |
---|
| 1601 | + if (boot_ec && (boot_ec->handle == device->handle || |
---|
| 1602 | + !strcmp(acpi_device_hid(device), ACPI_ECDT_HID))) { |
---|
| 1603 | + /* Fast path: this device corresponds to the boot EC. */ |
---|
1643 | 1604 | ec = boot_ec; |
---|
1644 | 1605 | } else { |
---|
| 1606 | + acpi_status status; |
---|
| 1607 | + |
---|
1645 | 1608 | ec = acpi_ec_alloc(); |
---|
1646 | 1609 | if (!ec) |
---|
1647 | 1610 | return -ENOMEM; |
---|
| 1611 | + |
---|
1648 | 1612 | status = ec_parse_device(device->handle, 0, ec, NULL); |
---|
1649 | 1613 | if (status != AE_CTRL_TERMINATE) { |
---|
1650 | 1614 | ret = -EINVAL; |
---|
1651 | | - goto err_alloc; |
---|
| 1615 | + goto err; |
---|
1652 | 1616 | } |
---|
1653 | | - } |
---|
1654 | 1617 | |
---|
1655 | | - if (acpi_is_boot_ec(ec)) { |
---|
1656 | | - boot_ec_is_ecdt = is_ecdt; |
---|
1657 | | - if (!is_ecdt) { |
---|
| 1618 | + if (boot_ec && ec->command_addr == boot_ec->command_addr && |
---|
| 1619 | + ec->data_addr == boot_ec->data_addr && |
---|
| 1620 | + !EC_FLAGS_TRUST_DSDT_GPE) { |
---|
1658 | 1621 | /* |
---|
1659 | 1622 | * Trust PNP0C09 namespace location rather than |
---|
1660 | 1623 | * ECDT ID. But trust ECDT GPE rather than _GPE |
---|
.. | .. |
---|
1666 | 1629 | acpi_ec_free(ec); |
---|
1667 | 1630 | ec = boot_ec; |
---|
1668 | 1631 | } |
---|
1669 | | - ret = acpi_config_boot_ec(ec, ec->handle, true, is_ecdt); |
---|
1670 | | - } else |
---|
1671 | | - ret = acpi_ec_setup(ec, true); |
---|
| 1632 | + } |
---|
| 1633 | + |
---|
| 1634 | + ret = acpi_ec_setup(ec, device); |
---|
1672 | 1635 | if (ret) |
---|
1673 | | - goto err_query; |
---|
| 1636 | + goto err; |
---|
| 1637 | + |
---|
| 1638 | + if (ec == boot_ec) |
---|
| 1639 | + acpi_handle_info(boot_ec->handle, |
---|
| 1640 | + "Boot %s EC initialization complete\n", |
---|
| 1641 | + boot_ec_is_ecdt ? "ECDT" : "DSDT"); |
---|
| 1642 | + |
---|
| 1643 | + acpi_handle_info(ec->handle, |
---|
| 1644 | + "EC: Used to handle transactions and events\n"); |
---|
1674 | 1645 | |
---|
1675 | 1646 | device->driver_data = ec; |
---|
1676 | 1647 | |
---|
.. | .. |
---|
1679 | 1650 | ret = !!request_region(ec->command_addr, 1, "EC cmd"); |
---|
1680 | 1651 | WARN(!ret, "Could not request EC cmd io port 0x%lx", ec->command_addr); |
---|
1681 | 1652 | |
---|
1682 | | - if (!is_ecdt) { |
---|
1683 | | - /* Reprobe devices depending on the EC */ |
---|
1684 | | - acpi_walk_dep_device_list(ec->handle); |
---|
1685 | | - } |
---|
| 1653 | + /* Reprobe devices depending on the EC */ |
---|
| 1654 | + acpi_walk_dep_device_list(ec->handle); |
---|
| 1655 | + |
---|
1686 | 1656 | acpi_handle_debug(ec->handle, "enumerated.\n"); |
---|
1687 | 1657 | return 0; |
---|
1688 | 1658 | |
---|
1689 | | -err_query: |
---|
1690 | | - if (ec != boot_ec) |
---|
1691 | | - acpi_ec_remove_query_handlers(ec, true, 0); |
---|
1692 | | -err_alloc: |
---|
| 1659 | +err: |
---|
1693 | 1660 | if (ec != boot_ec) |
---|
1694 | 1661 | acpi_ec_free(ec); |
---|
| 1662 | + |
---|
1695 | 1663 | return ret; |
---|
1696 | 1664 | } |
---|
1697 | 1665 | |
---|
.. | .. |
---|
1747 | 1715 | * namespace EC before the main ACPI device enumeration process. It is |
---|
1748 | 1716 | * retained for historical reason and will be deprecated in the future. |
---|
1749 | 1717 | */ |
---|
1750 | | -int __init acpi_ec_dsdt_probe(void) |
---|
| 1718 | +void __init acpi_ec_dsdt_probe(void) |
---|
1751 | 1719 | { |
---|
1752 | | - acpi_status status; |
---|
1753 | 1720 | struct acpi_ec *ec; |
---|
| 1721 | + acpi_status status; |
---|
1754 | 1722 | int ret; |
---|
1755 | 1723 | |
---|
1756 | 1724 | /* |
---|
.. | .. |
---|
1760 | 1728 | * picking up an invalid EC device. |
---|
1761 | 1729 | */ |
---|
1762 | 1730 | if (boot_ec) |
---|
1763 | | - return -ENODEV; |
---|
| 1731 | + return; |
---|
1764 | 1732 | |
---|
1765 | 1733 | ec = acpi_ec_alloc(); |
---|
1766 | 1734 | if (!ec) |
---|
1767 | | - return -ENOMEM; |
---|
| 1735 | + return; |
---|
| 1736 | + |
---|
1768 | 1737 | /* |
---|
1769 | 1738 | * At this point, the namespace is initialized, so start to find |
---|
1770 | 1739 | * the namespace objects. |
---|
1771 | 1740 | */ |
---|
1772 | | - status = acpi_get_devices(ec_device_ids[0].id, |
---|
1773 | | - ec_parse_device, ec, NULL); |
---|
| 1741 | + status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device, ec, NULL); |
---|
1774 | 1742 | if (ACPI_FAILURE(status) || !ec->handle) { |
---|
1775 | | - ret = -ENODEV; |
---|
1776 | | - goto error; |
---|
| 1743 | + acpi_ec_free(ec); |
---|
| 1744 | + return; |
---|
1777 | 1745 | } |
---|
| 1746 | + |
---|
1778 | 1747 | /* |
---|
1779 | 1748 | * When the DSDT EC is available, always re-configure boot EC to |
---|
1780 | 1749 | * have _REG evaluated. _REG can only be evaluated after the |
---|
.. | .. |
---|
1782 | 1751 | * At this point, the GPE is not fully initialized, so do not to |
---|
1783 | 1752 | * handle the events. |
---|
1784 | 1753 | */ |
---|
1785 | | - ret = acpi_config_boot_ec(ec, ec->handle, false, false); |
---|
1786 | | -error: |
---|
1787 | | - if (ret) |
---|
| 1754 | + ret = acpi_ec_setup(ec, NULL); |
---|
| 1755 | + if (ret) { |
---|
1788 | 1756 | acpi_ec_free(ec); |
---|
1789 | | - return ret; |
---|
1790 | | -} |
---|
1791 | | - |
---|
1792 | | -/* |
---|
1793 | | - * If the DSDT EC is not functioning, we still need to prepare a fully |
---|
1794 | | - * functioning ECDT EC first in order to handle the events. |
---|
1795 | | - * https://bugzilla.kernel.org/show_bug.cgi?id=115021 |
---|
1796 | | - */ |
---|
1797 | | -static int __init acpi_ec_ecdt_start(void) |
---|
1798 | | -{ |
---|
1799 | | - acpi_handle handle; |
---|
1800 | | - |
---|
1801 | | - if (!boot_ec) |
---|
1802 | | - return -ENODEV; |
---|
1803 | | - /* In case acpi_ec_ecdt_start() is called after acpi_ec_add() */ |
---|
1804 | | - if (!boot_ec_is_ecdt) |
---|
1805 | | - return -ENODEV; |
---|
1806 | | - |
---|
1807 | | - /* |
---|
1808 | | - * At this point, the namespace and the GPE is initialized, so |
---|
1809 | | - * start to find the namespace objects and handle the events. |
---|
1810 | | - * |
---|
1811 | | - * Note: ec->handle can be valid if this function is called after |
---|
1812 | | - * acpi_ec_add(), hence the fast path. |
---|
1813 | | - */ |
---|
1814 | | - if (boot_ec->handle == ACPI_ROOT_OBJECT) { |
---|
1815 | | - if (!acpi_ec_ecdt_get_handle(&handle)) |
---|
1816 | | - return -ENODEV; |
---|
1817 | | - boot_ec->handle = handle; |
---|
| 1757 | + return; |
---|
1818 | 1758 | } |
---|
1819 | 1759 | |
---|
1820 | | - /* Register to ACPI bus with PM ops attached */ |
---|
1821 | | - return acpi_bus_register_early_device(ACPI_BUS_TYPE_ECDT_EC); |
---|
| 1760 | + boot_ec = ec; |
---|
| 1761 | + |
---|
| 1762 | + acpi_handle_info(ec->handle, |
---|
| 1763 | + "Boot DSDT EC used to handle transactions\n"); |
---|
1822 | 1764 | } |
---|
1823 | 1765 | |
---|
1824 | | -#if 0 |
---|
1825 | 1766 | /* |
---|
1826 | | - * Some EC firmware variations refuses to respond QR_EC when SCI_EVT is not |
---|
1827 | | - * set, for which case, we complete the QR_EC without issuing it to the |
---|
1828 | | - * firmware. |
---|
1829 | | - * https://bugzilla.kernel.org/show_bug.cgi?id=82611 |
---|
1830 | | - * https://bugzilla.kernel.org/show_bug.cgi?id=97381 |
---|
| 1767 | + * acpi_ec_ecdt_start - Finalize the boot ECDT EC initialization. |
---|
| 1768 | + * |
---|
| 1769 | + * First, look for an ACPI handle for the boot ECDT EC if acpi_ec_add() has not |
---|
| 1770 | + * found a matching object in the namespace. |
---|
| 1771 | + * |
---|
| 1772 | + * Next, in case the DSDT EC is not functioning, it is still necessary to |
---|
| 1773 | + * provide a functional ECDT EC to handle events, so add an extra device object |
---|
| 1774 | + * to represent it (see https://bugzilla.kernel.org/show_bug.cgi?id=115021). |
---|
| 1775 | + * |
---|
| 1776 | + * This is useful on platforms with valid ECDT and invalid DSDT EC settings, |
---|
| 1777 | + * like ASUS X550ZE (see https://bugzilla.kernel.org/show_bug.cgi?id=196847). |
---|
1831 | 1778 | */ |
---|
1832 | | -static int ec_flag_query_handshake(const struct dmi_system_id *id) |
---|
| 1779 | +static void __init acpi_ec_ecdt_start(void) |
---|
1833 | 1780 | { |
---|
1834 | | - pr_debug("Detected the EC firmware requiring QR_EC issued when SCI_EVT set\n"); |
---|
1835 | | - EC_FLAGS_QUERY_HANDSHAKE = 1; |
---|
1836 | | - return 0; |
---|
| 1781 | + struct acpi_table_ecdt *ecdt_ptr; |
---|
| 1782 | + acpi_handle handle; |
---|
| 1783 | + acpi_status status; |
---|
| 1784 | + |
---|
| 1785 | + /* Bail out if a matching EC has been found in the namespace. */ |
---|
| 1786 | + if (!boot_ec || boot_ec->handle != ACPI_ROOT_OBJECT) |
---|
| 1787 | + return; |
---|
| 1788 | + |
---|
| 1789 | + /* Look up the object pointed to from the ECDT in the namespace. */ |
---|
| 1790 | + status = acpi_get_table(ACPI_SIG_ECDT, 1, |
---|
| 1791 | + (struct acpi_table_header **)&ecdt_ptr); |
---|
| 1792 | + if (ACPI_FAILURE(status)) |
---|
| 1793 | + return; |
---|
| 1794 | + |
---|
| 1795 | + status = acpi_get_handle(NULL, ecdt_ptr->id, &handle); |
---|
| 1796 | + if (ACPI_SUCCESS(status)) { |
---|
| 1797 | + boot_ec->handle = handle; |
---|
| 1798 | + |
---|
| 1799 | + /* Add a special ACPI device object to represent the boot EC. */ |
---|
| 1800 | + acpi_bus_register_early_device(ACPI_BUS_TYPE_ECDT_EC); |
---|
| 1801 | + } |
---|
| 1802 | + |
---|
| 1803 | + acpi_put_table((struct acpi_table_header *)ecdt_ptr); |
---|
1837 | 1804 | } |
---|
1838 | | -#endif |
---|
1839 | 1805 | |
---|
1840 | 1806 | /* |
---|
1841 | 1807 | * On some hardware it is necessary to clear events accumulated by the EC during |
---|
.. | .. |
---|
1875 | 1841 | } |
---|
1876 | 1842 | |
---|
1877 | 1843 | /* |
---|
1878 | | - * Some DSDTs contain wrong GPE setting. |
---|
1879 | | - * Asus FX502VD/VE, GL702VMK, X550VXK, X580VD |
---|
1880 | | - * https://bugzilla.kernel.org/show_bug.cgi?id=195651 |
---|
| 1844 | + * Some ECDTs contain wrong GPE setting, but they share the same port addresses |
---|
| 1845 | + * with DSDT EC, don't duplicate the DSDT EC with ECDT EC in this case. |
---|
| 1846 | + * https://bugzilla.kernel.org/show_bug.cgi?id=209989 |
---|
1881 | 1847 | */ |
---|
1882 | | -static int ec_honor_ecdt_gpe(const struct dmi_system_id *id) |
---|
| 1848 | +static int ec_honor_dsdt_gpe(const struct dmi_system_id *id) |
---|
1883 | 1849 | { |
---|
1884 | | - pr_debug("Detected system needing ignore DSDT GPE setting.\n"); |
---|
1885 | | - EC_FLAGS_IGNORE_DSDT_GPE = 1; |
---|
| 1850 | + pr_debug("Detected system needing DSDT GPE setting.\n"); |
---|
| 1851 | + EC_FLAGS_TRUST_DSDT_GPE = 1; |
---|
1886 | 1852 | return 0; |
---|
1887 | 1853 | } |
---|
1888 | 1854 | |
---|
.. | .. |
---|
1892 | 1858 | DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star"), |
---|
1893 | 1859 | DMI_MATCH(DMI_PRODUCT_NAME, "MS-171F"),}, NULL}, |
---|
1894 | 1860 | { |
---|
1895 | | - ec_honor_ecdt_gpe, "ASUS FX502VD", { |
---|
1896 | | - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), |
---|
1897 | | - DMI_MATCH(DMI_PRODUCT_NAME, "FX502VD"),}, NULL}, |
---|
1898 | | - { |
---|
1899 | | - ec_honor_ecdt_gpe, "ASUS FX502VE", { |
---|
1900 | | - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), |
---|
1901 | | - DMI_MATCH(DMI_PRODUCT_NAME, "FX502VE"),}, NULL}, |
---|
1902 | | - { |
---|
1903 | | - ec_honor_ecdt_gpe, "ASUS GL702VMK", { |
---|
1904 | | - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), |
---|
1905 | | - DMI_MATCH(DMI_PRODUCT_NAME, "GL702VMK"),}, NULL}, |
---|
1906 | | - { |
---|
1907 | | - ec_honor_ecdt_gpe, "ASUSTeK COMPUTER INC. X505BA", { |
---|
1908 | | - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), |
---|
1909 | | - DMI_MATCH(DMI_PRODUCT_NAME, "X505BA"),}, NULL}, |
---|
1910 | | - { |
---|
1911 | | - ec_honor_ecdt_gpe, "ASUSTeK COMPUTER INC. X505BP", { |
---|
1912 | | - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), |
---|
1913 | | - DMI_MATCH(DMI_PRODUCT_NAME, "X505BP"),}, NULL}, |
---|
1914 | | - { |
---|
1915 | | - ec_honor_ecdt_gpe, "ASUSTeK COMPUTER INC. X542BA", { |
---|
1916 | | - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), |
---|
1917 | | - DMI_MATCH(DMI_PRODUCT_NAME, "X542BA"),}, NULL}, |
---|
1918 | | - { |
---|
1919 | | - ec_honor_ecdt_gpe, "ASUSTeK COMPUTER INC. X542BP", { |
---|
1920 | | - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), |
---|
1921 | | - DMI_MATCH(DMI_PRODUCT_NAME, "X542BP"),}, NULL}, |
---|
1922 | | - { |
---|
1923 | | - ec_honor_ecdt_gpe, "ASUS X550VXK", { |
---|
1924 | | - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), |
---|
1925 | | - DMI_MATCH(DMI_PRODUCT_NAME, "X550VXK"),}, NULL}, |
---|
1926 | | - { |
---|
1927 | | - ec_honor_ecdt_gpe, "ASUS X580VD", { |
---|
1928 | | - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), |
---|
1929 | | - DMI_MATCH(DMI_PRODUCT_NAME, "X580VD"),}, NULL}, |
---|
| 1861 | + /* https://bugzilla.kernel.org/show_bug.cgi?id=209989 */ |
---|
| 1862 | + ec_honor_dsdt_gpe, "HP Pavilion Gaming Laptop 15-cx0xxx", { |
---|
| 1863 | + DMI_MATCH(DMI_SYS_VENDOR, "HP"), |
---|
| 1864 | + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Gaming Laptop 15-cx0xxx"),}, NULL}, |
---|
1930 | 1865 | { |
---|
1931 | 1866 | ec_clear_on_resume, "Samsung hardware", { |
---|
1932 | 1867 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL}, |
---|
1933 | 1868 | {}, |
---|
1934 | 1869 | }; |
---|
1935 | 1870 | |
---|
1936 | | -int __init acpi_ec_ecdt_probe(void) |
---|
| 1871 | +void __init acpi_ec_ecdt_probe(void) |
---|
1937 | 1872 | { |
---|
1938 | | - int ret; |
---|
1939 | | - acpi_status status; |
---|
1940 | 1873 | struct acpi_table_ecdt *ecdt_ptr; |
---|
1941 | 1874 | struct acpi_ec *ec; |
---|
| 1875 | + acpi_status status; |
---|
| 1876 | + int ret; |
---|
1942 | 1877 | |
---|
1943 | | - ec = acpi_ec_alloc(); |
---|
1944 | | - if (!ec) |
---|
1945 | | - return -ENOMEM; |
---|
1946 | | - /* |
---|
1947 | | - * Generate a boot ec context |
---|
1948 | | - */ |
---|
| 1878 | + /* Generate a boot ec context. */ |
---|
1949 | 1879 | dmi_check_system(ec_dmi_table); |
---|
1950 | 1880 | status = acpi_get_table(ACPI_SIG_ECDT, 1, |
---|
1951 | 1881 | (struct acpi_table_header **)&ecdt_ptr); |
---|
1952 | | - if (ACPI_FAILURE(status)) { |
---|
1953 | | - ret = -ENODEV; |
---|
1954 | | - goto error; |
---|
1955 | | - } |
---|
| 1882 | + if (ACPI_FAILURE(status)) |
---|
| 1883 | + return; |
---|
1956 | 1884 | |
---|
1957 | 1885 | if (!ecdt_ptr->control.address || !ecdt_ptr->data.address) { |
---|
1958 | 1886 | /* |
---|
1959 | 1887 | * Asus X50GL: |
---|
1960 | 1888 | * https://bugzilla.kernel.org/show_bug.cgi?id=11880 |
---|
1961 | 1889 | */ |
---|
1962 | | - ret = -ENODEV; |
---|
1963 | | - goto error; |
---|
| 1890 | + goto out; |
---|
1964 | 1891 | } |
---|
| 1892 | + |
---|
| 1893 | + ec = acpi_ec_alloc(); |
---|
| 1894 | + if (!ec) |
---|
| 1895 | + goto out; |
---|
1965 | 1896 | |
---|
1966 | 1897 | if (EC_FLAGS_CORRECT_ECDT) { |
---|
1967 | 1898 | ec->command_addr = ecdt_ptr->data.address; |
---|
.. | .. |
---|
1970 | 1901 | ec->command_addr = ecdt_ptr->control.address; |
---|
1971 | 1902 | ec->data_addr = ecdt_ptr->data.address; |
---|
1972 | 1903 | } |
---|
1973 | | - ec->gpe = ecdt_ptr->gpe; |
---|
| 1904 | + |
---|
| 1905 | + /* |
---|
| 1906 | + * Ignore the GPE value on Reduced Hardware platforms. |
---|
| 1907 | + * Some products have this set to an erroneous value. |
---|
| 1908 | + */ |
---|
| 1909 | + if (!acpi_gbl_reduced_hardware) |
---|
| 1910 | + ec->gpe = ecdt_ptr->gpe; |
---|
| 1911 | + |
---|
| 1912 | + ec->handle = ACPI_ROOT_OBJECT; |
---|
1974 | 1913 | |
---|
1975 | 1914 | /* |
---|
1976 | 1915 | * At this point, the namespace is not initialized, so do not find |
---|
1977 | 1916 | * the namespace objects, or handle the events. |
---|
1978 | 1917 | */ |
---|
1979 | | - ret = acpi_config_boot_ec(ec, ACPI_ROOT_OBJECT, false, true); |
---|
1980 | | -error: |
---|
1981 | | - if (ret) |
---|
| 1918 | + ret = acpi_ec_setup(ec, NULL); |
---|
| 1919 | + if (ret) { |
---|
1982 | 1920 | acpi_ec_free(ec); |
---|
1983 | | - return ret; |
---|
| 1921 | + goto out; |
---|
| 1922 | + } |
---|
| 1923 | + |
---|
| 1924 | + boot_ec = ec; |
---|
| 1925 | + boot_ec_is_ecdt = true; |
---|
| 1926 | + |
---|
| 1927 | + pr_info("Boot ECDT EC used to handle transactions\n"); |
---|
| 1928 | + |
---|
| 1929 | +out: |
---|
| 1930 | + acpi_put_table((struct acpi_table_header *)ecdt_ptr); |
---|
1984 | 1931 | } |
---|
1985 | 1932 | |
---|
1986 | 1933 | #ifdef CONFIG_PM_SLEEP |
---|
.. | .. |
---|
1989 | 1936 | struct acpi_ec *ec = |
---|
1990 | 1937 | acpi_driver_data(to_acpi_device(dev)); |
---|
1991 | 1938 | |
---|
1992 | | - if (acpi_sleep_no_ec_events() && ec_freeze_events) |
---|
| 1939 | + if (!pm_suspend_no_platform() && ec_freeze_events) |
---|
1993 | 1940 | acpi_ec_disable_event(ec); |
---|
1994 | 1941 | return 0; |
---|
1995 | 1942 | } |
---|
.. | .. |
---|
2003 | 1950 | * masked at the low level without side effects. |
---|
2004 | 1951 | */ |
---|
2005 | 1952 | if (ec_no_wakeup && test_bit(EC_FLAGS_STARTED, &ec->flags) && |
---|
2006 | | - ec->reference_count >= 1) |
---|
| 1953 | + ec->gpe >= 0 && ec->reference_count >= 1) |
---|
2007 | 1954 | acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE); |
---|
2008 | 1955 | |
---|
2009 | | - if (acpi_sleep_no_ec_events()) |
---|
2010 | | - acpi_ec_enter_noirq(ec); |
---|
| 1956 | + acpi_ec_enter_noirq(ec); |
---|
2011 | 1957 | |
---|
2012 | 1958 | return 0; |
---|
2013 | 1959 | } |
---|
.. | .. |
---|
2016 | 1962 | { |
---|
2017 | 1963 | struct acpi_ec *ec = acpi_driver_data(to_acpi_device(dev)); |
---|
2018 | 1964 | |
---|
2019 | | - if (acpi_sleep_no_ec_events()) |
---|
2020 | | - acpi_ec_leave_noirq(ec); |
---|
| 1965 | + acpi_ec_leave_noirq(ec); |
---|
2021 | 1966 | |
---|
2022 | 1967 | if (ec_no_wakeup && test_bit(EC_FLAGS_STARTED, &ec->flags) && |
---|
2023 | | - ec->reference_count >= 1) |
---|
| 1968 | + ec->gpe >= 0 && ec->reference_count >= 1) |
---|
2024 | 1969 | acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE); |
---|
2025 | 1970 | |
---|
2026 | 1971 | return 0; |
---|
.. | .. |
---|
2034 | 1979 | acpi_ec_enable_event(ec); |
---|
2035 | 1980 | return 0; |
---|
2036 | 1981 | } |
---|
2037 | | -#endif |
---|
| 1982 | + |
---|
| 1983 | +void acpi_ec_mark_gpe_for_wake(void) |
---|
| 1984 | +{ |
---|
| 1985 | + if (first_ec && !ec_no_wakeup) |
---|
| 1986 | + acpi_mark_gpe_for_wake(NULL, first_ec->gpe); |
---|
| 1987 | +} |
---|
| 1988 | +EXPORT_SYMBOL_GPL(acpi_ec_mark_gpe_for_wake); |
---|
| 1989 | + |
---|
| 1990 | +void acpi_ec_set_gpe_wake_mask(u8 action) |
---|
| 1991 | +{ |
---|
| 1992 | + if (pm_suspend_no_platform() && first_ec && !ec_no_wakeup) |
---|
| 1993 | + acpi_set_gpe_wake_mask(NULL, first_ec->gpe, action); |
---|
| 1994 | +} |
---|
| 1995 | + |
---|
| 1996 | +bool acpi_ec_dispatch_gpe(void) |
---|
| 1997 | +{ |
---|
| 1998 | + bool work_in_progress; |
---|
| 1999 | + u32 ret; |
---|
| 2000 | + |
---|
| 2001 | + if (!first_ec) |
---|
| 2002 | + return acpi_any_gpe_status_set(U32_MAX); |
---|
| 2003 | + |
---|
| 2004 | + /* |
---|
| 2005 | + * Report wakeup if the status bit is set for any enabled GPE other |
---|
| 2006 | + * than the EC one. |
---|
| 2007 | + */ |
---|
| 2008 | + if (acpi_any_gpe_status_set(first_ec->gpe)) |
---|
| 2009 | + return true; |
---|
| 2010 | + |
---|
| 2011 | + /* |
---|
| 2012 | + * Dispatch the EC GPE in-band, but do not report wakeup in any case |
---|
| 2013 | + * to allow the caller to process events properly after that. |
---|
| 2014 | + */ |
---|
| 2015 | + ret = acpi_dispatch_gpe(NULL, first_ec->gpe); |
---|
| 2016 | + if (ret == ACPI_INTERRUPT_HANDLED) |
---|
| 2017 | + pm_pr_dbg("ACPI EC GPE dispatched\n"); |
---|
| 2018 | + |
---|
| 2019 | + /* Drain EC work. */ |
---|
| 2020 | + do { |
---|
| 2021 | + acpi_ec_flush_work(); |
---|
| 2022 | + |
---|
| 2023 | + pm_pr_dbg("ACPI EC work flushed\n"); |
---|
| 2024 | + |
---|
| 2025 | + spin_lock_irq(&first_ec->lock); |
---|
| 2026 | + |
---|
| 2027 | + work_in_progress = first_ec->events_in_progress + |
---|
| 2028 | + first_ec->queries_in_progress > 0; |
---|
| 2029 | + |
---|
| 2030 | + spin_unlock_irq(&first_ec->lock); |
---|
| 2031 | + } while (work_in_progress && !pm_wakeup_pending()); |
---|
| 2032 | + |
---|
| 2033 | + return false; |
---|
| 2034 | +} |
---|
| 2035 | +#endif /* CONFIG_PM_SLEEP */ |
---|
2038 | 2036 | |
---|
2039 | 2037 | static const struct dev_pm_ops acpi_ec_pm = { |
---|
2040 | 2038 | SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(acpi_ec_suspend_noirq, acpi_ec_resume_noirq) |
---|
.. | .. |
---|
2065 | 2063 | { |
---|
2066 | 2064 | switch (ec_event_clearing) { |
---|
2067 | 2065 | case ACPI_EC_EVT_TIMING_STATUS: |
---|
2068 | | - return sprintf(buffer, "status"); |
---|
| 2066 | + return sprintf(buffer, "status\n"); |
---|
2069 | 2067 | case ACPI_EC_EVT_TIMING_QUERY: |
---|
2070 | | - return sprintf(buffer, "query"); |
---|
| 2068 | + return sprintf(buffer, "query\n"); |
---|
2071 | 2069 | case ACPI_EC_EVT_TIMING_EVENT: |
---|
2072 | | - return sprintf(buffer, "event"); |
---|
| 2070 | + return sprintf(buffer, "event\n"); |
---|
2073 | 2071 | default: |
---|
2074 | | - return sprintf(buffer, "invalid"); |
---|
| 2072 | + return sprintf(buffer, "invalid\n"); |
---|
2075 | 2073 | } |
---|
2076 | 2074 | return 0; |
---|
2077 | 2075 | } |
---|
.. | .. |
---|
2091 | 2089 | .drv.pm = &acpi_ec_pm, |
---|
2092 | 2090 | }; |
---|
2093 | 2091 | |
---|
2094 | | -static inline int acpi_ec_query_init(void) |
---|
| 2092 | +static void acpi_ec_destroy_workqueues(void) |
---|
2095 | 2093 | { |
---|
2096 | | - if (!ec_query_wq) { |
---|
2097 | | - ec_query_wq = alloc_workqueue("kec_query", 0, |
---|
2098 | | - ec_max_queries); |
---|
2099 | | - if (!ec_query_wq) |
---|
2100 | | - return -ENODEV; |
---|
| 2094 | + if (ec_wq) { |
---|
| 2095 | + destroy_workqueue(ec_wq); |
---|
| 2096 | + ec_wq = NULL; |
---|
2101 | 2097 | } |
---|
2102 | | - return 0; |
---|
2103 | | -} |
---|
2104 | | - |
---|
2105 | | -static inline void acpi_ec_query_exit(void) |
---|
2106 | | -{ |
---|
2107 | 2098 | if (ec_query_wq) { |
---|
2108 | 2099 | destroy_workqueue(ec_query_wq); |
---|
2109 | 2100 | ec_query_wq = NULL; |
---|
2110 | 2101 | } |
---|
| 2102 | +} |
---|
| 2103 | + |
---|
| 2104 | +static int acpi_ec_init_workqueues(void) |
---|
| 2105 | +{ |
---|
| 2106 | + if (!ec_wq) |
---|
| 2107 | + ec_wq = alloc_ordered_workqueue("kec", 0); |
---|
| 2108 | + |
---|
| 2109 | + if (!ec_query_wq) |
---|
| 2110 | + ec_query_wq = alloc_workqueue("kec_query", 0, ec_max_queries); |
---|
| 2111 | + |
---|
| 2112 | + if (!ec_wq || !ec_query_wq) { |
---|
| 2113 | + acpi_ec_destroy_workqueues(); |
---|
| 2114 | + return -ENODEV; |
---|
| 2115 | + } |
---|
| 2116 | + return 0; |
---|
2111 | 2117 | } |
---|
2112 | 2118 | |
---|
2113 | 2119 | static const struct dmi_system_id acpi_ec_no_wakeup[] = { |
---|
.. | .. |
---|
2116 | 2122 | .matches = { |
---|
2117 | 2123 | DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), |
---|
2118 | 2124 | DMI_MATCH(DMI_PRODUCT_FAMILY, "Thinkpad X1 Carbon 6th"), |
---|
2119 | | - }, |
---|
2120 | | - }, |
---|
2121 | | - { |
---|
2122 | | - .ident = "ThinkPad X1 Carbon 6th", |
---|
2123 | | - .matches = { |
---|
2124 | | - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), |
---|
2125 | | - DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Carbon 6th"), |
---|
2126 | 2125 | }, |
---|
2127 | 2126 | }, |
---|
2128 | 2127 | { |
---|
.. | .. |
---|
2135 | 2134 | { }, |
---|
2136 | 2135 | }; |
---|
2137 | 2136 | |
---|
2138 | | -int __init acpi_ec_init(void) |
---|
| 2137 | +void __init acpi_ec_init(void) |
---|
2139 | 2138 | { |
---|
2140 | 2139 | int result; |
---|
2141 | | - int ecdt_fail, dsdt_fail; |
---|
2142 | 2140 | |
---|
2143 | | - /* register workqueue for _Qxx evaluations */ |
---|
2144 | | - result = acpi_ec_query_init(); |
---|
| 2141 | + result = acpi_ec_init_workqueues(); |
---|
2145 | 2142 | if (result) |
---|
2146 | | - return result; |
---|
| 2143 | + return; |
---|
2147 | 2144 | |
---|
2148 | 2145 | /* |
---|
2149 | 2146 | * Disable EC wakeup on following systems to prevent periodic |
---|
.. | .. |
---|
2154 | 2151 | pr_debug("Disabling EC wakeup on suspend-to-idle\n"); |
---|
2155 | 2152 | } |
---|
2156 | 2153 | |
---|
2157 | | - /* Drivers must be started after acpi_ec_query_init() */ |
---|
2158 | | - dsdt_fail = acpi_bus_register_driver(&acpi_ec_driver); |
---|
2159 | | - /* |
---|
2160 | | - * Register ECDT to ACPI bus only when PNP0C09 probe fails. This is |
---|
2161 | | - * useful for platforms (confirmed on ASUS X550ZE) with valid ECDT |
---|
2162 | | - * settings but invalid DSDT settings. |
---|
2163 | | - * https://bugzilla.kernel.org/show_bug.cgi?id=196847 |
---|
2164 | | - */ |
---|
2165 | | - ecdt_fail = acpi_ec_ecdt_start(); |
---|
2166 | | - return ecdt_fail && dsdt_fail ? -ENODEV : 0; |
---|
| 2154 | + /* Driver must be registered after acpi_ec_init_workqueues(). */ |
---|
| 2155 | + acpi_bus_register_driver(&acpi_ec_driver); |
---|
| 2156 | + |
---|
| 2157 | + acpi_ec_ecdt_start(); |
---|
2167 | 2158 | } |
---|
2168 | 2159 | |
---|
2169 | 2160 | /* EC driver currently not unloadable */ |
---|
.. | .. |
---|
2172 | 2163 | { |
---|
2173 | 2164 | |
---|
2174 | 2165 | acpi_bus_unregister_driver(&acpi_ec_driver); |
---|
2175 | | - acpi_ec_query_exit(); |
---|
| 2166 | + acpi_ec_destroy_workqueues(); |
---|
2176 | 2167 | } |
---|
2177 | 2168 | #endif /* 0 */ |
---|