Home | History | Annotate | Line # | Download | only in dev
if_mc.c revision 1.56.2.1
      1  1.56.2.1   thorpej /*	$NetBSD: if_mc.c,v 1.56.2.1 2021/04/03 22:28:29 thorpej Exp $	*/
      2       1.2    briggs 
      3       1.1    briggs /*-
      4      1.23       wiz  * Copyright (c) 1997 David Huang <khym (at) azeotrope.org>
      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.22     lukem 
     37      1.22     lukem #include <sys/cdefs.h>
     38  1.56.2.1   thorpej __KERNEL_RCSID(0, "$NetBSD: if_mc.c,v 1.56.2.1 2021/04/03 22:28:29 thorpej Exp $");
     39       1.1    briggs 
     40       1.7  jonathan #include "opt_ddb.h"
     41       1.7  jonathan #include "opt_inet.h"
     42       1.7  jonathan 
     43       1.1    briggs #include <sys/param.h>
     44       1.1    briggs #include <sys/systm.h>
     45       1.1    briggs #include <sys/mbuf.h>
     46       1.1    briggs #include <sys/buf.h>
     47       1.1    briggs #include <sys/protosw.h>
     48       1.1    briggs #include <sys/socket.h>
     49       1.1    briggs #include <sys/syslog.h>
     50       1.1    briggs #include <sys/ioctl.h>
     51       1.1    briggs #include <sys/errno.h>
     52       1.1    briggs #include <sys/device.h>
     53       1.1    briggs 
     54  1.56.2.1   thorpej #include <sys/rndsource.h>
     55  1.56.2.1   thorpej 
     56      1.20   thorpej #include <uvm/uvm_extern.h>
     57      1.20   thorpej 
     58       1.1    briggs #include <net/if.h>
     59       1.1    briggs #include <net/if_dl.h>
     60       1.1    briggs #include <net/if_ether.h>
     61      1.46   msaitoh #include <net/bpf.h>
     62       1.1    briggs 
     63       1.1    briggs #ifdef INET
     64       1.1    briggs #include <netinet/in.h>
     65       1.1    briggs #include <netinet/if_inarp.h>
     66       1.1    briggs #include <netinet/in_systm.h>
     67       1.1    briggs #include <netinet/in_var.h>
     68       1.1    briggs #include <netinet/ip.h>
     69       1.1    briggs #endif
     70       1.1    briggs 
     71       1.1    briggs #include <machine/bus.h>
     72       1.1    briggs #include <mac68k/dev/if_mcreg.h>
     73       1.1    briggs #include <mac68k/dev/if_mcvar.h>
     74       1.1    briggs 
     75      1.25       chs hide void	mcwatchdog(struct ifnet *);
     76      1.25       chs hide int	mcinit(struct mc_softc *);
     77      1.25       chs hide int	mcstop(struct mc_softc *);
     78      1.30  christos hide int	mcioctl(struct ifnet *, u_long, void *);
     79      1.25       chs hide void	mcstart(struct ifnet *);
     80      1.25       chs hide void	mcreset(struct mc_softc *);
     81      1.25       chs 
     82      1.25       chs integrate u_int	maceput(struct mc_softc *, struct mbuf *);
     83      1.25       chs integrate void	mc_tint(struct mc_softc *);
     84      1.30  christos integrate void	mace_read(struct mc_softc *, void *, int);
     85      1.30  christos integrate struct mbuf *mace_get(struct mc_softc *, void *, int);
     86      1.50   msaitoh static void mace_calcladrf(struct ethercom *, uint8_t *);
     87      1.50   msaitoh static inline uint16_t ether_cmp(void *, void *);
     88       1.1    briggs 
     89       1.1    briggs 
     90       1.1    briggs /*
     91       1.1    briggs  * Compare two Ether/802 addresses for equality, inlined and
     92      1.36    cegger  * unrolled for speed.  Use this like memcmp().
     93       1.1    briggs  *
     94       1.1    briggs  * XXX: Add <machine/inlines.h> for stuff like this?
     95       1.1    briggs  * XXX: or maybe add it to libkern.h instead?
     96       1.1    briggs  *
     97       1.1    briggs  * "I'd love to have an inline assembler version of this."
     98       1.1    briggs  * XXX: Who wanted that? mycroft?  I wrote one, but this
     99       1.1    briggs  * version in C is as good as hand-coded assembly. -gwr
    100       1.1    briggs  *
    101       1.1    briggs  * Please do NOT tweak this without looking at the actual
    102       1.1    briggs  * assembly code generated before and after your tweaks!
    103       1.1    briggs  */
    104      1.50   msaitoh static inline uint16_t
    105      1.25       chs ether_cmp(void *one, void *two)
    106       1.1    briggs {
    107      1.50   msaitoh 	uint16_t *a = (u_short *) one;
    108      1.50   msaitoh 	uint16_t *b = (u_short *) two;
    109      1.50   msaitoh 	uint16_t diff;
    110       1.1    briggs 
    111       1.1    briggs #ifdef	m68k
    112       1.1    briggs 	/*
    113       1.1    briggs 	 * The post-increment-pointer form produces the best
    114       1.1    briggs 	 * machine code for m68k.  This was carefully tuned
    115       1.1    briggs 	 * so it compiles to just 8 short (2-byte) op-codes!
    116       1.1    briggs 	 */
    117       1.1    briggs 	diff  = *a++ - *b++;
    118       1.1    briggs 	diff |= *a++ - *b++;
    119       1.1    briggs 	diff |= *a++ - *b++;
    120       1.1    briggs #else
    121       1.1    briggs 	/*
    122      1.52   msaitoh 	 * Most modern CPUs do better with a single expression.
    123       1.1    briggs 	 * Note that short-cut evaluation is NOT helpful here,
    124       1.1    briggs 	 * because it just makes the code longer, not faster!
    125       1.1    briggs 	 */
    126       1.1    briggs 	diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]);
    127       1.1    briggs #endif
    128       1.1    briggs 
    129      1.50   msaitoh 	return diff;
    130       1.1    briggs }
    131       1.1    briggs 
    132       1.1    briggs #define ETHER_CMP	ether_cmp
    133       1.1    briggs 
    134       1.1    briggs /*
    135       1.1    briggs  * Interface exists: make available by filling in network interface
    136       1.1    briggs  * record.  System will initialize the interface when it is ready
    137       1.1    briggs  * to accept packets.
    138       1.1    briggs  */
    139       1.1    briggs int
    140      1.50   msaitoh mcsetup(struct mc_softc	*sc, uint8_t *lladdr)
    141       1.1    briggs {
    142       1.1    briggs 	struct ifnet *ifp = &sc->sc_if;
    143       1.1    briggs 
    144       1.1    briggs 	/* reset the chip and disable all interrupts */
    145       1.1    briggs 	NIC_PUT(sc, MACE_BIUCC, SWRST);
    146       1.1    briggs 	DELAY(100);
    147       1.1    briggs 	NIC_PUT(sc, MACE_IMR, ~0);
    148       1.1    briggs 
    149      1.25       chs 	memcpy(sc->sc_enaddr, lladdr, ETHER_ADDR_LEN);
    150       1.1    briggs 	printf(": address %s\n", ether_sprintf(lladdr));
    151       1.1    briggs 
    152      1.39       chs 	memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
    153       1.1    briggs 	ifp->if_softc = sc;
    154       1.1    briggs 	ifp->if_ioctl = mcioctl;
    155       1.1    briggs 	ifp->if_start = mcstart;
    156      1.49   msaitoh 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
    157       1.1    briggs 	ifp->if_watchdog = mcwatchdog;
    158       1.1    briggs 
    159       1.1    briggs 	if_attach(ifp);
    160      1.45    nonaka 	if_deferred_start_init(ifp, NULL);
    161       1.1    briggs 	ether_ifattach(ifp, lladdr);
    162       1.1    briggs 
    163  1.56.2.1   thorpej 	rnd_attach_source(&sc->rnd_source, ifp->if_xname, RND_TYPE_NET,
    164  1.56.2.1   thorpej 	    RND_FLAG_DEFAULT);
    165  1.56.2.1   thorpej 
    166      1.50   msaitoh 	return 0;
    167       1.1    briggs }
    168       1.1    briggs 
    169       1.1    briggs hide int
    170      1.30  christos mcioctl(struct ifnet *ifp, u_long cmd, void *data)
    171       1.1    briggs {
    172       1.1    briggs 	struct mc_softc *sc = ifp->if_softc;
    173       1.1    briggs 	struct ifaddr *ifa;
    174       1.1    briggs 
    175       1.1    briggs 	int	s = splnet(), err = 0;
    176       1.1    briggs 
    177       1.1    briggs 	switch (cmd) {
    178       1.1    briggs 
    179      1.35    dyoung 	case SIOCINITIFADDR:
    180       1.1    briggs 		ifa = (struct ifaddr *)data;
    181       1.1    briggs 		ifp->if_flags |= IFF_UP;
    182      1.35    dyoung 		mcinit(sc);
    183       1.1    briggs 		switch (ifa->ifa_addr->sa_family) {
    184       1.1    briggs #ifdef INET
    185       1.1    briggs 		case AF_INET:
    186       1.1    briggs 			arp_ifinit(ifp, ifa);
    187       1.1    briggs 			break;
    188       1.1    briggs #endif
    189       1.1    briggs 		default:
    190       1.1    briggs 			break;
    191       1.1    briggs 		}
    192       1.1    briggs 		break;
    193       1.1    briggs 
    194       1.1    briggs 	case SIOCSIFFLAGS:
    195      1.35    dyoung 		if ((err = ifioctl_common(ifp, cmd, data)) != 0)
    196      1.35    dyoung 			break;
    197      1.35    dyoung 		/* XXX see the comment in ed_ioctl() about code re-use */
    198       1.1    briggs 		if ((ifp->if_flags & IFF_UP) == 0 &&
    199       1.1    briggs 		    (ifp->if_flags & IFF_RUNNING) != 0) {
    200       1.1    briggs 			/*
    201       1.1    briggs 			 * If interface is marked down and it is running,
    202       1.1    briggs 			 * then stop it.
    203       1.1    briggs 			 */
    204       1.1    briggs 			mcstop(sc);
    205       1.1    briggs 			ifp->if_flags &= ~IFF_RUNNING;
    206       1.1    briggs 		} else if ((ifp->if_flags & IFF_UP) != 0 &&
    207       1.1    briggs 		    (ifp->if_flags & IFF_RUNNING) == 0) {
    208       1.1    briggs 			/*
    209       1.1    briggs 			 * If interface is marked up and it is stopped,
    210       1.1    briggs 			 * then start it.
    211       1.1    briggs 			 */
    212       1.1    briggs 			(void)mcinit(sc);
    213       1.1    briggs 		} else {
    214       1.1    briggs 			/*
    215       1.1    briggs 			 * reset the interface to pick up any other changes
    216       1.1    briggs 			 * in flags
    217       1.1    briggs 			 */
    218       1.1    briggs 			mcreset(sc);
    219       1.1    briggs 			mcstart(ifp);
    220       1.1    briggs 		}
    221       1.1    briggs 		break;
    222       1.1    briggs 
    223       1.1    briggs 	case SIOCADDMULTI:
    224       1.1    briggs 	case SIOCDELMULTI:
    225      1.32    dyoung 		if ((err = ether_ioctl(ifp, cmd, data)) == ENETRESET) {
    226       1.1    briggs 			/*
    227       1.1    briggs 			 * Multicast list has changed; set the hardware
    228       1.1    briggs 			 * filter accordingly. But remember UP flag!
    229       1.1    briggs 			 */
    230      1.24   thorpej 			if (ifp->if_flags & IFF_RUNNING)
    231      1.24   thorpej 				mcreset(sc);
    232       1.1    briggs 			err = 0;
    233       1.1    briggs 		}
    234       1.1    briggs 		break;
    235       1.1    briggs 	default:
    236      1.35    dyoung 		err = ether_ioctl(ifp, cmd, data);
    237       1.1    briggs 	}
    238       1.1    briggs 	splx(s);
    239      1.50   msaitoh 	return err;
    240       1.1    briggs }
    241       1.1    briggs 
    242       1.1    briggs /*
    243       1.1    briggs  * Encapsulate a packet of type family for the local net.
    244       1.1    briggs  */
    245       1.1    briggs hide void
    246      1.25       chs mcstart(struct ifnet *ifp)
    247       1.1    briggs {
    248       1.1    briggs 	struct mc_softc	*sc = ifp->if_softc;
    249      1.25       chs 	struct mbuf *m;
    250       1.1    briggs 
    251       1.1    briggs 	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
    252       1.1    briggs 		return;
    253       1.1    briggs 
    254       1.1    briggs 	while (1) {
    255       1.1    briggs 		if (ifp->if_flags & IFF_OACTIVE)
    256       1.1    briggs 			return;
    257       1.1    briggs 
    258       1.1    briggs 		IF_DEQUEUE(&ifp->if_snd, m);
    259       1.1    briggs 		if (m == 0)
    260       1.1    briggs 			return;
    261       1.1    briggs 
    262       1.1    briggs 		/*
    263       1.1    briggs 		 * If bpf is listening on this interface, let it
    264       1.1    briggs 		 * see the packet before we commit it to the wire.
    265       1.1    briggs 		 */
    266      1.47   msaitoh 		bpf_mtap(ifp, m, BPF_D_OUT);
    267       1.1    briggs 
    268       1.1    briggs 		/*
    269       1.1    briggs 		 * Copy the mbuf chain into the transmit buffer.
    270       1.1    briggs 		 */
    271       1.1    briggs 		ifp->if_flags |= IFF_OACTIVE;
    272       1.1    briggs 		maceput(sc, m);
    273       1.1    briggs 
    274      1.53   thorpej 		if_statinc(ifp, if_opackets);	/* # of pkts */
    275       1.1    briggs 	}
    276       1.1    briggs }
    277       1.1    briggs 
    278       1.1    briggs /*
    279       1.1    briggs  * reset and restart the MACE.  Called in case of fatal
    280       1.1    briggs  * hardware/software errors.
    281       1.1    briggs  */
    282       1.1    briggs hide void
    283      1.25       chs mcreset(struct mc_softc *sc)
    284       1.1    briggs {
    285       1.1    briggs 	mcstop(sc);
    286       1.1    briggs 	mcinit(sc);
    287       1.1    briggs }
    288       1.1    briggs 
    289       1.1    briggs hide int
    290      1.25       chs mcinit(struct mc_softc *sc)
    291       1.1    briggs {
    292       1.1    briggs 	int s;
    293      1.50   msaitoh 	uint8_t maccc, ladrf[8];
    294       1.1    briggs 
    295       1.1    briggs 	if (sc->sc_if.if_flags & IFF_RUNNING)
    296       1.1    briggs 		/* already running */
    297      1.50   msaitoh 		return 0;
    298       1.1    briggs 
    299       1.1    briggs 	s = splnet();
    300       1.1    briggs 
    301       1.1    briggs 	NIC_PUT(sc, MACE_BIUCC, sc->sc_biucc);
    302       1.1    briggs 	NIC_PUT(sc, MACE_FIFOCC, sc->sc_fifocc);
    303       1.1    briggs 	NIC_PUT(sc, MACE_IMR, ~0); /* disable all interrupts */
    304       1.1    briggs 	NIC_PUT(sc, MACE_PLSCC, sc->sc_plscc);
    305       1.1    briggs 
    306       1.1    briggs 	NIC_PUT(sc, MACE_UTR, RTRD); /* disable reserved test registers */
    307       1.1    briggs 
    308       1.1    briggs 	/* set MAC address */
    309       1.1    briggs 	NIC_PUT(sc, MACE_IAC, ADDRCHG);
    310       1.1    briggs 	while (NIC_GET(sc, MACE_IAC) & ADDRCHG)
    311       1.1    briggs 		;
    312       1.1    briggs 	NIC_PUT(sc, MACE_IAC, PHYADDR);
    313       1.1    briggs 	bus_space_write_multi_1(sc->sc_regt, sc->sc_regh, MACE_REG(MACE_PADR),
    314       1.1    briggs 	    sc->sc_enaddr, ETHER_ADDR_LEN);
    315       1.1    briggs 
    316       1.1    briggs 	/* set logical address filter */
    317       1.1    briggs 	mace_calcladrf(&sc->sc_ethercom, ladrf);
    318       1.1    briggs 
    319       1.1    briggs 	NIC_PUT(sc, MACE_IAC, ADDRCHG);
    320       1.1    briggs 	while (NIC_GET(sc, MACE_IAC) & ADDRCHG)
    321       1.1    briggs 		;
    322       1.1    briggs 	NIC_PUT(sc, MACE_IAC, LOGADDR);
    323       1.1    briggs 	bus_space_write_multi_1(sc->sc_regt, sc->sc_regh, MACE_REG(MACE_LADRF),
    324       1.1    briggs 	    ladrf, 8);
    325       1.1    briggs 
    326       1.1    briggs 	NIC_PUT(sc, MACE_XMTFC, APADXMT);
    327       1.1    briggs 	/*
    328       1.1    briggs 	 * No need to autostrip padding on receive... Ethernet frames
    329       1.1    briggs 	 * don't have a length field, unlike 802.3 frames, so the MACE
    330       1.1    briggs 	 * can't figure out the length of the packet anyways.
    331       1.1    briggs 	 */
    332       1.1    briggs 	NIC_PUT(sc, MACE_RCVFC, 0);
    333       1.1    briggs 
    334       1.1    briggs 	maccc = ENXMT | ENRCV;
    335       1.1    briggs 	if (sc->sc_if.if_flags & IFF_PROMISC)
    336       1.1    briggs 		maccc |= PROM;
    337       1.1    briggs 
    338       1.1    briggs 	NIC_PUT(sc, MACE_MACCC, maccc);
    339       1.1    briggs 
    340       1.1    briggs 	if (sc->sc_bus_init)
    341       1.1    briggs 		(*sc->sc_bus_init)(sc);
    342       1.1    briggs 
    343       1.1    briggs 	/*
    344       1.1    briggs 	 * Enable all interrupts except receive, since we use the DMA
    345       1.1    briggs 	 * completion interrupt for that.
    346       1.1    briggs 	 */
    347       1.1    briggs 	NIC_PUT(sc, MACE_IMR, RCVINTM);
    348       1.1    briggs 
    349       1.1    briggs 	/* flag interface as "running" */
    350       1.1    briggs 	sc->sc_if.if_flags |= IFF_RUNNING;
    351       1.1    briggs 	sc->sc_if.if_flags &= ~IFF_OACTIVE;
    352       1.1    briggs 
    353       1.1    briggs 	splx(s);
    354      1.50   msaitoh 	return 0;
    355       1.1    briggs }
    356       1.1    briggs 
    357       1.1    briggs /*
    358       1.1    briggs  * close down an interface and free its buffers
    359       1.1    briggs  * Called on final close of device, or if mcinit() fails
    360       1.1    briggs  * part way through.
    361       1.1    briggs  */
    362       1.1    briggs hide int
    363      1.25       chs mcstop(struct mc_softc *sc)
    364       1.1    briggs {
    365      1.25       chs 	int s;
    366      1.50   msaitoh 
    367      1.25       chs 	s = splnet();
    368       1.1    briggs 
    369       1.1    briggs 	NIC_PUT(sc, MACE_BIUCC, SWRST);
    370       1.1    briggs 	DELAY(100);
    371       1.1    briggs 
    372       1.1    briggs 	sc->sc_if.if_timer = 0;
    373      1.21     bjh21 	sc->sc_if.if_flags &= ~IFF_RUNNING;
    374       1.1    briggs 
    375       1.1    briggs 	splx(s);
    376      1.50   msaitoh 	return 0;
    377       1.1    briggs }
    378       1.1    briggs 
    379       1.1    briggs /*
    380       1.1    briggs  * Called if any Tx packets remain unsent after 5 seconds,
    381       1.1    briggs  * In all cases we just reset the chip, and any retransmission
    382       1.1    briggs  * will be handled by higher level protocol timeouts.
    383       1.1    briggs  */
    384       1.1    briggs hide void
    385      1.25       chs mcwatchdog(struct ifnet *ifp)
    386       1.1    briggs {
    387       1.1    briggs 	struct mc_softc *sc = ifp->if_softc;
    388       1.1    briggs 
    389       1.1    briggs 	printf("mcwatchdog: resetting chip\n");
    390       1.1    briggs 	mcreset(sc);
    391       1.1    briggs }
    392       1.1    briggs 
    393       1.1    briggs /*
    394       1.1    briggs  * stuff packet into MACE (at splnet)
    395       1.1    briggs  */
    396       1.1    briggs integrate u_int
    397      1.25       chs maceput(struct mc_softc *sc, struct mbuf *m)
    398       1.1    briggs {
    399       1.1    briggs 	struct mbuf *n;
    400       1.1    briggs 	u_int len, totlen = 0;
    401       1.1    briggs 	u_char *buff;
    402       1.1    briggs 
    403      1.31        he 	buff = (u_char*)sc->sc_txbuf + (sc->sc_txset == 0 ? 0 : 0x800);
    404       1.1    briggs 
    405       1.1    briggs 	for (; m; m = n) {
    406       1.1    briggs 		u_char *data = mtod(m, u_char *);
    407       1.1    briggs 		len = m->m_len;
    408       1.1    briggs 		totlen += len;
    409      1.25       chs 		memcpy(buff, data, len);
    410       1.1    briggs 		buff += len;
    411      1.43  christos 		n = m_free(m);
    412       1.1    briggs 	}
    413       1.1    briggs 
    414      1.20   thorpej 	if (totlen > PAGE_SIZE)
    415      1.39       chs 		panic("%s: maceput: packet overflow", device_xname(sc->sc_dev));
    416       1.1    briggs 
    417       1.1    briggs #if 0
    418       1.1    briggs 	if (totlen < ETHERMIN + sizeof(struct ether_header)) {
    419       1.1    briggs 		int pad = ETHERMIN + sizeof(struct ether_header) - totlen;
    420      1.25       chs 		memset(sc->sc_txbuf + totlen, 0, pad);
    421       1.1    briggs 		totlen = ETHERMIN + sizeof(struct ether_header);
    422       1.1    briggs 	}
    423       1.1    briggs #endif
    424       1.1    briggs 
    425       1.1    briggs 	(*sc->sc_putpacket)(sc, totlen);
    426       1.1    briggs 
    427       1.1    briggs 	sc->sc_if.if_timer = 5;	/* 5 seconds to watch for failing to transmit */
    428      1.50   msaitoh 	return totlen;
    429       1.1    briggs }
    430       1.1    briggs 
    431       1.1    briggs void
    432      1.25       chs mcintr(void *arg)
    433       1.1    briggs {
    434       1.1    briggs struct mc_softc *sc = arg;
    435      1.50   msaitoh 	uint8_t ir;
    436       1.1    briggs 
    437       1.1    briggs 	ir = NIC_GET(sc, MACE_IR) & ~NIC_GET(sc, MACE_IMR);
    438       1.1    briggs 	if (ir & JAB) {
    439       1.1    briggs #ifdef MCDEBUG
    440      1.39       chs 		printf("%s: jabber error\n", device_xname(sc->sc_dev));
    441       1.1    briggs #endif
    442      1.53   thorpej 		if_statinc(&sc->sc_if, if_oerrors);
    443       1.1    briggs 	}
    444       1.1    briggs 
    445       1.1    briggs 	if (ir & BABL) {
    446       1.1    briggs #ifdef MCDEBUG
    447      1.39       chs 		printf("%s: babble\n", device_xname(sc->sc_dev));
    448       1.1    briggs #endif
    449      1.53   thorpej 		if_statinc(&sc->sc_if, if_oerrors);
    450       1.1    briggs 	}
    451       1.1    briggs 
    452       1.1    briggs 	if (ir & CERR) {
    453      1.14    scottr #ifdef MCDEBUG
    454      1.39       chs 		printf("%s: collision error\n", device_xname(sc->sc_dev));
    455      1.14    scottr #endif
    456      1.53   thorpej 		if_statinc(&sc->sc_if, if_collisions);
    457       1.1    briggs 	}
    458       1.1    briggs 
    459       1.1    briggs 	/*
    460       1.1    briggs 	 * Pretend we have carrier; if we don't this will be cleared
    461       1.1    briggs 	 * shortly.
    462       1.1    briggs 	 */
    463      1.56       roy 	const int ocarrier = sc->sc_havecarrier;
    464       1.1    briggs 	sc->sc_havecarrier = 1;
    465       1.1    briggs 
    466       1.1    briggs 	if (ir & XMTINT)
    467       1.1    briggs 		mc_tint(sc);
    468       1.1    briggs 
    469       1.1    briggs 	if (ir & RCVINT)
    470       1.1    briggs 		mc_rint(sc);
    471      1.56       roy 
    472      1.56       roy 	if (sc->sc_havecarrier != ocarrier)
    473      1.56       roy 		if_link_state_change(&sc->sc_if,
    474      1.56       roy 		    sc->sc_havecarrier ? LINK_STATE_UP : LINK_STATE_DOWN);
    475       1.1    briggs }
    476       1.1    briggs 
    477       1.1    briggs integrate void
    478      1.25       chs mc_tint(struct mc_softc *sc)
    479       1.1    briggs {
    480      1.50   msaitoh 	uint8_t /* xmtrc,*/ xmtfs;
    481       1.1    briggs 
    482      1.40    martin 	/* xmtrc = */ NIC_GET(sc, MACE_XMTRC);
    483       1.1    briggs 	xmtfs = NIC_GET(sc, MACE_XMTFS);
    484       1.1    briggs 
    485       1.1    briggs 	if ((xmtfs & XMTSV) == 0)
    486       1.1    briggs 		return;
    487       1.1    briggs 
    488       1.1    briggs 	if (xmtfs & UFLO) {
    489      1.39       chs 		printf("%s: underflow\n", device_xname(sc->sc_dev));
    490       1.1    briggs 		mcreset(sc);
    491       1.1    briggs 		return;
    492       1.1    briggs 	}
    493       1.1    briggs 
    494      1.53   thorpej 	net_stat_ref_t nsr = IF_STAT_GETREF(&sc->sc_if);
    495      1.53   thorpej 
    496       1.1    briggs 	if (xmtfs & LCOL) {
    497      1.39       chs 		printf("%s: late collision\n", device_xname(sc->sc_dev));
    498      1.53   thorpej 		if_statinc_ref(nsr, if_oerrors);
    499      1.53   thorpej 		if_statinc_ref(nsr, if_collisions);
    500       1.1    briggs 	}
    501       1.1    briggs 
    502       1.1    briggs 	if (xmtfs & MORE)
    503       1.1    briggs 		/* Real number is unknown. */
    504      1.55    martin 		if_statadd_ref(nsr, if_collisions, 2);
    505       1.1    briggs 	else if (xmtfs & ONE)
    506      1.53   thorpej 		if_statinc_ref(nsr, if_collisions);
    507       1.1    briggs 	else if (xmtfs & RTRY) {
    508      1.39       chs 		printf("%s: excessive collisions\n", device_xname(sc->sc_dev));
    509      1.55    martin 		if_statadd_ref(nsr, if_collisions, 16);
    510      1.53   thorpej 		if_statinc_ref(nsr, if_oerrors);
    511       1.1    briggs 	}
    512       1.1    briggs 
    513       1.1    briggs 	if (xmtfs & LCAR) {
    514       1.1    briggs 		sc->sc_havecarrier = 0;
    515      1.39       chs 		printf("%s: lost carrier\n", device_xname(sc->sc_dev));
    516      1.53   thorpej 		if_statinc_ref(nsr, if_oerrors);
    517       1.1    briggs 	}
    518       1.1    briggs 
    519      1.53   thorpej 	IF_STAT_PUTREF(&sc->sc_if);
    520      1.53   thorpej 
    521       1.1    briggs 	sc->sc_if.if_flags &= ~IFF_OACTIVE;
    522       1.1    briggs 	sc->sc_if.if_timer = 0;
    523      1.45    nonaka 	if_schedule_deferred_start(&sc->sc_if);
    524  1.56.2.1   thorpej 
    525  1.56.2.1   thorpej 	rnd_add_uint32(&sc->rnd_source, xmtfs);
    526       1.1    briggs }
    527       1.1    briggs 
    528       1.5    scottr void
    529      1.25       chs mc_rint(struct mc_softc *sc)
    530       1.1    briggs {
    531       1.1    briggs #define	rxf	sc->sc_rxframe
    532       1.1    briggs 	u_int len;
    533       1.1    briggs 
    534       1.1    briggs 	len = (rxf.rx_rcvcnt | ((rxf.rx_rcvsts & 0xf) << 8)) - 4;
    535       1.1    briggs 
    536       1.1    briggs #ifdef MCDEBUG
    537       1.1    briggs 	if (rxf.rx_rcvsts & 0xf0)
    538       1.1    briggs 		printf("%s: rcvcnt %02x rcvsts %02x rntpc 0x%02x rcvcc 0x%02x\n",
    539      1.39       chs 		    device_xname(sc->sc_dev), rxf.rx_rcvcnt, rxf.rx_rcvsts,
    540       1.1    briggs 		    rxf.rx_rntpc, rxf.rx_rcvcc);
    541       1.1    briggs #endif
    542       1.1    briggs 
    543       1.1    briggs 	if (rxf.rx_rcvsts & OFLO) {
    544      1.39       chs 		printf("%s: receive FIFO overflow\n", device_xname(sc->sc_dev));
    545      1.53   thorpej 		if_statinc(&sc->sc_if, if_ierrors);
    546       1.1    briggs 		return;
    547       1.1    briggs 	}
    548       1.1    briggs 
    549       1.1    briggs 	if (rxf.rx_rcvsts & CLSN)
    550      1.53   thorpej 		if_statinc(&sc->sc_if, if_collisions);
    551       1.1    briggs 
    552       1.1    briggs 	if (rxf.rx_rcvsts & FRAM) {
    553       1.1    briggs #ifdef MCDEBUG
    554      1.39       chs 		printf("%s: framing error\n", device_xname(sc->sc_dev));
    555       1.1    briggs #endif
    556      1.53   thorpej 		if_statinc(&sc->sc_if, if_ierrors);
    557       1.1    briggs 		return;
    558       1.1    briggs 	}
    559       1.1    briggs 
    560       1.1    briggs 	if (rxf.rx_rcvsts & FCS) {
    561       1.1    briggs #ifdef MCDEBUG
    562      1.39       chs 		printf("%s: frame control checksum error\n", device_xname(sc->sc_dev));
    563       1.1    briggs #endif
    564      1.53   thorpej 		if_statinc(&sc->sc_if, if_ierrors);
    565       1.1    briggs 		return;
    566       1.1    briggs 	}
    567       1.1    briggs 
    568       1.1    briggs 	mace_read(sc, rxf.rx_frame, len);
    569  1.56.2.1   thorpej 
    570  1.56.2.1   thorpej 	rnd_add_uint32(&sc->rnd_source, rxf.rx_rcvsts);
    571       1.1    briggs #undef	rxf
    572       1.1    briggs }
    573       1.1    briggs 
    574       1.1    briggs integrate void
    575      1.30  christos mace_read(struct mc_softc *sc, void *pkt, int len)
    576       1.1    briggs {
    577       1.1    briggs 	struct ifnet *ifp = &sc->sc_if;
    578       1.1    briggs 	struct mbuf *m;
    579       1.1    briggs 
    580       1.1    briggs 	if (len <= sizeof(struct ether_header) ||
    581       1.1    briggs 	    len > ETHERMTU + sizeof(struct ether_header)) {
    582       1.1    briggs #ifdef MCDEBUG
    583       1.1    briggs 		printf("%s: invalid packet size %d; dropping\n",
    584      1.39       chs 		    device_xname(sc->sc_dev), len);
    585       1.1    briggs #endif
    586      1.53   thorpej 		if_statinc(ifp, if_ierrors);
    587       1.1    briggs 		return;
    588       1.1    briggs 	}
    589       1.1    briggs 
    590       1.1    briggs 	m = mace_get(sc, pkt, len);
    591       1.1    briggs 	if (m == NULL) {
    592      1.53   thorpej 		if_statinc(ifp, if_ierrors);
    593       1.1    briggs 		return;
    594       1.1    briggs 	}
    595       1.1    briggs 
    596      1.13   thorpej 	/* Pass the packet up. */
    597      1.41     ozaki 	if_percpuq_enqueue(ifp->if_percpuq, m);
    598       1.1    briggs }
    599       1.1    briggs 
    600       1.1    briggs /*
    601       1.1    briggs  * Pull data off an interface.
    602       1.1    briggs  * Len is length of data, with local net header stripped.
    603       1.1    briggs  * We copy the data into mbufs.  When full cluster sized units are present
    604       1.1    briggs  * we copy into clusters.
    605       1.1    briggs  */
    606       1.1    briggs integrate struct mbuf *
    607      1.30  christos mace_get(struct mc_softc *sc, void *pkt, int totlen)
    608       1.1    briggs {
    609      1.25       chs 	struct mbuf *m;
    610       1.1    briggs 	struct mbuf *top, **mp;
    611       1.1    briggs 	int len;
    612       1.1    briggs 
    613       1.1    briggs 	MGETHDR(m, M_DONTWAIT, MT_DATA);
    614       1.1    briggs 	if (m == 0)
    615      1.50   msaitoh 		return 0;
    616      1.42     ozaki 	m_set_rcvif(m, &sc->sc_if);
    617       1.1    briggs 	m->m_pkthdr.len = totlen;
    618       1.1    briggs 	len = MHLEN;
    619       1.1    briggs 	top = 0;
    620       1.1    briggs 	mp = &top;
    621       1.1    briggs 
    622       1.1    briggs 	while (totlen > 0) {
    623       1.1    briggs 		if (top) {
    624       1.1    briggs 			MGET(m, M_DONTWAIT, MT_DATA);
    625       1.1    briggs 			if (m == 0) {
    626       1.1    briggs 				m_freem(top);
    627       1.1    briggs 				return 0;
    628       1.1    briggs 			}
    629       1.1    briggs 			len = MLEN;
    630       1.1    briggs 		}
    631       1.1    briggs 		if (totlen >= MINCLSIZE) {
    632       1.1    briggs 			MCLGET(m, M_DONTWAIT);
    633       1.1    briggs 			if ((m->m_flags & M_EXT) == 0) {
    634       1.1    briggs 				m_free(m);
    635       1.1    briggs 				m_freem(top);
    636       1.1    briggs 				return 0;
    637       1.1    briggs 			}
    638       1.1    briggs 			len = MCLBYTES;
    639       1.1    briggs 		}
    640      1.48  riastrad 		m->m_len = len = uimin(totlen, len);
    641      1.30  christos 		memcpy(mtod(m, void *), pkt, len);
    642      1.31        he 		pkt = (char*)pkt + len;
    643       1.1    briggs 		totlen -= len;
    644       1.1    briggs 		*mp = m;
    645       1.1    briggs 		mp = &m->m_next;
    646       1.1    briggs 	}
    647       1.1    briggs 
    648      1.50   msaitoh 	return top;
    649       1.1    briggs }
    650       1.1    briggs 
    651       1.1    briggs /*
    652       1.1    briggs  * Go through the list of multicast addresses and calculate the logical
    653       1.1    briggs  * address filter.
    654       1.1    briggs  */
    655       1.1    briggs void
    656      1.50   msaitoh mace_calcladrf(struct ethercom *ec, uint8_t *af)
    657       1.1    briggs {
    658      1.50   msaitoh 	struct ifnet *ifp = &ec->ec_if;
    659       1.1    briggs 	struct ether_multi *enm;
    660      1.25       chs 	u_char *cp;
    661      1.50   msaitoh 	uint32_t crc;
    662      1.50   msaitoh 	static const uint32_t crctab[] = {
    663       1.6   mycroft 		0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
    664       1.6   mycroft 		0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
    665       1.6   mycroft 		0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
    666       1.6   mycroft 		0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
    667       1.6   mycroft 	};
    668      1.25       chs 	int len;
    669       1.1    briggs 	struct ether_multistep step;
    670       1.1    briggs 
    671       1.1    briggs 	/*
    672       1.1    briggs 	 * Set up multicast address filter by passing all multicast addresses
    673       1.1    briggs 	 * through a crc generator, and then using the high order 6 bits as an
    674       1.1    briggs 	 * index into the 64 bit logical address filter.  The high order bit
    675       1.1    briggs 	 * selects the word, while the rest of the bits select the bit within
    676       1.1    briggs 	 * the word.
    677       1.1    briggs 	 */
    678       1.1    briggs 
    679      1.50   msaitoh 	*((uint32_t *)af) = *((uint32_t *)af + 1) = 0;
    680      1.51   msaitoh 	ETHER_LOCK(ec);
    681      1.50   msaitoh 	ETHER_FIRST_MULTI(step, ec, enm);
    682       1.1    briggs 	while (enm != NULL) {
    683       1.1    briggs 		if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) {
    684       1.1    briggs 			/*
    685       1.1    briggs 			 * We must listen to a range of multicast addresses.
    686       1.1    briggs 			 * For now, just accept all multicasts, rather than
    687       1.1    briggs 			 * trying to set only those filter bits needed to match
    688       1.1    briggs 			 * the range.  (At this time, the only use of address
    689       1.1    briggs 			 * ranges is for IP multicast routing, for which the
    690       1.1    briggs 			 * range is big enough to require all bits set.)
    691       1.1    briggs 			 */
    692      1.51   msaitoh 			ETHER_UNLOCK(ec);
    693       1.1    briggs 			goto allmulti;
    694       1.1    briggs 		}
    695       1.1    briggs 
    696       1.1    briggs 		cp = enm->enm_addrlo;
    697       1.1    briggs 		crc = 0xffffffff;
    698       1.1    briggs 		for (len = sizeof(enm->enm_addrlo); --len >= 0;) {
    699       1.6   mycroft 			crc ^= *cp++;
    700       1.6   mycroft 			crc = (crc >> 4) ^ crctab[crc & 0xf];
    701       1.6   mycroft 			crc = (crc >> 4) ^ crctab[crc & 0xf];
    702       1.1    briggs 		}
    703       1.1    briggs 		/* Just want the 6 most significant bits. */
    704       1.1    briggs 		crc >>= 26;
    705       1.1    briggs 
    706       1.1    briggs 		/* Set the corresponding bit in the filter. */
    707       1.1    briggs 		af[crc >> 3] |= 1 << (crc & 7);
    708       1.1    briggs 
    709       1.1    briggs 		ETHER_NEXT_MULTI(step, enm);
    710       1.1    briggs 	}
    711      1.51   msaitoh 	ETHER_UNLOCK(ec);
    712       1.1    briggs 	ifp->if_flags &= ~IFF_ALLMULTI;
    713       1.1    briggs 	return;
    714       1.1    briggs 
    715       1.1    briggs allmulti:
    716       1.1    briggs 	ifp->if_flags |= IFF_ALLMULTI;
    717      1.50   msaitoh 	*((uint32_t *)af) = *((uint32_t *)af + 1) = 0xffffffff;
    718       1.1    briggs }
    719       1.1    briggs 
    720       1.1    briggs static u_char bbr4[] = {0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15};
    721       1.1    briggs #define bbr(v)  ((bbr4[(v)&0xf] << 4) | bbr4[((v)>>4) & 0xf])
    722       1.1    briggs 
    723       1.1    briggs u_char
    724      1.25       chs mc_get_enaddr(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
    725      1.25       chs     u_char *dst)
    726       1.1    briggs {
    727       1.1    briggs 	int	i;
    728       1.1    briggs 	u_char	b, csum;
    729       1.1    briggs 
    730       1.1    briggs 	/*
    731       1.1    briggs 	 * The XOR of the 8 bytes of the ROM must be 0xff for it to be
    732       1.1    briggs 	 * valid
    733       1.1    briggs 	*/
    734       1.1    briggs 	for (i = 0, csum = 0; i < 8; i++) {
    735       1.1    briggs 		b = bus_space_read_1(t, h, o+16*i);
    736       1.1    briggs 		if (i < ETHER_ADDR_LEN)
    737       1.1    briggs 			dst[i] = bbr(b);
    738       1.1    briggs 		csum ^= b;
    739       1.1    briggs 	}
    740       1.1    briggs 
    741       1.1    briggs 	return csum;
    742       1.1    briggs }
    743