diff --git a/sys/arch/cobalt/cobalt/autoconf.c b/sys/arch/cobalt/cobalt/autoconf.c index cfc7baca3f88..344803786556 100644 --- a/sys/arch/cobalt/cobalt/autoconf.c +++ b/sys/arch/cobalt/cobalt/autoconf.c @@ -1,4 +1,4 @@ -/* $NetBSD: autoconf.c,v 1.19 2006/04/21 18:17:45 tsutsui Exp $ */ +/* $NetBSD: autoconf.c,v 1.20 2006/05/31 12:59:39 tsutsui Exp $ */ /* * Copyright (c) 2000 Soren S. Jorvang. All rights reserved. @@ -26,7 +26,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.19 2006/04/21 18:17:45 tsutsui Exp $"); +__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.20 2006/05/31 12:59:39 tsutsui Exp $"); #include #include @@ -35,6 +35,7 @@ __KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.19 2006/04/21 18:17:45 tsutsui Exp $" #include #include +#include #include @@ -52,6 +53,7 @@ cpu_configure(void) (void)splhigh(); evcnt_attach_static(&hardclock_ev); + icu_init(); if (config_rootfound("mainbus", NULL) == NULL) panic("no mainbus found"); diff --git a/sys/arch/cobalt/cobalt/machdep.c b/sys/arch/cobalt/cobalt/machdep.c index 2353dae4c3ca..dc8de1f2f548 100644 --- a/sys/arch/cobalt/cobalt/machdep.c +++ b/sys/arch/cobalt/cobalt/machdep.c @@ -1,4 +1,31 @@ -/* $NetBSD: machdep.c,v 1.66 2006/04/21 18:21:30 tsutsui Exp $ */ +/* $NetBSD: machdep.c,v 1.67 2006/05/31 12:59:39 tsutsui Exp $ */ + +/* + * 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. @@ -26,7 +53,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.66 2006/04/21 18:21:30 tsutsui Exp $"); +__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.67 2006/05/31 12:59:39 tsutsui Exp $"); #include "opt_ddb.h" #include "opt_kgdb.h" @@ -61,6 +88,7 @@ __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.66 2006/04/21 18:21:30 tsutsui Exp $") #include #include #include +#include #include #include @@ -69,10 +97,14 @@ __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.66 2006/04/21 18:21:30 tsutsui Exp $") #include +#include +#include + #include #include #define GT_BASE 0x14000000 /* XXX */ +#define PCIB_BASE 0x10000000 /* XXX */ #ifdef KGDB #include @@ -400,9 +432,28 @@ cpu_reboot(int howto, char *bootstr) ; } -#define NINTR 6 -static struct cobalt_intrhand intrtab[NINTR]; +#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)) const uint32_t mips_ipl_si_to_sr[_IPL_NSOFT] = { MIPS_SOFT_INT_MASK_0, /* IPL_SOFT */ @@ -411,15 +462,195 @@ const uint32_t mips_ipl_si_to_sr[_IPL_NSOFT] = { 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]; + +static int icu_intr(void *); +static void icu_reinit_irqs(void); +static u_int icu_setmask(u_int); + + +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(); + } +} + +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; +} + +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 (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)); + + out: + return handled; +} + void * cpu_intr_establish(int level, int ipl, int (*func)(void *), void *arg) { struct cobalt_intrhand *ih; - if (level < 0 || level >= NINTR) + if (level < 0 || level >= NCPU_INT) panic("invalid interrupt level"); - ih = &intrtab[level]; + ih = &cpu_intrtab[level]; if (ih->ih_func != NULL) panic("cannot share CPU interrupts"); @@ -427,7 +658,7 @@ cpu_intr_establish(int level, int ipl, int (*func)(void *), void *arg) 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); + 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); @@ -451,11 +682,23 @@ 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_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 = @@ -467,6 +710,29 @@ cpu_intr(uint32_t status, uint32_t cause, uint32_t pc, uint32_t ipending) 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++; } @@ -474,23 +740,9 @@ cpu_intr(uint32_t status, uint32_t cause, uint32_t pc, uint32_t ipending) } _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]; + ih = &cpu_intrtab[3]; if (ih->ih_func != NULL) { if ((*ih->ih_func)(ih->ih_arg)) { cause &= ~MIPS_INT_MASK_3; @@ -502,7 +754,7 @@ cpu_intr(uint32_t status, uint32_t cause, uint32_t pc, uint32_t ipending) if (ipending & MIPS_INT_MASK_1) { /* tulip primary */ - ih = &intrtab[1]; + ih = &cpu_intrtab[1]; if (ih->ih_func != NULL) { if ((*ih->ih_func)(ih->ih_arg)) { cause &= ~MIPS_INT_MASK_1; @@ -512,7 +764,7 @@ cpu_intr(uint32_t status, uint32_t cause, uint32_t pc, uint32_t ipending) } if (ipending & MIPS_INT_MASK_2) { /* tulip secondary */ - ih = &intrtab[2]; + ih = &cpu_intrtab[2]; if (ih->ih_func != NULL) { if ((*ih->ih_func)(ih->ih_arg)) { cause &= ~MIPS_INT_MASK_2; @@ -524,7 +776,7 @@ cpu_intr(uint32_t status, uint32_t cause, uint32_t pc, uint32_t ipending) if (ipending & MIPS_INT_MASK_4) { /* ICU interrupts */ - ih = &intrtab[4]; + ih = &cpu_intrtab[4]; if (ih->ih_func != NULL) { if ((*ih->ih_func)(ih->ih_arg)) { cause &= ~MIPS_INT_MASK_4; diff --git a/sys/arch/cobalt/include/intr.h b/sys/arch/cobalt/include/intr.h index 94b10cf775ce..d803b978ced3 100644 --- a/sys/arch/cobalt/include/intr.h +++ b/sys/arch/cobalt/include/intr.h @@ -1,4 +1,4 @@ -/* $NetBSD: intr.h,v 1.20 2006/04/21 18:17:45 tsutsui Exp $ */ +/* $NetBSD: intr.h,v 1.21 2006/05/31 12:59:39 tsutsui Exp $ */ /* * Copyright (c) 2000 Soren S. Jorvang. All rights reserved. @@ -103,6 +103,7 @@ struct cobalt_intrhand { 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 *cpu_intr_establish(int, int, int (*)(void *), void *); 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 */ diff --git a/sys/arch/cobalt/pci/pcib.c b/sys/arch/cobalt/pci/pcib.c index 1b852767fbfe..776a137ba8bb 100644 --- a/sys/arch/cobalt/pci/pcib.c +++ b/sys/arch/cobalt/pci/pcib.c @@ -1,4 +1,4 @@ -/* $NetBSD: pcib.c,v 1.17 2006/04/21 18:17:45 tsutsui Exp $ */ +/* $NetBSD: pcib.c,v 1.18 2006/05/31 12:59:39 tsutsui Exp $ */ /* * Copyright (c) 2000 Soren S. Jorvang. All rights reserved. @@ -26,7 +26,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: pcib.c,v 1.17 2006/04/21 18:17:45 tsutsui Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pcib.c,v 1.18 2006/05/31 12:59:39 tsutsui Exp $"); #include #include @@ -37,25 +37,17 @@ __KERNEL_RCSID(0, "$NetBSD: pcib.c,v 1.17 2006/04/21 18:17:45 tsutsui Exp $"); #include #include #include -#include #include #include #include -#include - -#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 @@ pcib_attach(struct device *parent, struct device *self, void *aux) 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; }