• Hans de Goede's avatar
    x86: Select HARDIRQS_SW_RESEND on x86 · 17e5888e
    Hans de Goede authored
    Modern x86 laptops are starting to use GPIO pins as interrupts more
    and more, e.g. touchpads and touchscreens have almost all moved away
    from PS/2 and USB to using I2C with a GPIO pin as interrupt.
    Modern x86 laptops also have almost all moved to using s2idle instead
    of using the system S3 ACPI power state to suspend.
    
    The Intel and AMD pinctrl drivers do not define irq_retrigger handlers
    for the irqchips they register, this is causing edge triggered interrupts
    which happen while suspended using s2idle to get lost.
    
    One specific example of this is the lid switch on some devices, lid
    switches used to be handled by the embedded-controller, but now the
    lid open/closed sensor is sometimes directly connected to a GPIO pin.
    On most devices the ACPI code for this looks like this:
    
    Method (_E00, ...) {
    	Notify (LID0, 0x80) // Status Change
    }
    
    Where _E00 is an ACPI event handler for changes on both edges of the GPIO
    connected to the lid sensor, this event handler is then combined with an
    _LID method which directly reads the pin. When the device is resumed by
    opening the lid, the GPIO interrupt will wake the system, but because the
    pinctrl irqchip doesn't have an irq_retrigger handler, the Notify will not
    happen. This is not a problem in the case the _LID method directly reads
    the GPIO, because the drivers/acpi/button.c code will call _LID on resume
    anyways.
    
    But some devices have an event handler for the GPIO connected to the
    lid sensor which looks like this:
    
    Method (_E00, ...) {
    	if (LID_GPIO == One)
    		LIDS = One
    	else
    		LIDS = Zero
    	Notify (LID0, 0x80) // Status Change
    }
    
    And the _LID method returns the cached LIDS value, since on open we
    do not re-run the edge-interrupt handler when we re-enable IRQS on resume
    (because of the missing irq_retrigger handler), _LID now will keep
    reporting closed, as LIDS was never changed to reflect the open status,
    this causes userspace to re-resume the laptop again shortly after opening
    the lid.
    
    The Intel GPIO controllers do not allow implementing irq_retrigger without
    emulating it in software, at which point we are better of just using the
    generic HARDIRQS_SW_RESEND mechanism rather then re-implementing software
    emulation for this separately in aprox. 14 different pinctrl drivers.
    
    Select HARDIRQS_SW_RESEND to solve the problem of edge-triggered GPIO
    interrupts not being re-triggered on resume when they were triggered during
    suspend (s2idle) and/or when they were the cause of the wakeup.
    
    This requires
    
     008f1d60 ("x86/apic/vector: Force interupt handler invocation to irq context")
     c16816ac ("genirq: Add protection against unsafe usage of generic_handle_irq()")
    
    to protect the APIC based interrupts from being wreckaged by a software
    resend.
    Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
    Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
    Link: https://lkml.kernel.org/r/20200123210242.53367-1-hdegoede@redhat.com
    17e5888e
Kconfig 95.7 KB