1 From 317cb092cbabed65d888b6f75dfa2c99a1ebc051 Mon Sep 17 00:00:00 2001
2 From: Thomas Gleixner <tglx@linutronix.de>
3 Date: Tue, 31 Jan 2012 13:01:27 +0100
4 Subject: [PATCH 112/365] genirq: Allow disabling of softirq processing in irq
7 The processing of softirqs in irq thread context is a performance gain
8 for the non-rt workloads of a system, but it's counterproductive for
9 interrupts which are explicitely related to the realtime
10 workload. Allow such interrupts to prevent softirq processing in their
13 Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
15 include/linux/interrupt.h | 2 ++
16 include/linux/irq.h | 4 +++-
17 kernel/irq/manage.c | 13 ++++++++++++-
18 kernel/irq/settings.h | 12 ++++++++++++
19 kernel/softirq.c | 9 +++++++++
20 5 files changed, 38 insertions(+), 2 deletions(-)
22 diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
23 index 7033381..47d38a0 100644
24 --- a/include/linux/interrupt.h
25 +++ b/include/linux/interrupt.h
27 * interrupt handler after suspending interrupts. For system
28 * wakeup devices users need to implement wakeup detection in
29 * their interrupt handlers.
30 + * IRQF_NO_SOFTIRQ_CALL - Do not process softirqs in the irq thread context (RT)
32 #define IRQF_SHARED 0x00000080
33 #define IRQF_PROBE_SHARED 0x00000100
35 #define IRQF_NO_THREAD 0x00010000
36 #define IRQF_EARLY_RESUME 0x00020000
37 #define IRQF_COND_SUSPEND 0x00040000
38 +#define IRQF_NO_SOFTIRQ_CALL 0x00080000
40 #define IRQF_TIMER (__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD)
42 diff --git a/include/linux/irq.h b/include/linux/irq.h
43 index f7cade0..dac9e11 100644
44 --- a/include/linux/irq.h
45 +++ b/include/linux/irq.h
46 @@ -72,6 +72,7 @@ enum irqchip_irq_state;
47 * IRQ_IS_POLLED - Always polled by another interrupt. Exclude
48 * it from the spurious interrupt detection
49 * mechanism and from core side polling.
50 + * IRQ_NO_SOFTIRQ_CALL - No softirq processing in the irq thread context (RT)
51 * IRQ_DISABLE_UNLAZY - Disable lazy irq disable
54 @@ -99,13 +100,14 @@ enum {
55 IRQ_PER_CPU_DEVID = (1 << 17),
56 IRQ_IS_POLLED = (1 << 18),
57 IRQ_DISABLE_UNLAZY = (1 << 19),
58 + IRQ_NO_SOFTIRQ_CALL = (1 << 20),
61 #define IRQF_MODIFY_MASK \
62 (IRQ_TYPE_SENSE_MASK | IRQ_NOPROBE | IRQ_NOREQUEST | \
63 IRQ_NOAUTOEN | IRQ_MOVE_PCNTXT | IRQ_LEVEL | IRQ_NO_BALANCING | \
64 IRQ_PER_CPU | IRQ_NESTED_THREAD | IRQ_NOTHREAD | IRQ_PER_CPU_DEVID | \
65 - IRQ_IS_POLLED | IRQ_DISABLE_UNLAZY)
66 + IRQ_IS_POLLED | IRQ_DISABLE_UNLAZY | IRQ_NO_SOFTIRQ_CALL)
68 #define IRQ_NO_BALANCING_MASK (IRQ_PER_CPU | IRQ_NO_BALANCING)
70 diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
71 index 8842388..5b1ad63 100644
72 --- a/kernel/irq/manage.c
73 +++ b/kernel/irq/manage.c
74 @@ -940,7 +940,15 @@ irq_forced_thread_fn(struct irq_desc *desc, struct irqaction *action)
76 ret = action->thread_fn(action->irq, action->dev_id);
77 irq_finalize_oneshot(desc, action);
80 + * Interrupts which have real time requirements can be set up
81 + * to avoid softirq processing in the thread handler. This is
82 + * safe as these interrupts do not raise soft interrupts.
84 + if (irq_settings_no_softirq_call(desc))
91 @@ -1390,6 +1398,9 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
92 irqd_set(&desc->irq_data, IRQD_NO_BALANCING);
95 + if (new->flags & IRQF_NO_SOFTIRQ_CALL)
96 + irq_settings_set_no_softirq_call(desc);
98 /* Set default affinity mask once everything is setup */
99 setup_affinity(desc, mask);
101 diff --git a/kernel/irq/settings.h b/kernel/irq/settings.h
102 index 320579d..2df2d44 100644
103 --- a/kernel/irq/settings.h
104 +++ b/kernel/irq/settings.h
105 @@ -16,6 +16,7 @@ enum {
106 _IRQ_PER_CPU_DEVID = IRQ_PER_CPU_DEVID,
107 _IRQ_IS_POLLED = IRQ_IS_POLLED,
108 _IRQ_DISABLE_UNLAZY = IRQ_DISABLE_UNLAZY,
109 + _IRQ_NO_SOFTIRQ_CALL = IRQ_NO_SOFTIRQ_CALL,
110 _IRQF_MODIFY_MASK = IRQF_MODIFY_MASK,
113 @@ -30,6 +31,7 @@ enum {
114 #define IRQ_PER_CPU_DEVID GOT_YOU_MORON
115 #define IRQ_IS_POLLED GOT_YOU_MORON
116 #define IRQ_DISABLE_UNLAZY GOT_YOU_MORON
117 +#define IRQ_NO_SOFTIRQ_CALL GOT_YOU_MORON
118 #undef IRQF_MODIFY_MASK
119 #define IRQF_MODIFY_MASK GOT_YOU_MORON
121 @@ -40,6 +42,16 @@ irq_settings_clr_and_set(struct irq_desc *desc, u32 clr, u32 set)
122 desc->status_use_accessors |= (set & _IRQF_MODIFY_MASK);
125 +static inline bool irq_settings_no_softirq_call(struct irq_desc *desc)
127 + return desc->status_use_accessors & _IRQ_NO_SOFTIRQ_CALL;
130 +static inline void irq_settings_set_no_softirq_call(struct irq_desc *desc)
132 + desc->status_use_accessors |= _IRQ_NO_SOFTIRQ_CALL;
135 static inline bool irq_settings_is_per_cpu(struct irq_desc *desc)
137 return desc->status_use_accessors & _IRQ_PER_CPU;
138 diff --git a/kernel/softirq.c b/kernel/softirq.c
139 index 61de6e9..0fd9331 100644
140 --- a/kernel/softirq.c
141 +++ b/kernel/softirq.c
142 @@ -576,6 +576,15 @@ void __local_bh_enable(void)
144 EXPORT_SYMBOL(__local_bh_enable);
146 +void _local_bh_enable(void)
148 + if (WARN_ON(current->softirq_nestcnt == 0))
150 + if (--current->softirq_nestcnt == 0)
153 +EXPORT_SYMBOL(_local_bh_enable);
155 int in_serving_softirq(void)
157 return current->flags & PF_IN_SOFTIRQ;