From: David Brownell Subject: GENIRQ: add handle_threaded_irq() flow handler Define a new flow handler, handle_threaded_irq(), for IRQ threads to use when chaining IRQs. Unlike existing flow handlers, handle_simple_irq() and siblings, this one is used only from sleep-capable contexts. It always calls irqaction handlers from that same (shared) sleep-capable context. This is independent of Thomas' irq threading patchset, and can be viewed as a complement to it. This adds support for IRQs whose handlers must *ONLY* ever run in thread contexts ... instead of offloading code from hardirq context into a thread. Another way this differs is that it doesn't create more kernel threads; it only leverages an existing thread. Signed-off-by: David Brownell --- include/linux/irq.h | 7 ++++- kernel/irq/chip.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -278,8 +278,8 @@ static inline int irq_balancing_disabled extern irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action); /* - * Built-in IRQ handlers for various IRQ types, - * callable via desc->chip->handle_irq() + * IRQ flow handlers for various IRQ types, callable via + * generic_handle_irq*() or desc->handle_irq() */ extern void handle_level_irq(unsigned int irq, struct irq_desc *desc); extern void handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc); @@ -288,6 +288,9 @@ extern void handle_simple_irq(unsigned i extern void handle_percpu_irq(unsigned int irq, struct irq_desc *desc); extern void handle_bad_irq(unsigned int irq, struct irq_desc *desc); +/* Flow handler that must only be called from sleeping context */ +extern void handle_threaded_irq(unsigned int irq, struct irq_desc *desc); + /* * Monolithic do_IRQ implementation. */ --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -300,6 +300,67 @@ static inline void mask_ack_irq(struct i } /** + * handle_threaded_irq - flow handler reusing current irq thread + * @irq: the interrupt number + * @desc: the interrupt description structure for this irq + * Context: irq thread, with IRQs enabled + * + * IRQ threads which demultiplex IRQs may use this flow handler + * to chain those demultiplexed IRQs to subsidiary handlers, when + * all that IRQ dispatch logic must run in sleeping contexts. + * + * Examples include some multifunction I2C and SPI based devices + * (where access to registers, including ones involved in IRQ + * dispatching, requires sleeping) that have multiple independent + * maskable interupts. + * + * The irq thread using this flow handler must handle any ack, + * clear, mask or unmask issues needed. + */ +void +handle_threaded_irq(unsigned int irq, struct irq_desc *desc) +{ + struct irqaction *action; + irqreturn_t action_ret; + + spin_lock_irq(&desc->lock); + + if (unlikely(desc->status & IRQ_INPROGRESS)) + goto out_unlock; + desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); + kstat_incr_irqs_this_cpu(irq, desc); + + action = desc->action; + if (unlikely(!action || (desc->status & IRQ_DISABLED))) + goto out_unlock; + + desc->status |= IRQ_INPROGRESS; + spin_unlock_irq(&desc->lock); + + /* simplified handle_IRQ_event(): no random sampling; + * IRQs are always enabled so action->handler may sleep; + * no hooks for handing off to yet another irq thread. + */ + action_ret = IRQ_NONE; + do { + /* REVISIT can we get some explicit knowledge that this + * handler expects to run in thread context? Maybe an + * IRQF_THREADED check, or a new handler type ... + */ + action_ret |= action->handler(irq, action->dev_id); + action = action->next; + } while (action); + + if (!noirqdebug) + note_interrupt(irq, desc, action_ret); + + spin_lock_irq(&desc->lock); + desc->status &= ~IRQ_INPROGRESS; +out_unlock: + spin_unlock_irq(&desc->lock); +} + +/** * handle_simple_irq - Simple and software-decoded IRQs. * @irq: the interrupt number * @desc: the interrupt description structure for this irq