lkml.org 
[lkml]   [2003]   [Apr]   [8]   [last100]   RSS Feed
Views: [more markup]  [less markup]  [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Subject[PATCH][v850] On the v850/nb85e, acknowledge interrupts immediately after handling them
DateTue, 8 Apr 2003 18:27:40 +0900 (JST)
From(Miles Bader)
Previously, it was done automatically by the `reti' isntruction upon
returning from the kernel, but that doesn't do the correct thing in
various cases, for instance if there's a context switch, or a softirq.

diff -ruN -X../cludes linux-2.5.67-moo.orig/arch/v850/kernel/nb85e_intc.c linux-2.5.67-moo/arch/v850/kernel/nb85e_intc.c
--- linux-2.5.67-moo.orig/arch/v850/kernel/nb85e_intc.c	2002-11-28 10:24:54.000000000 +0900
+++ linux-2.5.67-moo/arch/v850/kernel/nb85e_intc.c	2003-04-08 14:03:02.000000000 +0900
@@ -1,8 +1,8 @@
 /*
  * arch/v850/kernel/nb85e_intc.c -- NB85E cpu core interrupt controller (INTC)
  *
- *  Copyright (C) 2001,02  NEC Corporation
- *  Copyright (C) 2001,02  Miles Bader <miles@gnu.org>
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
  *
  * This file is subject to the terms and conditions of the GNU General
  * Public License.  See the file COPYING in the main directory of this
@@ -26,6 +26,42 @@
 	return 0;
 }
 
+static void nb85e_intc_end_irq (unsigned irq)
+{
+	unsigned long psw, temp;
+
+	/* Clear the highest-level bit in the In-service priority register
+	   (ISPR), to allow this interrupt (or another of the same or
+	   lesser priority) to happen again.
+
+	   The `reti' instruction normally does this automatically when the
+	   PSW bits EP and NP are zero, but we can't always rely on reti
+	   being used consistently to return after an interrupt (another
+	   process can be scheduled, for instance, which can delay the
+	   associated reti for a long time, or this process may be being
+	   single-stepped, which uses the `dbret' instruction to return
+	   from the kernel).
+
+	   We also set the PSW EP bit, which prevents reti from also
+	   trying to modify the ISPR itself.  */
+
+	/* Get PSW and disable interrupts.  */
+	asm volatile ("stsr psw, %0; di" : "=r" (psw));
+	/* We don't want to do anything for NMIs (they don't use the ISPR).  */
+	if (! (psw & 0xC0)) {
+		/* Transition to `trap' state, so that an eventual real
+		   reti instruction won't modify the ISPR.  */
+		psw |= 0x40;
+		/* Fake an interrupt return, which automatically clears the
+		   appropriate bit in the ISPR.  */
+		asm volatile ("mov hilo(1f), %0;"
+			      "ldsr %0, eipc; ldsr %1, eipsw;"
+			      "reti;"
+			      "1:"
+			      : "=&r" (temp) : "r" (psw));
+	}
+}
+
 /* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array
    INITS (which is terminated by an entry with the name field == 0).  */
 void __init nb85e_intc_init_irq_types (struct nb85e_intc_irq_init *inits,
@@ -43,7 +79,7 @@
 		hwit->enable   = nb85e_intc_enable_irq;
 		hwit->disable  = nb85e_intc_disable_irq;
 		hwit->ack      = irq_nop;
-		hwit->end      = irq_nop;
+		hwit->end      = nb85e_intc_end_irq;
 		
 		/* Initialize kernel IRQ infrastructure for this interrupt.  */
 		init_irq_handlers(init->base, init->num, init->interval, hwit);
diff -ruN -X../cludes linux-2.5.67-moo.orig/include/asm-v850/nb85e_intc.h linux-2.5.67-moo/include/asm-v850/nb85e_intc.h
--- linux-2.5.67-moo.orig/include/asm-v850/nb85e_intc.h	2002-11-05 11:25:32.000000000 +0900
+++ linux-2.5.67-moo/include/asm-v850/nb85e_intc.h	2003-04-08 14:03:02.000000000 +0900
@@ -1,8 +1,8 @@
 /*
  * include/asm-v850/nb85e_intc.h -- NB85E cpu core interrupt controller (INTC)
  *
- *  Copyright (C) 2001,02  NEC Corporation
- *  Copyright (C) 2001,02  Miles Bader <miles@gnu.org>
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
  *
  * This file is subject to the terms and conditions of the GNU General
  * Public License.  See the file COPYING in the main directory of this
@@ -26,7 +26,7 @@
    address.  */
 #define NB85E_INTC_IC_BASE_ADDR	  0xFFFFF110
 #define NB85E_INTC_IC_ADDR(irq)	  (NB85E_INTC_IC_BASE_ADDR + ((irq) << 1))
-#define NB85E_INTC_IC(irq)	  (*(char *)NB85E_INTC_IC_ADDR(irq))
+#define NB85E_INTC_IC(irq)	  (*(volatile u8 *)NB85E_INTC_IC_ADDR(irq))
 /* Encode priority PR for storing in an interrupt control register.  */
 #define NB85E_INTC_IC_PR(pr)	  (pr)
 /* Interrupt disable bit in an interrupt control register.  */
@@ -36,6 +36,13 @@
 #define NB85E_INTC_IC_IF_BIT	  7
 #define NB85E_INTC_IC_IF	  (1 << NB85E_INTC_IC_IF_BIT)
 
+/* The ISPR (In-service priority register) contains one bit for each interrupt
+   priority level, which is set to one when that level is currently being
+   serviced (and thus blocking any interrupts of equal or lesser level).  */
+#define NB85E_INTC_ISPR_ADDR	  0xFFFFF1FA
+#define NB85E_INTC_ISPR		  (*(volatile u8 *)NB85E_INTC_ISPR_ADDR)
+
+
 #ifndef __ASSEMBLY__
 
 /* Enable interrupt handling for interrupt IRQ.  */
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
\
 
 \ /
  Last update: 2005-03-22 12:34    [from the cache]
©2003-2008