Message ID | 8151717.nkhnGBri9h@vostro.rjw.lan (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Thu, 26 Feb 2015 19:17:03 +0100 "Rafael J. Wysocki" <rjw@rjwysocki.net> wrote: > On Thursday, February 26, 2015 04:47:24 PM Boris Brezillon wrote: > > On Thu, 26 Feb 2015 16:44:16 +0100 > > "Rafael J. Wysocki" <rjw@rjwysocki.net> wrote: [...] > > > > > > But it is still a bit risky. Namely, if the driver in question is sufficiently > > > broken (eg. it may not suspend the device and rely on the fact that its interrupt > > > handler will be run just because it is sharing a "no suspend" IRQ), we may get > > > an interrupt storm. > > > > > > Isn't that a problem? > > > > For me no (I'll fix all the drivers to handle wakeup, and they are all > > already masking interrupts coming from their side in the suspend > > callback). > > I can't talk for other people though. > > The only problem I see here is that you're not informing people that > > they are erroneously mixing IRQF_NO_SUSPEND and !IRQF_NO_SUSPEND anymore > > (you removed the warning backtrace). > > Moreover, you are replacing their handler by a stub when entering > > suspend, so they might end-up receiving spurious interrupts when > > suspended without knowing why ? > > > > How about checking if the number of actions registered with > > IRQF_NO_SUSPEND + those registered with IRQF_COND_SUSPEND (or another > > flag stating that the handler can safely be called in suspended state > > even if it didn't ask for NO_SUSPEND) are equal to the total number of > > registered actions, and complain if it's not the case. > > The same idea I had while talking to Peter over IRC. So the patch below > implements that. Yep, that's what I had in mind.
On Thursday, February 26, 2015 07:17:24 PM Boris Brezillon wrote: > On Thu, 26 Feb 2015 19:17:03 +0100 > "Rafael J. Wysocki" <rjw@rjwysocki.net> wrote: > > > On Thursday, February 26, 2015 04:47:24 PM Boris Brezillon wrote: > > > On Thu, 26 Feb 2015 16:44:16 +0100 > > > "Rafael J. Wysocki" <rjw@rjwysocki.net> wrote: > > [...] > > > > > > > > > But it is still a bit risky. Namely, if the driver in question is sufficiently > > > > broken (eg. it may not suspend the device and rely on the fact that its interrupt > > > > handler will be run just because it is sharing a "no suspend" IRQ), we may get > > > > an interrupt storm. > > > > > > > > Isn't that a problem? > > > > > > For me no (I'll fix all the drivers to handle wakeup, and they are all > > > already masking interrupts coming from their side in the suspend > > > callback). > > > I can't talk for other people though. > > > The only problem I see here is that you're not informing people that > > > they are erroneously mixing IRQF_NO_SUSPEND and !IRQF_NO_SUSPEND anymore > > > (you removed the warning backtrace). > > > Moreover, you are replacing their handler by a stub when entering > > > suspend, so they might end-up receiving spurious interrupts when > > > suspended without knowing why ? > > > > > > How about checking if the number of actions registered with > > > IRQF_NO_SUSPEND + those registered with IRQF_COND_SUSPEND (or another > > > flag stating that the handler can safely be called in suspended state > > > even if it didn't ask for NO_SUSPEND) are equal to the total number of > > > registered actions, and complain if it's not the case. > > > > The same idea I had while talking to Peter over IRC. So the patch below > > implements that. > > Yep, that's what I had in mind. OK, thanks. I'll submit it formally, then.
Index: linux-pm/include/linux/interrupt.h =================================================================== --- linux-pm.orig/include/linux/interrupt.h +++ linux-pm/include/linux/interrupt.h @@ -57,6 +57,10 @@ * IRQF_NO_THREAD - Interrupt cannot be threaded * IRQF_EARLY_RESUME - Resume IRQ early during syscore instead of at device * resume time. + * IRQF_COND_SUSPEND - If the IRQ is shared with a NO_SUSPEND user, execute this + * interrupt handler after suspending interrupts. For system + * wakeup devices users need to implement wakeup detection in + * their interrupt handlers. */ #define IRQF_DISABLED 0x00000020 #define IRQF_SHARED 0x00000080 @@ -70,6 +74,7 @@ #define IRQF_FORCE_RESUME 0x00008000 #define IRQF_NO_THREAD 0x00010000 #define IRQF_EARLY_RESUME 0x00020000 +#define IRQF_COND_SUSPEND 0x00040000 #define IRQF_TIMER (__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD) Index: linux-pm/include/linux/irqdesc.h =================================================================== --- linux-pm.orig/include/linux/irqdesc.h +++ linux-pm/include/linux/irqdesc.h @@ -78,6 +78,7 @@ struct irq_desc { #ifdef CONFIG_PM_SLEEP unsigned int nr_actions; unsigned int no_suspend_depth; + unsigned int cond_suspend_depth; unsigned int force_resume_depth; #endif #ifdef CONFIG_PROC_FS Index: linux-pm/kernel/irq/pm.c =================================================================== --- linux-pm.orig/kernel/irq/pm.c +++ linux-pm/kernel/irq/pm.c @@ -43,9 +43,12 @@ void irq_pm_install_action(struct irq_de if (action->flags & IRQF_NO_SUSPEND) desc->no_suspend_depth++; + else if (action->flags & IRQF_COND_SUSPEND) + desc->cond_suspend_depth++; WARN_ON_ONCE(desc->no_suspend_depth && - desc->no_suspend_depth != desc->nr_actions); + (desc->no_suspend_depth + + desc->cond_suspend_depth) != desc->nr_actions); } /* @@ -61,6 +64,8 @@ void irq_pm_remove_action(struct irq_des if (action->flags & IRQF_NO_SUSPEND) desc->no_suspend_depth--; + else if (action->flags & IRQF_COND_SUSPEND) + desc->cond_suspend_depth--; } static bool suspend_device_irq(struct irq_desc *desc, int irq) Index: linux-pm/kernel/irq/manage.c =================================================================== --- linux-pm.orig/kernel/irq/manage.c +++ linux-pm/kernel/irq/manage.c @@ -1474,8 +1474,13 @@ int request_threaded_irq(unsigned int ir * otherwise we'll have trouble later trying to figure out * which interrupt is which (messes up the interrupt freeing * logic etc). + * + * Also IRQF_COND_SUSPEND only makes sense for shared interrupts and + * it is mutually exclusive with IRQF_NO_SUSPEND. */ - if ((irqflags & IRQF_SHARED) && !dev_id) + if (((irqflags & IRQF_SHARED) && !dev_id) || + (!(irqflags & IRQF_SHARED) && (irqflags & IRQF_COND_SUSPEND)) || + ((irqflags & IRQF_NO_SUSPEND) && (irqflags & IRQF_COND_SUSPEND))) return -EINVAL; desc = irq_to_desc(irq);