Subject: Re: test kernel for cobalt
To: None <port-cobalt@NetBSD.org>
From: Izumi Tsutsui <tsutsui@ceres.dti.ne.jp>
List: port-cobalt
Date: 05/21/2006 01:50:39
mk@kilbi.de wrote:

> this additional gt.c patch seems to improve ata/ide disk performance
> (partially), but seems to decrease network (tlp0 in my case)
> performance.

Hmm. I've tested GENERIC kernels (updated today) with my local patch,
but I can't see network (tlp0) performance decrease on my RaQ2:
---

Summary:
---
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
w/o gt.c change:
          100  3844 94.5  3877 58.7  3528 82.3  4690 98.7 13934 99.9 351.2 77.3
w/  gt.c change:
          100  4255 97.1  7224 75.9  6230 95.1  4727 99.6 14025 99.8 764.3 99.3

 (BTW I guess most data is cached on inputs since my RaQ2 has 256MB RAM)

w/o gt.c change:
ttcp-t: 16777216 bytes in 3.57 real seconds = 4583.46 KB/sec +++
w/  gt.c change:
ttcp-t: 16777216 bytes in 3.44 real seconds = 4758.06 KB/sec +++

w/o gt.c change:
ttcp-r: 16777216 bytes in 3.49 real seconds = 4687.96 KB/sec +++
w/  gt.c change:
ttcp-r: 16777216 bytes in 3.47 real seconds = 4726.09 KB/sec +++
---

Details:

GENERIC+patch without gt.c change:
---
% bonnie
File './Bonnie.41', size: 104857600
Writing with putc()...done
Rewriting...done
Writing intelligently...done
Reading with getc()...done
Reading intelligently...done
Seeker 1...Seeker 2...Seeker 3...start 'em...done...done...done...
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
          100  3844 94.5  3877 58.7  3528 82.3  4690 98.7 13934 99.9 351.2 77.3
% 
 :
% ttcp -ts 192.168.20.1
ttcp-t: buflen=8192, nbuf=2048, align=16384/0, port=5001  tcp  -> 192.168.20.1
ttcp-t: socket
ttcp-: connect
ttcp-t: 16777216 bytes in 3.57 real seconds = 4583.46 KB/sec +++
ttcp-t: 2048 I/O calls, msec/call = 1.79, calls/sec = 572.93
ttcp-t: 0.0user 3.5sys 0:03real 99% 0i+0d 0maxrss 0+4098pf 0+50csw
% ttcp -rs
ttcp-r: buflen=8192, nbuf=2048, align=16384/0, port=5001  tcp
ttcp-r: socket
ttcp-r: accept from 192.168.20.1
ttcp-r: 16777216 bytes in 3.49 real seconds = 4687.96 KB/sec +++
ttcp-r: 2049 I/O calls, msec/call = 1.75, calls/sec = 586.28
ttcp-r: 0.0user 3.4sys 0:03real 99% 0i+0d 0maxrss 0+2pf 0+51csw
% 
---

GENERIC+patch with gt.c change (#if 0 -> #if 1 in the attached patch)
---
% bonnie
File './Bonnie.41', size: 104857600
Writing with putc()...done
Rewriting...done
Writing intelligently...done
Reading with getc()...done
Reading intelligently...done
Seeker 1...Seeker 2...Seeker 3...start 'em...done...done...done...
              -------Sequential Output-------- ---Sequential Input-- --Random--
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --Seeks---
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU  /sec %CPU
          100  4255 97.1  7224 75.9  6230 95.1  4727 99.6 14025 99.8 764.3 99.3
% 

 :

% ttcp -ts 192.168.20.1
ttcp-t: buflen=8192, nbuf=2048, align=16384/0, port=5001  tcp  -> 192.168.20.1
ttcp-t: socket
ttcp-t: connect
ttcp-t: 16777216 bytes in 3.44 real seconds = 4758.06 KB/sec +++
ttcp-t: 2048 I/O calls,ec/call = 1.72, calls/sec = 594.76
ttcp-t: 0.0user 3.3sys 0:03real 97% 0i+0d 0maxrss 0+4098pf 1+55csw
% ttcp -rs
ttcp-r: buflen=8192, nbuf=2048, align=16384/0, port=5001  tcp
ttcp-r: socket
ttcp-r: accept from 192.168.20.1
ttcp-r: 16777216 bytes in 3.47 real seconds = 4726.09 KB/sec +++
ttcp-r: 2049 I/O calls, msec/call = 1.73, calls/sec = 591.05
ttcp-r: 0.0user 3.4sys 0:03real 99% 0i+0d 0maxrss 0+2pf 0+48csw
% 
---

full dmesg:
---
Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
    The NetBSD Foundation, Inc.  All rights reserved.
Copyright (c) 1982, 1986, 1989, 1991, 1993
    The Regents of the University of California.  All rights reserved.

NetBSD 3.99.20 (GENERIC) #1: Sun May 21 00:51:56 JST 2006
	tsutsui@mirage:/usr/src/sys/arch/cobalt/compile/GENERIC
Cobalt RaQ 2
total memory = 256 MB
avail memory = 246 MB
mainbus0 (root)
com0 at mainbus0 addr 0x1c800000 level 3: st16650a, working fifo
com0: console
cpu0 at mainbus0: QED RM5200 CPU (0x28a0) Rev. 10.0 with built-in FPU Rev. 10.0
cpu0: 32KB/32B 2-way set-associative L1 Instruction cache, 48 TLB entries
cpu0: 32KB/32B 2-way set-associative write-back L1 Data cache
mcclock0 at mainbus0 addr 0x10000070: mc146818 compatible time-of-day clock
panel0 at mainbus0 addr 0x1f000000
gt0 at mainbus0 addr 0x14000000
pci0 at gt0
pci0: i/o space, memory space enabled, rd/line, wr/inv ok
pchb0 at pci0 dev 0 function 0: Galileo GT-64111 System Controller, rev 1
tlp0 at pci0 dev 7 function 0: DECchip 21143 Ethernet, pass 4.1
tlp0: interrupting at level 1
tlp0: Ethernet address 00:10:e0:00:5e:95
lxtphy0 at tlp0 phy 1: LXT970 10/100 media interface, rev. 3
lxtphy0: 10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, auto
siop0 at pci0 dev 8 function 0: Symbios Logic 53c860 (ultra scsi)
siop0: interrupting at irq 4
scsibus0 at siop0: 8 targets, 8 luns per target
pcib0 at pci0 dev 9 function 0
pcib0: VIA Technologies VT82C586 PCI-ISA Bridge, rev 37
viaide0 at pci0 dev 9 function 1
viaide0: VIA Technologies VT82C586 (Apollo VP) ATA33 controller
viaide0: bus-master DMA support present
viaide0: primary channel configured to compatibility mode
viaide0: primary channel interrupting at irq 14
atabus0 at viaide0 channel 0
viaide0: secondary channel configured to compatibility mode
viaide0: secondary channel interrupting at irq 15
atabus1 at viaide0 channel 1
VIA Technologies VT83C572 USB Controller (USB serial bus, revision 0x02) at pci0 dev 9 function 2 not configured
tlp1 at pci0 dev 12 function 0: DECchip 21143 Ethernet, pass 4.1
tlp1: interrupting at level 2
tlp1: Ethernet address 00:10:e0:00:5e:97
lxtphy1 at tlp1 phy 1: LXT970 10/100 media interface, rev. 3
lxtphy1: 10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, auto
Kernelized RAIDframe activated
scsibus0: waiting 2 seconds for devices to settle...
sd0 at scsibus0 target 3 lun 0: <, DPES-, > disk fixed
sd0: 1034 MB, 4903 cyl, 4 head, 108 sec, 512 bytes/sect x 2118144 sectors
sd0: sync (100.00ns offset 8), 8-bit (10.000MB/s) transfers, tagged queueing
wd0 at atabus0 drive 0: <IBM-DTTA-351680>
wd0: drive supports 16-sector PIO transfers, LBA addressing
wd0: 16124 MB, 32760 cyl, 16 head, 63 sec, 512 bytes/sect x 33022080 sectors
wd0: 32-bit data port
wd0: drive supports PIO mode 4, DMA mode 2, Ultra-DMA mode 2 (Ultra/33)
wd0(viaide0:0:0): using PIO mode 4, Ultra-DMA mode 2 (Ultra/33) (using DMA)
boot device: wd0
root on wd0a dumps on wd0b
root file system type: ffs
---


my latest patch:
---
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	20 May 2006 15:39:37 -0000
@@ -35,6 +35,7 @@
 #include <sys/device.h>
 
 #include <machine/cpu.h>
+#include <machine/intr.h>
 
 #include <cobalt/cobalt/clockvar.h>
 
@@ -52,6 +53,7 @@
 	(void)splhigh();
 
 	evcnt_attach_static(&hardclock_ev);
+	icu_init();
 
 	if (config_rootfound("mainbus", NULL) == NULL)
 		panic("no mainbus found");
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	20 May 2006 15:39:37 -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	20 May 2006 15:39:37 -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: dev/gt.c
===================================================================
RCS file: /cvsroot/src/sys/arch/cobalt/dev/gt.c,v
retrieving revision 1.18
diff -u -r1.18 gt.c
--- dev/gt.c	20 May 2006 03:38:03 -0000	1.18
+++ dev/gt.c	20 May 2006 15:39:37 -0000
@@ -114,6 +114,11 @@
 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, GT_PCI_COMMAND,
 	    (bus_space_read_4(sc->sc_bst, sc->sc_bsh, GT_PCI_COMMAND) &
 	    ~PCI_SYNCMODE) | PCI_PCLK_HIGH);
+#if 0
+	(void)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,
+	    0x00 << PCI_RETRYCTR_SHIFT | 0xff << PCI_TIMEOUT1_SHIFT | 0xff);
+#endif
 
 #if NPCI > 0
 	pc = &sc->sc_pc;
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	20 May 2006 15:39:37 -0000
@@ -103,6 +103,7 @@
 	LIST_ENTRY(cobalt_intrhand) ih_q;
 	int (*ih_func)(void *);
 	void *ih_arg;
+	int ih_type;
 	int ih_cookie_type;
 #define	COBALT_COOKIE_TYPE_CPU	0x1
 #define	COBALT_COOKIE_TYPE_ICU	0x2
@@ -117,6 +118,7 @@
 void *icu_intr_establish(int, int, int, int (*)(void *), void *);
 void cpu_intr_disestablish(void *);
 void icu_intr_disestablish(void *);
+void icu_init(void);
 
 #endif /* !_LOCORE */
 #endif /* _LOCORE */
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	20 May 2006 15:39:37 -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-21 00:36:49.000000000 +0900
+++ cobalt/interrupt.c	2006-05-20 00:03:07.000000000 +0900
@@ -0,0 +1,441 @@
+/*	$NetBSD$	*/
+
+/*
+ * Copyright (c) 2006 Izumi Tsutsui.
+ * 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.
+ * 3. The name of the author may not 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.
+ */
+
+/*
+ * 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 IO_ELCR		0x4d0
+#define IO_ELCRSIZE	2
+#define ELCR0		0
+#define ELCR1		1
+
+#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))
+#define ELCR_READ(reg)		\
+    bus_space_read_1(icu_bst, elcr_bsh, (reg))
+#define ELCR_WRITE(reg, val)	\
+    bus_space_write_1(icu_bst, elcr_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");
+
+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 */
+};
+
+u_int icu_imen;
+
+static bus_space_tag_t icu_bst;
+static bus_space_handle_t icu1_bsh, icu2_bsh, elcr_bsh;
+static struct cobalt_intrhand cpu_intrtab[NCPU_INT];
+static struct cobalt_intrhand icu_intrtab[NICU_INT];
+
+
+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) {
+		mips3_cp0_compare_write(mips3_cp0_count_read()); /* XXX */
+#if 0
+		cf.pc = pc;
+		cf.sr = status;
+
+		statclock(&cf);
+#endif
+
+		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 (__predict_true((*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 (__predict_true(ih->ih_func != NULL)) {
+			if (__predict_true((*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 (__predict_true(ih->ih_func != NULL)) {
+			if (__predict_true((*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 (__predict_true(ih->ih_func != NULL)) {
+			if (__predict_true((*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 (__predict_true(ih->ih_func != NULL)) {
+			if (__predict_true((*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 *
+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
+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);
+	bus_space_map(icu_bst, PCIB_BASE + IO_ELCR, IO_ELCRSIZE, 0, &elcr_bsh);
+
+	/* Initialize master PIC */
+
+	/* reset; program device, four bytes */
+	ICU1_WRITE(PIC_ICW1, ICW1_SELECT | ICW1_IC4);
+	/* starting at this vector index */
+	ICU1_WRITE(PIC_ICW2, 0);			/* XXX */
+	/* slave on line 2 */
+	ICU1_WRITE(PIC_ICW3, ICW3_CASCADE(IRQ_SLAVE));
+	/* special fully nested mode, 8086 mode */
+	ICU1_WRITE(PIC_ICW4, ICW4_SFNM | ICW4_8086);
+	/* special mask mode */
+	ICU1_WRITE(PIC_OCW3, OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
+	/* read IRR by default */
+	ICU1_WRITE(PIC_OCW3, OCW3_SELECT | OCW3_RR);
+
+	/* Initialize slave PIC */
+
+	/* reset; program device, four bytes */
+	ICU2_WRITE(PIC_ICW1, ICW1_SELECT | ICW1_IC4);
+	/* starting at this vector index */
+	ICU2_WRITE(PIC_ICW2, 8);			/* XXX */
+	/* slave connected to line 2 of master */
+	ICU2_WRITE(PIC_ICW3, ICW3_SIC(IRQ_SLAVE));
+	/* special fully nested mode, 8086 mode */
+	ICU2_WRITE(PIC_ICW4, ICW4_SFNM | ICW4_8086);
+	/* special mask mode */
+	ICU2_WRITE(PIC_OCW3, OCW3_SELECT | OCW3_SSMM | OCW3_SMM);
+	/* read IRR by default */
+	ICU2_WRITE(PIC_OCW3, OCW3_SELECT | OCW3_RR);
+
+	icu_setmask(0xffff);	/* mask all interrupts */
+
+	/* default to edge-triggered */
+	ELCR_WRITE(ELCR0, 0);
+	ELCR_WRITE(ELCR1, 0);
+
+	wbflush();
+
+	cpu_intr_establish(4, IPL_NONE, icu_intr, NULL);
+}
+
+void *
+icu_intr_establish(int irq, int type, int ipl, 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;
+	ih->ih_type = type;
+	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;
+		ih->ih_type = IST_NONE;
+		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)
+		goto out;
+
+	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 (__predict_false(ih->ih_func == NULL)) {
+		printf("icu_intr(): spurious interrupt (irq = %d)\n", irq);
+	} else if (__predict_true((*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));
+
+ out:
+	return handled;
+}
+
+void
+icu_reinit_irqs(void)
+{
+	u_int i, irqs, elcr;
+
+	/* unmask interrupts */
+	irqs = 0;
+	elcr = 0;
+	for (i = 0; i < NICU_INT; i++) {
+		if (icu_intrtab[i].ih_func) {
+			irqs |= 1 << i;
+			if (icu_intrtab[i].ih_type == IST_LEVEL)
+				elcr |= 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);
+
+	ELCR_WRITE(ELCR0, elcr);
+	ELCR_WRITE(ELCR1, elcr >> 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;
+}

---
Izumi Tsutsui