diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/mvme88k/dev/bugio.c | 10 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/busswitch.c | 152 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/busswitchreg.h | 10 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/cl.c | 27 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/clock.c | 280 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/dart.c | 1191 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/dartreg.h | 311 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/i82596.h | 310 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/if_ie.c | 277 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/if_ie.h | 46 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/nvram.c | 110 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/nvramreg.h | 17 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/pcctwo.c | 37 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/sclock.c | 412 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/syscon.c | 250 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/sysconreg.h | 61 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/vme.c | 290 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/vs.c | 541 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/vsdma.c | 6 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/vsreg.h | 71 |
20 files changed, 3670 insertions, 739 deletions
diff --git a/sys/arch/mvme88k/dev/bugio.c b/sys/arch/mvme88k/dev/bugio.c index 3a3d085dd5e..aee175f7206 100644 --- a/sys/arch/mvme88k/dev/bugio.c +++ b/sys/arch/mvme88k/dev/bugio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bugio.c,v 1.3 1999/05/29 04:41:42 smurph Exp $ */ +/* $OpenBSD: bugio.c,v 1.4 1999/09/27 18:43:21 smurph Exp $ */ /* Copyright (c) 1998 Steve Murphree, Jr. */ #include <machine/bugio.h> @@ -64,13 +64,15 @@ buginit() char buginchr(void) { - register int cc asm("r2"); + register int cc; + int ret; BUGCTXT(); asm volatile ("or r9,r0," INCHR); asm volatile ("tb0 0,r0,0x1F0"); asm volatile ("or %0,r0,r2" : "=r" (cc) : ); - OSCTXT(); - return ((char)cc & 0xFF); + ret = cc; + OSCTXT(); + return ((char)ret & 0xFF); } bugoutchr(unsigned char c) diff --git a/sys/arch/mvme88k/dev/busswitch.c b/sys/arch/mvme88k/dev/busswitch.c new file mode 100644 index 00000000000..71eb44d9937 --- /dev/null +++ b/sys/arch/mvme88k/dev/busswitch.c @@ -0,0 +1,152 @@ +/* $OpenBSD: busswitch.c,v 1.1 1999/09/27 18:43:22 smurph Exp $ */ + +/* + * Copyright (c) 1999 Steve Murphree, Jr. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed under OpenBSD by + * Theo de Raadt for Willowglen Singapore. + * 4. 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. + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/ioctl.h> +#include <sys/device.h> +#include <sys/systm.h> +#include <sys/uio.h> +#include <sys/malloc.h> +#include <machine/psl.h> +#include <machine/autoconf.h> +#include <machine/bugio.h> +#include <machine/cpu.h> +#include <machine/mioctl.h> +#include <machine/vmparam.h> + +#include <mvme88k/dev/busswitchreg.h> + +struct busswitchsoftc { + struct device sc_dev; + void * sc_paddr; + void * sc_vaddr; + int sc_len; + struct busswitchreg * sc_busswitch; +}; + +void busswitchattach __P((struct device *, struct device *, void *)); +int busswitchmatch __P((struct device *, void *, void *)); + +struct cfattach busswitch_ca = { + sizeof(struct busswitchsoftc), busswitchmatch, busswitchattach +}; + +struct cfdriver busswitch_cd = { + NULL, "busswitch", DV_DULL, 0 +}; + +int +busswitchmatch(parent, vcf, args) + struct device *parent; + void *vcf, *args; +{ + struct cfdata *cf = vcf; + struct confargs *ca = args; + struct busswitchreg *busswitch; + /* Don't match if wrong cpu */ + if (cputyp != CPU_197) return (0); + + busswitch = (struct busswitchreg *)(IIOV(ca->ca_paddr)); + if (badvaddr(busswitch, 4) <= 0){ + printf("==> busswitch: failed address check.\n"); + return (0); + } + return (1); +} + +void +busswitchattach(parent, self, args) + struct device *parent, *self; + void *args; +{ + struct confargs *ca = args; + struct busswitchsoftc *sc = (struct busswitchsoftc *)self; + + sc->sc_paddr = ca->ca_paddr; + sc->sc_vaddr = ca->ca_vaddr; + + /* + printf(": rev %d\n", sc->sc_busswitch->chiprev); + */ + printf(": rev %d\n", 0); +} + +int +busswitch_print(args, bus) + void *args; + const char *bus; +{ + struct confargs *ca = args; + + if (ca->ca_offset != -1) + printf(" offset 0x%x", ca->ca_offset); + if (ca->ca_ipl > 0) + printf(" ipl %d", ca->ca_ipl); + return (UNCONF); +} + +int +busswitch_scan(parent, child, args) + struct device *parent; + void *child, *args; +{ + struct cfdata *cf = child; + struct busswitchsoftc *sc = (struct busswitchsoftc *)parent; + struct confargs *ca = args; + struct confargs oca; + + if (parent->dv_cfdata->cf_driver->cd_indirect) { + printf(" indirect devices not supported\n"); + return 0; + } + + bzero(&oca, sizeof oca); + oca.ca_offset = cf->cf_loc[0]; + oca.ca_ipl = cf->cf_loc[1]; + if ((oca.ca_offset != (void*)-1) && ISIIOVA(sc->sc_vaddr + oca.ca_offset)) { + oca.ca_vaddr = sc->sc_vaddr + oca.ca_offset; + oca.ca_paddr = sc->sc_paddr + oca.ca_offset; + } else { + oca.ca_vaddr = (void *)-1; + oca.ca_paddr = (void *)-1; + } + oca.ca_bustype = BUS_BUSSWITCH; + oca.ca_master = (void *)sc->sc_busswitch; + oca.ca_name = cf->cf_driver->cd_name; + if ((*cf->cf_attach->ca_match)(parent, cf, &oca) == 0) + return (0); + config_attach(parent, cf, &oca, busswitch_print); + return (1); +} + diff --git a/sys/arch/mvme88k/dev/busswitchreg.h b/sys/arch/mvme88k/dev/busswitchreg.h new file mode 100644 index 00000000000..d1f95c717a2 --- /dev/null +++ b/sys/arch/mvme88k/dev/busswitchreg.h @@ -0,0 +1,10 @@ +/* $OpenBSD: busswitchreg.h,v 1.1 1999/09/27 18:43:22 smurph Exp $ */ + +/* + * Memory map for BusSwitch chip found in mvme197 boards. + */ + +struct busswitchreg { + unsigned start; +}; + diff --git a/sys/arch/mvme88k/dev/cl.c b/sys/arch/mvme88k/dev/cl.c index 6e738b5a4fa..f00246bb230 100644 --- a/sys/arch/mvme88k/dev/cl.c +++ b/sys/arch/mvme88k/dev/cl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cl.c,v 1.4 1999/05/29 04:41:43 smurph Exp $ */ +/* $OpenBSD: cl.c,v 1.5 1999/09/27 18:43:22 smurph Exp $ */ /* * Copyright (c) 1995 Dale Rahn. All rights reserved. @@ -900,16 +900,21 @@ clcnprobe(cp) { /* always there ? */ /* serial major */ - int maj; - - /* locate the major number */ - for (maj = 0; maj < nchrdev; maj++) - if (cdevsw[maj].d_open == clopen) - break; - cp->cn_dev = makedev (maj, 0); - cp->cn_pri = CN_NORMAL; - - return 1; + int maj; + + /* bomb if it'a a MVME188 */ + if (cputyp == CPU_188){ + cp->cn_pri = CN_DEAD; + return 0; + } + /* locate the major number */ + for (maj = 0; maj < nchrdev; maj++) + if (cdevsw[maj].d_open == clopen) + break; + cp->cn_dev = makedev (maj, 0); + cp->cn_pri = CN_NORMAL; + + return 1; } int diff --git a/sys/arch/mvme88k/dev/clock.c b/sys/arch/mvme88k/dev/clock.c index 80a022fc263..2609694ac5d 100644 --- a/sys/arch/mvme88k/dev/clock.c +++ b/sys/arch/mvme88k/dev/clock.c @@ -1,6 +1,6 @@ -/* $OpenBSD: clock.c,v 1.5 1999/05/29 04:41:43 smurph Exp $ */ - +/* $OpenBSD: clock.c,v 1.6 1999/09/27 18:43:23 smurph Exp $ */ /* + * Copyright (c) 1999 Steve Murphree, Jr. * Copyright (c) 1995 Theo de Raadt * * Redistribution and use in source and binary forms, with or without @@ -77,10 +77,11 @@ */ /* - * Clock driver. Has both interval timer as well as statistics timer. + * interval clock driver. */ #include <sys/param.h> +#include <sys/simplelock.h> #include <sys/kernel.h> #include <sys/device.h> #ifdef GPROF @@ -91,30 +92,27 @@ #include <machine/autoconf.h> #include <machine/bugio.h> #include <machine/cpu.h> - +#include "pcctwo.h" +#if NPCCTWO > 0 #include <mvme88k/dev/pcctworeg.h> +#endif +#include "syscon.h" +#if NSYSCON > 0 +#include <mvme88k/dev/sysconreg.h> +#endif #include <mvme88k/dev/vme.h> -#include "pcctwo.h" -extern struct vme2reg *sys_vme2; -/* - * Statistics clock interval and 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 4096 would - * give us offsets in [0..4095]. Instead, we take offsets in [1..4095]. - * This is symmetric about the point 2048, or statvar/2, and thus averages - * to that value (assuming uniform random numbers). - */ -int statvar = 8192; -int statmin; /* statclock interval - 1/2*variance */ +extern struct vme2reg *sys_vme2; int timerok = 0; u_long delay_factor = 1; static int clockmatch __P((struct device *, void *, void *)); static void clockattach __P((struct device *, struct device *, void *)); -/*int clockintr __P((void *, void *));*/ -/*#int statintr __P((void *, void *));*/ + +void sbc_initclock(void); +void m188_initclock(void); +void m188_timer_init __P((unsigned)); struct clocksoftc { struct device sc_dev; @@ -130,16 +128,18 @@ struct cfdriver clock_cd = { NULL, "clock", DV_DULL, 0 }; -int clockintr __P((void *)); -int statintr __P((void *)); +int sbc_clockintr __P((void *)); +int sbc_statintr __P((void *)); +int m188_clockintr __P((void *)); +int m188_statintr __P((void *)); int clockbus; -u_char stat_reset, prof_reset; +u_char prof_reset; - /* +/* * Every machine must have a clock tick device of some sort; for this * platform this file manages it, no matter what form it takes. - */ + */ int clockmatch(parent, vcf, args) struct device *parent; @@ -148,8 +148,7 @@ clockmatch(parent, vcf, args) register struct confargs *ca = args; register struct cfdata *cf = vcf; - if (ca->ca_bustype != BUS_PCCTWO || - strcmp(cf->cf_driver->cd_name, "clock")) { + if (strcmp(cf->cf_driver->cd_name, "clock")) { return (0); } @@ -174,67 +173,50 @@ clockattach(parent, self, args) struct confargs *ca = args; struct clocksoftc *sc = (struct clocksoftc *)self; - sc->sc_profih.ih_fn = clockintr; - sc->sc_profih.ih_arg = 0; - sc->sc_profih.ih_wantframe = 1; - sc->sc_profih.ih_ipl = ca->ca_ipl; - - sc->sc_statih.ih_fn = statintr; - sc->sc_statih.ih_arg = 0; - sc->sc_statih.ih_wantframe = 1; - sc->sc_statih.ih_ipl = ca->ca_ipl; - clockbus = ca->ca_bustype; - prof_reset = ca->ca_ipl | PCC2_IRQ_IEN | PCC2_IRQ_ICLR; - stat_reset = ca->ca_ipl | PCC2_IRQ_IEN | PCC2_IRQ_ICLR; - pcctwointr_establish(PCC2V_TIMER1, &sc->sc_profih); - pcctwointr_establish(PCC2V_TIMER2, &sc->sc_statih); - + + switch (clockbus) { +#if NPCCTWO > 0 + case BUS_PCCTWO: + sc->sc_profih.ih_fn = sbc_clockintr; + sc->sc_profih.ih_arg = 0; + sc->sc_profih.ih_wantframe = 1; + sc->sc_profih.ih_ipl = ca->ca_ipl; + prof_reset = ca->ca_ipl | PCC2_IRQ_IEN | PCC2_IRQ_ICLR; + pcctwointr_establish(PCC2V_TIMER1, &sc->sc_profih); + mdfp.clock_init_func = &sbc_initclock; + printf(": VME1x7"); + break; +#endif /* NPCCTWO */ +#if NSYSCON > 0 + case BUS_SYSCON: + sc->sc_profih.ih_fn = m188_clockintr; + sc->sc_profih.ih_arg = 0; + sc->sc_profih.ih_wantframe = 1; + sc->sc_profih.ih_ipl = ca->ca_ipl; + sysconintr_establish(SYSCV_TIMER1, &sc->sc_profih); + mdfp.clock_init_func = &m188_initclock; + printf(": VME188"); + break; +#endif /* NSYSCON */ + } printf("\n"); } - /* - * clockintr: ack intr and call hardclock - */ -int -clockintr(arg) - void *arg; -{ - sys_pcc2->pcc2_t1irq = prof_reset; - hardclock(arg); -#include "bugtty.h" -#if NBUGTTY > 0 - bugtty_chkinput(); -#endif /* NBUGTTY */ - timerok = 1; - return (1); -} - -/* - * Set up real-time clock; we don't have a statistics clock at - * present. - */ -cpu_initclocks() +#if NPCCTWO > 0 +void +sbc_initclock(void) { register int statint, minint; +#ifdef DEBUG + printf("SBC clock init\n"); +#endif if (1000000 % hz) { printf("cannot get %d Hz clock; using 100 Hz\n", hz); hz = 100; tick = 1000000 / hz; } - if (stathz == 0) - stathz = hz; - if (1000000 % stathz) { - printf("cannot get %d Hz statclock; using 100 Hz\n", stathz); - stathz = 100; - } - profhz = stathz; /* always */ - - statint = 1000000 / stathz; - minint = statint / 2 + 100; - while (statvar > minint) - statvar >>= 1; /* profclock */ sys_pcc2->pcc2_t1ctl = 0; @@ -244,53 +226,25 @@ cpu_initclocks() PCC2_TCTL_COVF; sys_pcc2->pcc2_t1irq = prof_reset; - /* statclock */ - sys_pcc2->pcc2_t2ctl = 0; - sys_pcc2->pcc2_t2cmp = pcc2_timer_us2lim(statint); - sys_pcc2->pcc2_t2count = 0; - sys_pcc2->pcc2_t2ctl = PCC2_TCTL_CEN | PCC2_TCTL_COC | - PCC2_TCTL_COVF; - sys_pcc2->pcc2_t2irq = stat_reset; - - statmin = statint - (statvar >> 1); -} - -void -setstatclockrate(newhz) - int newhz; -{ } +/* + * clockintr: ack intr and call hardclock + */ int -statintr(cap) - void *cap; +sbc_clockintr(arg) + void *arg; { - register u_long newint, r, var; - - sys_pcc2->pcc2_t2irq = stat_reset; - - statclock((struct clockframe *)cap); - - /* - * Compute new randomized interval. The intervals are uniformly - * distributed on [statint - statvar / 2, statint + statvar / 2], - * and therefore have mean statint, giving a stathz frequency clock. - */ - var = statvar; - do { - r = random() & (var - 1); - } while (r == 0); - newint = statmin + r; - - sys_pcc2->pcc2_t2ctl = 0; - sys_pcc2->pcc2_t2cmp = pcc2_timer_us2lim(newint); - sys_pcc2->pcc2_t2count = 0; /* should I? */ - sys_pcc2->pcc2_t2irq = stat_reset; - sys_pcc2->pcc2_t2ctl = PCC2_TCTL_CEN | PCC2_TCTL_COC; - - return (1); + sys_pcc2->pcc2_t1irq = prof_reset; + hardclock(arg); +#include "bugtty.h" +#if NBUGTTY > 0 + bugtty_chkinput(); +#endif /* NBUGTTY */ + timerok = 1; + return (1); } - +#endif /* NPCCTWO */ delay(us) register int us; @@ -299,10 +253,11 @@ delay(us) unsigned long st; /* * We use the vme system controller for the delay clock. - * Do not go to the real timer until vme device is present + * Do not go to the real timer until vme device is present. + * Or, in the case of MVME188, not at all. */ - if (sys_vme2 == NULL) { - c = 5 * us; + if (sys_vme2 == NULL || cputyp == CPU_188) { + c = 3 * us; while (--c > 0); return(0); } @@ -311,10 +266,93 @@ delay(us) sys_vme2->vme2_tctl |= (VME2_TCTL1_CEN | VME2_TCTL1_COVF); while (sys_vme2->vme2_t1count < us) - ; + ; sys_vme2->vme2_tctl &= ~(VME2_TCTL1_CEN | VME2_TCTL1_COVF); - return (0); + return (0); +} + +#if NSYSCON > 0 +int counter = 0; + +int +m188_clockintr(arg) + void *arg; +{ + volatile int tmp; + /* acknowledge the timer interrupt */ + /* clear the counter/timer output OP3 while we program the DART */ + *((volatile int *) DART_OPCR) = 0x00; + + /* do the stop counter/timer command */ + tmp = *((volatile int *) DART_STOPC); + + /* set counter/timer to counter mode, clock/16 */ + *((volatile int *) DART_ACR) = 0x30; + + *((volatile int *) DART_CTUR) = counter / 256; /* set counter MSB */ + *((volatile int *) DART_CTLR) = counter % 256; /* set counter LSB */ + *((volatile int *) DART_IVR) = SYSCV_TIMER1; /* set interrupt vec */ + + hardclock(arg); +#include "bugtty.h" +#if NBUGTTY > 0 + bugtty_chkinput(); +#endif /* NBUGTTY */ + /* give the start counter/timer command */ + tmp = *((volatile int *) DART_STARTC); + *((volatile int *) DART_OPCR) = 0x04; + return (1); } +void +m188_initclock(void) +{ + register int statint, minint; +#ifdef DEBUG + printf("VME188 clock init\n"); +#endif + if (1000000 % hz) { + printf("cannot get %d Hz clock; using 100 Hz\n", hz); + hz = 100; + tick = 1000000 / hz; + } + m188_timer_init(tick); +} +void +m188_timer_init(unsigned period) +{ + int imr; + + /* make sure the counter range is proper. */ + if ( period < 9 ) + counter = 2; + else if ( period > 284421 ) + counter = 65535; + else + counter = period / 4.34; +#ifdef DEBUG + printf("tick == %d, period == %d\n", tick, period); + printf("timer will interrupt every %d usec\n", (int) (counter * 4.34)); +#endif + /* clear the counter/timer output OP3 while we program the DART */ + *((volatile int *) DART_OPCR) = 0x00; + + /* do the stop counter/timer command */ + imr = *((volatile int *) DART_STOPC); + + /* set counter/timer to counter mode, clock/16 */ + *((volatile int *) DART_ACR) = 0x30; + + *((volatile int *) DART_CTUR) = counter / 256; /* set counter MSB */ + *((volatile int *) DART_CTLR) = counter % 256; /* set counter LSB */ + *((volatile int *) DART_IVR) = SYSCV_TIMER1; /* set interrupt vec */ + /* give the start counter/timer command */ + /* (yes, this is supposed to be a read) */ + imr = *((volatile int *) DART_STARTC); + + /* set the counter/timer output OP3 */ + *((volatile int *) DART_OPCR) = 0x04; +} +#endif /* NSYSCON */ diff --git a/sys/arch/mvme88k/dev/dart.c b/sys/arch/mvme88k/dev/dart.c new file mode 100644 index 00000000000..f49afd5148e --- /dev/null +++ b/sys/arch/mvme88k/dev/dart.c @@ -0,0 +1,1191 @@ +/* + * Mach Operating System + * Copyright (c) 1993-1991 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <sys/param.h> +#include <sys/callout.h> +#include <sys/conf.h> +#include <sys/ioctl.h> +#include <sys/proc.h> +#include <sys/tty.h> +#include <sys/uio.h> +#include <sys/systm.h> +#include <sys/time.h> +#include <sys/device.h> +#include <sys/simplelock.h> +#include <machine/cpu.h> +#include <machine/autoconf.h> +#include <machine/cpu_number.h> +#include <machine/asm_macro.h> /* enable/disable interrupts */ +#include <dev/cons.h> +#include <mvme88k/dev/sysconreg.h> +#include <mvme88k/dev/dartreg.h> +#include <sys/syslog.h> +#include "dart.h" +#include <machine/psl.h> +#define spldart() splx(IPL_TTY) + +#if DDB + #include <machine/db_machdep.h> /* for details on entering kdb */ +extern unsigned char ddb_break_mode, ddb_break_char; +#endif + +#if DEBUG + #define dprintf(stuff) /*printf stuff*/ +#else + #define dprintf(stuff) +#endif + +struct dart_info { + struct tty *tty; + u_char dart_swflags; + struct simplelock t_lock; +}; + +struct dartsoftc { + struct device sc_dev; + struct evcnt sc_intrcnt; + union dartreg *dart_reg; + struct dart_info sc_dart[2]; + struct intrhand sc_ih; + int sc_flags; + int sc_ipl; + int sc_vec; +}; + +int dartmatch __P((struct device *parent, void *self, void *aux)); +void dartattach __P((struct device *parent, struct device *self, void *aux)); + +struct cfattach dart_ca = { + sizeof(struct dartsoftc), dartmatch, dartattach +}; + +struct cfdriver dart_cd = { + NULL, "dart", DV_TTY, 0 +}; + +/* prototypes */ +int dartcnprobe __P((struct consdev *cp)); +int dartcninit __P((struct consdev *cp)); +int dartcngetc __P((dev_t dev)); +int dartcnputc __P((dev_t dev, char c)); + +int dartopen __P((dev_t dev, int flag, int mode, struct proc *p)); +int dartclose __P((dev_t dev, int flag, int mode, struct proc *p)); +int dartread __P((dev_t dev, struct uio *uio, int flag)); +int dartwrite __P((dev_t dev, struct uio *uio, int flag)); +int dartioctl __P((dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)); +int dartstop __P((struct tty *tp, int flag)); +int dartintr __P((struct dartsoftc *sc)); +void dartbreak __P((dev_t dev, int state)); + +/* + * Lock strategy in that driver: + * Use the tp->t_lock used by chario stuff as a lock + * when modifying the chip's registers. + * + * Should be changed if driver crashes when powering + * two lines. + */ + +#define DART_PORT(dev) minor(dev) +#define dart_tty darttty +struct dart_sv_reg dart_sv_reg; + +/* speed tables */ +int dart_speeds[] = +{ + 0, /* 0 baud, special HUP condition */ + NOBAUD, /* 50 baud, not implemented */ + BD75, /* 75 baud */ + BD110, /* 110 baud */ + BD134, /* 134.5 baud */ + BD150, /* 150 baud */ + NOBAUD, /* 200 baud, not implemented */ + BD300, /* 300 baud */ + BD600, /* 600 baud */ + BD1200, /* 1200 baud */ + BD1800, /* 1800 baud */ + BD2400, /* 2400 baud */ + BD4800, /* 4800 baud */ + BD9600, /* 9600 baud */ + BD19200, /* 19200 baud */ + NOBAUD /* 38400 baud, not implemented */ +}; + +struct tty * darttty(dev) +dev_t dev; +{ + int port; + struct dartsoftc *sc; + sc = (struct dartsoftc *) dart_cd.cd_devs[0]; + port = DART_PORT(dev); + return sc->sc_dart[port].tty; +} + +int +dartmatch(parent, vcf, args) +struct device *parent; +void *vcf, *args; +{ + struct cfdata *cf = vcf; + struct confargs *ca = args; + union dartreg *addr; + + /* Don't match if wrong cpu */ + if (cputyp != CPU_188) return (0); + ca->ca_vaddr = ca->ca_paddr; /* 1:1 */ + addr = (union dartreg *)ca->ca_vaddr; + if (badvaddr(addr, 2) <= 0) { + printf("==> syscon: failed address check.\n"); + return (0); + } + return (1); +} + +void +dartattach(parent, self, aux) +struct device *parent; +struct device *self; +void *aux; +{ + struct dartsoftc *sc = (struct dartsoftc *)self; + struct confargs *ca = aux; + int i; + union dartreg *addr; /* pointer to DUART regs */ + union dart_pt_io *ptaddr; /* pointer to port regs */ + int port; /* port index */ + + /* set up dual port memory and registers and init*/ + sc->dart_reg = (union dartreg *)ca->ca_vaddr; + sc->sc_ipl = ca->ca_ipl; + ca->ca_vec = SYSCV_SCC; /* hard coded vector */ + sc->sc_vec = ca->ca_vec; + + addr = sc->dart_reg; + + /* save standard initialization */ + dart_sv_reg.sv_mr1[A_PORT] = PARDIS | RXRTS | CL8; + dart_sv_reg.sv_mr2[A_PORT] = /* TXCTS | */ SB1; + dart_sv_reg.sv_csr[A_PORT] = BD9600; + dart_sv_reg.sv_cr[A_PORT] = TXEN | RXEN; + + dart_sv_reg.sv_mr1[B_PORT] = PARDIS | RXRTS | CL8; + dart_sv_reg.sv_mr2[B_PORT] = /* TXCTS | */ SB1; + dart_sv_reg.sv_csr[B_PORT] = BD9600; + dart_sv_reg.sv_cr[B_PORT] = TXEN | RXEN; + + dart_sv_reg.sv_acr = BDSET2 | CCLK16 | IPDCDIB | IPDCDIA; + + /* Start out with Tx and RX interrupts disabled */ + /* Enable input port change interrupt */ + dart_sv_reg.sv_imr = IIPCHG; + + dprintf(("dartattach: resetting port A\n")); + + /* reset port a */ + addr->write.wr_cra = RXRESET | TXDIS | RXDIS; + DELAY_CR; + addr->write.wr_cra = TXRESET | TXDIS | RXDIS; + DELAY_CR; + addr->write.wr_cra = ERRRESET | TXDIS | RXDIS; + DELAY_CR; + addr->write.wr_cra = BRKINTRESET | TXDIS | RXDIS; + DELAY_CR; + addr->write.wr_cra = MRRESET | TXDIS | RXDIS; + + dprintf(("dartattach: resetting port B\n")); + + /* reset port b */ + addr->write.wr_crb = RXRESET | TXDIS | RXDIS; + DELAY_CR; + addr->write.wr_crb = TXRESET | TXDIS | RXDIS; + DELAY_CR; + addr->write.wr_crb = ERRRESET | TXDIS | RXDIS; + DELAY_CR; + addr->write.wr_crb = BRKINTRESET | TXDIS | RXDIS; + DELAY_CR; + addr->write.wr_crb = MRRESET | TXDIS | RXDIS; + DELAY_CR; + + /* initialize ports */ + for (port = 0, ptaddr = (union dart_pt_io *)addr; + port < MAXPORTS; + port++, ptaddr++) { + dprintf(("dartattach: init port %c\n", 'A' + port)); + ptaddr->write.wr_mr = dart_sv_reg.sv_mr1[port]; + ptaddr->write.wr_mr = dart_sv_reg.sv_mr2[port]; + ptaddr->write.wr_csr = dart_sv_reg.sv_csr[port]; + ptaddr->write.wr_cr = dart_sv_reg.sv_cr [port]; + } + + dprintf(("dartattach: init common regs\n")); + + /* initialize common register of a DUART */ + addr->write.wr_oprset = OPDTRA | OPRTSA | OPDTRB | OPRTSB; + + addr->write.wr_ctur = SLCTIM>>8; + addr->write.wr_ctlr = SLCTIM & 0xFF; + addr->write.wr_acr = dart_sv_reg.sv_acr; + addr->write.wr_imr = dart_sv_reg.sv_imr; + addr->write.wr_opcr = OPSET; + addr->write.wr_ivr = sc->sc_vec; + + /* enable interrupts */ + sc->sc_ih.ih_fn = dartintr; + sc->sc_ih.ih_arg = sc; + sc->sc_ih.ih_ipl = ca->ca_ipl; + sc->sc_ih.ih_wantframe = 0; + + intr_establish(ca->ca_vec, &sc->sc_ih); + evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt); + printf("\n"); +} + +/* + * To be called at spltty - tty already locked. + */ +void +dartstart(tp) +struct tty *tp; +{ + dev_t dev; + struct dartsoftc *sc; + int s, cnt; + union dart_pt_io *ptaddr; + union dartreg *addr; + int port; + int c; + + dev = tp->t_dev; + port = DART_PORT(dev); + sc = (struct dartsoftc *) dart_cd.cd_devs[0]; + + if ((tp->t_state & TS_ISOPEN) == 0) + return; + + addr = sc->dart_reg; + ptaddr = (union dart_pt_io *)addr + port; + + if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) + goto out; + + /* + if (tp->t_outq.c_cc <= TTLOWAT(tp)) { + ttwakeup(tp); + } + */ + + if (tp->t_outq.c_cc != 0) { + + tp->t_state |= TS_BUSY; + + /* load transmitter until it is full */ + while (ptaddr->read.rd_sr & TXRDY) { + c = getc(&tp->t_outq); + + if (tp->t_flags & CS8 || c <= 0177) { + + dprintf(("dartstart: writing char \"%c\" (0x%02x)\n", + c & 0xff, c % 0xff)); + ptaddr->write.wr_tb = c & 0xff; + + dprintf(("dartstart: enabling Tx int\n")); + if (port == A_PORT) + dart_sv_reg.sv_imr = dart_sv_reg.sv_imr | ITXRDYA; + else + dart_sv_reg.sv_imr = dart_sv_reg.sv_imr | ITXRDYB; + addr -> write.wr_imr = dart_sv_reg.sv_imr; + } else { + tp->t_state &= ~TS_BUSY; + dprintf(("dartxint: timing out char \"%c\" (0x%02x)\n", + c & 0xff, c % 0xff)); + ttrstrt(tp); + tp->t_state |= TS_TIMEOUT; + } + } + } + + out: + return; +} + +/* + * To be called at spltty - tty already locked. + */ +int +dartstop(tp, flag) +struct tty *tp; +int flag; +{ + int s; + + if (tp->t_state & TS_BUSY) { + if ((tp->t_state & TS_TTSTOP) == 0) + tp->t_state |= TS_FLUSH; + } + return 0; +} + +#define HANDLE_FLAG(_FLAG_, _PORT_, _AFLAG_, _BFLAG_) \ + if (flags & (_FLAG_)) \ + { newflags |= ((_PORT_) == A_PORT) ? (_AFLAG_) : (_BFLAG_); \ + flags &= ~(_FLAG_); } + +#define HOW2STR(_OP_) \ + ((_OP_) == DMGET) ? "GET" : \ + (((_OP_) == DMSET) ? "FORCE" : \ + ((((_OP_) == DMBIS) ? "SET" : \ + (((((_OP_) == DMBIC) ? "CLR" : "???")))))) + +#define FLAGSTRING \ + "\20\1LE\2DTR\3RTS\4ST\5SR\6CTS\7CAR\10RNG\11DSR\12BRK" + +/* + * To be called at spltty - tty already locked. + * Returns status of carrier. + */ + +int +dartmctl (dev, flags, how) +dev_t dev; +int flags; +int how; +{ + union dartreg *addr; + int port; + unsigned int dcdstate; + int newflags = 0; + struct dart_info *dart; + struct dartsoftc *sc; + + if (port = DART_PORT(dev) > 1) { + return (ENODEV); + } + sc = (struct dartsoftc *) dart_cd.cd_devs[0]; + dart = &sc->sc_dart[port]; + addr = sc->dart_reg; + + /* special case: set or clear break */ + if (flags & TIOCSBRK) { + dartbreak(port, 1); + flags &= ~TIOCSBRK; + } + if (flags & TIOCCBRK) { + dartbreak(port, 0); + flags &= ~TIOCCBRK; + } + + HANDLE_FLAG(TIOCM_DTR, port, OPDTRA, OPDTRB); + HANDLE_FLAG(TIOCM_RTS, port, OPRTSA, OPRTSB); + +#if 0 + if (flags) { + printf("dartmctl: currently only BRK, DTR and RTS supported\n"); + printf("dartmctl: op=%s flags left = 0x%b\n", + HOW2STR(how), flags, FLAGSTRING); + panic("dartmctl"); + } +#endif + dprintf(("dartmctl: action=%s flags=0x%x\n", + HOW2STR(how), newflags)); + + switch (how) { + case DMSET: + addr->write.wr_oprset = newflags; + addr->write.wr_oprreset = ~newflags; + break; + case DMBIS: + addr->write.wr_oprset = newflags; + break; + case DMBIC: + addr->write.wr_oprreset = newflags; + break; + case DMGET: + panic("dartmctl: DMGET not supported (yet)\n"); + break; + } + + /* read DCD input */ + /* input is inverted at port */ + dcdstate = !(addr->read.rd_ip & ((port == A_PORT) ? IPDCDA : IPDCDB)); + + dprintf(("dartmctl: DCD is %s\n", dcdstate ? "up" : "down")); + + return dcdstate; +} + +/* + * To be called at spltty - tty already locked. + */ +void +dartbreak(dev_t dev, int state) +{ + union dartreg *addr; + union dart_pt_io *ptaddr; + int port; + struct dart_info *dart; + struct dartsoftc *sc; + + dprintf(("dartbreak: break %s\n", (state == 1) ? "on" : "off")); + + port = DART_PORT(dev); + sc = (struct dartsoftc *) dart_cd.cd_devs[0]; + dart = &sc->sc_dart[port]; + addr = sc->dart_reg; + + ptaddr = (union dart_pt_io *) addr + port; + + if (state == 1) { + /* the duart must be enabled with a dummy byte, + to prevent the transmitter empty interrupt */ + ptaddr->write.wr_cr = BRKSTART|TXEN; + ptaddr->write.wr_tb = 0; + } else { + ptaddr->write.wr_cr = BRKSTOP; /* stop a break*/ + } + + return; +} + +int dartioctl (dev, cmd, data, flag, p) + dev_t dev; + int cmd; + caddr_t data; + int flag; + struct proc *p; +{ + int error; + int port; + struct tty *tp; + struct dart_info *dart; + struct dartsoftc *sc; + port = DART_PORT(dev); + sc = (struct dartsoftc *) dart_cd.cd_devs[0]; + dart = &sc->sc_dart[port]; + tp = dart->tty; + if (!tp) + return ENXIO; + + error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); + if (error >= 0) + return(error); + + error = ttioctl(tp, cmd, data, flag, p); + if (error >= 0) + return(error); + + switch (cmd) { + case TIOCSBRK: + /* */ + break; + + case TIOCCBRK: + /* */ + break; + + case TIOCSDTR: + (void) dartmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS); + break; + + case TIOCCDTR: + (void) dartmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC); + break; + + case TIOCMSET: + (void) dartmctl(dev, *(int *) data, DMSET); + break; + + case TIOCMBIS: + (void) dartmctl(dev, *(int *) data, DMBIS); + break; + + case TIOCMBIC: + (void) dartmctl(dev, *(int *) data, DMBIC); + break; + + case TIOCMGET: +/* *(int *)data = dartmctl(dev, 0, DMGET);*/ + break; + case TIOCGFLAGS: + *(int *)data = dart->dart_swflags; + break; + case TIOCSFLAGS: + error = suser(p->p_ucred, &p->p_acflag); + if (error != 0) + return(EPERM); + + dart->dart_swflags = *(int *)data; + dart->dart_swflags &= /* only allow valid flags */ + (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS); + break; + default: + return(ENOTTY); + } + + return 0; +} + +/* + * To be called at spltty - tty already locked. + */ +int +dartparam(tp, t) +struct tty *tp; +struct termios *t; +{ + union dartreg *addr; + union dart_pt_io *ptaddr; + int flags; + int port; + int speeds; + unsigned char mr1, mr2; + struct dart_info *dart; + struct dartsoftc *sc; + dev_t dev; + + dprintf(("dartparam: setting param for dev %d\n", dev)); + + dev = tp->t_dev; + if (port = DART_PORT(dev) > 1) { + return (ENODEV); + } + + sc = (struct dartsoftc *) dart_cd.cd_devs[0]; + dart = &sc->sc_dart[port]; + addr = sc->dart_reg; + ptaddr = (union dart_pt_io *) addr + port; + tp->t_ispeed = t->c_ispeed; + tp->t_ospeed = t->c_ospeed; + tp->t_cflag = t->c_cflag; + + flags = tp->t_flags; + + /* Reset to make global changes*/ + /* disable Tx and Rx */ + dprintf(("dartparam: disabling Tx and Rx int\n")); + + if (port == A_PORT) + dart_sv_reg.sv_imr = dart_sv_reg.sv_imr & ~(ITXRDYA | IRXRDYA); + else + dart_sv_reg.sv_imr = dart_sv_reg.sv_imr & ~(ITXRDYB | IRXRDYB); + addr -> write.wr_imr = dart_sv_reg.sv_imr; + + /* hang up on zero baud rate */ + if (tp->t_ispeed == 0) { + dprintf(("dartparam: ispeed == 0 -> HUP\n")); + dartmctl(tp, HUPCL, DMSET); + return; + } else { + /* set baudrate */ + speeds = dart_speeds[(unsigned char)tp->t_ispeed]; + if (speeds == NOBAUD) + speeds = dart_sv_reg.sv_csr[port]; + ptaddr->write.wr_csr = speeds; + dart_sv_reg.sv_csr[port] = speeds; + dprintf(("dartparam: baudrate set param = %d\n", speeds)); + } + + /* get saved mode registers and clear set up parameters */ + mr1 = dart_sv_reg.sv_mr1[port]; + mr1 &= ~(CLMASK | PARTYPEMASK | PARMODEMASK); + + mr2 = dart_sv_reg.sv_mr2[port]; + mr2 &= ~SBMASK; + + /* set up character size */ + if (flags & CS8) { + mr1 |= CL8; + dprintf(("dartparam: PASS8\n")); + } else if (tp->t_ispeed == B134) { + mr1 |= CL6; + dprintf(("dartparam: CS6\n")); + } else { + mr1 |= CL7; + dprintf(("dartparam: CS7\n")); + } + + /* set up stop bits */ + if (tp->t_ospeed == B110) { + mr2 |= SB2; + dprintf(("dartparam: two stop bits\n")); + } else { + mr2 |= SB1; + dprintf(("dartparam: one stop bit\n")); + } + + /* set up parity */ + if (((flags & PARENB) != PARENB) && + (flags & PARENB)) { + mr1 |= PAREN; + if (flags & PARODD) { + mr1 |= ODDPAR; + dprintf(("dartparam: odd parity\n")); + } else { + mr1 |= EVENPAR; + dprintf(("dartparam: even parity\n")); + } + } else { + mr1 |= PARDIS; + dprintf(("dartparam: no parity\n")); + } + + if ((dart_sv_reg.sv_mr1[port] != mr1) + || (dart_sv_reg.sv_mr2[port] != mr2)) { + /* write mode registers to duart */ + ptaddr->write.wr_cr = MRRESET; + ptaddr->write.wr_mr = mr1; + ptaddr->write.wr_mr = mr2; + + /* save changed mode registers */ + dart_sv_reg.sv_mr1[port] = mr1; + dart_sv_reg.sv_mr2[port] = mr2; + } + + /* enable transmitter? */ + if (tp->t_state & TS_BUSY) { + dprintf(("dartparam: reenabling Tx int\n")); + + if (port == A_PORT) + dart_sv_reg.sv_imr = dart_sv_reg.sv_imr | ITXRDYA; + else + dart_sv_reg.sv_imr = dart_sv_reg.sv_imr | ITXRDYB; + addr -> write.wr_imr = dart_sv_reg.sv_imr; + } else { + dprintf(("dartparam: not enabling Tx\n")); + } + + /* re-enable the receiver */ + dprintf(("dartparam: reenabling Rx int\n")); + + DELAY_CR; + if (port == A_PORT) + dart_sv_reg.sv_imr = dart_sv_reg.sv_imr | IRXRDYA; + else + dart_sv_reg.sv_imr = dart_sv_reg.sv_imr | IRXRDYB; + addr -> write.wr_imr = dart_sv_reg.sv_imr; + + return 0; +} + +void +dartmodemtrans(sc, ip, ipcr) + struct dartsoftc *sc; + unsigned int ip; + unsigned int ipcr; +{ + unsigned int dcdstate; + struct tty *tp; + int port; + struct dart_info *dart; + + dprintf(("dartmodemtrans: ip=0x%x ipcr=0x%x\n", + ip, ipcr)); + + /* input is inverted at port!!! */ + if (ipcr & IPCRDCDA) { + port = A_PORT; + dcdstate = !(ip & IPDCDA); + } else if (ipcr & IPCRDCDB) { + port = B_PORT; + dcdstate = !(ip & IPDCDB); + } else { + printf("dartmodemtrans: unknown transition:\n"); + printf("dartmodemtrans: ip=0x%x ipcr=0x%x\n", + ip, ipcr); + panic("dartmodemtrans"); + } + dart = &sc->sc_dart[port]; + tp = dart->tty; + + dprintf(("dartmodemtrans: tp=0x%x new DCD state: %s\n", + tp, dcdstate ? "UP" : "DOWN")); + (void) ttymodem(tp, dcdstate); +} + +int dartopen (dev, flag, mode, p) +dev_t dev; +int flag; +int mode; +struct proc *p; +{ + int s, port; + struct dart_info *dart; + struct dartsoftc *sc; + struct tty *tp; + + if (port = DART_PORT(dev) > 1) { + return (ENODEV); + } + sc = (struct dartsoftc *) dart_cd.cd_devs[0]; + dart = &sc->sc_dart[port]; + s = spldart(); + + if (dart->tty) { + tp = dart->tty; + } else { + tp = dart->tty = ttymalloc(); + simple_lock_init(&dart->t_lock); + } + + simple_lock(&dart->t_lock); + tp->t_oproc = dartstart; + tp->t_param = dartparam; + tp->t_dev = dev; + + if ((tp->t_state & TS_ISOPEN) == 0) { + ttychars(tp); + tp->t_iflag = TTYDEF_IFLAG; + tp->t_oflag = TTYDEF_OFLAG; + tp->t_lflag = TTYDEF_LFLAG; + tp->t_ispeed = tp->t_ospeed = B9600; + dartparam(tp, &tp->t_termios); + if (port == 0) { + /* console is 8N1 */ + tp->t_cflag = (CREAD | CS8 | HUPCL); + } else { + tp->t_cflag = TTYDEF_CFLAG; + } + ttsetwater(tp); + (void)dartmctl(dev, TIOCM_DTR | TIOCM_RTS, DMSET); + tp->t_state |= TS_CARR_ON; + } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { + splx(s); + simple_unlock(&dart->t_lock); + return (EBUSY); + } + /* + * Reset the tty pointer, as there could have been a dialout + * use of the tty with a dialin open waiting. + */ + tp->t_dev = dev; + simple_unlock(&dart->t_lock); + splx(s); + return ((*linesw[tp->t_line].l_open)(dev, tp)); +} + +int dartclose (dev, flag, mode, p) +dev_t dev; +int flag; +int mode; +struct proc *p; +{ + int unit, channel; + struct tty *tp; + struct dart_info *dart; + struct dartsoftc *sc; + int s, port; + + if (port = DART_PORT(dev) > 1) { + return (ENODEV); + } + sc = (struct dartsoftc *) dart_cd.cd_devs[0]; + dart = &sc->sc_dart[port]; + tp = dart->tty; + (*linesw[tp->t_line].l_close)(tp, flag); + + s = spldart(); + ttyclose(tp); + splx(s); + return 0; +} + +int dartread (dev, uio, flag) +dev_t dev; +struct uio *uio; +int flag; +{ + int unit, port; + struct tty *tp; + struct dart_info *dart; + struct dartsoftc *sc; + + if (port = DART_PORT(dev) > 1) { + return (ENODEV); + } + sc = (struct dartsoftc *) dart_cd.cd_devs[0]; + dart = &sc->sc_dart[port]; + tp = dart->tty; + + if (!tp) + return ENXIO; + return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); +} + +int dartwrite (dev, uio, flag) +dev_t dev; +struct uio *uio; +int flag; +{ + int port; + struct tty *tp; + struct dart_info *dart; + struct dartsoftc *sc; + + if (port = DART_PORT(dev) > 1) { + return (ENODEV); + } + sc = (struct dartsoftc *)dart_cd.cd_devs[0]; + dart = &sc->sc_dart[port]; + + tp = dart->tty; + if (!tp) + return ENXIO; + return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); +} + +void +dartrint(sc, port) +struct dartsoftc *sc; +int port; +{ + union dartreg *addr; + union dart_pt_io *ptaddr; + struct tty *tp; + unsigned char data, sr; + struct dart_info *dart; + + dart = &sc->sc_dart[port]; + addr = sc->dart_reg; + + /* read status reg */ + ptaddr = (union dart_pt_io *) addr + port; + + dprintf(("dartrint: Rx int dev %d\n", dev)); + + tp = dart->tty; + + dprintf(("dartrint: ptaddr = 0x%08x from uart at 0x%08x\n", + ptaddr, addr)); + + while ((sr = ptaddr->read.rd_sr) & RXRDY) { + dprintf(("dartrint: sr = 0x%08x\n", sr)); + + data = ptaddr->read.rd_rb; /* read data and reset receiver */ + + dprintf(("dartrint: read char \"%c\" (0x%02x) tp = 0x%x\n", + data, data, tp)); + + if ((tp->t_state & (TS_ISOPEN|TS_WOPEN)) == 0){ + return; + } + + if (sr & RBRK) { + dprintf(("dartrint: BREAK detected\n")); + /* + data = tp->t_breakc; + ttyinput(data, tp); + */ + /* clear break state */ + ptaddr->write.wr_cr = BRKINTRESET; + DELAY_CR; + ptaddr->write.wr_cr = ERRRESET; + +#if DDB_XXX + if (ddb_break_mode & DDB_ENTER_BREAK) { + dprintf(("dartrint: break detected - entering debugger\n")); + gimmeabreak(); + } +#endif + } else { + if (sr & (FRERR|PERR|ROVRN)) { /* errors */ + if (sr & ROVRN) + printf("dart0: receiver overrun port %c\n", 'A' + port); + if (sr & FRERR) + printf("dart0: framing error port %c\n", 'A' + port); + if (sr & PERR) + printf("dart0: parity error port %c\n", 'A' + port); + dprintf(("dartrint: error received\n")); + /* clear error state */ + ptaddr->write.wr_cr = ERRRESET; + } else { + /* no errors */ +#if DDB_XXX + if ((ddb_break_mode & DDB_ENTER_CHAR) && (ddb_break_char == data)) { + dprintf(("dartrint: ddb_break_char detected - entering debugger\n")); + gimmeabreak(); + } else +#endif + { + if (tp->t_ispeed == B134) /* CS6 */ + data &= 077; +#if 0 /* XXX ??? */ + else if (tp->t_flags & (RAW|LITOUT|PASS8)) /*CS8*/ + ; +#endif + else + data &= 0177; /* CS7 */ + ttyinput(data, tp); + } + } + } + } + dprintf(("dartrint: ready\n")); +} + +void +dartxint(sc, port) +struct dartsoftc *sc; +int port; +{ + struct tty *tp; + struct dart_info *dart; + union dartreg *addr; + dev_t dev; + + dart = &sc->sc_dart[port]; + addr = sc->dart_reg; + + tp = dart->tty; + + simple_lock(&dart->t_lock); + + if ((tp->t_state & (TS_ISOPEN|TS_WOPEN))==0) + goto out; + + if (tp->t_state & TS_FLUSH) + tp->t_state &= ~TS_FLUSH; + + if (tp->t_state & TS_BUSY) { + tp->t_state &= ~TS_BUSY; + dprintf(("dartxint: starting output\n")); + dartstart(tp); + if (tp->t_state & TS_BUSY) { + dprintf(("dartxint: ready - Tx left enabled\n")); + simple_unlock(&dart->t_lock); + return; + } + } + out: + + /* disable transmitter */ + if (port == 0) + dart_sv_reg.sv_imr = dart_sv_reg.sv_imr & ~ITXRDYA; + else + dart_sv_reg.sv_imr = dart_sv_reg.sv_imr & ~ITXRDYB; + + addr->write.wr_imr = dart_sv_reg.sv_imr; + + simple_unlock(&dart->t_lock); + + dprintf(("dartxint: ready - Tx disabled\n")); + + return; +} + +int +dartintr(sc) +struct dartsoftc *sc; +{ + unsigned char isr; + unsigned char sr; + int port; + union dartreg *addr; + + /* read interrupt status register and mask with imr */ + addr = sc->dart_reg; + + isr = addr->read.rd_isr; + isr &= dart_sv_reg.sv_imr; + + if (isr) { /* interrupt from this duart */ + if (isr & IIPCHG) { + unsigned int ip = addr->read.rd_ip; + unsigned int ipcr = addr->read.rd_ipcr; + dartmodemtrans(sc, ip, ipcr); + return 0; + } + + if (isr & (IRXRDYA | ITXRDYA)) + port = 0; + else + if (isr & (IRXRDYB | ITXRDYB)) + port = 1; + else { + printf("dartintr: spurious interrupt, isr 0x%08x\n", isr); + panic("dartintr"); + } + + dprintf(("dartintr: interrupt from port %d, isr 0x%08x\n", + port, isr)); + + if (isr & (IRXRDYA | IRXRDYB)) { + dprintf(("dartintr: Rx interrupt\n")); + dartrint(sc, port); + } + if (isr & (ITXRDYA | ITXRDYB)) { + dprintf(("dartintr: Tx interrupt\n")); + dartxint(sc, port); + } + if (((port == A_PORT) && (isr & IBRKA)) + || ((port == B_PORT) && (isr & IBRKB))) { + union dart_pt_io *ptaddr = + (union dart_pt_io *)addr + port; + + dprintf(("dartintr: clearing end of BREAK state\n")); + ptaddr->write.wr_cr = BRKINTRESET; + } + } + dprintf(("dartintr: ready\n")); + return 1; +} + +/* + * Console interface routines. Currently only dev 0 or 1 + * supported. + */ + +int +dartcnprobe(cp) +struct consdev *cp; +{ + int maj; + + if (cputyp != CPU_188){ + cp->cn_pri = CN_DEAD; + return 0; + } + /* locate the major number */ + for (maj = 0; maj < nchrdev; maj++) + if (cdevsw[maj].d_open == dartopen) + break; + + cp->cn_dev = makedev(maj, 0); + cp->cn_pri = CN_NORMAL; + return (1); +} + +int +dartcninit(cp) +struct consdev *cp; +{ + /* Nothing to do */ +} + +int +dartcnputc(dev, c) +dev_t dev; +char c; +{ + union dartreg *addr; + union dart_pt_io *ptaddr; + m88k_psr_type psr; + + addr = (union dartreg *) MVME188_DUART; + + ptaddr = (union dart_pt_io *) addr + ((dev & 1) ? 1 : 0); + + psr = disable_interrupts_return_psr(); + + /* Assume first port initialized if we get here. */ + /* Assume the bug initializes the port */ + + /* inhibit interrupts on the chip */ + addr->write.wr_imr = dart_sv_reg.sv_imr & ~ITXRDYA; + /* make sure transmitter is enabled */ + DELAY_CR; + ptaddr->write.wr_cr = TXEN; + + /* If the character is a line feed(\n) */ + /* then follow it with carriage return (\r) */ + for (;;) { + while (!(ptaddr->read.rd_sr & TXRDY)) + ; + ptaddr->write.wr_tb = c; + if (c != '\n') + break; + c = '\r'; + } + + /* wait for transmitter to empty */ + while (!(ptaddr->read.rd_sr & TXEMT)) + ; + + /* restore the previous state */ + addr->write.wr_imr = dart_sv_reg.sv_imr; + DELAY_CR; + ptaddr->write.wr_cr = dart_sv_reg.sv_cr[0]; + + set_psr(psr); + + return; +} + +int +dartcngetc(dev) +dev_t dev; +{ + union dartreg *addr; /* pointer to DUART regs */ + union dart_pt_io *ptaddr; /* pointer to port regs */ + unsigned char sr; /* status reg of port a/b */ + int c; /* received character */ + m88k_psr_type psr; + char buf[] = "char x"; + + psr = disable_interrupts_return_psr(); + + addr = (union dartreg *) DART_BASE; + ptaddr = (union dart_pt_io *) addr + ((dev & 1) ? 1 : 0); + + /* enable receiver */ + ptaddr->write.wr_cr = RXEN; + + do { + /* read status reg */ + sr = ptaddr->read.rd_sr; + + /* receiver interrupt handler*/ + if (sr & RXRDY) { + /* read character from port */ + c = ptaddr->read.rd_rb; + + /* check break condition */ + if (sr & RBRK) { + /* clear break state */ + ptaddr->write.wr_cr = BRKINTRESET; + DELAY_CR; + ptaddr->write.wr_cr = ERRRESET; + set_psr(psr); + return c; + } + + if (sr & (FRERR|PERR|ROVRN)) { + /* clear error state */ + ptaddr->write.wr_cr = ERRRESET; + DELAY_CR; + ptaddr->write.wr_cr = BRKINTRESET; + } else { + buf[5] = (char) c; + + set_psr(psr); + return (c & 0x7f); + } + } + } while (-1); + + set_psr(psr); + + return -1; +} diff --git a/sys/arch/mvme88k/dev/dartreg.h b/sys/arch/mvme88k/dev/dartreg.h new file mode 100644 index 00000000000..10d996a172d --- /dev/null +++ b/sys/arch/mvme88k/dev/dartreg.h @@ -0,0 +1,311 @@ +/* + * Something to put append a 'U' to a long constant if it's C so that + * it'll be unsigned in both ANSI and traditional. + */ +#if defined(ASSEMBLER) +# define U(num) num +#else +# if defined(__STDC__) +# define U(num) num ## U +# else +# define U(num) num/**/U +# endif +#endif + +/*********************** CONFIGURATION *******************************/ +#define MAXPORTS 2 /* max count of PORTS/DUART */ + +/* + * The following define is for the utputc/utgetc Console routines + * which have to work without any configuration. + */ +#define MVME188_DUART U(0xFFF82000) /* M68692 DUART chip */ + +/*********************** DEFINITIONS *********************************/ +#define MISSING 0 /* flag, missing a configured DUART */ +#define ON 1 /* flag for modem() */ +#define OFF 0 /* flag for modem() */ +#define A_PORT 0 /* flag for port a */ +#define B_PORT 1 /* flag for port b */ + +/*********************** MACROS ***********************************/ +/* + * spl priority level should always be the same. + */ +#define SPLCLOCK spl6 /* set clock priority level */ +#define SPLM681 splhi /* set ut driver priority level */ + +/* the access to the same command register must be delayed, + because the chip has some hardware problems in this case */ +#define DELAY_CR { volatile register i; for ( i=0; i<250; ++i ); } + +/*********************** MC68681 DEFINITIONS ************************/ +#define PORTOFFSET 0x10 /* offset for port b address space */ + +/* mode register 1: MR1x operations */ +#define RXRTS 0x80 /* enable receiver RTS */ +#define PAREN 0x00 /* with parity */ +#define PARDIS 0x10 /* no parity */ +#define EVENPAR 0x00 /* even parity */ +#define ODDPAR 0x04 /* odd parity */ +#define CL5 0x00 /* 5 bits per char */ +#define CL6 0x01 /* 6 bits per char */ +#define CL7 0x02 /* 7 bits per char */ +#define CL8 0x03 /* 8 bits per char */ +#define PARMODEMASK 0x18 /* parity mode mask */ +#define PARTYPEMASK 0x04 /* parity type mask */ +#define CLMASK 0x03 /* character length mask */ + +/* mode register 2: MR2x operations */ +#define TXRTS 0x20 /* enable transmitter RTS */ +#define TXCTS 0x10 /* enable transmitter CTS */ +#define SB2 0x0f /* 2 stop bits */ +#define SB1 0x07 /* 1 stop bit */ +#define SB1L5 0x00 /* 1 stop bit at 5 bits per character */ + +#define SBMASK 0x0f /* stop bit mask */ + +/* clock-select register: CSRx operations */ +#define NOBAUD -1 /* 50 and 200 baud are not possible */ +/* they are not in Baud register set 2 */ +#define BD75 0x00 /* 75 baud */ +#define BD110 0x11 /* 110 baud */ +#define BD134 0x22 /* 134.5 baud */ +#define BD150 0x33 /* 150 baud */ +#define BD300 0x44 /* 300 baud */ +#define BD600 0x55 /* 600 baud */ +#define BD1200 0x66 /* 1200 baud */ +#define BD1800 0xaa /* 1800 baud */ +#define BD2400 0x88 /* 2400 baud */ +#define BD4800 0x99 /* 4800 baud */ +#define BD9600 0xbb /* 9600 baud */ +#define BD19200 0xcc /* 19200 baud */ + +#define DEFBAUD BD9600 /* default value if baudrate is not possible */ + + +/* channel command register: CRx operations */ +#define MRRESET 0x10 /* reset mr pointer to mr1 */ +#define RXRESET 0x20 /* reset receiver */ +#define TXRESET 0x30 /* reset transmitter */ +#define ERRRESET 0x40 /* reset error status */ +#define BRKINTRESET 0x50 /* reset channel's break interrupt */ +#define BRKSTART 0x60 /* start break */ +#define BRKSTOP 0x70 /* stop break */ +#define TXDIS 0x08 /* disable transmitter */ +#define TXEN 0x04 /* enable transmitter */ +#define RXDIS 0x02 /* disable receiver */ +#define RXEN 0x01 /* enable receiver */ + +/* status register: SRx status */ +#define RBRK 0x80 /* received break */ +#define FRERR 0x40 /* frame error */ +#define PERR 0x20 /* parity error */ +#define ROVRN 0x10 /* receiver overrun error */ +#define TXEMT 0x08 /* transmitter empty */ +#define TXRDY 0x04 /* transmitter ready */ +#define FFULL 0x02 /* receiver FIFO full */ +#define RXRDY 0x01 /* receiver ready */ + +/* output port configuration register: OPCR operations */ +#define OPSET 0x00 /* set all op lines to op function */ +#define OPSETTO 0x04 /* use OP3 for timer output */ + +/* output port register: OP operations */ +#define OPDTRB 0x20 /* DTR line output b on the VME188, 181, 141 */ +#define OPDTRA 0x04 /* DTR line output a */ +#define OPRTSB 0x02 /* RTS line output b */ +#define OPRTSA 0x01 /* RTS line output a */ + +/* auxiliary control register: ACR operations */ +#define BDSET1 0x00 /* baudrate generator set 1 */ +#define BDSET2 0x80 /* baudrate generator set 2 */ +#define CCLK1 0x60 /* timer clock: external rate. TA */ +#define CCLK16 0x30 /* counter clock: x1 clk divided by 16 */ +#define SLCTIM 0x7800/* timer count to get 60 Hz time slice (16.6ms ticks) */ +#define IPDCDIB 0x08 /* IP3 change == DCD input on port B */ +#define IPDCDIA 0x04 /* IP2 change == DCD input on port A */ + +/* input port change register: IPCR operations */ +#define IPCRDCDB 0x80 /* IP3 change == DCD change on port B */ +#define IPCRDCDA 0x40 /* IP2 change == DCD change on port A */ + +/* Defines for mvme335 */ +#define IPDCDB 0x20 /* DCD line input b */ +#define IPDCDA 0x10 /* DCD line input a */ + +#define IPDSRB 0x08 /* DSR line input b */ +#define IPDSRA 0x04 /* DSR line input a */ +#define IPCTSB 0x02 /* CTS line input b */ +#define IPCTSA 0x01 /* CTS line input a */ + +/* interrupt status and mask register: ISR status and IMR mask */ +#define IIPCHG 0x80 /* input port change */ +#define IBRKB 0x40 /* delta break b */ +#define IRXRDYB 0x20 /* receiver ready b */ +#define ITXRDYB 0x10 /* transmitter ready b */ +#define ITIMER 0x08 /* Enable timer interrupts. */ +#define IBRKA 0x04 /* delta break a */ +#define IRXRDYA 0x02 /* receiver ready a */ +#define ITXRDYA 0x01 /* transmitter ready a */ + +/* interrupts from port a or b */ +#define AINTPORT ( IRXRDYA | ITXRDYA ) +#define BINTPORT ( IRXRDYB | ITXRDYB ) + +/* HW write register index for ut_wr_regs[] */ +#define MR1A 0 /* mode register 1 a */ +#define CSRA 1 /* clock-select register a*/ +#define CRA 2 /* command register a */ +#define TBA 3 /* transmitter buffer a */ +#define ACR 4 /* auxialiary control register*/ +#define IMR 5 /* interrupt mask register */ +#define CTUR 6 /* counter/timer upper reg */ +#define CTLR 7 /* counter/timer lower reg */ +#define MR1B 8 /* mode register 1 b */ +#define CSRB 9 /* clock-select register b*/ +#define CRB 10 /* command register b */ +#define TBB 11 /* transmitter buffer b */ +#define IVR 12 /* interrupt vector register */ +#define OPCR 13 /* output port config reg */ +#define OPRSET 14 /* output port: bit set cmd */ +#define OPRRESET 15 /* output port: bit reset cmd */ +#define MR2A 16 /* mode register 2 a */ +#define MR2B 17 /* mode register 2 b */ +#define MAXREG 18 /* max count of registers */ + +/* + * Structure of MC68681 hardware read registers. + */ +struct dart_rd_reg +{ + volatile unsigned int rd_mra; /* mode register a */ + volatile unsigned int rd_sra; /* status register a*/ + volatile unsigned int dummy5; /* do not access */ + volatile unsigned int rd_rba; /* receiver buffer a */ + volatile unsigned int rd_ipcr; /* input port change register */ + volatile unsigned int rd_isr; /* interrupt status register */ + volatile unsigned int rd_cur; /* current MSB of counter */ + volatile unsigned int rd_clr; /* current LSB of counter */ + volatile unsigned int rd_mrb; /* mode register b */ + volatile unsigned int rd_srb; /* status register b*/ + volatile unsigned int dummyxb; /* do not access */ + volatile unsigned int rd_rbb; /* receiver buffer b */ + volatile unsigned int rd_ivr; /* interrupt vector register */ + volatile unsigned int rd_ip; /* input port (unlatched) */ + volatile unsigned int rd_ctstart; /* start-counter command */ + volatile unsigned int rd_ctstop; /* stop-counter command */ +}; + +/* + * Structure of MC68681 hardware write registers. + */ +struct dart_wr_reg +{ + volatile unsigned int wr_mra; /* mode register a */ + volatile unsigned int wr_csra; /* clock-select register a*/ + volatile unsigned int wr_cra; /* command register a */ + volatile unsigned int wr_tba; /* transmitter buffer a */ + volatile unsigned int wr_acr; /* auxialiary control register*/ + volatile unsigned int wr_imr; /* interrupt mask register */ + volatile unsigned int wr_ctur; /* counter/timer upper reg */ + volatile unsigned int wr_ctlr; /* counter/timer lower reg */ + volatile unsigned int wr_mrb; /* mode register b */ + volatile unsigned int wr_csrb; /* clock-select register b*/ + volatile unsigned int wr_crb; /* command register b */ + volatile unsigned int wr_tbb; /* transmitter buffer b */ + volatile unsigned int wr_ivr; /* interrupt vector register */ + volatile unsigned int wr_opcr; /* output port config reg */ + volatile unsigned int wr_oprset; /* output port: bit set cmd */ + volatile unsigned int wr_oprreset;/* output port: bit reset cmd */ +}; + +union dartreg { + struct dart_rd_reg read; /* read registers */ + struct dart_wr_reg write; /* write registers */ +}; + +/* + * Structure of MC68681 hardware port dependent read registers. + */ +struct dart_prd_reg +{ + volatile unsigned int rd_mr; /* mode register */ + volatile unsigned int rd_sr; /* status register */ + volatile unsigned int dummy5; + volatile unsigned int rd_rb; /* receiver buffer */ + volatile unsigned int dummy9; + volatile unsigned int dummy11; + volatile unsigned int dummy13; + volatile unsigned int dummy15; +}; + +/* + * Structure of MC68681 hardware port dependent write registers. + */ +struct dart_pwr_reg +{ + volatile unsigned int wr_mr; /* mode register */ + volatile unsigned int wr_csr; /* clock-select register */ + volatile unsigned int wr_cr; /* command register */ + volatile unsigned int wr_tb; /* transmitter buffer */ + volatile unsigned int dummy9; + volatile unsigned int dummy11; + volatile unsigned int dummy13; + volatile unsigned int dummy15; +}; + +union dart_pt_io { + struct dart_prd_reg read; /* read registers */ + struct dart_pwr_reg write; /* write registers */ +}; + +/* + * Structure of saved registers + */ +struct dart_sv_reg +{ + volatile unsigned char sv_mr1[MAXPORTS]; /* mode register 1 a */ + volatile unsigned char sv_mr2[MAXPORTS]; /* mode register 2 a */ + volatile unsigned char sv_csr[MAXPORTS]; /* clock-select register a*/ + volatile unsigned char sv_cr[MAXPORTS]; /* command register a */ + volatile unsigned char sv_acr; /* auxialiary control register*/ + volatile unsigned char sv_imr; /* interrupt mask register */ + volatile unsigned char sv_ivr; /* interrupt vector register */ +}; + +/* defines for receiver and DCD scanner */ +#define M681CSCAN 2 /* clock ticks for character scan */ +#define M681_CHAR 01 /* character arrived flag (ut_work) */ +#define M681_ACT 02 /* character in buffer flag (ut_work) */ +#define M681_DCD 04 /* DCD wait flag (ut_work) */ + + +/********************* SPECIAL IOCTL COMMAND DEFINITIONS ******************/ +/* HWHAND ioctls same as in MVME331 driver */ +#define MSETHWHAND (('m'<<8)+20) /* set hardware handshake */ +#define MCLEARHWHAND (('m'<<8)+21) /* clear hardware handshake */ +#define MGETHWHAND (('m'<<8)+22) /* get hardware handshake mode */ + +#define M681STATUS (('m'<<8)+40 ) /* get status of duarts */ +#define M681GETSTAT (('m'<<8)+42 ) /* get statistics */ + +#ifdef STATISTICS +struct dart_stat { + int open_cnt; /* count of open calls */ + int intr_cnt; /* count of interrupts */ + int tx_cnt; /* count of transmitted characters */ + int rx_cnt; /* count of received characters */ + int brk_cnt; /* count of break events */ + int rovrn_cnt; /* count of overruns */ + int frerr_cnt; /* count of frame errors */ + int perr_cnt; /* count of parity errors */ + int rxoff_cnt; /* count of received XOFF chars */ + int rxon_cnt; /* count of received XON chars */ + int txoff_cnt; /* count of transmitted XOFF chars */ + int txon_cnt; /* count of transmitted XON chars */ +}; +#endif + + + diff --git a/sys/arch/mvme88k/dev/i82596.h b/sys/arch/mvme88k/dev/i82596.h new file mode 100644 index 00000000000..15ce386304f --- /dev/null +++ b/sys/arch/mvme88k/dev/i82596.h @@ -0,0 +1,310 @@ +/* $OpenBSD: i82596.h,v 1.1 1999/09/27 18:43:23 smurph Exp $ */ + +/*- + * Copyright (c) 1995 Theo de Raadt + * Copyright (c) 1992, University of Vermont and State Agricultural College. + * Copyright (c) 1992, Garrett A. Wollman. + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * Vermont and State Agricultural College and Garrett A. Wollman. + * and + * This product includes software developed under OpenBSD by + * Theo de Raadt for Willowglen Singapore. + * 4. Neither the name of the University nor the name of the author + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 UNIVERSITY OR 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. + */ + +/* + * Intel 82596 Ethernet chip + * Register, bit, and structure definitions. + * + * Written by GAW with reference to the Clarkson Packet Driver code for this + * chip written by Russ Nelson and others. + * + * Sun support added by Charles D. Cranor, 25-Oct-94 + * + * Remade for 82596 in 32 bit mode by Per Fogelstrom. + */ + +struct ie_en_addr { + u_char data[6]; +}; + +/* + * This is the master configuration block. It tells the hardware where all + * the rest of the stuff is. + */ +struct ie_sys_conf_ptr { + u_char mbz1[3]; /* must be zero */ + u_char ie_bus_use; /* true if 8-bit only */ + u_char mbz2[4]; /* must be zero */ + u_int ie_iscp_ptr; /* physaddr of ISCP */ +}; + +/* + * The tells the hardware where all the rest of the stuff is, too. + * FIXME: some of these should be re-commented after we figure out their + * REAL function. + */ +struct ie_int_sys_conf_ptr { + u_char mbz1[1]; /* must be zero */ + u_char ie_busy; /* zeroed after init */ + u_short ie_mbz2; /* must be zero */ + u_int ie_base; /* 32-bit physaddr for all vars */ +}; + +/* + * This FINALLY tells the hardware what to do and where to put it. + */ +struct ie_sys_ctl_block { + u_short ie_status; /* status word */ + u_short ie_command; /* command word */ + u_int ie_command_list; /* 32-pointer to command block list */ + u_int ie_recv_list; /* 32-pointer to receive frame list */ + u_int ie_err_crc; /* CRC errors */ + u_int ie_err_align; /* Alignment errors */ + u_int ie_err_resource; /* Resource errors */ + u_int ie_err_overrun; /* Overrun errors */ + u_int ie_err_coll; /* Receive packets collision errors */ + u_int ie_err_short; /* Short frames recived errors */ + u_short ie_off_timer; /* Bus Throttle OFF timer */ + u_short ie_on_timer; /* Bus Throttle ON timer */ +}; + +/* Command values */ +#define IE_RU_COMMAND 0x0070 /* mask for RU command */ +#define IE_RU_NOP 0 /* for completeness */ +#define IE_RU_START 0x0010 /* start receive unit command */ +#define IE_RU_ENABLE 0x0020 /* enable receiver command */ +#define IE_RU_DISABLE 0x0030 /* disable receiver command */ +#define IE_RU_ABORT 0x0040 /* abort current receive operation */ + +#define IE_CU_COMMAND 0x0700 /* mask for CU command */ +#define IE_CU_NOP 0 /* included for completeness */ +#define IE_CU_START 0x0100 /* do-command command */ +#define IE_CU_RESUME 0x0200 /* resume a suspended cmd list */ +#define IE_CU_STOP 0x0300 /* SUSPEND was already taken */ +#define IE_CU_ABORT 0x0400 /* abort current command */ +#define IE_CU_THROTTLE 0x0500 /* load new throttle valuse */ + +#define IE_ACK_COMMAND 0xf000 /* mask for ACK command */ +#define IE_ACK_CX 0x8000 /* ack IE_ST_DONE */ +#define IE_ACK_FR 0x4000 /* ack IE_ST_RECV */ +#define IE_ACK_CNA 0x2000 /* ack IE_ST_ALLDONE */ +#define IE_ACK_RNR 0x1000 /* ack IE_ST_RNR */ + +#define IE_ACTION_COMMAND(x) (((x) & IE_CU_COMMAND) == IE_CU_START) + /* is this command an action command? */ + +/* Status values */ +#define IE_ST_WHENCE 0xf000 /* mask for cause of interrupt */ +#define IE_ST_DONE 0x8000 /* command with I bit completed */ +#define IE_ST_RECV 0x4000 /* frame received */ +#define IE_ST_ALLDONE 0x2000 /* all commands completed */ +#define IE_ST_RNR 0x1000 /* receive not ready */ + +#define IE_CU_STATUS 0x700 /* mask for command unit status */ +#define IE_CU_ACTIVE 0x200 /* command unit is active */ +#define IE_CU_SUSPEND 0x100 /* command unit is suspended */ + +#define IE_RU_STATUS 0x70 /* mask for receiver unit status */ +#define IE_RU_SUSPEND 0x10 /* receiver is suspended */ +#define IE_RU_NOSPACE 0x20 /* receiver has no resources */ +#define IE_RU_READY 0x40 /* reveiver is ready */ + +/* + * This is filled in partially by the chip, partially by us. + */ +struct ie_recv_frame_desc { + u_short ie_fd_status; /* status for this frame */ + u_short ie_fd_last; /* end of frame list flag */ + u_int ie_fd_next; /* 32-pointer to next RFD */ + u_int ie_fd_buf_desc; /* 32-pointer to list of buffer desc's */ + u_short ie_fd_actual; /* Actual count */ + u_short ie_fd_size; /* Size */ + struct ie_en_addr dest; /* destination ether */ + struct ie_en_addr src; /* source ether */ + u_short ie_length; /* 802 length/Ether type */ + u_short mbz; /* must be zero */ +}; + +#define IE_FD_LAST 0x8000 /* last rfd in list */ +#define IE_FD_SUSP 0x4000 /* suspend RU after receipt */ + +#define IE_FD_COMPLETE 0x8000 /* frame is complete */ +#define IE_FD_BUSY 0x4000 /* frame is busy */ +#define IE_FD_OK 0x2000 /* frame is bad */ +#define IE_FD_RNR 0x0200 /* receiver out of resources here */ +#define IE_FD_FLEX 0x0008 /* use flexible buffer scheeme */ + +/* + * linked list of buffers... + */ +struct ie_recv_buf_desc { + u_short ie_rbd_actual; /* status for this buffer */ + u_short ie_mbz1; + u_int ie_rbd_next; /* pointer to next RBD */ + u_int ie_rbd_buffer; /* pointer to buffer for this RBD */ + u_short ie_rbd_length; /* length of the buffer */ + u_short mbz; /* must be zero */ +}; + +#define IE_RBD_LAST 0x8000 /* last buffer */ +#define IE_RBD_USED 0x4000 /* this buffer has data */ +/* + * All commands share this in common. + */ +struct ie_cmd_common { + u_short ie_cmd_status; /* status of this command */ + u_short ie_cmd_cmd; /* command word */ + u_int ie_cmd_link; /* link to next command */ +}; + +#define IE_STAT_COMPL 0x8000 /* command is completed */ +#define IE_STAT_BUSY 0x4000 /* command is running now */ +#define IE_STAT_OK 0x2000 /* command completed successfully */ +#define IE_STAT_ABORT 0x1000 /* command was aborted */ + + +#define IE_CMD_NOP 0x0000 /* NOP */ +#define IE_CMD_IASETUP 0x0001 /* initial address setup */ +#define IE_CMD_CONFIG 0x0002 /* configure command */ +#define IE_CMD_MCAST 0x0003 /* multicast setup command */ +#define IE_CMD_XMIT 0x0004 /* transmit command */ +#define IE_CMD_TDR 0x0005 /* time-domain reflectometer command */ +#define IE_CMD_DUMP 0x0006 /* dump command */ +#define IE_CMD_DIAGNOSE 0x0007 /* diagnostics command */ + +#define IE_CMD_LAST 0x8000 /* this is the last command in the list */ +#define IE_CMD_SUSPEND 0x4000 /* suspend CU after this command */ +#define IE_CMD_INTR 0x2000 /* post an interrupt after completion */ +#define IE_CMD_FLEX 0x0008 /* use flexible format */ + +/* + * This is the command to transmit a frame. + */ +struct ie_xmit_cmd { + struct ie_cmd_common com; /* common part */ +#define ie_xmit_status com.ie_cmd_status + + u_int ie_xmit_desc; /* pointer to buffer descriptor */ + u_short ie_xmit_count; /* Tcb count field */ + u_short ie_mbz1; + struct ie_en_addr ie_xmit_addr; /* destination address */ + + u_short ie_xmit_length; /* 802.3 length/Ether type field */ +}; + +#define IE_XS_MAXCOLL 0x000f /* number of collisions during transmit */ +#define IE_XS_EXCMAX 0x0020 /* exceeded maximum number of collisions */ +#define IE_XS_SQE 0x0040 /* SQE positive */ +#define IE_XS_DEFERRED 0x0080 /* transmission deferred */ +#define IE_XS_UNDERRUN 0x0100 /* DMA underrun */ +#define IE_XS_LOSTCTS 0x0200 /* Lost CTS */ +#define IE_XS_NOCARRIER 0x0400 /* No Carrier */ + +/* + * This is a buffer descriptor for a frame to be transmitted. + */ + +struct ie_xmit_buf { + u_short ie_xmit_flags; /* see below */ + u_short mbz1; /* Must be zero */ + u_int ie_xmit_next; /* pointer to next desc. */ + u_int ie_xmit_buf; /* pointer to the actual buffer */ +}; + +#define IE_XMIT_LAST 0x8000 /* this TBD is the last one */ +/* The rest of the `flags' word is actually the length. */ + +/* + * Multicast setup command. + */ + +#define MAXMCAST 250 /* must fit in transmit buffer */ + +struct ie_mcast_cmd { + struct ie_cmd_common com; /* common part */ +#define ie_mcast_status com.ie_cmd_status + + u_short ie_mcast_bytes; /* size (in bytes) of multicast addresses */ + struct ie_en_addr ie_mcast_addrs[MAXMCAST + 1]; /* space for them */ +}; + +/* + * Time Domain Reflectometer command. + */ + +struct ie_tdr_cmd { + struct ie_cmd_common com; /* common part */ +#define ie_tdr_status com.ie_cmd_status + + u_short ie_tdr_time; /* error bits and time */ + u_short ie_mbz1; +}; + +#define IE_TDR_SUCCESS 0x8000 /* TDR succeeded without error */ +#define IE_TDR_XCVR 0x4000 /* detected a transceiver problem */ +#define IE_TDR_OPEN 0x2000 /* detected an open */ +#define IE_TDR_SHORT 0x1000 /* TDR detected a short */ +#define IE_TDR_TIME 0x07ff /* mask for reflection time */ + +/* + * Initial Address Setup command + */ +struct ie_iasetup_cmd { + struct ie_cmd_common com; +#define ie_iasetup_status com.ie_cmd_status + + struct ie_en_addr ie_address; + + u_short ie_mbz1; +}; + +/* + * Configuration command + */ +struct ie_config_cmd { + struct ie_cmd_common com; /* common part */ +#define ie_config_status com.ie_cmd_status + + u_char ie_config_count; /* byte count (0x0c) */ + u_char ie_fifo; /* fifo (8) */ + u_char ie_save_bad; /* save bad frames (0x40) */ + u_char ie_addr_len; /* address length (0x2e) (AL-LOC==1) */ + u_char ie_priority; /* priority and backoff (0x0) */ + u_char ie_ifs; /* inter-frame spacing (0x60) */ + u_char ie_slot_low; /* slot time, LSB (0x0) */ + u_char ie_slot_high; /* slot time, MSN, and retries (0xf2) */ + u_char ie_promisc; /* 1 if promiscuous, else 0 */ + u_char ie_crs_cdt; /* CSMA/CD parameters (0x0) */ + u_char ie_min_len; /* min frame length (0x40) */ + u_char ie_junk; /* stuff for 82596 (0xff) */ + u_char ie_dplx; + u_char ie_miabf; +}; + diff --git a/sys/arch/mvme88k/dev/if_ie.c b/sys/arch/mvme88k/dev/if_ie.c index e8041125a1c..10ac1ef6b4b 100644 --- a/sys/arch/mvme88k/dev/if_ie.c +++ b/sys/arch/mvme88k/dev/if_ie.c @@ -1,4 +1,4 @@ -/* $Id: if_ie.c,v 1.5 1999/05/29 04:41:43 smurph Exp $ */ +/* $Id: if_ie.c,v 1.6 1999/09/27 18:43:24 smurph Exp $ */ /*- * Copyright (c) 1998 Steve Murphree, Jr. @@ -50,7 +50,7 @@ */ /* - * Intel 82586 Ethernet chip + * Intel 82596 Ethernet chip * Register, bit, and structure definitions. * * Original StarLAN driver written by Garrett Wollman with reference to the @@ -73,11 +73,11 @@ extern int etherlen; /* Mode of operation: - We run the 82586 in a standard Ethernet mode. We keep NFRAMES + We run the 82596 in a standard Ethernet mode. We keep NFRAMES received frame descriptors around for the receiver to use, and NRXBUF associated receive buffer descriptors, both in a circular list. Whenever a frame is received, we rotate both lists as - necessary. (The 586 treats both lists as a simple queue.) We also + necessary. (The 596 treats both lists as a simple queue.) We also keep a transmit command around so that packets can be sent off quickly. @@ -130,19 +130,13 @@ Mode of operation: #include <vm/vm.h> -/* - * ugly byte-order hack for SUNs - */ - -#define SWAP(x) (x) - #include <machine/autoconf.h> #include <machine/cpu.h> #include <machine/pmap.h> #include "pcctwo.h" #include <mvme88k/dev/pcctworeg.h> #include <mvme88k/dev/if_ie.h> -#include <mvme88k/dev/i82586.h> +#include <mvme88k/dev/i82596.h> #include <machine/board.h> static struct mbuf *last_not_for_us; @@ -167,42 +161,7 @@ vm_map_t ie_map; /* for obio */ #define NTXBUF 2 /* number of transmit commands */ #define IE_TBUF_SIZE ETHER_MAX_LEN /* length of transmit buffer */ - -/* - * Ethernet status, per interface. - * - * hardware addresses/sizes to know (all KVA): - * sc_iobase = base of chip's 24 bit address space - * sc_maddr = base address of chip RAM as stored in ie_base of iscp - * sc_msize = size of chip's RAM - * sc_reg = address of card dependent registers - * - * the chip uses two types of pointers: 16 bit and 24 bit - * 16 bit pointers are offsets from sc_maddr/ie_base - * KVA(16 bit offset) = offset + sc_maddr - * 24 bit pointers are offset from sc_iobase in KVA - * KVA(24 bit address) = address + sc_iobase - * - * on the vme/multibus we have the page map to control where ram appears - * in the address space. we choose to have RAM start at 0 in the - * 24 bit address space. this means that sc_iobase == sc_maddr! - * to get the phyiscal address of the board's RAM you must take the - * top 12 bits of the physical address of the register address - * and or in the 4 bits from the status word as bits 17-20 (remember that - * the board ignores the chip's top 4 address lines). - * For example: - * if the register is @ 0xffe88000, then the top 12 bits are 0xffe00000. - * to get the 4 bits from the the status word just do status & IEVME_HADDR. - * suppose the value is "4". Then just shift it left 16 bits to get - * it into bits 17-20 (e.g. 0x40000). Then or it to get the - * address of RAM (in our example: 0xffe40000). see the attach routine! - * - * on the onboard ie interface the 24 bit address space is hardwired - * to be 0xff000000 -> 0xffffffff of KVA. this means that sc_iobase - * will be 0xff000000. sc_maddr will be where ever we allocate RAM - * in KVA. note that since the SCP is at a fixed address it means - * that we have to allocate a fixed KVA for the SCP. - */ +#define CACHED_TO_PHYS(x) pmap_extract(pmap_kernel(), (vm_offset_t)(x)) struct ie_softc { struct device sc_dev; /* device structure */ @@ -217,15 +176,13 @@ struct ie_softc { struct arpcom sc_arpcom;/* system arpcom structure */ - void (*reset_586)(); /* card dependent reset function */ + void (*reset_596)(); /* card dependent reset function */ void (*chan_attn)(); /* card dependent attn function */ - void (*run_586)(); /* card depenent "go on-line" function */ + void (*run_596)(); /* card depenent "go on-line" function */ void (*memcopy) __P((const void *, void *, u_int)); /* card dependent memory copy function */ - void (*memzero) __P((void *, u_int)); + void (*memzero) __P((void *, u_int)); /* card dependent memory zero function */ - - int want_mcsetup; /* mcsetup flag */ int promisc; /* are we in promisc mode? */ @@ -252,7 +209,7 @@ struct ie_softc { volatile struct ie_recv_frame_desc *rframes[MXFRAMES]; volatile struct ie_recv_buf_desc *rbuffs[MXRXBUF]; volatile char *cbuffs[MXRXBUF]; - int rfhead, rftail, rbhead, rbtail; + int rfhead, rftail, rbhead, rbtail; volatile struct ie_xmit_cmd *xmit_cmds[NTXBUF]; volatile struct ie_xmit_buf *xmit_buffs[NTXBUF]; @@ -270,7 +227,12 @@ struct ie_softc { #ifdef IEDEBUG int sc_debug; #endif +#if NMC > 0 + struct mcreg *sc_mc; +#endif +#if NPCCTWO > 0 struct pcctworeg *sc_pcc2; +#endif }; static void ie_obreset __P((struct ie_softc *)); @@ -316,16 +278,20 @@ struct cfdriver ie_cd = { /* * address generation macros - * MK_24 = KVA -> 24 bit address in SUN byte order - * MK_16 = KVA -> 16 bit address in INTEL byte order - * ST_24 = store a 24 bit address in SUN byte order to INTEL byte order */ -#define MK_24(base, ptr) ((caddr_t)((u_long)ptr)) -#define MK_16(base, ptr) SWAP((u_short)( ((u_long)(ptr)) - ((u_long)(base)) )) -#define ST_24(to, from) { \ - u_long fval = (u_long)(from); \ - u_char *t = (u_char *)&(to), *f = (u_char *)&fval; \ - t[0] = f[2]; t[1] = f[3]; /*t[2] = f[0]*/; t[3] = f[1]; \ +/* Make 32 bit value from swapped data (err counters access) */ +#define MK_32(ptr) ((((u_int)(ptr) >> 16) & 0xffff) | ((u_int)(ptr) << 16)) + +#define MKADR_32(ptr) \ + ((caddr_t)((((u_int)(ptr) >> 16) & 0xffff) | \ + (((u_int)(ptr) << 16)) + UNCACHED_MEMORY_ADDR)) + +/* *NOTE* The next macros also converts to physical address! */ +#define ASWAP(ptr) ((((u_int)(ptr) >> 16) & 0x1fff) | ((u_int)(ptr) << 16)) + +#define SWT_32(to, from) { \ + u_int *t = (u_int *)&to; \ + *t = ((((u_int)from >> 16) & 0x1fff) | ((u_int)from << 16)); \ } /* * Here are a few useful functions. We could have done these as macros, but @@ -337,8 +303,8 @@ ie_setup_config(cmd, promiscuous, manchester) int promiscuous, manchester; { - cmd->ie_config_count = 0x0c; - cmd->ie_fifo = 8; + cmd->ie_config_count = 0x0e; + cmd->ie_fifo = 0xc8; cmd->ie_save_bad = 0x40; cmd->ie_addr_len = 0x2e; cmd->ie_priority = 0; @@ -349,6 +315,8 @@ ie_setup_config(cmd, promiscuous, manchester) cmd->ie_crs_cdt = 0; cmd->ie_min_len = 64; cmd->ie_junk = 0xff; + cmd->ie_dplx = 0x00; + cmd->ie_miabf = 0x3f; } static inline void @@ -369,11 +337,11 @@ iematch(parent, vcf, args) struct cfdata *cf = vcf; struct confargs *ca = args; int ret; - + if ((ret = badvaddr(IIOV(ca->ca_vaddr), 1)) <=0){ - return(0); + return(0); } - return (1); + return(1); } /* @@ -393,8 +361,8 @@ ie_obreset(sc) ieo->portlow = a >> 16; delay(1000); - a = (u_long)pmap_extract(pmap_kernel(), (vm_offset_t)sc->scp) | - IE_PORT_NEWSCPADDR; + a = (u_long)CACHED_TO_PHYS(sc->scp) | + IE_PORT_NEWSCPADDR; ieo->porthigh = a & 0xffff; t = 0; t = 1; ieo->portlow = a >> 16; @@ -433,23 +401,23 @@ ieattach(parent, self, aux) volatile struct ieob *ieo; vm_offset_t pa; - sc->reset_586 = ie_obreset; + sc->reset_596 = ie_obreset; sc->chan_attn = ie_obattend; - sc->run_586 = ie_obrun; + sc->run_596 = ie_obrun; sc->memcopy = bcopy; sc->memzero = bzero; sc->sc_msize = etherlen; sc->sc_reg = ca->ca_vaddr; ieo = (volatile struct ieob *) sc->sc_reg; - - /* Are we the boot device? */ - if (ca->ca_paddr == bootaddr) - bootdv = self; - + + /* Are we the boot device? */ + if (ca->ca_paddr == bootaddr) + bootdv = self; + /* get the first avaliable etherbuf */ sc->sc_maddr = etherbuf; /* maddr = vaddr */ if (sc->sc_maddr == NULL) panic("ie: too many ethernet boards"); - pa = pmap_extract(pmap_kernel(), (vm_offset_t)sc->sc_maddr); + pa = CACHED_TO_PHYS(sc->sc_maddr); if (pa == 0) panic("ie: pmap_extract"); sc->sc_iobase = (caddr_t)pa; /* iobase = paddr (24 bit) */ @@ -457,21 +425,15 @@ ieattach(parent, self, aux) (sc->memzero)(sc->sc_maddr, sc->sc_msize); sc->iscp = (volatile struct ie_int_sys_conf_ptr *) - sc->sc_maddr; /* @ location zero */ + sc->sc_maddr; /* @@ location zero */ sc->scb = (volatile struct ie_sys_ctl_block *) roundup((int)sc->iscp + sizeof(struct ie_int_sys_conf_ptr), 16); sc->scp = (struct ie_sys_conf_ptr *) roundup((int)sc->scb + sizeof(struct ie_sys_ctl_block), 16); /*printf("scpV %x iscpV %x scbV %x\n", sc->scp, sc->iscp, sc->scb);*/ - sc->scp->ie_bus_use = 0; /* 16-bit */ - ST_24(sc->scp->ie_iscp_ptr, - pmap_extract(pmap_kernel(), (vm_offset_t)sc->iscp)); - - /*printf("iscpV(%x) = iscpP(%x) -> scp.ptr@%x = val:%x\n", - sc->iscp, pmap_extract(pmap_kernel(), (vm_offset_t)sc->iscp), - &sc->scp->ie_iscp_ptr, sc->scp->ie_iscp_ptr);*/ - + sc->scp->ie_bus_use = 0x44; + SWT_32(sc->scp->ie_iscp_ptr, CACHED_TO_PHYS(sc->iscp)); /* * rest of first page is unused (wasted!), rest of ram * for buffers @@ -632,23 +594,26 @@ ierint(sc) sc->sc_arpcom.ac_if.if_ipackets++; if (!--timesthru) { sc->sc_arpcom.ac_if.if_ierrors += - SWAP(scb->ie_err_crc) + - SWAP(scb->ie_err_align) + - SWAP(scb->ie_err_resource) + - SWAP(scb->ie_err_overrun); - scb->ie_err_crc = scb->ie_err_align = - scb->ie_err_resource = scb->ie_err_overrun = - 0; + MK_32(scb->ie_err_crc) + + MK_32(scb->ie_err_align) + + MK_32(scb->ie_err_resource) + + MK_32(scb->ie_err_overrun) + + MK_32(scb->ie_err_coll) + + MK_32(scb->ie_err_short); + scb->ie_err_crc = 0; + scb->ie_err_align = 0; + scb->ie_err_resource = 0; + scb->ie_err_overrun = 0; + scb->ie_err_coll = 0; + scb->ie_err_short = 0; timesthru = 1024; } ie_readframe(sc, i); } else { if ((status & IE_FD_RNR) != 0 && (scb->ie_status & IE_RU_READY) == 0) { - sc->rframes[0]->ie_fd_buf_desc = - MK_16(sc->sc_maddr, sc->rbuffs[0]); - scb->ie_recv_list = - MK_16(sc->sc_maddr, sc->rframes[0]); + sc->rframes[0]->ie_fd_buf_desc = ASWAP(sc->rbuffs[0]); + scb->ie_recv_list = ASWAP(sc->rframes[0]); command_and_wait(sc, IE_RU_START, 0, 0); } break; @@ -678,8 +643,7 @@ ietint(sc) if (status & IE_STAT_OK) { sc->sc_arpcom.ac_if.if_opackets++; - sc->sc_arpcom.ac_if.if_collisions += - SWAP(status & IE_XS_MAXCOLL); + sc->sc_arpcom.ac_if.if_collisions += status & IE_XS_MAXCOLL; } else if (status & IE_STAT_ABORT) { printf("%s: send aborted\n", sc->sc_dev.dv_xname); sc->sc_arpcom.ac_if.if_oerrors++; @@ -834,7 +798,7 @@ check_eh(sc, eh, to_bpf) /* * Only accept unicast packets destined for us, or multicasts * for groups that we belong to. For now, we assume that the - * '586 will only return packets that we asked it for. This + * '596 will only return packets that we asked it for. This * isn't strictly true (it uses hashing for the multicast * filter), but it will do in this case, and we want to get out * of here as quickly as possible. @@ -858,8 +822,7 @@ ie_buflen(sc, head) int head; { - return (SWAP(sc->rbuffs[head]->ie_rbd_actual) - & (IE_RBUF_SIZE | (IE_RBUF_SIZE - 1))); + return (sc->rbuffs[head]->ie_rbd_actual & (IE_RBUF_SIZE | (IE_RBUF_SIZE - 1))); } static inline int @@ -908,29 +871,32 @@ iexmit(sc) if (sc->sc_arpcom.ac_if.if_bpf) bpf_tap(sc->sc_arpcom.ac_if.if_bpf, sc->xmit_cbuffs[sc->xctail], - SWAP(sc->xmit_buffs[sc->xctail]->ie_xmit_flags)); + sc->xmit_buffs[sc->xctail]->ie_xmit_flags); #endif -/*printf("iexmit base %x cmd %x bfd %x to %x\n", +#if 0 +printf("iexmit base %x cmd %x bfd %x to %x\n", sc->sc_maddr, sc->xmit_cmds[sc->xctail], sc->xmit_buffs[sc->xctail], -sc->xmit_cbuffs[sc->xctail]);*/ +sc->xmit_cbuffs[sc->xctail]); +#endif sc->xmit_buffs[sc->xctail]->ie_xmit_flags |= IE_XMIT_LAST; - sc->xmit_buffs[sc->xctail]->ie_xmit_next = SWAP(0xffff); - ST_24(sc->xmit_buffs[sc->xctail]->ie_xmit_buf, - MK_24(sc->sc_iobase, sc->xmit_cbuffs[sc->xctail])); + sc->xmit_buffs[sc->xctail]->ie_xmit_next = 0xffffffff; + SWT_32(sc->xmit_buffs[sc->xctail]->ie_xmit_buf, + sc->xmit_cbuffs[sc->xctail]); - sc->xmit_cmds[sc->xctail]->com.ie_cmd_link = SWAP(0xffff); + sc->xmit_cmds[sc->xctail]->com.ie_cmd_link = 0xffffffff; sc->xmit_cmds[sc->xctail]->com.ie_cmd_cmd = - IE_CMD_XMIT | IE_CMD_INTR | IE_CMD_LAST; + IE_CMD_XMIT | IE_CMD_INTR | IE_CMD_LAST | IE_CMD_FLEX; - sc->xmit_cmds[sc->xctail]->ie_xmit_status = SWAP(0); + sc->xmit_cmds[sc->xctail]->ie_xmit_status = 0; sc->xmit_cmds[sc->xctail]->ie_xmit_desc = - MK_16(sc->sc_maddr, sc->xmit_buffs[sc->xctail]); + ASWAP(sc->xmit_buffs[sc->xctail]); + sc->xmit_cmds[sc->xctail]->ie_xmit_count = 0; sc->scb->ie_command_list = - MK_16(sc->sc_maddr, sc->xmit_cmds[sc->xctail]); + ASWAP(sc->xmit_cmds[sc->xctail]); command_and_wait(sc, IE_CU_START, 0, 0); sc->xmit_busy = 1; @@ -1099,7 +1065,7 @@ ieget(sc, mp, ehp, to_bpf) */ nextbuf: offset = 0; - sc->rbuffs[head]->ie_rbd_actual = SWAP(0); + sc->rbuffs[head]->ie_rbd_actual = 0; sc->rbuffs[head]->ie_rbd_length |= IE_RBD_LAST; sc->rbhead = head = (head + 1) % sc->nrxbuf; sc->rbuffs[sc->rbtail]->ie_rbd_length &= ~IE_RBD_LAST; @@ -1138,7 +1104,8 @@ ie_readframe(sc, num) status = sc->rframes[num]->ie_fd_status; /* Immediately advance the RFD list, since we have copied ours now. */ - sc->rframes[num]->ie_fd_status = SWAP(0); + sc->rframes[num]->ie_fd_status = 0; + sc->rframes[num]->ie_fd_actual = 0; sc->rframes[num]->ie_fd_last |= IE_FD_LAST; sc->rframes[sc->rftail]->ie_fd_last &= ~IE_FD_LAST; sc->rftail = (sc->rftail + 1) % sc->nframes; @@ -1236,7 +1203,7 @@ ie_drop_packet_buffer(sc) i = sc->rbuffs[sc->rbhead]->ie_rbd_actual & IE_RBD_LAST; sc->rbuffs[sc->rbhead]->ie_rbd_length |= IE_RBD_LAST; - sc->rbuffs[sc->rbhead]->ie_rbd_actual = SWAP(0); + sc->rbuffs[sc->rbhead]->ie_rbd_actual = 0; sc->rbhead = (sc->rbhead + 1) % sc->nrxbuf; sc->rbuffs[sc->rbtail]->ie_rbd_length &= ~IE_RBD_LAST; sc->rbtail = (sc->rbtail + 1) % sc->nrxbuf; @@ -1286,7 +1253,7 @@ iestart(ifp) m_freem(m0); len = max(len, ETHER_MIN_LEN); - sc->xmit_buffs[sc->xchead]->ie_xmit_flags = SWAP(len); + sc->xmit_buffs[sc->xchead]->ie_xmit_flags = len; sc->xmit_free--; sc->xchead = (sc->xchead + 1) % NTXBUF; @@ -1317,12 +1284,13 @@ ie_setupram(sc) scb = sc->scb; (sc->memzero)((char *) scb, sizeof *scb); + scb->ie_off_timer = 10; + scb->ie_on_timer = 10000; iscp->ie_busy = 1; /* ie_busy == char */ - iscp->ie_scb_offset = MK_16(sc->sc_maddr, scb); - ST_24(iscp->ie_base, sc->sc_iobase); + SWT_32(iscp->ie_base, sc->scb); - (sc->reset_586) (sc); + (sc->reset_596) (sc); (sc->chan_attn) (sc); delay(100); /* wait a while... */ @@ -1353,7 +1321,7 @@ iereset(sc) ieioctl(&sc->sc_arpcom.ac_if, SIOCSIFFLAGS, 0); /* - * Stop i82586 dead in its tracks. + * Stop i82596 dead in its tracks. */ if (command_and_wait(sc, IE_RU_ABORT | IE_CU_ABORT, 0, 0)) printf("%s: abort commands timed out\n", sc->sc_dev.dv_xname); @@ -1363,7 +1331,7 @@ iereset(sc) #ifdef notdef if (!check_ie_present(sc, sc->sc_maddr, sc->sc_msize)) - panic("ie disappeared!"); + panic("ie disappeared!\n"); #endif sc->sc_arpcom.ac_if.if_flags |= IFF_UP; @@ -1462,12 +1430,12 @@ run_tdr(sc, cmd) { int result; - cmd->com.ie_cmd_status = SWAP(0); + cmd->com.ie_cmd_status = 0; cmd->com.ie_cmd_cmd = IE_CMD_TDR | IE_CMD_LAST; - cmd->com.ie_cmd_link = SWAP(0xffff); + cmd->com.ie_cmd_link = 0xffffffff; - sc->scb->ie_command_list = MK_16(sc->sc_maddr, cmd); - cmd->ie_tdr_time = SWAP(0); + sc->scb->ie_command_list = ASWAP(cmd); + cmd->ie_tdr_time = 0; if (command_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) || !(cmd->com.ie_cmd_status & IE_STAT_OK)) @@ -1553,7 +1521,7 @@ setup_bufs(sc) sc->nframes = n / r; if (sc->nframes <= 0) - panic("ie: bogus buffer calc"); + panic("ie: bogus buffer calc\n"); if (sc->nframes > MXFRAMES) sc->nframes = MXFRAMES; @@ -1580,8 +1548,10 @@ setup_bufs(sc) * step 1b: link together the recv frames and set EOL on last one */ for (n = 0; n < sc->nframes; n++) { + sc->rframes[n]->ie_fd_last = IE_FD_FLEX; + sc->rframes[n]->ie_fd_size = 0; sc->rframes[n]->ie_fd_next = - MK_16(sc->sc_maddr, sc->rframes[(n + 1) % sc->nframes]); + ASWAP(sc->rframes[(n + 1) % sc->nframes]); } sc->rframes[sc->nframes - 1]->ie_fd_last |= IE_FD_LAST; @@ -1603,7 +1573,7 @@ setup_bufs(sc) */ for (n = 0; n < sc->nrxbuf; n++) { sc->rbuffs[n]->ie_rbd_next = - MK_16(sc->sc_maddr, sc->rbuffs[(n + 1) % sc->nrxbuf]); + ASWAP(sc->rbuffs[(n + 1) % sc->nrxbuf]); } sc->rbuffs[sc->nrxbuf - 1]->ie_rbd_length |= IE_RBD_LAST; @@ -1625,8 +1595,8 @@ setup_bufs(sc) for (n = 0; n < sc->nrxbuf; n++) { sc->cbuffs[n] = (char *) ptr; /* XXX why char vs uchar? */ - sc->rbuffs[n]->ie_rbd_length = SWAP(IE_RBUF_SIZE); - ST_24(sc->rbuffs[n]->ie_rbd_buffer, MK_24(sc->sc_iobase, ptr)); + sc->rbuffs[n]->ie_rbd_length = IE_RBUF_SIZE; + SWT_32(sc->rbuffs[n]->ie_rbd_buffer, ptr); ptr = Align(ptr + IE_RBUF_SIZE); } @@ -1641,8 +1611,8 @@ setup_bufs(sc) sc->rbhead = 0; sc->rbtail = sc->nrxbuf - 1; - sc->scb->ie_recv_list = MK_16(sc->sc_maddr, sc->rframes[0]); - sc->rframes[0]->ie_fd_buf_desc = MK_16(sc->sc_maddr, sc->rbuffs[0]); + sc->scb->ie_recv_list = ASWAP(sc->rframes[0]); + sc->rframes[0]->ie_fd_buf_desc = ASWAP(sc->rbuffs[0]); #ifdef IEDEBUG printf("IE_DEBUG: reserved %d bytes\n", ptr - sc->buf_area); @@ -1660,17 +1630,16 @@ mc_setup(sc, ptr) { volatile struct ie_mcast_cmd *cmd = ptr; - cmd->com.ie_cmd_status = SWAP(0); + cmd->com.ie_cmd_status = 0; cmd->com.ie_cmd_cmd = IE_CMD_MCAST | IE_CMD_LAST; - cmd->com.ie_cmd_link = SWAP(0xffff); + cmd->com.ie_cmd_link = 0xffffffff; (sc->memcopy)((caddr_t)sc->mcast_addrs, (caddr_t)cmd->ie_mcast_addrs, sc->mcast_count * sizeof *sc->mcast_addrs); - cmd->ie_mcast_bytes = - SWAP(sc->mcast_count * ETHER_ADDR_LEN); /* grrr... */ + cmd->ie_mcast_bytes = sc->mcast_count * ETHER_ADDR_LEN; /* grrr... */ - sc->scb->ie_command_list = MK_16(sc->sc_maddr, cmd); + sc->scb->ie_command_list = ASWAP(cmd); if (command_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) || !(cmd->com.ie_cmd_status & IE_STAT_OK)) { printf("%s: multicast address setup command failed\n", @@ -1699,15 +1668,28 @@ ieinit(sc) ptr = sc->buf_area; /* + * Set up bus throttles. + */ + + { + if (command_and_wait(sc, IE_CU_THROTTLE, 0, 0)) { + printf("%s: throttle set command failed\n", + sc->sc_dev.dv_xname); + return 0; + } + } + + /* * Send the configure command first. */ + { volatile struct ie_config_cmd *cmd = ptr; - scb->ie_command_list = MK_16(sc->sc_maddr, cmd); - cmd->com.ie_cmd_status = SWAP(0); + scb->ie_command_list = ASWAP(cmd); + cmd->com.ie_cmd_status = 0; cmd->com.ie_cmd_cmd = IE_CMD_CONFIG | IE_CMD_LAST; - cmd->com.ie_cmd_link = SWAP(0xffff); + cmd->com.ie_cmd_link = 0xffffffff; ie_setup_config(cmd, sc->promisc, 0); @@ -1725,10 +1707,10 @@ ieinit(sc) { volatile struct ie_iasetup_cmd *cmd = ptr; - scb->ie_command_list = MK_16(sc->sc_maddr, cmd); - cmd->com.ie_cmd_status = SWAP(0); + scb->ie_command_list = ASWAP(cmd); + cmd->com.ie_cmd_status = 0; cmd->com.ie_cmd_cmd = IE_CMD_IASETUP | IE_CMD_LAST; - cmd->com.ie_cmd_link = SWAP(0xffff); + cmd->com.ie_cmd_link = 0xffffffff; (sc->memcopy)(sc->sc_arpcom.ac_enaddr, (caddr_t)&cmd->ie_address, sizeof cmd->ie_address); @@ -1758,13 +1740,13 @@ ieinit(sc) sc->sc_arpcom.ac_if.if_flags |= IFF_RUNNING; /* tell higher levels that we are here */ - sc->scb->ie_recv_list = MK_16(sc->sc_maddr, sc->rframes[0]); + sc->scb->ie_recv_list = ASWAP(sc->rframes[0]); command_and_wait(sc, IE_RU_START, 0, 0); ie_ack(sc, IE_ST_WHENCE); - if (sc->run_586) - (sc->run_586)(sc); + if (sc->run_596) + (sc->run_596)(sc); return 0; } @@ -1909,3 +1891,4 @@ print_rbd(rbd) rbd->mbz); } #endif + diff --git a/sys/arch/mvme88k/dev/if_ie.h b/sys/arch/mvme88k/dev/if_ie.h index 42b1a0edae0..183e81e8fda 100644 --- a/sys/arch/mvme88k/dev/if_ie.h +++ b/sys/arch/mvme88k/dev/if_ie.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ie.h,v 1.2 1998/12/15 05:52:30 smurph Exp $ */ +/* $OpenBSD: if_ie.h,v 1.3 1999/09/27 18:43:24 smurph Exp $ */ /* Copyright (c) 1998 Steve Murphree, Jr. * Copyright (c) 1995 Theo de Raadt @@ -50,8 +50,8 @@ * generic: * the generic stuff of the ie chip is all done with data structures * that live in the chip's memory address space. the chip expects - * its main data structure (the sys conf ptr -- SCP) to be at a fixed - * address in its 24 bit space: 0xfffff4 + * its main data structure (the sys conf ptr -- SCP) to be at a + * address loaded into the chip at init. * * the SCP points to another structure called the ISCP. * the ISCP points to another structure called the SCB. @@ -69,14 +69,6 @@ * * to get data from the chip you program it to interrupt... * - * - * sun issues: - * - * there are 3 kinds of sun "ie" interfaces: - * 1 - a VME/multibus card - * 2 - an on-board interface (sun3's, sun-4/100's, and sun-4/200's) - * 3 - another VME board called the 3E - * * the VME boards lives in vme16 space. only 16 and 8 bit accesses * are allowed, so functions that copy data must be aware of this. * @@ -86,37 +78,6 @@ * that means that any buffer pointers you give the chip must be * swapped to intel format. yuck. * - * VME/multibus interface: - * for the multibus interface the board ignores the top 4 bits - * of the chip address. the multibus interface seems to have its - * own MMU like page map (without protections or valid bits, etc). - * there are 256 pages of physical memory on the board (each page - * is 1024 bytes). there are 1024 slots in the page map. so, - * a 1024 byte page takes up 10 bits of address for the offset, - * and if there are 1024 slots in the page that is another 10 bits - * of the address. that makes a 20 bit address, and as stated - * earlier the board ignores the top 4 bits, so that accounts - * for all 24 bits of address. - * - * note that the last entry of the page map maps the top of the - * 24 bit address space and that the SCP is supposed to be at - * 0xfffff4 (taking into account allignment). so, - * for multibus, that entry in the page map has to be used for the SCP. - * - * the page map effects BOTH how the ie chip sees the - * memory, and how the host sees it. - * - * the page map is part of the "register" area of the board - * - * on-board interface: - * - * <fill in useful info later> - * - * - * VME3E interface: - * - * <fill in useful info later> - * */ /* @@ -190,3 +151,4 @@ struct ieob { /* * not supported (yet?) */ + diff --git a/sys/arch/mvme88k/dev/nvram.c b/sys/arch/mvme88k/dev/nvram.c index e231f8ef7ca..94576ccfad5 100644 --- a/sys/arch/mvme88k/dev/nvram.c +++ b/sys/arch/mvme88k/dev/nvram.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nvram.c,v 1.4 1999/04/11 03:26:27 smurph Exp $ */ +/* $OpenBSD: nvram.c,v 1.5 1999/09/27 18:43:24 smurph Exp $ */ /* * Copyright (c) 1995 Theo de Raadt @@ -47,13 +47,12 @@ #include <mvme88k/dev/nvramreg.h> #include <mvme88k/dev/pcctworeg.h> - struct nvramsoftc { struct device sc_dev; - void * sc_paddr; - void * sc_vaddr; - int sc_len; - struct clockreg *sc_regs; + void * sc_paddr; + void * sc_vaddr; + int sc_len; + void * sc_regs; }; void nvramattach __P((struct device *, struct device *, void *)); @@ -76,6 +75,7 @@ nvrammatch(parent, vcf, args) struct cfdata *cf = vcf; struct confargs *ca = args; struct bugrtc rtc; + ca->ca_vaddr = ca->ca_paddr; /* map 1:1 */ /*X*/ if (ca->ca_vaddr == (void *)-1) /*X*/ return (1); @@ -109,7 +109,11 @@ nvramattach(parent, self, args) sc->sc_paddr = ca->ca_paddr; sc->sc_vaddr = ca->ca_vaddr; - sc->sc_len = MK48T08_SIZE; + if (cputyp == CPU_188) { + sc->sc_len = MK48T02_SIZE; + } else { + sc->sc_len = MK48T08_SIZE; + } /*X*/ if (sc->sc_vaddr == (void *)-1) /*X*/ sc->sc_vaddr = mapiodev((void *)sc->sc_paddr, @@ -117,8 +121,12 @@ nvramattach(parent, self, args) /*X*/ if (sc->sc_vaddr == NULL) /*X*/ panic("failed to map!"); - sc->sc_regs = (struct clockreg *)(sc->sc_vaddr + sc->sc_len - - sizeof(struct clockreg)); + if (cputyp != CPU_188) { + sc->sc_regs = (void *)(sc->sc_vaddr + sc->sc_len - + sizeof(struct clockreg)); + } else { + sc->sc_regs = (void *)(sc->sc_vaddr + M188_NVRAM_TOD_OFF); + } printf(": MK48T0%d len %d\n", sc->sc_len / 1024, sc->sc_len); } @@ -257,12 +265,12 @@ timetochip(c) /* * Set up the system's time, given a `reasonable' time value. */ + void inittodr(base) time_t base; { struct nvramsoftc *sc = (struct nvramsoftc *) nvram_cd.cd_devs[0]; - register struct clockreg *cl = sc->sc_regs; int sec, min, hour, day, mon, year; int badbase = 0, waszero = base == 0; @@ -277,16 +285,32 @@ inittodr(base) base = 21*SECYR + 186*SECDAY + SECDAY/2; badbase = 1; } - cl->cl_csr |= CLK_READ; /* enable read (stop time) */ - sec = cl->cl_sec; - min = cl->cl_min; - hour = cl->cl_hour; - day = cl->cl_mday; - mon = cl->cl_month; - year = cl->cl_year; - cl->cl_csr &= ~CLK_READ; /* time wears on */ + if (cputyp != CPU_188) { + register struct clockreg *cl = (struct clockreg *)sc->sc_regs; + cl->cl_csr |= CLK_READ; /* enable read (stop time) */ + sec = cl->cl_sec; + min = cl->cl_min; + hour = cl->cl_hour; + day = cl->cl_mday; + mon = cl->cl_month; + year = cl->cl_year; + cl->cl_csr &= ~CLK_READ; /* time wears on */ + } else { /* CPU_188 */ + register struct m188_clockreg *cl = (struct m188_clockreg *)sc->sc_regs; + cl->cl_csr |= CLK_READ; /* enable read (stop time) */ + sec = cl->cl_sec & 0xff; + min = cl->cl_min & 0xff; + hour = cl->cl_hour & 0xff; + day = cl->cl_mday & 0xff; + mon = cl->cl_month & 0xff; + year = cl->cl_year & 0xff; + cl->cl_csr &= ~CLK_READ; /* time wears on */ + } if ((time.tv_sec = chiptotime(sec, min, hour, day, mon, year)) == 0) { - printf("WARNING: bad date in nvram"); + printf("WARNING: bad date in nvram\n"); + printf("day = %d, mon = %d, year = %d, hour = %d, min = %d, sec = %d", + FROMBCD(day), FROMBCD(mon), FROMBCD(year) + YEAR0, + FROMBCD(hour), FROMBCD(min), FROMBCD(sec)); /* * Believe the time in the file system for lack of * anything better, resetting the clock. @@ -316,21 +340,38 @@ inittodr(base) void resettodr() { struct nvramsoftc *sc = (struct nvramsoftc *) nvram_cd.cd_devs[0]; - register struct clockreg *cl = sc->sc_regs; - struct chiptime c; - - if (!time.tv_sec || cl == NULL) - return; - timetochip(&c); - cl->cl_csr |= CLK_WRITE; /* enable write */ - cl->cl_sec = c.sec; - cl->cl_min = c.min; - cl->cl_hour = c.hour; - cl->cl_wday = c.wday; - cl->cl_mday = c.day; - cl->cl_month = c.mon; - cl->cl_year = c.year; - cl->cl_csr &= ~CLK_WRITE; /* load them up */ + struct chiptime c; + if (cputyp != CPU_188) { + register struct clockreg *cl = (struct clockreg *)sc->sc_regs; + + if (!time.tv_sec || cl == NULL) + return; + timetochip(&c); + cl->cl_csr |= CLK_WRITE; /* enable write */ + cl->cl_sec = c.sec; + cl->cl_min = c.min; + cl->cl_hour = c.hour; + cl->cl_wday = c.wday; + cl->cl_mday = c.day; + cl->cl_month = c.mon; + cl->cl_year = c.year; + cl->cl_csr &= ~CLK_WRITE; /* load them up */ + } else { /* CPU_188 */ + register struct m188_clockreg *cl = (struct m188_clockreg *)sc->sc_regs; + + if (!time.tv_sec || cl == NULL) + return; + timetochip(&c); + cl->cl_csr |= CLK_WRITE; /* enable write */ + cl->cl_sec = c.sec; + cl->cl_min = c.min; + cl->cl_hour = c.hour; + cl->cl_wday = c.wday; + cl->cl_mday = c.day; + cl->cl_month = c.mon; + cl->cl_year = c.year; + cl->cl_csr &= ~CLK_WRITE; /* load them up */ + } } /*ARGSUSED*/ @@ -351,7 +392,6 @@ nvramclose(dev, flag, mode) dev_t dev; int flag, mode; { - return (0); } diff --git a/sys/arch/mvme88k/dev/nvramreg.h b/sys/arch/mvme88k/dev/nvramreg.h index 67de360c02e..365fd5fa880 100644 --- a/sys/arch/mvme88k/dev/nvramreg.h +++ b/sys/arch/mvme88k/dev/nvramreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: nvramreg.h,v 1.2 1998/12/15 05:52:30 smurph Exp $ */ +/* $OpenBSD: nvramreg.h,v 1.3 1999/09/27 18:43:24 smurph Exp $ */ /* * Copyright (c) 1992, 1993 @@ -74,11 +74,23 @@ struct clockreg { volatile u_char cl_year; /* year (0..99; BCD) */ }; +struct m188_clockreg { + volatile u_long cl_csr; /* control register */ + volatile u_long cl_sec; /* seconds (0..59; BCD) */ + volatile u_long cl_min; /* minutes (0..59; BCD) */ + volatile u_long cl_hour; /* hour (0..23; BCD) */ + volatile u_long cl_wday; /* weekday (1..7) */ + volatile u_long cl_mday; /* day in month (1..31; BCD) */ + volatile u_long cl_month; /* month (1..12; BCD) */ + volatile u_long cl_year; /* year (0..99; BCD) */ +}; + /* bits in cl_csr */ #define CLK_WRITE 0x80 /* want to write */ #define CLK_READ 0x40 /* want to read (freeze clock) */ struct clockreg *clockreg; +struct m188_clockreg *m188_clockreg; /* * Motorola chose the year `1900' as their base count. @@ -87,7 +99,8 @@ struct clockreg *clockreg; #define YEAR0 00 #define NVRAMSIZE 0x8000 -#define NVRAM_TOD_OFF 0x1ff8 /* offset of tod in NVRAM space */ +#define SBC_NVRAM_TOD_OFF 0x1FF8 /* offset of tod in NVRAM space */ +#define M188_NVRAM_TOD_OFF 0x1FE0 /* offset of tod in NVRAM space */ #define MK48T02_SIZE 2*1024 #define MK48T08_SIZE 8*1024 diff --git a/sys/arch/mvme88k/dev/pcctwo.c b/sys/arch/mvme88k/dev/pcctwo.c index 415c8aae3b4..d39ee04bc89 100644 --- a/sys/arch/mvme88k/dev/pcctwo.c +++ b/sys/arch/mvme88k/dev/pcctwo.c @@ -1,5 +1,5 @@ -/* $OpenBSD: pcctwo.c,v 1.6 1999/05/29 04:41:44 smurph Exp $ */ +/* $OpenBSD: pcctwo.c,v 1.7 1999/09/27 18:43:24 smurph Exp $ */ /* * Copyright (c) 1995 Theo de Raadt @@ -87,13 +87,19 @@ pcctwomatch(parent, vcf, args) struct pcctworeg *pcc2; /* Bomb if wrong cpu */ - if (!(cputyp == CPU_187 || cputyp == CPU_188)){ - printf("==> pcctwo: wrong CPU type %x.\n", cputyp); - return (0); - } - - pcc2 = (struct pcctworeg *)(IIOV(ca->ca_paddr) + PCC2_PCC2CHIP_OFF); - if (badvaddr(pcc2, 4) <= 0){ + switch (cputyp) { + case CPU_187: + pcc2 = (struct pcctworeg *)(IIOV(ca->ca_paddr) + PCC2_PCC2CHIP_OFF); + break; + case CPU_197: /* pcctwo is a child of buswitch XXX smurph */ + pcc2 = (struct pcctworeg *)(IIOV(ca->ca_paddr)); + break; + default: + /* Bomb if wrong cpu */ + return (0); + } + + if (badvaddr(pcc2, 4) <= 0){ printf("==> pcctwo: failed address check.\n"); return (0); } @@ -170,7 +176,14 @@ pcctwoattach(parent, self, args) */ sc->sc_paddr = ca->ca_paddr; sc->sc_vaddr = (void *)IIOV(sc->sc_paddr); - sc->sc_pcc2 = (struct pcctworeg *)(sc->sc_vaddr + PCC2_PCC2CHIP_OFF); + switch (cputyp) { + case CPU_187: + sc->sc_pcc2 = (struct pcctworeg *)(sc->sc_vaddr + PCC2_PCC2CHIP_OFF); + break; + case CPU_197: /* pcctwo is a child of buswitch XXX smurph */ + sc->sc_pcc2 = (struct pcctworeg *)sc->sc_vaddr; + break; + } sys_pcc2 = sc->sc_pcc2; printf(": rev %d\n", sc->sc_pcc2->pcc2_chiprev); @@ -183,12 +196,6 @@ pcctwoattach(parent, self, args) */ pcc2intr_ipl = (u_char *)&(sc->sc_pcc2->pcc2_ipl); pcc2intr_mask = (u_char *)&(sc->sc_pcc2->pcc2_mask); - -#ifdef MVME187 - printf("setting interrupt ack vectors.\n"); - setupiackvectors(); -#endif /* MVME187 */ - config_search(pcctwo_scan, self, args); } diff --git a/sys/arch/mvme88k/dev/sclock.c b/sys/arch/mvme88k/dev/sclock.c new file mode 100644 index 00000000000..fcc0ea7a398 --- /dev/null +++ b/sys/arch/mvme88k/dev/sclock.c @@ -0,0 +1,412 @@ +/* $OpenBSD: sclock.c,v 1.1 1999/09/27 18:43:25 smurph Exp $ */ +/* + * Copyright (c) 1999 Steve Murphree, Jr. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed under OpenBSD by + * Theo de Raadt for Willowglen Singapore. + * 4. 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) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 1995 Nivas Madhur + * Copyright (c) 1994 Gordon W. Ross + * Copyright (c) 1993 Adam Glass + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + */ + +/* + * Statistics clock driver. + */ + +#include <sys/param.h> +#include <sys/simplelock.h> +#include <sys/kernel.h> +#include <sys/device.h> +#ifdef GPROF +#include <sys/gmon.h> +#endif + +#include <machine/psl.h> +#include <machine/autoconf.h> +#include <machine/bugio.h> +#include <machine/cpu.h> +#include "pcctwo.h" +#if NPCCTWO > 0 +#include <mvme88k/dev/pcctworeg.h> +#endif +#include "syscon.h" +#if NSYSCON > 0 +#include <mvme88k/dev/sysconreg.h> +#endif +#include <mvme88k/dev/vme.h> + +extern struct vme2reg *sys_vme2; +struct simplelock cio_lock; +/* + * Statistics clock interval and 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 4096 would + * give us offsets in [0..4095]. Instead, we take offsets in [1..4095]. + * This is symmetric about the point 2048, or statvar/2, and thus averages + * to that value (assuming uniform random numbers). + */ +int statvar = 8192; +int statmin; /* statclock interval - 1/2*variance */ + +static int sclockmatch __P((struct device *, void *, void *)); +static void sclockattach __P((struct device *, struct device *, void *)); + +void sbc_initstatclock __P((void)); +void m188_initstatclock __P((void)); +void m188_cio_init __P((unsigned)); +void write_cio __P((unsigned, unsigned)); + +struct sclocksoftc { + struct device sc_dev; + struct intrhand sc_statih; +}; + +struct cfattach sclock_ca = { + sizeof(struct sclocksoftc), sclockmatch, sclockattach +}; + +struct cfdriver sclock_cd = { + NULL, "sclock", DV_DULL, 0 +}; + +int sbc_statintr __P((void *)); +int m188_statintr __P((void *)); + +int sclockbus; +u_char stat_reset; + +/* + * Every machine needs, but doesn't have to have, a statistics clock. + * For this platform, this file manages it, no matter what form it takes. + */ +int +sclockmatch(parent, vcf, args) + struct device *parent; + void *vcf, *args; +{ + register struct confargs *ca = args; + register struct cfdata *cf = vcf; + + if (strcmp(cf->cf_driver->cd_name, "sclock")) { + return (0); + } + + /* + * clock has to be at ipl 5 + * We return the ipl here so that the parent can print + * a message if it is different from what ioconf.c says. + */ + ca->ca_ipl = IPL_CLOCK; + /* set size to 0 - see pcctwo.c:match for details */ + ca->ca_len = 0; + return (1); +} + +void +sclockattach(parent, self, args) + struct device *parent, *self; + void *args; +{ + struct confargs *ca = args; + struct sclocksoftc *sc = (struct sclocksoftc *)self; + + sclockbus = ca->ca_bustype; + + switch (sclockbus) { +#if NPCCTWO > 0 + case BUS_PCCTWO: + sc->sc_statih.ih_fn = sbc_statintr; + sc->sc_statih.ih_arg = 0; + sc->sc_statih.ih_wantframe = 1; + sc->sc_statih.ih_ipl = ca->ca_ipl; + stat_reset = ca->ca_ipl | PCC2_IRQ_IEN | PCC2_IRQ_ICLR; + pcctwointr_establish(PCC2V_TIMER2, &sc->sc_statih); + mdfp.statclock_init_func = &sbc_initstatclock; + printf(": VME1x7"); + break; +#endif /* NPCCTWO */ +#if NSYSCON > 0 + case BUS_SYSCON: + sc->sc_statih.ih_fn = m188_statintr; + sc->sc_statih.ih_arg = 0; + sc->sc_statih.ih_wantframe = 1; + sc->sc_statih.ih_ipl = ca->ca_ipl; + sysconintr_establish(SYSCV_TIMER2, &sc->sc_statih); + mdfp.statclock_init_func = &m188_initstatclock; + printf(": VME188"); + break; +#endif /* NSYSCON */ + } + printf("\n"); +} + +#if NPCCTWO > 0 +void +sbc_initstatclock(void) +{ + register int statint, minint; + +#ifdef DEBUG + printf("SBC statclock init\n"); +#endif + if (stathz == 0) + stathz = hz; + if (1000000 % stathz) { + printf("cannot get %d Hz statclock; using 100 Hz\n", stathz); + stathz = 100; + } + profhz = stathz; /* always */ + + statint = 1000000 / stathz; + minint = statint / 2 + 100; + while (statvar > minint) + statvar >>= 1; + + /* statclock */ + sys_pcc2->pcc2_t2ctl = 0; + sys_pcc2->pcc2_t2cmp = pcc2_timer_us2lim(statint); + sys_pcc2->pcc2_t2count = 0; + sys_pcc2->pcc2_t2ctl = PCC2_TCTL_CEN | PCC2_TCTL_COC | + PCC2_TCTL_COVF; + sys_pcc2->pcc2_t2irq = stat_reset; + + statmin = statint - (statvar >> 1); +} + +int +sbc_statintr(cap) + void *cap; +{ + register u_long newint, r, var; + + sys_pcc2->pcc2_t2irq = stat_reset; + + statclock((struct clockframe *)cap); + + /* + * Compute new randomized interval. The intervals are uniformly + * distributed on [statint - statvar / 2, statint + statvar / 2], + * and therefore have mean statint, giving a stathz frequency clock. + */ + var = statvar; + do { + r = random() & (var - 1); + } while (r == 0); + newint = statmin + r; + + sys_pcc2->pcc2_t2ctl = 0; + sys_pcc2->pcc2_t2cmp = pcc2_timer_us2lim(newint); + sys_pcc2->pcc2_t2count = 0; /* should I? */ + sys_pcc2->pcc2_t2irq = stat_reset; + sys_pcc2->pcc2_t2ctl = PCC2_TCTL_CEN | PCC2_TCTL_COC; + return (1); +} +#endif /* NPCCTWO */ + +#if NSYSCON > 0 +#define CIO_LOCK simple_lock(&cio_lock) +#define CIO_UNLOCK simple_unlock(&cio_lock) + +int +m188_statintr(cap) + void *cap; +{ + register u_long newint, r, var; + + CIO_LOCK; + statclock((struct clockframe *)cap); + write_cio(CIO_CSR1, CIO_GCB|CIO_CIP); /* Ack the interrupt */ + + /* + * Compute new randomized interval. The intervals are uniformly + * distributed on [statint - statvar / 2, statint + statvar / 2], + * and therefore have mean statint, giving a stathz frequency clock. + */ + var = statvar; + do { + r = random() & (var - 1); + } while (r == 0); + newint = statmin + r; +/* printf("newint = %d, 0x%x\n", newint, newint);*/ + write_cio(CIO_CT1MSB, (newint & 0xFF00) >> 8); /* Load time constant CTC #1 */ + write_cio(CIO_CT1LSB, newint & 0xFF); + /* force a trigger event */ + write_cio(CIO_CSR1, CIO_GCB|CIO_TCB|CIO_IE); /* Start CTC #1 running */ + CIO_UNLOCK; + return (1); +} + +void +m188_initstatclock(void) +{ + register int statint, minint; + +#ifdef DEBUG + printf("VME188 clock init\n"); +#endif + simple_lock_init(&cio_lock); + if (stathz == 0) + stathz = hz; + if (1000000 % stathz) { + printf("cannot get %d Hz statclock; using 100 Hz\n", stathz); + stathz = 100; + } + profhz = stathz; /* always */ + + statint = 1000000 / stathz; + minint = statint / 2 + 100; + while (statvar > minint) + statvar >>= 1; + m188_cio_init(statint); + statmin = statint - (statvar >> 1); +} + +#define CIO_CNTRL 0xFFF8300C + +/* Write CIO register */ +void +write_cio(reg, val) +unsigned reg,val; +{ + int s, i; + s = splclock(); + /* Select register */ + *((volatile int *) CIO_CTRL) = (reg & 0xFF); + /* Write the value */ + *((volatile int *) CIO_CTRL) = (val & 0xFF); + splx(s); +} + +/* Read CIO register */ +static u_char +read_cio(reg) +unsigned reg; +{ + int c; + int s, i; + volatile int *port = (volatile int *)CIO_CNTRL; + + s = splclock(); + /* Select register */ + *port = (char)(reg&0xFF); + /* Delay for a short time to allow 8536 to settle */ + for(i=0;i<100;i++); + /* read the value */ + c = *port; + splx(s); + return((u_char)c&0xFF); +} + +/* + * Initialize the CTC (8536) + * Only the counter/timers are used - the IO ports are un-comitted. + * Channels 1 and 2 are linked to provide a /32 counter. + */ + +void +m188_cio_init(unsigned p) +{ + long i; + short period; + + CIO_LOCK; + + period = p & 0xFFFF; + + /* Initialize 8536 CTC */ + /* Start by forcing chip into known state */ + (void) read_cio(CIO_MICR); + + write_cio(CIO_MICR, CIO_MICR_RESET); /* Reset the CTC */ + for(i=0;i < 1000L; i++) /* Loop to delay */ + ; + /* Clear reset and start init seq. */ + write_cio(CIO_MICR, 0x00); + + /* Wait for chip to come ready */ + while((read_cio(CIO_MICR)) != (char) CIO_MICR_RJA) + ; + /* init Z8036 */ + write_cio(CIO_MICR, CIO_MICR_MIE | CIO_MICR_NV | CIO_MICR_RJA | CIO_MICR_DLC); + write_cio(CIO_CTMS1, CIO_CTMS_CSC); /* Continuous count */ + write_cio(CIO_PDCB, 0xFF); /* set port B to input */ + + write_cio(CIO_CT1MSB, (period & 0xFF00) >> 8); /* Load time constant CTC #1 */ + write_cio(CIO_CT1LSB, period & 0xFF); + + /* enable counter 1 */ + write_cio(CIO_MCCR, CIO_MCCR_CT1E | CIO_MCCR_PBE); + + /* enable interrupts and start */ + /*write_cio(CIO_IVR, SYSCV_TIMER2);*/ + write_cio(CIO_CSR1, CIO_GCB|CIO_TCB|CIO_IE); /* Start CTC #1 running */ + + CIO_UNLOCK; +} + +#endif /* NSYSCON */ diff --git a/sys/arch/mvme88k/dev/syscon.c b/sys/arch/mvme88k/dev/syscon.c new file mode 100644 index 00000000000..9971544faa8 --- /dev/null +++ b/sys/arch/mvme88k/dev/syscon.c @@ -0,0 +1,250 @@ + +/* $OpenBSD: syscon.c,v 1.1 1999/09/27 18:43:25 smurph Exp $ */ +/* + * Copyright (c) 1999 Steve Murphree, Jr. + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed under OpenBSD by + * Theo de Raadt for Willowglen Singapore. + * 4. 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. + */ + +/* + * VME188 SYSCON + */ + +#include <sys/param.h> +#include <sys/conf.h> +#include <sys/ioctl.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/tty.h> +#include <sys/uio.h> +#include <sys/callout.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/syslog.h> +#include <sys/fcntl.h> +#include <sys/device.h> +#include <machine/cpu.h> +#include <machine/autoconf.h> +#include <machine/frame.h> +#include <machine/board.h> +#include <dev/cons.h> + +#include <mvme88k/dev/sysconreg.h> + +struct sysconreg syscon_reg = { + (volatile unsigned int*)IEN0_REG,(volatile unsigned int*)IEN1_REG, + (volatile unsigned int*)IEN2_REG,(volatile unsigned int*)IEN3_REG, + (volatile unsigned int*)IENALL_REG,(volatile unsigned int*)IST_REG, + (volatile unsigned int*)SETSWI_REG,(volatile unsigned int*)CLRSWI_REG, + (volatile unsigned int*)ISTATE_REG,(volatile unsigned int*)CLRINT_REG, + (volatile unsigned char*)GLB0,(volatile unsigned char*)GLB1, + (volatile unsigned char*)GLB2,(volatile unsigned char*)GLB3, + (volatile unsigned int*)UCSR_REG,(volatile unsigned int*)GLBRES_REG, + (volatile unsigned int*)CCSR_REG,(volatile unsigned int*)ERROR_REG, + (volatile unsigned int*)PCNFA_REG,(volatile unsigned int*)PCNFB_REG, + (volatile unsigned int*)EXTAD_REG,(volatile unsigned int*)EXTAM_REG, + (volatile unsigned int*)WHOAMI_REG,(volatile unsigned int*)WMAD_REG, + (volatile unsigned int*)RMAD_REG,(volatile unsigned int*)WVAD_REG, + (volatile unsigned int*)RVAD_REG,(volatile unsigned int*)CIO_PORTC, + (volatile unsigned int*)CIO_PORTB,(volatile unsigned int*)CIO_PORTA, + (volatile unsigned int*)CIO_CTRL + }; + +struct sysconsoftc { + struct device sc_dev; + void *sc_vaddr; /* Utility I/O space */ + void *sc_paddr; + struct sysconreg *sc_syscon; /* the actual registers */ + struct intrhand sc_abih; /* `abort' switch */ + struct intrhand sc_acih; /* `ac fial' */ + struct intrhand sc_sfih; /* `sys fial' */ +}; + +void sysconattach __P((struct device *, struct device *, void *)); +int sysconmatch __P((struct device *, void *, void *)); +void setupiackvectors __P((void)); +int sysconabort __P((struct frame *frame)); +int sysconacfail __P((struct frame *frame)); +int sysconsysfail __P((struct frame *frame)); + +struct cfattach syscon_ca = { + sizeof(struct sysconsoftc), sysconmatch, sysconattach +}; + +struct cfdriver syscon_cd = { + NULL, "syscon", DV_DULL, 0 +}; + +struct sysconreg *sys_syscon = NULL; + +int +sysconmatch(parent, vcf, args) + struct device *parent; + void *vcf, *args; +{ + struct cfdata *cf = vcf; + struct confargs *ca = args; + struct sysconreg *syscon; + + /* Don't match if wrong cpu */ + if (cputyp != CPU_188) return (0); + /* Uh, MVME188 better have on of these, so always match if it + * is a MVME188... */ + syscon = (struct sysconreg *)(IIOV(ca->ca_paddr)); + return (1); +} + +int +syscon_print(args, bus) + void *args; + const char *bus; +{ + struct confargs *ca = args; + + if (ca->ca_offset != -1) + printf(" offset 0x%x", ca->ca_offset); + if (ca->ca_ipl > 0) + printf(" ipl %d", ca->ca_ipl); + return (UNCONF); +} + +int +syscon_scan(parent, child, args) + struct device *parent; + void *child, *args; +{ + struct cfdata *cf = child; + struct sysconsoftc *sc = (struct sysconsoftc *)parent; + struct confargs *ca = args; + struct confargs oca; + + if (parent->dv_cfdata->cf_driver->cd_indirect) { + printf(" indirect devices not supported\n"); + return 0; + } + + bzero(&oca, sizeof oca); + oca.ca_offset = cf->cf_loc[0]; + oca.ca_ipl = cf->cf_loc[1]; + if ((oca.ca_offset != (void*)-1) && ISIIOVA(sc->sc_vaddr + oca.ca_offset)) { + oca.ca_vaddr = sc->sc_vaddr + oca.ca_offset; + oca.ca_paddr = sc->sc_paddr + oca.ca_offset; + } else { + oca.ca_vaddr = (void *)-1; + oca.ca_paddr = (void *)-1; + } + oca.ca_bustype = BUS_SYSCON; + oca.ca_master = (void *)sc->sc_syscon; + oca.ca_name = cf->cf_driver->cd_name; + if ((*cf->cf_attach->ca_match)(parent, cf, &oca) == 0) + return (0); + config_attach(parent, cf, &oca, syscon_print); + return (1); +} + +void +sysconattach(parent, self, args) + struct device *parent, *self; + void *args; +{ + struct confargs *ca = args; + struct sysconsoftc *sc = (struct sysconsoftc *)self; + int i; + + if (sys_syscon) + panic("syscon already attached!"); + + /* + * since we know ourself to land in intiobase land, + * we must adjust our address + */ + sc->sc_paddr = ca->ca_paddr; + sc->sc_vaddr = (void *)IIOV(sc->sc_paddr); + sc->sc_syscon = &syscon_reg; + sys_syscon = sc->sc_syscon; + + printf(": rev %d\n", 1); + + /* + * pseudo driver, abort interrupt handler + */ + sc->sc_abih.ih_fn = sysconabort; + sc->sc_abih.ih_arg = 0; + sc->sc_abih.ih_ipl = IPL_ABORT; + sc->sc_abih.ih_wantframe = 1; + sc->sc_acih.ih_fn = sysconacfail; + sc->sc_acih.ih_arg = 0; + sc->sc_acih.ih_ipl = IPL_ABORT; + sc->sc_acih.ih_wantframe = 1; + sc->sc_sfih.ih_fn = sysconsysfail; + sc->sc_sfih.ih_arg = 0; + sc->sc_sfih.ih_ipl = IPL_ABORT; + sc->sc_sfih.ih_wantframe = 1; + + intr_establish(SYSCV_ABRT, &sc->sc_abih); + intr_establish(SYSCV_ACF, &sc->sc_acih); + intr_establish(SYSCV_SYSF, &sc->sc_sfih); + + config_search(syscon_scan, self, args); +} + +int +sysconintr_establish(vec, ih) + int vec; + struct intrhand *ih; +{ + return (intr_establish(vec, ih)); +} + +int +sysconabort(frame) + struct frame *frame; +{ + ISR_RESET_NMI; + nmihand(frame); + return (1); +} + +int +sysconsysfail(frame) + struct frame *frame; +{ + ISR_RESET_SYSFAIL; + nmihand(frame); + return (1); +} + +int +sysconacfail(frame) + struct frame *frame; +{ + ISR_RESET_ACFAIL; + nmihand(frame); + return (1); +} + diff --git a/sys/arch/mvme88k/dev/sysconreg.h b/sys/arch/mvme88k/dev/sysconreg.h new file mode 100644 index 00000000000..bcf4739371f --- /dev/null +++ b/sys/arch/mvme88k/dev/sysconreg.h @@ -0,0 +1,61 @@ +/* $OpenBSD: sysconreg.h,v 1.1 1999/09/27 18:43:25 smurph Exp $ */ + +/* + * Memory map for SYSCON found in mvme188 board set. + * No specific chips are found here like the PCCTWO + * on MVME1x7. All chips are included in this one + * map/device so that devices don't run rampant in + * the config files. I may change this later XXX smurph. + */ + +#include <machine/board.h> + +struct sysconreg { + volatile unsigned int *ien0; + volatile unsigned int *ien1; + volatile unsigned int *ien2; + volatile unsigned int *ien3; + volatile unsigned int *ienall; + volatile unsigned int *ist; + volatile unsigned int *setswi; + volatile unsigned int *clrswi; + volatile unsigned int *istate; + volatile unsigned int *clrint; + volatile unsigned char *global0; + volatile unsigned char *global1; + volatile unsigned char *global2; + volatile unsigned char *global3; + volatile unsigned int *ucsr; + volatile unsigned int *glbres; + volatile unsigned int *ccsr; + volatile unsigned int *error; + volatile unsigned int *pcnfa; + volatile unsigned int *pcnfb; + volatile unsigned int *extad; + volatile unsigned int *extam; + volatile unsigned int *whoami; + volatile unsigned int *wmad; + volatile unsigned int *rmad; + volatile unsigned int *wvad; + volatile unsigned int *rvad; + volatile unsigned int *cio_portc; + volatile unsigned int *cio_portb; + volatile unsigned int *cio_porta; + volatile unsigned int *cio_ctrl; +}; + +extern struct sysconreg *sys_syscon; + +/* + * Vectors we use + */ +#define SYSCV_ABRT 0x110 +#define SYSCV_SYSF 0x111 +#define SYSCV_ACF 0x112 +#define SYSCV_SCC 0x55 +#define SYSCV_TIMER4 0x56 +#define SYSCV_TIMER3 0x57 +#define SYSCV_TIMER2 0x58 +#define SYSCV_TIMER1 0x59 + + diff --git a/sys/arch/mvme88k/dev/vme.c b/sys/arch/mvme88k/dev/vme.c index 958077067a1..3d980f28669 100644 --- a/sys/arch/mvme88k/dev/vme.c +++ b/sys/arch/mvme88k/dev/vme.c @@ -1,6 +1,6 @@ -/* $OpenBSD: vme.c,v 1.3 1999/05/29 04:41:44 smurph Exp $ */ - +/* $OpenBSD: vme.c,v 1.4 1999/09/27 18:43:25 smurph Exp $ */ /* + * Copyright (c) 1999 Steve Murphree, Jr. * Copyright (c) 1995 Theo de Raadt * All rights reserved. * @@ -52,22 +52,22 @@ #include "machine/pmap.h" #include "pcctwo.h" +#include "syscon.h" #include <mvme88k/dev/vme.h> +#if NSYSCON > 0 +#include <mvme88k/dev/sysconreg.h> +#endif int vmematch __P((struct device *, void *, void *)); void vmeattach __P((struct device *, struct device *, void *)); -int vme1chip_init __P((struct vmesoftc *sc)); int vme2chip_init __P((struct vmesoftc *sc)); u_long vme2chip_map __P((u_long base, int len, int dwidth)); int vme2abort __P((struct frame *frame)); +int sysconabort __P((struct frame *frame)); static int vmebustype; -volatile vm_offset_t master1va; -volatile vm_offset_t master2va; -volatile vm_offset_t master3va; -volatile vm_offset_t master4va; struct vme2reg *sys_vme2 = NULL; struct cfattach vme_ca = { @@ -85,37 +85,9 @@ vmematch(parent, cf, args) void *args; { struct confargs *ca = args; - -#if NMC > 0 - if (ca->ca_bustype == BUS_MC) { - struct mcreg *mc = (struct mcreg *)ca->ca_master; - - if (mc->mc_ver & MC_VER_NOVME) - return (0); - } -#endif return (1); } -#ifndef BUGMAP -/* - * make local addresses 1G-2G correspond to VME addresses 3G-4G, - * as D32 - */ -#define VME2_D32STARTPHYS (1*1024*1024*1024UL) -#define VME2_D32ENDPHYS (2*1024*1024*1024UL) -#define VME2_D32STARTVME (3*1024*1024*1024UL) -#define VME2_D32BITSVME (3*1024*1024*1024UL) - -/* - * make local addresses 3G-3.75G correspond to VME addresses 3G-3.75G, - * as D16 - */ -#define VME2_D16STARTPHYS (3*1024*1024*1024UL) -#define VME2_D16ENDPHYS (3*1024*1024*1024UL + 768*1024*1024UL) - -#else - /* * make local addresses 1G-2G correspond to VME addresses 3G-4G, * as D32 @@ -135,8 +107,6 @@ vmematch(parent, cf, args) #define VME2_A32D16STARTPHYS (0xFF000000UL) #define VME2_A32D16ENDPHYS (0xFF7FFFFFUL) -#endif - /* * Returns a physical address mapping for a VME address & length. @@ -155,43 +125,9 @@ vmepmap(sc, vmeaddr, len, bustype) len = roundup(len, NBPG); switch (vmebustype) { -#if NPCC > 0 - case BUS_PCC: - switch (bustype) { - case BUS_VMES: - printf("base 0x%8x/0x%8x len 0x%x\n", - vmeaddr, base, len); - if (base > VME1_A16BASE && - (base+len - VME1_A16BASE) < VME1_A16D16LEN) { - base = base - VME1_A16BASE + VME1_A16D16BASE; - printf("vmes1: base = 0x%8x\n", base); /* 1:1 */ - } else if (base > VME1_A32D16BASE && - base+len < VME1_A16BASE) { - /* 1:1 mapped */ - printf("vmes2: base = 0x%8x\n", base); - } else { - printf("%s: cannot map pa 0x%x len 0x%x\n", - sc->sc_dev.dv_xname, base, len); - return (NULL); - } - break; - case BUS_VMEL: - if (base >= physmem && (base+len) < VME1_A32D32LEN) - base = base + VME1_A32D32BASE; - else if (base+len < VME1_A32D16LEN) /* HACK! */ - base = base + VME1_A32D16BASE; - else { - printf("%s: cannot map pa 0x%x len 0x%x\n", - sc->sc_dev.dv_xname, base, len); - return (NULL); - } - break; - } - break; -#endif -#if NMC > 0 || NPCCTWO > 0 - case BUS_MC: +#if NPCCTWO > 0 || NSYSCON > 0 case BUS_PCCTWO: + case BUS_SYSCON: switch (bustype) { case BUS_VMES: /* D16 VME Transfers */ /*printf("base 0x%8x/0x%8x len 0x%x\n", vmeaddr, base, len);*/ @@ -357,6 +293,7 @@ vmeattach(parent, self, args) struct vme1reg *vme1; struct vme2reg *vme2; int scon; + char sconc; /* XXX any initialization to do? */ @@ -364,16 +301,7 @@ vmeattach(parent, self, args) vmebustype = ca->ca_bustype; switch (ca->ca_bustype) { -#if NPCC > 0 - case BUS_PCC: - vme1 = (struct vme1reg *)sc->sc_vaddr; - scon = (vme1->vme1_scon & VME1_SCON_SWITCH); - printf(": %ssystem controller\n", scon ? "" : "not "); - vme1chip_init(sc); - break; -#endif -#if (NMC > 0) || (NPCCTWO > 0) - case BUS_MC: +#if NPCCTWO > 0 case BUS_PCCTWO: vme2 = (struct vme2reg *)sc->sc_vaddr; scon = (vme2->vme2_tctl & VME2_TCTL_SCON); @@ -382,6 +310,15 @@ vmeattach(parent, self, args) vme2chip_init(sc); break; #endif +#if NSYSCON > 0 + case BUS_SYSCON: + vme2 = (struct vme2reg *)sc->sc_vaddr; + sconc = *(char *)GLOBAL1; + sconc &= M188_SYSCON; + printf(": %ssystem controller\n", scon ? "" : "not "); + vmesyscon_init(sc); + break; +#endif } while (config_found(self, NULL, NULL)) @@ -406,125 +343,74 @@ vmeintr_establish(vec, ih) struct intrhand *ih; { struct vmesoftc *sc = (struct vmesoftc *) vme_cd.cd_devs[0]; -#if NPCC > 0 - struct vme1reg *vme1; -#endif -#if NMC > 0 || NPCCTWO > 0 +#if NPCCTWO > 0 struct vme2reg *vme2; #endif +#if NSYSCON > 0 + struct sysconreg *syscon; +#endif int x; x = (intr_establish(vec, ih)); switch (vmebustype) { -#if NPCC > 0 - case BUS_PCC: - vme1 = (struct vme1reg *)sc->sc_vaddr; - vme1->vme1_irqen = vme1->vme1_irqen | - VME1_IRQ_VME(ih->ih_ipl); - break; -#endif -#if NMC > 0 || NPCCTWO > 0 - case BUS_MC: +#if NPCCTWO > 0 case BUS_PCCTWO: vme2 = (struct vme2reg *)sc->sc_vaddr; vme2->vme2_irqen = vme2->vme2_irqen | VME2_IRQ_VME(ih->ih_ipl); break; #endif +#if NSYSCON > 0 + case BUS_SYSCON: + syscon = (struct sysconreg *)sc->sc_vaddr; + /* + syscon->vme2_irqen = vme2->vme2_irqen | + VMES_IRQ_VME(ih->ih_ipl); + */ + break; +#endif } return (x); } -#if defined(MVME147) -int -vme1chip_init(sc) - struct vmesoftc *sc; -{ - struct vme1reg *vme1 = (struct vme1reg *)sc->sc_vaddr; - - vme1->vme1_scon &= ~VME1_SCON_SYSFAIL; /* XXX doesn't work */ -} -#endif - - -#ifndef BUGMAP - -/* - * XXX what AM bits should be used for the D32/D16 mappings? - */ +#if NPCCTWO > 0 int vme2chip_init(sc) struct vmesoftc *sc; { struct vme2reg *vme2 = (struct vme2reg *)sc->sc_vaddr; - u_long ctl; + u_long ctl, addr, vasize; /* turn off SYSFAIL LED */ vme2->vme2_tctl &= ~VME2_TCTL_SYSFAIL; ctl = vme2->vme2_masterctl; - - /* unused decoders 1 */ - vme2->vme2_master1 = 0; - ctl &= ~(VME2_MASTERCTL_ALL << VME2_MASTERCTL_1SHIFT); + printf("%s: using BUG parameters\n", sc->sc_dev.dv_xname); + /* setup a A32D16 space */ printf("%s: 1phys 0x%08x-0x%08x to VME 0x%08x-0x%08x\n", sc->sc_dev.dv_xname, vme2->vme2_master1 << 16, vme2->vme2_master1 & 0xffff0000, vme2->vme2_master1 << 16, vme2->vme2_master1 & 0xffff0000); - /* unused decoders 2 */ - vme2->vme2_master2 = 0; - ctl &= ~(VME2_MASTERCTL_ALL << VME2_MASTERCTL_2SHIFT); + /* setup a A32D32 space */ printf("%s: 2phys 0x%08x-0x%08x to VME 0x%08x-0x%08x\n", sc->sc_dev.dv_xname, vme2->vme2_master2 << 16, vme2->vme2_master2 & 0xffff0000, vme2->vme2_master2 << 16, vme2->vme2_master2 & 0xffff0000); /* setup a A24D16 space */ - vme2->vme2_master3 = ((VME2_D16ENDPHYS-1) & 0xffff0000) | - (VME2_D16STARTPHYS >> 16); - ctl &= ~(VME2_MASTERCTL_ALL << VME2_MASTERCTL_3SHIFT); - ctl |= (VME2_MASTERCTL_D16 | VME2_MASTERCTL_AM24UD) << - VME2_MASTERCTL_3SHIFT; printf("%s: 3phys 0x%08x-0x%08x to VME 0x%08x-0x%08x\n", sc->sc_dev.dv_xname, vme2->vme2_master3 << 16, vme2->vme2_master3 & 0xffff0000, vme2->vme2_master3 << 16, vme2->vme2_master3 & 0xffff0000); - /* setup a A32D32 space */ - vme2->vme2_master4 = ((VME2_D32ENDPHYS-1) & 0xffff0000) | - (VME2_D32STARTPHYS >> 16); - vme2->vme2_master4mod = (VME2_D32STARTVME & 0xffff0000) | - (VME2_D32BITSVME >> 16); - ctl &= ~(VME2_MASTERCTL_ALL << VME2_MASTERCTL_4SHIFT); - ctl |= (VME2_MASTERCTL_AM32UD) << - VME2_MASTERCTL_4SHIFT; + /* setup a XXXXXX space */ printf("%s: 4phys 0x%08x-0x%08x to VME 0x%08x-0x%08x\n", sc->sc_dev.dv_xname, vme2->vme2_master4 << 16, vme2->vme2_master4 & 0xffff0000, - vme2->vme2_master4 << 16, vme2->vme2_master4 & 0xffff0000); - - vme2->vme2_masterctl = ctl; - ctl = vme2->vme2_gcsrctl; - - /* enable A16 short IO map decoder (0xffffxxxx) */ - ctl &= ~(VME2_GCSRCTL_I1EN | VME2_GCSRCTL_I1D16 | VME2_GCSRCTL_I1WP | - VME2_GCSRCTL_I1SU); - ctl |= VME2_GCSRCTL_I1EN | VME2_GCSRCTL_I1D16 | VME2_GCSRCTL_I1SU; - - /* enable A24D16 (0xf0xxxxxx) and A32D16 (0xf[1-e]xxxxxx) decoders */ - ctl &= ~(VME2_GCSRCTL_I2EN | VME2_GCSRCTL_I2WP | VME2_GCSRCTL_I2SU | - VME2_GCSRCTL_I2PD); - ctl |= VME2_GCSRCTL_I2EN | VME2_GCSRCTL_I2SU | VME2_GCSRCTL_I2PD; - - /* map decoders 3 & 4 which were just configured */ - ctl &= ~(VME2_GCSRCTL_MDEN4 | VME2_GCSRCTL_MDEN3 | VME2_GCSRCTL_MDEN1 | - VME2_GCSRCTL_MDEN2); - ctl |= VME2_GCSRCTL_MDEN4 | VME2_GCSRCTL_MDEN3; - - vme2->vme2_gcsrctl = ctl; - + vme2->vme2_master4 << 16 + vme2->vme2_master4mod << 16, + vme2->vme2_master4 & 0xffff0000 + vme2->vme2_master4 & 0xffff0000); /* * Map the VME irq levels to the cpu levels 1:1. * This is rather inflexible, but much easier. @@ -533,101 +419,69 @@ vme2chip_init(sc) (6 << VME2_IRQL4_VME6SHIFT) | (5 << VME2_IRQL4_VME5SHIFT) | (4 << VME2_IRQL4_VME4SHIFT) | (3 << VME2_IRQL4_VME3SHIFT) | (2 << VME2_IRQL4_VME2SHIFT) | (1 << VME2_IRQL4_VME1SHIFT); + printf("%s: vme to cpu irq level 1:1\n",sc->sc_dev.dv_xname); + /* printf("%s: vme2_irql4 = 0x%08x\n", sc->sc_dev.dv_xname, vme2->vme2_irql4); - -#if NPCCTWO > 0 - if (vmebustype == BUS_PCCTWO) { + */ + if (vmebustype == BUS_PCCTWO){ + /* + * pseudo driver, abort interrupt handler + */ sc->sc_abih.ih_fn = vme2abort; sc->sc_abih.ih_arg = 0; - sc->sc_abih.ih_ipl = 7; + sc->sc_abih.ih_ipl = IPL_NMI; sc->sc_abih.ih_wantframe = 1; - - intr_establish(110, &sc->sc_abih); /* XXX 110 */ + intr_establish(110, &sc->sc_abih); vme2->vme2_irqen |= VME2_IRQ_AB; } -#endif vme2->vme2_irqen = vme2->vme2_irqen | VME2_IRQ_ACF; } +#endif /* NPCCTWO */ -#else /* BUGMAP */ - +#if NSYSCON > 0 int -vme2chip_init(sc) +vmesyscon_init(sc) struct vmesoftc *sc; { - struct vme2reg *vme2 = (struct vme2reg *)sc->sc_vaddr; + struct sysconreg *syscon = (struct sysconreg *)sc->sc_vaddr; u_long ctl, addr, vasize; +#ifdef TODO /* turn off SYSFAIL LED */ vme2->vme2_tctl &= ~VME2_TCTL_SYSFAIL; ctl = vme2->vme2_masterctl; printf("%s: using BUG parameters\n", sc->sc_dev.dv_xname); - /* setup a A32D16 space */ - printf("%s: 1phys 0x%08x-0x%08x to VME 0x%08x-0x%08x\n", + printf("%s: 1phys 0x%08x-0x%08x to VME 0x%08x-0x%08x master\n", sc->sc_dev.dv_xname, vme2->vme2_master1 << 16, vme2->vme2_master1 & 0xffff0000, vme2->vme2_master1 << 16, vme2->vme2_master1 & 0xffff0000); - - /* setup a A32D32 space */ - printf("%s: 2phys 0x%08x-0x%08x to VME 0x%08x-0x%08x\n", + printf("%s: 2phys 0x%08x-0x%08x to VME 0x%08x-0x%08x slave\n", sc->sc_dev.dv_xname, vme2->vme2_master2 << 16, vme2->vme2_master2 & 0xffff0000, vme2->vme2_master2 << 16, vme2->vme2_master2 & 0xffff0000); - /* setup a A24D16 space */ - printf("%s: 3phys 0x%08x-0x%08x to VME 0x%08x-0x%08x\n", - sc->sc_dev.dv_xname, - vme2->vme2_master3 << 16, vme2->vme2_master3 & 0xffff0000, - vme2->vme2_master3 << 16, vme2->vme2_master3 & 0xffff0000); - - /* setup a XXXXXX space */ - printf("%s: 4phys 0x%08x-0x%08x to VME 0x%08x-0x%08x\n", - sc->sc_dev.dv_xname, - vme2->vme2_master4 << 16, vme2->vme2_master4 & 0xffff0000, - vme2->vme2_master4 << 16 + vme2->vme2_master4mod << 16, - vme2->vme2_master4 & 0xffff0000 + vme2->vme2_master4 & 0xffff0000); - /* - * Map the VME irq levels to the cpu levels 1:1. - * This is rather inflexible, but much easier. - */ - vme2->vme2_irql4 = (7 << VME2_IRQL4_VME7SHIFT) | - (6 << VME2_IRQL4_VME6SHIFT) | (5 << VME2_IRQL4_VME5SHIFT) | - (4 << VME2_IRQL4_VME4SHIFT) | (3 << VME2_IRQL4_VME3SHIFT) | - (2 << VME2_IRQL4_VME2SHIFT) | (1 << VME2_IRQL4_VME1SHIFT); - printf("%s: vme to cpu irq level 1:1\n",sc->sc_dev.dv_xname); - /* - printf("%s: vme2_irql4 = 0x%08x\n", sc->sc_dev.dv_xname, - vme2->vme2_irql4); - */ -#if NPCCTWO > 0 - if (vmebustype == BUS_PCCTWO){ - /* - * pseudo driver, abort interrupt handler - */ - sc->sc_abih.ih_fn = vme2abort; - sc->sc_abih.ih_arg = 0; - sc->sc_abih.ih_ipl = IPL_NMI; - sc->sc_abih.ih_wantframe = 1; -#if 0 - printf("inserting vme_ab handler\n"); -#endif - intr_establish(110, &sc->sc_abih); - vme2->vme2_irqen |= VME2_IRQ_AB; - } -#endif - vme2->vme2_irqen = vme2->vme2_irqen | VME2_IRQ_ACF; + /* + * pseudo driver, abort interrupt handler + */ + sc->sc_abih.ih_fn = sysconabort; + sc->sc_abih.ih_arg = 0; + sc->sc_abih.ih_ipl = IPL_NMI; + sc->sc_abih.ih_wantframe = 1; + intr_establish(110, &sc->sc_abih); +#endif /* TODO */ } -#endif /* BUGMAP */ +#endif /* NSYSCON */ -#if defined(MVME162) || defined(MVME167) || defined(MVME177) || defined (MVME187) || defined (MVME188) +#if defined(MVME162) || defined(MVME167) || defined(MVME177) || defined (MVME187) || defined (MVME197) /* - * A32 accesses on the MVME1[678]x require setting up mappings in + * A32 accesses on the MVME1[6789]x require setting up mappings in * the VME2 chip. * XXX VME address must be between 2G and 4G * XXX We only support D32 at the moment.. + * XXX smurph - This is bogus, get rid of it! Should check vme/syson for offsets. */ u_long vme2chip_map(base, len, dwidth) @@ -654,7 +508,7 @@ vme2abort(frame) struct vme2reg *vme2 = (struct vme2reg *)sc->sc_vaddr; if (vme2->vme2_irqstat & VME2_IRQ_AB == 0) { - printf("%s: vme2chip irq not set\n", sc->sc_dev.dv_xname); + printf("%s: abort irq not set\n", sc->sc_dev.dv_xname); return (0); } vme2->vme2_irqclr = VME2_IRQ_AB; diff --git a/sys/arch/mvme88k/dev/vs.c b/sys/arch/mvme88k/dev/vs.c index a92f1bf6211..5c5e44b991d 100644 --- a/sys/arch/mvme88k/dev/vs.c +++ b/sys/arch/mvme88k/dev/vs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vs.c,v 1.1 1999/05/29 04:41:44 smurph Exp $ */ +/* $OpenBSD: vs.c,v 1.2 1999/09/27 18:43:25 smurph Exp $ */ /* * Copyright (c) 1999 Steve Murphree, Jr. @@ -52,13 +52,19 @@ #include <scsi/scsiconf.h> #include <machine/autoconf.h> #include <machine/param.h> -#if defined(MVME187) -#include <mvme88k/dev/vsreg.h> -#include <mvme88k/dev/vsvar.h> -#include "machine/mmu.h" + +#if defined(MVME187) || defined(MVME188) || defined(MVME197) + #define PAGESIZE 4096 + #include <mvme88k/dev/vsreg.h> + #include <mvme88k/dev/vsvar.h> + #include "machine/mmu.h" + #define ROUND_PAGE m88k_round_page + #define TRUNC_PAGE m88k_trunc_page #else -#include <mvme68k/dev/vsreg.h> -#include <mvme68k/dev/vsvar.h> + #include <mvme68k/dev/vsreg.h> + #include <mvme68k/dev/vsvar.h> + #define ROUND_PAGE m68k_round_page + #define TRUNC_PAGE m68k_trunc_page #endif /* MVME187 */ int vs_checkintr __P((struct vs_softc *, struct scsi_xfer *, int *)); @@ -73,31 +79,77 @@ M328_CQE * vs_getcqe __P((struct vs_softc *)); M328_IOPB * vs_getiopb __P((struct vs_softc *)); extern int cold; -extern u_int kvtop(); +extern u_int kvtop(); +/* + * 16 bit 's' memory functions. MVME328 is a D16 board. + * We must program with that in mind or else... + * bcopy/bzero (the 'b' meaning byte) is implemented in + * 32 bit operations for speed, so thay are not really + * 'byte' operations at all!! MVME1x7 can be set up to + * handle D32 -> D16 read/writes via VMEChip2 Address + * modifiers, however MVME188 can not. These next two + * function insure 16 bit copy/zero operations. The + * structures are all implemented with 16 bit or less + * types. smurph + */ + +void +scopy(void *src, void *dst, unsigned short cnt) +{ + register unsigned short volatile *x, *y, z; + + z = cnt >> 1; + x = (unsigned short *) src; + y = (unsigned short *) dst; + + while (z--) { + *y++ = *x++; + } +} + +void +szero(void *src, u_long cnt) +{ + register unsigned short *source; + register unsigned short zero = 0; + register unsigned short z; + + source = (unsigned short *) src; + z = cnt >> 1; + + while (z--) { + *source++ = zero; + } + return; +} + + + + /* * default minphys routine for MVME328 based controllers */ void vs_minphys(bp) - struct buf *bp; +struct buf *bp; { - /* - * No max transfer at this level. - */ - minphys(bp); + /* + * No max transfer at this level. + */ + minphys(bp); } int do_vspoll(sc, to) - struct vs_softc *sc; - int to; +struct vs_softc *sc; +int to; { int i; if (to <= 0 ) to = 50000; /* use cmd_wait values? */ i = 50000; /*spl0();*/ - while(!(CRSW & (M_CRSW_CRBV | M_CRSW_CC))){ + while (!(CRSW & (M_CRSW_CRBV | M_CRSW_CC))) { if (--i <= 0) { #ifdef DEBUG printf ("waiting: timeout %d crsw 0x%x\n", to, CRSW); @@ -118,8 +170,8 @@ int do_vspoll(sc, to) int vs_poll(sc, xs) - struct vs_softc *sc; - struct scsi_xfer *xs; +struct vs_softc *sc; +struct scsi_xfer *xs; { M328_CIB *cib = (M328_CIB *)&sc->sc_vsreg->sh_CIB; M328_CQE *mc = (M328_CQE*)&sc->sc_vsreg->sh_MCE; @@ -129,29 +181,29 @@ vs_poll(sc, xs) M328_MCSB *mcsb = (M328_MCSB *)&sc->sc_vsreg->sh_MCSB; M328_CQE *cqep; M328_IOPB *iopb; - int i; - int status; - int s; - int to; - - /*s = splbio();*/ - to = xs->timeout / 1000; - for (;;) { - if (do_vspoll(sc, to)) break; + int i; + int status; + int s; + int to; + + /*s = splbio();*/ + to = xs->timeout / 1000; + for (;;) { + if (do_vspoll(sc, to)) break; if (vs_checkintr(sc, xs, &status)) { - vs_scsidone(xs, status); - } - if (CRSW & M_CRSW_ER) + vs_scsidone(xs, status); + } + if (CRSW & M_CRSW_ER) CRB_CLR_ER(CRSW); CRB_CLR_DONE(CRSW); if (xs->flags & ITSDONE) break; - } - return (COMPLETE); + } + return (COMPLETE); } void thaw_queue(sc, target) - struct vs_softc *sc; - u_int8_t target; +struct vs_softc *sc; +u_int8_t target; { u_short t; t = target << 8; @@ -176,21 +228,21 @@ int stat; } xs->flags |= ITSDONE; /*sc->sc_tinfo[slp->target].cmds++;*/ - if (CRSW & M_CRSW_ER) + if (CRSW & M_CRSW_ER) CRB_CLR_ER(CRSW); CRB_CLR_DONE(CRSW); thaw_queue(sc, slp->target + 1); - bzero(riopb, sizeof(M328_IOPB)); + szero(riopb, sizeof(M328_IOPB)); scsi_done(xs); } int vs_scsicmd(xs) - struct scsi_xfer *xs; +struct scsi_xfer *xs; { - struct scsi_link *slp = xs->sc_link; - struct vs_softc *sc = slp->adapter_softc; - int flags, s, i; + struct scsi_link *slp = xs->sc_link; + struct vs_softc *sc = slp->adapter_softc; + int flags, s, i; unsigned long buf, len; u_short iopb_len; M328_CQE *mc = (M328_CQE*)&sc->sc_vsreg->sh_MCE; @@ -200,6 +252,7 @@ vs_scsicmd(xs) M328_MCSB *mcsb = (M328_MCSB *)&sc->sc_vsreg->sh_MCSB; M328_CQE *cqep; M328_IOPB *iopb; + M328_CMD *m328_cmd; /* If the target doesn't exist, abort */ if (!sc->sc_tinfo[slp->target].avail) { @@ -208,12 +261,12 @@ vs_scsicmd(xs) xs->flags |= ITSDONE; scsi_done(xs); } - + slp->quirks |= SDEV_NOLUNS; flags = xs->flags; #ifdef SDEBUG printf("scsi_cmd() "); - if (xs->cmd->opcode == 0){ + if (xs->cmd->opcode == 0) { printf("TEST_UNIT_READY "); } else if (xs->cmd->opcode == REQUEST_SENSE) { printf("REQUEST_SENSE "); @@ -245,50 +298,52 @@ vs_scsicmd(xs) printf("READ_COMMAND "); } #endif - if (flags & SCSI_POLL){ + if (flags & SCSI_POLL) { cqep = mc; iopb = miopb; - }else{ + } else { cqep = vs_getcqe(sc); iopb = vs_getiopb(sc); } if (cqep == NULL) { xs->error = XS_DRIVER_STUFFUP; - return(TRY_AGAIN_LATER); + return (TRY_AGAIN_LATER); } - + /* s = splbio();*/ iopb_len = sizeof(M328_short_IOPB) + xs->cmdlen; - bzero(iopb, sizeof(M328_IOPB)); + szero(iopb, sizeof(M328_IOPB)); - bcopy(xs->cmd, &iopb->iopb_SCSI[0], xs->cmdlen); - iopb->iopb_CMD = IOPB_SCSI; + scopy(xs->cmd, &iopb->iopb_SCSI[0], xs->cmdlen); + iopb->iopb_CMD = IOPB_SCSI; +#if 0 LV(iopb->iopb_BUFF, kvtop(xs->data)); LV(iopb->iopb_LENGTH, xs->datalen); +#endif iopb->iopb_UNIT = slp->lun << 3; iopb->iopb_UNIT |= slp->target; iopb->iopb_NVCT = (u_char)sc->sc_nvec; iopb->iopb_EVCT = (u_char)sc->sc_evec; - - /* - * Since the 187 doesn't support cache snooping, we have - * to flush the cache for a write and flush with inval for - * a read, prior to starting the IO. - */ + + /* + * Since the 187 doesn't support cache snooping, we have + * to flush the cache for a write and flush with inval for + * a read, prior to starting the IO. + */ if (xs->flags & SCSI_DATA_IN) { /* read */ #if defined(MVME187) dma_cachectl((vm_offset_t)xs->data, xs->datalen, - DMA_CACHE_SYNC_INVAL); + DMA_CACHE_SYNC_INVAL); #endif iopb->iopb_OPTION |= OPT_READ; } else { /* write */ #if defined(MVME187) - dma_cachectl((vm_offset_t)xs->data, xs->datalen, - DMA_CACHE_SYNC); + dma_cachectl((vm_offset_t)xs->data, xs->datalen, + DMA_CACHE_SYNC); #endif iopb->iopb_OPTION |= OPT_WRITE; } - + if (flags & SCSI_POLL) { iopb->iopb_OPTION |= OPT_INTDIS; iopb->iopb_LEVEL = 0; @@ -297,23 +352,33 @@ vs_scsicmd(xs) iopb->iopb_LEVEL = sc->sc_ipl; } iopb->iopb_ADDR = ADDR_MOD; - + /* * Wait until we can use the command queue entry. * Should only have to wait if the master command * queue entry is busy. */ - while(cqep->cqe_QECR & M_QECR_GO); - + while (cqep->cqe_QECR & M_QECR_GO); + cqep->cqe_IOPB_ADDR = OFF(iopb); cqep->cqe_IOPB_LENGTH = iopb_len; - if (flags & SCSI_POLL){ + if (flags & SCSI_POLL) { cqep->cqe_WORK_QUEUE = slp->target + 1; - }else{ + } else { cqep->cqe_WORK_QUEUE = slp->target + 1; } - LV(cqep->cqe_CTAG, xs); + MALLOC(m328_cmd, M328_CMD*, sizeof(M328_CMD), M_DEVBUF, M_WAITOK); + + m328_cmd->xs = xs; + if (xs->datalen) { + m328_cmd->top_sg_list = vs_build_memory_structure(xs, iopb); + } else { + m328_cmd->top_sg_list = (M328_SG)0; + } + + LV(cqep->cqe_CTAG, m328_cmd); + if (crb->crb_CRSW & M_CRSW_AQ) { cqep->cqe_QECR = M_QECR_AA; } @@ -324,42 +389,42 @@ vs_scsicmd(xs) slp->lun, buf, len, cqep->cqe_WORK_QUEUE, iopb->iopb_LEVEL); #endif cqep->cqe_QECR |= M_QECR_GO; - - if (flags & SCSI_POLL){ + + if (flags & SCSI_POLL) { /* poll for the command to complete */ /* splx(s);*/ vs_poll(sc, xs); return (COMPLETE); } /* splx(s);*/ - return(SUCCESSFULLY_QUEUED); + return (SUCCESSFULLY_QUEUED); } int vs_chksense(xs) - struct scsi_xfer *xs; +struct scsi_xfer *xs; { - int flags, s, i; + int flags, s, i; struct scsi_link *slp = xs->sc_link; struct vs_softc *sc = slp->adapter_softc; struct scsi_sense *ss; M328_CQE *mc = (M328_CQE*)&sc->sc_vsreg->sh_MCE; M328_IOPB *riopb = (M328_IOPB *)&sc->sc_vsreg->sh_RET_IOPB; M328_IOPB *miopb = (M328_IOPB *)&sc->sc_vsreg->sh_MCE_IOPB; - + /* ack and clear the error */ CRB_CLR_DONE(CRSW); CRB_CLR_ER(CRSW); xs->status = 0; - - bzero(miopb, sizeof(M328_IOPB)); + + szero(miopb, sizeof(M328_IOPB)); /* This is a command, so point to it */ ss = (void *)&miopb->iopb_SCSI[0]; - bzero(ss, sizeof(*ss)); + szero(ss, sizeof(*ss)); ss->opcode = REQUEST_SENSE; ss->byte2 = slp->lun << 5; ss->length = sizeof(struct scsi_sense_data); - + miopb->iopb_CMD = IOPB_SCSI; miopb->iopb_OPTION = OPT_READ; miopb->iopb_NVCT = (u_char)sc->sc_nvec; @@ -368,8 +433,8 @@ vs_chksense(xs) miopb->iopb_ADDR = ADDR_MOD; LV(miopb->iopb_BUFF, kvtop(&xs->sense)); LV(miopb->iopb_LENGTH, sizeof(struct scsi_sense_data)); - - bzero(mc, sizeof(M328_CQE)); + + szero(mc, sizeof(M328_CQE)); mc->cqe_IOPB_ADDR = OFF(miopb); mc->cqe_IOPB_LENGTH = sizeof(M328_short_IOPB) + sizeof(struct scsi_sense); mc->cqe_WORK_QUEUE = 0; @@ -391,42 +456,42 @@ vs_chksense(xs) M328_CQE * vs_getcqe(sc) - struct vs_softc *sc; +struct vs_softc *sc; { M328_MCSB *mcsb = (M328_MCSB *)&sc->sc_vsreg->sh_MCSB; M328_CQE *cqep; - + cqep = (M328_CQE *)&sc->sc_vsreg->sh_CQE[mcsb->mcsb_QHDP]; - - if (cqep->cqe_QECR & M_QECR_GO) + + if (cqep->cqe_QECR & M_QECR_GO) return NULL; /* Hopefully, this will never happen */ mcsb->mcsb_QHDP++; if (mcsb->mcsb_QHDP == NUM_CQE) mcsb->mcsb_QHDP = 0; - bzero(cqep, sizeof(M328_CQE)); + szero(cqep, sizeof(M328_CQE)); return cqep; } M328_IOPB * vs_getiopb(sc) - struct vs_softc *sc; +struct vs_softc *sc; { M328_MCSB *mcsb = (M328_MCSB *)&sc->sc_vsreg->sh_MCSB; M328_IOPB *iopb; int slot; - - if (mcsb->mcsb_QHDP == 0) { + + if (mcsb->mcsb_QHDP == 0) { slot = NUM_CQE; } else { slot = mcsb->mcsb_QHDP - 1; } iopb = (M328_IOPB *)&sc->sc_vsreg->sh_IOPB[slot]; - bzero(iopb, sizeof(M328_IOPB)); + szero(iopb, sizeof(M328_IOPB)); return iopb; } void vs_initialize(sc) - struct vs_softc *sc; +struct vs_softc *sc; { M328_CIB *cib = (M328_CIB *)&sc->sc_vsreg->sh_CIB; M328_CQE *mc = (M328_CQE*)&sc->sc_vsreg->sh_MCE; @@ -438,7 +503,8 @@ vs_initialize(sc) u_short i, crsw; int failed = 0; - bzero(cib, sizeof(M328_CIB)); + CRB_CLR_DONE(CRSW); + szero(cib, sizeof(M328_CIB)); mcsb->mcsb_QHDP = 0; sc->sc_qhp = 0; cib->cib_NCQE = 10; @@ -464,7 +530,7 @@ vs_initialize(sc) cib->cib_SRATE1 = 0x0; iopb = (M328_IOPB *)&sc->sc_vsreg->sh_MCE_IOPB; - bzero(iopb, sizeof(M328_IOPB)); + szero(iopb, sizeof(M328_IOPB)); iopb->iopb_CMD = CNTR_INIT; iopb->iopb_OPTION = 0; iopb->iopb_NVCT = (u_char)sc->sc_nvec; @@ -473,8 +539,8 @@ vs_initialize(sc) iopb->iopb_ADDR = SHIO_MOD; LV(iopb->iopb_BUFF, OFF(cib)); LV(iopb->iopb_LENGTH, sizeof(M328_CIB)); - - bzero(mc, sizeof(M328_CQE)); + + szero(mc, sizeof(M328_CQE)); mc->cqe_IOPB_ADDR = OFF(iopb); mc->cqe_IOPB_LENGTH = sizeof(M328_IOPB); mc->cqe_WORK_QUEUE = 0; @@ -482,10 +548,10 @@ vs_initialize(sc) /* poll for the command to complete */ do_vspoll(sc, 0); CRB_CLR_DONE(CRSW); - + /* initialize work queues */ for (i=1; i<8; i++) { - bzero(wiopb, sizeof(M328_IOPB)); + szero(wiopb, sizeof(M328_IOPB)); wiopb->wqcf_CMD = CNTR_INIT_WORKQ; wiopb->wqcf_OPTION = 0; wiopb->wqcf_NVCT = (u_char)sc->sc_nvec; @@ -495,8 +561,8 @@ vs_initialize(sc) wiopb->wqcf_WOPT = (WQO_FOE | WQO_INIT); wiopb->wqcf_SLOTS = JAGUAR_MAX_Q_SIZ; LV(wiopb->wqcf_CMDTO, 2); - - bzero(mc, sizeof(M328_CQE)); + + szero(mc, sizeof(M328_CQE)); mc->cqe_IOPB_ADDR = OFF(wiopb); mc->cqe_IOPB_LENGTH = sizeof(M328_IOPB); mc->cqe_WORK_QUEUE = 0; @@ -504,12 +570,12 @@ vs_initialize(sc) /* poll for the command to complete */ do_vspoll(sc, 0); if (CRSW & M_CRSW_ER) { - printf("error: queue %d status = 0x%x\n", i, riopb->iopb_STATUS); + /*printf("\nerror: queue %d status = 0x%x\n", i, riopb->iopb_STATUS);*/ /*failed = 1;*/ CRB_CLR_ER(CRSW); } CRB_CLR_DONE(CRSW); - delay(1000); + delay(500); } /* start queue mode */ CRSW = 0; @@ -521,7 +587,7 @@ vs_initialize(sc) CRB_CLR_ER(CRSW); } CRB_CLR_DONE(CRSW); - + if (failed) { printf(": failed!\n"); return; @@ -530,12 +596,12 @@ vs_initialize(sc) vs_reset(sc); /* sync all devices */ vs_resync(sc); - printf(": target %d\n", sc->sc_link.adapter_target); + printf(": target %d\n", sc->sc_link.adapter_target); } - + void vs_resync(sc) - struct vs_softc *sc; +struct vs_softc *sc; { M328_CQE *mc = (M328_CQE*)&sc->sc_vsreg->sh_MCE; M328_IOPB *riopb = (M328_IOPB *)&sc->sc_vsreg->sh_RET_IOPB; @@ -543,15 +609,15 @@ vs_resync(sc) u_short i; for (i=0; i<7; i++) { - bzero(devreset, sizeof(M328_DRCF)); + szero(devreset, sizeof(M328_DRCF)); devreset->drcf_CMD = CNTR_DEV_REINIT; devreset->drcf_OPTION = 0x00; /* no interrupts yet... */ devreset->drcf_NVCT = sc->sc_nvec; devreset->drcf_EVCT = sc->sc_evec; devreset->drcf_ILVL = 0; devreset->drcf_UNIT = i; - - bzero(mc, sizeof(M328_CQE)); + + szero(mc, sizeof(M328_CQE)); mc->cqe_IOPB_ADDR = OFF(devreset); mc->cqe_IOPB_LENGTH = sizeof(M328_DRCF); mc->cqe_WORK_QUEUE = 0; @@ -572,12 +638,12 @@ vs_resync(sc) void vs_reset(sc) - struct vs_softc *sc; +struct vs_softc *sc; { - struct vsreg * rp; - u_int s; - u_char i; - struct iopb_reset* iopr; + struct vsreg * rp; + u_int s; + u_char i; + struct iopb_reset* iopr; struct cqe *cqep; struct iopb_scsi *iopbs; struct scsi_sense *ss; @@ -588,8 +654,8 @@ vs_reset(sc) M328_MCSB *mcsb = (M328_MCSB *)&sc->sc_vsreg->sh_MCSB; M328_SRCF *reset = (M328_SRCF *)&sc->sc_vsreg->sh_MCE_IOPB; M328_IOPB *iopb; - - bzero(reset, sizeof(M328_SRCF)); + + szero(reset, sizeof(M328_SRCF)); reset->srcf_CMD = IOPB_RESET; reset->srcf_OPTION = 0x00; /* no interrupts yet... */ reset->srcf_NVCT = sc->sc_nvec; @@ -597,14 +663,14 @@ vs_reset(sc) reset->srcf_ILVL = 0; reset->srcf_BUSID = 0; s = splbio(); - - bzero(mc, sizeof(M328_CQE)); + + szero(mc, sizeof(M328_CQE)); mc->cqe_IOPB_ADDR = OFF(reset); mc->cqe_IOPB_LENGTH = sizeof(M328_SRCF); mc->cqe_WORK_QUEUE = 0; mc->cqe_QECR = M_QECR_GO; /* poll for the command to complete */ - while(1){ + while (1) { do_vspoll(sc, 0); /* ack & clear scsi error condition cause by reset */ if (CRSW & M_CRSW_ER) { @@ -617,7 +683,7 @@ vs_reset(sc) } /* thaw all work queues */ thaw_queue(sc, 0xFF); - splx (s); + splx (s); } @@ -629,13 +695,13 @@ vs_reset(sc) int vs_checkintr(sc, xs, status) - struct vs_softc *sc; - struct scsi_xfer *xs; - int *status; +struct vs_softc *sc; +struct scsi_xfer *xs; +int *status; { - struct vsreg * rp = sc->sc_vsreg; - int target = -1; - int lun = -1; + struct vsreg * rp = sc->sc_vsreg; + int target = -1; + int lun = -1; M328_CRB *crb = (M328_CRB *)&sc->sc_vsreg->sh_CRB; M328_IOPB *riopb = (M328_IOPB *)&sc->sc_vsreg->sh_RET_IOPB; struct scsi_generic *cmd; @@ -646,7 +712,7 @@ vs_checkintr(sc, xs, status) target = xs->sc_link->target; lun = xs->sc_link->lun; cmd = (struct scsi_generic *)&riopb->iopb_SCSI[0]; - + VL(buf, riopb->iopb_BUFF); VL(len, riopb->iopb_LENGTH); *status = riopb->iopb_STATUS >> 8; @@ -654,8 +720,8 @@ vs_checkintr(sc, xs, status) #ifdef SDEBUG printf("scsi_chk() "); - - if (xs->cmd->opcode == 0){ + + if (xs->cmd->opcode == 0) { printf("TEST_UNIT_READY "); } else if (xs->cmd->opcode == REQUEST_SENSE) { printf("REQUEST_SENSE "); @@ -686,9 +752,9 @@ vs_checkintr(sc, xs, status) } else if (xs->cmd->opcode == 0x08) { printf("READ_COMMAND "); } - + printf("tgt %d lun %d buf %x len %d status %x ", target, lun, buf, len, riopb->iopb_STATUS); - + if (CRSW & M_CRSW_EX) { printf("[ex]"); } @@ -714,7 +780,7 @@ vs_checkintr(sc, xs, status) } else { xs->resid = 0; } - + if (error == SCSI_SELECTION_TO) { xs->error = XS_SELTIMEOUT; xs->status = -1; @@ -725,34 +791,235 @@ vs_checkintr(sc, xs, status) int vs_intr (sc) - register struct vs_softc *sc; +register struct vs_softc *sc; { M328_CRB *crb = (M328_CRB *)&sc->sc_vsreg->sh_CRB; - struct scsi_xfer *xs; + struct scsi_xfer *xs; + M328_CMD *m328_cmd; unsigned long loc; - int status; + int status; int s; - s = splbio(); - /* Got a valid interrupt on this device */ - + s = splbio(); + /* Got a valid interrupt on this device */ + VL(loc, crb->crb_CTAG); #ifdef SDEBUG printf("Interrupt!!! "); printf("loc == 0x%x\n", loc); #endif /* - * If this is a controller error, there won't be a scsi_xfer + * If this is a controller error, there won't be a m328_cmd * pointer in the CTAG feild. Bad things happen if you try * to point to address 0. Controller error should be handeled - * in m328dma.c I'll change this soon - steve. + * in vsdma.c I'll change this soon - steve. */ if (loc) { - xs = (struct scsi_xfer *)loc; + m328_cmd = (M328_CMD *)loc; + xs = m328_cmd->xs; + if (m328_cmd->top_sg_list) { + vs_dealloc_scatter_gather(m328_cmd->top_sg_list); + m328_cmd->top_sg_list = (M328_SG)0; + } + + FREE(m328_cmd, M_DEVBUF); /* free the command tag */ if (vs_checkintr (sc, xs, &status)) { vs_scsidone(xs, status); } } - splx(s); + splx(s); +} + +/* + * Useful functions for scatter/gather list + */ + +M328_SG +vs_alloc_scatter_gather(void) +{ + M328_SG sg; + + MALLOC(sg, M328_SG, sizeof(struct m328_sg), M_DEVBUF, M_WAITOK); + assert ( sg ); + if ( !sg ) { + panic ("Memory for scatter_gather_list not available"); + } + bzero(sg, sizeof(struct m328_sg)); + + return (sg); +} + +void +vs_dealloc_scatter_gather(M328_SG sg) +{ + register int i; + + if (sg->level > 0) { + for (i=0; sg->down[i] && i<MAX_SG_ELEMENTS; i++) { + vs_dealloc_scatter_gather(sg->down[i]); + } + } + FREE(sg, M_DEVBUF); +} + +void +vs_link_sg_element(sg_list_element_t * element, + register vm_offset_t phys_add, + register int len) +{ + element->count.bytes = len; + LV(element->address, phys_add); + element->link = 0; /* FALSE */ + element->transfer_type = NORMAL_TYPE; + element->memory_type = LONG_TRANSFER; + element->address_modifier = 0xD; +} + +void +vs_link_sg_list(sg_list_element_t * list, + register vm_offset_t phys_add, + register int elements) +{ + + list->count.scatter.gather = elements; + LV(list->address, phys_add); + list->link = 1; /* TRUE */ + list->transfer_type = NORMAL_TYPE; + list->memory_type = LONG_TRANSFER; + list->address_modifier = 0xD; } +M328_SG +vs_build_memory_structure(xs, iopb) +struct scsi_xfer *xs; +M328_IOPB *iopb; /* the iopb */ +{ + M328_SG sg; + vm_offset_t starting_point_virt, starting_point_phys, point_virt, + point1_phys, point2_phys, virt; + unsigned len; + int level; + + sg = (M328_SG)0; /* Hopefully we need no scatter/gather list */ + + /* + * We have the following things: + * virt the virtuell address of the contiguous virtual memory block + * len the lenght of the contiguous virtual memory block + * starting_point_virt the virtual address of the contiguous *physical* memory block + * starting_point_phys the *physical* address of the contiguous *physical* memory block + * point_virt the pointer to the virtual memory we are checking at the moment + * point1_phys the pointer to the *physical* memory we are checking at the moment + * point2_phys the pointer to the *physical* memory we are checking at the moment + */ + + level = 0; + virt = starting_point_virt = (vm_offset_t)xs->data; + point1_phys = starting_point_phys = kvtop(xs->data); + len = xs->datalen; + /* + * Check if we need scatter/gather + */ + + if (len > PAGESIZE) { + for (level = 0, point_virt = ROUND_PAGE(starting_point_virt+1); + /* if we do already scatter/gather we have to stay in the loop and jump */ + point_virt < virt + (vm_offset_t)len || sg ; + point_virt += PAGESIZE) { /* out later */ + + point2_phys = kvtop(point_virt); + + if ((point2_phys - TRUNC_PAGE(point1_phys) - PAGESIZE) || /* physical memory is not contiguous */ + (point_virt - starting_point_virt >= MAX_SG_BLOCK_SIZE && sg)) { /* we only can access (1<<16)-1 bytes in scatter/gather_mode */ + if (point_virt - starting_point_virt >= MAX_SG_BLOCK_SIZE) { /* We were walking too far for one scatter/gather block ... */ + assert( MAX_SG_BLOCK_SIZE > PAGESIZE ); + point_virt = TRUNC_PAGE(starting_point_virt+MAX_SG_BLOCK_SIZE-1); /* So go back to the beginning of the last matching page */ + /* and gererate the physadress of this location for the next time. */ + point2_phys = kvtop(point_virt); + } + + if (!sg) { + /* We allocate our fist scatter/gather list */ + sg = vs_alloc_scatter_gather(); + } +#if 1 /* broken firmware */ + + if (sg->elements >= MAX_SG_ELEMENTS) { + vs_dealloc_scatter_gather(sg); + return (NULL); + } + +#else /* if the firmware will ever get fixed */ + while (sg->elements >= MAX_SG_ELEMENTS) { + if (!sg->up) { /* If the list full in this layer ? */ + sg->up = vs_alloc_scatter_gather(); + sg->up->level = sg->level+1; + sg->up->down[0] = sg; + sg->up->elements = 1; + } + /* link this full list also in physical memory */ + vs_link_sg_list(&(sg->up->list[sg->up->elements-1]), + kvtop((vm_offset_t)sg->list), + sg->elements); + sg = sg->up; /* Climb up */ + } + while (sg->level) { /* As long as we are not a the base level */ + register int i; + + i = sg->elements; + /* We need a new element */ + sg->down[i] = vs_alloc_scatter_gather(); + sg->down[i]->level = sg->level - 1; + sg->down[i]->up = sg; + sg->elements++; + sg = sg->down[i]; /* Climb down */ + } +#endif /* 1 */ + + if (point_virt < virt+(vm_offset_t)len) { + /* linking element */ + vs_link_sg_element(&(sg->list[sg->elements]), + starting_point_phys, + point_virt-starting_point_virt); + sg->elements++; + } else { + /* linking last element */ + vs_link_sg_element(&(sg->list[sg->elements]), + starting_point_phys, + (vm_offset_t)(virt+len)-starting_point_virt); + sg->elements++; + break; /* We have now collected all blocks */ + } + starting_point_virt = point_virt; + starting_point_phys = point2_phys; + } + point1_phys = point2_phys; + } + } + + /* + * Climb up along the right side of the tree until we reach the top. + */ + + if (sg) { + while (sg->up) { + /* link this list also in physical memory */ + vs_link_sg_list(&(sg->up->list[sg->up->elements-1]), + kvtop((vm_offset_t)sg->list), + sg->elements); + sg = sg->up; /* Climb up */ + } + + iopb->iopb_OPTION |= M_OPT_SG; + iopb->iopb_ADDR |= M_ADR_SG_LINK; + LV(iopb->iopb_BUFF, kvtop((vm_offset_t)sg->list)); + LV(iopb->iopb_LENGTH, sg->elements); + LV(iopb->iopb_SGTTL, len); + } else { + /* no scatter/gather neccessary */ + LV(iopb->iopb_BUFF, starting_point_phys); + LV(iopb->iopb_LENGTH, len); + } + return (sg); +} + diff --git a/sys/arch/mvme88k/dev/vsdma.c b/sys/arch/mvme88k/dev/vsdma.c index c8a3186d0ab..ce15c791b55 100644 --- a/sys/arch/mvme88k/dev/vsdma.c +++ b/sys/arch/mvme88k/dev/vsdma.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vsdma.c,v 1.1 1999/05/29 04:41:44 smurph Exp $ */ +/* $OpenBSD: vsdma.c,v 1.2 1999/09/27 18:43:26 smurph Exp $ */ /* * Copyright (c) 1999 Steve Murphree, Jr. * All rights reserved. @@ -96,11 +96,13 @@ vsmatch(pdp, vcf, args) struct cfdata *cf = vcf; struct confargs *ca = args; if (!badvaddr(ca->ca_vaddr, 1)) { + /* if (ca->ca_vec & 0x03) { printf("vs: bad vector 0x%x\n", ca->ca_vec); return (0); } - return(1); + */ + return(1); } else { return (0); } diff --git a/sys/arch/mvme88k/dev/vsreg.h b/sys/arch/mvme88k/dev/vsreg.h index d722d62e7ea..8adac5f60fe 100644 --- a/sys/arch/mvme88k/dev/vsreg.h +++ b/sys/arch/mvme88k/dev/vsreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vsreg.h,v 1.1 1999/05/29 04:41:44 smurph Exp $ */ +/* $OpenBSD: vsreg.h,v 1.2 1999/09/27 18:43:26 smurph Exp $ */ /* * Copyright (c) 1999 Steve Murphree, Jr. * Copyright (c) 1990 The Regents of the University of California. @@ -38,6 +38,7 @@ #if !defined(_M328REG_H_) #define _M328REG_H_ + typedef struct LONGV { u_short msw; @@ -161,6 +162,52 @@ typedef struct mcsb /**************** END Master Control Status Block (MCSB) *******************/ +/**************** Scater/Gather Stuff *******************/ + +typedef struct { + union { + unsigned short bytes :16; + #define MAX_SG_BLOCK_SIZE (1<<16) /* the size *has* to be always *smaller* */ + struct { + unsigned short :8; + unsigned short gather :8; + } scatter; + } count; + LONGV address; + unsigned short link :1; + unsigned short :3; + unsigned short transfer_type :2; + /* 0x0 is reserved */ + #define SHORT_TREANSFER 0x1 + #define LONG_TRANSFER 0x2 + #define SCATTER_GATTER_LIST_IN_SHORT_IO 0x3 + unsigned short memory_type :2; + #define NORMAL_TYPE 0x0 + #define BLOCK_MODE 0x1 + /* 0x2 is reserved */ + /* 0x3 is reserved */ + unsigned short address_modifier :8; +}sg_list_element_t; + +typedef sg_list_element_t * scatter_gather_list_t; + +#define MAX_SG_ELEMENTS 64 + +struct m328_sg { + struct m328_sg *up; + int elements; + int level; + struct m328_sg *down[MAX_SG_ELEMENTS]; + sg_list_element_t list[MAX_SG_ELEMENTS]; +}; + +typedef struct m328_sg *M328_SG; + +typedef struct { + struct scsi_xfer *xs; + M328_SG top_sg_list; +} M328_CMD; +/**************** END Scater/Gather Stuff *******************/ /**************** Host Semaphore Block (HSB) *******************/ @@ -388,6 +435,7 @@ typedef struct csb #define M_ADR_TRANS 0x0C00 /* transfer type */ #define M_ADR_MEMT 0x0300 /* memory type */ #define M_ADR_MOD 0x00FF /* VME address modifier */ +#define M_ADR_SG_LINK 0x8000 /* Scatter/Gather Link bit */ /* * defines for IOPB Unit Address on SCSI Bus @@ -412,8 +460,7 @@ typedef struct short_iopb volatile u_short iopb_ADDR; /* IOPB Address type and modifer */ volatile LONGV iopb_BUFF; /* IOPB Buffer Address */ volatile LONGV iopb_LENGTH; /* IOPB Max-Transfer Length */ - volatile u_short iopb_RES2; /* IOPB Reserved word */ - volatile u_short iopb_RES3; /* IOPB Reserved word */ + volatile LONGV iopb_SGTTL; /* IOPB Scatter/Gather Total Transfer len */ volatile u_short iopb_RES4; /* IOPB Reserved word */ volatile u_short iopb_UNIT; /* IOPB Unit address on SCSI bus */ } M328_short_IOPB; @@ -431,8 +478,7 @@ typedef struct iopb volatile u_short iopb_ADDR; /* IOPB Address type and modifer */ volatile LONGV iopb_BUFF; /* IOPB Buffer Address */ volatile LONGV iopb_LENGTH; /* IOPB Max-Transfer Length */ - volatile u_short iopb_RES2; /* IOPB Reserved word */ - volatile u_short iopb_RES3; /* IOPB Reserved word */ + volatile LONGV iopb_SGTTL; /* IOPB Scatter/Gather Total Transfer len */ volatile u_short iopb_RES4; /* IOPB Reserved word */ volatile u_short iopb_UNIT; /* IOPB Unit address on SCSI bus */ u_short iopb_SCSI[S_IOPB_RES/2]; /* IOPB SCSI words for pass thru */ @@ -596,6 +642,7 @@ typedef struct ipsg #define CNTR_ISSUE_ABORT 0x4E /* An abort has been issued */ #define CNTR_DOWNLOAD_FIRMWARE 0x4F /* Download firmware (COUGAR) */ + /* * Memory types */ @@ -692,4 +739,18 @@ typedef struct ipsg #define D64_MOD ( (TT_D64 << 10) | (MEMTYPE << 8) | ADRM_EXT_S_D64 ) #define SHIO_MOD ( (TT_NORMAL << 10) | (MEMT_SHIO << 8) | ADRM_SHT_N_IO) +/* + * Scatter/gather functions + */ + +M328_SG vs_alloc_scatter_gather __P((void)); +void vs_dealloc_scatter_gather __P((M328_SG sg)); +void vs_link_scatter_gather_element __P((sg_list_element_t *element, + register vm_offset_t phys_add, + register int len)); +void vs_link_scatter_gather_list __P((sg_list_element_t *list, + register vm_offset_t phys_add, + register int elements)); +M328_SG vs_build_memory_structure __P((struct scsi_xfer *xs, M328_IOPB *iopb)); + #endif /* _M328REG_H_ */ |