2012-10-24 14:29:13 +00:00
|
|
|
Subject: genirq: Allow disabling of softirq processing in irq thread context
|
2012-02-08 21:25:53 +00:00
|
|
|
From: Thomas Gleixner <tglx@linutronix.de>
|
|
|
|
Date: Tue, 31 Jan 2012 13:01:27 +0100
|
|
|
|
|
|
|
|
The processing of softirqs in irq thread context is a performance gain
|
|
|
|
for the non-rt workloads of a system, but it's counterproductive for
|
|
|
|
interrupts which are explicitely related to the realtime
|
|
|
|
workload. Allow such interrupts to prevent softirq processing in their
|
|
|
|
thread context.
|
|
|
|
|
|
|
|
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
|
|
|
|
Cc: stable-rt@vger.kernel.org
|
|
|
|
---
|
|
|
|
include/linux/interrupt.h | 2 ++
|
|
|
|
include/linux/irq.h | 5 ++++-
|
|
|
|
kernel/irq/manage.c | 13 ++++++++++++-
|
|
|
|
kernel/irq/settings.h | 12 ++++++++++++
|
|
|
|
kernel/softirq.c | 7 +++++++
|
|
|
|
5 files changed, 37 insertions(+), 2 deletions(-)
|
|
|
|
|
2012-10-24 14:29:13 +00:00
|
|
|
Index: linux-stable/include/linux/interrupt.h
|
|
|
|
===================================================================
|
|
|
|
--- linux-stable.orig/include/linux/interrupt.h
|
|
|
|
+++ linux-stable/include/linux/interrupt.h
|
|
|
|
@@ -58,6 +58,7 @@
|
2012-02-08 21:25:53 +00:00
|
|
|
* IRQF_NO_THREAD - Interrupt cannot be threaded
|
|
|
|
* IRQF_EARLY_RESUME - Resume IRQ early during syscore instead of at device
|
|
|
|
* resume time.
|
|
|
|
+ * IRQF_NO_SOFTIRQ_CALL - Do not process softirqs in the irq thread context (RT)
|
|
|
|
*/
|
|
|
|
#define IRQF_DISABLED 0x00000020
|
2012-10-24 14:29:13 +00:00
|
|
|
#define IRQF_SHARED 0x00000080
|
|
|
|
@@ -71,6 +72,7 @@
|
2012-02-08 21:25:53 +00:00
|
|
|
#define IRQF_FORCE_RESUME 0x00008000
|
|
|
|
#define IRQF_NO_THREAD 0x00010000
|
|
|
|
#define IRQF_EARLY_RESUME 0x00020000
|
|
|
|
+#define IRQF_NO_SOFTIRQ_CALL 0x00040000
|
|
|
|
|
|
|
|
#define IRQF_TIMER (__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD)
|
|
|
|
|
2012-10-24 14:29:13 +00:00
|
|
|
Index: linux-stable/include/linux/irq.h
|
|
|
|
===================================================================
|
|
|
|
--- linux-stable.orig/include/linux/irq.h
|
|
|
|
+++ linux-stable/include/linux/irq.h
|
|
|
|
@@ -73,6 +73,7 @@ typedef void (*irq_preflow_handler_t)(st
|
2012-02-08 21:25:53 +00:00
|
|
|
* IRQ_MOVE_PCNTXT - Interrupt can be migrated from process context
|
|
|
|
* IRQ_NESTED_TRHEAD - Interrupt nests into another thread
|
|
|
|
* IRQ_PER_CPU_DEVID - Dev_id is a per-cpu variable
|
|
|
|
+ * IRQ_NO_SOFTIRQ_CALL - No softirq processing in the irq thread context (RT)
|
|
|
|
*/
|
|
|
|
enum {
|
|
|
|
IRQ_TYPE_NONE = 0x00000000,
|
2012-06-04 21:20:09 +00:00
|
|
|
@@ -97,12 +98,14 @@ enum {
|
2012-02-08 21:25:53 +00:00
|
|
|
IRQ_NESTED_THREAD = (1 << 15),
|
|
|
|
IRQ_NOTHREAD = (1 << 16),
|
|
|
|
IRQ_PER_CPU_DEVID = (1 << 17),
|
|
|
|
+ IRQ_NO_SOFTIRQ_CALL = (1 << 18),
|
|
|
|
};
|
|
|
|
|
|
|
|
#define IRQF_MODIFY_MASK \
|
|
|
|
(IRQ_TYPE_SENSE_MASK | IRQ_NOPROBE | IRQ_NOREQUEST | \
|
|
|
|
IRQ_NOAUTOEN | IRQ_MOVE_PCNTXT | IRQ_LEVEL | IRQ_NO_BALANCING | \
|
|
|
|
- IRQ_PER_CPU | IRQ_NESTED_THREAD | IRQ_NOTHREAD | IRQ_PER_CPU_DEVID)
|
|
|
|
+ IRQ_PER_CPU | IRQ_NESTED_THREAD | IRQ_NOTHREAD | IRQ_PER_CPU_DEVID | \
|
|
|
|
+ IRQ_NO_SOFTIRQ_CALL)
|
|
|
|
|
|
|
|
#define IRQ_NO_BALANCING_MASK (IRQ_PER_CPU | IRQ_NO_BALANCING)
|
|
|
|
|
2012-10-24 14:29:13 +00:00
|
|
|
Index: linux-stable/kernel/irq/manage.c
|
|
|
|
===================================================================
|
|
|
|
--- linux-stable.orig/kernel/irq/manage.c
|
|
|
|
+++ linux-stable/kernel/irq/manage.c
|
|
|
|
@@ -757,7 +757,15 @@ irq_forced_thread_fn(struct irq_desc *de
|
2012-02-08 21:25:53 +00:00
|
|
|
local_bh_disable();
|
|
|
|
ret = action->thread_fn(action->irq, action->dev_id);
|
2012-06-04 21:20:09 +00:00
|
|
|
irq_finalize_oneshot(desc, action);
|
2012-02-08 21:25:53 +00:00
|
|
|
- local_bh_enable();
|
|
|
|
+ /*
|
|
|
|
+ * Interrupts which have real time requirements can be set up
|
|
|
|
+ * to avoid softirq processing in the thread handler. This is
|
|
|
|
+ * safe as these interrupts do not raise soft interrupts.
|
|
|
|
+ */
|
|
|
|
+ if (irq_settings_no_softirq_call(desc))
|
|
|
|
+ _local_bh_enable();
|
|
|
|
+ else
|
|
|
|
+ local_bh_enable();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-10-24 14:29:13 +00:00
|
|
|
@@ -1090,6 +1098,9 @@ __setup_irq(unsigned int irq, struct irq
|
2012-02-08 21:25:53 +00:00
|
|
|
irqd_set(&desc->irq_data, IRQD_NO_BALANCING);
|
|
|
|
}
|
|
|
|
|
|
|
|
+ if (new->flags & IRQF_NO_SOFTIRQ_CALL)
|
|
|
|
+ irq_settings_set_no_softirq_call(desc);
|
|
|
|
+
|
|
|
|
/* Set default affinity mask once everything is setup */
|
|
|
|
setup_affinity(irq, desc, mask);
|
|
|
|
|
2012-10-24 14:29:13 +00:00
|
|
|
Index: linux-stable/kernel/irq/settings.h
|
|
|
|
===================================================================
|
|
|
|
--- linux-stable.orig/kernel/irq/settings.h
|
|
|
|
+++ linux-stable/kernel/irq/settings.h
|
2012-02-08 21:25:53 +00:00
|
|
|
@@ -14,6 +14,7 @@ enum {
|
|
|
|
_IRQ_NO_BALANCING = IRQ_NO_BALANCING,
|
|
|
|
_IRQ_NESTED_THREAD = IRQ_NESTED_THREAD,
|
|
|
|
_IRQ_PER_CPU_DEVID = IRQ_PER_CPU_DEVID,
|
|
|
|
+ _IRQ_NO_SOFTIRQ_CALL = IRQ_NO_SOFTIRQ_CALL,
|
|
|
|
_IRQF_MODIFY_MASK = IRQF_MODIFY_MASK,
|
|
|
|
};
|
|
|
|
|
|
|
|
@@ -26,6 +27,7 @@ enum {
|
|
|
|
#define IRQ_NOAUTOEN GOT_YOU_MORON
|
|
|
|
#define IRQ_NESTED_THREAD GOT_YOU_MORON
|
|
|
|
#define IRQ_PER_CPU_DEVID GOT_YOU_MORON
|
|
|
|
+#define IRQ_NO_SOFTIRQ_CALL GOT_YOU_MORON
|
|
|
|
#undef IRQF_MODIFY_MASK
|
|
|
|
#define IRQF_MODIFY_MASK GOT_YOU_MORON
|
|
|
|
|
2012-10-24 14:29:13 +00:00
|
|
|
@@ -36,6 +38,16 @@ irq_settings_clr_and_set(struct irq_desc
|
2012-02-08 21:25:53 +00:00
|
|
|
desc->status_use_accessors |= (set & _IRQF_MODIFY_MASK);
|
|
|
|
}
|
|
|
|
|
|
|
|
+static inline bool irq_settings_no_softirq_call(struct irq_desc *desc)
|
|
|
|
+{
|
|
|
|
+ return desc->status_use_accessors & _IRQ_NO_SOFTIRQ_CALL;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static inline void irq_settings_set_no_softirq_call(struct irq_desc *desc)
|
|
|
|
+{
|
|
|
|
+ desc->status_use_accessors |= _IRQ_NO_SOFTIRQ_CALL;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
static inline bool irq_settings_is_per_cpu(struct irq_desc *desc)
|
|
|
|
{
|
|
|
|
return desc->status_use_accessors & _IRQ_PER_CPU;
|
2012-10-24 14:29:13 +00:00
|
|
|
Index: linux-stable/kernel/softirq.c
|
|
|
|
===================================================================
|
|
|
|
--- linux-stable.orig/kernel/softirq.c
|
|
|
|
+++ linux-stable/kernel/softirq.c
|
|
|
|
@@ -434,6 +434,13 @@ void local_bh_enable_ip(unsigned long ip
|
2012-02-08 21:25:53 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(local_bh_enable_ip);
|
|
|
|
|
|
|
|
+void _local_bh_enable(void)
|
|
|
|
+{
|
|
|
|
+ current->softirq_nestcnt--;
|
|
|
|
+ migrate_enable();
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL(_local_bh_enable);
|
|
|
|
+
|
|
|
|
/* For tracing */
|
|
|
|
int notrace __in_softirq(void)
|
|
|
|
{
|