diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2007-12-04 23:45:54 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2007-12-04 23:45:54 +0000 |
commit | 5424d15729d1b5915d87e909b47eabdfaf06cd12 (patch) | |
tree | 8fb2005ec56bdde5c8ea1525c1eefe2033b80623 /sys/arch/mvme88k | |
parent | 1214d4250a15e351eadd4f3c0f36335de0f25cba (diff) |
Work in progress SMP code for 88110 processor using the BusSwitch chip as
an IPI facility, for MVME197DP.
It's still missing a few remote cache IPIs and IPI do not seem to be reliably
triggered on remote processors at the moment (but this could be a problem
on the board I am currently testing on), at least it will boot multiuser
using only cpu0 to schedule processes.
Diffstat (limited to 'sys/arch/mvme88k')
-rw-r--r-- | sys/arch/mvme88k/dev/bussw.c | 47 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/busswreg.h | 22 | ||||
-rw-r--r-- | sys/arch/mvme88k/include/mvme197.h | 6 | ||||
-rw-r--r-- | sys/arch/mvme88k/mvme88k/m197_machdep.c | 260 | ||||
-rw-r--r-- | sys/arch/mvme88k/mvme88k/m1x7_machdep.c | 22 | ||||
-rw-r--r-- | sys/arch/mvme88k/mvme88k/m88110.c | 37 |
6 files changed, 301 insertions, 93 deletions
diff --git a/sys/arch/mvme88k/dev/bussw.c b/sys/arch/mvme88k/dev/bussw.c index 2b283a6c544..4e0a52249c3 100644 --- a/sys/arch/mvme88k/dev/bussw.c +++ b/sys/arch/mvme88k/dev/bussw.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bussw.c,v 1.18 2007/12/04 05:40:14 miod Exp $ */ +/* $OpenBSD: bussw.c,v 1.19 2007/12/04 23:45:52 miod Exp $ */ /* * Copyright (c) 1999 Steve Murphree, Jr. * @@ -36,7 +36,6 @@ struct bussw_softc { struct device sc_dev; - struct intrhand sc_abih; /* `abort' switch */ bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; }; @@ -54,8 +53,6 @@ struct cfdriver bussw_cd = { int bussw_print(void *, const char *); int bussw_scan(struct device *, void *, void *); -int busswabort(void *); -int busswintr_establish(int, struct intrhand *, const char *); int bussw_match(parent, vcf, args) @@ -107,18 +104,12 @@ bussw_attach(parent, self, args) bus_space_write_1(sc->sc_iot, ioh, BS_VBASE, bus_space_read_1(sc->sc_iot, ioh, BS_VBASE) | BS_VECBASE); + + /* enable external interrupts */ bus_space_write_2(sc->sc_iot, ioh, BS_GCSR, bus_space_read_2(sc->sc_iot, ioh, BS_GCSR) | BS_GCSR_XIPL); - /* - * pseudo driver, abort interrupt handler - */ - sc->sc_abih.ih_fn = busswabort; - sc->sc_abih.ih_arg = 0; - sc->sc_abih.ih_wantframe = 1; - sc->sc_abih.ih_ipl = IPL_NMI; - - busswintr_establish(BS_ABORTIRQ, &sc->sc_abih, "abort"); + /* enable abort switch */ bus_space_write_1(sc->sc_iot, ioh, BS_ABORT, bus_space_read_1(sc->sc_iot, ioh, BS_ABORT) | BS_ABORT_IEN); @@ -167,33 +158,3 @@ bussw_scan(parent, child, args) config_attach(parent, cf, &oca, bussw_print); return (1); } - -int -busswintr_establish(int vec, struct intrhand *ih, const char *name) -{ -#ifdef DIAGNOSTIC - if (vec < 0 || vec >= BS_NVEC) - panic("busswintr_establish: illegal vector 0x%x", vec); -#endif - - return intr_establish(BS_VECBASE + vec, ih, name); -} - -int -busswabort(eframe) - void *eframe; -{ - struct frame *frame = eframe; - - struct bussw_softc *sc = (struct bussw_softc *)bussw_cd.cd_devs[0]; - u_int8_t abort; - - abort = bus_space_read_1(sc->sc_iot, sc->sc_ioh, BS_ABORT); - if (abort & BS_ABORT_INT) { - bus_space_write_1(sc->sc_iot, sc->sc_ioh, BS_ABORT, - abort | BS_ABORT_ICLR); - nmihand(frame); - return 1; - } - return 0; -} diff --git a/sys/arch/mvme88k/dev/busswreg.h b/sys/arch/mvme88k/dev/busswreg.h index 15a31df42ca..f17e49c5f01 100644 --- a/sys/arch/mvme88k/dev/busswreg.h +++ b/sys/arch/mvme88k/dev/busswreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: busswreg.h,v 1.8 2007/11/22 05:53:57 miod Exp $ */ +/* $OpenBSD: busswreg.h,v 1.9 2007/12/04 23:45:52 miod Exp $ */ /* * Memory map for BusSwitch chip found in mvme197 boards. @@ -191,16 +191,18 @@ #define BS_VBASE_SRC_EXT 0x4 /* external interrupt */ #define BS_VBASE_SRC_SPUR 0x7 /* spurious interrupt */ -/* We lock off BusSwitch vectors at 0x40 */ -#define BS_VECBASE 0x40 -#define BS_NVEC 0x10 +/* + * BusSwitch wired interrupt vectors + */ -/* Bottom 4 bits of the vector returned during IACK cycle */ -#define BS_TMR1IRQ 0x01 /* lowest */ -#define BS_TMR2IRQ 0x02 -#define BS_ABORTIRQ 0x03 +#define BS_VECBASE 0x40 /* vector base */ +#define BS_NVEC 0x10 -/* Define the Abort vector */ -#define BS_ABORTVEC (BS_VECBASE | BS_ABORTIRQ) +#define BS_TMR1IRQ 0x00 /* timer1 */ +#define BS_TMR2IRQ 0x01 /* timer2 */ +#define BS_WPEIRQ 0x02 /* write post error */ +#define BS_PALIRQ 0x03 /* processor address log interrupt */ +#define BS_EXTIRQ 0x04 /* external interrupt */ +#define BS_SPURIRQ 0x07 /* spurious interrupt */ #endif /* BUSSWREG_H */ diff --git a/sys/arch/mvme88k/include/mvme197.h b/sys/arch/mvme88k/include/mvme197.h index 9f137ad3451..84eab739bd5 100644 --- a/sys/arch/mvme88k/include/mvme197.h +++ b/sys/arch/mvme88k/include/mvme197.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mvme197.h,v 1.7 2006/04/27 20:21:19 miod Exp $ */ +/* $OpenBSD: mvme197.h,v 1.8 2007/12/04 23:45:52 miod Exp $ */ /* * Copyright (c) 1996 Nivas Madhur * Copyright (c) 1999 Steve Murphree, Jr. @@ -58,4 +58,8 @@ #define M197_ISRC 0xfff0006f /* interrupt SRC */ #define M197_IACK 0xfff00100 /* interrupt ACK base */ +#ifdef _KERNEL +void m197_send_complex_ipi(int, cpuid_t, u_int32_t, u_int32_t); +#endif + #endif /* __MACHINE_MVME197_H__ */ diff --git a/sys/arch/mvme88k/mvme88k/m197_machdep.c b/sys/arch/mvme88k/mvme88k/m197_machdep.c index f73107ffc05..3f1ca1c6323 100644 --- a/sys/arch/mvme88k/mvme88k/m197_machdep.c +++ b/sys/arch/mvme88k/mvme88k/m197_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: m197_machdep.c,v 1.19 2007/12/02 21:32:10 miod Exp $ */ +/* $OpenBSD: m197_machdep.c,v 1.20 2007/12/04 23:45:53 miod Exp $ */ /* * Copyright (c) 1998, 1999, 2000, 2001 Steve Murphree, Jr. * Copyright (c) 1996 Nivas Madhur @@ -62,11 +62,18 @@ #include <mvme88k/dev/busswreg.h> #include <mvme88k/mvme88k/clockvar.h> +#ifdef MULTIPROCESSOR +#include <machine/db_machdep.h> +#endif + void m197_bootstrap(void); +void m197_clock_ipi_handler(struct trapframe *); void m197_ext_int(u_int, struct trapframe *); u_int m197_getipl(void); +void m197_ipi_handler(struct trapframe *); vaddr_t m197_memsize(void); u_int m197_raiseipl(u_int); +void m197_send_ipi(int, cpuid_t); u_int m197_setipl(u_int); void m197_startup(void); @@ -154,23 +161,17 @@ m197_startup() void m197_ext_int(u_int v, struct trapframe *eframe) { +#ifdef MULTIPROCESSOR + struct cpu_info *ci = curcpu(); +#endif + u_int32_t psr; int level; struct intrhand *intr; intrhand_t *list; int ret; vaddr_t ivec; u_int8_t vec; - - if (v == T_NON_MASK) { - /* This is the abort switch */ - level = IPL_NMI; - vec = BS_ABORTVEC; - } else { - level = *(u_int8_t *)M197_ILEVEL & 0x07; - /* generate IACK and get the vector */ - ivec = M197_IACK + (level << 2) + 0x03; - vec = *(volatile u_int8_t *)ivec; - } + u_int8_t abort; #ifdef MULTIPROCESSOR if (eframe->tf_mask < IPL_SCHED) @@ -179,27 +180,63 @@ m197_ext_int(u_int v, struct trapframe *eframe) uvmexp.intrs++; - if (v != T_NON_MASK || cold == 0) { + if (v == T_NON_MASK) { + /* + * Non-maskable interrupts are either the abort switch (on + * cpu0 only) or IPIs (on any cpu). We check for IPI first. + */ +#ifdef MULTIPROCESSOR + if ((*(volatile u_int8_t *)(BS_BASE + BS_CPINT)) & BS_CPI_INT) + m197_ipi_handler(eframe); +#endif + + abort = *(u_int8_t *)(BS_BASE + BS_ABORT); + if (abort & BS_ABORT_INT) { + *(u_int8_t *)(BS_BASE + BS_ABORT) = + abort | BS_ABORT_ICLR; + nmihand(eframe); + } + +#ifdef MULTIPROCESSOR + /* + * If we have pending hardware IPIs and the current + * level allows them to be processed, do them now. + */ + if (eframe->tf_mask < IPL_SCHED && + ISSET(ci->ci_ipi, + CI_IPI_HARDCLOCK | CI_IPI_STATCLOCK)) { + psr = get_psr(); + set_psr(psr & ~PSR_IND); + m197_clock_ipi_handler(eframe); + set_psr(psr); + } +#endif + } else { + level = *(u_int8_t *)M197_ILEVEL & 0x07; + /* generate IACK and get the vector */ + ivec = M197_IACK + (level << 2) + 0x03; + vec = *(volatile u_int8_t *)ivec; + /* block interrupts at level or lower */ m197_setipl(level); - flush_pipeline(); - set_psr(get_psr() & ~PSR_IND); - } + psr = get_psr(); + set_psr(psr & ~PSR_IND); - list = &intr_handlers[vec]; - if (SLIST_EMPTY(list)) { - printf("Spurious interrupt (level %x and vec %x)\n", - level, vec); - } else { -#ifdef DEBUG - intr = SLIST_FIRST(list); - if (intr->ih_ipl != level) { - panic("Handler ipl %x not the same as level %x. " - "vec = 0x%x", - intr->ih_ipl, level, vec); - } +#ifdef MULTIPROCESSOR + /* + * If we have pending hardware IPIs and the current + * level allows them to be processed, do them now. + */ + if (eframe->tf_mask < IPL_SCHED && + ISSET(ci->ci_ipi, CI_IPI_HARDCLOCK | CI_IPI_STATCLOCK)) + m197_clock_ipi_handler(eframe); #endif + list = &intr_handlers[vec]; + if (SLIST_EMPTY(list)) + printf("Spurious interrupt (level %x and vec %x)\n", + level, vec); + /* * Walk through all interrupt handlers in the chain for the * given vector, calling each handler in turn, till some handler @@ -222,14 +259,12 @@ m197_ext_int(u_int v, struct trapframe *eframe) printf("Unclaimed interrupt (level %x and vec %x)\n", level, vec); } - } - if (v != T_NON_MASK || cold == 0) { /* * Disable interrupts before returning to assembler, * the spl will be restored later. */ - set_psr(get_psr() | PSR_IND); + set_psr(psr | PSR_IND); } #ifdef MULTIPROCESSOR @@ -297,10 +332,8 @@ m197_bootstrap() * set the correct value in the other one, since we set * all the active bits. */ - cpu = *(volatile u_int16_t *)(BS_BASE + BS_GCSR) & - BS_GCSR_CPUID; - *(volatile u_int8_t *)(BS_BASE + (cpu ? BS_ISEL1 : BS_ISEL0)) = - 0xfe; + cpu = *(u_int16_t *)(BS_BASE + BS_GCSR) & BS_GCSR_CPUID; + *(u_int8_t *)(BS_BASE + (cpu ? BS_ISEL1 : BS_ISEL0)) = 0xfe; } else cmmu = &cmmu88110; /* 197LE */ @@ -309,4 +342,161 @@ m197_bootstrap() md_setipl = m197_setipl; md_raiseipl = m197_raiseipl; md_init_clocks = m1x7_init_clocks; +#ifdef MULTIPROCESSOR + md_send_ipi = m197_send_ipi; +#endif +} + +#ifdef MULTIPROCESSOR + +void +m197_send_ipi(int ipi, cpuid_t cpu) +{ + struct cpu_info *ci = &m88k_cpus[cpu]; + + if (ci->ci_ipi & ipi) + return; + + if (ci->ci_ddb_state == CI_DDB_PAUSE) + return; /* XXX skirting deadlock */ + + atomic_setbits_int(&ci->ci_ipi, ipi); + + /* + * If the other processor doesn't have an IPI pending, send one, + * keeping IPIs enabled for us. + */ + if ((*(volatile u_int8_t *)(BS_BASE + BS_CPINT) & BS_CPI_STAT) == 0) + *(volatile u_int8_t *)(BS_BASE + BS_CPINT) = + BS_CPI_SCPI | BS_CPI_IEN; } + +void +m197_send_complex_ipi(int ipi, cpuid_t cpu, u_int32_t arg1, u_int32_t arg2) +{ + struct cpu_info *ci = &m88k_cpus[cpu]; + int wait = 0; + + if ((ci->ci_flags & CIF_ALIVE) == 0) + return; /* XXX not ready yet */ + + if (ci->ci_ddb_state == CI_DDB_PAUSE) + return; /* XXX skirting deadlock */ + + /* + * Wait for the other processor to be ready to accept an IPI. + */ + for (wait = 10000000; wait != 0; wait--) { + if (!ISSET(*(volatile u_int8_t *)(BS_BASE + BS_CPINT), + BS_CPI_STAT)) + break; + } + if (wait == 0) + panic("couldn't send complex ipi %x to cpu %d", ipi, cpu); + + /* + * In addition to the ipi bit itself, we need to set up ipi arguments. + * Note that we do not need to protect against another processor + * trying to send another complex IPI, since we know there are only + * two processors on the board. + */ + ci->ci_ipi_arg1 = arg1; + ci->ci_ipi_arg2 = arg2; + atomic_setbits_int(&ci->ci_ipi, ipi); + + /* + * Send an IPI, keeping our IPIs enabled. + */ + *(volatile u_int8_t *)(BS_BASE + BS_CPINT) = BS_CPI_SCPI | BS_CPI_IEN; +} + +void +m197_ipi_handler(struct trapframe *eframe) +{ + struct cpu_info *ci = curcpu(); + int ipi = ci->ci_ipi & ~(CI_IPI_HARDCLOCK | CI_IPI_STATCLOCK); + u_int32_t arg1, arg2; + + if (ipi != 0) + atomic_clearbits_int(&ci->ci_ipi, ipi); + + /* + * Complex IPIs (with extra arguments). There can only be one + * pending at the same time, sending processor will wait for us + * to have processed the current one before sending a new one. + */ + if (ipi & + (CI_IPI_TLB_FLUSH | CI_IPI_CACHE_FLUSH | CI_IPI_ICACHE_FLUSH)) { + arg1 = ci->ci_ipi_arg1; + arg2 = ci->ci_ipi_arg2; + if (ipi & CI_IPI_TLB_FLUSH) { + cmmu_flush_tlb(ci->ci_cpuid, arg1, arg2, 0); + } + else if (ipi & CI_IPI_CACHE_FLUSH) { + cmmu_flush_cache(ci->ci_cpuid, arg1, arg2); + } + else if (ipi & CI_IPI_ICACHE_FLUSH) { + cmmu_flush_inst_cache(ci->ci_cpuid, arg1, arg2); + } + } + + /* + * Regular, simple, IPIs. We can have as many bits set as possible. + */ + if (ipi & CI_IPI_DDB) { +#ifdef DDB + /* + * Another processor has entered DDB. Spin on the ddb lock + * until it is done. + */ + extern struct __mp_lock ddb_mp_lock; + + ci->ci_ddb_state = CI_DDB_PAUSE; + + __mp_lock(&ddb_mp_lock); + __mp_unlock(&ddb_mp_lock); + + ci->ci_ddb_state = CI_DDB_RUNNING; + + /* + * If ddb is hoping to us, it's our turn to enter ddb now. + */ + if (ci->ci_cpuid == ddb_mp_nextcpu) + Debugger(); +#endif + } + if (ipi & CI_IPI_NOTIFY) { + /* nothing to do */ + } + + /* + * Acknowledge IPIs. + */ + *(volatile u_int8_t *)(BS_BASE + BS_CPINT) = BS_CPI_ICLR | BS_CPI_IEN; +} + +/* + * Maskable IPIs. + * + * These IPIs are received as non maskable, but are only processed if + * the current spl permits it; so they are checked again on return from + * regular interrupts to process them as soon as possible. + */ +void +m197_clock_ipi_handler(struct trapframe *eframe) +{ + struct cpu_info *ci = curcpu(); + int ipi = ci->ci_ipi & (CI_IPI_HARDCLOCK | CI_IPI_STATCLOCK); + int s; + + atomic_clearbits_int(&ci->ci_ipi, ipi); + + s = splclock(); + if (ipi & CI_IPI_HARDCLOCK) + hardclock((struct clockframe *)eframe); + if (ipi & CI_IPI_STATCLOCK) + statclock((struct clockframe *)eframe); + splx(s); +} + +#endif diff --git a/sys/arch/mvme88k/mvme88k/m1x7_machdep.c b/sys/arch/mvme88k/mvme88k/m1x7_machdep.c index 344e1d55d42..60185b55a24 100644 --- a/sys/arch/mvme88k/mvme88k/m1x7_machdep.c +++ b/sys/arch/mvme88k/mvme88k/m1x7_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: m1x7_machdep.c,v 1.5 2007/05/14 16:57:43 miod Exp $ */ +/* $OpenBSD: m1x7_machdep.c,v 1.6 2007/12/04 23:45:53 miod Exp $ */ /* * Copyright (c) 1999 Steve Murphree, Jr. * Copyright (c) 1995 Theo de Raadt @@ -159,6 +159,14 @@ m1x7_clockintr(void *eframe) hardclock(eframe); +#ifdef MULTIPROCESSOR + /* + * Send an IPI to all other processors, so they can get their + * own ticks. + */ + m88k_broadcast_ipi(CI_IPI_HARDCLOCK); +#endif + return (1); } @@ -169,8 +177,6 @@ m1x7_statintr(void *eframe) *(volatile u_int8_t *)(PCC2_BASE + PCCTWO_T2ICR) = STAT_RESET; - statclock((struct clockframe *)eframe); - /* * Compute new randomized interval. The intervals are uniformly * distributed on [statint - statvar / 2, statint + statvar / 2], @@ -189,5 +195,15 @@ m1x7_statintr(void *eframe) *(volatile u_int8_t *)(PCC2_BASE + PCCTWO_T2ICR) = STAT_RESET; *(volatile u_int8_t *)(PCC2_BASE + PCCTWO_T2CTL) = PCC2_TCTL_CEN | PCC2_TCTL_COC; + + statclock((struct clockframe *)eframe); + +#ifdef MULTIPROCESSOR + /* + * Send an IPI to all other processors as well. + */ + m88k_broadcast_ipi(CI_IPI_STATCLOCK); +#endif + return (1); } diff --git a/sys/arch/mvme88k/mvme88k/m88110.c b/sys/arch/mvme88k/mvme88k/m88110.c index 0cec6f53e37..4c79f141fc8 100644 --- a/sys/arch/mvme88k/mvme88k/m88110.c +++ b/sys/arch/mvme88k/mvme88k/m88110.c @@ -1,4 +1,4 @@ -/* $OpenBSD: m88110.c,v 1.47 2007/12/04 05:41:48 miod Exp $ */ +/* $OpenBSD: m88110.c,v 1.48 2007/12/04 23:45:53 miod Exp $ */ /* * Copyright (c) 1998 Steve Murphree, Jr. * All rights reserved. @@ -70,6 +70,9 @@ #include <machine/psl.h> #include <mvme88k/dev/busswreg.h> +#ifdef MULTIPROCESSOR +#include <machine/mvme197.h> +#endif cpuid_t m88110_init(void); cpuid_t m88410_init(void); @@ -233,6 +236,14 @@ m88410_init(void) dctl |= CMMU_DCTL_SEN; set_dctl(dctl); mc88410_inval(); /* clear external data cache */ + +#ifdef MULTIPROCESSOR + /* + * Mark us as allowing IPIs now. + */ + *(volatile u_int8_t *)(BS_BASE + BS_CPINT) = BS_CPI_ICLR | BS_CPI_IEN; +#endif + return (cpu); } @@ -364,6 +375,14 @@ void m88110_flush_tlb(cpuid_t cpu, u_int kernel, vaddr_t vaddr, u_int count) { u_int32_t psr; +#ifdef MULTIPROCESSOR + struct cpu_info *ci = curcpu(); + + if (cpu != ci->ci_cpuid) { + m197_send_complex_ipi(CI_IPI_TLB_FLUSH, cpu, kernel, vaddr); + return; + } +#endif psr = get_psr(); set_psr(psr | PSR_IND); @@ -420,6 +439,14 @@ void m88410_flush_cache(cpuid_t cpu, paddr_t pa, psize_t size) { u_int32_t psr; +#ifdef MULTIPROCESSOR + struct cpu_info *ci = curcpu(); + + if (cpu != ci->ci_cpuid) { + m197_send_complex_ipi(CI_IPI_CACHE_FLUSH, cpu, pa, size); + return; + } +#endif psr = get_psr(); set_psr(psr | PSR_IND); @@ -449,6 +476,14 @@ void m88410_flush_inst_cache(cpuid_t cpu, paddr_t pa, psize_t size) { u_int32_t psr; +#ifdef MULTIPROCESSOR + struct cpu_info *ci = curcpu(); + + if (cpu != ci->ci_cpuid) { + m197_send_complex_ipi(CI_IPI_ICACHE_FLUSH, cpu, pa, size); + return; + } +#endif psr = get_psr(); set_psr(psr | PSR_IND); |