Subject: patch for generic software interrupts
To: None <port-newsmips@netbsd.org>
From: Izumi Tsutsui <tsutsui@ceres.dti.ne.jp>
List: port-newsmips
Date: 04/27/2003 17:19:23
I wrote:

> (I've implemented generic software interrupt, but it doesn't help..)

The attached is a patch for generic software interrupt support.
Most code is taken from algor port, and interrupt handlers
of hb and apbus are also modified to share some structures.
I've tested new kernel with this patch both on NWS-3470D and
NWS-5000X, it seems to work without problem.

If there is no objection I'll commit this tomorrow.
---
Izumi Tsutsui
tsutsui@ceres.dti.ne.jp

Index: apbus/apbus.c
===================================================================
RCS file: /cvsroot/src/sys/arch/newsmips/apbus/apbus.c,v
retrieving revision 1.13
diff -u -r1.13 apbus.c
--- apbus/apbus.c	2003/04/19 14:56:05	1.13
+++ apbus/apbus.c	2003/04/27 04:50:33
@@ -38,6 +38,7 @@
 #include <machine/autoconf.h>
 #define _NEWSMIPS_BUS_DMA_PRIVATE
 #include <machine/bus.h>
+#include <machine/intr.h>
 #include <newsmips/apbus/apbusvar.h>
 
 static int  apbusmatch (struct device *, struct cfdata *, void *);
@@ -71,21 +72,8 @@
 CFATTACH_DECL(ap, sizeof(struct apbus_softc),
     apbusmatch, apbusattach, NULL, NULL);
 
-#define	APBUS_DEVNAMELEN	16
-
-struct ap_intrhand {
-	struct ap_intrhand *ai_next;
-	int ai_mask;
-	int ai_priority;
-	int (*ai_func) (void*);		/* function */
-	void *ai_aux;			/* softc */
-	char ai_name[APBUS_DEVNAMELEN];
-	int ai_ctlno;
-};
-
 #define	NLEVEL	2
-
-static struct ap_intrhand *apintr[NLEVEL];
+static struct newsmips_intr apintr_tab[NLEVEL];
 
 static int
 apbusmatch(parent, cfdata, aux)
@@ -111,6 +99,8 @@
 	struct apbus_attach_args child;
 	struct apbus_dev *apdev;
 	struct apbus_ctl *apctl;
+	struct newsmips_intr *ip;
+	int i;
 
 	*(volatile u_int *)(NEWS5000_APBUS_INTST) = 0xffffffff;
 	*(volatile u_int *)(NEWS5000_APBUS_INTMSK) = 0xffffffff;
@@ -119,6 +109,11 @@
 
 	printf("\n");
 
+	for (i = 0; i < NLEVEL; i++) {
+		ip = &apintr_tab[i];
+		LIST_INIT(&ip->intr_q);
+	}
+
 	/*
 	 * get first ap-device
 	 */
@@ -202,13 +197,16 @@
 	int level;
 	int stat;
 {
-	int nintr = 0;
-	struct ap_intrhand *ai;
-
-	for (ai = apintr[level]; ai != NULL; ai = ai->ai_next) {
-		if (ai->ai_mask & stat) {
-			nintr += (*ai->ai_func)(ai->ai_aux);
-		}
+	struct newsmips_intr *ip;
+	struct newsmips_intrhand *ih;
+	int nintr;
+
+	ip = &apintr_tab[level];
+
+	nintr = 0;
+	LIST_FOREACH(ih, &ip->intr_q, ih_q) {
+		if (ih->ih_mask & stat)
+			nintr += (*ih->ih_func)(ih->ih_arg);
 	}
 	return nintr;
 }
@@ -217,45 +215,58 @@
  * register device interrupt routine
  */
 void *
-apbus_intr_establish(level, mask, priority, func, aux, name, ctlno)
+apbus_intr_establish(level, mask, priority, func, arg, name, ctlno)
 	int level;
 	int mask;
 	int priority;
 	int (*func) (void *);
-	void *aux;
+	void *arg;
 	char *name;
 	int ctlno;
 {
-	struct ap_intrhand *ai, **aip;
-	volatile unsigned int *inten0 = (volatile unsigned int *)NEWS5000_INTEN0;
-	volatile unsigned int *inten1 = (volatile unsigned int *)NEWS5000_INTEN1;
+	struct newsmips_intr *ip;
+	struct newsmips_intrhand *ih, *curih;
+	volatile u_int32_t *inten0, *inten1;
+
+	ip = &apintr_tab[level];
 
-	ai = malloc(sizeof(*ai), M_DEVBUF, M_NOWAIT);
-	if (ai == NULL)
+	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
+	if (ih == NULL)
 		panic("apbus_intr_establish: can't malloc handler info");
-	ai->ai_mask = mask;
-	ai->ai_priority = priority;
-	ai->ai_func = func;
-	ai->ai_aux = aux;
-	strncpy(ai->ai_name, name, APBUS_DEVNAMELEN-1);
-	ai->ai_ctlno = ctlno;
-
-	for (aip = &apintr[level]; *aip != NULL; aip = &(*aip)->ai_next) {
-		if ((*aip)->ai_priority < priority)
-			break;
+	ih->ih_mask = mask;
+	ih->ih_priority = priority;
+	ih->ih_func = func;
+	ih->ih_arg = arg;
+
+	if (LIST_EMPTY(&ip->intr_q)) {
+		LIST_INSERT_HEAD(&ip->intr_q, ih, ih_q);
+		goto done;
 	}
-	ai->ai_next = *aip;
-	*aip = ai;
+
+	for (curih = LIST_FIRST(&ip->intr_q);
+	    LIST_NEXT(curih, ih_q) != NULL;
+	    curih = LIST_NEXT(curih, ih_q)) {
+		if (ih->ih_priority > curih->ih_priority) {
+			LIST_INSERT_BEFORE(curih, ih, ih_q);
+			goto done;
+		}
+	}
+
+	LIST_INSERT_AFTER(curih, ih, ih_q);
+
+ done:
 	switch (level) {
 	case 0:
+		inten0 = (volatile u_int32_t *)NEWS5000_INTEN0;
 		*inten0 |= mask;
 		break;
 	case 1:
+		inten1 = (volatile u_int32_t *)NEWS5000_INTEN1;
 		*inten1 |= mask;
 		break;
 	}
 
-	return (void *)ai;
+	return (void *)ih;
 }
 
 static void
Index: apbus/zs_ap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/newsmips/apbus/zs_ap.c,v
retrieving revision 1.13
diff -u -r1.13 zs_ap.c
--- apbus/zs_ap.c	2003/04/26 18:43:19	1.13
+++ apbus/zs_ap.c	2003/04/27 04:50:34
@@ -311,6 +311,7 @@
 	if (!didintr) {
 		didintr = 1;
 
+		zsc->zsc_si = softintr_establish(IPL_SOFTSERIAL, zssoft, zsc);
 		apbus_intr_establish(1, /* interrupt level ( 0 or 1 ) */
 				     NEWS5000_INT1_SCC,
 				     0, /* priority */
Index: conf/files.newsmips
===================================================================
RCS file: /cvsroot/src/sys/arch/newsmips/conf/files.newsmips,v
retrieving revision 1.21
diff -u -r1.21 files.newsmips
--- conf/files.newsmips	2002/10/26 13:50:38	1.21
+++ conf/files.newsmips	2003/04/27 04:50:34
@@ -89,6 +89,7 @@
 
 file arch/newsmips/newsmips/autoconf.c
 file arch/newsmips/newsmips/bus.c
+file arch/newsmips/newsmips/interrupt.c
 file arch/newsmips/newsmips/machdep.c
 file arch/newsmips/newsmips/news3400.c		hb
 file arch/newsmips/newsmips/news5000.c		ap
Index: dev/hb.c
===================================================================
RCS file: /cvsroot/src/sys/arch/newsmips/dev/hb.c,v
retrieving revision 1.10
diff -u -r1.10 hb.c
--- dev/hb.c	2003/01/01 01:55:42	1.10
+++ dev/hb.c	2003/04/27 04:50:34
@@ -3,8 +3,10 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/device.h>
+#include <sys/malloc.h>
 
 #include <machine/autoconf.h>
+#include <machine/intr.h>
 
 static int	hb_match __P((struct device *, struct cfdata *, void *));
 static void	hb_attach __P((struct device *, struct device *, void *));
@@ -17,13 +19,8 @@
 
 extern struct cfdriver hb_cd;
 
-struct intrhand {
-	int (*func) __P((void *));
-	void *arg;
-};
-
-#define NHBINTR	4
-struct intrhand hb_intrhand[6][NHBINTR];
+#define NLEVEL	4
+static struct newsmips_intr hbintr_tab[NLEVEL];
 
 static int
 hb_match(parent, cf, aux)
@@ -46,8 +43,16 @@
 	void *aux;
 {
 	struct confargs *ca = aux;
+	struct newsmips_intr *ip;
+	int i;
 
 	printf("\n");
+
+	for (i = 0; i < NLEVEL; i++) {
+		ip = &hbintr_tab[i];
+		LIST_INIT(&ip->intr_q);
+	}
+
 	config_search(hb_search, self, ca);
 }
 
@@ -90,50 +95,53 @@
 }
 
 void *
-hb_intr_establish(irq, level, func, arg)
-	int irq, level;
+hb_intr_establish(level, priority, func, arg)
+	int level, priority;
 	int (*func) __P((void *));
 	void *arg;
 {
-	struct intrhand *ih = hb_intrhand[irq];
-	int i;
+	struct newsmips_intr *ip;
+	struct newsmips_intrhand *ih, *curih;
+
+	ip = &hbintr_tab[level];
 
-	for (i = NHBINTR; i > 0; i--) {
-		if (ih->func == NULL)
-			goto found;
-		ih++;
+	ih = malloc(sizeof *ih, M_DEVBUF, M_NOWAIT);
+	if (ih == NULL)
+		panic("hb_intr_establish: malloc failed");
+
+	ih->ih_func = func;
+	ih->ih_arg = arg;
+	ih->ih_priority = priority;
+	if (LIST_EMPTY(&ip->intr_q)) {
+		LIST_INSERT_HEAD(&ip->intr_q, ih, ih_q);
+		goto done;
 	}
-	panic("hb_intr_establish: no room");
 
-found:
-	ih->func = func;
-	ih->arg = arg;
-
-#ifdef HB_DEBUG
-	for (irq = 0; irq <= 2; irq++) {
-		for (i = 0; i < NHBINTR; i++) {
-			printf("%p(%p) ",
-			       hb_intrhand[irq][i].func,
-			       hb_intrhand[irq][i].arg);
+	for (curih = LIST_FIRST(&ip->intr_q);
+	    LIST_NEXT(curih, ih_q) != NULL;
+	    curih = LIST_NEXT(curih, ih_q)) {
+		if (ih->ih_priority > curih->ih_priority) {
+			LIST_INSERT_BEFORE(curih, ih, ih_q);
+			goto done;
 		}
-		printf("\n");
 	}
-#endif
 
+	LIST_INSERT_AFTER(curih, ih, ih_q);
+
+ done:
 	return ih;
 }
 
 void
-hb_intr_dispatch(irq)
-	int irq;
+hb_intr_dispatch(level)
+	int level;
 {
-	struct intrhand *ih;
-	int i;
+	struct newsmips_intr *ip;
+	struct newsmips_intrhand *ih;
+
+	ip = &hbintr_tab[level];
 
-	ih = hb_intrhand[irq];
-	for (i = NHBINTR; i > 0; i--) {
-		if (ih->func)
-			(*ih->func)(ih->arg);
-		ih++;
+	LIST_FOREACH(ih, &ip->intr_q, ih_q) {
+		(*ih->ih_func)(ih->ih_arg);
 	}
 }
Index: dev/zs.c
===================================================================
RCS file: /cvsroot/src/sys/arch/newsmips/dev/zs.c,v
retrieving revision 1.17
diff -u -r1.17 zs.c
--- dev/zs.c	2003/04/26 18:43:20	1.17
+++ dev/zs.c	2003/04/27 04:50:34
@@ -84,8 +84,6 @@
 	return UNCONF;
 }
 
-static volatile int zssoftpending;
-
 /*
  * Our ZS chips all share a common, autovectored interrupt,
  * so we have to look at all of them on each interrupt.
@@ -97,20 +95,16 @@
 	struct zsc_softc *zsc;
 	int unit, rval, softreq;
 
-	rval = softreq = 0;
+	rval = 0;
 	for (unit = 0; unit < zsc_cd.cd_ndevs; unit++) {
 		zsc = zsc_cd.cd_devs[unit];
 		if (zsc == NULL)
 			continue;
 		rval |= zsc_intr_hard(zsc);
-		softreq |= zsc->zsc_cs[0]->cs_softreq;
+		softreq =  zsc->zsc_cs[0]->cs_softreq;
 		softreq |= zsc->zsc_cs[1]->cs_softreq;
-	}
-
-	/* We are at splzs here, so no need to lock. */
-	if (softreq && (zssoftpending == 0)) {
-		zssoftpending = 1;
-		setsoftserial();
+		if (softreq)
+			softintr_schedule(zsc->zsc_si);
 	}
 
 	return rval;
@@ -125,19 +119,6 @@
 {
 	struct zsc_softc *zsc;
 	int s, unit;
-
-	/* This is not the only ISR on this IPL. */
-	if (zssoftpending == 0)
-		return;
-
-	/*
-	 * The soft intr. bit will be set by zshard only if
-	 * the variable zssoftpending is zero.  The order of
-	 * these next two statements prevents our clearing
-	 * the soft intr bit just after zshard has set it.
-	 */
-	/* clearsoftnet(); */
-	zssoftpending = 0;
 
 	/* Make sure we call the tty layer at spltty. */
 	s = spltty();
Index: dev/zs_hb.c
===================================================================
RCS file: /cvsroot/src/sys/arch/newsmips/dev/zs_hb.c,v
retrieving revision 1.11
diff -u -r1.11 zs_hb.c
--- dev/zs_hb.c	2003/04/26 18:43:20	1.11
+++ dev/zs_hb.c	2003/04/27 04:50:34
@@ -295,6 +295,7 @@
 	if (!didintr) {
 		didintr = 1;
 
+		zsc->zsc_si = softintr_establish(IPL_SOFTSERIAL, zssoft, zsc);
 		hb_intr_establish(intlevel, IPL_SERIAL, zshard_hb, NULL);
 	}
 	/* XXX; evcnt_attach() ? */
Index: include/intr.h
===================================================================
RCS file: /cvsroot/src/sys/arch/newsmips/include/intr.h,v
retrieving revision 1.11
diff -u -r1.11 intr.h
--- include/intr.h	2001/04/13 23:30:02	1.11
+++ include/intr.h	2003/04/27 04:50:35
@@ -1,7 +1,11 @@
 /*	$NetBSD: intr.h,v 1.11 2001/04/13 23:30:02 thorpej Exp $	*/
 
-/*
- * Copyright (c) 1998 Jonathan Stone.  All rights reserved.
+/*-
+ * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -13,39 +17,68 @@
  *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software
  *    must display the following acknowledgement:
- *	This product includes software developed by Jonathan Stone for
- *      the NetBSD Project.
- * 4. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
+ *	This product includes software developed by the NetBSD
+ *	Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
  *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifndef _MACHINE_INTR_H_
 #define _MACHINE_INTR_H_
 
 #define IPL_NONE	0	/* disable only this interrupt */
-#define IPL_BIO		1	/* disable block I/O interrupts */
-#define IPL_NET		2	/* disable network interrupts */
-#define IPL_TTY		3	/* disable terminal interrupts */
-#define IPL_CLOCK	4	/* disable clock interrupts */
-#define IPL_STATCLOCK	5	/* disable profiling interrupts */
-#define IPL_SERIAL	6	/* disable serial hardware interrupts */
-#define IPL_HIGH	7	/* disable all interrupts */
 
+#define IPL_SOFT	1	/* generic software interrupts (SI 0) */
+#define IPL_SOFTCLOCK	2	/* clock software interrupts (SI 0) */
+#define IPL_SOFTNET	3	/* network software interrupts (SI 1) */
+#define IPL_SOFTSERIAL	4	/* serial software interrupts (SI 1) */
+
+#define IPL_BIO		5	/* disable block I/O interrupts */
+#define IPL_NET		6	/* disable network interrupts */
+#define IPL_TTY		7	/* disable terminal interrupts */
+#define IPL_SERIAL	7	/* disable serial hardware interrupts */
+#define IPL_CLOCK	8	/* disable clock interrupts */
+#define IPL_STATCLOCK	8	/* disable profiling interrupts */
+#define IPL_HIGH	8	/* disable all interrupts */
+
+#define _IPL_NSOFT	4
+#define _IPL_N		9
+
+#define _IPL_SI0_FIRST	IPL_SOFT
+#define _IPL_SI0_LAST	IPL_SOFTCLOCK
+
+#define _IPL_SI1_FIRST	IPL_SOFTNET
+#define _IPL_SI1_LAST	IPL_SOFTSERIAL
+
+#define IPL_SOFTNAMES {							\
+	"misc",								\
+	"clock",							\
+	"net",								\
+	"serial",							\
+}
+
 #ifdef _KERNEL
 #ifndef _LOCORE
-#include <mips/cpuregs.h>
 
+#include <sys/device.h>
+#include <sys/lock.h>
+
+extern const u_int32_t ipl_sr_bits[_IPL_N];
+extern const u_int32_t ipl_si_to_sr[_IPL_NSOFT];
+
 extern int _splraise __P((int));
 extern int _spllower __P((int));
 extern int _splset __P((int));
@@ -53,82 +86,119 @@
 extern void _splnone __P((void));
 extern void _setsoftintr __P((int));
 extern void _clrsoftintr __P((int));
-
-/*
- * software simulated interrupt
- */
-#define SIR_NET		0x01
-#define SIR_SERIAL	0x02
-
-#define setsoft(x)	do {			\
-	extern u_int ssir;			\
-	int s;					\
-						\
-	s = splhigh();				\
-	ssir |= (x);				\
-	_setsoftintr(MIPS_SOFT_INT_MASK_1);	\
-	splx(s);				\
-} while (0)
-
-#define setsoftclock()	_setsoftintr(MIPS_SOFT_INT_MASK_0)
-#define setsoftnet()	setsoft(SIR_NET)
-#define setsoftserial()	setsoft(SIR_SERIAL)
 
-/*
- * nesting interrupt masks.
- */
-#define MIPS_INT_MASK_SPL_SOFT0	MIPS_SOFT_INT_MASK_0
-#define MIPS_INT_MASK_SPL_SOFT1	(MIPS_SOFT_INT_MASK_1|MIPS_INT_MASK_SPL_SOFT0)
-#define MIPS_INT_MASK_SPL0	(MIPS_INT_MASK_0|MIPS_INT_MASK_SPL_SOFT1)
-#define MIPS_INT_MASK_SPL1	(MIPS_INT_MASK_1|MIPS_INT_MASK_SPL0)
-#define MIPS_INT_MASK_SPL2	(MIPS_INT_MASK_2|MIPS_INT_MASK_SPL1)
-#define MIPS_INT_MASK_SPL3	(MIPS_INT_MASK_3|MIPS_INT_MASK_SPL2)
-#define MIPS_INT_MASK_SPL4	(MIPS_INT_MASK_4|MIPS_INT_MASK_SPL3)
-#define MIPS_INT_MASK_SPL5	(MIPS_INT_MASK_5|MIPS_INT_MASK_SPL4)
-
+#define splhigh()	_splraise(ipl_sr_bits[IPL_HIGH])
 #define spl0()		(void)_spllower(0)
 #define splx(s)		(void)_splset(s)
-#define splbio()	_splraise(MIPS_INT_MASK_SPL0)
-#define splnet()	_splraise(MIPS_INT_MASK_SPL1)
-#define spltty()	_splraise(MIPS_INT_MASK_SPL1)
-#define splvm()		_splraise(MIPS_INT_MASK_SPL1)
-#define splclock()	_splraise(MIPS_INT_MASK_SPL2)
-#define splstatclock()	_splraise(MIPS_INT_MASK_SPL2)
-#define splhigh()	_splraise(MIPS_INT_MASK_SPL2)
-#define	splsched()	splhigh()
-#define	spllock()	splhigh()
-
-#define splsoftclock()	_splraise(MIPS_INT_MASK_SPL_SOFT0)
-#define splsoftnet()	_splraise(MIPS_INT_MASK_SPL_SOFT1)
-#define spllowersoftclock() _spllower(MIPS_INT_MASK_SPL_SOFT0)
+#define splbio()	_splraise(ipl_sr_bits[IPL_BIO])
+#define splnet()	_splraise(ipl_sr_bits[IPL_NET])
+#define spltty()	_splraise(ipl_sr_bits[IPL_TTY])
+#define splserial()	_splraise(ipl_sr_bits[IPL_SERIAL])
+#define splvm()		spltty()
+#define splclock()	_splraise(ipl_sr_bits[IPL_CLOCK])
+#define splstatclock()	splclock()
+
+#define splsched()	splclock()
+#define spllock()	splhigh()
+
+#define splsoft()	_splraise(ipl_sr_bits[IPL_SOFT])
+#define splsoftclock()	_splraise(ipl_sr_bits[IPL_SOFTCLOCK])
+#define splsoftnet()	_splraise(ipl_sr_bits[IPL_SOFTNET])
+#define splsoftserial()	_splraise(ipl_sr_bits[IPL_SOFTSERIAL])
+
+#define spllowersoftclock() _spllower(ipl_sr_bits[IPL_SOFTCLOCK])
+
+struct newsmips_intrhand {
+	LIST_ENTRY(newsmips_intrhand) ih_q;
+	struct evcnt intr_count;
+	int (*ih_func)(void *);
+	void *ih_arg;
+	u_int ih_level;
+	u_int ih_mask;
+	u_int ih_priority;
+};
+
+struct newsmips_intr {
+	LIST_HEAD(,newsmips_intrhand) intr_q;
+};
+
+#define setsoft(x)							\
+do {									\
+	_setsoftintr(ipl_si_to_sr[(x) - IPL_SOFT]);			\
+} while (/*CONSTCOND*/0)
+
+struct newsmips_soft_intrhand {
+	TAILQ_ENTRY(newsmips_soft_intrhand) sih_q;
+	struct newsmips_soft_intr *sih_intrhead;
+	void (*sih_func)(void *);
+	void *sih_arg;
+	int sih_pending;
+};
+
+struct newsmips_soft_intr {
+	TAILQ_HEAD(,newsmips_soft_intrhand) softintr_q;
+	struct evcnt softintr_evcnt;
+	struct simplelock softintr_slock;
+	unsigned long softintr_ipl;
+};
+
+void *softintr_establish(int, void (*)(void *), void *);
+void softintr_disestablish(void *);
+void softintr_init(void);
+void softintr_dispatch(void);
+
+#define softintr_schedule(arg)						\
+do {									\
+	struct newsmips_soft_intrhand *__sih = (arg);			\
+	struct newsmips_soft_intr *__si = __sih->sih_intrhead;		\
+	int __s;							\
+									\
+	__s = splhigh();						\
+	simple_lock(&__si->softintr_slock);				\
+	if (__sih->sih_pending == 0) {					\
+		TAILQ_INSERT_TAIL(&__si->softintr_q, __sih, sih_q);	\
+		__sih->sih_pending = 1;					\
+		setsoft(__si->softintr_ipl);				\
+	}								\
+	simple_unlock(&__si->softintr_slock);				\
+	splx(__s);							\
+} while (/*CONSTCOND*/0)
+
+/* XXX For legacy software interrupts. */
+extern struct newsmips_soft_intrhand *softnet_intrhand;
+
+#define setsoftnet()	softintr_schedule(softnet_intrhand)
 
 /*
  * Index into intrcnt[], which is defined in locore
  */
-#define SOFTCLOCK_INTR	0
-#define SOFTNET_INTR	1
-#define SERIAL0_INTR	2
-#define SERIAL1_INTR	3
-#define SERIAL2_INTR	4
-#define LANCE_INTR	5
-#define SCSI_INTR	6
-#define ERROR_INTR	7
-#define HARDCLOCK_INTR	8
-#define FPU_INTR	9
-#define SLOT1_INTR	10
-#define SLOT2_INTR	11
-#define SLOT3_INTR	12
-#define FLOPPY_INTR	13
-#define STRAY_INTR	14
+#define SERIAL0_INTR	0
+#define SERIAL1_INTR	1
+#define SERIAL2_INTR	2
+#define LANCE_INTR	3
+#define SCSI_INTR	4
+#define ERROR_INTR	5
+#define HARDCLOCK_INTR	6
+#define FPU_INTR	7
+#define SLOT1_INTR	8
+#define SLOT2_INTR	9
+#define SLOT3_INTR	10
+#define FLOPPY_INTR	11
+#define STRAY_INTR	12
 
 extern u_int intrcnt[];
 
 /* handle i/o device interrupts */
-extern void news3400_intr __P((u_int, u_int, u_int, u_int));
-extern void news5000_intr __P((u_int, u_int, u_int, u_int));
+#ifdef news3400
+void news3400_intr __P((u_int, u_int, u_int, u_int));
+#endif
+#ifdef news5000
+void news5000_intr __P((u_int, u_int, u_int, u_int));
+#endif
+void (*hardware_intr) __P((u_int, u_int, u_int, u_int));
 
-extern void (*enable_intr) __P((void));
-extern void (*disable_intr) __P((void));
+void (*enable_intr) __P((void));
+void (*disable_intr) __P((void));
 
 #endif /* !_LOCORE */
 #endif /* _KERNEL */
Index: include/types.h
===================================================================
RCS file: /cvsroot/src/sys/arch/newsmips/include/types.h,v
retrieving revision 1.5
diff -u -r1.5 types.h
--- include/types.h	2002/08/05 02:13:15	1.5
+++ include/types.h	2003/04/27 04:50:35
@@ -3,6 +3,7 @@
 #include <mips/types.h>
 
 #define	__BROKEN_CONFIG_UNIT_USAGE
+#define	__HAVE_GENERIC_SOFT_INTERRUPTS
 
 /* MIPS specific options */
 #define	__HAVE_BOOTINFO_H
Index: include/z8530var.h
===================================================================
RCS file: /cvsroot/src/sys/arch/newsmips/include/z8530var.h,v
retrieving revision 1.4
diff -u -r1.4 z8530var.h
--- include/z8530var.h	2003/04/26 18:43:20	1.4
+++ include/z8530var.h	2003/04/27 04:50:35
@@ -52,6 +52,7 @@
 	struct	zs_chanstate *zsc_cs[2];	/* channel A and B soft state */
 	/* Machine-dependent part follows... */
 	struct zs_chanstate  zsc_cs_store[2];
+	void *zsc_si;			/* softinterrupt handle */
 };
 
 /*
@@ -77,5 +78,4 @@
 void (*zs_delay) __P((void));
 
 /* Zilog Serial hardware interrupts (level 1) */
-#define splzs		cpu_spl1
-extern int splzs(void);
+#define splzs	spltty
Index: newsmips/autoconf.c
===================================================================
RCS file: /cvsroot/src/sys/arch/newsmips/newsmips/autoconf.c,v
retrieving revision 1.16
diff -u -r1.16 autoconf.c
--- newsmips/autoconf.c	2002/09/25 22:21:15	1.16
+++ newsmips/autoconf.c	2003/04/27 04:50:36
@@ -98,6 +98,7 @@
 	/*
 	 * Kick off autoconfiguration
 	 */
+	softintr_init();
 	_splnone();	/* enable all interrupts */
 	splhigh();	/* ...then disable device interrupts */
 
Index: newsmips/locore_machdep.S
===================================================================
RCS file: /cvsroot/src/sys/arch/newsmips/newsmips/locore_machdep.S,v
retrieving revision 1.9
diff -u -r1.9 locore_machdep.S
--- newsmips/locore_machdep.S	2003/04/26 18:40:00	1.9
+++ newsmips/locore_machdep.S	2003/04/27 04:50:36
@@ -226,8 +226,6 @@
 	.globl _C_LABEL(intrnames)
 	.globl _C_LABEL(eintrnames)
 _C_LABEL(intrnames):
-	.asciiz	"softclock"
-	.asciiz	"softnet"
 	.asciiz	"serial0"
 	.asciiz	"serial1"
 	.asciiz	"serial2"
@@ -246,7 +244,7 @@
 _C_LABEL(eintrnames):
 	.align	2
 _C_LABEL(intrcnt):
-	.word	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0
+	.word	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0
 _C_LABEL(eintrcnt):
 	.word	0	# This shouldn't be needed but with 4.4bsd's as, the eintrcnt
 			#  label ends end up in a different section otherwise.
Index: newsmips/machdep.c
===================================================================
RCS file: /cvsroot/src/sys/arch/newsmips/newsmips/machdep.c,v
retrieving revision 1.69
diff -u -r1.69 machdep.c
--- newsmips/machdep.c	2003/04/26 18:50:19	1.69
+++ newsmips/machdep.c	2003/04/27 04:50:36
@@ -129,13 +129,8 @@
 int mem_cluster_cnt;
 
 struct idrom idrom;
-void (*enable_intr) __P((void));
-void (*disable_intr) __P((void));
 void (*readmicrotime) __P((struct timeval *tvp));
 
-static void (*hardware_intr) __P((u_int, u_int, u_int, u_int));
-u_int ssir;
-
 /*
  *  Local functions.
  */
@@ -649,52 +644,4 @@
 	int n;
 {
 	DELAY(n);
-}
-
-#include "zsc.h"
-
-int zssoft __P((void));
-
-void
-cpu_intr(status, cause, pc, ipending)
-	u_int32_t status;
-	u_int32_t cause;
-	u_int32_t pc;
-	u_int32_t ipending;
-{
-	uvmexp.intrs++;
-
-	/* device interrupts */
-	(*hardware_intr)(status, cause, pc, ipending);
-
-	/* software simulated interrupt */
-	if ((ipending & MIPS_SOFT_INT_MASK_1) ||
-	    (ssir && (status & MIPS_SOFT_INT_MASK_1))) {
-
-#define DO_SIR(bit, fn)						\
-	do {							\
-		if (n & (bit)) {				\
-			uvmexp.softs++;				\
-			fn;					\
-		}						\
-	} while (0)
-
-		unsigned n;
-		n = ssir; ssir = 0;
-		_clrsoftintr(MIPS_SOFT_INT_MASK_1);
-
-#if NZSC > 0
-		DO_SIR(SIR_SERIAL, zssoft());
-#endif
-		DO_SIR(SIR_NET, netintr());
-#undef DO_SIR
-	}
-
-	/* 'softclock' interrupt */
-	if (ipending & MIPS_SOFT_INT_MASK_0) {
-		_clrsoftintr(MIPS_SOFT_INT_MASK_0);
-		uvmexp.softs++;
-		intrcnt[SOFTCLOCK_INTR]++;
-		softclock(NULL);
-	}
 }
--- /dev/null	2003-04-27 13:38:34.000000000 +0900
+++ newsmips/interrupt.c	2003-04-27 13:17:36.000000000 +0900
@@ -0,0 +1,225 @@
+/*	$NetBSD$	*/
+
+/*
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <net/netisr.h>			/* Legacy softnet support */
+
+#include <machine/intr.h>
+
+/* XXX For legacy software interrupts. */
+struct newsmips_soft_intrhand *softnet_intrhand;
+
+/*
+ * This is a mask of bits to clear in the SR when we go to a
+ * given interrupt priority level.
+ */
+const u_int32_t ipl_sr_bits[_IPL_N] = {
+	0,					/* IPL_NONE */
+
+	MIPS_SOFT_INT_MASK_0,			/* IPL_SOFT */
+
+	MIPS_SOFT_INT_MASK_0,			/* IPL_SOFTCLOCK */
+
+	MIPS_SOFT_INT_MASK_0|
+		MIPS_SOFT_INT_MASK_1,		/* IPL_SOFTNET */
+
+	MIPS_SOFT_INT_MASK_0|
+		MIPS_SOFT_INT_MASK_1,		/* IPL_SOFTSERIAL */
+
+	MIPS_SOFT_INT_MASK_0|
+		MIPS_SOFT_INT_MASK_1|
+		MIPS_INT_MASK_0,		/* IPL_BIO */
+
+	MIPS_SOFT_INT_MASK_0|
+		MIPS_SOFT_INT_MASK_1|
+		MIPS_INT_MASK_0|
+		MIPS_INT_MASK_1,		/* IPL_NET */
+
+	MIPS_SOFT_INT_MASK_0|
+		MIPS_SOFT_INT_MASK_1|
+		MIPS_INT_MASK_0|
+		MIPS_INT_MASK_1,		/* IPL_{TTY,SERIAL} */
+
+	MIPS_SOFT_INT_MASK_0|
+		MIPS_SOFT_INT_MASK_1|
+		MIPS_INT_MASK_0|
+		MIPS_INT_MASK_1|
+		MIPS_INT_MASK_2,		/* IPL_{CLOCK,HIGH} */
+};
+
+const u_int32_t ipl_si_to_sr[_IPL_NSOFT] = {
+	MIPS_SOFT_INT_MASK_0,			/* IPL_SOFT */
+	MIPS_SOFT_INT_MASK_0,			/* IPL_SOFTCLOCK */
+	MIPS_SOFT_INT_MASK_1,			/* IPL_SOFTNET */
+	MIPS_SOFT_INT_MASK_1,			/* IPL_SOFTSERIAL */
+};
+
+struct newsmips_soft_intr newsmips_soft_intrs[_IPL_NSOFT];
+
+void
+cpu_intr(status, cause, pc, ipending)
+	u_int32_t status;
+	u_int32_t cause;
+	u_int32_t pc;
+	u_int32_t ipending;
+{
+	struct newsmips_soft_intr *nsi;
+	struct newsmips_soft_intrhand *sih;
+	int i, s;
+
+	uvmexp.intrs++;
+
+	/* device interrupts */
+	(*hardware_intr)(status, cause, pc, ipending);
+
+	/* software interrupts */
+	ipending &= (MIPS_SOFT_INT_MASK_1|MIPS_SOFT_INT_MASK_0);
+	if (ipending == 0)
+		return;
+
+	_clrsoftintr(ipending);
+
+	for (i = _IPL_NSOFT - 1; i >= 0; i--) {
+		if ((ipending & ipl_si_to_sr[i]) == 0)
+			continue;
+
+		nsi = &newsmips_soft_intrs[i];
+
+		if (TAILQ_FIRST(&nsi->softintr_q) != NULL)
+			nsi->softintr_evcnt.ev_count++;
+
+		for (;;) {
+			s = splhigh();
+
+			sih = TAILQ_FIRST(&nsi->softintr_q);
+			if (sih != NULL) {
+				TAILQ_REMOVE(&nsi->softintr_q, sih, sih_q);
+				sih->sih_pending = 0;
+			}
+
+			splx(s);
+
+			if (sih == NULL)
+				break;
+
+			uvmexp.softs++;
+			(*sih->sih_func)(sih->sih_arg);
+		}
+	}
+}
+
+/*
+ * softintr_init:
+ *
+ *	Initialize the software interrupt system.
+ */
+void
+softintr_init(void)
+{
+	static const char *softintr_names[] = IPL_SOFTNAMES;
+	struct newsmips_soft_intr *nsi;
+	int i;
+
+	for (i = 0; i < _IPL_NSOFT; i++) {
+		nsi = &newsmips_soft_intrs[i];
+		TAILQ_INIT(&nsi->softintr_q);
+		nsi->softintr_ipl = IPL_SOFT + i;
+		evcnt_attach_dynamic(&nsi->softintr_evcnt, EVCNT_TYPE_INTR,
+		    NULL, "soft", softintr_names[i]);
+	}
+
+	/* XXX Establish legacy soft interrupt handlers. */
+	softnet_intrhand = softintr_establish(IPL_SOFTNET,
+	    (void (*)(void *))netintr, NULL);
+
+	KASSERT(softnet_intrhand != NULL);
+}
+
+/*
+ * softintr_establish:		[interface]
+ *
+ *	Register a software interrupt handler.
+ */
+void *
+softintr_establish(int ipl, void (*func)(void *), void *arg)
+{
+	struct newsmips_soft_intr *nsi;
+	struct newsmips_soft_intrhand *sih;
+
+	if (__predict_false(ipl >= (IPL_SOFT + _IPL_NSOFT) ||
+			    ipl < IPL_SOFT))
+		panic("softintr_establish");
+
+	nsi = &newsmips_soft_intrs[ipl - IPL_SOFT];
+
+	sih = malloc(sizeof(*sih), M_DEVBUF, M_NOWAIT);
+	if (__predict_true(sih != NULL)) {
+		sih->sih_intrhead = nsi;
+		sih->sih_func = func;
+		sih->sih_arg = arg;
+		sih->sih_pending = 0;
+	}
+	return sih;
+}
+
+/*
+ * softintr_disestablish:	[interface]
+ *
+ *	Unregister a software interrupt handler.
+ */
+void
+softintr_disestablish(void *arg)
+{
+	struct newsmips_soft_intrhand *sih = arg;
+	struct newsmips_soft_intr *nsi = sih->sih_intrhead;
+	int s;
+
+	s = splhigh();
+	if (sih->sih_pending) {
+		TAILQ_REMOVE(&nsi->softintr_q, sih, sih_q);
+		sih->sih_pending = 0;
+	}
+	splx(s);
+
+	free(sih, M_DEVBUF);
+}