Skip to content

Commit 90428a8

Browse files
mkshahcMarc Zyngier
authored andcommitted
genirq/PM: Introduce IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND flag
An interrupt that is disabled/masked but set for wakeup may still need to be able to wake up the system from sleep states like "suspend to RAM". To that effect, introduce the IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND flag. If the irqchip have this flag set, the irq PM code will enable/unmask the irqs that are marked for wakeup, but that are in a disabled state. On resume, such irqs will be restored back to their disabled state. Suggested-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Maulik Shah <mkshah@codeaurora.org> [maz: commit message fix-up] Signed-off-by: Marc Zyngier <maz@kernel.org> Tested-by: Stephen Boyd <swboyd@chromium.org> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Douglas Anderson <dianders@chromium.org> Link: https://lore.kernel.org/r/1601267524-20199-4-git-send-email-mkshah@codeaurora.org
1 parent f41aaca commit 90428a8

3 files changed

Lines changed: 63 additions & 23 deletions

File tree

include/linux/irq.h

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,8 @@ struct irq_data {
215215
* from actual interrupt context.
216216
* IRQD_AFFINITY_ON_ACTIVATE - Affinity is set on activation. Don't call
217217
* irq_chip::irq_set_affinity() when deactivated.
218+
* IRQD_IRQ_ENABLED_ON_SUSPEND - Interrupt is enabled on suspend by irq pm if
219+
* irqchip have flag IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND set.
218220
*/
219221
enum {
220222
IRQD_TRIGGER_MASK = 0xf,
@@ -240,6 +242,7 @@ enum {
240242
IRQD_MSI_NOMASK_QUIRK = (1 << 27),
241243
IRQD_HANDLE_ENFORCE_IRQCTX = (1 << 28),
242244
IRQD_AFFINITY_ON_ACTIVATE = (1 << 29),
245+
IRQD_IRQ_ENABLED_ON_SUSPEND = (1 << 30),
243246
};
244247

245248
#define __irqd_to_state(d) ACCESS_PRIVATE((d)->common, state_use_accessors)
@@ -319,6 +322,11 @@ static inline bool irqd_is_handle_enforce_irqctx(struct irq_data *d)
319322
return __irqd_to_state(d) & IRQD_HANDLE_ENFORCE_IRQCTX;
320323
}
321324

325+
static inline bool irqd_is_enabled_on_suspend(struct irq_data *d)
326+
{
327+
return __irqd_to_state(d) & IRQD_IRQ_ENABLED_ON_SUSPEND;
328+
}
329+
322330
static inline bool irqd_is_wakeup_set(struct irq_data *d)
323331
{
324332
return __irqd_to_state(d) & IRQD_WAKEUP_STATE;
@@ -545,27 +553,30 @@ struct irq_chip {
545553
/*
546554
* irq_chip specific flags
547555
*
548-
* IRQCHIP_SET_TYPE_MASKED: Mask before calling chip.irq_set_type()
549-
* IRQCHIP_EOI_IF_HANDLED: Only issue irq_eoi() when irq was handled
550-
* IRQCHIP_MASK_ON_SUSPEND: Mask non wake irqs in the suspend path
551-
* IRQCHIP_ONOFFLINE_ENABLED: Only call irq_on/off_line callbacks
552-
* when irq enabled
553-
* IRQCHIP_SKIP_SET_WAKE: Skip chip.irq_set_wake(), for this irq chip
554-
* IRQCHIP_ONESHOT_SAFE: One shot does not require mask/unmask
555-
* IRQCHIP_EOI_THREADED: Chip requires eoi() on unmask in threaded mode
556-
* IRQCHIP_SUPPORTS_LEVEL_MSI Chip can provide two doorbells for Level MSIs
557-
* IRQCHIP_SUPPORTS_NMI: Chip can deliver NMIs, only for root irqchips
556+
* IRQCHIP_SET_TYPE_MASKED: Mask before calling chip.irq_set_type()
557+
* IRQCHIP_EOI_IF_HANDLED: Only issue irq_eoi() when irq was handled
558+
* IRQCHIP_MASK_ON_SUSPEND: Mask non wake irqs in the suspend path
559+
* IRQCHIP_ONOFFLINE_ENABLED: Only call irq_on/off_line callbacks
560+
* when irq enabled
561+
* IRQCHIP_SKIP_SET_WAKE: Skip chip.irq_set_wake(), for this irq chip
562+
* IRQCHIP_ONESHOT_SAFE: One shot does not require mask/unmask
563+
* IRQCHIP_EOI_THREADED: Chip requires eoi() on unmask in threaded mode
564+
* IRQCHIP_SUPPORTS_LEVEL_MSI: Chip can provide two doorbells for Level MSIs
565+
* IRQCHIP_SUPPORTS_NMI: Chip can deliver NMIs, only for root irqchips
566+
* IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND: Invokes __enable_irq()/__disable_irq() for wake irqs
567+
* in the suspend path if they are in disabled state
558568
*/
559569
enum {
560-
IRQCHIP_SET_TYPE_MASKED = (1 << 0),
561-
IRQCHIP_EOI_IF_HANDLED = (1 << 1),
562-
IRQCHIP_MASK_ON_SUSPEND = (1 << 2),
563-
IRQCHIP_ONOFFLINE_ENABLED = (1 << 3),
564-
IRQCHIP_SKIP_SET_WAKE = (1 << 4),
565-
IRQCHIP_ONESHOT_SAFE = (1 << 5),
566-
IRQCHIP_EOI_THREADED = (1 << 6),
567-
IRQCHIP_SUPPORTS_LEVEL_MSI = (1 << 7),
568-
IRQCHIP_SUPPORTS_NMI = (1 << 8),
570+
IRQCHIP_SET_TYPE_MASKED = (1 << 0),
571+
IRQCHIP_EOI_IF_HANDLED = (1 << 1),
572+
IRQCHIP_MASK_ON_SUSPEND = (1 << 2),
573+
IRQCHIP_ONOFFLINE_ENABLED = (1 << 3),
574+
IRQCHIP_SKIP_SET_WAKE = (1 << 4),
575+
IRQCHIP_ONESHOT_SAFE = (1 << 5),
576+
IRQCHIP_EOI_THREADED = (1 << 6),
577+
IRQCHIP_SUPPORTS_LEVEL_MSI = (1 << 7),
578+
IRQCHIP_SUPPORTS_NMI = (1 << 8),
579+
IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND = (1 << 9),
569580
};
570581

571582
#include <linux/irqdesc.h>

kernel/irq/debugfs.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ static const struct irq_bit_descr irqchip_flags[] = {
5757
BIT_MASK_DESCR(IRQCHIP_EOI_THREADED),
5858
BIT_MASK_DESCR(IRQCHIP_SUPPORTS_LEVEL_MSI),
5959
BIT_MASK_DESCR(IRQCHIP_SUPPORTS_NMI),
60+
BIT_MASK_DESCR(IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND),
6061
};
6162

6263
static void
@@ -125,6 +126,8 @@ static const struct irq_bit_descr irqdata_states[] = {
125126
BIT_MASK_DESCR(IRQD_DEFAULT_TRIGGER_SET),
126127

127128
BIT_MASK_DESCR(IRQD_HANDLE_ENFORCE_IRQCTX),
129+
130+
BIT_MASK_DESCR(IRQD_IRQ_ENABLED_ON_SUSPEND),
128131
};
129132

130133
static const struct irq_bit_descr irqdesc_states[] = {

kernel/irq/pm.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,26 @@ void irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action)
6969

7070
static bool suspend_device_irq(struct irq_desc *desc)
7171
{
72+
unsigned long chipflags = irq_desc_get_chip(desc)->flags;
73+
struct irq_data *irqd = &desc->irq_data;
74+
7275
if (!desc->action || irq_desc_is_chained(desc) ||
7376
desc->no_suspend_depth)
7477
return false;
7578

76-
if (irqd_is_wakeup_set(&desc->irq_data)) {
77-
irqd_set(&desc->irq_data, IRQD_WAKEUP_ARMED);
79+
if (irqd_is_wakeup_set(irqd)) {
80+
irqd_set(irqd, IRQD_WAKEUP_ARMED);
81+
82+
if ((chipflags & IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND) &&
83+
irqd_irq_disabled(irqd)) {
84+
/*
85+
* Interrupt marked for wakeup is in disabled state.
86+
* Enable interrupt here to unmask/enable in irqchip
87+
* to be able to resume with such interrupts.
88+
*/
89+
__enable_irq(desc);
90+
irqd_set(irqd, IRQD_IRQ_ENABLED_ON_SUSPEND);
91+
}
7892
/*
7993
* We return true here to force the caller to issue
8094
* synchronize_irq(). We need to make sure that the
@@ -93,7 +107,7 @@ static bool suspend_device_irq(struct irq_desc *desc)
93107
* chip level. The chip implementation indicates that with
94108
* IRQCHIP_MASK_ON_SUSPEND.
95109
*/
96-
if (irq_desc_get_chip(desc)->flags & IRQCHIP_MASK_ON_SUSPEND)
110+
if (chipflags & IRQCHIP_MASK_ON_SUSPEND)
97111
mask_irq(desc);
98112
return true;
99113
}
@@ -137,7 +151,19 @@ EXPORT_SYMBOL_GPL(suspend_device_irqs);
137151

138152
static void resume_irq(struct irq_desc *desc)
139153
{
140-
irqd_clear(&desc->irq_data, IRQD_WAKEUP_ARMED);
154+
struct irq_data *irqd = &desc->irq_data;
155+
156+
irqd_clear(irqd, IRQD_WAKEUP_ARMED);
157+
158+
if (irqd_is_enabled_on_suspend(irqd)) {
159+
/*
160+
* Interrupt marked for wakeup was enabled during suspend
161+
* entry. Disable such interrupts to restore them back to
162+
* original state.
163+
*/
164+
__disable_irq(desc);
165+
irqd_clear(irqd, IRQD_IRQ_ENABLED_ON_SUSPEND);
166+
}
141167

142168
if (desc->istate & IRQS_SUSPENDED)
143169
goto resume;

0 commit comments

Comments
 (0)