A threadable irq can benefit from irq_set_affinity when running in non threaded mode and prefer running unbounded to cpu when in threaded mode. Setting the IRQF_TH_NO_AFFINITY flag on irq registration allow the irq to achieve both behaviors.
A long running threaded irq can starve the system if scheduled under SCHED_FIFO. Setting the IRQF_TH_SCHED_NORMAL flag on irq will cause the irq thread to run by default under the SCHED_NORMAL scheduler. Signed-off-by: Paolo Abeni <pab...@redhat.com> Signed-off-by: Hannes Frederic Sowa <han...@stressinduktion.org> --- include/linux/interrupt.h | 6 ++++++ kernel/irq/manage.c | 17 +++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 85d3738..33c3033 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -61,6 +61,10 @@ * interrupt handler after suspending interrupts. For system * wakeup devices users need to implement wakeup detection in * their interrupt handlers. + * IRQF_TH_SCHED_NORMAL - If the IRQ is threaded, it will use SCHED_NORMAL, + * instead the default SCHED_FIFO scheduler + * IRQF_TH_NO_AFFINITY - If the IRQ is threaded, the affinity hint will not be + * enforced in the IRQ thread */ #define IRQF_SHARED 0x00000080 #define IRQF_PROBE_SHARED 0x00000100 @@ -74,6 +78,8 @@ #define IRQF_NO_THREAD 0x00010000 #define IRQF_EARLY_RESUME 0x00020000 #define IRQF_COND_SUSPEND 0x00040000 +#define IRQF_TH_SCHED_NORMAL 0x00080000 +#define IRQF_TH_NO_AFFINITY 0x00100000 #define IRQF_TIMER (__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index cce4efd..d695e12 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1055,9 +1055,7 @@ static struct task_struct * create_irq_thread(struct irqaction *new, unsigned int irq, bool secondary) { struct task_struct *t; - struct sched_param param = { - .sched_priority = MAX_USER_RT_PRIO/2, - }; + struct sched_param param; if (!secondary) { t = kthread_create(irq_thread, new, "irq/%d-%s", irq, @@ -1071,7 +1069,12 @@ create_irq_thread(struct irqaction *new, unsigned int irq, bool secondary) if (IS_ERR(t)) return t; - sched_setscheduler_nocheck(t, SCHED_FIFO, ¶m); + if (new->flags & IRQF_TH_SCHED_NORMAL) { + sched_setscheduler_nocheck(t, SCHED_NORMAL, ¶m); + } else { + param.sched_priority = MAX_USER_RT_PRIO/2; + sched_setscheduler_nocheck(t, SCHED_FIFO, ¶m); + } /* * We keep the reference to the task struct even if @@ -1100,7 +1103,8 @@ setup_irq_thread(struct irqaction *new, unsigned int irq, bool secondary) * correct as we want the thread to move to the cpu(s) * on which the requesting code placed the interrupt. */ - set_bit(IRQTF_AFFINITY, &new->thread_flags); + if (!(new->flags & IRQF_TH_NO_AFFINITY)) + set_bit(IRQTF_AFFINITY, &new->thread_flags); return 0; } @@ -1549,7 +1553,8 @@ void __irq_reconfigure_action(struct irq_desc *desc, struct irqaction *action, action->thread = t; set_bit(IRQTF_FORCED_THREAD, &action->thread_flags); - set_bit(IRQTF_AFFINITY, &action->thread_flags); + if (!(action->flags & IRQF_TH_NO_AFFINITY)) + set_bit(IRQTF_AFFINITY, &action->thread_flags); if (!(desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)) { /* -- 1.8.3.1