Blame view

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