From: Peter Zijlstra <peterz@infradead.org>
To: Thomas Gleixner <tglx@linutronix.de>
Cc: rjw@rjwysocki.net, linux-kernel@vger.kernel.org
Subject: [RFC][PATCH] irq: Rework IRQF_NO_SUSPENDED
Date: Thu, 24 Jul 2014 23:26:20 +0200 [thread overview]
Message-ID: <20140724212620.GO3935@laptop> (raw)
Subject: irq: Rework IRQF_NO_SUSPENDED
From: Peter Zijlstra <peterz@infradead.org>
Date: Thu Jul 24 22:34:50 CEST 2014
Typically when devices are suspended they're quiesced such that they
will not generate any further interrupts.
However some devices should still generate interrupts, even when
suspended, typically used to wake the machine back up.
Such logic should ideally be contained inside each driver, if it can
generate interrupts when suspended, it knows about this and the
interrupt handler can deal with it.
Except of course for shared interrupts, when such a wakeup device is
sharing an interrupt line with a device that does not expect
interrupts while suspended things can go funny.
This is where IRQF_NO_SUSPEND comes in, the idea is that drivers that
have the capability to wake the machine set IRQF_NO_SUSPEND and their
handler will still be called, even when the IRQ subsystem is formally
suspended. Handlers without IRQF_NO_SUSPEND will not be called.
This replaced the prior implementation of IRQF_NO_SUSPEND which had
a number of fatal issues in that it didn't actually work for the
shared case, exactly the case it should be helping.
There is still enable_irq_wake()/IRQD_WAKEUP_STATE that tries to serve
a similar purpose but is equially wrecked for shared interrupts,
ideally this would be removed.
Cc: rjw@rjwysocki.net
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
---
kernel/irq/chip.c | 4 +---
kernel/irq/handle.c | 24 +++++++++++++++++++++---
kernel/irq/internals.h | 6 ++++--
kernel/irq/manage.c | 31 ++++++-------------------------
kernel/irq/pm.c | 17 +++++++++--------
5 files changed, 41 insertions(+), 41 deletions(-)
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -677,9 +677,7 @@ void handle_percpu_devid_irq(unsigned in
if (chip->irq_ack)
chip->irq_ack(&desc->irq_data);
- trace_irq_handler_entry(irq, action);
- res = action->handler(irq, dev_id);
- trace_irq_handler_exit(irq, action, res);
+ res = do_irqaction(desc, action, irq, dev_id);
if (chip->irq_eoi)
chip->irq_eoi(&desc->irq_data);
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -131,6 +131,23 @@ void __irq_wake_thread(struct irq_desc *
}
irqreturn_t
+do_irqaction(struct irq_desc *desc, struct irqaction *action,
+ unsigned int irq, void *dev_id)
+{
+ irqreturn_t ret;
+
+ if (unlikely((desc->istate & IRQS_SUSPENDED) &&
+ !(action->flags & IRQF_NO_SUSPEND)))
+ return IRQ_NONE;
+
+ trace_irq_handler_entry(irq, action);
+ ret = action->handler(irq, dev_id);
+ trace_irq_handler_exit(irq, action, ret);
+
+ return ret;
+}
+
+irqreturn_t
handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
{
irqreturn_t retval = IRQ_NONE;
@@ -139,9 +156,7 @@ handle_irq_event_percpu(struct irq_desc
do {
irqreturn_t res;
- trace_irq_handler_entry(irq, action);
- res = action->handler(irq, action->dev_id);
- trace_irq_handler_exit(irq, action, res);
+ res = do_irqaction(desc, action, irq, action->dev_id);
if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pF enabled interrupts\n",
irq, action->handler))
@@ -175,6 +190,9 @@ handle_irq_event_percpu(struct irq_desc
add_interrupt_randomness(irq, flags);
+ if (unlikely(desc->istate & IRQS_SUSPENDED) && retval == IRQ_NONE)
+ retval = IRQ_HANDLED;
+
if (!noirqdebug)
note_interrupt(irq, desc, retval);
return retval;
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -63,8 +63,10 @@ enum {
extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
unsigned long flags);
-extern void __disable_irq(struct irq_desc *desc, unsigned int irq, bool susp);
-extern void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume);
+
+extern irqreturn_t
+do_irqaction(struct irq_desc *desc, struct irqaction *action,
+ unsigned int irq, void *dev_id);
extern int irq_startup(struct irq_desc *desc, bool resend);
extern void irq_shutdown(struct irq_desc *desc);
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -382,15 +382,8 @@ setup_affinity(unsigned int irq, struct
}
#endif
-void __disable_irq(struct irq_desc *desc, unsigned int irq, bool suspend)
+void __disable_irq(struct irq_desc *desc, unsigned int irq)
{
- if (suspend) {
- if (!desc->action || (desc->action->flags & IRQF_NO_SUSPEND) ||
- irqd_has_set(&desc->irq_data, IRQD_WAKEUP_STATE))
- return;
- desc->istate |= IRQS_SUSPENDED;
- }
-
if (!desc->depth++)
irq_disable(desc);
}
@@ -402,7 +395,7 @@ static int __disable_irq_nosync(unsigned
if (!desc)
return -EINVAL;
- __disable_irq(desc, irq, false);
+ __disable_irq(desc, irq);
irq_put_desc_busunlock(desc, flags);
return 0;
}
@@ -443,20 +436,8 @@ void disable_irq(unsigned int irq)
}
EXPORT_SYMBOL(disable_irq);
-void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume)
+void __enable_irq(struct irq_desc *desc, unsigned int irq)
{
- if (resume) {
- if (!(desc->istate & IRQS_SUSPENDED)) {
- if (!desc->action)
- return;
- if (!(desc->action->flags & IRQF_FORCE_RESUME))
- return;
- /* Pretend that it got disabled ! */
- desc->depth++;
- }
- desc->istate &= ~IRQS_SUSPENDED;
- }
-
switch (desc->depth) {
case 0:
err_out:
@@ -498,7 +479,7 @@ void enable_irq(unsigned int irq)
KERN_ERR "enable_irq before setup/request_irq: irq %u\n", irq))
goto out;
- __enable_irq(desc, irq, false);
+ __enable_irq(desc, irq);
out:
irq_put_desc_busunlock(desc, flags);
}
@@ -1079,7 +1060,7 @@ __setup_irq(unsigned int irq, struct irq
*/
#define IRQF_MISMATCH \
- (IRQF_TRIGGER_MASK | IRQF_ONESHOT | IRQF_NO_SUSPEND)
+ (IRQF_TRIGGER_MASK | IRQF_ONESHOT)
if (!((old->flags & new->flags) & IRQF_SHARED) ||
((old->flags ^ new->flags) & IRQF_MISMATCH))
@@ -1232,7 +1213,7 @@ __setup_irq(unsigned int irq, struct irq
*/
if (shared && (desc->istate & IRQS_SPURIOUS_DISABLED)) {
desc->istate &= ~IRQS_SPURIOUS_DISABLED;
- __enable_irq(desc, irq, false);
+ __enable_irq(desc, irq);
}
raw_spin_unlock_irqrestore(&desc->lock, flags);
--- a/kernel/irq/pm.c
+++ b/kernel/irq/pm.c
@@ -29,14 +29,20 @@ void suspend_device_irqs(void)
for_each_irq_desc(irq, desc) {
unsigned long flags;
+ /*
+ * Ideally this would be a global state, but we cannot
+ * for the trainwreck that is IRQD_WAKEUP_STATE.
+ */
raw_spin_lock_irqsave(&desc->lock, flags);
- __disable_irq(desc, irq, true);
+ if (!irqd_has_set(&desc->irq_data, IRQD_WAKEUP_STATE))
+ desc->istate |= IRQS_SUSPENDED;
raw_spin_unlock_irqrestore(&desc->lock, flags);
}
- for_each_irq_desc(irq, desc)
+ for_each_irq_desc(irq, desc) {
if (desc->istate & IRQS_SUSPENDED)
synchronize_irq(irq);
+ }
}
EXPORT_SYMBOL_GPL(suspend_device_irqs);
@@ -47,14 +53,9 @@ static void resume_irqs(bool want_early)
for_each_irq_desc(irq, desc) {
unsigned long flags;
- bool is_early = desc->action &&
- desc->action->flags & IRQF_EARLY_RESUME;
-
- if (!is_early && want_early)
- continue;
raw_spin_lock_irqsave(&desc->lock, flags);
- __enable_irq(desc, irq, true);
+ desc->istate &= ~IRQS_SUSPENDED;
raw_spin_unlock_irqrestore(&desc->lock, flags);
}
}
next reply other threads:[~2014-07-24 21:26 UTC|newest]
Thread overview: 73+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-07-24 21:26 Peter Zijlstra [this message]
2014-07-24 22:02 ` [RFC][PATCH] irq: Rework IRQF_NO_SUSPENDED Rafael J. Wysocki
2014-07-24 23:10 ` Rafael J. Wysocki
2014-07-25 5:58 ` Peter Zijlstra
2014-07-29 19:20 ` Brian Norris
2014-07-29 19:28 ` Peter Zijlstra
2014-07-29 20:41 ` Brian Norris
2014-07-25 9:27 ` Thomas Gleixner
2014-07-25 12:49 ` Rafael J. Wysocki
2014-07-25 13:55 ` Thomas Gleixner
2014-07-25 9:40 ` Thomas Gleixner
2014-07-25 12:40 ` Peter Zijlstra
2014-07-25 13:25 ` Peter Zijlstra
2014-07-25 17:03 ` Rafael J. Wysocki
2014-07-25 16:58 ` Peter Zijlstra
2014-07-25 21:00 ` Thomas Gleixner
2014-07-25 22:25 ` Rafael J. Wysocki
2014-07-25 23:07 ` Rafael J. Wysocki
2014-07-26 11:49 ` Rafael J. Wysocki
2014-07-26 11:53 ` Rafael J. Wysocki
2014-07-28 6:49 ` Peter Zijlstra
2014-07-28 12:33 ` Thomas Gleixner
2014-07-28 13:04 ` Peter Zijlstra
2014-07-28 21:53 ` Rafael J. Wysocki
2014-07-28 23:01 ` Rafael J. Wysocki
2014-07-29 12:46 ` Thomas Gleixner
2014-07-29 13:33 ` Rafael J. Wysocki
2014-07-30 21:46 ` [PATCH 0/3] irq / PM: wakeup interrupt interface for drivers (was: Re: [RFC][PATCH] irq: Rework IRQF_NO_SUSPENDED) Rafael J. Wysocki
2014-07-30 21:51 ` [PATCH 1/3] irq / PM: New driver interface for wakeup interrupts Rafael J. Wysocki
2014-07-30 22:56 ` Thomas Gleixner
2014-07-31 0:12 ` Thomas Gleixner
2014-07-31 2:14 ` Rafael J. Wysocki
2014-07-31 10:44 ` Thomas Gleixner
2014-07-31 18:36 ` Rafael J. Wysocki
2014-07-31 20:12 ` Alan Stern
2014-07-31 21:04 ` Rafael J. Wysocki
2014-07-31 23:41 ` Thomas Gleixner
2014-08-01 0:51 ` Rafael J. Wysocki
2014-08-01 14:41 ` Alan Stern
2014-07-31 22:16 ` Thomas Gleixner
2014-08-01 0:08 ` Rafael J. Wysocki
2014-08-01 1:24 ` Rafael J. Wysocki
2014-08-01 9:40 ` [PATCH 1/3] irq / PM: New driver interface for wakeup interruptsn Thomas Gleixner
2014-08-01 13:45 ` Rafael J. Wysocki
2014-08-01 13:43 ` Thomas Gleixner
2014-08-01 14:29 ` Rafael J. Wysocki
2014-08-02 1:31 ` Rafael J. Wysocki
2014-08-03 13:42 ` Rafael J. Wysocki
2014-08-04 3:38 ` Rafael J. Wysocki
2014-08-05 15:22 ` [PATCH 0/5] irq / PM: Shared IRQs vs IRQF_NO_SUSPEND and suspend-to-idle wakeup Rafael J. Wysocki
2014-08-05 15:24 ` [PATCH 1/5] PM / sleep: Mechanism for aborting system suspends unconditionally Rafael J. Wysocki
2014-08-05 23:29 ` [Update][PATCH " Rafael J. Wysocki
2014-08-05 15:25 ` [PATCH 2/5] irq / PM: Fix IRQF_NO_SUSPEND problem with shared interrupts Rafael J. Wysocki
2014-08-05 15:26 ` [PATCH 3/5] irq / PM: Make wakeup interrupts wake up from suspend-to-idle Rafael J. Wysocki
2014-08-08 1:58 ` [Update][PATCH " Rafael J. Wysocki
2014-08-09 0:28 ` Rafael J. Wysocki
2014-08-05 15:27 ` [PATCH 4/5] x86 / PM: Set IRQCHIP_SKIP_SET_WAKE for IOAPIC IRQ chip objects Rafael J. Wysocki
2014-08-05 15:28 ` [PATCH 5/5] PCI / PM: Make PCIe PME interrupts wake up from suspend-to-idle Rafael J. Wysocki
2014-08-05 16:12 ` [PATCH 0/5] irq / PM: Shared IRQs vs IRQF_NO_SUSPEND and suspend-to-idle wakeup Peter Zijlstra
2014-08-08 2:09 ` Rafael J. Wysocki
2014-07-31 22:54 ` [PATCH 1/3] irq / PM: New driver interface for wakeup interrupts Thomas Gleixner
2014-07-30 21:51 ` [PATCH 2/3] PCI / PM: Make PCIe PME interrupts wake up from "freeze" sleep state Rafael J. Wysocki
2014-07-30 21:52 ` [PATCH 3/3] gpio-keys / PM: use enable/disable_device_irq_wake() Rafael J. Wysocki
2014-07-28 21:27 ` [RFC][PATCH] irq: Rework IRQF_NO_SUSPENDED Rafael J. Wysocki
2014-07-27 15:53 ` Rafael J. Wysocki
2014-07-27 22:00 ` [PATCH, v2] Rafael J. Wysocki
2014-07-28 12:11 ` Thomas Gleixner
2014-07-28 21:17 ` [PATCH, v3] irq / PM: Fix IRQF_NO_SUSPEND problem with shared interrupts (was: Re: [PATCH, v2]) Rafael J. Wysocki
2014-07-29 7:28 ` [PATCH, v4] irq / PM: Fix IRQF_NO_SUSPEND problem with shared interrupts Rafael J. Wysocki
2014-07-29 13:46 ` [PATCH, v5] " Rafael J. Wysocki
2014-07-30 0:54 ` [PATCH, v6] " Rafael J. Wysocki
2014-07-25 12:47 ` [RFC][PATCH] irq: Rework IRQF_NO_SUSPENDED Rafael J. Wysocki
2014-07-25 13:22 ` Peter Zijlstra
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20140724212620.GO3935@laptop \
--to=peterz@infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=rjw@rjwysocki.net \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox