Subject: test kernel for cobalt
To: None <port-cobalt@NetBSD.org>
From: Izumi Tsutsui <tsutsui@ceres.dti.ne.jp>
List: port-cobalt
Date: 05/13/2006 15:18:14
I've uploaded a test kernel which includes some random patches
in my local tree:
http://www.ceres.dti.ne.jp/~tsutsui/netbsd/netbsd-COBALT_TEST-20060510.gz

It contains the following changes:
- prepare a sparate statclock() handler which uses the CPU internal counter
  (similar changes I posted before)
- as a sideeffect of the above, fix overblocking after spllowersoftclock(9)
  in hardclock(9) (see src/sys/arch/arc/TODO)
- initialize icu (i8259 PIC) more properly, check requrested irq
  in icu_intr(), and use explicit manual EOI to ack interrupts rather
  than AEOI, which is not used by any other ports
- (move interrupt stuff into separate interrupt.c from machdep.c and pcib.c)
- initialize GT64x11 PCI timeout retry register as Linux/MIPS source does
- set cacheline and latency timer registers on GT64x11 and viaide
- use CPU INT 2 rather than INT 1 for the primary (and only?) tulip
  on QUBE2700 and RAQ1, as Linux/MIPS does
- misc cosmetics

I'm not sure if these changes could fix any problem reported before,
but if you find any better (or worse) behaviors with this kernel
than -current stock kernel (you can get binary from
ftp://ftp.NetBSD.org/NetBSD-daily/HEAD/), please let me know
with your kernel console logs.
---
Izumi Tsutsui


Index: cobalt/autoconf.c
===================================================================
RCS file: /cvsroot/src/sys/arch/cobalt/cobalt/autoconf.c,v
retrieving revision 1.19
diff -u -r1.19 autoconf.c
--- cobalt/autoconf.c	21 Apr 2006 18:17:45 -0000	1.19
+++ cobalt/autoconf.c	13 May 2006 05:47:51 -0000
@@ -35,6 +35,7 @@
 #include <sys/device.h>
 
 #include <machine/cpu.h>
+#include <machine/intr.h>
 
 #include <cobalt/cobalt/clockvar.h>
 
@@ -52,11 +53,14 @@
 	(void)splhigh();
 
 	evcnt_attach_static(&hardclock_ev);
+	evcnt_attach_static(&statclock_ev);
+	icu_init();
 
 	if (config_rootfound("mainbus", NULL) == NULL)
 		panic("no mainbus found");
 
-	_splnone();
+	/* turn on interrupts except cpu clock */
+	_spllower(MIPS_INT_MASK_5);
 }
 
 void
Index: cobalt/clock.c
===================================================================
RCS file: /cvsroot/src/sys/arch/cobalt/cobalt/clock.c,v
retrieving revision 1.12
diff -u -r1.12 clock.c
--- cobalt/clock.c	21 Apr 2006 16:52:15 -0000	1.12
+++ cobalt/clock.c	13 May 2006 05:47:51 -0000
@@ -47,6 +47,20 @@
 void *timer_cookie;
 
 /*
+ * Statistics clock variance, in usec.  Variance must be a
+ * power of two.  Since this gives us an even number, not an odd number,
+ * we discard one case and compensate.  That is, a variance of 1024 would
+ * give us offsets in [0..1023].  Instead, we take offsets in [1..1023].
+ * This is symmetric about the point 512, or statvar/2, and thus averages
+ * to that value (assuming uniform random numbers).
+ */
+static const uint32_t statvar = 1024;
+static uint32_t statint;	/* number of clock ticks for stathz */
+static uint32_t statmin;	/* minimum stat clock count in ticks */
+static uint32_t statprev;/* last value of we set statclock to */
+static u_int statcountperusec;	/* number of ticks per usec at current stathz */
+
+/*
  * Common parts of todclock autoconfiguration.
  */
 void
@@ -63,12 +77,21 @@
 cpu_initclocks(void)
 {
 
-	/* start timer */
+	if (stathz == 0)
+		stathz = hz;
+
+	if (profhz == 0)
+		profhz = hz * 5;
+
+	setstatclockrate(stathz);
+
+	/* start timer interrups for hardclock */
 	if (timer_start == NULL)
 		panic("cpu_initclocks(): no timer configured");
 	(*timer_start)(timer_cookie);
 
-	return;
+	/* enable statclock intr (CPU INT5) */
+	_splnone();
 }
 
 /*
@@ -139,11 +162,59 @@
 }
 
 void
-setstatclockrate(int arg)
+setstatclockrate(int newhz)
 {
-	/* XXX */
+	uint32_t countpersecond, statvarticks;
+
+	statprev = mips3_cp0_count_read();
+
+	statint = ((curcpu()->ci_cpu_freq + newhz / 2) / newhz) / 2;
+
+	/* Get the total ticks a second */
+	countpersecond = statint * newhz;
+
+	/* now work out how many ticks per usec */
+	statcountperusec = countpersecond / 1000000;
+
+	/* calculate a variance range of statvar */
+	statvarticks = statcountperusec * statvar;
+
+	/* minimum is statint - 50% of variant */
+	statmin = statint - (statvarticks / 2);
+
+	mips3_cp0_compare_write(statprev + statint);
+}
+
+void
+statclockintr(struct clockframe *cfp)
+{
+	uint32_t curcount, statnext, delta, r;
+	int lost;
+
+	lost = 0;
+
+	do {
+		r = (uint32_t)random() & (statvar - 1);
+	} while (r == 0);
+	statnext = statprev + statmin + (r * statcountperusec);
+
+	mips3_cp0_compare_write(statnext);
+	curcount = mips3_cp0_count_read();
+	delta = statnext - curcount;
+
+	while ((int32_t)delta < 0) {
+		lost++;
+		delta += statint;
+	}
+	if (lost > 0) {
+		statnext = curcount + delta;
+		mips3_cp0_compare_write(statnext);
+		for (; lost > 0; lost--)
+			statclock(cfp);
+	}
+	statclock(cfp);
 
-	return;
+	statprev = statnext;
 }
 
 void
Index: cobalt/clockvar.h
===================================================================
RCS file: /cvsroot/src/sys/arch/cobalt/cobalt/clockvar.h,v
retrieving revision 1.3
diff -u -r1.3 clockvar.h
--- cobalt/clockvar.h	21 Apr 2006 18:17:45 -0000	1.3
+++ cobalt/clockvar.h	13 May 2006 05:47:51 -0000
@@ -25,7 +25,10 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+void statclockintr(struct clockframe *);
+
 extern struct evcnt hardclock_ev;
+extern struct evcnt statclock_ev;
 
 extern void (*timer_start)(void *);
 extern long (*timer_read)(void *);
Index: cobalt/machdep.c
===================================================================
RCS file: /cvsroot/src/sys/arch/cobalt/cobalt/machdep.c,v
retrieving revision 1.66
diff -u -r1.66 machdep.c
--- cobalt/machdep.c	21 Apr 2006 18:21:30 -0000	1.66
+++ cobalt/machdep.c	13 May 2006 05:47:51 -0000
@@ -36,43 +36,23 @@
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/proc.h>
-#include <sys/buf.h>
 #include <sys/reboot.h>
-#include <sys/conf.h>
-#include <sys/file.h>
-#include <sys/malloc.h>
-#include <sys/mbuf.h>
-#include <sys/msgbuf.h>
-#include <sys/device.h>
 #include <sys/user.h>
-#include <sys/exec.h>
-#include <uvm/uvm_extern.h>
-#include <sys/sysctl.h>
 #include <sys/mount.h>
-#include <sys/sa.h>
-#include <sys/syscallargs.h>
 #include <sys/kcore.h>
 #include <sys/boot_flag.h>
 #include <sys/ksyms.h>
 
-#include <machine/cpu.h>
-#include <machine/reg.h>
-#include <machine/psl.h>
-#include <machine/pte.h>
-#include <machine/autoconf.h>
-#include <machine/bootinfo.h>
-#include <machine/intr.h>
-#include <mips/locore.h>
+#include <uvm/uvm_extern.h>
 
+#include <machine/bootinfo.h>
+#include <machine/psl.h>
 #include <machine/nvram.h>
 #include <machine/leds.h>
 
 #include <dev/cons.h>
 
-#include <cobalt/cobalt/clockvar.h>
-
 #include <cobalt/dev/gtreg.h>
-#define GT_BASE		0x14000000	/* XXX */
 
 #ifdef KGDB
 #include <sys/kgdb.h>
@@ -108,8 +88,6 @@
 
 int cpuspeed;
 
-struct evcnt hardclock_ev =
-    EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, "cpu", "hardclock");
 
 u_int cobalt_id;
 static const char * const cobalt_model[] =
@@ -400,150 +378,6 @@
 		;
 }
 
-#define NINTR	6
-
-static struct cobalt_intrhand intrtab[NINTR];
-
-const uint32_t mips_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 */
-};
-
-void *
-cpu_intr_establish(int level, int ipl, int (*func)(void *), void *arg)
-{
-	struct cobalt_intrhand *ih;
-
-	if (level < 0 || level >= NINTR)
-		panic("invalid interrupt level");
-
-	ih = &intrtab[level];
-
-	if (ih->ih_func != NULL)
-		panic("cannot share CPU interrupts");
-
-	ih->ih_cookie_type = COBALT_COOKIE_TYPE_CPU;
-	ih->ih_func = func;
-	ih->ih_arg = arg;
-	snprintf(ih->ih_evname, sizeof(ih->ih_evname), "level %d", level);
-	evcnt_attach_dynamic(&ih->ih_evcnt, EVCNT_TYPE_INTR, NULL,
-	    "cpu", ih->ih_evname);
-
-	return ih;
-}
-
-void
-cpu_intr_disestablish(void *cookie)
-{
-	struct cobalt_intrhand *ih = cookie;
-
-	if (ih->ih_cookie_type == COBALT_COOKIE_TYPE_CPU) {
-		ih->ih_func = NULL;
-		ih->ih_arg = NULL;
-		ih->ih_cookie_type = 0;
-		evcnt_detach(&ih->ih_evcnt);
-	}
-}
-
-void
-cpu_intr(uint32_t status, uint32_t cause, uint32_t pc, uint32_t ipending)
-{
-	struct clockframe cf;
-	static uint32_t cycles;
-	struct cobalt_intrhand *ih;
-
-	uvmexp.intrs++;
-
-	if (ipending & MIPS_INT_MASK_0) {
-		/* GT64x11 timer0 for hardclock */
-		volatile uint32_t *irq_src =
-		    (uint32_t *)MIPS_PHYS_TO_KSEG1(GT_BASE + GT_INTR_CAUSE);
-
-		if ((*irq_src & T0EXP) != 0) {
-			*irq_src = 0;
-
-			cf.pc = pc;
-			cf.sr = status;
-
-			hardclock(&cf);
-			hardclock_ev.ev_count++;
-		}
-		cause &= ~MIPS_INT_MASK_0;
-	}
-	_splset((status & ~cause & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE);
-
-	if (ipending & MIPS_INT_MASK_5) {
-		cycles = mips3_cp0_count_read();
-		mips3_cp0_compare_write(cycles + 1250000);	/* XXX */
-
-#if 0
-		cf.pc = pc;
-		cf.sr = status;
-
-		statclock(&cf);
-#endif
-		cause &= ~MIPS_INT_MASK_5;
-	}
-	_splset((status & ~cause & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE);
-
-	if (ipending & MIPS_INT_MASK_3) {
-		/* 16650 serial */
-		ih = &intrtab[3];
-		if (ih->ih_func != NULL) {
-			if ((*ih->ih_func)(ih->ih_arg)) {
-				cause &= ~MIPS_INT_MASK_3;
-				ih->ih_evcnt.ev_count++;
-			}
-		}
-	}
-	_splset((status & ~cause & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE);
-
-	if (ipending & MIPS_INT_MASK_1) {
-		/* tulip primary */
-		ih = &intrtab[1];
-		if (ih->ih_func != NULL) {
-			if ((*ih->ih_func)(ih->ih_arg)) {
-				cause &= ~MIPS_INT_MASK_1;
-				ih->ih_evcnt.ev_count++;
-			}
-		}
-	}
-	if (ipending & MIPS_INT_MASK_2) {
-		/* tulip secondary */
-		ih = &intrtab[2];
-		if (ih->ih_func != NULL) {
-			if ((*ih->ih_func)(ih->ih_arg)) {
-				cause &= ~MIPS_INT_MASK_2;
-				ih->ih_evcnt.ev_count++;
-			}
-		}
-	}
-	_splset((status & ~cause & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE);
-
-	if (ipending & MIPS_INT_MASK_4) {
-		/* ICU interrupts */
-		ih = &intrtab[4];
-		if (ih->ih_func != NULL) {
-			if ((*ih->ih_func)(ih->ih_arg)) {
-				cause &= ~MIPS_INT_MASK_4;
-				/* evcnt for ICU is done in icu_intr() */
-			}
-		}
-	}
-	_splset((status & ~cause & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE);
-
-	/* software interrupt */
-	ipending &= (MIPS_SOFT_INT_MASK_1|MIPS_SOFT_INT_MASK_0);
-	if (ipending == 0)
-		return;
-
-	_clrsoftintr(ipending);
-
-	softintr_dispatch(ipending);
-}
-
 
 void
 decode_bootstring(void)
@@ -663,6 +497,7 @@
 	volatile uint32_t *pcicfg_addr, *pcicfg_data;
 	uint32_t reg;
 
+#define GT_BASE			0x14000000	/* XXX */
 #define PCIB_PCI_BUS		0
 #define PCIB_PCI_DEV		9
 #define PCIB_PCI_FUNC		0
Index: conf/files.cobalt
===================================================================
RCS file: /cvsroot/src/sys/arch/cobalt/conf/files.cobalt,v
retrieving revision 1.25
diff -u -r1.25 files.cobalt
--- conf/files.cobalt	15 Apr 2006 13:33:05 -0000	1.25
+++ conf/files.cobalt	13 May 2006 05:47:51 -0000
@@ -38,6 +38,7 @@
 file arch/cobalt/cobalt/console.c
 file arch/cobalt/cobalt/disksubr.c
 file arch/cobalt/cobalt/machdep.c
+file arch/cobalt/cobalt/interrupt.c
 
 file arch/mips/mips/softintr.c
 
Index: conf/std.cobalt
===================================================================
RCS file: /cvsroot/src/sys/arch/cobalt/conf/std.cobalt,v
retrieving revision 1.12
diff -u -r1.12 std.cobalt
--- conf/std.cobalt	11 Dec 2005 12:17:06 -0000	1.12
+++ conf/std.cobalt	13 May 2006 05:47:51 -0000
@@ -5,6 +5,7 @@
 makeoptions	MACHINE_ARCH="mipsel"
 
 options 	MIPS3
+options 	MIPS3_ENABLE_CLOCK_INTR
 
 options 	EXEC_ELF32	# exec ELF32 binaries
 options 	EXEC_SCRIPT	# exec #! scripts
Index: dev/gt.c
===================================================================
RCS file: /cvsroot/src/sys/arch/cobalt/dev/gt.c,v
retrieving revision 1.17
diff -u -r1.17 gt.c
--- dev/gt.c	21 Apr 2006 19:04:57 -0000	1.17
+++ dev/gt.c	13 May 2006 05:47:51 -0000
@@ -98,6 +98,8 @@
 #if NPCI > 0
 	pci_chipset_tag_t pc;
 	struct pcibus_attach_args pba;
+	pcitag_t tag;
+	pcireg_t misc;
 #endif
 
 	sc->sc_bst = ma->ma_iot;
@@ -115,6 +117,14 @@
 	    (bus_space_read_4(sc->sc_bst, sc->sc_bsh, GT_PCI_COMMAND) &
 	    ~PCI_SYNCMODE) | PCI_PCLK_HIGH);
 
+	printf("GT_PCI_TIMEOUT_RETRY=0x%08x\n",
+	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, GT_PCI_TIMEOUT_RETRY));
+	bus_space_write_4(sc->sc_bst, sc->sc_bsh, GT_PCI_TIMEOUT_RETRY,
+	    0xff << PCI_RETRYCTR_SHIFT | 0xff << PCI_TIMEOUT1_SHIFT | 0xff);
+	printf("GT_PCI_TIMEOUT_RETRY=0x%08x\n",
+	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, GT_PCI_TIMEOUT_RETRY));
+	    
+
 #if NPCI > 0
 	pc = &sc->sc_pc;
 	pc->pc_bst = sc->sc_bst;
@@ -128,6 +138,27 @@
 	pci_configure_bus(pc, pc->pc_ioext, pc->pc_memext, NULL, 0,
 	    mips_dcache_align);
 #endif
+
+	/* fix up gt XXX is this needed? */
+	tag = pci_make_tag(pc, 0, 0, 0);
+	misc = pci_conf_read(pc, tag, PCI_BHLC_REG);
+	misc &= ~((PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT) |
+	    (PCI_CACHELINE_MASK << PCI_CACHELINE_SHIFT));
+	misc |= ((0x40 & PCI_LATTIMER_MASK) << PCI_LATTIMER_SHIFT) |
+	    (((mips_dcache_align >> 2) & PCI_CACHELINE_MASK)
+	    << PCI_CACHELINE_SHIFT);
+	pci_conf_write(pc, tag, PCI_BHLC_REG, misc);
+
+	/* fix up viaide XXX is this needed? */
+	tag = pci_make_tag(pc, 0, 9, 1);
+	misc = pci_conf_read(pc, tag, PCI_BHLC_REG);
+	misc &= ~((PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT) |
+	    (PCI_CACHELINE_MASK << PCI_CACHELINE_SHIFT));
+	misc |= ((0x40 & PCI_LATTIMER_MASK) << PCI_LATTIMER_SHIFT) |
+	    (((mips_dcache_align >> 2) & PCI_CACHELINE_MASK)
+	    << PCI_CACHELINE_SHIFT);
+	pci_conf_write(pc, tag, PCI_BHLC_REG, misc);
+
 	pba.pba_dmat = &pci_bus_dma_tag;
 	pba.pba_dmat64 = NULL;
 	pba.pba_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED;
Index: dev/gtreg.h
===================================================================
RCS file: /cvsroot/src/sys/arch/cobalt/dev/gtreg.h,v
retrieving revision 1.3
diff -u -r1.3 gtreg.h
--- dev/gtreg.h	9 Apr 2006 01:24:05 -0000	1.3
+++ dev/gtreg.h	13 May 2006 05:47:51 -0000
@@ -46,6 +46,13 @@
 #define  PCI_PCLK_HIGH		0x00000002
 #define  PCI_PCLK_SYNC		0x00000004
 
+#define GT_PCI_TIMEOUT_RETRY	0xc04
+#define  PCI_TIMEOUT0		0x000000ff
+#define  PCI_TIMEOUT1		0x0000ff00
+#define  PCI_TIMEOUT1_SHIFT	8
+#define  PCI_RETRYCTR		0x00ff0000
+#define  PCI_RETRYCTR_SHIFT	16
+
 #define GT_INTR_CAUSE		0xc18
 #define  INTSUM			0x00000001
 #define  MEMOUT			0x00000002
Index: include/intr.h
===================================================================
RCS file: /cvsroot/src/sys/arch/cobalt/include/intr.h,v
retrieving revision 1.20
diff -u -r1.20 intr.h
--- include/intr.h	21 Apr 2006 18:17:45 -0000	1.20
+++ include/intr.h	13 May 2006 05:47:51 -0000
@@ -80,7 +80,8 @@
 #define SPLBIO		(SPLSOFT | MIPS_INT_MASK_4)
 #define SPLNET		(SPLBIO | MIPS_INT_MASK_1 | MIPS_INT_MASK_2)
 #define SPLTTY		(SPLNET | MIPS_INT_MASK_3)
-#define SPLCLOCK	(SPLTTY | MIPS_INT_MASK_0 | MIPS_INT_MASK_5)
+#define SPLCLOCK	(SPLTTY | MIPS_INT_MASK_0)
+#define SPLSTATCLOCK	(SPLCLOCK | MIPS_INT_MASK_5)
 #define splbio()	_splraise(SPLBIO)
 #define splnet()	_splraise(SPLNET)
 #define spltty()	_splraise(SPLTTY)
@@ -88,7 +89,7 @@
 #define splserial()	_splraise(SPLTTY)
 #define splclock()	_splraise(SPLCLOCK)
 #define splvm()		splclock()
-#define splstatclock()	splclock()
+#define splstatclock()	_splraise(SPLSTATCLOCK)
 #define spllowersoftclock() _spllower(MIPS_SOFT_INT_MASK_0)
 
 #define	splsched()	splhigh()
@@ -117,6 +118,9 @@
 void *icu_intr_establish(int, int, int, int (*)(void *), void *);
 void cpu_intr_disestablish(void *);
 void icu_intr_disestablish(void *);
+void icu_init(void);
+
+#define	CPU_INTRLINE_OFFSET	16
 
 #endif /* !_LOCORE */
 #endif /* _LOCORE */
Index: pci/pci_machdep.c
===================================================================
RCS file: /cvsroot/src/sys/arch/cobalt/pci/pci_machdep.c,v
retrieving revision 1.22
diff -u -r1.22 pci_machdep.c
--- pci/pci_machdep.c	18 Apr 2006 12:26:45 -0000	1.22
+++ pci/pci_machdep.c	13 May 2006 05:47:52 -0000
@@ -155,12 +155,33 @@
 	 * directly to the CPU.
 	 */
 
-	if (bus == 0 && dev == 7 && pin == PCI_INTERRUPT_PIN_A)
-		*ihp = 16 + 1;
-	else if (bus == 0 && dev == 12 && pin == PCI_INTERRUPT_PIN_A)
-		*ihp = 16 + 2;
-	else
-		*ihp = line;
+	if (bus == 0 && dev == 7 && pin == PCI_INTERRUPT_PIN_A) {
+		switch (cobalt_id) {
+		case COBALT_ID_QUBE2700:
+		case COBALT_ID_RAQ:
+			*ihp = CPU_INTRLINE_OFFSET + 2;
+			return 0;
+		case COBALT_ID_QUBE2:
+		case COBALT_ID_RAQ2:
+			*ihp = CPU_INTRLINE_OFFSET + 1;
+			return 0;
+		default:
+			break;
+		}
+	}
+	if (bus == 0 && dev == 12 && pin == PCI_INTERRUPT_PIN_A) {
+		switch (cobalt_id) {
+		case COBALT_ID_QUBE2:
+		case COBALT_ID_RAQ2:
+			*ihp = CPU_INTRLINE_OFFSET + 2;
+			return 0;
+		default:
+			break;
+		}
+	}
+
+	/* XXX how should we handle a multi-function card on the PCI slot? */
+	*ihp = line;
 
 	return 0;
 }
@@ -170,8 +191,8 @@
 {
 	static char irqstr[8];
 
-	if (ih >= 16)
-		sprintf(irqstr, "level %d", ih - 16);
+	if (ih >= CPU_INTRLINE_OFFSET)
+		sprintf(irqstr, "cpu int %d", ih - CPU_INTRLINE_OFFSET);
 	else
 		sprintf(irqstr, "irq %d", ih);
 
@@ -191,8 +212,9 @@
     int (*func)(void *), void *arg)
 {
 
-	if (ih >= 16)
-		return cpu_intr_establish(ih - 16, level, func, arg);
+	if (ih >= CPU_INTRLINE_OFFSET)
+		return cpu_intr_establish(ih - CPU_INTRLINE_OFFSET,
+		    level, func, arg);
 	else
 		return icu_intr_establish(ih, IST_LEVEL, level, func, arg);
 }
Index: pci/pcib.c
===================================================================
RCS file: /cvsroot/src/sys/arch/cobalt/pci/pcib.c,v
retrieving revision 1.17
diff -u -r1.17 pcib.c
--- pci/pcib.c	21 Apr 2006 18:17:45 -0000	1.17
+++ pci/pcib.c	13 May 2006 05:47:52 -0000
@@ -37,25 +37,17 @@
 #include <machine/cpu.h>
 #include <machine/bus.h>
 #include <machine/autoconf.h>
-#include <machine/intr.h>
 
 #include <dev/pci/pcivar.h>
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcidevs.h>
 
-#include <dev/isa/isareg.h>
-
-#define PCIB_BASE	0x10000000	/* XXX */
-
 static int	pcib_match(struct device *, struct cfdata *, void *);
 static void	pcib_attach(struct device *, struct device *, void *);
-static int	icu_intr(void *);
 
 CFATTACH_DECL(pcib, sizeof(struct device),
     pcib_match, pcib_attach, NULL, NULL);
 
-static struct cobalt_intrhand icu[IO_ICUSIZE];
-
 static int
 pcib_match(struct device *parent, struct cfdata *match, void *aux)
 {
@@ -78,74 +70,4 @@
 	printf("\n%s: %s, rev %d\n", self->dv_xname, devinfo,
 	    PCI_REVISION(pa->pa_class));
 
-	/*
-	 * Initialize ICU. Since we block all these interrupts with
-	 * splbio(), we can just enable all of them all the time here.
-	 */
-	*(volatile uint8_t *)MIPS_PHYS_TO_KSEG1(PCIB_BASE + IO_ICU1) = 0x10;
-	*(volatile uint8_t *)MIPS_PHYS_TO_KSEG1(PCIB_BASE + IO_ICU1 + 1) = 0xff;
-	*(volatile uint8_t *)MIPS_PHYS_TO_KSEG1(PCIB_BASE + IO_ICU2) = 0x10;
-	*(volatile uint8_t *)MIPS_PHYS_TO_KSEG1(PCIB_BASE + IO_ICU2 + 1) = 0xff;
-	wbflush();
-
-	cpu_intr_establish(4, IPL_NONE, icu_intr, NULL);
-}
-
-void *
-icu_intr_establish(int irq, int type, int level, int (*func)(void *),
-    void *arg)
-{
-	struct cobalt_intrhand *ih;
-	int i;
-
-	for (i = 0; i < IO_ICUSIZE; i++) {
-		ih = &icu[i];
-		if (ih->ih_func == NULL) {
-			ih->ih_cookie_type = COBALT_COOKIE_TYPE_ICU;
-			ih->ih_func = func;
-			ih->ih_arg = arg;
-			snprintf(ih->ih_evname, sizeof(ih->ih_evname),
-			    "irq %d", irq);
-			evcnt_attach_dynamic(&ih->ih_evcnt, EVCNT_TYPE_INTR,
-			    NULL, "icu", ih->ih_evname);
-			return ih;
-		}
-	}
-
-	panic("too many IRQs");
-}
-
-void
-icu_intr_disestablish(void *cookie)
-{
-	struct cobalt_intrhand *ih = cookie;
-
-	if (ih->ih_cookie_type == COBALT_COOKIE_TYPE_ICU) {
-		ih->ih_func = NULL;
-		ih->ih_arg = NULL;
-		ih->ih_cookie_type = 0;
-		evcnt_detach(&ih->ih_evcnt);
-	}
-}
-
-int
-icu_intr(void *arg)
-{
-	struct cobalt_intrhand *ih;
-	int i, handled;
-
-	handled = 0;
-
-	for (i = 0; i < IO_ICUSIZE; i++) {
-		ih = &icu[i];
-		if (ih->ih_func == NULL)
-			break;
-
-		if ((*ih->ih_func)(ih->ih_arg)) {
-			ih->ih_evcnt.ev_count++;
-			handled = 1;
-		}
-	}
-
-	return handled;
 }
--- /dev/null	2006-05-13 12:57:00.000000000 +0900
+++ cobalt/interrupt.c	2006-05-13 01:15:43.000000000 +0900
@@ -0,0 +1,377 @@
+/*	$NetBSD$	*/
+
+/*
+ * Copyright (c) 2000 Soren S. Jorvang.  All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD");
+
+#include <sys/param.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+
+#include <mips/locore.h>
+
+#include <dev/ic/i8259reg.h>
+#include <dev/isa/isareg.h>
+
+#include <cobalt/cobalt/clockvar.h>
+
+#include <cobalt/dev/gtreg.h>
+
+#define PCIB_BASE	0x10000000	/* XXX */
+#define GT_BASE		0x14000000	/* XXX */
+
+#define NCPU_INT	6
+#define NICU_INT	16
+#define IRQ_SLAVE	2
+
+#define ICU1_READ(reg)		\
+    bus_space_read_1(icu_bst, icu1_bsh, (reg))
+#define ICU1_WRITE(reg, val)	\
+    bus_space_write_1(icu_bst, icu1_bsh, (reg), (val))
+#define ICU2_READ(reg)		\
+    bus_space_read_1(icu_bst, icu2_bsh, (reg))
+#define ICU2_WRITE(reg, val)	\
+    bus_space_write_1(icu_bst, icu2_bsh, (reg), (val))
+
+static int	icu_intr(void *);
+static void	icu_reinit_irqs(void);
+static u_int	icu_setmask(u_int);
+
+struct evcnt hardclock_ev =
+    EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, "cpu", "hardclock");
+struct evcnt statclock_ev =
+    EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, "cpu", "statclock");
+
+static struct cobalt_intrhand cpu_intrtab[NCPU_INT];
+static struct cobalt_intrhand icu_intrtab[NICU_INT];
+
+const uint32_t mips_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 */
+};
+
+bus_space_tag_t icu_bst;
+bus_space_handle_t icu1_bsh, icu2_bsh;
+u_int icu_imen;
+
+void *
+cpu_intr_establish(int level, int ipl, int (*func)(void *), void *arg)
+{
+	struct cobalt_intrhand *ih;
+
+	if (level < 0 || level >= NCPU_INT)
+		panic("invalid interrupt level");
+
+	ih = &cpu_intrtab[level];
+
+	if (ih->ih_func != NULL)
+		panic("cannot share CPU interrupts");
+
+	ih->ih_cookie_type = COBALT_COOKIE_TYPE_CPU;
+	ih->ih_func = func;
+	ih->ih_arg = arg;
+	snprintf(ih->ih_evname, sizeof(ih->ih_evname), "int %d", level);
+	evcnt_attach_dynamic(&ih->ih_evcnt, EVCNT_TYPE_INTR, NULL,
+	    "cpu", ih->ih_evname);
+
+	return ih;
+}
+
+void
+cpu_intr_disestablish(void *cookie)
+{
+	struct cobalt_intrhand *ih = cookie;
+
+	if (ih->ih_cookie_type == COBALT_COOKIE_TYPE_CPU) {
+		ih->ih_func = NULL;
+		ih->ih_arg = NULL;
+		ih->ih_cookie_type = 0;
+		evcnt_detach(&ih->ih_evcnt);
+	}
+}
+
+void
+cpu_intr(uint32_t status, uint32_t cause, uint32_t pc, uint32_t ipending)
+{
+	struct clockframe cf;
+	struct cobalt_intrhand *ih;
+
+	uvmexp.intrs++;
+
+	if (ipending & MIPS_INT_MASK_5) {
+		/* statclock */
+		cf.pc = pc;
+		cf.sr = status;
+
+		statclockintr(&cf);
+		statclock_ev.ev_count++;
+
+		cause &= ~MIPS_INT_MASK_5;
+	}
+	_splset((status & MIPS_INT_MASK_5) | MIPS_SR_INT_IE);
+
+	if (ipending & MIPS_INT_MASK_0) {
+		/* GT64x11 timer0 for hardclock */
+		volatile uint32_t *irq_src =
+		    (uint32_t *)MIPS_PHYS_TO_KSEG1(GT_BASE + GT_INTR_CAUSE);
+
+		if ((*irq_src & T0EXP) != 0) {
+			*irq_src = 0;
+
+			cf.pc = pc;
+			cf.sr = status;
+
+			if ((status & MIPS_INT_MASK) == MIPS_INT_MASK) {
+				if ((ipending & MIPS_INT_MASK &
+				     ~MIPS_INT_MASK_0) == 0) {
+					/*
+					 * If all interrupts were enabled and
+					 * there is no pending interrupts,
+					 * set MIPS_SR_INT_IE so that
+					 * spllowerclock() in hardclock()
+					 * works properly.
+					 */
+#if 0					/* MIPS_SR_INT_IE is enabled above */
+					_splset(MIPS_SR_INT_IE);
+#endif
+ 				} else {
+					/*
+					 * If there are any pending interrputs,
+					 * clear MIPS_SR_INT_IE in cf.sr so that
+					 * spllowerclock() in hardclock() will
+					 * not happen.
+					 */
+					cf.sr &= ~MIPS_SR_INT_IE;
+				}
+			}
+			hardclock(&cf);
+			hardclock_ev.ev_count++;
+		}
+		cause &= ~MIPS_INT_MASK_0;
+	}
+	_splset((status & ~cause & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE);
+
+	if (ipending & MIPS_INT_MASK_3) {
+		/* 16650 serial */
+		ih = &cpu_intrtab[3];
+		if (ih->ih_func != NULL) {
+			if ((*ih->ih_func)(ih->ih_arg)) {
+				cause &= ~MIPS_INT_MASK_3;
+				ih->ih_evcnt.ev_count++;
+			}
+		}
+	}
+	_splset((status & ~cause & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE);
+
+	if (ipending & MIPS_INT_MASK_1) {
+		/* tulip primary */
+		ih = &cpu_intrtab[1];
+		if (ih->ih_func != NULL) {
+			if ((*ih->ih_func)(ih->ih_arg)) {
+				cause &= ~MIPS_INT_MASK_1;
+				ih->ih_evcnt.ev_count++;
+			}
+		}
+	}
+	if (ipending & MIPS_INT_MASK_2) {
+		/* tulip secondary */
+		ih = &cpu_intrtab[2];
+		if (ih->ih_func != NULL) {
+			if ((*ih->ih_func)(ih->ih_arg)) {
+				cause &= ~MIPS_INT_MASK_2;
+				ih->ih_evcnt.ev_count++;
+			}
+		}
+	}
+	_splset((status & ~cause & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE);
+
+	if (ipending & MIPS_INT_MASK_4) {
+		/* ICU interrupts */
+		ih = &cpu_intrtab[4];
+		if (ih->ih_func != NULL) {
+			if ((*ih->ih_func)(ih->ih_arg)) {
+				cause &= ~MIPS_INT_MASK_4;
+				/* evcnt for ICU is done in icu_intr() */
+			}
+		}
+	}
+	_splset((status & ~cause & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE);
+
+	/* software interrupt */
+	ipending &= (MIPS_SOFT_INT_MASK_1|MIPS_SOFT_INT_MASK_0);
+	if (ipending == 0)
+		return;
+
+	_clrsoftintr(ipending);
+
+	softintr_dispatch(ipending);
+}
+
+void
+icu_init(void)
+{
+
+	icu_bst = 0;	/* XXX unused on cobalt */
+	bus_space_map(icu_bst, PCIB_BASE + IO_ICU1, IO_ICUSIZE, 0, &icu1_bsh);
+	bus_space_map(icu_bst, PCIB_BASE + IO_ICU2, IO_ICUSIZE, 0, &icu2_bsh);
+
+	/* initialize master */
+	ICU1_WRITE(PIC_ICW1, ICW1_SELECT | ICW1_IC4);
+	ICU1_WRITE(PIC_ICW2, 0);			/* XXX */
+	ICU1_WRITE(PIC_ICW3, ICW3_CASCADE(IRQ_SLAVE));
+	ICU1_WRITE(PIC_ICW4, ICW4_SFNM | ICW4_8086);
+	ICU1_WRITE(PIC_OCW3, OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
+	ICU1_WRITE(PIC_OCW3, OCW3_SELECT | OCW3_RR);
+
+	/* initialize slave */
+	ICU2_WRITE(PIC_ICW1, ICW1_SELECT | ICW1_IC4);
+	ICU2_WRITE(PIC_ICW2, 8);			/* XXX */
+	ICU2_WRITE(PIC_ICW3, ICW3_SIC(IRQ_SLAVE));
+	ICU2_WRITE(PIC_ICW4, ICW4_SFNM | ICW4_8086);
+	ICU2_WRITE(PIC_OCW3, OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
+	ICU2_WRITE(PIC_OCW3, OCW3_SELECT | OCW3_RR);
+
+	icu_setmask(0xffff);	/* mask all interrupts */
+
+	wbflush();
+
+	cpu_intr_establish(4, IPL_NONE, icu_intr, NULL);
+}
+
+void *
+icu_intr_establish(int irq, int type, int level, int (*func)(void *),
+    void *arg)
+{
+	struct cobalt_intrhand *ih;
+
+	ih = &icu_intrtab[irq];
+	if (ih->ih_func != NULL)
+		panic("icu_intr_establish(): irq %d is already in use", irq);
+
+	ih->ih_cookie_type = COBALT_COOKIE_TYPE_ICU;
+	ih->ih_func = func;
+	ih->ih_arg = arg;
+	snprintf(ih->ih_evname, sizeof(ih->ih_evname),
+	    "irq %d", irq);
+	evcnt_attach_dynamic(&ih->ih_evcnt, EVCNT_TYPE_INTR,
+	    NULL, "icu", ih->ih_evname);
+
+	icu_reinit_irqs();
+
+	return ih;
+}
+
+void
+icu_intr_disestablish(void *cookie)
+{
+	struct cobalt_intrhand *ih = cookie;
+
+	if (ih->ih_cookie_type == COBALT_COOKIE_TYPE_ICU) {
+		ih->ih_func = NULL;
+		ih->ih_arg = NULL;
+		ih->ih_cookie_type = 0;
+		evcnt_detach(&ih->ih_evcnt);
+
+		icu_reinit_irqs();
+	}
+}
+
+int
+icu_intr(void *arg)
+{
+	struct cobalt_intrhand *ih;
+	int irq, handled;
+
+	handled = 0;
+
+	/* check requested irq */
+	ICU1_WRITE(PIC_OCW3, OCW3_SELECT | OCW3_POLL);
+	irq = ICU1_READ(PIC_OCW3);
+	if ((irq & OCW3_POLL_PENDING) == 0)
+		return 0;
+
+	irq = OCW3_POLL_IRQ(irq);
+	if (irq == IRQ_SLAVE) {
+		ICU2_WRITE(PIC_OCW3, OCW3_SELECT | OCW3_POLL);
+		irq = OCW3_POLL_IRQ(ICU2_READ(PIC_OCW3)) + 8;
+	}
+
+	ih = &icu_intrtab[irq];
+	if (ih->ih_func == NULL) {
+		printf("icu_intr(): spurious interrupt (irq = %d)\n", irq);
+	} else if ((*ih->ih_func)(ih->ih_arg)) {
+		ih->ih_evcnt.ev_count++;
+		handled = 1;
+	}
+
+	/* issue EOI to ack */
+	if (irq >= 8) {
+		ICU2_WRITE(PIC_OCW2,
+		    OCW2_SELECT | OCW2_SL | OCW2_EOI | OCW2_ILS(irq - 8));
+		irq = IRQ_SLAVE;
+	}
+	ICU1_WRITE(PIC_OCW2, OCW2_SELECT | OCW2_SL | OCW2_EOI | OCW2_ILS(irq));
+
+	return handled;
+}
+
+void
+icu_reinit_irqs(void)
+{
+	u_int i, irqs;
+
+	/* unmask interrupts */
+	irqs = 0;
+	for (i = 0; i < NICU_INT; i++) {
+		if (icu_intrtab[i].ih_func)
+			irqs |= 1 << i;
+	}
+	if (irqs & 0xff00) /* any slave IRQs in use */
+		irqs |= 1 << IRQ_SLAVE;
+	icu_imen = ~irqs;
+
+	ICU1_WRITE(PIC_OCW1, icu_imen);
+	ICU2_WRITE(PIC_OCW1, icu_imen >> 8);
+}
+
+u_int
+icu_setmask(u_int mask)
+{
+	u_int old;
+
+	old = icu_imen;
+	icu_imen = mask;
+	ICU1_WRITE(PIC_OCW1, icu_imen);
+	ICU2_WRITE(PIC_OCW1, icu_imen >> 8);
+
+	return old;
+}