Skip to content

Commit 896e97b

Browse files
jeremy-compostellarafaeljw
authored andcommitted
ACPI: EC: Clear GPE on interrupt handling only
On multiple devices I work on, we noticed that /sys/firmware/acpi/interrupts/sci_not is non-zero and keeps increasing over time. It turns out that there is a race condition between servicing a GPE interrupt and handling task driven transactions. If a GPE interrupt is received at the same time ec_poll() is running, the advance_transaction() clears the GPE flag and the interrupt is not serviced as acpi_ev_detect_gpe() relies on the GPE flag to call the handler. As a result, `sci_not' is increased. To address this, move the GPE status check and clearing from advance_transaction() directly into acpi_ec_handle_interrupt(), so the EC GPE only gets cleared in the interrupt handling path. Signed-off-by: Jeremy Compostella <[email protected]> [ rjw: Changelog edits ] Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 858fd16 commit 896e97b

File tree

1 file changed

+16
-15
lines changed

1 file changed

+16
-15
lines changed

drivers/acpi/ec.c

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -662,21 +662,6 @@ static void advance_transaction(struct acpi_ec *ec, bool interrupt)
662662

663663
ec_dbg_stm("%s (%d)", interrupt ? "IRQ" : "TASK", smp_processor_id());
664664

665-
/*
666-
* Clear GPE_STS upfront to allow subsequent hardware GPE_STS 0->1
667-
* changes to always trigger a GPE interrupt.
668-
*
669-
* GPE STS is a W1C register, which means:
670-
*
671-
* 1. Software can clear it without worrying about clearing the other
672-
* GPEs' STS bits when the hardware sets them in parallel.
673-
*
674-
* 2. As long as software can ensure only clearing it when it is set,
675-
* hardware won't set it in parallel.
676-
*/
677-
if (ec->gpe >= 0 && acpi_ec_gpe_status_set(ec))
678-
acpi_clear_gpe(NULL, ec->gpe);
679-
680665
status = acpi_ec_read_status(ec);
681666

682667
/*
@@ -1287,6 +1272,22 @@ static void acpi_ec_handle_interrupt(struct acpi_ec *ec)
12871272
unsigned long flags;
12881273

12891274
spin_lock_irqsave(&ec->lock, flags);
1275+
1276+
/*
1277+
* Clear GPE_STS upfront to allow subsequent hardware GPE_STS 0->1
1278+
* changes to always trigger a GPE interrupt.
1279+
*
1280+
* GPE STS is a W1C register, which means:
1281+
*
1282+
* 1. Software can clear it without worrying about clearing the other
1283+
* GPEs' STS bits when the hardware sets them in parallel.
1284+
*
1285+
* 2. As long as software can ensure only clearing it when it is set,
1286+
* hardware won't set it in parallel.
1287+
*/
1288+
if (ec->gpe >= 0 && acpi_ec_gpe_status_set(ec))
1289+
acpi_clear_gpe(NULL, ec->gpe);
1290+
12901291
advance_transaction(ec, true);
12911292
spin_unlock_irqrestore(&ec->lock, flags);
12921293
}

0 commit comments

Comments
 (0)