Subject: ACPI: Avoid bogus EC mode switch from interrupt to polling From : Zhao Yakui When EC works in GPE interrupt mode, sometimes it will be switched from interrupt mode to polling mode when EC timeout happens. if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event), msecs_to_jiffies(ACPI_EC_DELAY))) return 0; In fact in Linux although one process is already by wakeup by some events (For example: interrupt wakeup, timeout wakeup), it won't be scheduled immediately. Maybe it will have to wait for some time before it is scheduled on some CPU. In such case maybe there exists the following phenomenon. When the EC GPE interrupt is triggered, the waiting process will be waked up in the GPE interrupt service routine. But as the process can't be scheduled immediately, maybe the wait_event_timeout will also return 0, which means that timeout happens and EC will be switched from interrupt mode to polling mode. As when the EC_FLAGS_WAIT_GPE bit will be cleared in GPE handler, Maybe it will be appropriate that OS check the EC_FLAGS_WAIT_GPE bit of EC flag and EC status before mode switch although timeout happens. If the bit of EC_FLAGS_WAIT_GPE is changed and EC status is what we expect, OS won't switch EC work mode even when the timeout happens. Otherwise it will continue the orignal routine. --- drivers/acpi/ec.c | 9 +++++++++ 1 file changed, 9 insertions(+) Index: linux-2.6/drivers/acpi/ec.c =================================================================== --- linux-2.6.orig/drivers/acpi/ec.c +++ linux-2.6/drivers/acpi/ec.c @@ -203,6 +203,15 @@ static int acpi_ec_wait(struct acpi_ec * if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event), msecs_to_jiffies(ACPI_EC_DELAY))) return 0; + /* + * If the EC_FLAGS_WAI_GPE bit is already clear and EC status + * is what OS expects, it won't be switched interrupt mode to + * polling mode. + */ + if (!test_bit(EC_FLAGS_WAIT_GPE, &ec->flags) && + acpi_ec_check_status(ec, event)) + return 0; + clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); if (acpi_ec_check_status(ec, event)) { /* missing GPEs, switch back to poll mode */