aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/ec.c81
1 files changed, 73 insertions, 8 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index c385606bbceb..2540870e89f7 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -121,6 +121,7 @@ struct transaction {
121}; 121};
122 122
123static int acpi_ec_query(struct acpi_ec *ec, u8 *data); 123static int acpi_ec_query(struct acpi_ec *ec, u8 *data);
124static void advance_transaction(struct acpi_ec *ec);
124 125
125struct acpi_ec *boot_ec, *first_ec; 126struct acpi_ec *boot_ec, *first_ec;
126EXPORT_SYMBOL(first_ec); 127EXPORT_SYMBOL(first_ec);
@@ -132,7 +133,7 @@ static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
132static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */ 133static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */
133 134
134/* -------------------------------------------------------------------------- 135/* --------------------------------------------------------------------------
135 * Transaction Management 136 * EC Registers
136 * -------------------------------------------------------------------------- */ 137 * -------------------------------------------------------------------------- */
137 138
138static inline u8 acpi_ec_read_status(struct acpi_ec *ec) 139static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
@@ -191,6 +192,64 @@ static const char *acpi_ec_cmd_string(u8 cmd)
191#define acpi_ec_cmd_string(cmd) "UNDEF" 192#define acpi_ec_cmd_string(cmd) "UNDEF"
192#endif 193#endif
193 194
195/* --------------------------------------------------------------------------
196 * GPE Registers
197 * -------------------------------------------------------------------------- */
198
199static inline bool acpi_ec_is_gpe_raised(struct acpi_ec *ec)
200{
201 acpi_event_status gpe_status = 0;
202
203 (void)acpi_get_gpe_status(NULL, ec->gpe, &gpe_status);
204 return (gpe_status & ACPI_EVENT_FLAG_SET) ? true : false;
205}
206
207static inline void acpi_ec_enable_gpe(struct acpi_ec *ec, bool open)
208{
209 if (open)
210 acpi_enable_gpe(NULL, ec->gpe);
211 else
212 acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
213 if (acpi_ec_is_gpe_raised(ec)) {
214 /*
215 * On some platforms, EN=1 writes cannot trigger GPE. So
216 * software need to manually trigger a pseudo GPE event on
217 * EN=1 writes.
218 */
219 pr_debug("***** Polling quirk *****\n");
220 advance_transaction(ec);
221 }
222}
223
224static inline void acpi_ec_disable_gpe(struct acpi_ec *ec, bool close)
225{
226 if (close)
227 acpi_disable_gpe(NULL, ec->gpe);
228 else
229 acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
230}
231
232static inline void acpi_ec_clear_gpe(struct acpi_ec *ec)
233{
234 /*
235 * GPE STS is a W1C register, which means:
236 * 1. Software can clear it without worrying about clearing other
237 * GPEs' STS bits when the hardware sets them in parallel.
238 * 2. As long as software can ensure only clearing it when it is
239 * set, hardware won't set it in parallel.
240 * So software can clear GPE in any contexts.
241 * Warning: do not move the check into advance_transaction() as the
242 * EC commands will be sent without GPE raised.
243 */
244 if (!acpi_ec_is_gpe_raised(ec))
245 return;
246 acpi_clear_gpe(NULL, ec->gpe);
247}
248
249/* --------------------------------------------------------------------------
250 * Transaction Management
251 * -------------------------------------------------------------------------- */
252
194static void acpi_ec_submit_query(struct acpi_ec *ec) 253static void acpi_ec_submit_query(struct acpi_ec *ec)
195{ 254{
196 if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { 255 if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
@@ -227,6 +286,12 @@ static void advance_transaction(struct acpi_ec *ec)
227 286
228 pr_debug("===== %s (%d) =====\n", 287 pr_debug("===== %s (%d) =====\n",
229 in_interrupt() ? "IRQ" : "TASK", smp_processor_id()); 288 in_interrupt() ? "IRQ" : "TASK", smp_processor_id());
289 /*
290 * By always clearing STS before handling all indications, we can
291 * ensure a hardware STS 0->1 change after this clearing can always
292 * trigger a GPE interrupt.
293 */
294 acpi_ec_clear_gpe(ec);
230 status = acpi_ec_read_status(ec); 295 status = acpi_ec_read_status(ec);
231 t = ec->curr; 296 t = ec->curr;
232 if (!t) 297 if (!t)
@@ -378,7 +443,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
378 /* disable GPE during transaction if storm is detected */ 443 /* disable GPE during transaction if storm is detected */
379 if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { 444 if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
380 /* It has to be disabled, so that it doesn't trigger. */ 445 /* It has to be disabled, so that it doesn't trigger. */
381 acpi_disable_gpe(NULL, ec->gpe); 446 acpi_ec_disable_gpe(ec, false);
382 } 447 }
383 448
384 status = acpi_ec_transaction_unlocked(ec, t); 449 status = acpi_ec_transaction_unlocked(ec, t);
@@ -386,7 +451,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
386 if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { 451 if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
387 msleep(1); 452 msleep(1);
388 /* It is safe to enable the GPE outside of the transaction. */ 453 /* It is safe to enable the GPE outside of the transaction. */
389 acpi_enable_gpe(NULL, ec->gpe); 454 acpi_ec_enable_gpe(ec, false);
390 } else if (t->irq_count > ec_storm_threshold) { 455 } else if (t->irq_count > ec_storm_threshold) {
391 pr_info("GPE storm detected(%d GPEs), " 456 pr_info("GPE storm detected(%d GPEs), "
392 "transactions will use polling mode\n", 457 "transactions will use polling mode\n",
@@ -693,7 +758,7 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
693 spin_lock_irqsave(&ec->lock, flags); 758 spin_lock_irqsave(&ec->lock, flags);
694 advance_transaction(ec); 759 advance_transaction(ec);
695 spin_unlock_irqrestore(&ec->lock, flags); 760 spin_unlock_irqrestore(&ec->lock, flags);
696 return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE; 761 return ACPI_INTERRUPT_HANDLED;
697} 762}
698 763
699/* -------------------------------------------------------------------------- 764/* --------------------------------------------------------------------------
@@ -812,13 +877,13 @@ static int ec_install_handlers(struct acpi_ec *ec)
812 877
813 if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags)) 878 if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags))
814 return 0; 879 return 0;
815 status = acpi_install_gpe_handler(NULL, ec->gpe, 880 status = acpi_install_gpe_raw_handler(NULL, ec->gpe,
816 ACPI_GPE_EDGE_TRIGGERED, 881 ACPI_GPE_EDGE_TRIGGERED,
817 &acpi_ec_gpe_handler, ec); 882 &acpi_ec_gpe_handler, ec);
818 if (ACPI_FAILURE(status)) 883 if (ACPI_FAILURE(status))
819 return -ENODEV; 884 return -ENODEV;
820 885
821 acpi_enable_gpe(NULL, ec->gpe); 886 acpi_ec_enable_gpe(ec, true);
822 status = acpi_install_address_space_handler(ec->handle, 887 status = acpi_install_address_space_handler(ec->handle,
823 ACPI_ADR_SPACE_EC, 888 ACPI_ADR_SPACE_EC,
824 &acpi_ec_space_handler, 889 &acpi_ec_space_handler,
@@ -833,7 +898,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
833 pr_err("Fail in evaluating the _REG object" 898 pr_err("Fail in evaluating the _REG object"
834 " of EC device. Broken bios is suspected.\n"); 899 " of EC device. Broken bios is suspected.\n");
835 } else { 900 } else {
836 acpi_disable_gpe(NULL, ec->gpe); 901 acpi_ec_disable_gpe(ec, true);
837 acpi_remove_gpe_handler(NULL, ec->gpe, 902 acpi_remove_gpe_handler(NULL, ec->gpe,
838 &acpi_ec_gpe_handler); 903 &acpi_ec_gpe_handler);
839 return -ENODEV; 904 return -ENODEV;
@@ -848,7 +913,7 @@ static void ec_remove_handlers(struct acpi_ec *ec)
848{ 913{
849 if (!test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags)) 914 if (!test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags))
850 return; 915 return;
851 acpi_disable_gpe(NULL, ec->gpe); 916 acpi_ec_disable_gpe(ec, true);
852 if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle, 917 if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
853 ACPI_ADR_SPACE_EC, &acpi_ec_space_handler))) 918 ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
854 pr_err("failed to remove space handler\n"); 919 pr_err("failed to remove space handler\n");