]> rtime.felk.cvut.cz Git - zynq/linux.git/commitdiff
genirq: Allow disabling of softirq processing in irq thread context
authorThomas Gleixner <tglx@linutronix.de>
Tue, 31 Jan 2012 12:01:27 +0000 (13:01 +0100)
committerMichal Sojka <sojka@merica.cz>
Sun, 13 Sep 2015 07:47:20 +0000 (09:47 +0200)
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
include/linux/irq.h
kernel/irq/manage.c
kernel/irq/settings.h
kernel/softirq.c

index 4642258338093cff2951c2bb5067d9bc1ea1c7c2..57734a52428386bc9f02cc982fcbcaba9c385b05 100644 (file)
@@ -63,6 +63,7 @@
  *                interrupt handler after suspending interrupts. For system
  *                wakeup devices users need to implement wakeup detection in
  *                their interrupt handlers.
+ * IRQF_NO_SOFTIRQ_CALL - Do not process softirqs in the irq thread context (RT)
  */
 #define IRQF_DISABLED          0x00000020
 #define IRQF_SHARED            0x00000080
@@ -77,6 +78,7 @@
 #define IRQF_NO_THREAD         0x00010000
 #define IRQF_EARLY_RESUME      0x00020000
 #define IRQF_COND_SUSPEND      0x00040000
+#define IRQF_NO_SOFTIRQ_CALL   0x00080000
 
 #define IRQF_TIMER             (__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD)
 
index d09ec7a1243e767dd95df2a4cc1d54775da0eb25..1e3af4e7d40ee98e89ff4284cd29523333570f09 100644 (file)
@@ -71,6 +71,7 @@ struct msi_msg;
  * IRQ_IS_POLLED               - Always polled by another interrupt. Exclude
  *                               it from the spurious interrupt detection
  *                               mechanism and from core side polling.
+ * IRQ_NO_SOFTIRQ_CALL         - No softirq processing in the irq thread context (RT)
  */
 enum {
        IRQ_TYPE_NONE           = 0x00000000,
@@ -96,13 +97,14 @@ enum {
        IRQ_NOTHREAD            = (1 << 16),
        IRQ_PER_CPU_DEVID       = (1 << 17),
        IRQ_IS_POLLED           = (1 << 18),
+       IRQ_NO_SOFTIRQ_CALL     = (1 << 19),
 };
 
 #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_IS_POLLED)
+        IRQ_IS_POLLED | IRQ_NO_SOFTIRQ_CALL)
 
 #define IRQ_NO_BALANCING_MASK  (IRQ_PER_CPU | IRQ_NO_BALANCING)
 
index cc699c856a423a4835e87d2213cde13f6679f73c..440543e03bb86ad527cca8cb4badb1642df1939d 100644 (file)
@@ -868,7 +868,15 @@ irq_forced_thread_fn(struct irq_desc *desc, struct irqaction *action)
        local_bh_disable();
        ret = action->thread_fn(action->irq, action->dev_id);
        irq_finalize_oneshot(desc, action);
-       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;
 }
 
@@ -1264,6 +1272,9 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
                        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);
 
index 3320b84cc60f79ac09501d6f4d55acc01b0cebe6..34b803b89d41038988a499b0c5e7cf3f315cb758 100644 (file)
@@ -15,6 +15,7 @@ enum {
        _IRQ_NESTED_THREAD      = IRQ_NESTED_THREAD,
        _IRQ_PER_CPU_DEVID      = IRQ_PER_CPU_DEVID,
        _IRQ_IS_POLLED          = IRQ_IS_POLLED,
+       _IRQ_NO_SOFTIRQ_CALL    = IRQ_NO_SOFTIRQ_CALL,
        _IRQF_MODIFY_MASK       = IRQF_MODIFY_MASK,
 };
 
@@ -28,6 +29,7 @@ enum {
 #define IRQ_NESTED_THREAD      GOT_YOU_MORON
 #define IRQ_PER_CPU_DEVID      GOT_YOU_MORON
 #define IRQ_IS_POLLED          GOT_YOU_MORON
+#define IRQ_NO_SOFTIRQ_CALL    GOT_YOU_MORON
 #undef IRQF_MODIFY_MASK
 #define IRQF_MODIFY_MASK       GOT_YOU_MORON
 
@@ -38,6 +40,16 @@ irq_settings_clr_and_set(struct irq_desc *desc, u32 clr, u32 set)
        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;
index e9f64256cb6811c9a8fc60a7809b470ada45c971..a3ee908414a843901fba21610ab3f9b6c5544d40 100644 (file)
@@ -469,6 +469,13 @@ void local_bh_enable_ip(unsigned long ip)
 }
 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)
 {