cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

suspend-and-interrupts.rst (7279B)


      1====================================
      2System Suspend and Device Interrupts
      3====================================
      4
      5Copyright (C) 2014 Intel Corp.
      6Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
      7
      8
      9Suspending and Resuming Device IRQs
     10-----------------------------------
     11
     12Device interrupt request lines (IRQs) are generally disabled during system
     13suspend after the "late" phase of suspending devices (that is, after all of the
     14->prepare, ->suspend and ->suspend_late callbacks have been executed for all
     15devices).  That is done by suspend_device_irqs().
     16
     17The rationale for doing so is that after the "late" phase of device suspend
     18there is no legitimate reason why any interrupts from suspended devices should
     19trigger and if any devices have not been suspended properly yet, it is better to
     20block interrupts from them anyway.  Also, in the past we had problems with
     21interrupt handlers for shared IRQs that device drivers implementing them were
     22not prepared for interrupts triggering after their devices had been suspended.
     23In some cases they would attempt to access, for example, memory address spaces
     24of suspended devices and cause unpredictable behavior to ensue as a result.
     25Unfortunately, such problems are very difficult to debug and the introduction
     26of suspend_device_irqs(), along with the "noirq" phase of device suspend and
     27resume, was the only practical way to mitigate them.
     28
     29Device IRQs are re-enabled during system resume, right before the "early" phase
     30of resuming devices (that is, before starting to execute ->resume_early
     31callbacks for devices).  The function doing that is resume_device_irqs().
     32
     33
     34The IRQF_NO_SUSPEND Flag
     35------------------------
     36
     37There are interrupts that can legitimately trigger during the entire system
     38suspend-resume cycle, including the "noirq" phases of suspending and resuming
     39devices as well as during the time when nonboot CPUs are taken offline and
     40brought back online.  That applies to timer interrupts in the first place,
     41but also to IPIs and to some other special-purpose interrupts.
     42
     43The IRQF_NO_SUSPEND flag is used to indicate that to the IRQ subsystem when
     44requesting a special-purpose interrupt.  It causes suspend_device_irqs() to
     45leave the corresponding IRQ enabled so as to allow the interrupt to work as
     46expected during the suspend-resume cycle, but does not guarantee that the
     47interrupt will wake the system from a suspended state -- for such cases it is
     48necessary to use enable_irq_wake().
     49
     50Note that the IRQF_NO_SUSPEND flag affects the entire IRQ and not just one
     51user of it.  Thus, if the IRQ is shared, all of the interrupt handlers installed
     52for it will be executed as usual after suspend_device_irqs(), even if the
     53IRQF_NO_SUSPEND flag was not passed to request_irq() (or equivalent) by some of
     54the IRQ's users.  For this reason, using IRQF_NO_SUSPEND and IRQF_SHARED at the
     55same time should be avoided.
     56
     57
     58System Wakeup Interrupts, enable_irq_wake() and disable_irq_wake()
     59------------------------------------------------------------------
     60
     61System wakeup interrupts generally need to be configured to wake up the system
     62from sleep states, especially if they are used for different purposes (e.g. as
     63I/O interrupts) in the working state.
     64
     65That may involve turning on a special signal handling logic within the platform
     66(such as an SoC) so that signals from a given line are routed in a different way
     67during system sleep so as to trigger a system wakeup when needed.  For example,
     68the platform may include a dedicated interrupt controller used specifically for
     69handling system wakeup events.  Then, if a given interrupt line is supposed to
     70wake up the system from sleep sates, the corresponding input of that interrupt
     71controller needs to be enabled to receive signals from the line in question.
     72After wakeup, it generally is better to disable that input to prevent the
     73dedicated controller from triggering interrupts unnecessarily.
     74
     75The IRQ subsystem provides two helper functions to be used by device drivers for
     76those purposes.  Namely, enable_irq_wake() turns on the platform's logic for
     77handling the given IRQ as a system wakeup interrupt line and disable_irq_wake()
     78turns that logic off.
     79
     80Calling enable_irq_wake() causes suspend_device_irqs() to treat the given IRQ
     81in a special way.  Namely, the IRQ remains enabled, by on the first interrupt
     82it will be disabled, marked as pending and "suspended" so that it will be
     83re-enabled by resume_device_irqs() during the subsequent system resume.  Also
     84the PM core is notified about the event which causes the system suspend in
     85progress to be aborted (that doesn't have to happen immediately, but at one
     86of the points where the suspend thread looks for pending wakeup events).
     87
     88This way every interrupt from a wakeup interrupt source will either cause the
     89system suspend currently in progress to be aborted or wake up the system if
     90already suspended.  However, after suspend_device_irqs() interrupt handlers are
     91not executed for system wakeup IRQs.  They are only executed for IRQF_NO_SUSPEND
     92IRQs at that time, but those IRQs should not be configured for system wakeup
     93using enable_irq_wake().
     94
     95
     96Interrupts and Suspend-to-Idle
     97------------------------------
     98
     99Suspend-to-idle (also known as the "freeze" sleep state) is a relatively new
    100system sleep state that works by idling all of the processors and waiting for
    101interrupts right after the "noirq" phase of suspending devices.
    102
    103Of course, this means that all of the interrupts with the IRQF_NO_SUSPEND flag
    104set will bring CPUs out of idle while in that state, but they will not cause the
    105IRQ subsystem to trigger a system wakeup.
    106
    107System wakeup interrupts, in turn, will trigger wakeup from suspend-to-idle in
    108analogy with what they do in the full system suspend case.  The only difference
    109is that the wakeup from suspend-to-idle is signaled using the usual working
    110state interrupt delivery mechanisms and doesn't require the platform to use
    111any special interrupt handling logic for it to work.
    112
    113
    114IRQF_NO_SUSPEND and enable_irq_wake()
    115-------------------------------------
    116
    117There are very few valid reasons to use both enable_irq_wake() and the
    118IRQF_NO_SUSPEND flag on the same IRQ, and it is never valid to use both for the
    119same device.
    120
    121First of all, if the IRQ is not shared, the rules for handling IRQF_NO_SUSPEND
    122interrupts (interrupt handlers are invoked after suspend_device_irqs()) are
    123directly at odds with the rules for handling system wakeup interrupts (interrupt
    124handlers are not invoked after suspend_device_irqs()).
    125
    126Second, both enable_irq_wake() and IRQF_NO_SUSPEND apply to entire IRQs and not
    127to individual interrupt handlers, so sharing an IRQ between a system wakeup
    128interrupt source and an IRQF_NO_SUSPEND interrupt source does not generally
    129make sense.
    130
    131In rare cases an IRQ can be shared between a wakeup device driver and an
    132IRQF_NO_SUSPEND user. In order for this to be safe, the wakeup device driver
    133must be able to discern spurious IRQs from genuine wakeup events (signalling
    134the latter to the core with pm_system_wakeup()), must use enable_irq_wake() to
    135ensure that the IRQ will function as a wakeup source, and must request the IRQ
    136with IRQF_COND_SUSPEND to tell the core that it meets these requirements. If
    137these requirements are not met, it is not valid to use IRQF_COND_SUSPEND.