From a4633adcdbc15ac51afcd0e1395de58cee27cf92 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 29 Jun 2006 02:24:48 -0700 Subject: [PATCH] [PATCH] genirq: add genirq sw IRQ-retrigger Enable platforms that do not have a hardware-assisted hardirq-resend mechanism to resend them via a softirq-driven IRQ emulation mechanism. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/irq.h | 3 ++ kernel/irq/Makefile | 2 +- kernel/irq/manage.c | 10 +----- kernel/irq/resend.c | 78 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 kernel/irq/resend.c diff --git a/include/linux/irq.h b/include/linux/irq.h index b2688157b5..9a39756bfd 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -246,6 +246,9 @@ extern void note_interrupt(unsigned int irq, struct irq_desc *desc, int action_ret, struct pt_regs *regs); extern int can_request_irq(unsigned int irq, unsigned long irqflags); +/* Resending of interrupts :*/ +void check_irq_resend(struct irq_desc *desc, unsigned int irq); + extern void init_irq_proc(void); #endif /* CONFIG_GENERIC_HARDIRQS */ diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile index 9f77f50d81..627ace98d4 100644 --- a/kernel/irq/Makefile +++ b/kernel/irq/Makefile @@ -1,5 +1,5 @@ -obj-y := handle.o manage.o spurious.o +obj-y := handle.o manage.o spurious.o resend.o obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 19b438e09f..cffde48438 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -118,15 +118,7 @@ void enable_irq(unsigned int irq) WARN_ON(1); break; case 1: { - unsigned int status = desc->status & ~IRQ_DISABLED; - - desc->status = status; - if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { - desc->status = status | IRQ_REPLAY; - if (desc->chip && desc->chip->retrigger) - desc->chip->retrigger(irq); - } - desc->chip->enable(irq); + check_irq_resend(desc, irq); /* fall-through */ } default: diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c new file mode 100644 index 0000000000..096b102fb3 --- /dev/null +++ b/kernel/irq/resend.c @@ -0,0 +1,78 @@ +/* + * linux/kernel/irq/resend.c + * + * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar + * Copyright (C) 2005-2006, Thomas Gleixner + * + * This file contains the IRQ-resend code + * + * If the interrupt is waiting to be processed, we try to re-run it. + * We can't directly run it from here since the caller might be in an + * interrupt-protected region. Not all irq controller chips can + * retrigger interrupts at the hardware level, so in those cases + * we allow the resending of IRQs via a tasklet. + */ + +#include +#include +#include +#include + +#include "internals.h" + +#ifdef CONFIG_HARDIRQS_SW_RESEND + +/* Bitmap to handle software resend of interrupts: */ +static DECLARE_BITMAP(irqs_resend, NR_IRQS); + +/* + * Run software resends of IRQ's + */ +static void resend_irqs(unsigned long arg) +{ + struct irq_desc *desc; + int irq; + + while (!bitmap_empty(irqs_resend, NR_IRQS)) { + irq = find_first_bit(irqs_resend, NR_IRQS); + clear_bit(irq, irqs_resend); + desc = irq_desc + irq; + spin_lock_irqsave(&desc->lock, flags); + desc->handle_irq(irq, desc, NULL); + spin_unlock_irqrestore(&desc->lock, flags); + } +} + +/* Tasklet to handle resend: */ +static DECLARE_TASKLET(resend_tasklet, resend_irqs, 0); + +#endif + +/* + * IRQ resend + * + * Is called with interrupts disabled and desc->lock held. + */ +void check_irq_resend(struct irq_desc *desc, unsigned int irq) +{ + unsigned int status = desc->status; + + /* + * Make sure the interrupt is enabled, before resending it: + */ + desc->chip->enable(irq); + + if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { + desc->status &= ~IRQ_PENDING; + desc->status = status | IRQ_REPLAY; + + if (!desc->chip || !desc->chip->retrigger || + !desc->chip->retrigger(irq)) { +#ifdef CONFIG_HARDIRQS_SW_RESEND + /* Set it pending and activate the softirq: */ + set_bit(irq, irqs_resend); + tasklet_schedule(&resend_tasklet); +#endif + } + } +} -- 2.39.5