[PATCH] pass irq handling status down to low-level code

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



(Note: Patch also attached because the inline version is certain to get
line wrapped.)

In order for low-level code to know whether/how a hardware interrupt
was
serviced, make sure this information gets passed down correctly.

At once, use the proper type (irqreturn_t) for returning this
information,
which in turn required breaking up a header into two to resolve
recursive
inclusion problems resulting otherwise.

Architecture dependent code needs to change for this to fully work,
but
no change should be necessary if the described functionality isn't
consumed on a given architecture. Thus respective adjustments in this
patch
are only to those architectures I have further depend code for (i386,
x86_64, ia64).

(Kernel debuggers may want to convert a hardware interrupt, say from a
hot key press, into a pseudo-exception, requiring that they should
have
a way to get this information communicated from the respective
interrupt
handler. For this to fully work, additional adjustments are necessary,
so this is meant ot only be the first step.)

Signed-off-by: Jan Beulich <[email protected]>

diff -Npru 2.6.13/arch/i386/kernel/irq.c
2.6.13-irqreturn/arch/i386/kernel/irq.c
--- 2.6.13/arch/i386/kernel/irq.c	2005-08-29 01:41:01.000000000
+0200
+++ 2.6.13-irqreturn/arch/i386/kernel/irq.c	2005-09-01
11:32:11.000000000 +0200
@@ -51,7 +51,7 @@ static union irq_ctx *softirq_ctx[NR_CPU
  * SMP cross-CPU interrupts have their own specific
  * handlers).
  */
-fastcall unsigned int do_IRQ(struct pt_regs *regs)
+fastcall irqreturn_t do_IRQ(struct pt_regs *regs)
 {	
 	/* high bits used in ret_from_ code */
 	int irq = regs->orig_eax & 0xff;
@@ -59,6 +59,7 @@ fastcall unsigned int do_IRQ(struct pt_r
 	union irq_ctx *curctx, *irqctx;
 	u32 *isp;
 #endif
+	irqreturn_t ret;
 
 	irq_enter();
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
@@ -88,7 +89,7 @@ fastcall unsigned int do_IRQ(struct pt_r
 	 * current stack (which is the irq stack already after all)
 	 */
 	if (curctx != irqctx) {
-		int arg1, arg2, ebx;
+		int edx, ebx;
 
 		/* build the stack frame on the IRQ stack */
 		isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
@@ -99,17 +100,17 @@ fastcall unsigned int do_IRQ(struct pt_r
 			"       xchgl   %%ebx,%%esp      \n"
 			"       call    __do_IRQ         \n"
 			"       movl   %%ebx,%%esp      \n"
-			: "=a" (arg1), "=d" (arg2), "=b" (ebx)
-			:  "0" (irq),   "1" (regs),  "2" (isp)
+			: "=a" (ret), "=d" (edx), "=b" (ebx)
+			:  "0" (irq),  "1" (regs), "2" (isp)
 			: "memory", "cc", "ecx"
 		);
 	} else
 #endif
-		__do_IRQ(irq, regs);
+		ret = __do_IRQ(irq, regs);
 
 	irq_exit();
 
-	return 1;
+	return ret;
 }
 
 #ifdef CONFIG_4KSTACKS
diff -Npru 2.6.13/arch/i386/mach-visws/visws_apic.c
2.6.13-irqreturn/arch/i386/mach-visws/visws_apic.c
--- 2.6.13/arch/i386/mach-visws/visws_apic.c	2005-08-29
01:41:01.000000000 +0200
+++ 2.6.13-irqreturn/arch/i386/mach-visws/visws_apic.c	2005-03-16
12:24:41.000000000 +0100
@@ -198,6 +198,7 @@ static irqreturn_t piix4_master_intr(int
 	int realirq;
 	irq_desc_t *desc;
 	unsigned long flags;
+	irqreturn_t ret;
 
 	spin_lock_irqsave(&i8259A_lock, flags);
 
@@ -246,12 +247,14 @@ static irqreturn_t piix4_master_intr(int
 	kstat_cpu(smp_processor_id()).irqs[realirq]++;
 
 	if (likely(desc->action != NULL))
-		handle_IRQ_event(realirq, regs, desc->action);
+		ret = handle_IRQ_event(realirq, regs, desc->action);
+	else
+		ret = IRQ_NONE;
 
 	if (!(desc->status & IRQ_DISABLED))
 		enable_8259A_irq(realirq);
 
-	return IRQ_HANDLED;
+	return ret;
 
 out_unlock:
 	spin_unlock_irqrestore(&i8259A_lock, flags);
diff -Npru 2.6.13/arch/ia64/kernel/irq_ia64.c
2.6.13-irqreturn/arch/ia64/kernel/irq_ia64.c
--- 2.6.13/arch/ia64/kernel/irq_ia64.c	2005-08-29 01:41:01.000000000
+0200
+++ 2.6.13-irqreturn/arch/ia64/kernel/irq_ia64.c	2005-09-01
14:08:15.000000000 +0200
@@ -99,10 +99,11 @@ free_irq_vector (int vector)
  * interrupt. This branches to the correct hardware IRQ handler via
  * function ptr.
  */
-void
+irqreturn_t
 ia64_handle_irq (ia64_vector vector, struct pt_regs *regs)
 {
 	unsigned long saved_tpr;
+	irqreturn_t ret;
 
 #if IRQ_DEBUG
 	{
@@ -142,12 +143,13 @@ ia64_handle_irq (ia64_vector vector, str
 	irq_enter();
 	saved_tpr = ia64_getreg(_IA64_REG_CR_TPR);
 	ia64_srlz_d();
+	ret = IRQ_NONE;
 	while (vector != IA64_SPURIOUS_INT_VECTOR) {
 		if (!IS_RESCHEDULE(vector)) {
 			ia64_setreg(_IA64_REG_CR_TPR, vector);
 			ia64_srlz_d();
 
-			__do_IRQ(local_vector_to_irq(vector), regs);
+			ret |= __do_IRQ(local_vector_to_irq(vector),
regs);
 
 			/*
 			 * Disable interrupts and send EOI:
@@ -164,6 +166,7 @@ ia64_handle_irq (ia64_vector vector, str
 	 * come through until ia64_eoi() has been done.
 	 */
 	irq_exit();
+	return ret;
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
diff -Npru 2.6.13/arch/x86_64/kernel/irq.c
2.6.13-irqreturn/arch/x86_64/kernel/irq.c
--- 2.6.13/arch/x86_64/kernel/irq.c	2005-08-29 01:41:01.000000000
+0200
+++ 2.6.13-irqreturn/arch/x86_64/kernel/irq.c	2005-09-01
11:32:11.000000000 +0200
@@ -93,18 +93,19 @@ skip:
  * SMP cross-CPU interrupts have their own specific
  * handlers).
  */
-asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
+asmlinkage irqreturn_t do_IRQ(struct pt_regs *regs)
 {	
 	/* high bits used in ret_from_ code  */
 	unsigned irq = regs->orig_rax & 0xff;
+	irqreturn_t ret = IRQ_NONE;
 
 	irq_enter();
-	BUG_ON(irq > 256);
 
-	__do_IRQ(irq, regs);
+	ret = __do_IRQ(irq, regs);
+
 	irq_exit();
 
-	return 1;
+	return ret;
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
diff -Npru 2.6.13/include/linux/interrupt.h
2.6.13-irqreturn/include/linux/interrupt.h
--- 2.6.13/include/linux/interrupt.h	2005-08-29 01:41:01.000000000
+0200
+++ 2.6.13-irqreturn/include/linux/interrupt.h	2005-03-21
14:20:20.000000000 +0100
@@ -8,31 +8,12 @@
 #include <linux/bitops.h>
 #include <linux/preempt.h>
 #include <linux/cpumask.h>
+#include <linux/irqreturn.h>
 #include <linux/hardirq.h>
 #include <asm/atomic.h>
 #include <asm/ptrace.h>
 #include <asm/system.h>
 
-/*
- * For 2.4.x compatibility, 2.4.x can use
- *
- *	typedef void irqreturn_t;
- *	#define IRQ_NONE
- *	#define IRQ_HANDLED
- *	#define IRQ_RETVAL(x)
- *
- * To mix old-style and new-style irq handler returns.
- *
- * IRQ_NONE means we didn't handle it.
- * IRQ_HANDLED means that we did have a valid interrupt and handled
it.
- * IRQ_RETVAL(x) selects on the two depending on x being non-zero (for
handled)
- */
-typedef int irqreturn_t;
-
-#define IRQ_NONE	(0)
-#define IRQ_HANDLED	(1)
-#define IRQ_RETVAL(x)	((x) != 0)
-
 struct irqaction {
 	irqreturn_t (*handler)(int, void *, struct pt_regs *);
 	unsigned long flags;
diff -Npru 2.6.13/include/linux/irq.h
2.6.13-irqreturn/include/linux/irq.h
--- 2.6.13/include/linux/irq.h	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-irqreturn/include/linux/irq.h	2005-09-01
17:43:05.000000000 +0200
@@ -17,6 +17,7 @@
 #include <linux/cache.h>
 #include <linux/spinlock.h>
 #include <linux/cpumask.h>
+#include <linux/irqreturn.h>
 
 #include <asm/irq.h>
 #include <asm/ptrace.h>
@@ -86,7 +87,7 @@ extern int noirqdebug_setup(char *str);
 
 extern fastcall int handle_IRQ_event(unsigned int irq, struct pt_regs
*regs,
 					struct irqaction *action);
-extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs
*regs);
+extern fastcall irqreturn_t __do_IRQ(unsigned int irq, struct pt_regs
*regs);
 extern void note_interrupt(unsigned int irq, irq_desc_t *desc,
 					int action_ret, struct pt_regs
*regs);
 extern int can_request_irq(unsigned int irq, unsigned long irqflags);
diff -Npru 2.6.13/include/linux/irqreturn.h
2.6.13-irqreturn/include/linux/irqreturn.h
--- 2.6.13/include/linux/irqreturn.h	1970-01-01 01:00:00.000000000
+0100
+++ 2.6.13-irqreturn/include/linux/irqreturn.h	2005-03-21
14:21:06.000000000 +0100
@@ -0,0 +1,27 @@
+/* irqreturn.h */
+#ifndef _LINUX_IRQRETURN_H
+#define _LINUX_IRQRETURN_H
+
+#include <linux/config.h>
+
+/*
+ * For 2.4.x compatibility, 2.4.x can use
+ *
+ *	typedef void irqreturn_t;
+ *	#define IRQ_NONE
+ *	#define IRQ_HANDLED
+ *	#define IRQ_RETVAL(x)
+ *
+ * To mix old-style and new-style irq handler returns.
+ *
+ * IRQ_NONE means we didn't handle it.
+ * IRQ_HANDLED means that we did have a valid interrupt and handled
it.
+ * IRQ_RETVAL(x) selects on the two depending on x being non-zero (for
handled)
+ */
+typedef int irqreturn_t;
+
+#define IRQ_NONE	(0)
+#define IRQ_HANDLED	(1)
+#define IRQ_RETVAL(x)	((x) != 0)
+
+#endif
diff -Npru 2.6.13/kernel/irq/handle.c
2.6.13-irqreturn/kernel/irq/handle.c
--- 2.6.13/kernel/irq/handle.c	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-irqreturn/kernel/irq/handle.c	2005-09-01
17:54:23.000000000 +0200
@@ -76,16 +76,18 @@ irqreturn_t no_action(int cpl, void *dev
 /*
  * Have got an event to handle:
  */
-fastcall int handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
+fastcall irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs
*regs,
 				struct irqaction *action)
 {
-	int ret, retval = 0, status = 0;
+	int status = 0;
+	irqreturn_t retval = IRQ_NONE;
 
 	if (!(action->flags & SA_INTERRUPT))
 		local_irq_enable();
 
 	do {
-		ret = action->handler(irq, action->dev_id, regs);
+		irqreturn_t ret = action->handler(irq, action->dev_id,
regs);
+
 		if (ret == IRQ_HANDLED)
 			status |= action->flags;
 		retval |= ret;
@@ -104,15 +106,16 @@ fastcall int handle_IRQ_event(unsigned i
  * SMP cross-CPU interrupts have their own specific
  * handlers).
  */
-fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs
*regs)
+fastcall irqreturn_t __do_IRQ(unsigned int irq, struct pt_regs *regs)
 {
 	irq_desc_t *desc = irq_desc + irq;
 	struct irqaction * action;
 	unsigned int status;
+	irqreturn_t ret = IRQ_NONE;
 
 	kstat_this_cpu.irqs[irq]++;
 	if (desc->status & IRQ_PER_CPU) {
-		irqreturn_t action_ret;
+		irqreturn_t action_ret = IRQ_NONE;
 
 		/*
 		 * No locking required for CPU-local interrupts:
@@ -120,7 +123,7 @@ fastcall unsigned int __do_IRQ(unsigned 
 		desc->handler->ack(irq);
 		action_ret = handle_IRQ_event(irq, regs, desc->action);
 		desc->handler->end(irq);
-		return 1;
+		return action_ret;
 	}
 
 	spin_lock(&desc->lock);
@@ -173,6 +176,7 @@ fastcall unsigned int __do_IRQ(unsigned 
 		spin_lock(&desc->lock);
 		if (!noirqdebug)
 			note_interrupt(irq, desc, action_ret, regs);
+		ret |= action_ret;
 		if (likely(!(desc->status & IRQ_PENDING)))
 			break;
 		desc->status &= ~IRQ_PENDING;
@@ -187,6 +191,6 @@ out:
 	desc->handler->end(irq);
 	spin_unlock(&desc->lock);
 
-	return 1;
+	return ret;
 }
 

Attachment: linux-2.6.13-irqreturn.patch
Description: Binary data


[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]
  Powered by Linux