diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1996-04-21 22:33:19 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1996-04-21 22:33:19 +0000 |
commit | 67d88b0a9910a68bb666b448d2dac29cb4d3d8c2 (patch) | |
tree | 967b89f6e07398a22bd8c76d30179b648776542d /sys/dev/ic | |
parent | ba95d3c1d69cdb251d15a12ebf70f50b0ea2019b (diff) |
partial sync with netbsd 960418, more to come
Diffstat (limited to 'sys/dev/ic')
-rw-r--r-- | sys/dev/ic/aic7xxx.c | 24 | ||||
-rw-r--r-- | sys/dev/ic/aic7xxxvar.h | 6 | ||||
-rw-r--r-- | sys/dev/ic/am7990.c | 57 | ||||
-rw-r--r-- | sys/dev/ic/com.c | 116 | ||||
-rw-r--r-- | sys/dev/ic/comvar.h | 5 | ||||
-rw-r--r-- | sys/dev/ic/ncr5380sbc.c | 23 | ||||
-rw-r--r-- | sys/dev/ic/smc90cx6.c | 1231 | ||||
-rw-r--r-- | sys/dev/ic/smc90cx6reg.h | 99 | ||||
-rw-r--r-- | sys/dev/ic/z8530sc.c | 108 | ||||
-rw-r--r-- | sys/dev/ic/z8530sc.h | 12 | ||||
-rw-r--r-- | sys/dev/ic/z8530tty.c | 253 |
11 files changed, 1695 insertions, 239 deletions
diff --git a/sys/dev/ic/aic7xxx.c b/sys/dev/ic/aic7xxx.c index a3bf8e44807..215e059b98d 100644 --- a/sys/dev/ic/aic7xxx.c +++ b/sys/dev/ic/aic7xxx.c @@ -1,5 +1,5 @@ -/* $OpenBSD: aic7xxx.c,v 1.3 1996/04/18 23:47:15 niklas Exp $ */ -/* $NetBSD: aic7xxx.c,v 1.3 1996/02/25 22:56:30 cgd Exp $ */ +/* $OpenBSD: aic7xxx.c,v 1.4 1996/04/21 22:21:03 deraadt Exp $ */ +/* $NetBSD: aic7xxx.c,v 1.5 1996/03/29 00:24:58 mycroft Exp $ */ /* * Generic driver for the aic7xxx based adaptec SCSI controllers @@ -63,13 +63,12 @@ void ahcminphys __P((struct buf *)); int ahc_poll __P((struct ahc_softc *, struct scsi_xfer *, int)); /* Different debugging levels */ +#ifdef AHC_DEBUG #define AHC_SHOWMISC 0x0001 #define AHC_SHOWCMDS 0x0002 #define AHC_SHOWSCBS 0x0004 -/*#define AHC_DEBUG /**/ int ahc_debug = AHC_SHOWMISC; - -/*#define AHC_MORE_DEBUG /**/ +#endif #ifdef AHC_MORE_DEBUG #define DEBUGLEVEL -1 @@ -629,7 +628,6 @@ ahc_scsirate(offset, period, ahc, target) struct ahc_softc *ahc; int target; { - u_char scsirate; int i; for (i = 0; i < ahc_num_syncrates; i++) { @@ -652,9 +650,15 @@ ahc_scsirate(offset, period, ahc, target) #endif /* AHC_DEBUG */ } -ahcprint() +int +ahcprint(aux, name) + void *aux; + char *name; { + if (name != NULL) + printf("%s: scsibus ", name); + return UNCONF; } /* @@ -768,7 +772,7 @@ ahcintr(ahc) break; case NO_IDENT: panic("%s: No IDENTIFY message from reconnecting " - "target %d at seqaddr = 0x%lx " + "target %d at seqaddr = 0x%x " "SAVED_TCL == 0x%x\n", ahc->sc_dev.dv_xname, (inb(SELID + iobase) >> 4) & 0xf, @@ -847,7 +851,7 @@ ahcintr(ahc) */ #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOWMISC) - printf("Sending SDTR!!\n"); + printf("Sending SDTR!!\n"); #endif outb(HA_RETURN_1 + iobase, SEND_SDTR); } @@ -1018,7 +1022,6 @@ ahcintr(ahc) if (xs->error == XS_NOERROR && scb->flags != SCB_CHKSENSE) { - u_char flags; u_char head; u_char tail; struct ahc_dma_seg *sg = scb->ahc_dma; @@ -1389,7 +1392,6 @@ ahc_init(ahc) ahc->sc_dev.dv_xname, sizeof(struct ahc_scb), SCB_DOWN_SIZE, sizeof(struct ahc_dma_seg)); #endif /* AHC_DEBUG */ - /*printf("%s: reading board settings\n", ahc->sc_dev.dv_xname);/**/ /* Save the IRQ type before we do a chip reset */ diff --git a/sys/dev/ic/aic7xxxvar.h b/sys/dev/ic/aic7xxxvar.h index 48e902a398c..82022e8ab35 100644 --- a/sys/dev/ic/aic7xxxvar.h +++ b/sys/dev/ic/aic7xxxvar.h @@ -1,5 +1,5 @@ -/* $OpenBSD: aic7xxxvar.h,v 1.2 1996/04/18 23:47:16 niklas Exp $ */ -/* $NetBSD: aic7xxxvar.h,v 1.2 1996/03/14 02:30:30 cgd Exp $ */ +/* $OpenBSD: aic7xxxvar.h,v 1.3 1996/04/21 22:21:12 deraadt Exp $ */ +/* $NetBSD: aic7xxxvar.h,v 1.3 1996/03/29 00:25:02 mycroft Exp $ */ /* * Interface to the generic driver for the aic7xxx based adaptec @@ -27,8 +27,6 @@ #ifndef _AIC7XXX_H_ #define _AIC7XXX_H_ -/*#include "ahc.h" /* for NAHC from config */ - #define AHC_NSEG 256 /* number of dma segments supported */ #define AHC_SCB_MAX 16 /* diff --git a/sys/dev/ic/am7990.c b/sys/dev/ic/am7990.c index 87c5712eba2..b050dd728db 100644 --- a/sys/dev/ic/am7990.c +++ b/sys/dev/ic/am7990.c @@ -1,5 +1,5 @@ -/* $OpenBSD: am7990.c,v 1.4 1996/04/18 23:47:17 niklas Exp $ */ -/* $NetBSD: am7990.c,v 1.11 1996/03/14 19:05:07 christos Exp $ */ +/* $OpenBSD: am7990.c,v 1.5 1996/04/21 22:21:15 deraadt Exp $ */ +/* $NetBSD: am7990.c,v 1.16 1996/04/09 15:21:59 pk Exp $ */ /*- * Copyright (c) 1995 Charles M. Hannum. All rights reserved. @@ -74,6 +74,10 @@ void xmit_print __P((struct le_softc *, int)); #define ifp (&sc->sc_arpcom.ac_if) +#ifndef ETHER_CMP +#define ETHER_CMP(a, b) bcmp((a), (b), ETHER_ADDR_LEN) +#endif + void leconfig(sc) struct le_softc *sc; @@ -123,8 +127,8 @@ leconfig(sc) panic("leconfig: weird memory size"); } - printf(": address %s\n%s: %d receive buffers, %d transmit buffers\n", - ether_sprintf(sc->sc_arpcom.ac_enaddr), + printf(": address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr)); + printf("%s: %d receive buffers, %d transmit buffers\n", sc->sc_dev.dv_xname, sc->sc_nrbuf, sc->sc_ntbuf); mem = 0; @@ -420,8 +424,7 @@ leread(sc, boff, len) */ if ((ifp->if_flags & IFF_PROMISC) != 0 && (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */ - bcmp(eh->ether_dhost, sc->sc_arpcom.ac_enaddr, - sizeof(eh->ether_dhost)) != 0) { + ETHER_CMP(eh->ether_dhost, sc->sc_arpcom.ac_enaddr)) { m_freem(m); return; } @@ -430,10 +433,15 @@ leread(sc, boff, len) #endif #ifdef LANCE_REVC_BUG - if (bcmp(eh->ether_dhost, sc->sc_arpcom.ac_enaddr, - sizeof(eh->ether_dhost)) != 0 && - bcmp(eh->ether_dhost, etherbroadcastaddr, - sizeof(eh->ether_dhost)) != 0) { + /* + * The old LANCE (Rev. C) chips have a bug which causes + * garbage to be inserted in front of the received packet. + * The work-around is to ignore packets with an invalid + * destination address (garbage will usually not match). + * Of course, this precludes multicast support... + */ + if (ETHER_CMP(eh->ether_dhost, sc->sc_arpcom.ac_enaddr) && + ETHER_CMP(eh->ether_dhost, etherbroadcastaddr)) { m_freem(m); return; } @@ -483,7 +491,7 @@ lerint(sc) printf("%s: receive buffer error\n", sc->sc_dev.dv_xname); ifp->if_ierrors++; - } else if (rmd.rmd1_bits & (LE_R1_STP | LE_R1_ENP) != + } else if ((rmd.rmd1_bits & (LE_R1_STP | LE_R1_ENP)) != (LE_R1_STP | LE_R1_ENP)) { printf("%s: dropping chained buffer\n", sc->sc_dev.dv_xname); @@ -503,8 +511,12 @@ lerint(sc) #ifdef LEDEBUG if (sc->sc_debug) - printf("sc->sc_last_rd = %x, rmd = %x\n", - sc->sc_last_rd, rmd); + printf("sc->sc_last_rd = %x, rmd: " + "ladr %04x, hadr %02x, flags %02x, " + "bcnt %04x, mcnt %04x\n", + sc->sc_last_rd, + rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits, + rmd.rmd2, rmd.rmd3); #endif if (++bix == sc->sc_nrbuf) @@ -529,7 +541,11 @@ letint(sc) #ifdef LEDEBUG if (sc->sc_debug) - printf("trans tmd = %x\n", tmd); + printf("trans tmd: " + "ladr %04x, hadr %02x, flags %02x, " + "bcnt %04x, mcnt %04x\n", + tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits, + tmd.tmd2, tmd.tmd3); #endif (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, bix), @@ -877,9 +893,10 @@ recv_print(sc, no) rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits, rmd.rmd2, rmd.rmd3); if (len >= sizeof(eh)) { (*sc->sc_copyfrombuf)(sc, &eh, LE_RBUFADDR(sc, no), sizeof(eh)); - printf("%s: dst %s", ether_sprintf(eh.ether_dhost)); + printf("%s: dst %s", sc->sc_dev.dv_xname, + ether_sprintf(eh.ether_dhost)); printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost), - ntohs(eh.ether_type)); + ntohs(eh.ether_type)); } } @@ -902,7 +919,8 @@ xmit_print(sc, no) tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits, tmd.tmd2, tmd.tmd3); if (len >= sizeof(eh)) { (*sc->sc_copyfrombuf)(sc, &eh, LE_TBUFADDR(sc, no), sizeof(eh)); - printf("%s: dst %s", ether_sprintf(eh.ether_dhost)); + printf("%s: dst %s", sc->sc_dev.dv_xname, + ether_sprintf(eh.ether_dhost)); printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost), ntohs(eh.ether_type)); } @@ -938,8 +956,7 @@ lesetladrf(ac, af) af[0] = af[1] = af[2] = af[3] = 0x0000; ETHER_FIRST_MULTI(step, ac, enm); while (enm != NULL) { - if (bcmp(enm->enm_addrlo, enm->enm_addrhi, - sizeof(enm->enm_addrlo)) != 0) { + if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) { /* * We must listen to a range of multicast addresses. * For now, just accept all multicasts, rather than @@ -1058,7 +1075,6 @@ copytobuf_gap2(sc, fromv, boff, len) volatile caddr_t buf = sc->sc_mem; register caddr_t from = fromv; register volatile u_int16_t *bptr; - register int xfer; if (boff & 0x1) { /* handle unaligned first byte */ @@ -1088,7 +1104,6 @@ copyfrombuf_gap2(sc, tov, boff, len) register caddr_t to = tov; register volatile u_int16_t *bptr; register u_int16_t tmp; - register int xfer; if (boff & 0x1) { /* handle unaligned first byte */ diff --git a/sys/dev/ic/com.c b/sys/dev/ic/com.c index d34ba82a096..77dd24748f4 100644 --- a/sys/dev/ic/com.c +++ b/sys/dev/ic/com.c @@ -1,5 +1,5 @@ -/* $OpenBSD: com.c,v 1.10 1996/04/18 23:47:32 niklas Exp $ */ -/* $NetBSD: com.c,v 1.75 1996/03/10 09:01:24 cgd Exp $ */ +/* $OpenBSD: com.c,v 1.11 1996/04/21 22:23:15 deraadt Exp $ */ +/* $NetBSD: com.c,v 1.79 1996/04/15 18:54:31 cgd Exp $ */ /*- * Copyright (c) 1993, 1994, 1995, 1996 @@ -57,7 +57,11 @@ #include <sys/types.h> #include <sys/device.h> -#include <machine/cpu.h> +#ifdef i386 /* XXX */ +#include <machine/cpu.h> /* XXX */ +#else /* XXX */ +#include <machine/intr.h> +#endif /* XXX */ #include <machine/bus.h> #include <dev/isa/isavar.h> @@ -69,6 +73,8 @@ #endif #define com_lcr com_cfcr +#include "com.h" + #define COM_IBUFSIZE (2 * 512) #define COM_IHIGHWATER ((3 * COM_IBUFSIZE) / 4) @@ -109,11 +115,9 @@ struct com_softc { u_char sc_ibufs[2][COM_IBUFSIZE]; }; -int comprobe __P((struct device *, void *, void *)); #ifdef COM_HAYESP int comprobeHAYESP __P((bus_io_handle_t hayespioh, struct com_softc *sc)); #endif -void comattach __P((struct device *, struct device *, void *)); int comopen __P((dev_t, int, int, struct proc *)); int comclose __P((dev_t, int, int, struct proc *)); void comdiag __P((void *)); @@ -122,11 +126,30 @@ void compoll __P((void *)); int comparam __P((struct tty *, struct termios *)); void comstart __P((struct tty *)); -int cominit __P((bus_chipset_tag_t, bus_io_handle_t, int)); +/* + * XXX the following two cfattach structs should be different, and possibly + * XXX elsewhere. + */ +int comprobe __P((struct device *, void *, void *)); +void comattach __P((struct device *, struct device *, void *)); + +#if NCOM_ISA +struct cfattach com_isa_ca = { + sizeof(struct com_softc), comprobe, comattach +}; +#endif -struct cfdriver comcd = { - NULL, "com", comprobe, comattach, DV_TTY, sizeof(struct com_softc) +#if NCOM_COMMULTI +struct cfattach com_commulti_ca = { + sizeof(struct com_softc), comprobe, comattach }; +#endif + +struct cfdriver com_cd = { + NULL, "com", DV_TTY +}; + +int cominit __P((bus_chipset_tag_t, bus_io_handle_t, int)); #ifdef COMCONSOLE int comdefaultrate = CONSPEED; /* XXX why set default? */ @@ -138,6 +161,7 @@ int comconsinit; int comconsattached; bus_chipset_tag_t comconsbc; bus_io_handle_t comconsioh; +tcflag_t comconscflag = TTYDEF_CFLAG; int commajor; int comsopen = 0; @@ -157,7 +181,7 @@ extern int kgdb_debug_init; #define CLR(t, f) (t) &= ~(f) #define ISSET(t, f) ((t) & (f)) -#include "pcmciabus.h" +/*#include "pcmciabus.h"*/ #if NPCMCIABUS >0 /* additional setup needed for pcmcia devices */ #include <dev/pcmcia/pcmciabus.h> @@ -327,13 +351,22 @@ comprobe(parent, match, aux) int iobase, needioh; int rv = 1; + /* + * XXX should be broken out into functions for isa probe and + * XXX for commulti probe, with a helper function that contains + * XXX most of the interesting stuff. + */ +#if NCOM_ISA if (!strcmp(parent->dv_cfdata->cf_driver->cd_name, "isa")) { struct isa_attach_args *ia = aux; bc = ia->ia_bc; iobase = ia->ia_iobase; needioh = 1; - } else { + } else +#endif +#if NCOM_COMMULTI + if (1) { struct commulti_attach_args *ca = aux; if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != ca->ca_slave) @@ -343,7 +376,9 @@ comprobe(parent, match, aux) iobase = ca->ca_iobase; ioh = ca->ca_ioh; needioh = 0; - } + } else +#endif + return(0); /* This cannot happen */ /* if it's in use as console, it's there. */ if (iobase == comconsaddr && !comconsattached) @@ -358,12 +393,14 @@ comprobe(parent, match, aux) bus_io_unmap(bc, ioh, COM_NPORTS); out: +#if NCOM_ISA if (rv && !strcmp(parent->dv_cfdata->cf_driver->cd_name, "isa")) { struct isa_attach_args *ia = aux; ia->ia_iosize = COM_NPORTS; ia->ia_msize = 0; } +#endif return (rv); } @@ -383,8 +420,14 @@ comattach(parent, self, aux) int *hayespp; #endif + /* + * XXX should be broken out into functions for isa attach and + * XXX for commulti attach, with a helper function that contains + * XXX most of the interesting stuff. + */ sc->sc_hwflags = 0; sc->sc_swflags = 0; +#if NCOM_ISA if (!strcmp(parent->dv_cfdata->cf_driver->cd_name, "isa")) { struct isa_attach_args *ia = aux; @@ -399,7 +442,10 @@ comattach(parent, self, aux) } else ioh = comconsioh; irq = ia->ia_irq; - } else { + } else +#endif +#if NCOM_COMMULTI + if (1) { struct commulti_attach_args *ca = aux; /* @@ -412,7 +458,9 @@ comattach(parent, self, aux) if (ca->ca_noien) sc->sc_hwflags |= COM_HW_NOIEN; - } + } else +#endif + panic("comattach: impossible"); sc->sc_bc = bc; sc->sc_ioh = ioh; @@ -473,9 +521,18 @@ comattach(parent, self, aux) bus_io_write_1(bc, ioh, com_ier, 0); bus_io_write_1(bc, ioh, com_mcr, 0); - if (irq != IRQUNK) - sc->sc_ih = isa_intr_establish(irq, IST_EDGE, IPL_TTY, - comintr, sc, sc->sc_dev.dv_xname); + if (irq != IRQUNK) { +#if NCOM_ISA + if (!strcmp(parent->dv_cfdata->cf_driver->cd_name, "isa")) { + struct isa_attach_args *ia = aux; + + sc->sc_ih = isa_intr_establish(ia->ia_ic, irq, + IST_EDGE, IPL_TTY, comintr, sc, + sc->sc_dev.dv_xname); + } else +#endif + panic("comattach: IRQ but can't have one"); + } #ifdef KGDB if (kgdb_dev == makedev(commajor, unit)) { @@ -516,9 +573,9 @@ comopen(dev, flag, mode, p) int s; int error = 0; - if (unit >= comcd.cd_ndevs) + if (unit >= com_cd.cd_ndevs) return ENXIO; - sc = comcd.cd_devs[unit]; + sc = com_cd.cd_devs[unit]; if (!sc) return ENXIO; @@ -535,7 +592,10 @@ comopen(dev, flag, mode, p) ttychars(tp); tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; - tp->t_cflag = TTYDEF_CFLAG; + if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) + tp->t_cflag = comconscflag; + else + tp->t_cflag = TTYDEF_CFLAG; if (ISSET(sc->sc_swflags, COM_SW_CLOCAL)) SET(tp->t_cflag, CLOCAL); if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS)) @@ -644,7 +704,7 @@ comclose(dev, flag, mode, p) struct proc *p; { int unit = COMUNIT(dev); - struct com_softc *sc = comcd.cd_devs[unit]; + struct com_softc *sc = com_cd.cd_devs[unit]; struct tty *tp = sc->sc_tty; bus_chipset_tag_t bc = sc->sc_bc; bus_io_handle_t ioh = sc->sc_ioh; @@ -684,7 +744,7 @@ comread(dev, uio, flag) struct uio *uio; int flag; { - struct com_softc *sc = comcd.cd_devs[COMUNIT(dev)]; + struct com_softc *sc = com_cd.cd_devs[COMUNIT(dev)]; struct tty *tp = sc->sc_tty; return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); @@ -696,7 +756,7 @@ comwrite(dev, uio, flag) struct uio *uio; int flag; { - struct com_softc *sc = comcd.cd_devs[COMUNIT(dev)]; + struct com_softc *sc = com_cd.cd_devs[COMUNIT(dev)]; struct tty *tp = sc->sc_tty; return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); @@ -706,7 +766,7 @@ struct tty * comtty(dev) dev_t dev; { - struct com_softc *sc = comcd.cd_devs[COMUNIT(dev)]; + struct com_softc *sc = com_cd.cd_devs[COMUNIT(dev)]; struct tty *tp = sc->sc_tty; return (tp); @@ -734,7 +794,7 @@ comioctl(dev, cmd, data, flag, p) struct proc *p; { int unit = COMUNIT(dev); - struct com_softc *sc = comcd.cd_devs[unit]; + struct com_softc *sc = com_cd.cd_devs[unit]; struct tty *tp = sc->sc_tty; bus_chipset_tag_t bc = sc->sc_bc; bus_io_handle_t ioh = sc->sc_ioh; @@ -846,7 +906,7 @@ comparam(tp, t) struct tty *tp; struct termios *t; { - struct com_softc *sc = comcd.cd_devs[COMUNIT(tp->t_dev)]; + struct com_softc *sc = com_cd.cd_devs[COMUNIT(tp->t_dev)]; bus_chipset_tag_t bc = sc->sc_bc; bus_io_handle_t ioh = sc->sc_ioh; int ospeed = comspeed(t->c_ospeed); @@ -985,7 +1045,7 @@ void comstart(tp) struct tty *tp; { - struct com_softc *sc = comcd.cd_devs[COMUNIT(tp->t_dev)]; + struct com_softc *sc = com_cd.cd_devs[COMUNIT(tp->t_dev)]; bus_chipset_tag_t bc = sc->sc_bc; bus_io_handle_t ioh = sc->sc_ioh; int s; @@ -1106,8 +1166,8 @@ compoll(arg) comevents = 0; splx(s); - for (unit = 0; unit < comcd.cd_ndevs; unit++) { - sc = comcd.cd_devs[unit]; + for (unit = 0; unit < com_cd.cd_ndevs; unit++) { + sc = com_cd.cd_devs[unit]; if (sc == 0 || sc->sc_ibufp == sc->sc_ibuf) continue; diff --git a/sys/dev/ic/comvar.h b/sys/dev/ic/comvar.h index 9b412b06936..c3f8068caec 100644 --- a/sys/dev/ic/comvar.h +++ b/sys/dev/ic/comvar.h @@ -1,5 +1,5 @@ -/* $OpenBSD: comvar.h,v 1.1 1996/04/19 16:08:34 niklas Exp $ */ -/* $NetBSD: comvar.h,v 1.3 1996/03/10 09:01:26 cgd Exp $ */ +/* $OpenBSD: comvar.h,v 1.2 1996/04/21 22:23:20 deraadt Exp $ */ +/* $NetBSD: comvar.h,v 1.4 1996/04/15 18:54:35 cgd Exp $ */ /* * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved. @@ -46,3 +46,4 @@ extern int comconsaddr; extern int comconsattached; extern bus_chipset_tag_t comconsbc; extern bus_io_handle_t comconsioh; +extern tcflag_t comconscflag; diff --git a/sys/dev/ic/ncr5380sbc.c b/sys/dev/ic/ncr5380sbc.c index 2fe5e7db748..a7e356d4bac 100644 --- a/sys/dev/ic/ncr5380sbc.c +++ b/sys/dev/ic/ncr5380sbc.c @@ -1,5 +1,5 @@ -/* $OpenBSD: ncr5380sbc.c,v 1.4 1996/04/18 23:47:19 niklas Exp $ */ -/* $NetBSD: ncr5380sbc.c,v 1.8 1996/03/07 15:00:17 christos Exp $ */ +/* $OpenBSD: ncr5380sbc.c,v 1.5 1996/04/21 22:21:21 deraadt Exp $ */ +/* $NetBSD: ncr5380sbc.c,v 1.9 1996/03/18 23:09:02 gwr Exp $ */ /* * Copyright (c) 1995 David Jones, Gordon W. Ross @@ -2330,8 +2330,25 @@ do_actions: if (act_flags & ACT_DISCONNECT) { /* * The device has dropped BSY (or will soon). - * Return and let ncr5380_sched() do its thing. + * We have to wait here for BSY to drop, otherwise + * the next command may decide we need a bus reset. */ + timo = ncr5380_wait_nrq_timo; /* XXX */ + for (;;) { + if (!SCI_BUSY(sc)) + goto busfree; + if (--timo <= 0) + break; + delay(2); + } + /* Device is sitting on the bus! */ + printf("%s: SCSI job did not finish, resetting...\n", + sc->sc_dev.dv_xname); + ncr5380_reset_scsibus(sc); + busfree: + NCR_TRACE("machine: discon, waited %d\n", + ncr5380_wait_nrq_timo - timo); + *sc->sci_icmd = 0; *sc->sci_mode = 0; *sc->sci_tcmd = PHASE_INVALID; diff --git a/sys/dev/ic/smc90cx6.c b/sys/dev/ic/smc90cx6.c new file mode 100644 index 00000000000..afa12df2b80 --- /dev/null +++ b/sys/dev/ic/smc90cx6.c @@ -0,0 +1,1231 @@ +/* $NetBSD: smc90cx6.c,v 1.16 1996/03/20 13:28:50 is Exp $ */ + +/* + * Copyright (c) 1994, 1995 Ignatios Souvatzis + * 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 Ignatios Souvatzis + * for the NetBSD Project. + * 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. + */ + +/* + * Driver for the Commodore Busines Machines ARCnet card. + */ + +#define BAHASMCOPY /**/ +#define BAHSOFTCOPY /**/ +#define BAHRETRANSMIT /**/ +/* #define BAHTIMINGS */ +/* #define BAH_DEBUG 3 */ + +/* zeroth version of M68060 support */ + +#if defined(M68060) && defined(BAHASMCOPY) +#undef BAHASMCOPY +#endif + +#include "bpfilter.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/buf.h> +#include <sys/device.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/syslog.h> +#include <sys/ioctl.h> +#include <sys/errno.h> + +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_types.h> +#include <net/netisr.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#include <netinet/if_ether.h> +#include <netinet/if_arc.h> +#endif + +#if NBPFILTER > 0 +#include <net/bpf.h> +#include <net/bpfdesc.h> +#endif + +#include <sys/kernel.h> +#include <machine/cpu.h> +#include <machine/mtpr.h> + +#include <amiga/amiga/device.h> +#include <amiga/amiga/isr.h> +#include <amiga/dev/zbusvar.h> +#include <amiga/dev/if_bahreg.h> + +/* these should be elsewhere */ + +#define ARC_MIN_LEN 1 +#define ARC_MIN_FORBID_LEN 254 +#define ARC_MAX_FORBID_LEN 256 +#define ARC_MAX_LEN 508 +#define ARC_ADDR_LEN 1 + +/* for watchdog timer. This should be more than enough. */ +#define ARCTIMEOUT (5*IFNET_SLOWHZ) + +/* + * This currently uses 2 bufs for tx, 2 for rx + * + * New rx protocol: + * + * rx has a fillcount variable. If fillcount > (NRXBUF-1), + * rx can be switched off from rx hard int. + * Else rx is restarted on the other receiver. + * rx soft int counts down. if it is == (NRXBUF-1), it restarts + * the receiver. + * To ensure packet ordering (we need that for 1201 later), we have a counter + * which is incremented modulo 256 on each receive and a per buffer + * variable, which is set to the counter on filling. The soft int can + * compare both values to determine the older packet. + * + * Transmit direction: + * + * bah_start checks tx_fillcount + * case 2: return + * + * else fill tx_act ^ 1 && inc tx_fillcount + * + * check tx_fillcount again. + * case 2: set IFF_OACTIVE to stop arc_output from filling us. + * case 1: start tx + * + * tint clears IFF_OCATIVE, decrements and checks tx_fillcount + * case 1: start tx on tx_act ^ 1, softcall bah_start + * case 0: softcall bah_start + * + * #define fill(i) get mbuf && copy mbuf to chip(i) + */ + +#ifdef BAHTIMINGS +/* + * ARCnet stats; per interface. + */ +struct bah_stats { + u_long mincopyin; + u_long maxcopyin; /* divided by byte count */ + u_long mincopyout; + u_long maxcopyout; + u_long minsend; + u_long maxsend; + u_long lasttxstart_mics; + struct timeval lasttxstart_tv; +}; + +#error BAHTIMINGS CODE IS BROKEN; use of clkread() is bogus +#endif + +/* + * Arcnet software status per interface + */ +struct bah_softc { + struct device sc_dev; + struct arccom sc_arccom; /* Common arcnet structures */ + struct isr sc_isr; + struct a2060 *sc_base; + u_long sc_recontime; /* seconds only, I'm lazy */ + u_long sc_reconcount; /* for the above */ + u_long sc_reconcount_excessive; /* for the above */ +#define ARC_EXCESSIVE_RECONS 20 +#define ARC_EXCESSIVE_RECONS_REWARN 400 + u_char sc_intmask; + u_char sc_rx_act; /* 2..3 */ + u_char sc_tx_act; /* 0..1 */ + u_char sc_rx_fillcount; + u_char sc_tx_fillcount; + u_char sc_broadcast[2]; /* is it a broadcast packet? */ + u_char sc_retransmits[2]; /* unused at the moment */ +#ifdef BAHTIMINGS + struct bah_stats sc_stats; +#endif +}; + +int bah_zbus_match __P((struct device *, void *, void *)); +void bah_zbus_attach __P((struct device *, struct device *, void *)); +void bah_init __P((struct bah_softc *)); +void bah_reset __P((struct bah_softc *)); +void bah_stop __P((struct bah_softc *)); +void bah_start __P((struct ifnet *)); +int bahintr __P((struct bah_softc *sc)); +int bah_ioctl __P((struct ifnet *, unsigned long, caddr_t)); +void bah_watchdog __P((int)); +void movepout __P((u_char *from, u_char __volatile *to, int len)); +void movepin __P((u_char __volatile *from, u_char *to, int len)); +void bah_srint __P((void *vsc, void *dummy)); +void callstart __P((void *vsc, void *dummy)); + +#ifdef BAHTIMINGS +int clkread(); +#endif + +struct cfattach bah_zbus_ca = { + sizeof(struct bah_softc), bah_zbus_match, bah_zbus_attach +}; + +struct cfdriver bah_cd = { + NULL, "bah", DV_IFNET +}; + +int +bah_zbus_match(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + struct zbus_args *zap = aux; + + if ((zap->manid == 514 || zap->manid == 1053) && zap->prodid == 9) + return (1); + + return (0); +} + +void +bah_zbus_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct bah_softc *sc = (void *)self; + struct zbus_args *zap = aux; + struct ifnet *ifp = &sc->sc_arccom.ac_if; + int s, linkaddress; + +#if (defined(BAH_DEBUG) && (BAH_DEBUG > 2)) + printf("\n%s: attach(0x%x, 0x%x, 0x%x)\n", + sc->sc_dev.dv_xname, parent, self, aux); +#endif + s = splhigh(); + sc->sc_base = zap->va; + + /* + * read the arcnet address from the board + */ + + sc->sc_base->kick1 = 0x0; + sc->sc_base->kick2 = 0x0; + DELAY(200); + + sc->sc_base->kick1 = 0xFF; + sc->sc_base->kick2 = 0xFF; + do { + DELAY(200); + } while (!(sc->sc_base->status & ARC_POR)); + + linkaddress = sc->sc_base->dipswitches; + +#ifdef BAHTIMINGS + printf(": link addr 0x%02x(%ld), with timer\n", + linkaddress, linkaddress); +#else + printf(": link addr 0x%02x(%ld)\n", linkaddress, linkaddress); +#endif + + sc->sc_arccom.ac_anaddr = linkaddress; + + /* clear the int mask... */ + + sc->sc_base->status = sc->sc_intmask = 0; + + sc->sc_base->command = ARC_CONF(CONF_LONG); + sc->sc_base->command = ARC_CLR(CLR_POR|CLR_RECONFIG); + sc->sc_recontime = sc->sc_reconcount = 0; + + /* and reenable kernel int level */ + splx(s); + + /* + * set interface to stopped condition (reset) + */ + bah_stop(sc); + + ifp->if_unit = sc->sc_dev.dv_unit; + ifp->if_name = bah_cd.cd_name; + ifp->if_output = arc_output; + ifp->if_start = bah_start; + ifp->if_ioctl = bah_ioctl; + ifp->if_timer = 0; + ifp->if_watchdog = bah_watchdog; + + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | + IFF_NOTRAILERS | IFF_NOARP; + + ifp->if_mtu = ARCMTU; + + if_attach(ifp); + arc_ifattach(ifp); + +#if NBPFILTER > 0 + bpfattach(&ifp->if_bpf, ifp, DLT_ARCNET, ARC_HDRLEN); +#endif + /* under heavy load we need four of them: */ + alloc_sicallback(); + alloc_sicallback(); + alloc_sicallback(); + alloc_sicallback(); + + sc->sc_isr.isr_intr = bahintr; + sc->sc_isr.isr_arg = sc; + sc->sc_isr.isr_ipl = 2; + add_isr(&sc->sc_isr); +} + +/* + * Initialize device + * + */ +void +bah_init(sc) + struct bah_softc *sc; +{ + struct ifnet *ifp; + int s; + + ifp = &sc->sc_arccom.ac_if; + + if ((ifp->if_flags & IFF_RUNNING) == 0) { + s = splnet(); + ifp->if_flags |= IFF_RUNNING; + bah_reset(sc); + bah_start(ifp); + splx(s); + } +} + +/* + * Reset the interface... + * + * this assumes that it is called inside a critical section... + * + */ +void +bah_reset(sc) + struct bah_softc *sc; +{ + struct ifnet *ifp; + int linkaddress; + + ifp = &sc->sc_arccom.ac_if; + +#ifdef BAH_DEBUG + printf("%s: reset\n", sc->sc_dev.dv_xname); +#endif + /* stop hardware in case it still runs */ + + sc->sc_base->kick1 = 0; + sc->sc_base->kick2 = 0; + DELAY(200); + + /* and restart it */ + sc->sc_base->kick1 = 0xFF; + sc->sc_base->kick2 = 0xFF; + + do { + DELAY(200); + } while (!(sc->sc_base->status & ARC_POR)); + + linkaddress = sc->sc_base->dipswitches; + +#if defined(BAH_DEBUG) && (BAH_DEBUG > 2) + printf("bah%ld: reset: card reset, link addr = 0x%02x (%ld)\n", + ifp->if_unit, linkaddress, linkaddress); +#endif + sc->sc_arccom.ac_anaddr = linkaddress; + + /* tell the routing level about the (possibly changed) link address */ + arc_ifattach(ifp); + + /* POR is NMI, but we need it below: */ + sc->sc_intmask = ARC_RECON|ARC_POR; + sc->sc_base->status = sc->sc_intmask; + sc->sc_base->command = ARC_CONF(CONF_LONG); + +#ifdef BAH_DEBUG + printf("%s: reset: chip configured, status=0x%02x\n", + sc->sc_dev.dv_xname, sc->sc_base->status); +#endif + + sc->sc_base->command = ARC_CLR(CLR_POR|CLR_RECONFIG); + +#ifdef BAH_DEBUG + printf("%s: reset: bits cleared, status=0x%02x\n", + sc->sc_dev.dv_xname, sc->sc_base->status); +#endif + + sc->sc_reconcount_excessive = ARC_EXCESSIVE_RECONS; + + /* start receiver */ + + sc->sc_intmask |= ARC_RI; + sc->sc_rx_fillcount = 0; + sc->sc_rx_act = 2; + + sc->sc_base->command = ARC_RXBC(2); + sc->sc_base->status = sc->sc_intmask; + +#ifdef BAH_DEBUG + printf("%s: reset: started receiver, status=0x%02x\n", + sc->sc_dev.dv_xname, sc->sc_base->status); +#endif + + /* and init transmitter status */ + sc->sc_tx_act = 0; + sc->sc_tx_fillcount = 0; + + ifp->if_flags |= IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; + +#ifdef BAHTIMINGS + bzero((caddr_t)&(sc->sc_stats), sizeof(sc->sc_stats)); + sc->sc_stats.mincopyin = + sc->sc_stats.mincopyout = + sc->sc_stats.minsend = ULONG_MAX; +#endif + + bah_start(ifp); +} + +/* + * Take interface offline + */ +void +bah_stop(sc) + struct bah_softc *sc; +{ + /* Stop the interrupts */ + sc->sc_base->status = 0; + + /* Stop the interface */ + sc->sc_base->kick1 = 0; + sc->sc_base->kick2 = 0; + + /* Stop watchdog timer */ + sc->sc_arccom.ac_if.if_timer = 0; + +#ifdef BAHTIMINGS + log(LOG_DEBUG,"%s: to board: %6lu .. %6lu ns/byte\n", + sc->sc_dev.dv_xname, + sc->sc_stats.mincopyout, sc->sc_stats.maxcopyout); + + log(LOG_DEBUG,"%s: from board: %6lu .. %6lu ns/byte\n", + sc->sc_dev.dv_xname, + sc->sc_stats.mincopyin, sc->sc_stats.maxcopyin); + + log(LOG_DEBUG,"%s: send time: %6lu .. %6lu mics/byte\n", + sc->sc_dev.dv_xname, + sc->sc_stats.minsend, sc->sc_stats.maxsend); + + sc->sc_stats.minsend = + sc->sc_stats.mincopyout = + sc->sc_stats.mincopyin = ULONG_MAX; + sc->sc_stats.maxsend = + sc->sc_stats.maxcopyout = + sc->sc_stats.maxcopyin = 0; +#endif +} + +__inline void +movepout(from, to, len) + u_char *from; + __volatile u_char *to; + int len; +{ +#ifdef BAHASMCOPY + u_short shortd; + u_long longd, longd1, longd2, longd3, longd4; + + if ((len > 3) && ((long)from) & 3) { + switch (((long)from) & 3) { + case 3: + *to = *from++; + to += 2; --len; + break; + case 1: + *to = *from++; + to += 2; --len; + case 2: + shortd = *((u_short *)from)++; + asm("movepw %0,%1@(0)" : : "d"(shortd), "a"(to)); + to += 4; len -= 2; + break; + default: + } + + while (len >= 32) { + longd1 = *((u_long *)from)++; + longd2 = *((u_long *)from)++; + longd3 = *((u_long *)from)++; + longd4 = *((u_long *)from)++; + asm("movepl %0,%1@(0)" : : "d"(longd1), "a"(to)); + asm("movepl %0,%1@(8)" : : "d"(longd2), "a"(to)); + asm("movepl %0,%1@(16)" : : "d"(longd3), "a"(to)); + asm("movepl %0,%1@(24)" : : "d"(longd4), "a"(to)); + + longd1 = *((u_long *)from)++; + longd2 = *((u_long *)from)++; + longd3 = *((u_long *)from)++; + longd4 = *((u_long *)from)++; + asm("movepl %0,%1@(32)" : : "d"(longd1), "a"(to)); + asm("movepl %0,%1@(40)" : : "d"(longd2), "a"(to)); + asm("movepl %0,%1@(48)" : : "d"(longd3), "a"(to)); + asm("movepl %0,%1@(56)" : : "d"(longd4), "a"(to)); + + to += 64; len -= 32; + } + while (len > 0) { + longd = *((u_long *)from)++; + asm("movepl %0,%1@(0)" : : "d"(longd), "a"(to)); + to += 8; len -= 4; + } + } +#endif + while (len > 0) { + *to = *from++; + to += 2; + --len; + } +} + +/* + * Start output on interface. Get another datagram to send + * off the interface queue, and copy it to the + * interface becore starting the output + * + * this assumes that it is called inside a critical section... + * XXX hm... does it still? + * + */ +void +bah_start(ifp) + struct ifnet *ifp; +{ + struct bah_softc *sc; + struct mbuf *m,*mp; + __volatile u_char *bah_ram_ptr; + int len, tlen, offset, s, buffer; +#ifdef BAHTIMINGS + u_long copystart, lencopy, perbyte; +#endif + + sc = bah_cd.cd_devs[ifp->if_unit]; + +#if defined(BAH_DEBUG) && (BAH_DEBUG > 3) + printf("%s: start(0x%x)\n", sc->sc_dev.dv_xname, ifp); +#endif + + if ((ifp->if_flags & IFF_RUNNING) == 0) + return; + + s = splnet(); + + if (sc->sc_tx_fillcount >= 2) { + splx(s); + return; + } + + IF_DEQUEUE(&ifp->if_snd, m); + buffer = sc->sc_tx_act ^ 1; + + splx(s); + + if (m == 0) + return; + +#if NBPFILTER > 0 + /* + * If bpf is listening on this interface, let it + * see the packet before we commit it to the wire + * + * (can't give the copy in A2060 card RAM to bpf, because + * that RAM is just accessed as on every other byte) + */ + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m); +#endif + +#ifdef BAH_DEBUG + m = m_pullup(m,3); /* gcc does structure padding */ + printf("%s: start: filling %ld from %ld to %ld type %ld\n", + sc->sc_dev.dv_xname, buffer, mtod(m, u_char *)[0], + mtod(m, u_char *)[1], mtod(m, u_char *)[2]); +#else + m = m_pullup(m, 2); +#endif + bah_ram_ptr = sc->sc_base->buffers + buffer*512*2; + + /* write the addresses to RAM and throw them away */ + + /* + * Hardware does this: Yet Another Microsecond Saved. + * (btw, timing code says usually 2 microseconds) + * bah_ram_ptr[0*2] = mtod(m, u_char *)[0]; + */ + bah_ram_ptr[1 * 2] = mtod(m, u_char *)[1]; + m_adj(m, 2); + + /* get total length left at this point */ + tlen = m->m_pkthdr.len; + if (tlen < ARC_MIN_FORBID_LEN) { + offset = 256 - tlen; + bah_ram_ptr[2 * 2] = offset; + } else { + bah_ram_ptr[2 * 2] = 0; + if (tlen <= ARC_MAX_FORBID_LEN) + offset = 255; /* !!! */ + else { + if (tlen > ARC_MAX_LEN) + tlen = ARC_MAX_LEN; + offset = 512 - tlen; + } + bah_ram_ptr[3 * 2] = offset; + + } + bah_ram_ptr += offset * 2; + + /* lets loop through the mbuf chain */ + + for (mp = m; mp; mp = mp->m_next) { + if ((len = mp->m_len)) { /* YAMS */ +#ifdef BAHTIMINGS + lencopy = len; + copystart = clkread(); +#endif + movepout(mtod(mp, caddr_t), bah_ram_ptr, len); + +#ifdef BAHTIMINGS + perbyte = 1000 * (clkread() - copystart) / lencopy; + sc->sc_stats.mincopyout = + ulmin(sc->sc_stats.mincopyout, perbyte); + sc->sc_stats.maxcopyout = + ulmax(sc->sc_stats.maxcopyout, perbyte); +#endif + bah_ram_ptr += len*2; + } + } + + sc->sc_broadcast[buffer] = (m->m_flags & M_BCAST) != 0; + sc->sc_retransmits[buffer] = (m->m_flags & M_BCAST) ? 1 : 5; + + /* actually transmit the packet */ + s = splnet(); + + if (++sc->sc_tx_fillcount > 1) { + /* + * We are filled up to the rim. No more bufs for the moment, + * please. + */ + ifp->if_flags |= IFF_OACTIVE; + } else { +#ifdef BAH_DEBUG + printf("%s: start: starting transmitter on buffer %d\n", + sc->sc_dev.dv_xname, buffer); +#endif + /* Transmitter was off, start it */ + sc->sc_tx_act = buffer; + + /* + * We still can accept another buf, so don't: + * ifp->if_flags |= IFF_OACTIVE; + */ + sc->sc_intmask |= ARC_TA; + sc->sc_base->command = ARC_TX(buffer); + sc->sc_base->status = sc->sc_intmask; + + sc->sc_arccom.ac_if.if_timer = ARCTIMEOUT; +#ifdef BAHTIMINGS + bcopy((caddr_t)&time, + (caddr_t)&(sc->sc_stats.lasttxstart_tv), + sizeof(struct timeval)); + + sc->sc_stats.lasttxstart_mics = clkread(); +#endif + } + splx(s); + m_freem(m); + + /* + * After 10 times reading the docs, I realized + * that in the case the receiver NAKs the buffer request, + * the hardware retries till shutdown. + * This is integrated now in the code above. + */ + + return; +} + +void +callstart(vsc, dummy) + void *vsc, *dummy; +{ + struct bah_softc *sc; + + sc = (struct bah_softc *)vsc; + bah_start(&sc->sc_arccom.ac_if); +} + +__inline void +movepin(from, to, len) + __volatile u_char *from; + u_char *to; + int len; +{ +#ifdef BAHASMCOPY + unsigned long longd, longd1, longd2, longd3, longd4; + ushort shortd; + + if ((len > 3) && (((long)to) & 3)) { + switch (((long)to) & 3) { + case 3: *to++ = *from; + from += 2; --len; + break; + case 1: *to++ = *from; + from += 2; --len; + case 2: asm ("movepw %1@(0),%0": "=d" (shortd) : "a" (from)); + *((ushort *)to)++ = shortd; + from += 4; len -= 2; + break; + default: + } + + while (len >= 32) { + asm("movepl %1@(0),%0" : "=d"(longd1) : "a" (from)); + asm("movepl %1@(8),%0" : "=d"(longd2) : "a" (from)); + asm("movepl %1@(16),%0" : "=d"(longd3) : "a" (from)); + asm("movepl %1@(24),%0" : "=d"(longd4) : "a" (from)); + *((unsigned long *)to)++ = longd1; + *((unsigned long *)to)++ = longd2; + *((unsigned long *)to)++ = longd3; + *((unsigned long *)to)++ = longd4; + + asm("movepl %1@(32),%0" : "=d"(longd1) : "a" (from)); + asm("movepl %1@(40),%0" : "=d"(longd2) : "a" (from)); + asm("movepl %1@(48),%0" : "=d"(longd3) : "a" (from)); + asm("movepl %1@(56),%0" : "=d"(longd4) : "a" (from)); + *((unsigned long *)to)++ = longd1; + *((unsigned long *)to)++ = longd2; + *((unsigned long *)to)++ = longd3; + *((unsigned long *)to)++ = longd4; + + from += 64; len -= 32; + } + while (len > 0) { + asm("movepl %1@(0),%0" : "=d"(longd) : "a" (from)); + *((unsigned long *)to)++ = longd; + from += 8; len -= 4; + } + + } +#endif /* BAHASMCOPY */ + while (len > 0) { + *to++ = *from; + from += 2; + --len; + } + +} + +/* + * Arcnet interface receiver soft interrupt: + * get the stuff out of any filled buffer we find. + */ +void +bah_srint(vsc, dummy) + void *vsc, *dummy; +{ + struct bah_softc *sc; + int buffer, len, len1, amount, offset, s, i, type; + u_char __volatile *bah_ram_ptr; + struct mbuf *m, *dst, *head; + struct arc_header *ah; + struct ifnet *ifp; +#ifdef BAHTIMINGS + u_long copystart, lencopy, perbyte; +#endif + sc = (struct bah_softc *)vsc; + ifp = &sc->sc_arccom.ac_if; + head = 0; + + s = splnet(); + buffer = sc->sc_rx_act ^ 1; + splx(s); + + /* Allocate header mbuf */ + MGETHDR(m, M_DONTWAIT, MT_DATA); + + if (m == 0) { + /* + * in case s.th. goes wrong with mem, drop it + * to make sure the receiver can be started again + * count it as input error (we dont have any other + * detectable) + */ + ifp->if_ierrors++; + goto cleanup; + } + + m->m_pkthdr.rcvif = ifp; + + /* + * Align so that IP packet will be longword aligned. Here we + * assume that m_data of new packet is longword aligned. + * When implementing PHDS, we might have to change it to 2, + * (2*sizeof(ulong) - ARC_HDRNEWLEN)), packet type dependent. + */ + + bah_ram_ptr = sc->sc_base->buffers + buffer*512*2; + offset = bah_ram_ptr[2*2]; + if (offset) + len = 256 - offset; + else { + offset = bah_ram_ptr[3*2]; + len = 512 - offset; + } + type = bah_ram_ptr[offset*2]; + m->m_data += 1 + arc_isphds(type); + + head = m; + ah = mtod(head, struct arc_header *); + + ah->arc_shost = bah_ram_ptr[0*2]; + ah->arc_dhost = bah_ram_ptr[1*2]; + + m->m_pkthdr.len = len+2; /* whole packet length */ + m->m_len = 2; /* mbuf filled with ARCnet addresses */ + bah_ram_ptr += offset*2; /* ram buffer continues there */ + + while (len > 0) { + + len1 = len; + amount = M_TRAILINGSPACE(m); + + if (amount == 0) { + dst = m; + MGET(m, M_DONTWAIT, MT_DATA); + + if (m == 0) { + ifp->if_ierrors++; + goto cleanup; + } + + if (len1 >= MINCLSIZE) + MCLGET(m, M_DONTWAIT); + + m->m_len = 0; + dst->m_next = m; + amount = M_TRAILINGSPACE(m); + } + + if (amount < len1) + len1 = amount; + +#ifdef BAHTIMINGS + lencopy = len; + copystart = clkread(); +#endif + + movepin(bah_ram_ptr, mtod(m, u_char *) + m->m_len, len1); + +#ifdef BAHTIMINGS + perbyte = 1000 * (clkread() - copystart) / lencopy; + sc->sc_stats.mincopyin = + ulmin(sc->sc_stats.mincopyin, perbyte); + sc->sc_stats.maxcopyin = + ulmax(sc->sc_stats.maxcopyin, perbyte); +#endif + + m->m_len += len1; + bah_ram_ptr += len1*2; + len -= len1; + } + +#if NBPFILTER > 0 + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, head); +#endif + + arc_input(&sc->sc_arccom.ac_if, head); + + /* arc_input has freed it, we dont need to... */ + + head = NULL; + ifp->if_ipackets++; + +cleanup: + + if (head != NULL) + m_freem(head); + + /* mark buffer as invalid by source id 0 */ + sc->sc_base->buffers[buffer*512*2] = 0; + s = splnet(); + + if (--sc->sc_rx_fillcount == 2 - 1) { + + /* was off, restart it on buffer just emptied */ + sc->sc_rx_act = buffer; + sc->sc_intmask |= ARC_RI; + + /* this also clears the RI flag interupt: */ + sc->sc_base->command = ARC_RXBC(buffer); + sc->sc_base->status = sc->sc_intmask; + +#ifdef BAH_DEBUG + printf("%s: srint: restarted rx on buf %ld\n", + sc->sc_dev.dv_xname, buffer); +#endif + } + splx(s); +} + +__inline static void +bah_tint(sc, isr) + struct bah_softc *sc; + int isr; +{ + struct ifnet *ifp; + + int buffer; +#ifdef BAHTIMINGS + int clknow; +#endif + + ifp = &(sc->sc_arccom.ac_if); + buffer = sc->sc_tx_act; + + /* + * retransmit code: + * Normal situtations first for fast path: + * If acknowledgement received ok or broadcast, we're ok. + * else if + */ + + if (isr & ARC_TMA || sc->sc_broadcast[buffer]) + sc->sc_arccom.ac_if.if_opackets++; +#ifdef BAHRETRANSMIT + else if (ifp->if_flags & IFF_LINK2 && ifp->if_timer > 0 + && --sc->sc_retransmits[buffer] > 0) { + /* retransmit same buffer */ + sc->sc_base->command = ARC_TX(buffer); + return; + } +#endif + else + ifp->if_oerrors++; + + +#ifdef BAHTIMINGS + clknow = clkread(); + + sc->sc_stats.minsend = ulmin(sc->sc_stats.minsend, + clknow - sc->sc_stats.lasttxstart_mics); + + sc->sc_stats.maxsend = ulmax(sc->sc_stats.maxsend, + clknow - sc->sc_stats.lasttxstart_mics); +#endif + + /* We know we can accept another buffer at this point. */ + ifp->if_flags &= ~IFF_OACTIVE; + + if (--sc->sc_tx_fillcount > 0) { + + /* + * start tx on other buffer. + * This also clears the int flag + */ + buffer ^= 1; + sc->sc_tx_act = buffer; + + /* + * already given: + * sc->sc_intmask |= ARC_TA; + * sc->sc_base->status = sc->sc_intmask; + */ + sc->sc_base->command = ARC_TX(buffer); + /* init watchdog timer */ + ifp->if_timer = ARCTIMEOUT; + +#ifdef BAHTIMINGS + bcopy((caddr_t)&time, + (caddr_t)&(sc->sc_stats.lasttxstart_tv), + sizeof(struct timeval)); + + sc->sc_stats.lasttxstart_mics = clkread(); +#endif + +#if defined(BAH_DEBUG) && (BAH_DEBUG > 1) + printf("%s: tint: starting tx on buffer %d, status 0x%02x\n", + sc->sc_dev.dv_xname, buffer, sc->sc_base->status); +#endif + } else { + /* have to disable TX interrupt */ + sc->sc_intmask &= ~ARC_TA; + sc->sc_base->status = sc->sc_intmask; + /* ... and watchdog timer */ + ifp->if_timer = 0; + +#ifdef BAH_DEBUG + printf("%s: tint: no more buffers to send, status 0x%02x\n", + sc->sc_dev.dv_xname, sc->sc_base->status); +#endif + } + +#ifdef BAHSOFTCOPY + /* schedule soft int to fill a new buffer for us */ + add_sicallback((sifunc_t)callstart, sc, NULL); +#else + /* call it directly */ + callstart(sc, NULL); +#endif +} + +/* + * Our interrupt routine + */ +int +bahintr(sc) + struct bah_softc *sc; +{ + u_char isr, maskedisr; + int buffer; + u_long newsec; + + isr = sc->sc_base->status; + maskedisr = isr & sc->sc_intmask; + if (!maskedisr) + return (0); + +#if defined(BAH_DEBUG) && (BAH_DEBUG>1) + printf("%s: intr: status 0x%02x, intmask 0x%02x\n", + sc->sc_dev.dv_xname, isr, sc->sc_intmask); +#endif + + if (maskedisr & ARC_POR) { + sc->sc_arccom.ac_anaddr = sc->sc_base->dipswitches; + sc->sc_base->command = ARC_CLR(CLR_POR); + log(LOG_WARNING, "%s: intr: got spurious power on reset int\n", + sc->sc_dev.dv_xname); + } + + if (maskedisr & ARC_RECON) { + /* + * we dont need to: + * sc->sc_base->command = ARC_CONF(CONF_LONG); + */ + sc->sc_base->command = ARC_CLR(CLR_RECONFIG); + sc->sc_arccom.ac_if.if_collisions++; + + /* + * If more than 2 seconds per reconfig: + * Reset time and counter. + * else: + * If more than ARC_EXCESSIVE_RECONFIGS reconfigs + * since last burst, complain and set treshold for + * warnings to ARC_EXCESSIVE_RECONS_REWARN. + * + * This allows for, e.g., new stations on the cable, or + * cable switching as long as it is over after (normally) + * 16 seconds. + * + * XXX TODO: check timeout bits in status word and double + * time if necessary. + */ + + newsec = time.tv_sec; + if (newsec - sc->sc_recontime > 2 * sc->sc_reconcount) { + sc->sc_recontime = newsec; + sc->sc_reconcount = 0; + sc->sc_reconcount_excessive = ARC_EXCESSIVE_RECONS; + } else if (++sc->sc_reconcount > sc->sc_reconcount_excessive) { + sc->sc_reconcount_excessive = + ARC_EXCESSIVE_RECONS_REWARN; + log(LOG_WARNING, + "%s: excessive token losses, cable problem?\n", + sc->sc_dev.dv_xname); + sc->sc_recontime = newsec; + sc->sc_reconcount = 0; + } + } + + if (maskedisr & ARC_RI) { + +#if defined(BAH_DEBUG) && (BAH_DEBUG > 1) + printf("%s: intr: hard rint, act %ld\n", + sc->sc_dev.dv_xname, sc->sc_rx_act); +#endif + + buffer = sc->sc_rx_act; + /* look if buffer is marked invalid: */ + if (sc->sc_base->buffers[buffer*512*2] == 0) { + /* invalid marked buffer (or illegally configured sender) */ + log(LOG_WARNING, + "%s: spurious RX interrupt or sender 0 (ignored)\n", + sc->sc_dev.dv_xname); + /* + * restart receiver on same buffer. + */ + sc->sc_base->command = ARC_RXBC(buffer); + + } else if (++sc->sc_rx_fillcount > 1) { + sc->sc_intmask &= ~ARC_RI; + sc->sc_base->status = sc->sc_intmask; + } else { + + buffer ^= 1; + sc->sc_rx_act = buffer; + + /* + * Start receiver on other receive buffer. + * This also clears the RI interupt flag. + */ + sc->sc_base->command = ARC_RXBC(buffer); + /* we are in the RX intr, so mask is ok for RX */ + +#ifdef BAH_DEBUG + printf("%s: started rx for buffer %ld, status 0x%02x\n", + sc->sc_dev.dv_xname, sc->sc_rx_act, + sc->sc_base->status); +#endif + } + +#ifdef BAHSOFTCOPY + /* this one starts a soft int to copy out of the hw */ + add_sicallback((sifunc_t)bah_srint, sc,NULL); +#else + /* this one does the copy here */ + bah_srint(sc,NULL); +#endif + } + + if (maskedisr & ARC_TA) + bah_tint(sc, isr); + + return (1); +} + +/* + * Process an ioctl request. + * This code needs some work - it looks pretty ugly. + */ +int +bah_ioctl(ifp, command, data) + register struct ifnet *ifp; + u_long command; + caddr_t data; +{ + struct bah_softc *sc; + register struct ifaddr *ifa; + int s, error; + + error = 0; + sc = bah_cd.cd_devs[ifp->if_unit]; + ifa = (struct ifaddr *)data; + s = splnet(); + +#if defined(BAH_DEBUG) && (BAH_DEBUG > 2) + printf("%s: ioctl() called, cmd = 0x%x\n", + sc->sc_dev.dv_xname, command); +#endif + + switch (command) { + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + switch (ifa->ifa_addr->sa_family) { +#ifdef INET + case AF_INET: + bah_init(sc); + break; +#endif + default: + bah_init(sc); + break; + } + + case SIOCSIFFLAGS: + if ((ifp->if_flags & IFF_UP) == 0 && + (ifp->if_flags & IFF_RUNNING) != 0) { + /* + * If interface is marked down and it is running, + * then stop it. + */ + bah_stop(sc); + ifp->if_flags &= ~IFF_RUNNING; + } else if ((ifp->if_flags & IFF_UP) != 0 && + (ifp->if_flags & IFF_RUNNING) == 0) { + /* + * If interface is marked up and it is stopped, then + * start it. + */ + bah_init(sc); + } + break; + + /* Multicast not supported */ + + default: + error = EINVAL; + } + + splx(s); + return (error); +} + +/* + * watchdog routine for transmitter. + * + * We need this, because else a receiver whose hardware is alive, but whose + * software has not enabled the Receiver, would make our hardware wait forever + * Discovered this after 20 times reading the docs. + * + * Only thing we do is disable transmitter. We'll get an transmit timeout, + * and the int handler will have to decide not to retransmit (in case + * retransmission is implemented). + * + * This one assumes being called inside splnet(), and that net >= ipl2 + */ + +void +bah_watchdog(unit) +int unit; +{ + struct bah_softc *sc; + struct ifnet *ifp; + + sc = bah_cd.cd_devs[unit]; + ifp = &(sc->sc_arccom.ac_if); + + sc->sc_base->command = ARC_TXDIS; + return; +} diff --git a/sys/dev/ic/smc90cx6reg.h b/sys/dev/ic/smc90cx6reg.h new file mode 100644 index 00000000000..f2ec2a06e5c --- /dev/null +++ b/sys/dev/ic/smc90cx6reg.h @@ -0,0 +1,99 @@ +/* $NetBSD: smc90cx6reg.h,v 1.4 1995/06/07 00:16:59 cgd Exp $ */ + +/* + * Copyright (c) 1994, 1995 Ignatios Souvatzis + * 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 Ignatios Souvatzis + * for the NetBSD project. + * 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. + */ + +/* + * The A2060/A560 card use the SMC COM90C26 Arcnet chipset. + * First or last 16k segment, resp., write a fifo which drives the reset line. + * 2nd 16k segment contains the registers. + * 3rd 16k segment contains the buffer RAM. + * All are only accessible at even addresses. + */ + +/* CBM Arcnet board */ +#define MANUFACTURER_1 514 +#define PRODUCT_1 9 + +/* Ameristar board */ +#define MANUFACTURER_2 1053 +#define PRODUCT_2 9 + +struct a2060 { + volatile u_int8_t kick1; + u_int8_t pad1[16383]; + volatile u_int8_t status; /* also intmask */ + u_int8_t pad2; + volatile u_int8_t command; + u_int8_t pad3[16381]; + volatile u_int8_t buffers[4096]; /* even bytes only */ + u_int8_t pad4[12228]; + volatile u_int8_t kick2; + u_int8_t pad5[16383]; +}; + +#define checkbyte buffers[0] +#define dipswitches buffers[2] + +/* calculate address for board b, buffer no n and offset o */ +#define BUFPTR(b,n,o) (&(b)->buffers[(n)*512+(o)*2]) + +#define ARC_TXDIS 0x01 +#define ARC_RXDIS 0x02 +#define ARC_TX(x) (0x03 | ((x)<<3)) +#define ARC_RX(x) (0x04 | ((x)<<3)) +#define ARC_RXBC(x) (0x84 | ((x)<<3)) + +#define ARC_CONF(x) (0x05 | (x)) +#define CLR_POR 0x08 +#define CLR_RECONFIG 0x10 + +#define ARC_CLR(x) (0x06 | (x)) +#define CONF_LONG 0x08 +#define CONF_SHORT 0x00 + +/* + * These are not in the COM90C65 docs. Derived from the arcnet.asm + * packet driver by Philippe Prindeville and Russel Nelson. + */ + +#define ARC_LDTST(x) (0x07 | (x)) +#define TEST_ON 0x08 +#define TEST_OFF 0x00 + +#define ARC_TA 1 /* int mask also */ +#define ARC_TMA 2 +#define ARC_RECON 4 /* int mask also */ +#define ARC_TEST 8 /* not in the COM90C65 docs (see above) */ +#define ARC_POR 0x10 /* non maskable interrupt */ +#define ARC_ET1 0x20 /* timeout value bits, normally 1 */ +#define ARC_ET2 0x40 /* timeout value bits, normally 1 */ +#define ARC_RI 0x80 /* int mask also */ diff --git a/sys/dev/ic/z8530sc.c b/sys/dev/ic/z8530sc.c index 7b7ef11d4aa..387f2b8aaf7 100644 --- a/sys/dev/ic/z8530sc.c +++ b/sys/dev/ic/z8530sc.c @@ -1,4 +1,5 @@ -/* $NetBSD: z8530sc.c,v 1.1 1996/01/24 01:07:23 gwr Exp $ */ +/* $OpenBSD: z8530sc.c,v 1.2 1996/04/21 22:21:35 deraadt Exp $ */ +/* $NetBSD: z8530sc.c,v 1.3 1996/04/10 21:44:35 gwr Exp $ */ /* * Copyright (c) 1994 Gordon W. Ross @@ -82,7 +83,7 @@ zs_break(cs, set) cs->cs_preg[5] &= ~ZSWR5_BREAK; cs->cs_creg[5] &= ~ZSWR5_BREAK; } - ZS_WRITE(cs, 5, cs->cs_creg[5]); + zs_write_reg(cs, 5, cs->cs_creg[5]); splx(s); } @@ -96,8 +97,8 @@ zs_getspeed(cs) { int tconst; - tconst = ZS_READ(cs, 12); - tconst |= ZS_READ(cs, 13) << 8; + tconst = zs_read_reg(cs, 12); + tconst |= zs_read_reg(cs, 13) << 8; return (TCONST_TO_BPS(cs->cs_pclk_div16, tconst)); } @@ -112,21 +113,20 @@ zs_iflush(cs) for (;;) { /* Is there input available? */ - rr0 = *(cs->cs_reg_csr); - ZS_DELAY(); + rr0 = zs_read_csr(cs); if ((rr0 & ZSRR0_RX_READY) == 0) break; - /* Read the data. */ - c = *(cs->cs_reg_data); - ZS_DELAY(); + /* + * First read the status, because reading the data + * destroys the status of this char. + */ + rr1 = zs_read_reg(cs, 1); + c = zs_read_data(cs); - /* Need to read status register too? */ - rr1 = ZS_READ(cs, 1); if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) { /* Clear the receive error. */ - *(cs->cs_reg_csr) = ZSWR0_RESET_ERRORS; - ZS_DELAY(); + zs_write_csr(cs, ZSWR0_RESET_ERRORS); } } } @@ -149,8 +149,7 @@ zs_loadchannelregs(cs) bcopy((caddr_t)cs->cs_preg, (caddr_t)cs->cs_creg, 16); reg = cs->cs_creg; /* current regs */ - *(cs->cs_reg_csr) = ZSM_RESET_ERR; /* XXX: reset error condition */ - ZS_DELAY(); + zs_write_csr(cs, ZSM_RESET_ERR); /* XXX: reset error condition */ #if 1 /* @@ -161,17 +160,17 @@ zs_loadchannelregs(cs) #endif /* baud clock divisor, stop bits, parity */ - ZS_WRITE(cs, 4, reg[4]); + zs_write_reg(cs, 4, reg[4]); /* misc. TX/RX control bits */ - ZS_WRITE(cs, 10, reg[10]); + zs_write_reg(cs, 10, reg[10]); /* char size, enable (RX/TX) */ - ZS_WRITE(cs, 3, reg[3] & ~ZSWR3_RX_ENABLE); - ZS_WRITE(cs, 5, reg[5] & ~ZSWR5_TX_ENABLE); + zs_write_reg(cs, 3, reg[3] & ~ZSWR3_RX_ENABLE); + zs_write_reg(cs, 5, reg[5] & ~ZSWR5_TX_ENABLE); /* interrupt enables: TX, TX, STATUS */ - ZS_WRITE(cs, 1, reg[1]); + zs_write_reg(cs, 1, reg[1]); #if 0 /* @@ -182,27 +181,27 @@ zs_loadchannelregs(cs) * and they should not be touched thereafter. */ /* interrupt vector */ - ZS_WRITE(cs, 2, reg[2]); + zs_write_reg(cs, 2, reg[2]); /* master interrupt control */ - ZS_WRITE(cs, 9, reg[9]); + zs_write_reg(cs, 9, reg[9]); #endif /* clock mode control */ - ZS_WRITE(cs, 11, reg[11]); + zs_write_reg(cs, 11, reg[11]); /* baud rate (lo/hi) */ - ZS_WRITE(cs, 12, reg[12]); - ZS_WRITE(cs, 13, reg[13]); + zs_write_reg(cs, 12, reg[12]); + zs_write_reg(cs, 13, reg[13]); /* Misc. control bits */ - ZS_WRITE(cs, 14, reg[14]); + zs_write_reg(cs, 14, reg[14]); /* which lines cause status interrupts */ - ZS_WRITE(cs, 15, reg[15]); + zs_write_reg(cs, 15, reg[15]); /* char size, enable (RX/TX)*/ - ZS_WRITE(cs, 3, reg[3]); - ZS_WRITE(cs, 5, reg[5]); + zs_write_reg(cs, 3, reg[3]); + zs_write_reg(cs, 5, reg[5]); } @@ -224,16 +223,15 @@ zsc_intr_hard(arg) register struct zsc_softc *zsc = arg; register struct zs_chanstate *cs_a; register struct zs_chanstate *cs_b; - register int rval, soft; + register int rval; register u_char rr3; cs_a = &zsc->zsc_cs[0]; cs_b = &zsc->zsc_cs[1]; rval = 0; - soft = 0; /* Note: only channel A has an RR3 */ - rr3 = ZS_READ(cs_a, 3); + rr3 = zs_read_reg(cs_a, 3); /* Handle receive interrupts first. */ if (rr3 & ZSRR3_IP_A_RX) @@ -241,33 +239,30 @@ zsc_intr_hard(arg) if (rr3 & ZSRR3_IP_B_RX) (*cs_b->cs_ops->zsop_rxint)(cs_b); + /* Handle status interrupts (i.e. flow control). */ + if (rr3 & ZSRR3_IP_A_STAT) + (*cs_a->cs_ops->zsop_stint)(cs_a); + if (rr3 & ZSRR3_IP_B_STAT) + (*cs_b->cs_ops->zsop_stint)(cs_b); + /* Handle transmit done interrupts. */ if (rr3 & ZSRR3_IP_A_TX) (*cs_a->cs_ops->zsop_txint)(cs_a); if (rr3 & ZSRR3_IP_B_TX) (*cs_b->cs_ops->zsop_txint)(cs_b); - /* Handle status interrupts. */ - if (rr3 & ZSRR3_IP_A_STAT) - (*cs_a->cs_ops->zsop_stint)(cs_a); - if (rr3 & ZSRR3_IP_B_STAT) - (*cs_b->cs_ops->zsop_stint)(cs_b); - /* Clear interrupt. */ if (rr3 & (ZSRR3_IP_A_RX | ZSRR3_IP_A_TX | ZSRR3_IP_A_STAT)) { - *(cs_a->cs_reg_csr) = ZSWR0_CLR_INTR; - ZS_DELAY(); + zs_write_csr(cs_a, ZSWR0_CLR_INTR); rval |= 1; } if (rr3 & (ZSRR3_IP_B_RX | ZSRR3_IP_B_TX | ZSRR3_IP_B_STAT)) { - *(cs_b->cs_reg_csr) = ZSWR0_CLR_INTR; - ZS_DELAY(); + zs_write_csr(cs_b, ZSWR0_CLR_INTR); rval |= 2; } - if ((cs_a->cs_softreq) || (cs_b->cs_softreq)) - { - /* This is a machine-dependent function. */ + if ((cs_a->cs_softreq) || (cs_b->cs_softreq)) { + /* This is a machine-dependent function (or macro). */ zsc_req_softint(zsc); } @@ -284,18 +279,19 @@ zsc_intr_soft(arg) { register struct zsc_softc *zsc = arg; register struct zs_chanstate *cs; - register int req, rval, s, unit; + register int rval, unit; rval = 0; for (unit = 0; unit < 2; unit++) { cs = &zsc->zsc_cs[unit]; - s = splzs(); - req = cs->cs_softreq; - cs->cs_softreq = 0; - splx(s); - - if (req) { + /* + * The softint flag can be safely cleared once + * we have decided to call the softint routine. + * (No need to do splzs() first.) + */ + if (cs->cs_softreq) { + cs->cs_softreq = 0; (*cs->cs_ops->zsop_softint)(cs); rval = 1; } @@ -304,15 +300,15 @@ zsc_intr_soft(arg) } -static int +static void zsnull_intr(cs) struct zs_chanstate *cs; { - ZS_WRITE(cs, 1, 0); - ZS_WRITE(cs, 15, 0); + zs_write_reg(cs, 1, 0); + zs_write_reg(cs, 15, 0); } -static int +static void zsnull_softint(cs) struct zs_chanstate *cs; { diff --git a/sys/dev/ic/z8530sc.h b/sys/dev/ic/z8530sc.h index 57ec9c4dc91..f271fe46bde 100644 --- a/sys/dev/ic/z8530sc.h +++ b/sys/dev/ic/z8530sc.h @@ -1,4 +1,4 @@ -/* $NetBSD: z8530sc.h,v 1.1 1996/01/24 01:07:24 gwr Exp $ */ +/* $NetBSD: z8530sc.h,v 1.2 1996/04/10 21:44:44 gwr Exp $ */ /* * Copyright (c) 1994 Gordon W. Ross @@ -50,10 +50,10 @@ * Function vector - per channel */ struct zsops { - int (*zsop_rxint)(); /* receive char available */ - int (*zsop_stint)(); /* external/status */ - int (*zsop_txint)(); /* xmit buffer empty */ - int (*zsop_softint)(); /* process software interrupt */ + void (*zsop_rxint)(); /* receive char available */ + void (*zsop_stint)(); /* external/status */ + void (*zsop_txint)(); /* xmit buffer empty */ + void (*zsop_softint)(); /* process software interrupt */ }; extern struct zsops zsops_null; @@ -93,9 +93,9 @@ struct zs_chanstate { u_char cs_heldchange; /* change pending (creg != preg) */ u_char cs_rr0; /* last rr0 processed */ + u_char cs_rr0_new; /* rr0 saved in status interrupt. */ char cs_softreq; /* need soft interrupt call */ - char cs__spare; }; struct zsc_softc { diff --git a/sys/dev/ic/z8530tty.c b/sys/dev/ic/z8530tty.c index 577a2845d51..db07810fdf9 100644 --- a/sys/dev/ic/z8530tty.c +++ b/sys/dev/ic/z8530tty.c @@ -1,5 +1,5 @@ -/* $OpenBSD: z8530tty.c,v 1.2 1996/04/18 23:47:26 niklas Exp $ */ -/* $NetBSD: z8530tty.c,v 1.1 1996/01/24 01:07:25 gwr Exp $ */ +/* $OpenBSD: z8530tty.c,v 1.3 1996/04/21 22:21:46 deraadt Exp $ */ +/* $NetBSD: z8530tty.c,v 1.6 1996/04/10 21:44:47 gwr Exp $ */ /* * Copyright (c) 1994 Gordon W. Ross @@ -60,6 +60,7 @@ #include <sys/conf.h> #include <sys/file.h> #include <sys/ioctl.h> +#include <sys/malloc.h> #include <sys/tty.h> #include <sys/time.h> #include <sys/kernel.h> @@ -86,9 +87,14 @@ extern int zs_check_kgdb(); * Note: must be a power of two! */ #ifndef ZSTTY_RING_SIZE -#define ZSTTY_RING_SIZE 1024 +#define ZSTTY_RING_SIZE 2048 #endif -#define ZSTTY_RING_MASK (ZSTTY_RING_SIZE-1) + +/* + * Make this an option variable one can patch. + * But be warned: this must be a power of 2! + */ +int zstty_rbuf_size = ZSTTY_RING_SIZE; struct zstty_softc { struct device zst_dev; /* required first: base device */ @@ -126,7 +132,8 @@ struct zstty_softc { */ u_int zst_rbget; /* ring buffer `get' index */ volatile u_int zst_rbput; /* ring buffer `put' index */ - u_short zst_rbuf[ZSTTY_RING_SIZE]; /* rr1, data pairs */ + u_int zst_ringmask; + u_short *zst_rbuf; /* rr1, data pairs */ }; @@ -134,9 +141,12 @@ struct zstty_softc { static int zstty_match(struct device *, void *, void *); static void zstty_attach(struct device *, struct device *, void *); -struct cfdriver zsttycd = { - NULL, "zstty", zstty_match, zstty_attach, - DV_TTY, sizeof(struct zstty_softc), NULL, +struct cfattach zstty_ca = { + sizeof(struct zstty_softc), zstty_match, zstty_attach +}; + +struct cfdriver zstty_cd = { + NULL, "zstty", DV_TTY }; struct zsops zsops_tty; @@ -221,11 +231,16 @@ zstty_attach(parent, self, aux) } printf("\n"); - tp = zst->zst_tty = ttymalloc(); + tp = ttymalloc(); tp->t_dev = dev; tp->t_oproc = zsstart; tp->t_param = zsparam; + zst->zst_tty = tp; + zst->zst_ringmask = zstty_rbuf_size - 1; + zst->zst_rbuf = malloc(zstty_rbuf_size * sizeof(zst->zst_rbuf[0]), + M_DEVBUF, M_WAITOK); + /* * Hardware init */ @@ -244,7 +259,7 @@ zstty_attach(parent, self, aux) reset = (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET; s = splzs(); - ZS_WRITE(cs, 9, reset); + zs_write_reg(cs, 9, reset); splx(s); } @@ -269,10 +284,10 @@ zstty(dev) int unit = minor(dev); #ifdef DIAGNOSTIC - if (unit >= zsttycd.cd_ndevs) + if (unit >= zstty_cd.cd_ndevs) panic("zstty"); #endif - zst = zsttycd.cd_devs[unit]; + zst = zstty_cd.cd_devs[unit]; return (zst->zst_tty); } @@ -293,9 +308,9 @@ zsopen(dev, flags, mode, p) int error, s, unit; unit = minor(dev); - if (unit >= zsttycd.cd_ndevs) + if (unit >= zstty_cd.cd_ndevs) return (ENXIO); - zst = zsttycd.cd_devs[unit]; + zst = zstty_cd.cd_devs[unit]; if (zst == NULL) return (ENXIO); tp = zst->zst_tty; @@ -344,12 +359,10 @@ zsopen(dev, flags, mode, p) /* Wait for carrier. */ for (;;) { - register int rr0; /* Might never get status intr if carrier already on. */ - rr0 = *(cs->cs_reg_csr); - ZS_DELAY(); - if (rr0 & ZSRR0_DCD) { + cs->cs_rr0 = zs_read_csr(cs); + if (cs->cs_rr0 & ZSRR0_DCD) { tp->t_state |= TS_CARR_ON; break; } @@ -399,7 +412,7 @@ zsclose(dev, flags, mode, p) struct zsinfo *zi; int hup, s; - zst = zsttycd.cd_devs[minor(dev)]; + zst = zstty_cd.cd_devs[minor(dev)]; cs = zst->zst_cs; tp = zst->zst_tty; @@ -437,7 +450,7 @@ zsread(dev, uio, flags) register struct zstty_softc *zst; register struct tty *tp; - zst = zsttycd.cd_devs[minor(dev)]; + zst = zstty_cd.cd_devs[minor(dev)]; tp = zst->zst_tty; return (linesw[tp->t_line].l_read(tp, uio, flags)); } @@ -451,7 +464,7 @@ zswrite(dev, uio, flags) register struct zstty_softc *zst; register struct tty *tp; - zst = zsttycd.cd_devs[minor(dev)]; + zst = zstty_cd.cd_devs[minor(dev)]; tp = zst->zst_tty; return (linesw[tp->t_line].l_write(tp, uio, flags)); } @@ -472,7 +485,7 @@ zsioctl(dev, cmd, data, flag, p) register struct tty *tp; register int error, tmp; - zst = zsttycd.cd_devs[minor(dev)]; + zst = zstty_cd.cd_devs[minor(dev)]; cs = zst->zst_cs; tp = zst->zst_tty; @@ -541,7 +554,7 @@ zsstart(tp) register struct zs_chanstate *cs; register int s, nch; - zst = zsttycd.cd_devs[minor(tp->t_dev)]; + zst = zstty_cd.cd_devs[minor(tp->t_dev)]; cs = zst->zst_cs; s = spltty(); @@ -574,9 +587,8 @@ zsstart(tp) cs->cs_preg[1] |= ZSWR1_TIE; cs->cs_creg[1] |= ZSWR1_TIE; - ZS_WRITE(cs, 1, cs->cs_creg[1]); - *(cs->cs_reg_data) = *p; - ZS_DELAY(); + zs_write_reg(cs, 1, cs->cs_creg[1]); + zs_write_data(cs, *p); zst->zst_tba = p + 1; zst->zst_tbc = nch - 1; } else { @@ -587,7 +599,7 @@ zsstart(tp) (void) splzs(); cs->cs_preg[1] &= ~ZSWR1_TIE; cs->cs_creg[1] &= ~ZSWR1_TIE; - ZS_WRITE(cs, 1, cs->cs_creg[1]); + zs_write_reg(cs, 1, cs->cs_creg[1]); } out: splx(s); @@ -605,7 +617,7 @@ zsstop(tp, flag) register struct zs_chanstate *cs; register int s; - zst = zsttycd.cd_devs[minor(tp->t_dev)]; + zst = zstty_cd.cd_devs[minor(tp->t_dev)]; cs = zst->zst_cs; s = splzs(); @@ -637,7 +649,7 @@ zsparam(tp, t) register int s, bps, cflag, tconst; u_char tmp3, tmp4, tmp5, reset; - zst = zsttycd.cd_devs[minor(tp->t_dev)]; + zst = zstty_cd.cd_devs[minor(tp->t_dev)]; cs = zst->zst_cs; /* @@ -709,9 +721,8 @@ zsparam(tp, t) */ tmp3 |= ZSWR3_RX_ENABLE; if (cflag & CCTS_OFLOW) { - if (*(cs->cs_reg_csr) & ZSRR0_DCD) + if (zs_read_csr(cs) & ZSRR0_DCD) tmp3 |= ZSWR3_HFC; - ZS_DELAY(); } cs->cs_preg[3] = tmp3; @@ -773,7 +784,7 @@ zs_modem(zst, onoff) cs->cs_heldchange = 1; } else { cs->cs_creg[5] = (cs->cs_creg[5] | bis) & and; - ZS_WRITE(cs, 5, cs->cs_creg[5]); + zs_write_reg(cs, 5, cs->cs_creg[5]); } } splx(s); @@ -788,33 +799,37 @@ zs_modem(zst, onoff) * XXX: need to do input flow-control to avoid ring overrun. */ -static int +/* + * receiver ready interrupt. (splzs) + */ +static void zstty_rxint(cs) register struct zs_chanstate *cs; { register struct zstty_softc *zst; - register put, put_next; + register put, put_next, ringmask; register u_char c, rr0, rr1; zst = cs->cs_private; put = zst->zst_rbput; + ringmask = zst->zst_ringmask; nextchar: - /* Read the input data ASAP. */ - c = *(cs->cs_reg_data); - ZS_DELAY(); - /* Save the status register too. */ - rr1 = ZS_READ(cs, 1); + /* + * First read the status, because reading the received char + * destroys the status of this char. + */ + rr1 = zs_read_reg(cs, 1); + c = zs_read_data(cs); if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) { /* Clear the receive error. */ - *(cs->cs_reg_csr) = ZSWR0_RESET_ERRORS; - ZS_DELAY(); + zs_write_csr(cs, ZSWR0_RESET_ERRORS); } zst->zst_rbuf[put] = (c << 8) | rr1; - put_next = (put + 1) & ZSTTY_RING_MASK; + put_next = (put + 1) & ringmask; /* Would overrun if increment makes (put==get). */ if (put_next == zst->zst_rbget) { @@ -825,8 +840,7 @@ nextchar: } /* Keep reading until the FIFO is empty. */ - rr0 = *(cs->cs_reg_csr); - ZS_DELAY(); + rr0 = zs_read_csr(cs); if (rr0 & ZSRR0_RX_READY) goto nextchar; @@ -835,63 +849,93 @@ nextchar: /* Ask for softint() call. */ cs->cs_softreq = 1; - return(1); } -static int +/* + * transmitter ready interrupt. (splzs) + */ +static void zstty_txint(cs) register struct zs_chanstate *cs; { register struct zstty_softc *zst; - register int count, rval; + register int count; zst = cs->cs_private; count = zst->zst_tbc; + /* + * If our transmit buffer still has data, + * just send the next character. + */ if (count > 0) { /* Send the next char. */ - *(cs->cs_reg_data) = *zst->zst_tba++; - ZS_DELAY(); zst->zst_tbc = --count; - rval = 0; - } else { - /* Nothing more to send. */ - *(cs->cs_reg_csr) = ZSWR0_RESET_TXINT; - ZS_DELAY(); - zst->zst_intr_flags |= INTR_TX_EMPTY; - rval = 1; /* want softcall */ + zs_write_data(cs, *zst->zst_tba); + zst->zst_tba++; + return; } - cs->cs_softreq = rval; - return (rval); + zs_write_csr(cs, ZSWR0_RESET_TXINT); + + /* Ask the softint routine for more output. */ + zst->zst_intr_flags |= INTR_TX_EMPTY; + cs->cs_softreq = 1; } -static int +/* + * status change interrupt. (splzs) + */ +static void zstty_stint(cs) register struct zs_chanstate *cs; { register struct zstty_softc *zst; - register int rr0; + register struct tty *tp; + register u_char rr0; zst = cs->cs_private; + tp = zst->zst_tty; - rr0 = *(cs->cs_reg_csr); - ZS_DELAY(); + rr0 = zs_read_csr(cs); + zs_write_csr(cs, ZSWR0_RESET_STATUS); - *(cs->cs_reg_csr) = ZSWR0_RESET_STATUS; - ZS_DELAY(); + /* + * The chip's hardware flow control is, as noted in zsreg.h, + * busted---if the DCD line goes low the chip shuts off the + * receiver (!). If we want hardware CTS flow control but do + * not have it, and carrier is now on, turn HFC on; if we have + * HFC now but carrier has gone low, turn it off. + */ + if (rr0 & ZSRR0_DCD) { + if (tp->t_cflag & CCTS_OFLOW && + (cs->cs_creg[3] & ZSWR3_HFC) == 0) { + cs->cs_creg[3] |= ZSWR3_HFC; + zs_write_reg(cs, 3, cs->cs_creg[3]); + } + } else { + if (cs->cs_creg[3] & ZSWR3_HFC) { + cs->cs_creg[3] &= ~ZSWR3_HFC; + zs_write_reg(cs, 3, cs->cs_creg[3]); + } + } - if ((rr0 & ZSRR0_BREAK) && + /* + * Check here for console break, so that we can abort + * even when interrupts are locking up the machine. + */ + if ((rr0 & ZSRR0_BREAK) && (zst->zst_hwflags & ZS_HWFLAG_CONSOLE)) { zs_abort(); - return (0); + return; } + cs->cs_rr0_new = rr0; zst->zst_intr_flags |= INTR_ST_CHECK; + /* Ask for softint() call. */ cs->cs_softreq = 1; - return (1); } /* @@ -911,7 +955,10 @@ zsoverrun(zst, ptime, what) } } -static int +/* + * Software interrupt. Called at zssoft + */ +static void zstty_softint(cs) struct zs_chanstate *cs; { @@ -919,24 +966,29 @@ zstty_softint(cs) register struct linesw *line; register struct tty *tp; register int get, c, s; - int intr_flags; + int intr_flags, ringmask; register u_short ring_data; register u_char rr0, rr1; zst = cs->cs_private; tp = zst->zst_tty; line = &linesw[tp->t_line]; + ringmask = zst->zst_ringmask; /* Atomically get and clear flags. */ s = splzs(); intr_flags = zst->zst_intr_flags; zst->zst_intr_flags = 0; - splx(s); + + /* + * Lower to tty priority while servicing the ring. + */ + (void) spltty(); if (intr_flags & INTR_RX_OVERRUN) { /* May turn this on again below. */ intr_flags &= ~INTR_RX_OVERRUN; - zsoverrun(zst, "ring"); + zsoverrun(zst, &zst->zst_rotime, "ring"); } /* @@ -945,7 +997,7 @@ zstty_softint(cs) get = zst->zst_rbget; while (get != zst->zst_rbput) { ring_data = zst->zst_rbuf[get]; - get = (get + 1) & ZSTTY_RING_MASK; + get = (get + 1) & ringmask; if (ring_data & ZSRR1_DO) intr_flags |= INTR_RX_OVERRUN; @@ -960,32 +1012,36 @@ zstty_softint(cs) } zst->zst_rbget = get; - /* If set, it is from the loop above. */ + /* + * If the overrun flag is set now, it was set while + * copying char/status pairs from the ring, which + * means this was a hardware (fifo) overrun. + */ if (intr_flags & INTR_RX_OVERRUN) { - zsoverrun(zst, "fifo"); + zsoverrun(zst, &zst->zst_fotime, "fifo"); } if (intr_flags & INTR_TX_EMPTY) { /* - * Transmit done. Change registers and resume, - * or just clear BUSY. + * The transmitter output buffer count is zero. + * If we suspended output for a "held" change, + * then handle that now and resume. Otherwise, + * try to start a new output chunk. */ if (cs->cs_heldchange) { - s = splzs(); - rr0 = *(cs->cs_reg_csr); - ZS_DELAY(); + (void) splzs(); + rr0 = zs_read_csr(cs); if ((rr0 & ZSRR0_DCD) == 0) cs->cs_preg[3] &= ~ZSWR3_HFC; zs_loadchannelregs(cs); - splx(s); + (void) spltty(); cs->cs_heldchange = 0; - if (zst->zst_heldtbc && (tp->t_state & TS_TTSTOP) == 0) { zst->zst_tbc = zst->zst_heldtbc - 1; - *(cs->cs_reg_data) = *zst->zst_tba++; - ZS_DELAY(); + zs_write_data(cs, *zst->zst_tba); + zst->zst_tba++; goto tx_resumed; } } @@ -1001,31 +1057,11 @@ zstty_softint(cs) if (intr_flags & INTR_ST_CHECK) { /* - * Status line change. - * - * The chip's hardware flow control is, as noted in zsreg.h, - * busted---if the DCD line goes low the chip shuts off the - * receiver (!). If we want hardware CTS flow control but do - * not have it, and carrier is now on, turn HFC on; if we have - * HFC now but carrier has gone low, turn it off. + * Status line change. HFC bit is run in + * hardware interrupt, to avoid locking + * at splzs here. */ - s = splzs(); - rr0 = *(cs->cs_reg_csr); - if (rr0 & ZSRR0_DCD) { - if (tp->t_cflag & CCTS_OFLOW && - (cs->cs_creg[3] & ZSWR3_HFC) == 0) { - cs->cs_creg[3] |= ZSWR3_HFC; - ZS_WRITE(cs, 3, cs->cs_creg[3]); - } - } else { - if (cs->cs_creg[3] & ZSWR3_HFC) { - cs->cs_creg[3] &= ~ZSWR3_HFC; - ZS_WRITE(cs, 3, cs->cs_creg[3]); - } - } - splx(s); - - /* Was there a change on DCD? */ + rr0 = cs->cs_rr0_new; if ((rr0 ^ cs->cs_rr0) & ZSRR0_DCD) { c = ((rr0 & ZSRR0_DCD) != 0); if (line->l_modem(tp, c) == 0) @@ -1034,7 +1070,7 @@ zstty_softint(cs) cs->cs_rr0 = rr0; } - return (1); + splx(s); } struct zsops zsops_tty = { @@ -1043,3 +1079,4 @@ struct zsops zsops_tty = { zstty_txint, /* xmit buffer empty */ zstty_softint, /* process software interrupt */ }; + |