Subject: interrupt handler pending list issue
To: None <port-sparc64@netbsd.org>
From: Takeshi Nakayama <tn@catvmics.ne.jp>
List: port-sparc64
Date: 07/24/2004 10:08:56
----Next_Part(Sat_Jul_24_10:08:56_2004_589)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Hi folks,
Our interrupt handler pending list has issue that it has
possibilities to link same handler twice, since we use same value
0 to indicate the list end and a interrupt handler in-use flag.
I found this issue about two years ago, and then I has been used
attached patch (intr_pend-fix1.diff). This patch simply changes
the list end value from 0 to -1.
It seems that OpenBSD fixed this issue a year ago to introduce
ih_busy in interrupt handler. Here is the commit log of OpenBSD.
| Changes by: henric at cvs.openbsd.org 2003/03/20 16:05:30
|
| Modified files:
| sys/arch/sparc64/include: cpu.h
| sys/arch/sparc64/sparc64: genassym.cf intr.c locore.s
|
| Log message:
| The current code tries to use the same field in the interrupt handler as
| both a "next" pointer for a singly-linked list and as an in-use flag.
| This obviously does not work all that well. This change adds a separate
| ih_busy flag to mark the handler as in-use, leaving ih_pending for use by
| the list code.
I adopt this changes to -current, then make a patch attached
(intr_pend-fix2.diff).
I think the latter patch is easy to understand and some more
changes. So I would like to commit this patch. Commnets?
Note: attached patches can apply cleanly both to netbsd-1-6 and
to netbsd-2-0.
-- Takeshi Nakayama
----Next_Part(Sat_Jul_24_10:08:56_2004_589)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="intr_pend-fix1.diff"
--- sparc64/locore.s.orig Thu Jul 22 13:09:23 2004
+++ sparc64/locore.s Thu Jul 22 13:08:07 2004
@@ -3984,7 +3984,7 @@
.data
.globl intrpending
intrpending:
- .space 16 * 8 * PTRSZ
+ .space 16 * 8 * PTRSZ, -1
#ifdef DEBUG
#define INTRDEBUG_VECTOR 0x1
@@ -4443,9 +4443,9 @@
1:
membar #StoreLoad ! Make sure any failed casxa insns complete
LDPTR [%l4], %l2 ! Check a slot
- brz,pn %l2, intrcmplt ! Empty list?
-
- clr %l7
+ cmp %l2, -1
+ beq,pn CCCR, intrcmplt ! Empty list?
+ mov -1, %l7
membar #LoadStore
CASPTR [%l4] ASI_N, %l2, %l7 ! Grab the entire list
cmp %l7, %l2
@@ -4468,7 +4468,8 @@
stx %g0, [%l1] ! Clear intr source
membar #Sync ! Should not be needed
0:
- brnz,pn %l7, 2b ! 'Nother?
+ cmp %l7, -1
+ bne,pn CCCR, 2b ! 'Nother?
mov %l7, %l2
#else /* INTRLIST */
----Next_Part(Sat_Jul_24_10:08:56_2004_589)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="intr_pend-fix2.diff"
--- include/cpu.h.orig Sat Jun 19 20:26:30 2004
+++ include/cpu.h Thu Jul 22 13:53:31 2004
@@ -293,8 +293,9 @@
short ih_number; /* interrupt number */
/* the H/W provides */
char ih_pil; /* interrupt priority */
+ volatile char ih_busy; /* handler is on list */
struct intrhand *ih_next; /* global list */
- struct intrhand *ih_pending; /* interrupt queued */
+ struct intrhand *ih_pending; /* pending list */
volatile u_int64_t *ih_map; /* Interrupt map reg */
volatile u_int64_t *ih_clr; /* clear interrupt reg */
};
--- sparc64/clock.c.orig Thu Mar 18 09:55:50 2004
+++ sparc64/clock.c Thu Jul 22 13:59:04 2004
@@ -649,6 +649,7 @@
schedint.ih_pil = PIL_SCHED;
schedint.ih_clr = NULL;
schedint.ih_arg = 0;
+ schedint.ih_busy = 0;
schedint.ih_pending = 0;
schedhz = stathz/4;
--- sparc64/genassym.cf.orig Sun Mar 28 17:44:32 2004
+++ sparc64/genassym.cf Thu Jul 22 13:54:40 2004
@@ -256,6 +256,7 @@
define IH_ARG offsetof(struct intrhand, ih_arg)
define IH_NUMBER offsetof(struct intrhand, ih_number)
define IH_PIL offsetof(struct intrhand, ih_pil)
+define IH_BUSY offsetof(struct intrhand, ih_busy)
define IH_PEND offsetof(struct intrhand, ih_pending)
define IH_NEXT offsetof(struct intrhand, ih_next)
define IH_MAP offsetof(struct intrhand, ih_map)
--- sparc64/intr.c.orig Tue Nov 11 11:45:12 2003
+++ sparc64/intr.c Thu Jul 22 13:58:48 2004
@@ -243,6 +243,7 @@
* and we do want to preserve order.
*/
ih->ih_pil = level; /* XXXX caller should have done this before */
+ ih->ih_busy = 0; /* XXXX caller should have done this before */
ih->ih_pending = 0; /* XXXX caller should have done this before */
ih->ih_next = NULL;
@@ -317,6 +318,7 @@
ih->ih_fun = (int (*) __P((void *)))fun; /* XXX */
ih->ih_arg = arg;
ih->ih_pil = level;
+ ih->ih_busy = 0;
ih->ih_pending = 0;
ih->ih_clr = NULL;
return (void *)ih;
--- sparc64/locore.s.orig Thu Jul 22 13:09:23 2004
+++ sparc64/locore.s Thu Jul 22 14:12:43 2004
@@ -4076,7 +4076,8 @@
setup_sparcintr:
#ifdef INTR_INTERLOCK
- LDPTR [%g5+IH_PEND], %g6 ! Read pending flag
+ ldstub [%g5+IH_BUSY], %g6 ! Check if already in use
+ membar #LoadLoad | #LoadStore
brnz,pn %g6, ret_from_intr_vector ! Skip it if it's running
#endif
ldub [%g5+IH_PIL], %g6 ! Read interrupt mask
@@ -4452,21 +4453,37 @@
bne,pn %icc, 1b
add %sp, CC64FSZ+STKB, %o2 ! tf = %sp + CC64FSZ + STKB
2:
+ LDPTR [%l2 + IH_PEND], %l7 ! Load next pending
LDPTR [%l2 + IH_FUN], %o4 ! ih->ih_fun
LDPTR [%l2 + IH_ARG], %o0 ! ih->ih_arg
+ LDPTR [%l2 + IH_CLR], %l1 ! ih->ih_clear
+
+ STPTR %g0, [%l2 + IH_PEND] ! Unlink from list
+
+ ! Note that the function handler itself or an interrupt
+ ! may add handlers to the pending pending. This includes
+ ! the current entry in %l2 and entries held on our local
+ ! pending list in %l7. The former is ok because we are
+ ! done with it now and the latter because they are still
+ ! marked busy. We may also be able to do this by having
+ ! the soft interrupts use a variation of the hardware
+ ! interrupts' ih_clr scheme. Note: The busy flag does
+ ! not itself prevent the handler from being entered
+ ! recursively. It only indicates that the handler is
+ ! about to be invoked and that it should not be added
+ ! to the pending table.
+ membar #StoreStore | #LoadStore
+ stb %g0, [%l2 + IH_BUSY] ! Allow the ih to be reused
+
+ ! At this point, the current ih could already be added
+ ! back to the pending table.
jmpl %o4, %o7 ! handled = (*ih->ih_fun)(...)
movrz %o0, %o2, %o0 ! arg = (arg == 0) ? arg : tf
- LDPTR [%l2 + IH_PEND], %l7 ! Clear pending flag
- LDPTR [%l2 + IH_CLR], %l1
- membar #LoadStore
- STPTR %g0, [%l2 + IH_PEND] ! Clear pending flag
- membar #Sync
brz,pn %l1, 0f
- add %l5, %o0, %l5
+ add %l5, %o0, %l5 ! Add handler return value
stx %g0, [%l1] ! Clear intr source
- membar #Sync ! Should not be needed
0:
brnz,pn %l7, 2b ! 'Nother?
mov %l7, %l2
@@ -11632,15 +11649,21 @@
*/
ENTRY(send_softint)
rdpr %pil, %g1 ! s = splx(level)
+#if 1
+ wrpr %g0, PIL_HIGH, %pil
+#else
cmp %g1, %o1
bge,pt %icc, 1f
nop
wrpr %o1, 0, %pil
+#endif
1:
brz,pn %o2, 1f
- set intrpending, %o3
- LDPTR [%o2 + IH_PEND], %o5
- mov 8, %o4 ! Number of slots to search
+ mov 8, %o4 ! Number of slots to search
+ set intrpending, %o3
+
+ ldstub [%o2 + IH_BUSY], %o5
+ membar #LoadLoad | #LoadStore
#ifdef INTR_INTERLOCK
brnz %o5, 1f
#endif
----Next_Part(Sat_Jul_24_10:08:56_2004_589)----