genirq: ipipe: enable pipelined interrupt management
authorPhilippe Gerum <rpm@xenomai.org>
Sun, 3 Dec 2017 11:00:44 +0000 (12:00 +0100)
committerMarek Szyprowski <m.szyprowski@samsung.com>
Fri, 27 Apr 2018 09:21:34 +0000 (11:21 +0200)
include/linux/hardirq.h
include/linux/irq.h
include/linux/irqdesc.h
include/linux/irqnr.h
kernel/irq/chip.c
kernel/irq/dummychip.c
kernel/irq/generic-chip.c
kernel/irq/internals.h
kernel/irq/irqdesc.c
kernel/irq/manage.c

index 0fbbcdf0c178ec5dc6ff5372fa248b121b65b49d..4c9217373014b75b3f906e5719e96ba1900e8a01 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/lockdep.h>
 #include <linux/ftrace_irq.h>
 #include <linux/vtime.h>
+#include <linux/ipipe.h>
 #include <asm/hardirq.h>
 
 
@@ -62,6 +63,7 @@ extern void irq_exit(void);
 
 #define nmi_enter()                                            \
        do {                                                    \
+               __ipipe_nmi_enter();                            \
                printk_nmi_enter();                             \
                lockdep_off();                                  \
                ftrace_nmi_enter();                             \
@@ -80,6 +82,7 @@ extern void irq_exit(void);
                ftrace_nmi_exit();                              \
                lockdep_on();                                   \
                printk_nmi_exit();                              \
+               __ipipe_nmi_exit();                             \
        } while (0)
 
 #endif /* LINUX_HARDIRQ_H */
index 0d53626405bf85b263f4528d339e28ce547a2502..11d8fc0cc351e9da07d7f454b493e49f70325eb1 100644 (file)
@@ -452,6 +452,11 @@ struct irq_chip {
 
        void            (*irq_bus_lock)(struct irq_data *data);
        void            (*irq_bus_sync_unlock)(struct irq_data *data);
+#ifdef CONFIG_IPIPE
+       void            (*irq_move)(struct irq_data *data);
+       void            (*irq_hold)(struct irq_data *data);
+       void            (*irq_release)(struct irq_data *data);
+#endif /* CONFIG_IPIPE */
 
        void            (*irq_cpu_online)(struct irq_data *data);
        void            (*irq_cpu_offline)(struct irq_data *data);
@@ -491,6 +496,7 @@ struct irq_chip {
  * IRQCHIP_SKIP_SET_WAKE:      Skip chip.irq_set_wake(), for this irq chip
  * IRQCHIP_ONESHOT_SAFE:       One shot does not require mask/unmask
  * IRQCHIP_EOI_THREADED:       Chip requires eoi() on unmask in threaded mode
+ * IRQCHIP_PIPELINE_SAFE:      Chip can work in pipelined mode
  */
 enum {
        IRQCHIP_SET_TYPE_MASKED         = (1 <<  0),
@@ -500,6 +506,7 @@ enum {
        IRQCHIP_SKIP_SET_WAKE           = (1 <<  4),
        IRQCHIP_ONESHOT_SAFE            = (1 <<  5),
        IRQCHIP_EOI_THREADED            = (1 <<  6),
+       IRQCHIP_PIPELINE_SAFE           = (1 <<  7),
 };
 
 #include <linux/irqdesc.h>
@@ -587,6 +594,11 @@ extern int irq_chip_retrigger_hierarchy(struct irq_data *data);
 extern void irq_chip_mask_parent(struct irq_data *data);
 extern void irq_chip_unmask_parent(struct irq_data *data);
 extern void irq_chip_eoi_parent(struct irq_data *data);
+#ifdef CONFIG_IPIPE
+extern void irq_chip_hold_parent(struct irq_data *data);
+extern void irq_chip_release_parent(struct irq_data *data);
+#endif
+
 extern int irq_chip_set_affinity_parent(struct irq_data *data,
                                        const struct cpumask *dest,
                                        bool force);
@@ -711,7 +723,14 @@ extern int irq_set_irq_type(unsigned int irq, unsigned int type);
 extern int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry);
 extern int irq_set_msi_desc_off(unsigned int irq_base, unsigned int irq_offset,
                                struct msi_desc *entry);
-extern struct irq_data *irq_get_irq_data(unsigned int irq);
+
+static inline __attribute__((const)) struct irq_data *
+irq_get_irq_data(unsigned int irq)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+
+       return desc ? &desc->irq_data : NULL;
+}
 
 static inline struct irq_chip *irq_get_chip(unsigned int irq)
 {
@@ -953,7 +972,11 @@ struct irq_chip_type {
  * different flow mechanisms (level/edge) for it.
  */
 struct irq_chip_generic {
+#ifdef CONFIG_IPIPE
+       ipipe_spinlock_t        lock;
+#else
        raw_spinlock_t          lock;
+#endif
        void __iomem            *reg_base;
        u32                     (*reg_readl)(void __iomem *addr);
        void                    (*reg_writel)(u32 val, void __iomem *addr);
@@ -1081,18 +1104,28 @@ static inline struct irq_chip_type *irq_data_get_chip_type(struct irq_data *d)
 #define IRQ_MSK(n) (u32)((n) < 32 ? ((1 << (n)) - 1) : UINT_MAX)
 
 #ifdef CONFIG_SMP
-static inline void irq_gc_lock(struct irq_chip_generic *gc)
+static inline unsigned long irq_gc_lock(struct irq_chip_generic *gc)
 {
-       raw_spin_lock(&gc->lock);
+       unsigned long flags = 0;
+       raw_spin_lock_irqsave_cond(&gc->lock, flags);
+       return flags;
 }
 
-static inline void irq_gc_unlock(struct irq_chip_generic *gc)
+static inline void 
+irq_gc_unlock(struct irq_chip_generic *gc, unsigned long flags)
 {
-       raw_spin_unlock(&gc->lock);
+       raw_spin_unlock_irqrestore_cond(&gc->lock, flags);
 }
 #else
-static inline void irq_gc_lock(struct irq_chip_generic *gc) { }
-static inline void irq_gc_unlock(struct irq_chip_generic *gc) { }
+static inline unsigned long irq_gc_lock(struct irq_chip_generic *gc) 
+{ 
+       return hard_cond_local_irq_save();
+}
+static inline void 
+irq_gc_unlock(struct irq_chip_generic *gc, unsigned long flags) 
+{ 
+       hard_cond_local_irq_restore(flags);
+}
 #endif
 
 /*
index b6084898d33017e01edaef49893169a26c9c0164..cf6be97e3f4e85bebbaf25e76a9f5dfff4cc02b8 100644 (file)
@@ -56,6 +56,10 @@ struct irq_desc {
        struct irq_common_data  irq_common_data;
        struct irq_data         irq_data;
        unsigned int __percpu   *kstat_irqs;
+#ifdef CONFIG_IPIPE
+       void                    (*ipipe_ack)(struct irq_desc *desc);
+       void                    (*ipipe_end)(struct irq_desc *desc);
+#endif /* CONFIG_IPIPE */
        irq_flow_handler_t      handle_irq;
 #ifdef CONFIG_IRQ_PREFLOW_FASTEOI
        irq_preflow_handler_t   preflow_handler;
@@ -183,6 +187,10 @@ static inline int irq_desc_has_action(struct irq_desc *desc)
        return desc->action != NULL;
 }
 
+irq_flow_handler_t
+__fixup_irq_handler(struct irq_desc *desc, irq_flow_handler_t handle,
+                   int is_chained);
+
 static inline int irq_has_action(unsigned int irq)
 {
        return irq_desc_has_action(irq_to_desc(irq));
index 3496baa0b07f37929eb68216738a10182257bda5..c731f187404282805a91265782ff644bf217ce0e 100644 (file)
@@ -6,7 +6,11 @@
 
 
 extern int nr_irqs;
+#if !defined(CONFIG_IPIPE) || defined(CONFIG_SPARSE_IRQ)
 extern struct irq_desc *irq_to_desc(unsigned int irq);
+#else
+#define irq_to_desc(irq)       ({ ipipe_virtual_irq_p(irq) ? NULL : &irq_desc[irq]; })
+#endif
 unsigned int irq_get_next_irq(unsigned int offset);
 
 # define for_each_irq_desc(irq, desc)                                  \
index 5a2ef92c2782c59c177e1f6c2eb5b4b17fb75a49..7ecd946713591009dffaf08414eb0223ba2be5f7 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/irqdomain.h>
+#include <linux/ipipe.h>
 
 #include <trace/events/irq.h>
 
@@ -50,6 +51,10 @@ int irq_set_chip(unsigned int irq, struct irq_chip *chip)
 
        if (!chip)
                chip = &no_irq_chip;
+       else
+               WARN_ONCE(IS_ENABLED(CONFIG_IPIPE) &&
+                         (chip->flags & IRQCHIP_PIPELINE_SAFE) == 0,
+                         "irqchip %s is not pipeline-safe!", chip->name);
 
        desc->irq_data.chip = chip;
        irq_put_desc_unlock(desc, flags);
@@ -157,14 +162,6 @@ int irq_set_chip_data(unsigned int irq, void *data)
 }
 EXPORT_SYMBOL(irq_set_chip_data);
 
-struct irq_data *irq_get_irq_data(unsigned int irq)
-{
-       struct irq_desc *desc = irq_to_desc(irq);
-
-       return desc ? &desc->irq_data : NULL;
-}
-EXPORT_SYMBOL_GPL(irq_get_irq_data);
-
 static void irq_state_clr_disabled(struct irq_desc *desc)
 {
        irqd_clear(&desc->irq_data, IRQD_IRQ_DISABLED);
@@ -238,9 +235,14 @@ static int __irq_startup(struct irq_desc *desc)
 
        irq_domain_activate_irq(d);
        if (d->chip->irq_startup) {
+               unsigned long flags = hard_cond_local_irq_save();
                ret = d->chip->irq_startup(d);
                irq_state_clr_disabled(desc);
                irq_state_clr_masked(desc);
+               hard_cond_local_irq_restore(flags);
+#ifdef CONFIG_IPIPE
+               desc->istate &= ~IPIPE_IRQS_NEEDS_STARTUP;
+#endif
        } else {
                irq_enable(desc);
        }
@@ -288,6 +290,9 @@ void irq_shutdown(struct irq_desc *desc)
                        desc->irq_data.chip->irq_shutdown(&desc->irq_data);
                        irq_state_set_disabled(desc);
                        irq_state_set_masked(desc);
+#ifdef CONFIG_IPIPE
+                       desc->istate |= IPIPE_IRQS_NEEDS_STARTUP;
+#endif
                } else {
                        __irq_disable(desc, true);
                }
@@ -304,6 +309,8 @@ void irq_shutdown(struct irq_desc *desc)
 
 void irq_enable(struct irq_desc *desc)
 {
+       unsigned long flags = hard_cond_local_irq_save();
+
        if (!irqd_irq_disabled(&desc->irq_data)) {
                unmask_irq(desc);
        } else {
@@ -315,10 +322,14 @@ void irq_enable(struct irq_desc *desc)
                        unmask_irq(desc);
                }
        }
+
+       hard_cond_local_irq_restore(flags);
 }
 
 static void __irq_disable(struct irq_desc *desc, bool mask)
 {
+       unsigned long flags = hard_cond_local_irq_save();
+
        if (irqd_irq_disabled(&desc->irq_data)) {
                if (mask)
                        mask_irq(desc);
@@ -331,6 +342,8 @@ static void __irq_disable(struct irq_desc *desc, bool mask)
                        mask_irq(desc);
                }
        }
+
+       hard_cond_local_irq_restore(flags);
 }
 
 /**
@@ -360,11 +373,13 @@ void irq_disable(struct irq_desc *desc)
 
 void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu)
 {
+       unsigned long flags = hard_cond_local_irq_save();
        if (desc->irq_data.chip->irq_enable)
                desc->irq_data.chip->irq_enable(&desc->irq_data);
        else
                desc->irq_data.chip->irq_unmask(&desc->irq_data);
        cpumask_set_cpu(cpu, desc->percpu_enabled);
+       hard_cond_local_irq_restore(flags);
 }
 
 void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu)
@@ -401,12 +416,16 @@ void mask_irq(struct irq_desc *desc)
 
 void unmask_irq(struct irq_desc *desc)
 {
+       unsigned long flags;
+
        if (!irqd_irq_masked(&desc->irq_data))
                return;
 
        if (desc->irq_data.chip->irq_unmask) {
+               flags = hard_cond_local_irq_save();
                desc->irq_data.chip->irq_unmask(&desc->irq_data);
                irq_state_clr_masked(desc);
+               hard_cond_local_irq_restore(flags);
        }
 }
 
@@ -603,7 +622,9 @@ static void cond_unmask_irq(struct irq_desc *desc)
 void handle_level_irq(struct irq_desc *desc)
 {
        raw_spin_lock(&desc->lock);
+#ifndef CONFIG_IPIPE
        mask_ack_irq(desc);
+#endif
 
        if (!irq_may_run(desc))
                goto out_unlock;
@@ -639,7 +660,16 @@ static inline void preflow_handler(struct irq_desc *desc)
 static inline void preflow_handler(struct irq_desc *desc) { }
 #endif
 
-static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip)
+#ifdef CONFIG_IPIPE
+static void cond_release_fasteoi_irq(struct irq_desc *desc,
+                                    struct irq_chip *chip)
+{
+       if (chip->irq_release && 
+           !irqd_irq_disabled(&desc->irq_data) && !desc->threads_oneshot)
+               chip->irq_release(&desc->irq_data);
+}
+#else
+static inline void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip)
 {
        if (!(desc->istate & IRQS_ONESHOT)) {
                chip->irq_eoi(&desc->irq_data);
@@ -659,6 +689,7 @@ static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip)
                chip->irq_eoi(&desc->irq_data);
        }
 }
+#endif /* !CONFIG_IPIPE */
 
 /**
  *     handle_fasteoi_irq - irq handler for transparent controllers
@@ -691,13 +722,23 @@ void handle_fasteoi_irq(struct irq_desc *desc)
        }
 
        kstat_incr_irqs_this_cpu(desc);
+#ifndef CONFIG_IPIPE
        if (desc->istate & IRQS_ONESHOT)
                mask_irq(desc);
+#endif
 
        preflow_handler(desc);
        handle_irq_event(desc);
 
+#ifdef CONFIG_IPIPE
+       /*
+        * IRQCHIP_EOI_IF_HANDLED is ignored as the I-pipe always
+        * sends EOI.
+        */
+       cond_release_fasteoi_irq(desc, chip);
+#else  /* !CONFIG_IPIPE */
        cond_unmask_eoi_irq(desc, chip);
+#endif /* !CONFIG_IPIPE */
 
        raw_spin_unlock(&desc->lock);
        return;
@@ -748,7 +789,9 @@ void handle_edge_irq(struct irq_desc *desc)
        kstat_incr_irqs_this_cpu(desc);
 
        /* Start handling the irq */
+#ifndef CONFIG_IPIPE
        desc->irq_data.chip->irq_ack(&desc->irq_data);
+#endif
 
        do {
                if (unlikely(!desc->action)) {
@@ -836,6 +879,11 @@ void handle_percpu_irq(struct irq_desc *desc)
 
        kstat_incr_irqs_this_cpu(desc);
 
+#ifdef CONFIG_IPIPE
+       (void)chip;
+       handle_irq_event_percpu(desc);
+       desc->ipipe_end(desc);
+#else
        if (chip->irq_ack)
                chip->irq_ack(&desc->irq_data);
 
@@ -843,6 +891,7 @@ void handle_percpu_irq(struct irq_desc *desc)
 
        if (chip->irq_eoi)
                chip->irq_eoi(&desc->irq_data);
+#endif
 }
 
 /**
@@ -865,13 +914,20 @@ void handle_percpu_devid_irq(struct irq_desc *desc)
 
        kstat_incr_irqs_this_cpu(desc);
 
+#ifndef CONFIG_IPIPE
        if (chip->irq_ack)
                chip->irq_ack(&desc->irq_data);
+#endif
 
        if (likely(action)) {
                trace_irq_handler_entry(irq, action);
                res = action->handler(irq, raw_cpu_ptr(action->percpu_dev_id));
                trace_irq_handler_exit(irq, action, res);
+#ifdef CONFIG_IPIPE
+               (void)chip;
+               desc->ipipe_end(desc);
+               return;
+#endif
        } else {
                unsigned int cpu = smp_processor_id();
                bool enabled = cpumask_test_cpu(cpu, desc->percpu_enabled);
@@ -887,6 +943,156 @@ void handle_percpu_devid_irq(struct irq_desc *desc)
                chip->irq_eoi(&desc->irq_data);
 }
 
+#ifdef CONFIG_IPIPE
+
+void __ipipe_ack_level_irq(struct irq_desc *desc)
+{
+       mask_ack_irq(desc);
+}
+
+void __ipipe_end_level_irq(struct irq_desc *desc)
+{
+       desc->irq_data.chip->irq_unmask(&desc->irq_data);
+}
+
+void __ipipe_ack_fasteoi_irq(struct irq_desc *desc)
+{
+       desc->irq_data.chip->irq_hold(&desc->irq_data);
+}
+
+void __ipipe_end_fasteoi_irq(struct irq_desc *desc)
+{
+       if (desc->irq_data.chip->irq_release)
+               desc->irq_data.chip->irq_release(&desc->irq_data);
+}
+
+void __ipipe_ack_edge_irq(struct irq_desc *desc)
+{
+       desc->irq_data.chip->irq_ack(&desc->irq_data);
+}
+
+void __ipipe_ack_percpu_irq(struct irq_desc *desc)
+{
+       if (desc->irq_data.chip->irq_ack)
+               desc->irq_data.chip->irq_ack(&desc->irq_data);
+
+       if (desc->irq_data.chip->irq_eoi)
+               desc->irq_data.chip->irq_eoi(&desc->irq_data);
+}
+
+void __ipipe_nop_irq(struct irq_desc *desc)
+{
+}
+
+void __ipipe_chained_irq(struct irq_desc *desc)
+{
+       /*
+        * XXX: Do NOT fold this into __ipipe_nop_irq(), see
+        * ipipe_chained_irq_p().
+        */
+}
+
+static void __ipipe_ack_bad_irq(struct irq_desc *desc)
+{
+       handle_bad_irq(desc);
+       WARN_ON_ONCE(1);
+}
+
+irq_flow_handler_t
+__fixup_irq_handler(struct irq_desc *desc, irq_flow_handler_t handle, int is_chained)
+{
+       if (unlikely(handle == NULL)) {
+               desc->ipipe_ack = __ipipe_ack_bad_irq;
+               desc->ipipe_end = __ipipe_nop_irq;
+       } else {
+               if (is_chained) {
+                       desc->ipipe_ack = handle;
+                       desc->ipipe_end = __ipipe_nop_irq;
+                       handle = __ipipe_chained_irq;
+               } else if (handle == handle_simple_irq) {
+                       desc->ipipe_ack = __ipipe_nop_irq;
+                       desc->ipipe_end = __ipipe_nop_irq;
+               } else if (handle == handle_level_irq) {
+                       desc->ipipe_ack = __ipipe_ack_level_irq;
+                       desc->ipipe_end = __ipipe_end_level_irq;
+               } else if (handle == handle_edge_irq) {
+                       desc->ipipe_ack = __ipipe_ack_edge_irq;
+                       desc->ipipe_end = __ipipe_nop_irq;
+               } else if (handle == handle_fasteoi_irq) {
+                       desc->ipipe_ack = __ipipe_ack_fasteoi_irq;
+                       desc->ipipe_end = __ipipe_end_fasteoi_irq;
+               } else if (handle == handle_percpu_irq ||
+                          handle == handle_percpu_devid_irq) {
+                       if (irq_desc_get_chip(desc) &&
+                           irq_desc_get_chip(desc)->irq_hold) {
+                               desc->ipipe_ack = __ipipe_ack_fasteoi_irq;
+                               desc->ipipe_end = __ipipe_end_fasteoi_irq;
+                       } else {
+                               desc->ipipe_ack = __ipipe_ack_percpu_irq;
+                               desc->ipipe_end = __ipipe_nop_irq;
+                       }
+               } else if (irq_desc_get_chip(desc) == &no_irq_chip) {
+                       desc->ipipe_ack = __ipipe_nop_irq;
+                       desc->ipipe_end = __ipipe_nop_irq;
+               } else {
+                       desc->ipipe_ack = __ipipe_ack_bad_irq;
+                       desc->ipipe_end = __ipipe_nop_irq;
+               }
+       }
+
+       /* Suppress intermediate trampoline routine. */
+       ipipe_root_domain->irqs[desc->irq_data.irq].ackfn = desc->ipipe_ack;
+
+       return handle;
+}
+
+void ipipe_enable_irq(unsigned int irq)
+{
+       struct irq_desc *desc;
+       struct irq_chip *chip;
+       unsigned long flags;
+
+       desc = irq_to_desc(irq);
+       if (desc == NULL)
+               return;
+
+       chip = irq_desc_get_chip(desc);
+
+       if (chip->irq_startup && (desc->istate & IPIPE_IRQS_NEEDS_STARTUP)) {
+
+               ipipe_root_only();
+
+               raw_spin_lock_irqsave(&desc->lock, flags);
+               if (desc->istate & IPIPE_IRQS_NEEDS_STARTUP) {
+                       desc->istate &= ~IPIPE_IRQS_NEEDS_STARTUP;
+                       chip->irq_startup(&desc->irq_data);
+               }
+               raw_spin_unlock_irqrestore(&desc->lock, flags);
+
+               return;
+       }
+
+       if (WARN_ON_ONCE(chip->irq_enable == NULL && chip->irq_unmask == NULL))
+               return;
+
+       if (chip->irq_enable)
+               chip->irq_enable(&desc->irq_data);
+       else
+               chip->irq_unmask(&desc->irq_data);
+}
+EXPORT_SYMBOL_GPL(ipipe_enable_irq);
+
+#else /* !CONFIG_IPIPE */
+
+irq_flow_handler_t
+__fixup_irq_handler(struct irq_desc *desc, irq_flow_handler_t handle, int is_chained)
+{
+       return handle;
+}
+
+#endif /* !CONFIG_IPIPE */
+EXPORT_SYMBOL_GPL(__fixup_irq_handler);
+
 static void
 __irq_do_set_handler(struct irq_desc *desc, irq_flow_handler_t handle,
                     int is_chained, const char *name)
@@ -921,6 +1127,8 @@ __irq_do_set_handler(struct irq_desc *desc, irq_flow_handler_t handle,
                        return;
        }
 
+       handle = __fixup_irq_handler(desc, handle, is_chained);
+
        /* Uninstall? */
        if (handle == handle_bad_irq) {
                if (desc->irq_data.chip != &no_irq_chip)
@@ -1256,6 +1464,20 @@ void irq_chip_mask_parent(struct irq_data *data)
 }
 EXPORT_SYMBOL_GPL(irq_chip_mask_parent);
 
+#ifdef CONFIG_IPIPE
+void irq_chip_hold_parent(struct irq_data *data)
+{
+       data = data->parent_data;
+       data->chip->irq_hold(data);
+}
+
+void irq_chip_release_parent(struct irq_data *data)
+{
+       data = data->parent_data;
+       data->chip->irq_release(data);
+}
+#endif
+
 /**
  * irq_chip_unmask_parent - Unmask the parent interrupt
  * @data:      Pointer to interrupt specific data
index 326a67f2410bf95c8f4299ef03de214b8d529964..d9a73e8a4134faa75796eff8b75f446fe7fe04a9 100644 (file)
@@ -42,7 +42,7 @@ struct irq_chip no_irq_chip = {
        .irq_enable     = noop,
        .irq_disable    = noop,
        .irq_ack        = ack_bad,
-       .flags          = IRQCHIP_SKIP_SET_WAKE,
+       .flags          = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_PIPELINE_SAFE,
 };
 
 /*
@@ -58,6 +58,6 @@ struct irq_chip dummy_irq_chip = {
        .irq_ack        = noop,
        .irq_mask       = noop,
        .irq_unmask     = noop,
-       .flags          = IRQCHIP_SKIP_SET_WAKE,
+       .flags          = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_PIPELINE_SAFE,
 };
 EXPORT_SYMBOL_GPL(dummy_irq_chip);
index c26c5bb6b491f75f76f1190cdc21989f79d17e09..4e21ee687bbfb7739fa82021674492fb5de9d02e 100644 (file)
@@ -36,12 +36,13 @@ void irq_gc_mask_disable_reg(struct irq_data *d)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
        struct irq_chip_type *ct = irq_data_get_chip_type(d);
+       unsigned long flags;
        u32 mask = d->mask;
 
-       irq_gc_lock(gc);
+       flags = irq_gc_lock(gc);
        irq_reg_writel(gc, mask, ct->regs.disable);
        *ct->mask_cache &= ~mask;
-       irq_gc_unlock(gc);
+       irq_gc_unlock(gc, flags);
 }
 
 /**
@@ -55,12 +56,13 @@ void irq_gc_mask_set_bit(struct irq_data *d)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
        struct irq_chip_type *ct = irq_data_get_chip_type(d);
+       unsigned long flags;
        u32 mask = d->mask;
 
-       irq_gc_lock(gc);
+       flags = irq_gc_lock(gc);
        *ct->mask_cache |= mask;
        irq_reg_writel(gc, *ct->mask_cache, ct->regs.mask);
-       irq_gc_unlock(gc);
+       irq_gc_unlock(gc, flags);
 }
 EXPORT_SYMBOL_GPL(irq_gc_mask_set_bit);
 
@@ -75,12 +77,13 @@ void irq_gc_mask_clr_bit(struct irq_data *d)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
        struct irq_chip_type *ct = irq_data_get_chip_type(d);
+       unsigned long flags;
        u32 mask = d->mask;
 
-       irq_gc_lock(gc);
+       flags = irq_gc_lock(gc);
        *ct->mask_cache &= ~mask;
        irq_reg_writel(gc, *ct->mask_cache, ct->regs.mask);
-       irq_gc_unlock(gc);
+       irq_gc_unlock(gc, flags);
 }
 EXPORT_SYMBOL_GPL(irq_gc_mask_clr_bit);
 
@@ -95,12 +98,13 @@ void irq_gc_unmask_enable_reg(struct irq_data *d)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
        struct irq_chip_type *ct = irq_data_get_chip_type(d);
+       unsigned long flags;
        u32 mask = d->mask;
 
-       irq_gc_lock(gc);
+       flags = irq_gc_lock(gc);
        irq_reg_writel(gc, mask, ct->regs.enable);
        *ct->mask_cache |= mask;
-       irq_gc_unlock(gc);
+       irq_gc_unlock(gc, flags);
 }
 
 /**
@@ -111,11 +115,12 @@ void irq_gc_ack_set_bit(struct irq_data *d)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
        struct irq_chip_type *ct = irq_data_get_chip_type(d);
+       unsigned long flags;
        u32 mask = d->mask;
 
-       irq_gc_lock(gc);
+       flags = irq_gc_lock(gc);
        irq_reg_writel(gc, mask, ct->regs.ack);
-       irq_gc_unlock(gc);
+       irq_gc_unlock(gc, flags);
 }
 EXPORT_SYMBOL_GPL(irq_gc_ack_set_bit);
 
@@ -127,11 +132,12 @@ void irq_gc_ack_clr_bit(struct irq_data *d)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
        struct irq_chip_type *ct = irq_data_get_chip_type(d);
+       unsigned long flags;
        u32 mask = ~d->mask;
 
-       irq_gc_lock(gc);
+       flags = irq_gc_lock(gc);
        irq_reg_writel(gc, mask, ct->regs.ack);
-       irq_gc_unlock(gc);
+       irq_gc_unlock(gc, flags);
 }
 
 /**
@@ -150,13 +156,14 @@ void irq_gc_mask_disable_and_ack_set(struct irq_data *d)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
        struct irq_chip_type *ct = irq_data_get_chip_type(d);
+       unsigned long flags;
        u32 mask = d->mask;
 
-       irq_gc_lock(gc);
+       flags = irq_gc_lock(gc);
        irq_reg_writel(gc, mask, ct->regs.disable);
        *ct->mask_cache &= ~mask;
        irq_reg_writel(gc, mask, ct->regs.ack);
-       irq_gc_unlock(gc);
+       irq_gc_unlock(gc, flags);
 }
 
 /**
@@ -167,11 +174,12 @@ void irq_gc_eoi(struct irq_data *d)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
        struct irq_chip_type *ct = irq_data_get_chip_type(d);
+       unsigned long flags;
        u32 mask = d->mask;
 
-       irq_gc_lock(gc);
+       flags = irq_gc_lock(gc);
        irq_reg_writel(gc, mask, ct->regs.eoi);
-       irq_gc_unlock(gc);
+       irq_gc_unlock(gc, flags);
 }
 
 /**
@@ -186,17 +194,18 @@ void irq_gc_eoi(struct irq_data *d)
 int irq_gc_set_wake(struct irq_data *d, unsigned int on)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       unsigned long flags;
        u32 mask = d->mask;
 
        if (!(mask & gc->wake_enabled))
                return -EINVAL;
 
-       irq_gc_lock(gc);
+       flags = irq_gc_lock(gc);
        if (on)
                gc->wake_active |= mask;
        else
                gc->wake_active &= ~mask;
-       irq_gc_unlock(gc);
+       irq_gc_unlock(gc, flags);
        return 0;
 }
 
index 44ed5f8c8759051896fcdae2a38ae6eb0c4edd83..c5454d58b6a07f80f2bda1c54e70166961a0dbc2 100644 (file)
@@ -60,6 +60,7 @@ enum {
        IRQS_PENDING            = 0x00000200,
        IRQS_SUSPENDED          = 0x00000800,
        IRQS_TIMINGS            = 0x00001000,
+       IPIPE_IRQS_NEEDS_STARTUP= 0x80000000,
 };
 
 #include "debug.h"
index 82afb7ed369f0df70bcd5d6fdc110addda5b842f..2aaa00e60b8599748f5058481a8b48a872ab8bdb 100644 (file)
@@ -126,6 +126,9 @@ static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node,
        for_each_possible_cpu(cpu)
                *per_cpu_ptr(desc->kstat_irqs, cpu) = 0;
        desc_smp_init(desc, node, affinity);
+#ifdef CONFIG_IPIPE
+       desc->istate |= IPIPE_IRQS_NEEDS_STARTUP;
+#endif
 }
 
 int nr_irqs = NR_IRQS;
@@ -541,11 +544,13 @@ int __init early_irq_init(void)
        return arch_early_irq_init();
 }
 
+#ifndef CONFIG_IPIPE
 struct irq_desc *irq_to_desc(unsigned int irq)
 {
        return (irq < NR_IRQS) ? irq_desc + irq : NULL;
 }
 EXPORT_SYMBOL(irq_to_desc);
+#endif /* CONFIG_IPIPE */
 
 static void free_desc(unsigned int irq)
 {
index b02caa442776f6ddfb036462154cfd5ab46b7c01..ec194621b1a91a941572944630cd826ba490def7 100644 (file)
@@ -818,9 +818,14 @@ again:
 
        desc->threads_oneshot &= ~action->thread_mask;
 
+#ifndef CONFIG_IPIPE
        if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) &&
            irqd_irq_masked(&desc->irq_data))
                unmask_threaded_irq(desc);
+#else /* CONFIG_IPIPE */
+       if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data))
+               desc->ipipe_end(desc);
+#endif /* CONFIG_IPIPE */
 
 out_unlock:
        raw_spin_unlock_irq(&desc->lock);