• Rafael J. Wysocki's avatar
    PCI / PM: Fix native PME handling during system suspend/resume · c7b5a4e6
    Rafael J. Wysocki authored
    Commit 76cde7e4 (PCI / PM: Make PCIe PME interrupts wake up from
    suspend-to-idle) went too far with preventing pcie_pme_work_fn() from
    clearing the root port's PME Status and re-enabling the PME interrupt
    which should be done for PMEs to work correctly after system resume.
    
    The failing scenario is as follows:
    
     1. pcie_pme_suspend() finds that the PME IRQ should be designated
        for system wakeup, so it calls enable_irq_wake() and then sets
        data->suspend_level to PME_SUSPEND_WAKEUP.
    
     2. PME interrupt happens at this point.
    
     3. pcie_pme_irq() runs, disables the PME interrupt and queues up
        the execution of pcie_pme_work_fn().
    
     4. pcie_pme_work_fn() runs before pcie_pme_resume() and breaks out
        of the loop right away, because data->suspend_level is not
        PME_SUSPEND_NONE, and it doesn't re-enable the PME interrupt
        for the same reason.
    
     5. pcie_pme_resume() runs and simply calls disable_irq_wake()
        without re-enabling the PME interrupt (because data->suspend_level
        is not PME_SUSPEND_NONE), so the PME interrupt remains disabled
        and the PME Status remains set.
    
    To fix this notice that there is no reason why pcie_pme_work_fn()
    should behave in a special way during system resume if the PME
    interrupt is not disabled by pcie_pme_suspend() and partially revert
    commit 76cde7e4 and restore the previous (and correct) behavior
    of pcie_pme_work_fn().
    
    Fixes: 76cde7e4 (PCI / PM: Make PCIe PME interrupts wake up from suspend-to-idle)
    Reported-and-tested-by: default avatarNaresh Solanki <naresh.solanki@intel.com>
    Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
    Acked-by: default avatarBjorn Helgaas <bhelgaas@google.com>
    c7b5a4e6
pme.c 11 KB