Home | History | Annotate | Line # | Download | only in dev
if_mc.c revision 1.9
      1  1.9  jonathan /*	$NetBSD: if_mc.c,v 1.9 1998/07/05 03:14:41 jonathan Exp $	*/
      2  1.2    briggs 
      3  1.1    briggs /*-
      4  1.1    briggs  * Copyright (c) 1997 David Huang <khym (at) bga.com>
      5  1.1    briggs  * All rights reserved.
      6  1.1    briggs  *
      7  1.1    briggs  * Portions of this code are based on code by Denton Gentry <denny1 (at) home.com>,
      8  1.1    briggs  * Charles M. Hannum, Yanagisawa Takeshi <yanagisw (at) aa.ap.titech.ac.jp>, and
      9  1.1    briggs  * Jason R. Thorpe.
     10  1.1    briggs  *
     11  1.1    briggs  * Redistribution and use in source and binary forms, with or without
     12  1.1    briggs  * modification, are permitted provided that the following conditions
     13  1.1    briggs  * are met:
     14  1.1    briggs  * 1. Redistributions of source code must retain the above copyright
     15  1.1    briggs  *    notice, this list of conditions and the following disclaimer.
     16  1.1    briggs  * 2. The name of the author may not be used to endorse or promote products
     17  1.1    briggs  *    derived from this software without specific prior written permission
     18  1.1    briggs  *
     19  1.1    briggs  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     20  1.1    briggs  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     21  1.1    briggs  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     22  1.1    briggs  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     23  1.1    briggs  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     24  1.1    briggs  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  1.1    briggs  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  1.1    briggs  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  1.1    briggs  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     28  1.1    briggs  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  1.1    briggs  *
     30  1.1    briggs  */
     31  1.1    briggs 
     32  1.1    briggs /*
     33  1.1    briggs  * Driver for the AMD Am79C940 (MACE) ethernet chip, used for onboard
     34  1.1    briggs  * ethernet on the Centris/Quadra 660av and Quadra 840av.
     35  1.1    briggs  */
     36  1.1    briggs 
     37  1.7  jonathan #include "opt_ddb.h"
     38  1.7  jonathan #include "opt_inet.h"
     39  1.8  jonathan #include "opt_ccitt.h"
     40  1.9  jonathan #include "opt_llc.h"
     41  1.7  jonathan 
     42  1.1    briggs #include <sys/param.h>
     43  1.1    briggs #include <sys/systm.h>
     44  1.1    briggs #include <sys/mbuf.h>
     45  1.1    briggs #include <sys/buf.h>
     46  1.1    briggs #include <sys/protosw.h>
     47  1.1    briggs #include <sys/socket.h>
     48  1.1    briggs #include <sys/syslog.h>
     49  1.1    briggs #include <sys/ioctl.h>
     50  1.1    briggs #include <sys/errno.h>
     51  1.1    briggs #include <sys/device.h>
     52  1.1    briggs 
     53  1.1    briggs #include <net/if.h>
     54  1.1    briggs #include <net/if_dl.h>
     55  1.1    briggs #include <net/if_ether.h>
     56  1.1    briggs 
     57  1.1    briggs #ifdef INET
     58  1.1    briggs #include <netinet/in.h>
     59  1.1    briggs #include <netinet/if_inarp.h>
     60  1.1    briggs #include <netinet/in_systm.h>
     61  1.1    briggs #include <netinet/in_var.h>
     62  1.1    briggs #include <netinet/ip.h>
     63  1.1    briggs #endif
     64  1.1    briggs 
     65  1.1    briggs #ifdef NS
     66  1.1    briggs #include <netns/ns.h>
     67  1.1    briggs #include <netns/ns_if.h>
     68  1.1    briggs #endif
     69  1.1    briggs 
     70  1.1    briggs #if defined(CCITT) && defined(LLC)
     71  1.1    briggs #include <sys/socketvar.h>
     72  1.1    briggs #include <netccitt/x25.h>
     73  1.1    briggs #include <netccitt/pk.h>
     74  1.1    briggs #include <netccitt/pk_var.h>
     75  1.1    briggs #include <netccitt/pk_extern.h>
     76  1.1    briggs #endif
     77  1.1    briggs 
     78  1.1    briggs #include <vm/vm.h>
     79  1.1    briggs 
     80  1.1    briggs #include "bpfilter.h"
     81  1.1    briggs #if NBPFILTER > 0
     82  1.1    briggs #include <net/bpf.h>
     83  1.1    briggs #include <net/bpfdesc.h>
     84  1.1    briggs #endif
     85  1.1    briggs 
     86  1.1    briggs #include <machine/bus.h>
     87  1.1    briggs #include <mac68k/dev/if_mcreg.h>
     88  1.1    briggs #include <mac68k/dev/if_mcvar.h>
     89  1.7  jonathan 
     90  1.7  jonathan #ifdef DDB
     91  1.7  jonathan #define	integrate
     92  1.7  jonathan #define hide
     93  1.7  jonathan #else
     94  1.7  jonathan #define	integrate	static __inline
     95  1.7  jonathan #define hide		static
     96  1.7  jonathan #endif
     97  1.1    briggs 
     98  1.1    briggs hide void	mcwatchdog __P((struct ifnet *));
     99  1.1    briggs hide int	mcinit __P((struct mc_softc *sc));
    100  1.1    briggs hide int	mcstop __P((struct mc_softc *sc));
    101  1.1    briggs hide int	mcioctl __P((struct ifnet *ifp, u_long cmd, caddr_t data));
    102  1.1    briggs hide void	mcstart __P((struct ifnet *ifp));
    103  1.1    briggs hide void	mcreset __P((struct mc_softc *sc));
    104  1.1    briggs 
    105  1.1    briggs integrate u_int	maceput __P((struct mc_softc *sc, struct mbuf *m0));
    106  1.3    scottr integrate void	mc_tint __P((struct mc_softc *sc));
    107  1.1    briggs integrate void	mace_read __P((struct mc_softc *, caddr_t, int));
    108  1.1    briggs integrate struct mbuf *mace_get __P((struct mc_softc *, caddr_t, int));
    109  1.1    briggs static void mace_calcladrf __P((struct ethercom *ac, u_int8_t *af));
    110  1.1    briggs static inline u_int16_t ether_cmp __P((void *, void *));
    111  1.1    briggs 
    112  1.1    briggs 
    113  1.1    briggs /*
    114  1.1    briggs  * Compare two Ether/802 addresses for equality, inlined and
    115  1.1    briggs  * unrolled for speed.  Use this like bcmp().
    116  1.1    briggs  *
    117  1.1    briggs  * XXX: Add <machine/inlines.h> for stuff like this?
    118  1.1    briggs  * XXX: or maybe add it to libkern.h instead?
    119  1.1    briggs  *
    120  1.1    briggs  * "I'd love to have an inline assembler version of this."
    121  1.1    briggs  * XXX: Who wanted that? mycroft?  I wrote one, but this
    122  1.1    briggs  * version in C is as good as hand-coded assembly. -gwr
    123  1.1    briggs  *
    124  1.1    briggs  * Please do NOT tweak this without looking at the actual
    125  1.1    briggs  * assembly code generated before and after your tweaks!
    126  1.1    briggs  */
    127  1.1    briggs static inline u_int16_t
    128  1.1    briggs ether_cmp(one, two)
    129  1.1    briggs 	void *one, *two;
    130  1.1    briggs {
    131  1.1    briggs 	register u_int16_t *a = (u_short *) one;
    132  1.1    briggs 	register u_int16_t *b = (u_short *) two;
    133  1.1    briggs 	register u_int16_t diff;
    134  1.1    briggs 
    135  1.1    briggs #ifdef	m68k
    136  1.1    briggs 	/*
    137  1.1    briggs 	 * The post-increment-pointer form produces the best
    138  1.1    briggs 	 * machine code for m68k.  This was carefully tuned
    139  1.1    briggs 	 * so it compiles to just 8 short (2-byte) op-codes!
    140  1.1    briggs 	 */
    141  1.1    briggs 	diff  = *a++ - *b++;
    142  1.1    briggs 	diff |= *a++ - *b++;
    143  1.1    briggs 	diff |= *a++ - *b++;
    144  1.1    briggs #else
    145  1.1    briggs 	/*
    146  1.1    briggs 	 * Most modern CPUs do better with a single expresion.
    147  1.1    briggs 	 * Note that short-cut evaluation is NOT helpful here,
    148  1.1    briggs 	 * because it just makes the code longer, not faster!
    149  1.1    briggs 	 */
    150  1.1    briggs 	diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]);
    151  1.1    briggs #endif
    152  1.1    briggs 
    153  1.1    briggs 	return (diff);
    154  1.1    briggs }
    155  1.1    briggs 
    156  1.1    briggs #define ETHER_CMP	ether_cmp
    157  1.1    briggs 
    158  1.1    briggs /*
    159  1.1    briggs  * Interface exists: make available by filling in network interface
    160  1.1    briggs  * record.  System will initialize the interface when it is ready
    161  1.1    briggs  * to accept packets.
    162  1.1    briggs  */
    163  1.1    briggs int
    164  1.1    briggs mcsetup(sc, lladdr)
    165  1.1    briggs 	struct mc_softc	*sc;
    166  1.1    briggs 	u_int8_t *lladdr;
    167  1.1    briggs {
    168  1.1    briggs 	struct ifnet *ifp = &sc->sc_if;
    169  1.1    briggs 
    170  1.1    briggs 	/* reset the chip and disable all interrupts */
    171  1.1    briggs 	NIC_PUT(sc, MACE_BIUCC, SWRST);
    172  1.1    briggs 	DELAY(100);
    173  1.1    briggs 	NIC_PUT(sc, MACE_IMR, ~0);
    174  1.1    briggs 
    175  1.1    briggs 	bcopy(lladdr, sc->sc_enaddr, ETHER_ADDR_LEN);
    176  1.1    briggs 	printf(": address %s\n", ether_sprintf(lladdr));
    177  1.1    briggs 
    178  1.1    briggs 	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
    179  1.1    briggs 	ifp->if_softc = sc;
    180  1.1    briggs 	ifp->if_ioctl = mcioctl;
    181  1.1    briggs 	ifp->if_start = mcstart;
    182  1.1    briggs 	ifp->if_flags =
    183  1.1    briggs 	    IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
    184  1.1    briggs 	ifp->if_watchdog = mcwatchdog;
    185  1.1    briggs 
    186  1.1    briggs #if NBPFILTER > 0
    187  1.1    briggs 	bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
    188  1.1    briggs #endif
    189  1.1    briggs 	if_attach(ifp);
    190  1.1    briggs 	ether_ifattach(ifp, lladdr);
    191  1.1    briggs 
    192  1.1    briggs 	return (0);
    193  1.1    briggs }
    194  1.1    briggs 
    195  1.1    briggs hide int
    196  1.1    briggs mcioctl(ifp, cmd, data)
    197  1.1    briggs 	struct ifnet *ifp;
    198  1.1    briggs 	u_long cmd;
    199  1.1    briggs 	caddr_t data;
    200  1.1    briggs {
    201  1.1    briggs 	struct mc_softc *sc = ifp->if_softc;
    202  1.1    briggs 	struct ifaddr *ifa;
    203  1.1    briggs 	struct ifreq *ifr;
    204  1.1    briggs 
    205  1.1    briggs 	int	s = splnet(), err = 0;
    206  1.1    briggs 	int	temp;
    207  1.1    briggs 
    208  1.1    briggs 	switch (cmd) {
    209  1.1    briggs 
    210  1.1    briggs 	case SIOCSIFADDR:
    211  1.1    briggs 		ifa = (struct ifaddr *)data;
    212  1.1    briggs 		ifp->if_flags |= IFF_UP;
    213  1.1    briggs 		switch (ifa->ifa_addr->sa_family) {
    214  1.1    briggs #ifdef INET
    215  1.1    briggs 		case AF_INET:
    216  1.1    briggs 			mcinit(sc);
    217  1.1    briggs 			arp_ifinit(ifp, ifa);
    218  1.1    briggs 			break;
    219  1.1    briggs #endif
    220  1.1    briggs #ifdef NS
    221  1.1    briggs 		case AF_NS:
    222  1.1    briggs 		    {
    223  1.1    briggs 			register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
    224  1.1    briggs 
    225  1.1    briggs 			if (ns_nullhost(*ina))
    226  1.1    briggs 				ina->x_host =
    227  1.1    briggs 				    *(union ns_host *)LLADDR(ifp->if_sadl);
    228  1.1    briggs 			else {
    229  1.1    briggs 				bcopy(ina->x_host.c_host,
    230  1.1    briggs 				    LLADDR(ifp->if_sadl),
    231  1.1    briggs 				    sizeof(sc->sc_enaddr));
    232  1.1    briggs 			}
    233  1.1    briggs 			/* Set new address. */
    234  1.1    briggs 			mcinit(sc);
    235  1.1    briggs 			break;
    236  1.1    briggs 		    }
    237  1.1    briggs #endif
    238  1.1    briggs 		default:
    239  1.1    briggs 			mcinit(sc);
    240  1.1    briggs 			break;
    241  1.1    briggs 		}
    242  1.1    briggs 		break;
    243  1.1    briggs 
    244  1.1    briggs 	case SIOCSIFFLAGS:
    245  1.1    briggs 		if ((ifp->if_flags & IFF_UP) == 0 &&
    246  1.1    briggs 		    (ifp->if_flags & IFF_RUNNING) != 0) {
    247  1.1    briggs 			/*
    248  1.1    briggs 			 * If interface is marked down and it is running,
    249  1.1    briggs 			 * then stop it.
    250  1.1    briggs 			 */
    251  1.1    briggs 			mcstop(sc);
    252  1.1    briggs 			ifp->if_flags &= ~IFF_RUNNING;
    253  1.1    briggs 		} else if ((ifp->if_flags & IFF_UP) != 0 &&
    254  1.1    briggs 		    (ifp->if_flags & IFF_RUNNING) == 0) {
    255  1.1    briggs 			/*
    256  1.1    briggs 			 * If interface is marked up and it is stopped,
    257  1.1    briggs 			 * then start it.
    258  1.1    briggs 			 */
    259  1.1    briggs 			(void)mcinit(sc);
    260  1.1    briggs 		} else {
    261  1.1    briggs 			/*
    262  1.1    briggs 			 * reset the interface to pick up any other changes
    263  1.1    briggs 			 * in flags
    264  1.1    briggs 			 */
    265  1.1    briggs 			temp = ifp->if_flags & IFF_UP;
    266  1.1    briggs 			mcreset(sc);
    267  1.1    briggs 			ifp->if_flags |= temp;
    268  1.1    briggs 			mcstart(ifp);
    269  1.1    briggs 		}
    270  1.1    briggs 		break;
    271  1.1    briggs 
    272  1.1    briggs 	case SIOCADDMULTI:
    273  1.1    briggs 	case SIOCDELMULTI:
    274  1.1    briggs 		ifr = (struct ifreq *) data;
    275  1.1    briggs 		err = (cmd == SIOCADDMULTI) ?
    276  1.1    briggs 		    ether_addmulti(ifr, &sc->sc_ethercom) :
    277  1.1    briggs 		    ether_delmulti(ifr, &sc->sc_ethercom);
    278  1.1    briggs 
    279  1.1    briggs 		if (err == ENETRESET) {
    280  1.1    briggs 			/*
    281  1.1    briggs 			 * Multicast list has changed; set the hardware
    282  1.1    briggs 			 * filter accordingly. But remember UP flag!
    283  1.1    briggs 			 */
    284  1.1    briggs 			temp = ifp->if_flags & IFF_UP;
    285  1.1    briggs 			mcreset(sc);
    286  1.1    briggs 			ifp->if_flags |= temp;
    287  1.1    briggs 			err = 0;
    288  1.1    briggs 		}
    289  1.1    briggs 		break;
    290  1.1    briggs 	default:
    291  1.1    briggs 		err = EINVAL;
    292  1.1    briggs 	}
    293  1.1    briggs 	splx(s);
    294  1.1    briggs 	return (err);
    295  1.1    briggs }
    296  1.1    briggs 
    297  1.1    briggs /*
    298  1.1    briggs  * Encapsulate a packet of type family for the local net.
    299  1.1    briggs  */
    300  1.1    briggs hide void
    301  1.1    briggs mcstart(ifp)
    302  1.1    briggs 	struct ifnet *ifp;
    303  1.1    briggs {
    304  1.1    briggs 	struct mc_softc	*sc = ifp->if_softc;
    305  1.1    briggs 	struct mbuf	*m;
    306  1.1    briggs 
    307  1.1    briggs 	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
    308  1.1    briggs 		return;
    309  1.1    briggs 
    310  1.1    briggs 	while (1) {
    311  1.1    briggs 		if (ifp->if_flags & IFF_OACTIVE)
    312  1.1    briggs 			return;
    313  1.1    briggs 
    314  1.1    briggs 		IF_DEQUEUE(&ifp->if_snd, m);
    315  1.1    briggs 		if (m == 0)
    316  1.1    briggs 			return;
    317  1.1    briggs 
    318  1.1    briggs #if NBPFILTER > 0
    319  1.1    briggs 		/*
    320  1.1    briggs 		 * If bpf is listening on this interface, let it
    321  1.1    briggs 		 * see the packet before we commit it to the wire.
    322  1.1    briggs 		 */
    323  1.1    briggs 		if (ifp->if_bpf)
    324  1.1    briggs 			bpf_mtap(ifp->if_bpf, m);
    325  1.1    briggs #endif
    326  1.1    briggs 
    327  1.1    briggs 		/*
    328  1.1    briggs 		 * Copy the mbuf chain into the transmit buffer.
    329  1.1    briggs 		 */
    330  1.1    briggs 		ifp->if_flags |= IFF_OACTIVE;
    331  1.1    briggs 		maceput(sc, m);
    332  1.1    briggs 
    333  1.1    briggs 		ifp->if_opackets++;		/* # of pkts */
    334  1.1    briggs 	}
    335  1.1    briggs }
    336  1.1    briggs 
    337  1.1    briggs /*
    338  1.1    briggs  * reset and restart the MACE.  Called in case of fatal
    339  1.1    briggs  * hardware/software errors.
    340  1.1    briggs  */
    341  1.1    briggs hide void
    342  1.1    briggs mcreset(sc)
    343  1.1    briggs 	struct mc_softc *sc;
    344  1.1    briggs {
    345  1.1    briggs 	mcstop(sc);
    346  1.1    briggs 	mcinit(sc);
    347  1.1    briggs }
    348  1.1    briggs 
    349  1.1    briggs hide int
    350  1.1    briggs mcinit(sc)
    351  1.1    briggs 	struct mc_softc *sc;
    352  1.1    briggs {
    353  1.1    briggs 	int s;
    354  1.1    briggs 	u_int8_t maccc, ladrf[8];
    355  1.1    briggs 
    356  1.1    briggs 	if (sc->sc_if.if_flags & IFF_RUNNING)
    357  1.1    briggs 		/* already running */
    358  1.1    briggs 		return (0);
    359  1.1    briggs 
    360  1.1    briggs 	s = splnet();
    361  1.1    briggs 
    362  1.1    briggs 	NIC_PUT(sc, MACE_BIUCC, sc->sc_biucc);
    363  1.1    briggs 	NIC_PUT(sc, MACE_FIFOCC, sc->sc_fifocc);
    364  1.1    briggs 	NIC_PUT(sc, MACE_IMR, ~0); /* disable all interrupts */
    365  1.1    briggs 	NIC_PUT(sc, MACE_PLSCC, sc->sc_plscc);
    366  1.1    briggs 
    367  1.1    briggs 	NIC_PUT(sc, MACE_UTR, RTRD); /* disable reserved test registers */
    368  1.1    briggs 
    369  1.1    briggs 	/* set MAC address */
    370  1.1    briggs 	NIC_PUT(sc, MACE_IAC, ADDRCHG);
    371  1.1    briggs 	while (NIC_GET(sc, MACE_IAC) & ADDRCHG)
    372  1.1    briggs 		;
    373  1.1    briggs 	NIC_PUT(sc, MACE_IAC, PHYADDR);
    374  1.1    briggs 	bus_space_write_multi_1(sc->sc_regt, sc->sc_regh, MACE_REG(MACE_PADR),
    375  1.1    briggs 	    sc->sc_enaddr, ETHER_ADDR_LEN);
    376  1.1    briggs 
    377  1.1    briggs 	/* set logical address filter */
    378  1.1    briggs 	mace_calcladrf(&sc->sc_ethercom, ladrf);
    379  1.1    briggs 
    380  1.1    briggs 	NIC_PUT(sc, MACE_IAC, ADDRCHG);
    381  1.1    briggs 	while (NIC_GET(sc, MACE_IAC) & ADDRCHG)
    382  1.1    briggs 		;
    383  1.1    briggs 	NIC_PUT(sc, MACE_IAC, LOGADDR);
    384  1.1    briggs 	bus_space_write_multi_1(sc->sc_regt, sc->sc_regh, MACE_REG(MACE_LADRF),
    385  1.1    briggs 	    ladrf, 8);
    386  1.1    briggs 
    387  1.1    briggs 	NIC_PUT(sc, MACE_XMTFC, APADXMT);
    388  1.1    briggs 	/*
    389  1.1    briggs 	 * No need to autostrip padding on receive... Ethernet frames
    390  1.1    briggs 	 * don't have a length field, unlike 802.3 frames, so the MACE
    391  1.1    briggs 	 * can't figure out the length of the packet anyways.
    392  1.1    briggs 	 */
    393  1.1    briggs 	NIC_PUT(sc, MACE_RCVFC, 0);
    394  1.1    briggs 
    395  1.1    briggs 	maccc = ENXMT | ENRCV;
    396  1.1    briggs 	if (sc->sc_if.if_flags & IFF_PROMISC)
    397  1.1    briggs 		maccc |= PROM;
    398  1.1    briggs 
    399  1.1    briggs 	NIC_PUT(sc, MACE_MACCC, maccc);
    400  1.1    briggs 
    401  1.1    briggs 	if (sc->sc_bus_init)
    402  1.1    briggs 		(*sc->sc_bus_init)(sc);
    403  1.1    briggs 
    404  1.1    briggs 	/*
    405  1.1    briggs 	 * Enable all interrupts except receive, since we use the DMA
    406  1.1    briggs 	 * completion interrupt for that.
    407  1.1    briggs 	 */
    408  1.1    briggs 	NIC_PUT(sc, MACE_IMR, RCVINTM);
    409  1.1    briggs 
    410  1.1    briggs 	/* flag interface as "running" */
    411  1.1    briggs 	sc->sc_if.if_flags |= IFF_RUNNING;
    412  1.1    briggs 	sc->sc_if.if_flags &= ~IFF_OACTIVE;
    413  1.1    briggs 
    414  1.1    briggs 	splx(s);
    415  1.1    briggs 	return (0);
    416  1.1    briggs }
    417  1.1    briggs 
    418  1.1    briggs /*
    419  1.1    briggs  * close down an interface and free its buffers
    420  1.1    briggs  * Called on final close of device, or if mcinit() fails
    421  1.1    briggs  * part way through.
    422  1.1    briggs  */
    423  1.1    briggs hide int
    424  1.1    briggs mcstop(sc)
    425  1.1    briggs 	struct mc_softc *sc;
    426  1.1    briggs {
    427  1.1    briggs 	int	s = splnet();
    428  1.1    briggs 
    429  1.1    briggs 	NIC_PUT(sc, MACE_BIUCC, SWRST);
    430  1.1    briggs 	DELAY(100);
    431  1.1    briggs 
    432  1.1    briggs 	sc->sc_if.if_timer = 0;
    433  1.1    briggs 	sc->sc_if.if_flags &= ~(IFF_RUNNING | IFF_UP);
    434  1.1    briggs 
    435  1.1    briggs 	splx(s);
    436  1.1    briggs 	return (0);
    437  1.1    briggs }
    438  1.1    briggs 
    439  1.1    briggs /*
    440  1.1    briggs  * Called if any Tx packets remain unsent after 5 seconds,
    441  1.1    briggs  * In all cases we just reset the chip, and any retransmission
    442  1.1    briggs  * will be handled by higher level protocol timeouts.
    443  1.1    briggs  */
    444  1.1    briggs hide void
    445  1.1    briggs mcwatchdog(ifp)
    446  1.1    briggs 	struct ifnet *ifp;
    447  1.1    briggs {
    448  1.1    briggs 	struct mc_softc *sc = ifp->if_softc;
    449  1.1    briggs 	int temp;
    450  1.1    briggs 
    451  1.1    briggs 	printf("mcwatchdog: resetting chip\n");
    452  1.1    briggs 	temp = ifp->if_flags & IFF_UP;
    453  1.1    briggs 	mcreset(sc);
    454  1.1    briggs 	ifp->if_flags |= temp;
    455  1.1    briggs }
    456  1.1    briggs 
    457  1.1    briggs /*
    458  1.1    briggs  * stuff packet into MACE (at splnet)
    459  1.1    briggs  */
    460  1.1    briggs integrate u_int
    461  1.1    briggs maceput(sc, m)
    462  1.1    briggs 	struct mc_softc *sc;
    463  1.1    briggs 	struct mbuf *m;
    464  1.1    briggs {
    465  1.1    briggs 	struct mbuf *n;
    466  1.1    briggs 	u_int len, totlen = 0;
    467  1.1    briggs 	u_char *buff;
    468  1.1    briggs 
    469  1.1    briggs 	buff = sc->sc_txbuf;
    470  1.1    briggs 
    471  1.1    briggs 	for (; m; m = n) {
    472  1.1    briggs 		u_char *data = mtod(m, u_char *);
    473  1.1    briggs 		len = m->m_len;
    474  1.1    briggs 		totlen += len;
    475  1.1    briggs 		bcopy(data, buff, len);
    476  1.1    briggs 		buff += len;
    477  1.1    briggs 		MFREE(m, n);
    478  1.1    briggs 	}
    479  1.1    briggs 
    480  1.1    briggs 	if (totlen > NBPG)
    481  1.1    briggs 		panic("%s: maceput: packet overflow", sc->sc_dev.dv_xname);
    482  1.1    briggs 
    483  1.1    briggs #if 0
    484  1.1    briggs 	if (totlen < ETHERMIN + sizeof(struct ether_header)) {
    485  1.1    briggs 		int pad = ETHERMIN + sizeof(struct ether_header) - totlen;
    486  1.1    briggs 		bzero(sc->sc_txbuf + totlen, pad);
    487  1.1    briggs 		totlen = ETHERMIN + sizeof(struct ether_header);
    488  1.1    briggs 	}
    489  1.1    briggs #endif
    490  1.1    briggs 
    491  1.1    briggs 	(*sc->sc_putpacket)(sc, totlen);
    492  1.1    briggs 
    493  1.1    briggs 	sc->sc_if.if_timer = 5;	/* 5 seconds to watch for failing to transmit */
    494  1.1    briggs 	return (totlen);
    495  1.1    briggs }
    496  1.1    briggs 
    497  1.1    briggs void
    498  1.1    briggs mcintr(arg)
    499  1.1    briggs 	void *arg;
    500  1.1    briggs {
    501  1.1    briggs struct mc_softc *sc = arg;
    502  1.1    briggs 	u_int8_t ir;
    503  1.1    briggs 
    504  1.1    briggs 	ir = NIC_GET(sc, MACE_IR) & ~NIC_GET(sc, MACE_IMR);
    505  1.1    briggs 	if (ir & JAB) {
    506  1.1    briggs #ifdef MCDEBUG
    507  1.1    briggs 		printf("%s: jabber error\n", sc->sc_dev.dv_xname);
    508  1.1    briggs #endif
    509  1.1    briggs 		sc->sc_if.if_oerrors++;
    510  1.1    briggs 	}
    511  1.1    briggs 
    512  1.1    briggs 	if (ir & BABL) {
    513  1.1    briggs #ifdef MCDEBUG
    514  1.1    briggs 		printf("%s: babble\n", sc->sc_dev.dv_xname);
    515  1.1    briggs #endif
    516  1.1    briggs 		sc->sc_if.if_oerrors++;
    517  1.1    briggs 	}
    518  1.1    briggs 
    519  1.1    briggs 	if (ir & CERR) {
    520  1.1    briggs 		printf("%s: collision error\n", sc->sc_dev.dv_xname);
    521  1.1    briggs 		sc->sc_if.if_collisions++;
    522  1.1    briggs 	}
    523  1.1    briggs 
    524  1.1    briggs 	/*
    525  1.1    briggs 	 * Pretend we have carrier; if we don't this will be cleared
    526  1.1    briggs 	 * shortly.
    527  1.1    briggs 	 */
    528  1.1    briggs 	sc->sc_havecarrier = 1;
    529  1.1    briggs 
    530  1.1    briggs 	if (ir & XMTINT)
    531  1.1    briggs 		mc_tint(sc);
    532  1.1    briggs 
    533  1.1    briggs 	if (ir & RCVINT)
    534  1.1    briggs 		mc_rint(sc);
    535  1.1    briggs }
    536  1.1    briggs 
    537  1.1    briggs integrate void
    538  1.1    briggs mc_tint(sc)
    539  1.1    briggs 	struct mc_softc *sc;
    540  1.1    briggs {
    541  1.1    briggs 	u_int8_t xmtrc, xmtfs;
    542  1.1    briggs 
    543  1.1    briggs 	xmtrc = NIC_GET(sc, MACE_XMTRC);
    544  1.1    briggs 	xmtfs = NIC_GET(sc, MACE_XMTFS);
    545  1.1    briggs 
    546  1.1    briggs 	if ((xmtfs & XMTSV) == 0)
    547  1.1    briggs 		return;
    548  1.1    briggs 
    549  1.1    briggs 	if (xmtfs & UFLO) {
    550  1.1    briggs 		printf("%s: underflow\n", sc->sc_dev.dv_xname);
    551  1.1    briggs 		mcreset(sc);
    552  1.1    briggs 		return;
    553  1.1    briggs 	}
    554  1.1    briggs 
    555  1.1    briggs 	if (xmtfs & LCOL) {
    556  1.1    briggs 		printf("%s: late collision\n", sc->sc_dev.dv_xname);
    557  1.1    briggs 		sc->sc_if.if_oerrors++;
    558  1.1    briggs 		sc->sc_if.if_collisions++;
    559  1.1    briggs 	}
    560  1.1    briggs 
    561  1.1    briggs 	if (xmtfs & MORE)
    562  1.1    briggs 		/* Real number is unknown. */
    563  1.1    briggs 		sc->sc_if.if_collisions += 2;
    564  1.1    briggs 	else if (xmtfs & ONE)
    565  1.1    briggs 		sc->sc_if.if_collisions++;
    566  1.1    briggs 	else if (xmtfs & RTRY) {
    567  1.1    briggs 		sc->sc_if.if_collisions += 16;
    568  1.1    briggs 		sc->sc_if.if_oerrors++;
    569  1.1    briggs 	}
    570  1.1    briggs 
    571  1.1    briggs 	if (xmtfs & LCAR) {
    572  1.1    briggs 		sc->sc_havecarrier = 0;
    573  1.1    briggs 		printf("%s: lost carrier\n", sc->sc_dev.dv_xname);
    574  1.1    briggs 		sc->sc_if.if_oerrors++;
    575  1.1    briggs 	}
    576  1.1    briggs 
    577  1.1    briggs 	sc->sc_if.if_flags &= ~IFF_OACTIVE;
    578  1.1    briggs 	sc->sc_if.if_timer = 0;
    579  1.1    briggs 	mcstart(&sc->sc_if);
    580  1.1    briggs }
    581  1.1    briggs 
    582  1.5    scottr void
    583  1.1    briggs mc_rint(sc)
    584  1.1    briggs 	struct mc_softc *sc;
    585  1.1    briggs {
    586  1.1    briggs #define	rxf	sc->sc_rxframe
    587  1.1    briggs 	u_int len;
    588  1.1    briggs 
    589  1.1    briggs 	len = (rxf.rx_rcvcnt | ((rxf.rx_rcvsts & 0xf) << 8)) - 4;
    590  1.1    briggs 
    591  1.1    briggs #ifdef MCDEBUG
    592  1.1    briggs 	if (rxf.rx_rcvsts & 0xf0)
    593  1.1    briggs 		printf("%s: rcvcnt %02x rcvsts %02x rntpc 0x%02x rcvcc 0x%02x\n",
    594  1.1    briggs 		    sc->sc_dev.dv_xname, rxf.rx_rcvcnt, rxf.rx_rcvsts,
    595  1.1    briggs 		    rxf.rx_rntpc, rxf.rx_rcvcc);
    596  1.1    briggs #endif
    597  1.1    briggs 
    598  1.1    briggs 	if (rxf.rx_rcvsts & OFLO) {
    599  1.1    briggs 		printf("%s: receive FIFO overflow\n", sc->sc_dev.dv_xname);
    600  1.1    briggs 		sc->sc_if.if_ierrors++;
    601  1.1    briggs 		return;
    602  1.1    briggs 	}
    603  1.1    briggs 
    604  1.1    briggs 	if (rxf.rx_rcvsts & CLSN)
    605  1.1    briggs 		sc->sc_if.if_collisions++;
    606  1.1    briggs 
    607  1.1    briggs 	if (rxf.rx_rcvsts & FRAM) {
    608  1.1    briggs #ifdef MCDEBUG
    609  1.1    briggs 		printf("%s: framing error\n", sc->sc_dev.dv_xname);
    610  1.1    briggs #endif
    611  1.1    briggs 		sc->sc_if.if_ierrors++;
    612  1.1    briggs 		return;
    613  1.1    briggs 	}
    614  1.1    briggs 
    615  1.1    briggs 	if (rxf.rx_rcvsts & FCS) {
    616  1.1    briggs #ifdef MCDEBUG
    617  1.1    briggs 		printf("%s: frame control checksum error\n", sc->sc_dev.dv_xname);
    618  1.1    briggs #endif
    619  1.1    briggs 		sc->sc_if.if_ierrors++;
    620  1.1    briggs 		return;
    621  1.1    briggs 	}
    622  1.1    briggs 
    623  1.1    briggs 	mace_read(sc, rxf.rx_frame, len);
    624  1.1    briggs #undef	rxf
    625  1.1    briggs }
    626  1.1    briggs 
    627  1.1    briggs integrate void
    628  1.1    briggs mace_read(sc, pkt, len)
    629  1.1    briggs 	struct mc_softc *sc;
    630  1.1    briggs 	caddr_t pkt;
    631  1.1    briggs 	int len;
    632  1.1    briggs {
    633  1.1    briggs 	struct ifnet *ifp = &sc->sc_if;
    634  1.1    briggs 	struct ether_header *eh = (struct ether_header *)pkt;
    635  1.1    briggs 	struct mbuf *m;
    636  1.1    briggs 
    637  1.1    briggs 	if (len <= sizeof(struct ether_header) ||
    638  1.1    briggs 	    len > ETHERMTU + sizeof(struct ether_header)) {
    639  1.1    briggs #ifdef MCDEBUG
    640  1.1    briggs 		printf("%s: invalid packet size %d; dropping\n",
    641  1.1    briggs 		    sc->sc_dev.dv_xname, len);
    642  1.1    briggs #endif
    643  1.1    briggs 		ifp->if_ierrors++;
    644  1.1    briggs 		return;
    645  1.1    briggs 	}
    646  1.1    briggs 
    647  1.1    briggs #if NBPFILTER > 0
    648  1.1    briggs 	/*
    649  1.1    briggs 	 * Check if there's a bpf filter listening on this interface.
    650  1.1    briggs 	 * If so, hand off the raw packet to enet, then discard things
    651  1.1    briggs 	 * not destined for us (but be sure to keep broadcast/multicast).
    652  1.1    briggs 	 */
    653  1.1    briggs 	if (ifp->if_bpf) {
    654  1.1    briggs 		bpf_tap(ifp->if_bpf, pkt, len);
    655  1.1    briggs 		if ((ifp->if_flags & IFF_PROMISC) != 0 &&
    656  1.1    briggs 		    (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
    657  1.1    briggs 		    ETHER_CMP(eh->ether_dhost, sc->sc_enaddr))
    658  1.1    briggs 			return;
    659  1.1    briggs 	}
    660  1.1    briggs #endif
    661  1.1    briggs 	m = mace_get(sc, pkt, len);
    662  1.1    briggs 	if (m == NULL) {
    663  1.1    briggs 		ifp->if_ierrors++;
    664  1.1    briggs 		return;
    665  1.1    briggs 	}
    666  1.1    briggs 
    667  1.1    briggs 	ifp->if_ipackets++;
    668  1.1    briggs 
    669  1.1    briggs 	/* Pass the packet up, with the ether header sort-of removed. */
    670  1.1    briggs 	m_adj(m, sizeof(struct ether_header));
    671  1.1    briggs 	ether_input(ifp, eh, m);
    672  1.1    briggs }
    673  1.1    briggs 
    674  1.1    briggs /*
    675  1.1    briggs  * Pull data off an interface.
    676  1.1    briggs  * Len is length of data, with local net header stripped.
    677  1.1    briggs  * We copy the data into mbufs.  When full cluster sized units are present
    678  1.1    briggs  * we copy into clusters.
    679  1.1    briggs  */
    680  1.1    briggs integrate struct mbuf *
    681  1.1    briggs mace_get(sc, pkt, totlen)
    682  1.1    briggs 	struct mc_softc *sc;
    683  1.1    briggs 	caddr_t pkt;
    684  1.1    briggs 	int totlen;
    685  1.1    briggs {
    686  1.1    briggs 	register struct mbuf *m;
    687  1.1    briggs 	struct mbuf *top, **mp;
    688  1.1    briggs 	int len;
    689  1.1    briggs 
    690  1.1    briggs 	MGETHDR(m, M_DONTWAIT, MT_DATA);
    691  1.1    briggs 	if (m == 0)
    692  1.1    briggs 		return (0);
    693  1.1    briggs 	m->m_pkthdr.rcvif = &sc->sc_if;
    694  1.1    briggs 	m->m_pkthdr.len = totlen;
    695  1.1    briggs 	len = MHLEN;
    696  1.1    briggs 	top = 0;
    697  1.1    briggs 	mp = &top;
    698  1.1    briggs 
    699  1.1    briggs 	while (totlen > 0) {
    700  1.1    briggs 		if (top) {
    701  1.1    briggs 			MGET(m, M_DONTWAIT, MT_DATA);
    702  1.1    briggs 			if (m == 0) {
    703  1.1    briggs 				m_freem(top);
    704  1.1    briggs 				return 0;
    705  1.1    briggs 			}
    706  1.1    briggs 			len = MLEN;
    707  1.1    briggs 		}
    708  1.1    briggs 		if (totlen >= MINCLSIZE) {
    709  1.1    briggs 			MCLGET(m, M_DONTWAIT);
    710  1.1    briggs 			if ((m->m_flags & M_EXT) == 0) {
    711  1.1    briggs 				m_free(m);
    712  1.1    briggs 				m_freem(top);
    713  1.1    briggs 				return 0;
    714  1.1    briggs 			}
    715  1.1    briggs 			len = MCLBYTES;
    716  1.1    briggs 		}
    717  1.1    briggs 		m->m_len = len = min(totlen, len);
    718  1.1    briggs 		bcopy(pkt, mtod(m, caddr_t), len);
    719  1.1    briggs 		pkt += len;
    720  1.1    briggs 		totlen -= len;
    721  1.1    briggs 		*mp = m;
    722  1.1    briggs 		mp = &m->m_next;
    723  1.1    briggs 	}
    724  1.1    briggs 
    725  1.1    briggs 	return (top);
    726  1.1    briggs }
    727  1.1    briggs 
    728  1.1    briggs /*
    729  1.1    briggs  * Go through the list of multicast addresses and calculate the logical
    730  1.1    briggs  * address filter.
    731  1.1    briggs  */
    732  1.1    briggs void
    733  1.1    briggs mace_calcladrf(ac, af)
    734  1.1    briggs 	struct ethercom *ac;
    735  1.1    briggs 	u_int8_t *af;
    736  1.1    briggs {
    737  1.1    briggs 	struct ifnet *ifp = &ac->ec_if;
    738  1.1    briggs 	struct ether_multi *enm;
    739  1.6   mycroft 	register u_char *cp;
    740  1.1    briggs 	register u_int32_t crc;
    741  1.6   mycroft 	static const u_int32_t crctab[] = {
    742  1.6   mycroft 		0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
    743  1.6   mycroft 		0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
    744  1.6   mycroft 		0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
    745  1.6   mycroft 		0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
    746  1.6   mycroft 	};
    747  1.6   mycroft 	register int len;
    748  1.1    briggs 	struct ether_multistep step;
    749  1.1    briggs 
    750  1.1    briggs 	/*
    751  1.1    briggs 	 * Set up multicast address filter by passing all multicast addresses
    752  1.1    briggs 	 * through a crc generator, and then using the high order 6 bits as an
    753  1.1    briggs 	 * index into the 64 bit logical address filter.  The high order bit
    754  1.1    briggs 	 * selects the word, while the rest of the bits select the bit within
    755  1.1    briggs 	 * the word.
    756  1.1    briggs 	 */
    757  1.1    briggs 
    758  1.1    briggs 	*((u_int32_t *)af) = *((u_int32_t *)af + 1) = 0;
    759  1.1    briggs 	ETHER_FIRST_MULTI(step, ac, enm);
    760  1.1    briggs 	while (enm != NULL) {
    761  1.1    briggs 		if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) {
    762  1.1    briggs 			/*
    763  1.1    briggs 			 * We must listen to a range of multicast addresses.
    764  1.1    briggs 			 * For now, just accept all multicasts, rather than
    765  1.1    briggs 			 * trying to set only those filter bits needed to match
    766  1.1    briggs 			 * the range.  (At this time, the only use of address
    767  1.1    briggs 			 * ranges is for IP multicast routing, for which the
    768  1.1    briggs 			 * range is big enough to require all bits set.)
    769  1.1    briggs 			 */
    770  1.1    briggs 			goto allmulti;
    771  1.1    briggs 		}
    772  1.1    briggs 
    773  1.1    briggs 		cp = enm->enm_addrlo;
    774  1.1    briggs 		crc = 0xffffffff;
    775  1.1    briggs 		for (len = sizeof(enm->enm_addrlo); --len >= 0;) {
    776  1.6   mycroft 			crc ^= *cp++;
    777  1.6   mycroft 			crc = (crc >> 4) ^ crctab[crc & 0xf];
    778  1.6   mycroft 			crc = (crc >> 4) ^ crctab[crc & 0xf];
    779  1.1    briggs 		}
    780  1.1    briggs 		/* Just want the 6 most significant bits. */
    781  1.1    briggs 		crc >>= 26;
    782  1.1    briggs 
    783  1.1    briggs 		/* Set the corresponding bit in the filter. */
    784  1.1    briggs 		af[crc >> 3] |= 1 << (crc & 7);
    785  1.1    briggs 
    786  1.1    briggs 		ETHER_NEXT_MULTI(step, enm);
    787  1.1    briggs 	}
    788  1.1    briggs 	ifp->if_flags &= ~IFF_ALLMULTI;
    789  1.1    briggs 	return;
    790  1.1    briggs 
    791  1.1    briggs allmulti:
    792  1.1    briggs 	ifp->if_flags |= IFF_ALLMULTI;
    793  1.1    briggs 	*((u_int32_t *)af) = *((u_int32_t *)af + 1) = 0xffffffff;
    794  1.1    briggs }
    795  1.1    briggs 
    796  1.1    briggs static u_char bbr4[] = {0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15};
    797  1.1    briggs #define bbr(v)  ((bbr4[(v)&0xf] << 4) | bbr4[((v)>>4) & 0xf])
    798  1.1    briggs 
    799  1.1    briggs u_char
    800  1.1    briggs mc_get_enaddr(t, h, o, dst)
    801  1.1    briggs 	bus_space_tag_t t;
    802  1.1    briggs 	bus_space_handle_t h;
    803  1.1    briggs 	vm_offset_t o;
    804  1.1    briggs 	u_char *dst;
    805  1.1    briggs {
    806  1.1    briggs 	int	i;
    807  1.1    briggs 	u_char	b, csum;
    808  1.1    briggs 
    809  1.1    briggs 	/*
    810  1.1    briggs 	 * The XOR of the 8 bytes of the ROM must be 0xff for it to be
    811  1.1    briggs 	 * valid
    812  1.1    briggs 	*/
    813  1.1    briggs 	for (i = 0, csum = 0; i < 8; i++) {
    814  1.1    briggs 		b = bus_space_read_1(t, h, o+16*i);
    815  1.1    briggs 		if (i < ETHER_ADDR_LEN)
    816  1.1    briggs 			dst[i] = bbr(b);
    817  1.1    briggs 		csum ^= b;
    818  1.1    briggs 	}
    819  1.1    briggs 
    820  1.1    briggs 	return csum;
    821  1.1    briggs }
    822