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/19/2006 01:07:18
acruhl@gmail.com wrote:
> I ftp'd base.tgz to another netbsd box. With the netbsd-3 kernel, it
> was .98 meg per second average. With your kernel it was 1.05 meg per
> second average. From another box, it was 7.5 megs per second.
Getting files to a local disk on cobalt?
Maybe xfer rate could be limited by viaide(4) disk xfer
(and extra cache flash on it) in that case.
How about "get remote-file /dev/null" on ftp(1)?
(it shows 4.46MB/s on my RaQ2 with tlp)
> > - could you try any specific benchmark?
> Any one in particular? Is ttcp good enough?
pkgsrc/benchmark/nttcp or pkgsrc/net/netperf etc?
Now I've put a newer test kernel (based on today's source):
http://www.ceres.dti.ne.jp/~tsutsui/netbsd/netbsd-COBALT_TEST-20060518.gz
which contains only interrupt fixes (patch attached):
- fix overblocking after spllowersoftclock(9) in hardclock(9)
(see src/sys/arch/arc/TODO)
- initialize icu (i8259 PIC) more properly
- check interrupt types and set ELCR (edge/level control) regsters
(BTW should we handle shared interrupts? could it happen on cobalt?)
- check requested irq and call only a necessary handler in icu_intr()
- use specific EOI to ack interrupts rather than AEOI
- move interrupt stuff into separate interrupt.c from machdep.c and
pcib.c, since icu must be initialized before pcib is attached
---
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 18 May 2006 15:56:24 -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 18 May 2006 15:56:24 -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 18 May 2006 15:56:25 -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: 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 18 May 2006 15:56:25 -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 18 May 2006 15:56:25 -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-19 00:22:03.000000000 +0900
+++ cobalt/interrupt.c 2006-05-18 23:43:07.000000000 +0900
@@ -0,0 +1,426 @@
+/* $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");
+
+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 */
+};
+
+u_int icu_imen;
+
+static bus_space_tag_t icu_bst;
+static bus_space_handle_t icu1_bsh, icu2_bsh, elcr_bsh;
+
+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) {
+ 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 ((*irq_src & T0EXP) != 0) {
+ *irq_src = 0;
+
+ cf.pc = pc;
+ cf.sr = status;
+
+ if ((status & MIPS3_INT_MASK) == MIPS3_INT_MASK) {
+ if ((ipending & MIPS3_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);
+ bus_space_map(icu_bst, PCIB_BASE + IO_ELCR, IO_ELCRSIZE, 0, &elcr_bsh);
+
+ /* initialize master PIC */
+ 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 PIC */
+ 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 */
+
+ /* 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 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;
+ 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)
+ 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, 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;
+}