Re: [PATCH 2/4] genirq: Provide NMI management for percpu_devid interrupts
On 01/08/18 04:11, Ricardo Neri wrote: On Tue, Jul 24, 2018 at 12:07:05PM +0100, Julien Thierry wrote: Add support for percpu_devid interrupts treated as NMIs. Percpu_devid NMIs need to be setup/torn down on each CPU they target. The same restrictions as for global NMIs still apply for percpu_devid NMIs. Signed-off-by: Julien Thierry Cc: Thomas Gleixner Cc: Peter Zijlstra Cc: Ingo Molnar Cc: Marc Zyngier --- include/linux/interrupt.h | 9 +++ kernel/irq/manage.c | 149 ++ 2 files changed, 158 insertions(+) diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 3b1a320..59d3877 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -168,10 +168,15 @@ struct irqaction { devname, percpu_dev_id); } +extern int __must_check +request_percpu_nmi(unsigned int irq, irq_handler_t handler, + const char *devname, void __percpu *dev); + extern const void *free_irq(unsigned int, void *); extern void free_percpu_irq(unsigned int, void __percpu *); extern const void *free_nmi(unsigned int irq, void *dev_id); +extern void free_percpu_nmi(unsigned int irq, void __percpu *percpu_dev_id); struct device; @@ -224,7 +229,11 @@ struct irqaction { extern void irq_wake_thread(unsigned int irq, void *dev_id); extern void disable_nmi_nosync(unsigned int irq); +extern void disable_percpu_nmi(unsigned int irq); Shouldn't this be a disable_percpu_nmi_nosync() as disable_nmi_nosync()? The naming of the disable_percpu_irq didn't include the nosync either (and it doesn't wait for pending percpu_devid_irqs) extern void enable_nmi(unsigned int irq); +extern void enable_percpu_nmi(unsigned int irq, unsigned int type); +extern int ready_percpu_nmi(unsigned int irq); +extern void teardown_percpu_nmi(unsigned int irq); /* The following three functions are for the core kernel use only. */ extern void suspend_device_irqs(void); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 3b87143..ad41c4d 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -2162,6 +2162,11 @@ void enable_percpu_irq(unsigned int irq, unsigned int type) } EXPORT_SYMBOL_GPL(enable_percpu_irq); +void enable_percpu_nmi(unsigned int irq, unsigned int type) +{ + enable_percpu_irq(irq, type); +} + /** * irq_percpu_is_enabled - Check whether the per cpu irq is enabled * @irq: Linux irq number to check for @@ -2201,6 +2206,11 @@ void disable_percpu_irq(unsigned int irq) } EXPORT_SYMBOL_GPL(disable_percpu_irq); +void disable_percpu_nmi(unsigned int irq) +{ + disable_percpu_irq(irq); +} + /* * Internal function to unregister a percpu irqaction. */ @@ -2232,6 +2242,8 @@ static struct irqaction *__free_percpu_irq(unsigned int irq, void __percpu *dev_ /* Found it - now remove it from the list of entries: */ desc->action = NULL; + desc->istate &= ~IRQS_NMI; + raw_spin_unlock_irqrestore(>lock, flags); unregister_handler_proc(irq, action); @@ -2285,6 +2297,19 @@ void free_percpu_irq(unsigned int irq, void __percpu *dev_id) } EXPORT_SYMBOL_GPL(free_percpu_irq); +void free_percpu_nmi(unsigned int irq, void __percpu *dev_id) +{ + struct irq_desc *desc = irq_to_desc(irq); + + if (!desc || !irq_settings_is_per_cpu_devid(desc)) + return; + + if (WARN_ON(!(desc->istate & IRQS_NMI))) + return; + + kfree(__free_percpu_irq(irq, dev_id)); +} + /** *setup_percpu_irq - setup a per-cpu interrupt *@irq: Interrupt line to setup @@ -2375,6 +2400,130 @@ int __request_percpu_irq(unsigned int irq, irq_handler_t handler, EXPORT_SYMBOL_GPL(__request_percpu_irq); /** + * request_percpu_nmi - allocate a percpu interrupt line for NMI delivery + * @irq: Interrupt line to allocate + * @handler: Function to be called when the IRQ occurs. + * @devname: An ascii name for the claiming device + * @dev_id: A percpu cookie passed back to the handler function + * + * This call allocates interrupt resources and enables the + * interrupt on the local CPU. If the interrupt is supposed to be + * enabled on other CPUs, it has to be done on each CPU using + * enable_percpu_nmi(). + * + * Dev_id must be globally unique. It is a per-cpu variable, and + * the handler gets called with the interrupted CPU's instance of + * that variable. + * + * Interrupt lines requested for NMI delivering should have auto enabling + * setting disabled. + * + * If the interrupt line cannot be used to deliver NMIs, function + * will fail returning a negative value. + */ +int request_percpu_nmi(unsigned int irq, irq_handler_t handler, + const char *name, void __percpu *dev_id) +{ + struct irqaction *action; + struct irq_desc *desc; + unsigned long flags; +
Re: [PATCH 2/4] genirq: Provide NMI management for percpu_devid interrupts
On 01/08/18 04:11, Ricardo Neri wrote: On Tue, Jul 24, 2018 at 12:07:05PM +0100, Julien Thierry wrote: Add support for percpu_devid interrupts treated as NMIs. Percpu_devid NMIs need to be setup/torn down on each CPU they target. The same restrictions as for global NMIs still apply for percpu_devid NMIs. Signed-off-by: Julien Thierry Cc: Thomas Gleixner Cc: Peter Zijlstra Cc: Ingo Molnar Cc: Marc Zyngier --- include/linux/interrupt.h | 9 +++ kernel/irq/manage.c | 149 ++ 2 files changed, 158 insertions(+) diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 3b1a320..59d3877 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -168,10 +168,15 @@ struct irqaction { devname, percpu_dev_id); } +extern int __must_check +request_percpu_nmi(unsigned int irq, irq_handler_t handler, + const char *devname, void __percpu *dev); + extern const void *free_irq(unsigned int, void *); extern void free_percpu_irq(unsigned int, void __percpu *); extern const void *free_nmi(unsigned int irq, void *dev_id); +extern void free_percpu_nmi(unsigned int irq, void __percpu *percpu_dev_id); struct device; @@ -224,7 +229,11 @@ struct irqaction { extern void irq_wake_thread(unsigned int irq, void *dev_id); extern void disable_nmi_nosync(unsigned int irq); +extern void disable_percpu_nmi(unsigned int irq); Shouldn't this be a disable_percpu_nmi_nosync() as disable_nmi_nosync()? The naming of the disable_percpu_irq didn't include the nosync either (and it doesn't wait for pending percpu_devid_irqs) extern void enable_nmi(unsigned int irq); +extern void enable_percpu_nmi(unsigned int irq, unsigned int type); +extern int ready_percpu_nmi(unsigned int irq); +extern void teardown_percpu_nmi(unsigned int irq); /* The following three functions are for the core kernel use only. */ extern void suspend_device_irqs(void); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 3b87143..ad41c4d 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -2162,6 +2162,11 @@ void enable_percpu_irq(unsigned int irq, unsigned int type) } EXPORT_SYMBOL_GPL(enable_percpu_irq); +void enable_percpu_nmi(unsigned int irq, unsigned int type) +{ + enable_percpu_irq(irq, type); +} + /** * irq_percpu_is_enabled - Check whether the per cpu irq is enabled * @irq: Linux irq number to check for @@ -2201,6 +2206,11 @@ void disable_percpu_irq(unsigned int irq) } EXPORT_SYMBOL_GPL(disable_percpu_irq); +void disable_percpu_nmi(unsigned int irq) +{ + disable_percpu_irq(irq); +} + /* * Internal function to unregister a percpu irqaction. */ @@ -2232,6 +2242,8 @@ static struct irqaction *__free_percpu_irq(unsigned int irq, void __percpu *dev_ /* Found it - now remove it from the list of entries: */ desc->action = NULL; + desc->istate &= ~IRQS_NMI; + raw_spin_unlock_irqrestore(>lock, flags); unregister_handler_proc(irq, action); @@ -2285,6 +2297,19 @@ void free_percpu_irq(unsigned int irq, void __percpu *dev_id) } EXPORT_SYMBOL_GPL(free_percpu_irq); +void free_percpu_nmi(unsigned int irq, void __percpu *dev_id) +{ + struct irq_desc *desc = irq_to_desc(irq); + + if (!desc || !irq_settings_is_per_cpu_devid(desc)) + return; + + if (WARN_ON(!(desc->istate & IRQS_NMI))) + return; + + kfree(__free_percpu_irq(irq, dev_id)); +} + /** *setup_percpu_irq - setup a per-cpu interrupt *@irq: Interrupt line to setup @@ -2375,6 +2400,130 @@ int __request_percpu_irq(unsigned int irq, irq_handler_t handler, EXPORT_SYMBOL_GPL(__request_percpu_irq); /** + * request_percpu_nmi - allocate a percpu interrupt line for NMI delivery + * @irq: Interrupt line to allocate + * @handler: Function to be called when the IRQ occurs. + * @devname: An ascii name for the claiming device + * @dev_id: A percpu cookie passed back to the handler function + * + * This call allocates interrupt resources and enables the + * interrupt on the local CPU. If the interrupt is supposed to be + * enabled on other CPUs, it has to be done on each CPU using + * enable_percpu_nmi(). + * + * Dev_id must be globally unique. It is a per-cpu variable, and + * the handler gets called with the interrupted CPU's instance of + * that variable. + * + * Interrupt lines requested for NMI delivering should have auto enabling + * setting disabled. + * + * If the interrupt line cannot be used to deliver NMIs, function + * will fail returning a negative value. + */ +int request_percpu_nmi(unsigned int irq, irq_handler_t handler, + const char *name, void __percpu *dev_id) +{ + struct irqaction *action; + struct irq_desc *desc; + unsigned long flags; +
Re: [PATCH 2/4] genirq: Provide NMI management for percpu_devid interrupts
On Tue, Jul 24, 2018 at 12:07:05PM +0100, Julien Thierry wrote: > Add support for percpu_devid interrupts treated as NMIs. > > Percpu_devid NMIs need to be setup/torn down on each CPU they target. > > The same restrictions as for global NMIs still apply for percpu_devid NMIs. > > Signed-off-by: Julien Thierry > Cc: Thomas Gleixner > Cc: Peter Zijlstra > Cc: Ingo Molnar > Cc: Marc Zyngier > --- > include/linux/interrupt.h | 9 +++ > kernel/irq/manage.c | 149 > ++ > 2 files changed, 158 insertions(+) > > diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h > index 3b1a320..59d3877 100644 > --- a/include/linux/interrupt.h > +++ b/include/linux/interrupt.h > @@ -168,10 +168,15 @@ struct irqaction { > devname, percpu_dev_id); > } > > +extern int __must_check > +request_percpu_nmi(unsigned int irq, irq_handler_t handler, > +const char *devname, void __percpu *dev); > + > extern const void *free_irq(unsigned int, void *); > extern void free_percpu_irq(unsigned int, void __percpu *); > > extern const void *free_nmi(unsigned int irq, void *dev_id); > +extern void free_percpu_nmi(unsigned int irq, void __percpu *percpu_dev_id); > > struct device; > > @@ -224,7 +229,11 @@ struct irqaction { > extern void irq_wake_thread(unsigned int irq, void *dev_id); > > extern void disable_nmi_nosync(unsigned int irq); > +extern void disable_percpu_nmi(unsigned int irq); Shouldn't this be a disable_percpu_nmi_nosync() as disable_nmi_nosync()? > extern void enable_nmi(unsigned int irq); > +extern void enable_percpu_nmi(unsigned int irq, unsigned int type); > +extern int ready_percpu_nmi(unsigned int irq); > +extern void teardown_percpu_nmi(unsigned int irq); > > /* The following three functions are for the core kernel use only. */ > extern void suspend_device_irqs(void); > diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c > index 3b87143..ad41c4d 100644 > --- a/kernel/irq/manage.c > +++ b/kernel/irq/manage.c > @@ -2162,6 +2162,11 @@ void enable_percpu_irq(unsigned int irq, unsigned int > type) > } > EXPORT_SYMBOL_GPL(enable_percpu_irq); > > +void enable_percpu_nmi(unsigned int irq, unsigned int type) > +{ > + enable_percpu_irq(irq, type); > +} > + > /** > * irq_percpu_is_enabled - Check whether the per cpu irq is enabled > * @irq: Linux irq number to check for > @@ -2201,6 +2206,11 @@ void disable_percpu_irq(unsigned int irq) > } > EXPORT_SYMBOL_GPL(disable_percpu_irq); > > +void disable_percpu_nmi(unsigned int irq) > +{ > + disable_percpu_irq(irq); > +} > + > /* > * Internal function to unregister a percpu irqaction. > */ > @@ -2232,6 +2242,8 @@ static struct irqaction *__free_percpu_irq(unsigned int > irq, void __percpu *dev_ > /* Found it - now remove it from the list of entries: */ > desc->action = NULL; > > + desc->istate &= ~IRQS_NMI; > + > raw_spin_unlock_irqrestore(>lock, flags); > > unregister_handler_proc(irq, action); > @@ -2285,6 +2297,19 @@ void free_percpu_irq(unsigned int irq, void __percpu > *dev_id) > } > EXPORT_SYMBOL_GPL(free_percpu_irq); > > +void free_percpu_nmi(unsigned int irq, void __percpu *dev_id) > +{ > + struct irq_desc *desc = irq_to_desc(irq); > + > + if (!desc || !irq_settings_is_per_cpu_devid(desc)) > + return; > + > + if (WARN_ON(!(desc->istate & IRQS_NMI))) > + return; > + > + kfree(__free_percpu_irq(irq, dev_id)); > +} > + > /** > * setup_percpu_irq - setup a per-cpu interrupt > * @irq: Interrupt line to setup > @@ -2375,6 +2400,130 @@ int __request_percpu_irq(unsigned int irq, > irq_handler_t handler, > EXPORT_SYMBOL_GPL(__request_percpu_irq); > > /** > + * request_percpu_nmi - allocate a percpu interrupt line for NMI delivery > + * @irq: Interrupt line to allocate > + * @handler: Function to be called when the IRQ occurs. > + * @devname: An ascii name for the claiming device > + * @dev_id: A percpu cookie passed back to the handler function > + * > + * This call allocates interrupt resources and enables the > + * interrupt on the local CPU. If the interrupt is supposed to be > + * enabled on other CPUs, it has to be done on each CPU using > + * enable_percpu_nmi(). > + * > + * Dev_id must be globally unique. It is a per-cpu variable, and > + * the handler gets called with the interrupted CPU's instance of > + * that variable. > + * > + * Interrupt lines requested for NMI delivering should have auto enabling > + * setting disabled. > + * > + * If the interrupt line cannot be used to deliver NMIs, function > + * will fail returning a negative value. > + */ > +int request_percpu_nmi(unsigned int irq, irq_handler_t handler, > +const char *name, void __percpu *dev_id) > +{ > + struct irqaction *action; > + struct irq_desc *desc; > + unsigned long flags; > +
Re: [PATCH 2/4] genirq: Provide NMI management for percpu_devid interrupts
On Tue, Jul 24, 2018 at 12:07:05PM +0100, Julien Thierry wrote: > Add support for percpu_devid interrupts treated as NMIs. > > Percpu_devid NMIs need to be setup/torn down on each CPU they target. > > The same restrictions as for global NMIs still apply for percpu_devid NMIs. > > Signed-off-by: Julien Thierry > Cc: Thomas Gleixner > Cc: Peter Zijlstra > Cc: Ingo Molnar > Cc: Marc Zyngier > --- > include/linux/interrupt.h | 9 +++ > kernel/irq/manage.c | 149 > ++ > 2 files changed, 158 insertions(+) > > diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h > index 3b1a320..59d3877 100644 > --- a/include/linux/interrupt.h > +++ b/include/linux/interrupt.h > @@ -168,10 +168,15 @@ struct irqaction { > devname, percpu_dev_id); > } > > +extern int __must_check > +request_percpu_nmi(unsigned int irq, irq_handler_t handler, > +const char *devname, void __percpu *dev); > + > extern const void *free_irq(unsigned int, void *); > extern void free_percpu_irq(unsigned int, void __percpu *); > > extern const void *free_nmi(unsigned int irq, void *dev_id); > +extern void free_percpu_nmi(unsigned int irq, void __percpu *percpu_dev_id); > > struct device; > > @@ -224,7 +229,11 @@ struct irqaction { > extern void irq_wake_thread(unsigned int irq, void *dev_id); > > extern void disable_nmi_nosync(unsigned int irq); > +extern void disable_percpu_nmi(unsigned int irq); Shouldn't this be a disable_percpu_nmi_nosync() as disable_nmi_nosync()? > extern void enable_nmi(unsigned int irq); > +extern void enable_percpu_nmi(unsigned int irq, unsigned int type); > +extern int ready_percpu_nmi(unsigned int irq); > +extern void teardown_percpu_nmi(unsigned int irq); > > /* The following three functions are for the core kernel use only. */ > extern void suspend_device_irqs(void); > diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c > index 3b87143..ad41c4d 100644 > --- a/kernel/irq/manage.c > +++ b/kernel/irq/manage.c > @@ -2162,6 +2162,11 @@ void enable_percpu_irq(unsigned int irq, unsigned int > type) > } > EXPORT_SYMBOL_GPL(enable_percpu_irq); > > +void enable_percpu_nmi(unsigned int irq, unsigned int type) > +{ > + enable_percpu_irq(irq, type); > +} > + > /** > * irq_percpu_is_enabled - Check whether the per cpu irq is enabled > * @irq: Linux irq number to check for > @@ -2201,6 +2206,11 @@ void disable_percpu_irq(unsigned int irq) > } > EXPORT_SYMBOL_GPL(disable_percpu_irq); > > +void disable_percpu_nmi(unsigned int irq) > +{ > + disable_percpu_irq(irq); > +} > + > /* > * Internal function to unregister a percpu irqaction. > */ > @@ -2232,6 +2242,8 @@ static struct irqaction *__free_percpu_irq(unsigned int > irq, void __percpu *dev_ > /* Found it - now remove it from the list of entries: */ > desc->action = NULL; > > + desc->istate &= ~IRQS_NMI; > + > raw_spin_unlock_irqrestore(>lock, flags); > > unregister_handler_proc(irq, action); > @@ -2285,6 +2297,19 @@ void free_percpu_irq(unsigned int irq, void __percpu > *dev_id) > } > EXPORT_SYMBOL_GPL(free_percpu_irq); > > +void free_percpu_nmi(unsigned int irq, void __percpu *dev_id) > +{ > + struct irq_desc *desc = irq_to_desc(irq); > + > + if (!desc || !irq_settings_is_per_cpu_devid(desc)) > + return; > + > + if (WARN_ON(!(desc->istate & IRQS_NMI))) > + return; > + > + kfree(__free_percpu_irq(irq, dev_id)); > +} > + > /** > * setup_percpu_irq - setup a per-cpu interrupt > * @irq: Interrupt line to setup > @@ -2375,6 +2400,130 @@ int __request_percpu_irq(unsigned int irq, > irq_handler_t handler, > EXPORT_SYMBOL_GPL(__request_percpu_irq); > > /** > + * request_percpu_nmi - allocate a percpu interrupt line for NMI delivery > + * @irq: Interrupt line to allocate > + * @handler: Function to be called when the IRQ occurs. > + * @devname: An ascii name for the claiming device > + * @dev_id: A percpu cookie passed back to the handler function > + * > + * This call allocates interrupt resources and enables the > + * interrupt on the local CPU. If the interrupt is supposed to be > + * enabled on other CPUs, it has to be done on each CPU using > + * enable_percpu_nmi(). > + * > + * Dev_id must be globally unique. It is a per-cpu variable, and > + * the handler gets called with the interrupted CPU's instance of > + * that variable. > + * > + * Interrupt lines requested for NMI delivering should have auto enabling > + * setting disabled. > + * > + * If the interrupt line cannot be used to deliver NMIs, function > + * will fail returning a negative value. > + */ > +int request_percpu_nmi(unsigned int irq, irq_handler_t handler, > +const char *name, void __percpu *dev_id) > +{ > + struct irqaction *action; > + struct irq_desc *desc; > + unsigned long flags; > +