diff options
author | nyan <nyan@FreeBSD.org> | 2000-10-02 14:27:20 +0000 |
---|---|---|
committer | nyan <nyan@FreeBSD.org> | 2000-10-02 14:27:20 +0000 |
commit | bd4026ebae55d49b9834d42c7bae7f1a6f7b4d26 (patch) | |
tree | 7b40f1f273ca32e8c8eaf31dc2de4a944e5022f8 /sys/dev/snc | |
parent | ca9093b327311b17a6c77820abb0c66abf6a94f4 (diff) | |
download | FreeBSD-src-bd4026ebae55d49b9834d42c7bae7f1a6f7b4d26.zip FreeBSD-src-bd4026ebae55d49b9834d42c7bae7f1a6f7b4d26.tar.gz |
Added NEC PC-9801-83, 84, PC-9801-103, 104, PC-9801N-25 and PC-9801N-J02R
support which use National Semiconductor DP8393X (SONIC) as ethernet
controller. Currently, this driver is used on only PC-98.
Submitted by: Motomichi Matsuzaki <mzaki@e-mail.ne.jp>
Obtained from: NetBSD/pc98
Diffstat (limited to 'sys/dev/snc')
-rw-r--r-- | sys/dev/snc/dp83932.c | 1231 | ||||
-rw-r--r-- | sys/dev/snc/dp83932reg.h | 271 | ||||
-rw-r--r-- | sys/dev/snc/dp83932subr.c | 902 | ||||
-rw-r--r-- | sys/dev/snc/dp83932subr.h | 78 | ||||
-rw-r--r-- | sys/dev/snc/dp83932var.h | 307 | ||||
-rw-r--r-- | sys/dev/snc/if_snc.c | 258 | ||||
-rw-r--r-- | sys/dev/snc/if_snc_cbus.c | 224 | ||||
-rw-r--r-- | sys/dev/snc/if_snc_pccard.c | 160 | ||||
-rw-r--r-- | sys/dev/snc/if_sncreg.h | 140 | ||||
-rw-r--r-- | sys/dev/snc/if_sncvar.h | 47 |
10 files changed, 3618 insertions, 0 deletions
diff --git a/sys/dev/snc/dp83932.c b/sys/dev/snc/dp83932.c new file mode 100644 index 0000000..a27a332 --- /dev/null +++ b/sys/dev/snc/dp83932.c @@ -0,0 +1,1231 @@ +/* $FreeBSD$ */ +/* $NecBSD: dp83932.c,v 1.5 1999/07/29 05:08:44 kmatsuda Exp $ */ +/* $NetBSD: if_snc.c,v 1.18 1998/04/25 21:27:40 scottr Exp $ */ + +/* + * Copyright (c) 1997, 1998, 1999 + * Kouichi Matsuda. 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 Kouichi Matsuda for + * NetBSD/pc98. + * 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. + */ + +/* + * Modified for FreeBSD(98) 4.0 from NetBSD/pc98 1.4.2 by Motomichi Matsuzaki. + */ + +/* + * Modified for NetBSD/pc98 1.2G from NetBSD/mac68k 1.2G by Kouichi Matsuda. + * Make adapted for NEC PC-9801-83, 84, PC-9801-103, 104, PC-9801N-25 and + * PC-9801N-J02, J02R, which uses National Semiconductor DP83934AVQB as + * Ethernet Controller and National Semiconductor NS46C46 as + * (64 * 16 bits) Microwire Serial EEPROM. + */ + +/* + * National Semiconductor DP8393X SONIC Driver + * Copyright (c) 1991 Algorithmics Ltd (http://www.algor.co.uk) + * You may use, copy, and modify this program so long as you retain the + * copyright line. + * + * This driver has been substantially modified since Algorithmics donated + * it. + * + * Denton Gentry <denny1@home.com> + * and also + * Yanagisawa Takeshi <yanagisw@aa.ap.titech.ac.jp> + * did the work to get this running on the Macintosh. + */ + +#include "opt_inet.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sockio.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/syslog.h> +#include <sys/errno.h> +#if NRND > 0 +#include <sys/rnd.h> +#endif + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_dl.h> +#include <net/if_types.h> +#include <net/if_media.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#endif + +#include <net/bpf.h> +#include <net/bpfdesc.h> + +#include <sys/bus.h> +#include <machine/bus.h> +#include <dev/snc/dp83932reg.h> +#include <dev/snc/dp83932var.h> + +hide void sncwatchdog __P((struct ifnet *)); +hide void sncinit __P((void *)); +hide int sncstop __P((struct snc_softc *sc)); +hide int sncioctl __P((struct ifnet *ifp, u_long cmd, caddr_t data)); +hide void sncstart __P((struct ifnet *ifp)); +hide void sncreset __P((struct snc_softc *sc)); + +hide void caminitialise __P((struct snc_softc *)); +hide void camentry __P((struct snc_softc *, int, u_char *ea)); +hide void camprogram __P((struct snc_softc *)); +hide void initialise_tda __P((struct snc_softc *)); +hide void initialise_rda __P((struct snc_softc *)); +hide void initialise_rra __P((struct snc_softc *)); +#ifdef SNCDEBUG +hide void camdump __P((struct snc_softc *sc)); +#endif + +hide void sonictxint __P((struct snc_softc *)); +hide void sonicrxint __P((struct snc_softc *)); + +hide u_int sonicput __P((struct snc_softc *sc, struct mbuf *m0, + int mtd_next)); +hide int sonic_read __P((struct snc_softc *, u_int32_t, int)); +hide struct mbuf *sonic_get __P((struct snc_softc *, + u_int32_t, int)); + +int snc_enable __P((struct snc_softc *)); +void snc_disable __P((struct snc_softc *)); + +int snc_mediachange __P((struct ifnet *)); +void snc_mediastatus __P((struct ifnet *, struct ifmediareq *)); + +#ifdef NetBSD +#if NetBSD <= 199714 +struct cfdriver snc_cd = { + NULL, "snc", DV_IFNET +}; +#endif +#endif + +#undef assert +#undef _assert + +#ifdef NDEBUG +#define assert(e) ((void)0) +#define _assert(e) ((void)0) +#else +#define _assert(e) assert(e) +#ifdef __STDC__ +#define assert(e) ((e) ? (void)0 : __assert("snc ", __FILE__, __LINE__, #e)) +#else /* PCC */ +#define assert(e) ((e) ? (void)0 : __assert("snc "__FILE__, __LINE__, "e")) +#endif +#endif + +#ifdef SNCDEBUG +#define SNC_SHOWTXHDR 0x01 /* show tx ether_header */ +#define SNC_SHOWRXHDR 0x02 /* show rx ether_header */ +#define SNC_SHOWCAMENT 0x04 /* show CAM entry */ +#endif /* SNCDEBUG */ +int sncdebug = 0; + + +void +sncconfig(sc, media, nmedia, defmedia, myea) + struct snc_softc *sc; + int *media, nmedia, defmedia; + u_int8_t *myea; +{ + struct ifnet *ifp = &sc->sc_if; + int i; + +#ifdef SNCDEBUG + if ((sncdebug & SNC_SHOWCAMENT) != 0) { + camdump(sc); + } +#endif + device_printf(sc->sc_dev, "address %6D\n", myea, ":"); + +#ifdef SNCDEBUG + device_printf(sc->sc_dev, + "buffers: rra=0x%x cda=0x%x rda=0x%x tda=0x%x\n", + sc->v_rra[0], sc->v_cda, + sc->v_rda, sc->mtda[0].mtd_vtxp); +#endif + + ifp->if_softc = sc; + ifp->if_unit = device_get_unit(sc->sc_dev); + ifp->if_name = "snc"; + ifp->if_ioctl = sncioctl; + ifp->if_output = ether_output; + ifp->if_start = sncstart; + ifp->if_flags = + IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_watchdog = sncwatchdog; + ifp->if_init = sncinit; + ifp->if_mtu = ETHERMTU; + ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; + bcopy(myea, sc->sc_ethercom.ac_enaddr, ETHER_ADDR_LEN); + + /* Initialize media goo. */ + ifmedia_init(&sc->sc_media, 0, snc_mediachange, + snc_mediastatus); + if (media != NULL) { + for (i = 0; i < nmedia; i++) + ifmedia_add(&sc->sc_media, media[i], 0, NULL); + ifmedia_set(&sc->sc_media, defmedia); + } else { + ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL); + ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL); + } + + ether_ifattach(ifp, ETHER_BPF_SUPPORTED); + +#if NRND > 0 + rnd_attach_source(&sc->rnd_source, device_get_nameunit(sc->sc_dev), + RND_TYPE_NET, 0); +#endif +} + +void +sncshutdown(arg) + void *arg; +{ + + sncstop((struct snc_softc *)arg); +} + +/* + * Media change callback. + */ +int +snc_mediachange(ifp) + struct ifnet *ifp; +{ + struct snc_softc *sc = ifp->if_softc; + + if (sc->sc_mediachange) + return ((*sc->sc_mediachange)(sc)); + return (EINVAL); +} + +/* + * Media status callback. + */ +void +snc_mediastatus(ifp, ifmr) + struct ifnet *ifp; + struct ifmediareq *ifmr; +{ + struct snc_softc *sc = ifp->if_softc; + + if (sc->sc_enabled == 0) { + ifmr->ifm_active = IFM_ETHER | IFM_NONE; + ifmr->ifm_status = 0; + return; + } + + if (sc->sc_mediastatus) + (*sc->sc_mediastatus)(sc, ifmr); +} + + +hide int +sncioctl(ifp, cmd, data) + struct ifnet *ifp; + u_long cmd; + caddr_t data; +{ + struct ifreq *ifr; + struct snc_softc *sc = ifp->if_softc; + int s = splnet(), err = 0; + int temp; + + switch (cmd) { + + case SIOCSIFADDR: + case SIOCGIFADDR: + case SIOCSIFMTU: + err = ether_ioctl(ifp, cmd, data); + 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. + */ + sncstop(sc); + ifp->if_flags &= ~IFF_RUNNING; + snc_disable(sc); + } 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. + */ + if ((err = snc_enable(sc)) != 0) + break; + sncinit(sc); + } else if (sc->sc_enabled) { + /* + * reset the interface to pick up any other changes + * in flags + */ + temp = ifp->if_flags & IFF_UP; + sncreset(sc); + ifp->if_flags |= temp; + sncstart(ifp); + } + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + if (sc->sc_enabled == 0) { + err = EIO; + break; + } + temp = ifp->if_flags & IFF_UP; + sncreset(sc); + ifp->if_flags |= temp; + err = 0; + break; + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + ifr = (struct ifreq *) data; + err = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); + break; + default: + err = EINVAL; + } + splx(s); + return (err); +} + +/* + * Encapsulate a packet of type family for the local net. + */ +hide void +sncstart(ifp) + struct ifnet *ifp; +{ + struct snc_softc *sc = ifp->if_softc; + struct mbuf *m; + int mtd_next; + + if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) + return; + +outloop: + /* Check for room in the xmit buffer. */ + if ((mtd_next = (sc->mtd_free + 1)) == NTDA) + mtd_next = 0; + + if (mtd_next == sc->mtd_hw) { + ifp->if_flags |= IFF_OACTIVE; + return; + } + + IF_DEQUEUE(&ifp->if_snd, m); + if (m == 0) + return; + + /* We need the header for m_pkthdr.len. */ + if ((m->m_flags & M_PKTHDR) == 0) + panic("%s: sncstart: no header mbuf", + device_get_nameunit(sc->sc_dev)); + + /* + * If bpf is listening on this interface, let it + * see the packet before we commit it to the wire. + */ + if (ifp->if_bpf) + bpf_mtap(ifp, m); + + /* + * If there is nothing in the o/p queue, and there is room in + * the Tx ring, then send the packet directly. Otherwise append + * it to the o/p queue. + */ + if ((sonicput(sc, m, mtd_next)) == 0) { + IF_PREPEND(&ifp->if_snd, m); + return; + } + + sc->mtd_prev = sc->mtd_free; + sc->mtd_free = mtd_next; + + ifp->if_opackets++; /* # of pkts */ + + /* Jump back for possibly more punishment. */ + goto outloop; +} + +/* + * reset and restart the SONIC. Called in case of fatal + * hardware/software errors. + */ +hide void +sncreset(sc) + struct snc_softc *sc; +{ + sncstop(sc); + sncinit(sc); +} + +hide void +sncinit(xsc) + void *xsc; +{ + struct snc_softc *sc = xsc; + u_long s_rcr; + int s; + + if (sc->sc_if.if_flags & IFF_RUNNING) + /* already running */ + return; + + s = splnet(); + + NIC_PUT(sc, SNCR_CR, CR_RST); /* DCR only accessable in reset mode! */ + + /* config it */ + NIC_PUT(sc, SNCR_DCR, (sc->sncr_dcr | + (sc->bitmode ? DCR_DW32 : DCR_DW16))); + NIC_PUT(sc, SNCR_DCR2, sc->sncr_dcr2); + + s_rcr = RCR_BRD | RCR_LBNONE; + if (sc->sc_if.if_flags & IFF_PROMISC) + s_rcr |= RCR_PRO; + if (sc->sc_if.if_flags & IFF_ALLMULTI) + s_rcr |= RCR_AMC; + NIC_PUT(sc, SNCR_RCR, s_rcr); + + NIC_PUT(sc, SNCR_IMR, (IMR_PRXEN | IMR_PTXEN | IMR_TXEREN | IMR_LCDEN)); + + /* clear pending interrupts */ + NIC_PUT(sc, SNCR_ISR, ISR_ALL); + + /* clear tally counters */ + NIC_PUT(sc, SNCR_CRCT, -1); + NIC_PUT(sc, SNCR_FAET, -1); + NIC_PUT(sc, SNCR_MPT, -1); + + initialise_tda(sc); + initialise_rda(sc); + initialise_rra(sc); + + /* enable the chip */ + NIC_PUT(sc, SNCR_CR, 0); + wbflush(); + + /* program the CAM */ + camprogram(sc); + + /* get it to read resource descriptors */ + NIC_PUT(sc, SNCR_CR, CR_RRRA); + wbflush(); + while ((NIC_GET(sc, SNCR_CR)) & CR_RRRA) + continue; + + /* enable rx */ + NIC_PUT(sc, SNCR_CR, CR_RXEN); + wbflush(); + + /* flag interface as "running" */ + sc->sc_if.if_flags |= IFF_RUNNING; + sc->sc_if.if_flags &= ~IFF_OACTIVE; + + splx(s); + return; +} + +/* + * close down an interface and free its buffers + * Called on final close of device, or if sncinit() fails + * part way through. + */ +hide int +sncstop(sc) + struct snc_softc *sc; +{ + struct mtd *mtd; + int s = splnet(); + + /* stick chip in reset */ + NIC_PUT(sc, SNCR_CR, CR_RST); + wbflush(); + + /* free all receive buffers (currently static so nothing to do) */ + + /* free all pending transmit mbufs */ + while (sc->mtd_hw != sc->mtd_free) { + mtd = &sc->mtda[sc->mtd_hw]; + if (mtd->mtd_mbuf) + m_freem(mtd->mtd_mbuf); + if (++sc->mtd_hw == NTDA) sc->mtd_hw = 0; + } + + sc->sc_if.if_timer = 0; + sc->sc_if.if_flags &= ~(IFF_RUNNING | IFF_UP); + + splx(s); + return (0); +} + +/* + * Called if any Tx packets remain unsent after 5 seconds, + * In all cases we just reset the chip, and any retransmission + * will be handled by higher level protocol timeouts. + */ +hide void +sncwatchdog(ifp) + struct ifnet *ifp; +{ + struct snc_softc *sc = ifp->if_softc; + struct mtd *mtd; + int temp; + + if (sc->mtd_hw != sc->mtd_free) { + /* something still pending for transmit */ + mtd = &sc->mtda[sc->mtd_hw]; + if (SRO(sc, mtd->mtd_vtxp, TXP_STATUS) == 0) + log(LOG_ERR, "%s: Tx - timeout\n", + device_get_nameunit(sc->sc_dev)); + else + log(LOG_ERR, "%s: Tx - lost interrupt\n", + device_get_nameunit(sc->sc_dev)); + temp = ifp->if_flags & IFF_UP; + sncreset(sc); + ifp->if_flags |= temp; + } +} + +/* + * stuff packet into sonic (at splnet) + */ +hide u_int +sonicput(sc, m0, mtd_next) + struct snc_softc *sc; + struct mbuf *m0; + int mtd_next; +{ + struct mtd *mtdp; + struct mbuf *m; + u_int32_t buff; + u_int32_t txp; + u_int len = 0; + u_int totlen = 0; + +#ifdef whyonearthwouldyoudothis + if (NIC_GET(sc, SNCR_CR) & CR_TXP) + return (0); +#endif + + /* grab the replacement mtd */ + mtdp = &sc->mtda[sc->mtd_free]; + + buff = mtdp->mtd_vbuf; + + /* this packet goes to mtdnext fill in the TDA */ + mtdp->mtd_mbuf = m0; + txp = mtdp->mtd_vtxp; + + /* Write to the config word. Every (NTDA/2)+1 packets we set an intr */ + if (sc->mtd_pint == 0) { + sc->mtd_pint = NTDA/2; + SWO(sc, txp, TXP_CONFIG, TCR_PINT); + } else { + sc->mtd_pint--; + SWO(sc, txp, TXP_CONFIG, 0); + } + + for (m = m0; m; m = m->m_next) { + len = m->m_len; + totlen += len; + (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), buff, len); + buff += len; + } + if (totlen >= TXBSIZE) { + panic("%s: sonicput: packet overflow", + device_get_nameunit(sc->sc_dev)); + } + + SWO(sc, txp, TXP_FRAGOFF + (0 * TXP_FRAGSIZE) + TXP_FPTRLO, + LOWER(mtdp->mtd_vbuf)); + SWO(sc, txp, TXP_FRAGOFF + (0 * TXP_FRAGSIZE) + TXP_FPTRHI, + UPPER(mtdp->mtd_vbuf)); + + if (totlen < ETHERMIN + sizeof(struct ether_header)) { + int pad = ETHERMIN + sizeof(struct ether_header) - totlen; + (*sc->sc_zerobuf)(sc, mtdp->mtd_vbuf + totlen, pad); + totlen = ETHERMIN + sizeof(struct ether_header); + } + + SWO(sc, txp, TXP_FRAGOFF + (0 * TXP_FRAGSIZE) + TXP_FSIZE, + totlen); + SWO(sc, txp, TXP_FRAGCNT, 1); + SWO(sc, txp, TXP_PKTSIZE, totlen); + + /* link onto the next mtd that will be used */ + SWO(sc, txp, TXP_FRAGOFF + (1 * TXP_FRAGSIZE) + TXP_FPTRLO, + LOWER(sc->mtda[mtd_next].mtd_vtxp) | EOL); + + /* + * The previous txp.tlink currently contains a pointer to + * our txp | EOL. Want to clear the EOL, so write our + * pointer to the previous txp. + */ + SWO(sc, sc->mtda[sc->mtd_prev].mtd_vtxp, sc->mtd_tlinko, + LOWER(mtdp->mtd_vtxp)); + + /* make sure chip is running */ + wbflush(); + NIC_PUT(sc, SNCR_CR, CR_TXP); + wbflush(); + sc->sc_if.if_timer = 5; /* 5 seconds to watch for failing to transmit */ + + return (totlen); +} + +/* + * These are called from sonicioctl() when /etc/ifconfig is run to set + * the address or switch the i/f on. + */ +/* + * CAM support + */ +hide void +caminitialise(sc) + struct snc_softc *sc; +{ + u_int32_t v_cda = sc->v_cda; + int i; + int camoffset; + + for (i = 0; i < MAXCAM; i++) { + camoffset = i * CDA_CAMDESC; + SWO(sc, v_cda, (camoffset + CDA_CAMEP), i); + SWO(sc, v_cda, (camoffset + CDA_CAMAP2), 0); + SWO(sc, v_cda, (camoffset + CDA_CAMAP1), 0); + SWO(sc, v_cda, (camoffset + CDA_CAMAP0), 0); + } + SWO(sc, v_cda, CDA_ENABLE, 0); + +#ifdef SNCDEBUG + if ((sncdebug & SNC_SHOWCAMENT) != 0) { + camdump(sc); + } +#endif +} + +hide void +camentry(sc, entry, ea) + int entry; + u_char *ea; + struct snc_softc *sc; +{ + u_int32_t v_cda = sc->v_cda; + int camoffset = entry * CDA_CAMDESC; + + SWO(sc, v_cda, camoffset + CDA_CAMEP, entry); + SWO(sc, v_cda, camoffset + CDA_CAMAP2, (ea[5] << 8) | ea[4]); + SWO(sc, v_cda, camoffset + CDA_CAMAP1, (ea[3] << 8) | ea[2]); + SWO(sc, v_cda, camoffset + CDA_CAMAP0, (ea[1] << 8) | ea[0]); + SWO(sc, v_cda, CDA_ENABLE, + (SRO(sc, v_cda, CDA_ENABLE) | (1 << entry))); +} + +hide void +camprogram(sc) + struct snc_softc *sc; +{ + struct ifmultiaddr *ifma; + struct ifnet *ifp; + int timeout; + int mcount = 0; + + caminitialise(sc); + + ifp = &sc->sc_if; + + /* Always load our own address first. */ + camentry (sc, mcount, sc->sc_ethercom.ac_enaddr); + mcount++; + + /* Assume we won't need allmulti bit. */ + ifp->if_flags &= ~IFF_ALLMULTI; + + /* Loop through multicast addresses */ + for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; + ifma = ifma->ifma_link.le_next) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + if (mcount == MAXCAM) { + ifp->if_flags |= IFF_ALLMULTI; + break; + } + + /* program the CAM with the specified entry */ + camentry(sc, mcount, + LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); + mcount++; + } + + NIC_PUT(sc, SNCR_CDP, LOWER(sc->v_cda)); + NIC_PUT(sc, SNCR_CDC, MAXCAM); + NIC_PUT(sc, SNCR_CR, CR_LCAM); + wbflush(); + + timeout = 10000; + while ((NIC_GET(sc, SNCR_CR) & CR_LCAM) && timeout--) + continue; + if (timeout == 0) { + /* XXX */ + panic("%s: CAM initialisation failed\n", + device_get_nameunit(sc->sc_dev)); + } + timeout = 10000; + while (((NIC_GET(sc, SNCR_ISR) & ISR_LCD) == 0) && timeout--) + continue; + + if (NIC_GET(sc, SNCR_ISR) & ISR_LCD) + NIC_PUT(sc, SNCR_ISR, ISR_LCD); + else + device_printf(sc->sc_dev, + "CAM initialisation without interrupt\n"); +} + +#ifdef SNCDEBUG +hide void +camdump(sc) + struct snc_softc *sc; +{ + int i; + + printf("CAM entries:\n"); + NIC_PUT(sc, SNCR_CR, CR_RST); + wbflush(); + + for (i = 0; i < 16; i++) { + ushort ap2, ap1, ap0; + NIC_PUT(sc, SNCR_CEP, i); + wbflush(); + ap2 = NIC_GET(sc, SNCR_CAP2); + ap1 = NIC_GET(sc, SNCR_CAP1); + ap0 = NIC_GET(sc, SNCR_CAP0); + printf("%d: ap2=0x%x ap1=0x%x ap0=0x%x\n", i, ap2, ap1, ap0); + } + printf("CAM enable 0x%x\n", NIC_GET(sc, SNCR_CEP)); + + NIC_PUT(sc, SNCR_CR, 0); + wbflush(); +} +#endif + +hide void +initialise_tda(sc) + struct snc_softc *sc; +{ + struct mtd *mtd; + int i; + + for (i = 0; i < NTDA; i++) { + mtd = &sc->mtda[i]; + mtd->mtd_mbuf = 0; + } + + sc->mtd_hw = 0; + sc->mtd_prev = NTDA - 1; + sc->mtd_free = 0; + sc->mtd_tlinko = TXP_FRAGOFF + 1*TXP_FRAGSIZE + TXP_FPTRLO; + sc->mtd_pint = NTDA/2; + + NIC_PUT(sc, SNCR_UTDA, UPPER(sc->mtda[0].mtd_vtxp)); + NIC_PUT(sc, SNCR_CTDA, LOWER(sc->mtda[0].mtd_vtxp)); +} + +hide void +initialise_rda(sc) + struct snc_softc *sc; +{ + int i; + u_int32_t vv_rda = 0; + u_int32_t v_rda = 0; + + /* link the RDA's together into a circular list */ + for (i = 0; i < (sc->sc_nrda - 1); i++) { + v_rda = sc->v_rda + (i * RXPKT_SIZE(sc)); + vv_rda = sc->v_rda + ((i+1) * RXPKT_SIZE(sc)); + SWO(sc, v_rda, RXPKT_RLINK, LOWER(vv_rda)); + SWO(sc, v_rda, RXPKT_INUSE, 1); + } + v_rda = sc->v_rda + ((sc->sc_nrda - 1) * RXPKT_SIZE(sc)); + SWO(sc, v_rda, RXPKT_RLINK, LOWER(sc->v_rda) | EOL); + SWO(sc, v_rda, RXPKT_INUSE, 1); + + /* mark end of receive descriptor list */ + sc->sc_rdamark = sc->sc_nrda - 1; + + sc->sc_rxmark = 0; + + NIC_PUT(sc, SNCR_URDA, UPPER(sc->v_rda)); + NIC_PUT(sc, SNCR_CRDA, LOWER(sc->v_rda)); + wbflush(); +} + +hide void +initialise_rra(sc) + struct snc_softc *sc; +{ + int i; + u_int v; + int bitmode = sc->bitmode; + + if (bitmode) + NIC_PUT(sc, SNCR_EOBC, RBASIZE(sc) / 2 - 2); + else + NIC_PUT(sc, SNCR_EOBC, RBASIZE(sc) / 2 - 1); + + NIC_PUT(sc, SNCR_URRA, UPPER(sc->v_rra[0])); + NIC_PUT(sc, SNCR_RSA, LOWER(sc->v_rra[0])); + /* rea must point just past the end of the rra space */ + NIC_PUT(sc, SNCR_REA, LOWER(sc->v_rea)); + NIC_PUT(sc, SNCR_RRP, LOWER(sc->v_rra[0])); + NIC_PUT(sc, SNCR_RSC, 0); + + /* fill up SOME of the rra with buffers */ + for (i = 0; i < NRBA; i++) { + v = SONIC_GETDMA(sc->rbuf[i]); + SWO(sc, sc->v_rra[i], RXRSRC_PTRHI, UPPER(v)); + SWO(sc, sc->v_rra[i], RXRSRC_PTRLO, LOWER(v)); + SWO(sc, sc->v_rra[i], RXRSRC_WCHI, UPPER(NBPG/2)); + SWO(sc, sc->v_rra[i], RXRSRC_WCLO, LOWER(NBPG/2)); + } + sc->sc_rramark = NRBA; + NIC_PUT(sc, SNCR_RWP, LOWER(sc->v_rra[sc->sc_rramark])); + wbflush(); +} + +void +sncintr(arg) + void *arg; +{ + struct snc_softc *sc = (struct snc_softc *)arg; + int isr; + + if (sc->sc_enabled == 0) + return; + + while ((isr = (NIC_GET(sc, SNCR_ISR) & ISR_ALL)) != 0) { + /* scrub the interrupts that we are going to service */ + NIC_PUT(sc, SNCR_ISR, isr); + wbflush(); + + if (isr & (ISR_BR | ISR_LCD | ISR_TC)) + device_printf(sc->sc_dev, + "unexpected interrupt status 0x%x\n", + isr); + + if (isr & (ISR_TXDN | ISR_TXER | ISR_PINT)) + sonictxint(sc); + + if (isr & ISR_PKTRX) + sonicrxint(sc); + + if (isr & (ISR_HBL | ISR_RDE | ISR_RBE | ISR_RBAE | ISR_RFO)) { + if (isr & ISR_HBL) + /* + * The repeater is not providing a heartbeat. + * In itself this isn't harmful, lots of the + * cheap repeater hubs don't supply a heartbeat. + * So ignore the lack of heartbeat. Its only + * if we can't detect a carrier that we have a + * problem. + */ + ; + if (isr & ISR_RDE) + device_printf(sc->sc_dev, + "receive descriptors exhausted\n"); + if (isr & ISR_RBE) + device_printf(sc->sc_dev, + "receive buffers exhausted\n"); + if (isr & ISR_RBAE) + device_printf(sc->sc_dev, + "receive buffer area exhausted\n"); + if (isr & ISR_RFO) + device_printf(sc->sc_dev, + "receive FIFO overrun\n"); + } + if (isr & (ISR_CRC | ISR_FAE | ISR_MP)) { +#ifdef notdef + if (isr & ISR_CRC) + sc->sc_crctally++; + if (isr & ISR_FAE) + sc->sc_faetally++; + if (isr & ISR_MP) + sc->sc_mptally++; +#endif + } + sncstart(&sc->sc_if); + +#if NRND > 0 + if (isr) + rnd_add_uint32(&sc->rnd_source, isr); +#endif + } + return; +} + +/* + * Transmit interrupt routine + */ +hide void +sonictxint(sc) + struct snc_softc *sc; +{ + struct mtd *mtd; + u_int32_t txp; + unsigned short txp_status; + int mtd_hw; + struct ifnet *ifp = &sc->sc_if; + + mtd_hw = sc->mtd_hw; + + if (mtd_hw == sc->mtd_free) + return; + + while (mtd_hw != sc->mtd_free) { + mtd = &sc->mtda[mtd_hw]; + + txp = mtd->mtd_vtxp; + + if (SRO(sc, txp, TXP_STATUS) == 0) { + break; /* it hasn't really gone yet */ + } + +#ifdef SNCDEBUG + if ((sncdebug & SNC_SHOWTXHDR) != 0) + { + struct ether_header eh; + + (*sc->sc_copyfrombuf)(sc, &eh, mtd->mtd_vbuf, sizeof(eh)); + device_printf(sc->sc_dev, + "xmit status=0x%x len=%d type=0x%x from %6D", + SRO(sc, txp, TXP_STATUS), + SRO(sc, txp, TXP_PKTSIZE), + htons(eh.ether_type), + eh.ether_shost, ":"); + printf(" (to %6D)\n", eh.ether_dhost, ":"); + } +#endif /* SNCDEBUG */ + + ifp->if_flags &= ~IFF_OACTIVE; + + if (mtd->mtd_mbuf != 0) { + m_freem(mtd->mtd_mbuf); + mtd->mtd_mbuf = 0; + } + if (++mtd_hw == NTDA) mtd_hw = 0; + + txp_status = SRO(sc, txp, TXP_STATUS); + + ifp->if_collisions += (txp_status & TCR_EXC) ? 16 : + ((txp_status & TCR_NC) >> 12); + + if ((txp_status & TCR_PTX) == 0) { + ifp->if_oerrors++; + device_printf(sc->sc_dev, "Tx packet status=0x%x\n", + txp_status); + + /* XXX - DG This looks bogus */ + if (mtd_hw != sc->mtd_free) { + printf("resubmitting remaining packets\n"); + mtd = &sc->mtda[mtd_hw]; + NIC_PUT(sc, SNCR_CTDA, LOWER(mtd->mtd_vtxp)); + NIC_PUT(sc, SNCR_CR, CR_TXP); + wbflush(); + break; + } + } + } + + sc->mtd_hw = mtd_hw; + return; +} + +/* + * Receive interrupt routine + */ +hide void +sonicrxint(sc) + struct snc_softc *sc; +{ + u_int32_t rda; + int orra; + int len; + int rramark; + int rdamark; + u_int16_t rxpkt_ptr; + + rda = sc->v_rda + (sc->sc_rxmark * RXPKT_SIZE(sc)); + + while (SRO(sc, rda, RXPKT_INUSE) == 0) { + u_int status = SRO(sc, rda, RXPKT_STATUS); + + orra = RBASEQ(SRO(sc, rda, RXPKT_SEQNO)) & RRAMASK; + rxpkt_ptr = SRO(sc, rda, RXPKT_PTRLO); + /* + * Do not trunc ether_header length. + * Our sonic_read() and sonic_get() require it. + */ + len = SRO(sc, rda, RXPKT_BYTEC) - FCSSIZE; + if (status & RCR_PRX) { + /* XXX: Does PGOFSET require? */ + u_int32_t pkt = + sc->rbuf[orra & RBAMASK] + (rxpkt_ptr & PGOFSET); + if (sonic_read(sc, pkt, len)) + sc->sc_if.if_ipackets++; + else + sc->sc_if.if_ierrors++; + } else + sc->sc_if.if_ierrors++; + + /* + * give receive buffer area back to chip. + * + * If this was the last packet in the RRA, give the RRA to + * the chip again. + * If sonic read didnt copy it out then we would have to + * wait !! + * (dont bother add it back in again straight away) + * + * Really, we're doing v_rra[rramark] = v_rra[orra] but + * we have to use the macros because SONIC might be in + * 16 or 32 bit mode. + */ + if (status & RCR_LPKT) { + u_int32_t tmp1, tmp2; + + rramark = sc->sc_rramark; + tmp1 = sc->v_rra[rramark]; + tmp2 = sc->v_rra[orra]; + SWO(sc, tmp1, RXRSRC_PTRLO, + SRO(sc, tmp2, RXRSRC_PTRLO)); + SWO(sc, tmp1, RXRSRC_PTRHI, + SRO(sc, tmp2, RXRSRC_PTRHI)); + SWO(sc, tmp1, RXRSRC_WCLO, + SRO(sc, tmp2, RXRSRC_WCLO)); + SWO(sc, tmp1, RXRSRC_WCHI, + SRO(sc, tmp2, RXRSRC_WCHI)); + + /* zap old rra for fun */ + SWO(sc, tmp2, RXRSRC_WCHI, 0); + SWO(sc, tmp2, RXRSRC_WCLO, 0); + + sc->sc_rramark = (++rramark) & RRAMASK; + NIC_PUT(sc, SNCR_RWP, LOWER(sc->v_rra[rramark])); + wbflush(); + } + + /* + * give receive descriptor back to chip simple + * list is circular + */ + rdamark = sc->sc_rdamark; + SWO(sc, rda, RXPKT_INUSE, 1); + SWO(sc, rda, RXPKT_RLINK, + SRO(sc, rda, RXPKT_RLINK) | EOL); + SWO(sc, (sc->v_rda + (rdamark * RXPKT_SIZE(sc))), RXPKT_RLINK, + SRO(sc, (sc->v_rda + (rdamark * RXPKT_SIZE(sc))), + RXPKT_RLINK) & ~EOL); + sc->sc_rdamark = sc->sc_rxmark; + + if (++sc->sc_rxmark >= sc->sc_nrda) + sc->sc_rxmark = 0; + rda = sc->v_rda + (sc->sc_rxmark * RXPKT_SIZE(sc)); + } +} + +/* + * sonic_read -- pull packet off interface and forward to + * appropriate protocol handler + */ +hide int +sonic_read(sc, pkt, len) + struct snc_softc *sc; + u_int32_t pkt; + int len; +{ + struct ifnet *ifp = &sc->sc_if; + struct ether_header *et; + struct mbuf *m; + + if (len <= sizeof(struct ether_header) || + len > ETHERMTU + sizeof(struct ether_header)) { + device_printf(sc->sc_dev, + "invalid packet length %d bytes\n", len); + return (0); + } + + /* Pull packet off interface. */ + m = sonic_get(sc, pkt, len); + if (m == 0) { + return (0); + } + + /* We assume that the header fit entirely in one mbuf. */ + et = mtod(m, struct ether_header *); + +#ifdef SNCDEBUG + if ((sncdebug & SNC_SHOWRXHDR) != 0) + { + device_printf(sc->sc_dev, "rcvd 0x%x len=%d type=0x%x from %6D", + pkt, len, htons(et->ether_type), + et->ether_shost, ":"); + printf(" (to %6D)\n", et->ether_dhost, ":"); + } +#endif /* SNCDEBUG */ + + /* Pass the packet up, with the ether header sort-of removed. */ + m_adj(m, sizeof(struct ether_header)); + ether_input(ifp, et, m); + return (1); +} + + +/* + * munge the received packet into an mbuf chain + */ +hide struct mbuf * +sonic_get(sc, pkt, datalen) + struct snc_softc *sc; + u_int32_t pkt; + int datalen; +{ + struct mbuf *m, *top, **mp; + int len; + /* + * Do not trunc ether_header length. + * Our sonic_read() and sonic_get() require it. + */ + + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == 0) + return (0); + m->m_pkthdr.rcvif = &sc->sc_if; + m->m_pkthdr.len = datalen; + len = MHLEN; + top = 0; + mp = ⊤ + + while (datalen > 0) { + if (top) { + MGET(m, M_DONTWAIT, MT_DATA); + if (m == 0) { + m_freem(top); + return (0); + } + len = MLEN; + } + if (datalen >= MINCLSIZE) { + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + if (top) m_freem(top); + return (0); + } + len = MCLBYTES; + } +#if 0 + /* XXX: Require? */ + if (!top) { + register int pad = + ALIGN(sizeof(struct ether_header)) - + sizeof(struct ether_header); + m->m_data += pad; + len -= pad; + } +#endif + m->m_len = len = min(datalen, len); + + (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), pkt, len); + pkt += len; + datalen -= len; + *mp = m; + mp = &m->m_next; + } + + return (top); +} +/* + * Enable power on the interface. + */ +int +snc_enable(sc) + struct snc_softc *sc; +{ + +#ifdef SNCDEBUG + device_printf(sc->sc_dev, "snc_enable()\n"); +#endif /* SNCDEBUG */ + + if (sc->sc_enabled == 0 && sc->sc_enable != NULL) { + if ((*sc->sc_enable)(sc) != 0) { + device_printf(sc->sc_dev, "device enable failed\n"); + return (EIO); + } + } + + sc->sc_enabled = 1; + return (0); +} + +/* + * Disable power on the interface. + */ +void +snc_disable(sc) + struct snc_softc *sc; +{ + +#ifdef SNCDEBUG + device_printf(sc->sc_dev, "snc_disable()\n"); +#endif /* SNCDEBUG */ + + if (sc->sc_enabled != 0 && sc->sc_disable != NULL) { + (*sc->sc_disable)(sc); + sc->sc_enabled = 0; + } +} + + diff --git a/sys/dev/snc/dp83932reg.h b/sys/dev/snc/dp83932reg.h new file mode 100644 index 0000000..b72fe86 --- /dev/null +++ b/sys/dev/snc/dp83932reg.h @@ -0,0 +1,271 @@ +/* $FreeBSD$ */ +/* $NecBSD: dp83932reg.h,v 1.2 1999/02/12 05:50:13 kmatsuda Exp $ */ +/* $NetBSD: if_snreg.h,v 1.4 1997/06/15 20:20:12 scottr Exp $ */ + +/* + * Copyright (c) 1991 Algorithmics Ltd (http://www.algor.co.uk) + * You may use, copy, and modify this program so long as you retain the + * copyright line. + */ + +/* + * if_snreg.h -- National Semiconductor DP8393X (SONIC) register defs + */ + +/* + * SONIC registers as seen by the processor + */ +#define SNCR_CR 0x00 /* Command */ +#define SNCR_DCR 0x01 /* Data Configuration */ +#define SNCR_RCR 0x02 /* Receive Control */ +#define SNCR_TCR 0x03 /* Transmit Control */ +#define SNCR_IMR 0x04 /* Interrupt Mask */ +#define SNCR_ISR 0x05 /* Interrupt Status */ +#define SNCR_UTDA 0x06 /* Upper Transmit Descriptor Address */ +#define SNCR_CTDA 0x07 /* Current Transmit Descriptor Address */ +#define SNCR_TPS 0x08 /* Transmit Packet Size */ +#define SNCR_TFC 0x09 /* Transmit Fragment Count */ +#define SNCR_TSA0 0x0a /* Transmit Start Address 0 */ +#define SNCR_TSA1 0x0b /* Transmit Start Address 1 */ +#define SNCR_TFS 0x0c /* Transmit Fragment Size */ +#define SNCR_URDA 0x0d /* Upper Receive Descriptor Address */ +#define SNCR_CRDA 0x0e /* Current Receive Descriptor Address */ +#define SNCR_CRBA0 0x0f /* Current Receive Buffer Address 0 */ +#define SNCR_CRBA1 0x10 /* Current Receive Buffer Address 1 */ +#define SNCR_RBWC0 0x11 /* Remaining Buffer Word Count 0 */ +#define SNCR_RBWC1 0x12 /* Remaining Buffer Word Count 1 */ +#define SNCR_EOBC 0x13 /* End Of Buffer Word Count */ +#define SNCR_URRA 0x14 /* Upper Receive Resource Address */ +#define SNCR_RSA 0x15 /* Resource Start Address */ +#define SNCR_REA 0x16 /* Resource End Address */ +#define SNCR_RRP 0x17 /* Resource Read Pointer */ +#define SNCR_RWP 0x18 /* Resource Write Pointer */ +#define SNCR_TRBA0 0x19 /* Temporary Receive Buffer Address 0 */ +#define SNCR_TRBA1 0x1a /* Temporary Receive Buffer Address 1 */ +#define SNCR_TBWC0 0x1b /* Temporary Buffer Word Count 0 */ +#define SNCR_TBWC1 0x1c /* Temporary Buffer Word Count 1 */ +#define SNCR_ADDR0 0x1d /* Address Generator 0 */ +#define SNCR_ADDR1 0x1e /* Address Generator 1 */ +#define SNCR_LLFA 0x1f /* Last Link Field Address */ +#define SNCR_TTDA 0x20 /* Temp Transmit Descriptor Address */ +#define SNCR_CEP 0x21 /* CAM Entry Pointer */ +#define SNCR_CAP2 0x22 /* CAM Address Port 2 */ +#define SNCR_CAP1 0x23 /* CAM Address Port 1 */ +#define SNCR_CAP0 0x24 /* CAM Address Port 0 */ +#define SNCR_CE 0x25 /* CAM Enable */ +#define SNCR_CDP 0x26 /* CAM Descriptor Pointer */ +#define SNCR_CDC 0x27 /* CAM Descriptor Count */ +#define SNCR_SR 0x28 /* Silicon Revision */ +#define SNCR_WT0 0x29 /* Watchdog Timer 0 */ +#define SNCR_WT1 0x2a /* Watchdog Timer 1 */ +#define SNCR_RSC 0x2b /* Receive Sequence Counter */ +#define SNCR_CRCT 0x2c /* CRC Error Tally */ +#define SNCR_FAET 0x2d /* FAE Tally */ +#define SNCR_MPT 0x2e /* Missed Packet Tally */ +#define SNCR_MDT 0x2f /* Maximum Deferral Timer */ +#define SNCR_RTC 0x30 /* Receive Test Control */ +#define SNCR_TTC 0x31 /* Transmit Test Control */ +#define SNCR_DTC 0x32 /* DMA Test Control */ +#define SNCR_CC0 0x33 /* CAM Comparison 0 */ +#define SNCR_CC1 0x34 /* CAM Comparison 1 */ +#define SNCR_CC2 0x35 /* CAM Comparison 2 */ +#define SNCR_CM 0x36 /* CAM Match */ +#define SNCR_RES1 0x37 /* reserved */ +#define SNCR_RES2 0x38 /* reserved */ +#define SNCR_RBC 0x39 /* Receiver Byte Count */ +#define SNCR_RES3 0x3a /* reserved */ +#define SNCR_TBO 0x3b /* Transmitter Backoff Counter */ +#define SNCR_TRC 0x3c /* Transmitter Random Counter */ +#define SNCR_TBM 0x3d /* Transmitter Backoff Mask */ +#define SNCR_RES4 0x3e /* Reserved */ +#define SNCR_DCR2 0x3f /* Data Configuration 2 (AVF) */ + +#define SNC_NREGS 0x40 + +/* + * Register Interpretations + */ + +/* + * The command register is used for issuing commands to the SONIC. + * With the exception of CR_RST, the bit is reset when the operation + * completes. + */ +#define CR_LCAM 0x0200 /* load CAM with descriptor at s_cdp */ +#define CR_RRRA 0x0100 /* read next RRA descriptor at s_rrp */ +#define CR_RST 0x0080 /* software reset */ +#define CR_ST 0x0020 /* start timer */ +#define CR_STP 0x0010 /* stop timer */ +#define CR_RXEN 0x0008 /* receiver enable */ +#define CR_RXDIS 0x0004 /* receiver disable */ +#define CR_TXP 0x0002 /* transmit packets */ +#define CR_HTX 0x0001 /* halt transmission */ + +/* + * The data configuration register establishes the SONIC's bus cycle + * operation. This register can only be accessed when the SONIC is in + * reset mode (s_cr.CR_RST is set.) + */ +#define DCR_EXBUS 0x8000 /* extended bus mode (AVF) */ +#define DCR_LBR 0x2000 /* latched bus retry */ +#define DCR_PO1 0x1000 /* programmable output 1 */ +#define DCR_PO0 0x0800 /* programmable output 0 */ +#define DCR_STERM 0x0400 /* synchronous termination */ +#define DCR_USR1 0x0200 /* reflects USR1 input pin */ +#define DCR_USR0 0x0100 /* reflects USR0 input pin */ +#define DCR_WC1 0x0080 /* wait state control 1 */ +#define DCR_WC0 0x0040 /* wait state control 0 */ +#define DCR_DW 0x0020 /* data width select */ +#define DCR_BMS 0x0010 /* DMA block mode select */ +#define DCR_RFT1 0x0008 /* receive FIFO threshold control 1 */ +#define DCR_RFT0 0x0004 /* receive FIFO threshold control 0 */ +#define DCR_TFT1 0x0002 /* transmit FIFO threshold control 1 */ +#define DCR_TFT0 0x0001 /* transmit FIFO threshold control 0 */ + +/* data configuration register aliases */ +#define DCR_SYNC DCR_STERM /* synchronous (memory cycle 2 clocks) */ +#define DCR_ASYNC 0 /* asynchronous (memory cycle 3 clocks) */ + +#define DCR_WAIT0 0 /* 0 wait states added */ +#define DCR_WAIT1 DCR_WC0 /* 1 wait state added */ +#define DCR_WAIT2 DCR_WC1 /* 2 wait states added */ +#define DCR_WAIT3 (DCR_WC1|DCR_WC0) /* 3 wait states added */ + +#define DCR_DW16 0 /* use 16-bit DMA accesses */ +#define DCR_DW32 DCR_DW /* use 32-bit DMA accesses */ + +#define DCR_DMAEF 0 /* DMA until TX/RX FIFO has emptied/filled */ +#define DCR_DMABLOCK DCR_BMS /* DMA until RX/TX threshold crossed */ + +#define DCR_RFT4 0 /* receive threshold 4 bytes */ +#define DCR_RFT8 DCR_RFT0 /* receive threshold 8 bytes */ +#define DCR_RFT16 DCR_RFT1 /* receive threshold 16 bytes */ +#define DCR_RFT24 (DCR_RFT1|DCR_RFT0) /* receive threshold 24 bytes */ + +#define DCR_TFT8 0 /* transmit threshold 8 bytes */ +#define DCR_TFT16 DCR_TFT0 /* transmit threshold 16 bytes */ +#define DCR_TFT24 DCR_TFT1 /* transmit threshold 24 bytes */ +#define DCR_TFT28 (DCR_TFT1|DCR_TFT0) /* transmit threshold 28 bytes */ + +/* + * The receive control register is used to filter incoming packets and + * provides status information on packets received. + * The contents of the register are copied into the RXpkt.status field + * when a packet is received. RCR_MC - RCR_PRX are then reset. + */ +#define RCR_ERR 0x8000 /* accept packets with CRC errors */ +#define RCR_RNT 0x4000 /* accept runt (length < 64) packets */ +#define RCR_BRD 0x2000 /* accept broadcast packets */ +#define RCR_PRO 0x1000 /* accept all physical address packets */ +#define RCR_AMC 0x0800 /* accept all multicast packets */ +#define RCR_LB1 0x0400 /* loopback control 1 */ +#define RCR_LB0 0x0200 /* loopback control 0 */ +#define RCR_MC 0x0100 /* multicast packet received */ +#define RCR_BC 0x0080 /* broadcast packet received */ +#define RCR_LPKT 0x0040 /* last packet in RBA (RBWC < EOBC) */ +#define RCR_CRS 0x0020 /* carrier sense activity */ +#define RCR_COL 0x0010 /* collision activity */ +#define RCR_CRC 0x0008 /* CRC error */ +#define RCR_FAE 0x0004 /* frame alignment error */ +#define RCR_LBK 0x0002 /* loopback packet received */ +#define RCR_PRX 0x0001 /* packet received without errors */ + +/* receiver control register aliases */ +/* the loopback control bits provide the following options */ +#define RCR_LBNONE 0 /* no loopback - normal operation */ +#define RCR_LBMAC RCR_LB0 /* MAC loopback */ +#define RCR_LBENDEC RCR_LB1 /* ENDEC loopback */ +#define RCR_LBTRANS (RCR_LB1|RCR_LB0) /* transceiver loopback */ + +/* + * The transmit control register controls the SONIC's transmit operations. + * TCR_PINT - TCR_EXDIS are loaded from the TXpkt.config field at the + * start of transmission. TCR_EXD-TCR_PTX are cleared at the beginning + * of transmission and updated when the transmission is completed. + */ +#define TCR_PINT 0x8000 /* interrupt when transmission starts */ +#define TCR_POWC 0x4000 /* program out of window collision timer */ +#define TCR_CRCI 0x2000 /* transmit packet without 4 byte FCS */ +#define TCR_EXDIS 0x1000 /* disable excessive deferral timer */ +#define TCR_EXD 0x0400 /* excessive deferrals occurred (>3.2ms) */ +#define TCR_DEF 0x0200 /* deferred transmissions occurred */ +#define TCR_NCRS 0x0100 /* carrier not present during transmission */ +#define TCR_CRSL 0x0080 /* carrier lost during transmission */ +#define TCR_EXC 0x0040 /* excessive collisions (>16) detected */ +#define TCR_OWC 0x0020 /* out of window (bad) collision occurred */ +#define TCR_PMB 0x0008 /* packet monitored bad - the tansmitted + * packet had a bad source address or CRC */ +#define TCR_FU 0x0004 /* FIFO underrun (memory access failed) */ +#define TCR_BCM 0x0002 /* byte count mismatch (TXpkt.pkt_size + * != sum(TXpkt.frag_size) */ +#define TCR_PTX 0x0001 /* packet transmitted without errors */ +#define TCR_NC 0xf000 /* after transmission, # of colls */ + +/* transmit control register aliases */ +#define TCR_OWCSFD 0 /* start after start of frame delimiter */ +#define TCR_OWCPRE TCR_POWC /* start after first bit of preamble */ + + +/* + * The interrupt mask register masks the interrupts that + * are generated from the interrupt status register. + * All reserved bits should be written with 0. + */ +#define IMR_BREN 0x4000 /* bus retry occurred enable */ +#define IMR_HBLEN 0x2000 /* heartbeat lost enable */ +#define IMR_LCDEN 0x1000 /* load CAM done interrupt enable */ +#define IMR_PINTEN 0x0800 /* programmable interrupt enable */ +#define IMR_PRXEN 0x0400 /* packet received enable */ +#define IMR_PTXEN 0x0200 /* packet transmitted enable */ +#define IMR_TXEREN 0x0100 /* transmit error enable */ +#define IMR_TCEN 0x0080 /* timer complete enable */ +#define IMR_RDEEN 0x0040 /* receive descriptors exhausted enable */ +#define IMR_RBEEN 0x0020 /* receive buffers exhausted enable */ +#define IMR_RBAEEN 0x0010 /* receive buffer area exceeded enable */ +#define IMR_CRCEN 0x0008 /* CRC tally counter rollover enable */ +#define IMR_FAEEN 0x0004 /* FAE tally counter rollover enable */ +#define IMR_MPEN 0x0002 /* MP tally counter rollover enable */ +#define IMR_RFOEN 0x0001 /* receive FIFO overrun enable */ + + +/* + * The interrupt status register indicates the source of an interrupt when + * the INT pin goes active. The interrupt is acknowledged by writing + * the appropriate bit(s) in this register. + */ +#define ISR_ALL 0x7fff /* all interrupts */ +#define ISR_BR 0x4000 /* bus retry occurred */ +#define ISR_HBL 0x2000 /* CD heartbeat lost */ +#define ISR_LCD 0x1000 /* load CAM command has completed */ +#define ISR_PINT 0x0800 /* programmed interrupt from TXpkt.config */ +#define ISR_PKTRX 0x0400 /* packet received */ +#define ISR_TXDN 0x0200 /* no remaining packets to be transmitted */ +#define ISR_TXER 0x0100 /* packet transmission caused error */ +#define ISR_TC 0x0080 /* timer complete */ +#define ISR_RDE 0x0040 /* receive descriptors exhausted */ +#define ISR_RBE 0x0020 /* receive buffers exhausted */ +#define ISR_RBAE 0x0010 /* receive buffer area exceeded */ +#define ISR_CRC 0x0008 /* CRC tally counter rollover */ +#define ISR_FAE 0x0004 /* FAE tally counter rollover */ +#define ISR_MP 0x0002 /* MP tally counter rollover */ +#define ISR_RFO 0x0001 /* receive FIFO overrun */ + +/* + * The second data configuration register allows additional user defined + * pins to be controlled. These bits are only available if s_dcr.DCR_EXBUS + * is set. + */ +#define DCR2_EXPO3 0x8000 /* EXUSR3 output */ +#define DCR2_EXPO2 0x4000 /* EXUSR2 output */ +#define DCR2_EXPO1 0x2000 /* EXUSR1 output */ +#define DCR2_EXPO0 0x1000 /* EXUSR0 output */ +#define DCR2_HD 0x0800 /* heart beat disable (83934/83936) */ +#define DCR2_JD 0x0200 /* TPI jabber timer disable (83934/83936) */ +#define DCR2_AUTO 0x0100 /* AUI/TPI auto selection (83934/83936) */ +#define DCR2_XWRAP 0x0040 /* TPI transceiver loopback (83934/83936) */ +#define DCR2_FD 0x0020 /* full duplex (83936) */ +#define DCR2_PHL 0x0010 /* extend HOLD signal by 1/2 clock */ +#define DCR2_LRDY 0x0008 /* set latched ready mode */ +#define DCR2_PCM 0x0004 /* packet compress on match */ +#define DCR2_PCNM 0x0002 /* packet compress on mismatch */ +#define DCR2_RJM 0x0001 /* reject on match */ diff --git a/sys/dev/snc/dp83932subr.c b/sys/dev/snc/dp83932subr.c new file mode 100644 index 0000000..65b9de9 --- /dev/null +++ b/sys/dev/snc/dp83932subr.c @@ -0,0 +1,902 @@ +/* $FreeBSD$ */ +/* $NecBSD: dp83932subr.c,v 1.5.6.2 1999/10/09 05:47:23 kmatsuda Exp $ */ +/* $NetBSD$ */ + +/* + * Copyright (c) 1997, 1998, 1999 + * Kouichi Matsuda. 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 Kouichi Matsuda for + * NetBSD/pc98. + * 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. + */ +/* + * Routines of NEC PC-9801-83, 84, 103, 104, PC-9801N-25 and PC-9801N-J02, J02R + * Ethernet interface for NetBSD/pc98, ported by Kouichi Matsuda. + * + * These cards use National Semiconductor DP83934AVQB as Ethernet Controller + * and National Semiconductor NS46C46 as (64 * 16 bits) Microwire Serial EEPROM. + */ + +/* + * Modified for FreeBSD(98) 4.0 from NetBSD/pc98 1.4.2 by Motomichi Matsuzaki. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/syslog.h> +#include <sys/errno.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_dl.h> +#include <net/if_types.h> +#include <net/if_media.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#include <netinet/if_inarp.h> +#endif + +#include <net/bpf.h> + +#include <sys/bus.h> +#include <machine/clock.h> +#include <machine/cpu.h> +#include <machine/bus_pio.h> +#include <machine/bus_memio.h> +#include <machine/bus.h> + +#include <dev/snc/dp83932reg.h> +#include <dev/snc/dp83932var.h> +#include <dev/snc/if_sncreg.h> +#include <dev/snc/dp83932subr.h> + +integrate u_int16_t snc_nec16_select_bank + __P((struct snc_softc *, u_int32_t, u_int32_t)); + +/* + * Interface exists: make available by filling in network interface + * record. System will initialize the interface when it is ready + * to accept packets. + */ +int +sncsetup(sc, lladdr) + struct snc_softc *sc; + u_int8_t *lladdr; +{ + u_int32_t p, pp; + int i; + int offset; + + /* + * Put the pup in reset mode (sncinit() will fix it later), + * stop the timer, disable all interrupts and clear any interrupts. + */ + NIC_PUT(sc, SNCR_CR, CR_STP); + wbflush(); + NIC_PUT(sc, SNCR_CR, CR_RST); + wbflush(); + NIC_PUT(sc, SNCR_IMR, 0); + wbflush(); + NIC_PUT(sc, SNCR_ISR, ISR_ALL); + wbflush(); + + /* + * because the SONIC is basically 16bit device it 'concatenates' + * a higher buffer address to a 16 bit offset--this will cause wrap + * around problems near the end of 64k !! + */ + p = pp = 0; + + for (i = 0; i < NRRA; i++) { + sc->v_rra[i] = SONIC_GETDMA(p); + p += RXRSRC_SIZE(sc); + } + sc->v_rea = SONIC_GETDMA(p); + + p = SOALIGN(sc, p); + + sc->v_cda = SONIC_GETDMA(p); + p += CDA_SIZE(sc); + + p = SOALIGN(sc, p); + + for (i = 0; i < NTDA; i++) { + struct mtd *mtdp = &sc->mtda[i]; + mtdp->mtd_vtxp = SONIC_GETDMA(p); + p += TXP_SIZE(sc); + } + + p = SOALIGN(sc, p); + + if ((p - pp) > NBPG) { + device_printf (sc->sc_dev, "sizeof RRA (%ld) + CDA (%ld) +" + "TDA (%ld) > NBPG (%d). Punt!\n", + (ulong)sc->v_cda - (ulong)sc->v_rra[0], + (ulong)sc->mtda[0].mtd_vtxp - (ulong)sc->v_cda, + (ulong)p - (ulong)sc->mtda[0].mtd_vtxp, + NBPG); + return(1); + } + + p = pp + NBPG; + pp = p; + + sc->sc_nrda = NBPG / RXPKT_SIZE(sc); + sc->v_rda = SONIC_GETDMA(p); + + p = pp + NBPG; + + for (i = 0; i < NRBA; i++) { + sc->rbuf[i] = p; + p += NBPG; + } + + pp = p; + offset = TXBSIZE; + for (i = 0; i < NTDA; i++) { + struct mtd *mtdp = &sc->mtda[i]; + + mtdp->mtd_vbuf = SONIC_GETDMA(p); + offset += TXBSIZE; + if (offset < NBPG) { + p += TXBSIZE; + } else { + p = pp + NBPG; + pp = p; + offset = TXBSIZE; + } + } + + return (0); +} + +/* + * miscellaneous NEC/SONIC detect functions. + */ + +/* + * check if a specified irq is acceptable. + */ +u_int8_t +snc_nec16_validate_irq(irq) + int irq; +{ + const u_int8_t encoded_irq[16] = { + -1, -1, -1, 0, -1, 1, 2, -1, -1, 3, 4, -1, 5, 6, -1, -1 + }; + + return encoded_irq[irq]; +} + +/* + * specify irq to board. + */ +int +snc_nec16_register_irq(sc, irq) + struct snc_softc *sc; + int irq; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + u_int8_t encoded_irq; + + encoded_irq = snc_nec16_validate_irq(irq); + if (encoded_irq == (u_int8_t) -1) { + printf("snc_nec16_register_irq: unsupported irq (%d)\n", irq); + return 0; + } + + /* select SNECR_IRQSEL register */ + bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_IRQSEL); + /* write encoded irq value */ + bus_space_write_1(iot, ioh, SNEC_CTRLB, encoded_irq); + + return 1; +} + +/* + * check if a specified memory base address is acceptable. + */ +int +snc_nec16_validate_mem(maddr) + int maddr; +{ + + /* Check on Normal mode with max range, only */ + if ((maddr & ~0x1E000) != 0xC0000) { + printf("snc_nec16_validate_mem: " + "unsupported window base (0x%x)\n", maddr); + return 0; + } + + return 1; +} + +/* + * specify memory base address to board and map to first bank. + */ +int +snc_nec16_register_mem(sc, maddr) + struct snc_softc *sc; + int maddr; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + + if (snc_nec16_validate_mem(maddr) == 0) + return 0; + + /* select SNECR_MEMSEL register */ + bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMSEL); + /* write encoded memory base select value */ + bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_MEMSEL_PHYS2EN(maddr)); + + /* + * set current bank to 0 (bottom) and map + */ + /* select SNECR_MEMBS register */ + bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); + /* select new bank */ + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_MEMBS_B2EB(0) | SNECR_MEMBS_BSEN); + /* set current bank to 0 */ + sc->curbank = 0; + + return 1; +} + +int +snc_nec16_check_memory(iot, ioh, memt, memh) + bus_space_tag_t iot; + bus_space_handle_t ioh; + bus_space_tag_t memt; + bus_space_handle_t memh; +{ + u_int16_t val; + int i, j; + + val = 0; + for (i = 0; i < SNEC_NBANK; i++) { + /* select new bank */ + bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN); + + /* write test pattern */ + for (j = 0; j < SNEC_NMEMS / 2; j++) { + bus_space_write_2(memt, memh, j * 2, val + j); + } + val += 0x1000; + } + + val = 0; + for (i = 0; i < SNEC_NBANK; i++) { + /* select new bank */ + bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN); + + /* read test pattern */ + for (j = 0; j < SNEC_NMEMS / 2; j++) { + if (bus_space_read_2(memt, memh, j * 2) != val + j) + break; + } + + if (j < SNEC_NMEMS / 2) { + printf("snc_nec16_check_memory: " + "memory check failed at 0x%04x%04x" + "val 0x%04x != expected 0x%04x\n", i, j, + bus_space_read_2(memt, memh, j * 2), + val + j); + return 0; + } + val += 0x1000; + } + + /* zero clear mem */ + for (i = 0; i < SNEC_NBANK; i++) { + /* select new bank */ + bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN); + + bus_space_set_region_4(memt, memh, 0, 0, SNEC_NMEMS >> 2); + } + + /* again read test if these are 0 */ + for (i = 0; i < SNEC_NBANK; i++) { + /* select new bank */ + bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_MEMBS_B2EB(i) | SNECR_MEMBS_BSEN); + + /* check if cleared */ + for (j = 0; j < SNEC_NMEMS; j += 2) { + if (bus_space_read_2(memt, memh, j) != 0) + break; + } + + if (j != SNEC_NMEMS) { + printf("snc_nec16_check_memory: " + "memory zero clear failed at 0x%04x%04x\n", i, j); + return 0; + } + } + + return 1; +} + +int +snc_nec16_detectsubr(iot, ioh, memt, memh, irq, maddr, type) + bus_space_tag_t iot; + bus_space_handle_t ioh; + bus_space_tag_t memt; + bus_space_handle_t memh; + int irq; + int maddr; + u_int8_t type; +{ + u_int16_t cr; + u_int8_t ident; + int rv = 0; + + if (snc_nec16_validate_irq(irq) == (u_int8_t) -1) + return 0; + /* XXX: maddr already checked */ + if (snc_nec16_validate_mem(maddr) == 0) + return 0; + + bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_IDENT); + ident = bus_space_read_1(iot, ioh, SNEC_CTRLB); + if (ident == 0xff || ident == 0x00) { + /* not found */ + return 0; + } + + switch (type) { + case SNEC_TYPE_LEGACY: + rv = (ident == SNECR_IDENT_LEGACY_CBUS); + break; + case SNEC_TYPE_PNP: + rv = ((ident == SNECR_IDENT_PNP_CBUS) || + (ident == SNECR_IDENT_PNP_PCMCIABUS)); + break; + default: + break; + } + + if (rv == 0) { + printf("snc_nec16_detectsubr: parent bus mismatch\n"); + return 0; + } + + /* select SONIC register SNCR_CR */ + bus_space_write_1(iot, ioh, SNEC_ADDR, SNCR_CR); + bus_space_write_2(iot, ioh, SNEC_CTRL, CR_RXDIS | CR_STP | CR_RST); + delay(400); + + cr = bus_space_read_2(iot, ioh, SNEC_CTRL); + if (cr != (CR_RXDIS | CR_STP | CR_RST)) { +#ifdef DIAGNOSTIC + printf("snc_nec16_detectsubr: card reset failed, cr = 0x%04x\n", + cr); +#endif + return 0; + } + + if (snc_nec16_check_memory(iot, ioh, memt, memh) == 0) + return 0; + + return 1; +} + +/* XXX */ +#define SNC_VENDOR_NEC 0x00004c +#define SNC_NEC_SERIES_LEGACY_CBUS 0xa5 +#define SNC_NEC_SERIES_PNP_PCMCIA 0xd5 +#define SNC_NEC_SERIES_PNP_PCMCIA2 0x6d /* XXX */ +#define SNC_NEC_SERIES_PNP_CBUS 0x0d +#define SNC_NEC_SERIES_PNP_CBUS2 0x3d + +u_int8_t * +snc_nec16_detect_type(myea) + u_int8_t *myea; +{ + u_int32_t vendor = (myea[0] << 16) | (myea[1] << 8) | myea[2]; + u_int8_t series = myea[3]; + u_int8_t type = myea[4] & 0x80; + u_int8_t *typestr; + + switch (vendor) { + case SNC_VENDOR_NEC: + switch (series) { + case SNC_NEC_SERIES_LEGACY_CBUS: + if (type) + typestr = "NEC PC-9801-84"; + else + typestr = "NEC PC-9801-83"; + break; + case SNC_NEC_SERIES_PNP_CBUS: + case SNC_NEC_SERIES_PNP_CBUS2: + if (type) + typestr = "NEC PC-9801-104"; + else + typestr = "NEC PC-9801-103"; + break; + case SNC_NEC_SERIES_PNP_PCMCIA: + case SNC_NEC_SERIES_PNP_PCMCIA2: + /* XXX: right ? */ + if (type) + typestr = "NEC PC-9801N-J02R"; + else + typestr = "NEC PC-9801N-J02"; + break; + default: + typestr = "NEC unknown (PC-9801N-25?)"; + break; + } + break; + default: + typestr = "unknown (3rd vendor?)"; + break; + } + + return typestr; +} + +int +snc_nec16_get_enaddr(iot, ioh, myea) + bus_space_tag_t iot; + bus_space_handle_t ioh; + u_int8_t *myea; +{ + u_int8_t eeprom[SNEC_EEPROM_SIZE]; + u_int8_t rom_sum, sum = 0x00; + int i; + + snc_nec16_read_eeprom(iot, ioh, eeprom); + + for (i = SNEC_EEPROM_KEY0; i < SNEC_EEPROM_CKSUM; i++) { + sum = sum ^ eeprom[i]; + } + + rom_sum = eeprom[SNEC_EEPROM_CKSUM]; + + if (sum != rom_sum) { + printf("snc_nec16_get_enaddr: " + "checksum mismatch; calculated %02x != read %02x", + sum, rom_sum); + return 0; + } + + for (i = 0; i < ETHER_ADDR_LEN; i++) + myea[i] = eeprom[SNEC_EEPROM_SA0 + i]; + + return 1; +} + +/* + * read from NEC/SONIC NIC register. + */ +u_int16_t +snc_nec16_nic_get(sc, reg) + struct snc_softc *sc; + u_int8_t reg; +{ + u_int16_t val; + + /* select SONIC register */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, SNEC_ADDR, reg); + val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SNEC_CTRL); + + return val; +} + +/* + * write to NEC/SONIC NIC register. + */ +void +snc_nec16_nic_put(sc, reg, val) + struct snc_softc *sc; + u_int8_t reg; + u_int16_t val; +{ + + /* select SONIC register */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, SNEC_ADDR, reg); + bus_space_write_2(sc->sc_iot, sc->sc_ioh, SNEC_CTRL, val); +} + + +/* + * select memory bank and map + * where exists specified (internal buffer memory) offset. + */ +integrate u_int16_t +snc_nec16_select_bank(sc, base, offset) + struct snc_softc *sc; + u_int32_t base; + u_int32_t offset; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + u_int8_t bank; + u_int16_t noffset; + + /* bitmode is fixed to 16 bit. */ + bank = (base + offset * 2) >> 13; + noffset = (base + offset * 2) & (SNEC_NMEMS - 1); + +#ifdef SNCDEBUG + if (noffset % 2) { + device_printf(sc->sc_dev, "noffset is odd (0x%04x)\n", + noffset); + } +#endif /* SNCDEBUG */ + + if (sc->curbank != bank) { + /* select SNECR_MEMBS register */ + bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_MEMBS); + /* select new bank */ + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_MEMBS_B2EB(bank) | SNECR_MEMBS_BSEN); + /* update current bank */ + sc->curbank = bank; + } + + return noffset; +} + +/* + * write to SONIC descriptors. + */ +void +snc_nec16_writetodesc(sc, base, offset, val) + struct snc_softc *sc; + u_int32_t base; + u_int32_t offset; + u_int16_t val; +{ + bus_space_tag_t memt = sc->sc_memt; + bus_space_handle_t memh = sc->sc_memh; + u_int16_t noffset; + + noffset = snc_nec16_select_bank(sc, base, offset); + + bus_space_write_2(memt, memh, noffset, val); +} + +/* + * read from SONIC descriptors. + */ +u_int16_t +snc_nec16_readfromdesc(sc, base, offset) + struct snc_softc *sc; + u_int32_t base; + u_int32_t offset; +{ + bus_space_tag_t memt = sc->sc_memt; + bus_space_handle_t memh = sc->sc_memh; + u_int16_t noffset; + + noffset = snc_nec16_select_bank(sc, base, offset); + + return bus_space_read_2(memt, memh, noffset); +} + +/* + * read from SONIC data buffer. + */ +void +snc_nec16_copyfrombuf(sc, dst, offset, size) + struct snc_softc *sc; + void *dst; + u_int32_t offset; + size_t size; +{ + bus_space_tag_t memt = sc->sc_memt; + bus_space_handle_t memh = sc->sc_memh; + u_int16_t noffset; + u_int8_t* bptr = dst; + + noffset = snc_nec16_select_bank(sc, offset, 0); + + /* XXX: should check if offset + size < 0x2000. */ + + bus_space_barrier(memt, memh, noffset, size, + BUS_SPACE_BARRIER_READ); + + if (size > 3) { + if (noffset & 3) { + size_t asize = (~noffset & 3); + + bus_space_read_region_1(memt, memh, noffset, + bptr, asize); + bptr += asize; + noffset += asize; + size -= asize; + } + bus_space_read_region_4(memt, memh, noffset, + (u_int32_t *) bptr, size >> 2); + bptr += size & ~3; + noffset += size & ~3; + size &= 3; + } + if (size) + bus_space_read_region_1(memt, memh, noffset, bptr, size); +} + +/* + * write to SONIC data buffer. + */ +void +snc_nec16_copytobuf(sc, src, offset, size) + struct snc_softc *sc; + void *src; + u_int32_t offset; + size_t size; +{ + bus_space_tag_t memt = sc->sc_memt; + bus_space_handle_t memh = sc->sc_memh; + u_int16_t noffset, onoffset; + size_t osize = size; + u_int8_t* bptr = src; + + noffset = snc_nec16_select_bank(sc, offset, 0); + onoffset = noffset; + + /* XXX: should check if offset + size < 0x2000. */ + + if (size > 3) { + if (noffset & 3) { + size_t asize = (~noffset & 3); + + bus_space_write_region_1(memt, memh, noffset, + bptr, asize); + bptr += asize; + noffset += asize; + size -= asize; + } + bus_space_write_region_4(memt, memh, noffset, + (u_int32_t *)bptr, size >> 2); + bptr += size & ~3; + noffset += size & ~3; + size -= size & ~3; + } + if (size) + bus_space_write_region_1(memt, memh, noffset, bptr, size); + + bus_space_barrier(memt, memh, onoffset, osize, + BUS_SPACE_BARRIER_WRITE); +} + +/* + * write (fill) 0 to SONIC data buffer. + */ +void +snc_nec16_zerobuf(sc, offset, size) + struct snc_softc *sc; + u_int32_t offset; + size_t size; +{ + bus_space_tag_t memt = sc->sc_memt; + bus_space_handle_t memh = sc->sc_memh; + u_int16_t noffset, onoffset; + size_t osize = size; + + noffset = snc_nec16_select_bank(sc, offset, 0); + onoffset = noffset; + + /* XXX: should check if offset + size < 0x2000. */ + + if (size > 3) { + if (noffset & 3) { + size_t asize = (~noffset & 3); + + bus_space_set_region_1(memt, memh, noffset, 0, asize); + noffset += asize; + size -= asize; + } + bus_space_set_region_4(memt, memh, noffset, 0, size >> 2); + noffset += size & ~3; + size -= size & ~3; + } + if (size) + bus_space_set_region_1(memt, memh, noffset, 0, size); + + bus_space_barrier(memt, memh, onoffset, osize, + BUS_SPACE_BARRIER_WRITE); +} + + +/* + * Routines to read bytes sequentially from EEPROM through NEC PC-9801-83, + * 84, 103, 104, PC-9801N-25 and PC-9801N-J02, J02R for NetBSD/pc98. + * Ported by Kouichi Matsuda. + * + * This algorism is generic to read data sequentially from 4-Wire + * Microwire Serial EEPROM. + */ + +#define SNEC_EEP_DELAY 1000 + +void +snc_nec16_read_eeprom(iot, ioh, data) + bus_space_tag_t iot; + bus_space_handle_t ioh; + u_int8_t *data; +{ + u_int8_t n, val, bit; + + /* Read bytes from EEPROM; two bytes per an iteration. */ + for (n = 0; n < SNEC_EEPROM_SIZE / 2; n++) { + /* select SNECR_EEP */ + bus_space_write_1(iot, ioh, SNEC_ADDR, SNECR_EEP); + + bus_space_write_1(iot, ioh, SNEC_CTRLB, 0x00); + delay(SNEC_EEP_DELAY); + + /* Start EEPROM access. */ + bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS); + delay(SNEC_EEP_DELAY); + + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_EEP_CS | SNECR_EEP_SK); + delay(SNEC_EEP_DELAY); + + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_EEP_CS | SNECR_EEP_DI); + delay(SNEC_EEP_DELAY); + + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_EEP_CS | SNECR_EEP_SK | SNECR_EEP_DI); + delay(SNEC_EEP_DELAY); + + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_EEP_CS | SNECR_EEP_DI); + delay(SNEC_EEP_DELAY); + + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_EEP_CS | SNECR_EEP_SK | SNECR_EEP_DI); + delay(SNEC_EEP_DELAY); + + bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS); + delay(SNEC_EEP_DELAY); + + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_EEP_CS | SNECR_EEP_SK); + delay(SNEC_EEP_DELAY); + + /* Pass the iteration count to the chip. */ + for (bit = 0x20; bit != 0x00; bit >>= 1) { + bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS | + ((n & bit) ? SNECR_EEP_DI : 0x00)); + delay(SNEC_EEP_DELAY); + + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_EEP_CS | SNECR_EEP_SK | + ((n & bit) ? SNECR_EEP_DI : 0x00)); + delay(SNEC_EEP_DELAY); + } + + bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS); + (void) bus_space_read_1(iot, ioh, SNEC_CTRLB); /* ACK */ + delay(SNEC_EEP_DELAY); + + /* Read a byte. */ + val = 0; + for (bit = 0x80; bit != 0x00; bit >>= 1) { + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_EEP_CS | SNECR_EEP_SK); + delay(SNEC_EEP_DELAY); + + bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS); + + if (bus_space_read_1(iot, ioh, SNEC_CTRLB) & SNECR_EEP_DO) + val |= bit; + } + *data++ = val; + + /* Read one more byte. */ + val = 0; + for (bit = 0x80; bit != 0x00; bit >>= 1) { + bus_space_write_1(iot, ioh, SNEC_CTRLB, + SNECR_EEP_CS | SNECR_EEP_SK); + delay(SNEC_EEP_DELAY); + + bus_space_write_1(iot, ioh, SNEC_CTRLB, SNECR_EEP_CS); + + if (bus_space_read_1(iot, ioh, SNEC_CTRLB) & SNECR_EEP_DO) + val |= bit; + } + *data++ = val; + + bus_space_write_1(iot, ioh, SNEC_CTRLB, 0x00); + delay(SNEC_EEP_DELAY); + } + +#ifdef SNCDEBUG + /* Report what we got. */ + data -= SNEC_EEPROM_SIZE; + log(LOG_INFO, "%s: EEPROM:" + " %02x%02x%02x%02x %02x%02x%02x%02x -" + " %02x%02x%02x%02x %02x%02x%02x%02x -" + " %02x%02x%02x%02x %02x%02x%02x%02x -" + " %02x%02x%02x%02x %02x%02x%02x%02x\n", + "snc_nec16_read_eeprom", + data[ 0], data[ 1], data[ 2], data[ 3], + data[ 4], data[ 5], data[ 6], data[ 7], + data[ 8], data[ 9], data[10], data[11], + data[12], data[13], data[14], data[15], + data[16], data[17], data[18], data[19], + data[20], data[21], data[22], data[23], + data[24], data[25], data[26], data[27], + data[28], data[29], data[30], data[31]); +#endif +} + +#ifdef SNCDEBUG +void +snc_nec16_dump_reg(iot, ioh) + bus_space_tag_t iot; + bus_space_handle_t ioh; +{ + u_int8_t n; + u_int16_t val; + + printf("SONIC registers (word):"); + for (n = 0; n < SNC_NREGS; n++) { + /* select required SONIC register */ + bus_space_write_1(iot, ioh, SNEC_ADDR, n); + delay(10); + val = bus_space_read_2(iot, ioh, SNEC_CTRL); + if ((n % 0x10) == 0) + printf("\n%04x ", val); + else + printf("%04x ", val); + } + printf("\n"); + + printf("NEC/SONIC registers (byte):\n"); + for (n = SNECR_MEMBS; n <= SNECR_IDENT; n += 2) { + /* select required SONIC register */ + bus_space_write_1(iot, ioh, SNEC_ADDR, n); + delay(10); + val = (u_int16_t) bus_space_read_1(iot, ioh, SNEC_CTRLB); + printf("%04x ", val); + } + printf("\n"); +} + +#endif /* SNCDEBUG */ diff --git a/sys/dev/snc/dp83932subr.h b/sys/dev/snc/dp83932subr.h new file mode 100644 index 0000000..7bcf501 --- /dev/null +++ b/sys/dev/snc/dp83932subr.h @@ -0,0 +1,78 @@ +/* $FreeBSD$ */ +/* $NecBSD: dp83932subr.h,v 1.5 1999/02/02 00:47:25 kmatsuda Exp $ */ +/* $NetBSD$ */ + +/* + * Copyright (c) 1997, 1998, 1999 + * Kouichi Matsuda. 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 Kouichi Matsuda for + * NetBSD/pc98. + * 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. + */ +/* + * Routines of NEC PC-9801-83, 84, 103, 104, PC-9801N-25 and PC-9801N-J02, J02R + * Ethernet interface for NetBSD/pc98, ported by Kouichi Matsuda. + * + * These cards use National Semiconductor DP83934AVQB as Ethernet Controller + * and National Semiconductor NS46C46 as (64 * 16 bits) Microwire Serial EEPROM. + */ + +int sncsetup __P((struct snc_softc *, u_int8_t *)); + +u_int8_t snc_nec16_validate_irq __P((int)); +int snc_nec16_register_irq __P((struct snc_softc *, int)); +int snc_nec16_validate_mem __P((int)); +int snc_nec16_register_mem __P((struct snc_softc *, int)); + +u_int16_t snc_nec16_nic_get __P((struct snc_softc *, u_int8_t)); +void snc_nec16_nic_put __P((struct snc_softc *, u_int8_t, u_int16_t)); + + +void snc_nec16_writetodesc + __P((struct snc_softc *, u_int32_t, u_int32_t, u_int16_t)); +u_int16_t snc_nec16_readfromdesc + __P((struct snc_softc *, u_int32_t, u_int32_t)); + +void snc_nec16_copyfrombuf __P((struct snc_softc *, void *, u_int32_t, size_t)); +void snc_nec16_copytobuf __P((struct snc_softc *, void *, u_int32_t, size_t)); +void snc_nec16_zerobuf __P((struct snc_softc *, u_int32_t, size_t)); + +int snc_nec16_detectsubr + __P((bus_space_tag_t, bus_space_handle_t, bus_space_tag_t, + bus_space_handle_t, int, int, u_int8_t)); +int snc_nec16_check_memory + __P((bus_space_tag_t, bus_space_handle_t, bus_space_tag_t, + bus_space_handle_t)); + +int snc_nec16_get_enaddr + __P((bus_space_tag_t, bus_space_handle_t, u_int8_t *)); +u_int8_t *snc_nec16_detect_type __P((u_int8_t *)); +void snc_nec16_read_eeprom + __P((bus_space_tag_t, bus_space_handle_t, u_int8_t *)); + +#ifdef SNCDEBUG +void snc_nec16_dump_reg __P((bus_space_tag_t, bus_space_handle_t)); +#endif /* SNDEBUG */ diff --git a/sys/dev/snc/dp83932var.h b/sys/dev/snc/dp83932var.h new file mode 100644 index 0000000..adcf9c8 --- /dev/null +++ b/sys/dev/snc/dp83932var.h @@ -0,0 +1,307 @@ +/* $FreeBSD$ */ +/* $NecBSD: dp83932var.h,v 1.3 1999/01/24 01:39:51 kmatsuda Exp $ */ +/* $NetBSD: if_snvar.h,v 1.12 1998/05/01 03:42:47 scottr Exp $ */ + +/* + * [NetBSD for NEC PC-98 series] + * Copyright (c) 1997, 1998, 1999 + * Kouichi Matsuda. All rights reserved. + */ +/* + * Copyright (c) 1991 Algorithmics Ltd (http://www.algor.co.uk) + * You may use, copy, and modify this program so long as you retain the + * copyright line. + */ + +/* + * if_snvar.h -- National Semiconductor DP8393X (SONIC) NetBSD/mac68k vars + */ +/* + * Modified for NetBSD/pc98 1.2.1 from NetBSD/mac68k 1.2D by Kouichi Matsuda. + * Make adapted for NEC PC-9801-83, 84, PC-9801-103, 104, PC-9801N-25 and + * PC-9801N-J02, J02R, which uses National Semiconductor DP83934AVQB as + * Ethernet Controller and National Semiconductor NS46C46 as + * (64 * 16 bits) Microwire Serial EEPROM. + */ + +/* borrow from arch/mac68k/dev/if_mcvar.h for debug. */ +#ifdef DDB +#define integrate +#define hide +#else +#define integrate static __inline +#define hide static +#endif + +/* NetBSD Emulation */ +#ifdef __FreeBSD__ +#ifndef NBPG +#define NBPG PAGE_SIZE +#endif +#ifndef PGOFSET +#define PGOFSET PAGE_MASK +#endif +typedef unsigned long ulong; +#define delay(x) DELAY(x) +#endif + +/* + * Vendor types + */ + +/* + * SONIC buffers need to be aligned 16 or 32 bit aligned. + * These macros calculate and verify alignment. + */ +#define ROUNDUP(p, N) (((int) p + N - 1) & ~(N - 1)) + +#define SOALIGN(m, array) (m ? (ROUNDUP(array, 4)) : (ROUNDUP(array, 2))) + +#define LOWER(x) ((unsigned)(x) & 0xffff) +#define UPPER(x) ((unsigned)(x) >> 16) + +/* + * Memory access macros. Since we handle SONIC in 16 bit mode (PB5X0) + * and 32 bit mode (everything else) using a single GENERIC kernel + * binary, all structures have to be accessed using macros which can + * adjust the offsets appropriately. + */ +/* m is not sc->bitmode, we treat m as sc. */ +#define SWO(m, a, o, x) (*(m)->sc_writetodesc)((m), (a), (o), (x)) +#define SRO(m, a, o) (*(m)->sc_readfromdesc)((m), (a), (o)) + +/* + * Register access macros. We use bus_space_* to talk to the Sonic + * registers. A mapping table is used in case a particular configuration + * hooked the regs up at non-word offsets. + */ +#define NIC_GET(sc, reg) (*(sc)->sc_nic_get)(sc, reg) +#define NIC_PUT(sc, reg, val) (*(sc)->sc_nic_put)(sc, reg, val) + +#define SONIC_GETDMA(p) (p) + +/* pc98 does not have any write buffers to flush... */ +#define wbflush() + +/* + * buffer sizes in 32 bit mode + * 1 TXpkt is 4 hdr words + (3 * FRAGMAX) + 1 link word == 23 words == 92 bytes + * + * 1 RxPkt is 7 words == 28 bytes + * 1 Rda is 4 words == 16 bytes + * + * The CDA is 17 words == 68 bytes + * + * total space in page 0 = NTDA * 92 + NRRA * 16 + NRDA * 28 + 68 + */ + +#define NRBA 16 /* # receive buffers < NRRA */ +#define RBAMASK (NRBA-1) +#define NTDA 16 /* # transmit descriptors */ +#define NRRA 64 /* # receive resource descriptors */ +#define RRAMASK (NRRA-1) /* the reason why NRRA must be power of two */ + +#define FCSSIZE 4 /* size of FCS appended to packets */ + +/* + * maximum receive packet size plus 2 byte pad to make each + * one aligned. 4 byte slop (required for eobc) + */ +#define RBASIZE(sc) (sizeof(struct ether_header) + ETHERMTU + FCSSIZE + \ + ((sc)->bitmode ? 6 : 2)) + +/* + * transmit buffer area + */ +#define TXBSIZE 1536 /* 6*2^8 -- the same size as the 8390 TXBUF */ + +#define SN_NPAGES 2 + NRBA + (NTDA/2) + +typedef struct mtd { + u_int32_t mtd_vtxp; + u_int32_t mtd_vbuf; + struct mbuf *mtd_mbuf; +} mtd_t; + +/* + * The snc_softc for PC-98 if_snc. + */ +typedef struct snc_softc { + struct arpcom sc_ethercom; +#define sc_if sc_ethercom.ac_if /* network visible interface */ + + device_t sc_dev; + + struct resource * ioport; + int ioport_rid; + struct resource * iomem; + int iomem_rid; + struct resource * irq; + int irq_rid; + void * irq_handle; + + bus_space_tag_t sc_iot; /* bus identifier for io */ + bus_space_tag_t sc_memt; /* bus identifier for mem */ + bus_space_handle_t sc_ioh; /* io handle */ + bus_space_handle_t sc_memh; /* bus memory handle */ + + int bitmode; /* 32 bit mode == 1, 16 == 0 */ + + u_int16_t sncr_dcr; /* DCR for this instance */ + u_int16_t sncr_dcr2; /* DCR2 for this instance */ + + int sc_rramark; /* index into v_rra of wp */ + u_int32_t v_rra[NRRA]; /* DMA addresses of v_rra */ + u_int32_t v_rea; /* ptr to the end of the rra space */ + + int sc_rxmark; /* current hw pos in rda ring */ + int sc_rdamark; /* current sw pos in rda ring */ + int sc_nrda; /* total number of RDAs */ + u_int32_t v_rda; + + u_int32_t rbuf[NRBA]; + + struct mtd mtda[NTDA]; + int mtd_hw; /* idx of first mtd given to hw */ + int mtd_prev; /* idx of last mtd given to hardware */ + int mtd_free; /* next free mtd to use */ + int mtd_tlinko; /* + * offset of tlink of last txp given + * to SONIC. Need to clear EOL on + * this word to add a desc. + */ + int mtd_pint; /* Counter to set TXP_PINT */ + + u_int32_t v_cda; + + u_int8_t curbank; /* current window bank */ + + struct ifmedia sc_media; /* supported media information */ + + /* + * NIC register access functions: + */ + u_int16_t (*sc_nic_get) + __P((struct snc_softc *, u_int8_t)); + void (*sc_nic_put) + __P((struct snc_softc *, u_int8_t, u_int16_t)); + + /* + * Memory functions: + * + * copy to/from descriptor + * copy to/from buffer + * zero bytes in buffer + */ + void (*sc_writetodesc) + __P((struct snc_softc *, u_int32_t, u_int32_t, u_int16_t)); + u_int16_t (*sc_readfromdesc) + __P((struct snc_softc *, u_int32_t, u_int32_t)); + void (*sc_copytobuf) + __P((struct snc_softc *, void *, u_int32_t, size_t)); + void (*sc_copyfrombuf) + __P((struct snc_softc *, void *, u_int32_t, size_t)); + void (*sc_zerobuf) + __P((struct snc_softc *, u_int32_t, size_t)); + + /* + * Machine-dependent functions: + * + * hardware reset hook - may be NULL + * hardware init hook - may be NULL + * media change hook - may be NULL + */ + void (*sc_hwreset) __P((struct snc_softc *)); + void (*sc_hwinit) __P((struct snc_softc *)); + int (*sc_mediachange) __P((struct snc_softc *)); + void (*sc_mediastatus) __P((struct snc_softc *, + struct ifmediareq *)); + + int sc_enabled; /* boolean; power enabled on interface */ + + int (*sc_enable) __P((struct snc_softc *)); + void (*sc_disable) __P((struct snc_softc *)); + + void *sc_sh; /* shutdownhook cookie */ + int gone; + +#if NRND > 0 + rndsource_element_t rnd_source; +#endif +} snc_softc_t; + +/* + * Accessing SONIC data structures and registers as 32 bit values + * makes code endianess independent. The SONIC is however always in + * bigendian mode so it is necessary to ensure that data structures shared + * between the CPU and the SONIC are always in bigendian order. + */ + +/* + * Receive Resource Descriptor + * This structure describes the buffers into which packets + * will be received. Note that more than one packet may be + * packed into a single buffer if constraints permit. + */ +#define RXRSRC_PTRLO 0 /* buffer address LO */ +#define RXRSRC_PTRHI 1 /* buffer address HI */ +#define RXRSRC_WCLO 2 /* buffer size (16bit words) LO */ +#define RXRSRC_WCHI 3 /* buffer size (16bit words) HI */ + +#define RXRSRC_SIZE(sc) (sc->bitmode ? (4 * 4) : (4 * 2)) + +/* + * Receive Descriptor + * This structure holds information about packets received. + */ +#define RXPKT_STATUS 0 +#define RXPKT_BYTEC 1 +#define RXPKT_PTRLO 2 +#define RXPKT_PTRHI 3 +#define RXPKT_SEQNO 4 +#define RXPKT_RLINK 5 +#define RXPKT_INUSE 6 +#define RXPKT_SIZE(sc) (sc->bitmode ? (7 * 4) : (7 * 2)) + +#define RBASEQ(x) (((x)>>8)&0xff) +#define PSNSEQ(x) ((x) & 0xff) + +/* + * Transmit Descriptor + * This structure holds information about packets to be transmitted. + */ +#define FRAGMAX 8 /* maximum number of fragments in a packet */ + +#define TXP_STATUS 0 /* + transmitted packet status */ +#define TXP_CONFIG 1 /* transmission configuration */ +#define TXP_PKTSIZE 2 /* entire packet size in bytes */ +#define TXP_FRAGCNT 3 /* # fragments in packet */ + +#define TXP_FRAGOFF 4 /* offset to first fragment */ +#define TXP_FRAGSIZE 3 /* size of each fragment desc */ +#define TXP_FPTRLO 0 /* ptr to packet fragment LO */ +#define TXP_FPTRHI 1 /* ptr to packet fragment HI */ +#define TXP_FSIZE 2 /* fragment size */ + +#define TXP_WORDS (TXP_FRAGOFF + (FRAGMAX*TXP_FRAGSIZE) + 1) /* 1 for tlink */ +#define TXP_SIZE(sc) ((sc->bitmode) ? (TXP_WORDS*4) : (TXP_WORDS*2)) + +#define EOL 0x0001 /* end of list marker for link fields */ + +/* + * CDA, the CAM descriptor area. The SONIC has a 16 entry CAM to + * match incoming addresses against. It is programmed via DMA + * from a memory region. + */ +#define MAXCAM 16 /* number of user entries in CAM */ +#define CDA_CAMDESC 4 /* # words i na descriptor */ +#define CDA_CAMEP 0 /* CAM Address Port 0 xx-xx-xx-xx-YY-YY */ +#define CDA_CAMAP0 1 /* CAM Address Port 1 xx-xx-YY-YY-xx-xx */ +#define CDA_CAMAP1 2 /* CAM Address Port 2 YY-YY-xx-xx-xx-xx */ +#define CDA_CAMAP2 3 +#define CDA_ENABLE 64 /* mask enabling CAM entries */ +#define CDA_SIZE(sc) ((4*16 + 1) * ((sc->bitmode) ? 4 : 2)) + +void sncconfig __P((struct snc_softc *, int *, int, int, u_int8_t *)); +void sncintr __P((void *)); +void sncshutdown __P((void *)); diff --git a/sys/dev/snc/if_snc.c b/sys/dev/snc/if_snc.c new file mode 100644 index 0000000..5a30e3d --- /dev/null +++ b/sys/dev/snc/if_snc.c @@ -0,0 +1,258 @@ +/* + * Copyright (c) 1995, David Greenman + * 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 unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * National Semiconductor DP8393X SONIC Driver + * + * This is the bus independent attachment on FreeBSD 4.x + * written by Motomichi Matsuzaki <mzaki@e-mail.ne.jp> + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sockio.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/syslog.h> + +#include <sys/module.h> +#include <sys/bus.h> +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_media.h> +#include <net/if_dl.h> +#include <net/if_mib.h> + +#include <net/bpf.h> +#include "opt_bdg.h" +#ifdef BRIDGE +#include <net/bridge.h> +#endif + +#include <dev/snc/dp83932reg.h> +#include <dev/snc/dp83932var.h> +#include <dev/snc/dp83932subr.h> +#include <dev/snc/if_sncreg.h> +#include <dev/snc/if_sncvar.h> + +/* devclass for "snc" */ +devclass_t snc_devclass; + +/**************************************************************** + Resource management functions + ****************************************************************/ + +/* + * Allocate a port resource with the given resource id. + */ +int +snc_alloc_port(dev, rid) + device_t dev; + int rid; +{ + struct snc_softc *sc = device_get_softc(dev); + struct resource *res; + + res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, + 0ul, ~0ul, SNEC_NREGS, RF_ACTIVE); + if (res) { + sc->ioport = res; + sc->ioport_rid = rid; + sc->sc_iot = rman_get_bustag(res); + sc->sc_ioh = rman_get_bushandle(res); + return (0); + } else { + u_long start, count; + + bus_get_resource(dev, SYS_RES_IOPORT, rid, &start, &count); + printf("snc_alloc_port: can't assign port 0x%lx-0x%lx\n", + start, start + count - 1); + return (ENOENT); + } +} + +/* + * Allocate a memory resource with the given resource id. + */ +int +snc_alloc_memory(dev, rid) + device_t dev; + int rid; +{ + struct snc_softc *sc = device_get_softc(dev); + struct resource *res; + + res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, + 0ul, ~0ul, SNEC_NMEMS, RF_ACTIVE); + if (res) { + sc->iomem = res; + sc->iomem_rid = rid; + sc->sc_memt = rman_get_bustag(res); + sc->sc_memh = rman_get_bushandle(res); + return (0); + } else { + u_long start, count; + + bus_get_resource(dev, SYS_RES_MEMORY, rid, &start, &count); + printf("snc_alloc_memory: can't assign memory 0x%lx-0x%lx\n", + start, start + count - 1); + return (ENOENT); + } +} + +/* + * Allocate an irq resource with the given resource id. + */ +int +snc_alloc_irq(dev, rid, flags) + device_t dev; + int rid; + int flags; +{ + struct snc_softc *sc = device_get_softc(dev); + struct resource *res; + + res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, + 0ul, ~0ul, 1, (RF_ACTIVE | flags)); + if (res) { + sc->irq = res; + sc->irq_rid = rid; + return (0); + } else { + printf("snc_alloc_irq: can't assign irq %ld\n", + bus_get_resource_start(dev, SYS_RES_IRQ, rid)); + return (ENOENT); + } +} + +/* + * Release all resources + */ +void +snc_release_resources(dev) + device_t dev; +{ + struct snc_softc *sc = device_get_softc(dev); + + if (sc->ioport) { + bus_release_resource(dev, SYS_RES_IOPORT, + sc->ioport_rid, sc->ioport); + sc->ioport = 0; + } + if (sc->iomem) { + bus_release_resource(dev, SYS_RES_MEMORY, + sc->iomem_rid, sc->iomem); + sc->iomem = 0; + } + if (sc->irq) { + bus_release_resource(dev, SYS_RES_IRQ, + sc->irq_rid, sc->irq); + sc->irq = 0; + } +} + +/**************************************************************** + Probe routine + ****************************************************************/ + +int +snc_probe(dev, type) + device_t dev; + int type; +{ + struct snc_softc *sc = device_get_softc(dev); + + return snc_nec16_detectsubr(sc->sc_iot, sc->sc_ioh, + sc->sc_memt, sc->sc_memh, + rman_get_start(sc->irq), + rman_get_start(sc->iomem), + type); +} + +/**************************************************************** + Attach routine + ****************************************************************/ + +int +snc_attach(dev) + device_t dev; +{ + struct snc_softc *sc = device_get_softc(dev); + u_int8_t myea[ETHER_ADDR_LEN]; + + if (snc_nec16_register_irq(sc, rman_get_start(sc->irq)) == 0 || + snc_nec16_register_mem(sc, rman_get_start(sc->iomem)) == 0) { + snc_release_resources(dev); + return(ENOENT); + } + + snc_nec16_get_enaddr(sc->sc_iot, sc->sc_ioh, myea); + device_printf(dev, "%s Ethernet\n", snc_nec16_detect_type(myea)); + + sc->sc_dev = dev; + + sc->sncr_dcr = DCR_SYNC | DCR_WAIT0 | + DCR_DMABLOCK | DCR_RFT16 | DCR_TFT28; + sc->sncr_dcr2 = 0; /* XXX */ + sc->bitmode = 0; /* 16 bit card */ + + sc->sc_nic_put = snc_nec16_nic_put; + sc->sc_nic_get = snc_nec16_nic_get; + sc->sc_writetodesc = snc_nec16_writetodesc; + sc->sc_readfromdesc = snc_nec16_readfromdesc; + sc->sc_copytobuf = snc_nec16_copytobuf; + sc->sc_copyfrombuf = snc_nec16_copyfrombuf; + sc->sc_zerobuf = snc_nec16_zerobuf; + + /* sncsetup returns 1 if something fails */ + if (sncsetup(sc, myea)) { + snc_release_resources(dev); + return(ENOENT); + } + + sncconfig(sc, NULL, 0, 0, myea); + + return 0; +} + +/**************************************************************** + Shutdown routine + ****************************************************************/ + +void +snc_shutdown(dev) + device_t dev; +{ + sncshutdown(device_get_softc(dev)); +} diff --git a/sys/dev/snc/if_snc_cbus.c b/sys/dev/snc/if_snc_cbus.c new file mode 100644 index 0000000..6575269 --- /dev/null +++ b/sys/dev/snc/if_snc_cbus.c @@ -0,0 +1,224 @@ +/* + * Copyright (c) 1995, David Greenman + * 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 unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * National Semiconductor DP8393X SONIC Driver + * + * This is the C-bus specific attachment on FreeBSD + * written by Motomichi Matsuzaki <mzaki@e-mail.ne.jp> + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/socket.h> +#include <sys/kernel.h> + +#include <sys/module.h> +#include <sys/bus.h> +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_media.h> +#include <net/if_mib.h> + +#include <isa/isavar.h> +#include <isa/pnpvar.h> +#include <sys/malloc.h> /* as dependency for isa/isa_common.h */ +#include <isa/isa_common.h> /* for snc_isapnp_reconfig() */ + +#include <dev/snc/dp83932var.h> +#include <dev/snc/dp83932subr.h> +#include <dev/snc/if_sncreg.h> +#include <dev/snc/if_sncvar.h> + +static void snc_isapnp_reconfig __P((device_t)); +static int snc_isa_probe __P((device_t)); +static int snc_isa_attach __P((device_t)); + +static struct isa_pnp_id snc_ids[] = { + { 0x6180a3b8, NULL }, /* NEC8061 NEC PC-9801-104 */ + { 0, NULL } +}; + +static void +snc_isapnp_reconfig(dev) + device_t dev; +{ + struct isa_device *idev = DEVTOISA(dev); + struct isa_config config; + u_long start, count; + int rid; + + bzero(&config, sizeof(config)); + + for (rid = 0; rid < ISA_NMEM; rid++) { + if (bus_get_resource(dev, SYS_RES_MEMORY, rid, &start, &count)) + break; + config.ic_mem[rid].ir_start = start; + config.ic_mem[rid].ir_end = start; + config.ic_mem[rid].ir_size = count; + } + config.ic_nmem = rid; + for (rid = 0; rid < ISA_NPORT; rid++) { + if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &start, &count)) + break; + config.ic_port[rid].ir_start = start; + config.ic_port[rid].ir_end = start; + config.ic_port[rid].ir_size = count; + } + config.ic_nport = rid; + for (rid = 0; rid < ISA_NIRQ; rid++) { + if (bus_get_resource(dev, SYS_RES_IRQ, rid, &start, &count)) + break; + config.ic_irqmask[rid] = 1 << start; + } + config.ic_nirq = rid; + for (rid = 0; rid < ISA_NDRQ; rid++) { + if (bus_get_resource(dev, SYS_RES_DRQ, rid, &start, &count)) + break; + config.ic_drqmask[rid] = 1 << start; + } + config.ic_ndrq = rid; + + idev->id_config_cb(idev->id_config_arg, &config, 1); +} + +static int +snc_isa_probe(dev) + device_t dev; +{ + struct snc_softc *sc = device_get_softc(dev); + int type; + int error = 0; + + bzero(sc, sizeof(struct snc_softc)); + + /* Check isapnp ids */ + error = ISA_PNP_PROBE(device_get_parent(dev), dev, snc_ids); + + /* If the card had a PnP ID that didn't match any we know about */ + if (error == ENXIO) { + return(error); + } + + switch (error) { + case 0: /* Matched PnP */ + type = SNEC_TYPE_PNP; + break; + + case ENOENT: /* Legacy ISA */ + type = SNEC_TYPE_LEGACY; + break; + + default: /* If we had some other problem. */ + return(error); + } + + if (type == SNEC_TYPE_PNP && isa_get_portsize(dev) == 0) { + int port; + int rid = 0; + struct resource *res = NULL; + + for (port = 0x0888; port <= 0x3888; port += 0x1000) { + bus_set_resource(dev, SYS_RES_IOPORT, rid, + port, SNEC_NREGS); + res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, + 0, ~0, SNEC_NREGS, + 0 /* !RF_ACTIVE */); + if (res) break; + } + + printf("snc_isa_probe: broken PnP resource, "); + if (res) { + printf("use port 0x%x\n", port); + bus_release_resource(dev, SYS_RES_IOPORT, rid, res); + snc_isapnp_reconfig(dev); + } else { + printf("and can't find port\n"); + } + } + + error = snc_alloc_port(dev, 0); + error = max(error, snc_alloc_memory(dev, 0)); + error = max(error, snc_alloc_irq(dev, 0, 0)); + + if (!error && !snc_probe(dev, type)) + error = ENOENT; + + snc_release_resources(dev); + return (error); +} + +static int +snc_isa_attach(dev) + device_t dev; +{ + struct snc_softc *sc = device_get_softc(dev); + int error; + + bzero(sc, sizeof(struct snc_softc)); + + snc_alloc_port(dev, 0); + snc_alloc_memory(dev, 0); + snc_alloc_irq(dev, 0, 0); + + error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET, + sncintr, sc, &sc->irq_handle); + if (error) { + printf("snc_isa_attach: bus_setup_intr() failed\n"); + snc_release_resources(dev); + return (error); + } + + /* This interface is always enabled. */ + sc->sc_enabled = 1; + + return snc_attach(dev); +} + +static device_method_t snc_isa_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, snc_isa_probe), + DEVMETHOD(device_attach, snc_isa_attach), + DEVMETHOD(device_shutdown, snc_shutdown), + + { 0, 0 } +}; + +static driver_t snc_isa_driver = { + "snc", + snc_isa_methods, + sizeof(struct snc_softc) +}; + +DRIVER_MODULE(if_snc, isa, snc_isa_driver, snc_devclass, 0, 0); diff --git a/sys/dev/snc/if_snc_pccard.c b/sys/dev/snc/if_snc_pccard.c new file mode 100644 index 0000000..4a396d4 --- /dev/null +++ b/sys/dev/snc/if_snc_pccard.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 1995, David Greenman + * 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 unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * National Semiconductor DP8393X SONIC Driver + * + * This is the PC-Card attachment on FreeBSD + * written by Motomichi Matsuzaki <mzaki@e-mail.ne.jp> and + * Hiroshi Yamashita <bluemoon@msj.biglobe.ne.jp> + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/socket.h> +#include <sys/kernel.h> + +#include <sys/module.h> +#include <sys/bus.h> +#include <machine/bus.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_media.h> +#include <net/if_mib.h> + +#include <dev/pccard/pccardvar.h> + +#include <dev/snc/dp83932var.h> +#include <dev/snc/dp83932reg.h> +#include <dev/snc/if_sncvar.h> +#include <dev/snc/if_sncreg.h> + +/* + * PC-Card (PCMCIA) specific code. + */ +static int snc_pccard_probe(device_t); +static int snc_pccard_attach(device_t); +static int snc_pccard_detach(device_t); + + +static device_method_t snc_pccard_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, snc_pccard_probe), + DEVMETHOD(device_attach, snc_pccard_attach), + DEVMETHOD(device_detach, snc_pccard_detach), + + { 0, 0 } +}; + +static driver_t snc_pccard_driver = { + "snc", + snc_pccard_methods, + sizeof(struct snc_softc) +}; + +DRIVER_MODULE(if_snc, pccard, snc_pccard_driver, snc_devclass, 0, 0); + +/* + * snc_pccard_detach - unload the driver and clear the table. + * XXX TODO: + * This is usually called when the card is ejected, but + * can be caused by a modunload of a controller driver. + * The idea is to reset the driver's view of the device + * and ensure that any driver entry points such as + * read and write do not hang. + */ +static int +snc_pccard_detach(device_t dev) +{ + struct snc_softc *sc = device_get_softc(dev); + struct ifnet *ifp = &sc->sc_if; + + if (sc->gone) { + device_printf(dev, "already unloaded\n"); + return (0); + } + sncshutdown(sc); + ifp->if_flags &= ~IFF_RUNNING; + if_detach(ifp); + sc->gone = 1; + bus_teardown_intr(dev, sc->irq, sc->irq_handle); + snc_release_resources(dev); + return (0); +} + +/* + * Probe framework for pccards. Replicates the standard framework, + * minus the pccard driver registration and ignores the ether address + * supplied (from the CIS), relying on the probe to find it instead. + */ +static int +snc_pccard_probe(device_t dev) +{ + int error; + + error = snc_alloc_port(dev, 0); + error = max(error, snc_alloc_memory(dev, 0)); + error = max(error, snc_alloc_irq(dev, 0, 0)); + + if (!error && !snc_probe(dev, SNEC_TYPE_PNP)) + error = ENOENT; + + snc_release_resources(dev); + return (error); +} + +static int +snc_pccard_attach(device_t dev) +{ + struct snc_softc *sc = device_get_softc(dev); + int error; + + bzero(sc, sizeof(struct snc_softc)); + + snc_alloc_port(dev, 0); + snc_alloc_memory(dev, 0); + snc_alloc_irq(dev, 0, 0); + + error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET, + sncintr, sc, &sc->irq_handle); + if (error) { + printf("snc_isa_attach: bus_setup_intr() failed\n"); + snc_release_resources(dev); + return (error); + } + + /* This interface is always enabled. */ + sc->sc_enabled = 1; + + /* pccard_get_ether(dev, ether_addr); */ + + return snc_attach(dev); +} diff --git a/sys/dev/snc/if_sncreg.h b/sys/dev/snc/if_sncreg.h new file mode 100644 index 0000000..30b0bb7 --- /dev/null +++ b/sys/dev/snc/if_sncreg.h @@ -0,0 +1,140 @@ +/* $FreeBSD$ */ +/* $NecBSD: if_snreg.h,v 1.3 1999/01/24 01:39:52 kmatsuda Exp $ */ +/* $NetBSD$ */ + +/* + * Copyright (c) 1997, 1998, 1999 + * Kouichi Matsuda. 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 Kouichi Matsuda for + * NetBSD/pc98. + * 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. + */ +/* + * Modified for NetBSD/pc98 1.2.1 from NetBSD/mac68k 1.2D by Kouichi Matsuda. + * Make adapted for NEC PC-9801-83, 84, PC-9801-103, 104, PC-9801N-25 and + * PC-9801N-J02R, which uses National Semiconductor DP83934AVQB as + * Ethernet Controller and National Semiconductor NS46C46 as (64 * 16 bits) + * Microwire Serial EEPROM. + */ + +/* + * XXX: Should not be HERE. (Should be shared with...) + */ + +/* + * NEC/SONIC port mappings, offset from iobase. + */ +#define SNEC_CTRL 0 /* SONIC control port (word) */ +#define SNEC_CTRLB 1 /* NEC/SONIC control port (byte) */ +#define SNEC_RSVD0 2 /* not used */ +#define SNEC_ADDR 3 /* SONIC, NEC/SONIC register address set port */ +#define SNEC_RSVD1 4 /* not used */ +#define SNEC_RSVD2 5 /* not used */ + +#define SNEC_NREGS 6 + +/* bank memory size */ +#define SNEC_NMEMS (NBPG * 2) +/* how many bank */ +#define SNEC_NBANK 0x10 +/* internal buffer size */ +#define SNEC_NBUF (SNEC_NMEMS * SNEC_NBANK) + + +/* + * NEC/SONIC specific internal registers. + */ + +/* + * Memory Bank Select Register (MEMBS) + */ +#define SNECR_MEMBS 0x80 +#define SNECR_MEMBS_BSEN 0x01 /* enable memory bank select */ +#define SNECR_MEMBS_EBNMSK 0x1c /* encoded bank select number */ +/* Translate bank number to encoded bank select number. */ +#define SNECR_MEMBS_B2EB(bank) (bank << 2) +#define SNECR_MEMBS_PCMCIABUS 0x80 /* bus type identification */ + +/* + * Memory Base Address Select Register (MEMSEL) + */ +#define SNECR_MEMSEL 0x82 +/* Translate base phys address to encoded select number. */ +#define SNECR_MEMSEL_PHYS2EN(maddr) ((maddr >> 13) & 0x0f) + +/* + * Encoded Irq Select Register (IRQSEL) + */ +#define SNECR_IRQSEL 0x84 + +/* + * EEPROM Access Register (EEP) + */ +#define SNECR_EEP 0x86 +#define SNECR_EEP_DI 0x10 /* EEPROM Serial Data Input (high) */ +#define SNECR_EEP_CS 0x20 /* EEPROM Chip Select (high) */ +#define SNECR_EEP_SK 0x40 /* EEPROM Serial Data Clock (high) */ +#define SNECR_EEP_DO 0x80 /* EEPROM Serial Data Output (high) */ + +/* EEPROM data locations */ +#define SNEC_EEPROM_KEY0 6 /* Station Address Check Sum Key #1 */ +#define SNEC_EEPROM_KEY1 7 /* Station Address Check Sum Key #2 */ +#define SNEC_EEPROM_SA0 8 /* Station Address #1 */ +#define SNEC_EEPROM_SA1 9 /* Station Address #2 */ +#define SNEC_EEPROM_SA2 10 /* Station Address #3 */ +#define SNEC_EEPROM_SA3 11 /* Station Address #4 */ +#define SNEC_EEPROM_SA4 12 /* Station Address #5 */ +#define SNEC_EEPROM_SA5 13 /* Station Address #6 */ +#define SNEC_EEPROM_CKSUM 14 /* Station Address Check Sum */ + +#define SNEC_EEPROM_SIZE 32 /* valid EEPROM data (max 128 bytes) */ + +/* + * Bus and Mode Identification Register (IDENT) + */ +#define SNECR_IDENT 0x88 + /* Bit 0: Bus Identification. */ +#define SNECR_IDENT_CBUS 0x01 /* on PC-98 C-Bus */ +#define SNECR_IDENT_PCMCIABUS 0x00 /* on PCMCIA Bus */ + /* Bit 2: always 1 */ +#define SNECR_IDENT_MAGIC 0x04 + /* Bit 4: Bus Configuration Mode Identification. */ +#define SNECR_IDENT_PNP 0x10 /* Plug and Play (C-Bus and PCMCIA) */ +#define SNECR_IDENT_LEGACY 0x00 /* Legacy C-Bus */ + +#define SNECR_IDENT_LEGACY_CBUS \ + (SNECR_IDENT_LEGACY | SNECR_IDENT_MAGIC | SNECR_IDENT_CBUS) +#define SNECR_IDENT_PNP_CBUS \ + (SNECR_IDENT_PNP | SNECR_IDENT_MAGIC | SNECR_IDENT_CBUS) +#define SNECR_IDENT_PNP_PCMCIABUS \ + (SNECR_IDENT_PNP | SNECR_IDENT_MAGIC | SNECR_IDENT_PCMCIABUS) + +/* + * XXX: parent bus type aliases + */ +#define SNEC_TYPE_LEGACY 0 +#define SNEC_TYPE_PNP 1 + diff --git a/sys/dev/snc/if_sncvar.h b/sys/dev/snc/if_sncvar.h new file mode 100644 index 0000000..98b2d94 --- /dev/null +++ b/sys/dev/snc/if_sncvar.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 1995, David Greenman + * 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 unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * National Semiconductor DP8393X SONIC Driver + * + * This is the machine dependent attachment on FreeBSD 4.x + * written by Motomichi Matsuzaki <mzaki@e-mail.ne.jp> + */ + +extern devclass_t snc_devclass; + +void snc_release_resources __P((device_t)); +int snc_alloc_port __P((device_t, int)); +int snc_alloc_memory __P((device_t, int)); +int snc_alloc_irq __P((device_t, int, int)); + +int snc_probe __P((device_t, int)); +int snc_attach __P((device_t)); + +void snc_shutdown __P((device_t)); |