Home | History | Annotate | Line # | Download | only in ic
lemac.c revision 1.5
      1  1.5   mycroft /* $NetBSD: lemac.c,v 1.5 1998/03/29 22:34:28 mycroft Exp $ */
      2  1.1      matt 
      3  1.1      matt /*-
      4  1.1      matt  * Copyright (c) 1994, 1995, 1997 Matt Thomas <matt (at) 3am-software.com>
      5  1.1      matt  * All rights reserved.
      6  1.1      matt  *
      7  1.1      matt  * Redistribution and use in source and binary forms, with or without
      8  1.1      matt  * modification, are permitted provided that the following conditions
      9  1.1      matt  * are met:
     10  1.1      matt  * 1. Redistributions of source code must retain the above copyright
     11  1.1      matt  *    notice, this list of conditions and the following disclaimer.
     12  1.1      matt  * 2. The name of the author may not be used to endorse or promote products
     13  1.1      matt  *    derived from this software withough specific prior written permission
     14  1.1      matt  *
     15  1.1      matt  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     16  1.1      matt  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     17  1.1      matt  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     18  1.1      matt  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     19  1.1      matt  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     20  1.1      matt  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     21  1.1      matt  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     22  1.1      matt  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  1.1      matt  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     24  1.1      matt  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  1.1      matt  */
     26  1.1      matt 
     27  1.1      matt /*
     28  1.1      matt  * DEC EtherWORKS 3 Ethernet Controllers
     29  1.1      matt  *
     30  1.1      matt  * Written by Matt Thomas
     31  1.1      matt  * BPF support code stolen directly from if_ec.c
     32  1.1      matt  *
     33  1.1      matt  *   This driver supports the LEMAC DE203/204/205 cards.
     34  1.1      matt  */
     35  1.1      matt 
     36  1.2  explorer #include "rnd.h"
     37  1.2  explorer 
     38  1.1      matt #include <sys/param.h>
     39  1.1      matt #include <sys/systm.h>
     40  1.1      matt #include <sys/mbuf.h>
     41  1.1      matt #include <sys/protosw.h>
     42  1.1      matt #include <sys/socket.h>
     43  1.1      matt #include <sys/sockio.h>
     44  1.1      matt #include <sys/errno.h>
     45  1.1      matt #include <sys/malloc.h>
     46  1.1      matt #include <sys/device.h>
     47  1.2  explorer #if NRND > 0
     48  1.2  explorer #include <sys/rnd.h>
     49  1.2  explorer #endif
     50  1.1      matt 
     51  1.1      matt #include <net/if.h>
     52  1.1      matt #include <net/if_types.h>
     53  1.1      matt #include <net/if_dl.h>
     54  1.1      matt #include <net/route.h>
     55  1.1      matt #include <net/if_ether.h>
     56  1.1      matt #include <net/if_media.h>
     57  1.1      matt 
     58  1.1      matt #ifdef INET
     59  1.1      matt #include <netinet/in.h>
     60  1.1      matt #include <netinet/in_systm.h>
     61  1.1      matt #include <netinet/in_var.h>
     62  1.1      matt #include <netinet/ip.h>
     63  1.1      matt #include <netinet/if_inarp.h>
     64  1.1      matt #endif
     65  1.1      matt 
     66  1.1      matt #ifdef NS
     67  1.1      matt #include <netns/ns.h>
     68  1.1      matt #include <netns/ns_if.h>
     69  1.1      matt #endif
     70  1.1      matt 
     71  1.1      matt #include <machine/bus.h>
     72  1.1      matt 
     73  1.1      matt #include <dev/ic/lemacreg.h>
     74  1.1      matt #include <dev/ic/lemacvar.h>
     75  1.1      matt #if 0
     76  1.1      matt #include <i386/isa/decether.h>
     77  1.1      matt #endif
     78  1.1      matt 
     79  1.1      matt #include <vm/vm.h>
     80  1.1      matt 
     81  1.1      matt #include "bpfilter.h"
     82  1.1      matt #if NBPFILTER > 0
     83  1.1      matt #include <net/bpf.h>
     84  1.1      matt #endif
     85  1.1      matt 
     86  1.1      matt static void lemac_init(lemac_softc_t *sc);
     87  1.1      matt static void lemac_ifstart(struct ifnet *ifp);
     88  1.1      matt static void lemac_reset(lemac_softc_t *sc);
     89  1.1      matt static void lemac_rne_intr(lemac_softc_t *sc);
     90  1.1      matt static void lemac_tne_intr(lemac_softc_t *sc);
     91  1.1      matt static void lemac_txd_intr(lemac_softc_t *sc, unsigned cs_value);
     92  1.1      matt static void lemac_rxd_intr(lemac_softc_t *sc, unsigned cs_value);
     93  1.1      matt static int  lemac_read_eeprom(lemac_softc_t *sc);
     94  1.1      matt static void lemac_init_adapmem(lemac_softc_t *sc);
     95  1.1      matt 
     96  1.1      matt static const u_int16_t lemac_allmulti_mctbl[16] =  {
     97  1.1      matt     0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
     98  1.1      matt     0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
     99  1.1      matt     0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
    100  1.1      matt     0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
    101  1.1      matt };
    102  1.1      matt 
    103  1.1      matt /*
    104  1.1      matt  * Some tuning/monitoring variables.
    105  1.1      matt  */
    106  1.1      matt unsigned lemac_txmax = 16;
    107  1.1      matt 
    108  1.1      matt static void
    110  1.1      matt lemac_rxd_intr(
    111  1.1      matt     lemac_softc_t *sc,
    112  1.1      matt     unsigned cs_value)
    113  1.1      matt {
    114  1.1      matt     /*
    115  1.1      matt      * Handle CS_RXD (Receiver disabled) here.
    116  1.1      matt      *
    117  1.1      matt      * Check Free Memory Queue Count. If not equal to zero
    118  1.1      matt      * then just turn Receiver back on. If it is equal to
    119  1.1      matt      * zero then check to see if transmitter is disabled.
    120  1.1      matt      * Process transmit TXD loop once more.  If all else
    121  1.1      matt      * fails then do software init (0xC0 to EEPROM Init)
    122  1.1      matt      * and rebuild Free Memory Queue.
    123  1.1      matt      */
    124  1.1      matt 
    125  1.1      matt     sc->sc_cntrs.cntr_rxd_intrs++;
    126  1.1      matt 
    127  1.1      matt     /*
    128  1.1      matt      *  Re-enable Receiver.
    129  1.1      matt      */
    130  1.1      matt 
    131  1.1      matt     cs_value &= ~LEMAC_CS_RXD;
    132  1.1      matt     LEMAC_OUTB(sc, LEMAC_REG_CS, cs_value);
    133  1.1      matt 
    134  1.1      matt     if (LEMAC_INB(sc, LEMAC_REG_FMC) > 0)
    135  1.1      matt 	return;
    136  1.1      matt 
    137  1.1      matt     if (cs_value & LEMAC_CS_TXD)
    138  1.1      matt 	lemac_txd_intr(sc, cs_value);
    139  1.1      matt 
    140  1.1      matt     if ((LEMAC_INB(sc, LEMAC_REG_CS) & LEMAC_CS_RXD) == 0)
    141  1.1      matt 	return;
    142  1.1      matt 
    143  1.1      matt     printf("%s: fatal RXD error, attempting recovery\n", sc->sc_if.if_xname);
    144  1.1      matt 
    145  1.1      matt     lemac_reset(sc);
    146  1.1      matt     if (sc->sc_if.if_flags & IFF_UP) {
    147  1.1      matt 	lemac_init(sc);
    148  1.1      matt 	return;
    149  1.1      matt     }
    150  1.1      matt 
    151  1.1      matt     /*
    152  1.1      matt      *  Error during initializion.  Mark card as disabled.
    153  1.1      matt      */
    154  1.1      matt     printf("%s: recovery failed -- board disabled\n", sc->sc_if.if_xname);
    155  1.1      matt }
    156  1.1      matt 
    157  1.1      matt static void
    159  1.1      matt lemac_tne_intr(
    160  1.1      matt     lemac_softc_t *sc)
    161  1.1      matt {
    162  1.1      matt     unsigned txcount = LEMAC_INB(sc, LEMAC_REG_TDC);
    163  1.1      matt 
    164  1.1      matt     sc->sc_cntrs.cntr_tne_intrs++;
    165  1.1      matt     while (txcount-- > 0) {
    166  1.1      matt 	unsigned txsts = LEMAC_INB(sc, LEMAC_REG_TDQ);
    167  1.1      matt 	sc->sc_if.if_opackets++;		/* another one done */
    168  1.1      matt 	if ((txsts & (LEMAC_TDQ_LCL|LEMAC_TDQ_NCL))
    169  1.1      matt 	        || (txsts & LEMAC_TDQ_COL) == LEMAC_TDQ_EXCCOL) {
    170  1.1      matt 	    if (txsts & LEMAC_TDQ_NCL)
    171  1.1      matt 		sc->sc_flags &= ~LEMAC_LINKUP;
    172  1.1      matt 	    sc->sc_if.if_oerrors++;
    173  1.1      matt 	} else {
    174  1.1      matt 	    sc->sc_flags |= LEMAC_LINKUP;
    175  1.1      matt 	    if ((txsts & LEMAC_TDQ_COL) != LEMAC_TDQ_NOCOL)
    176  1.1      matt 		sc->sc_if.if_collisions++;
    177  1.1      matt 	}
    178  1.1      matt     }
    179  1.1      matt     sc->sc_if.if_flags &= ~IFF_OACTIVE;
    180  1.1      matt     lemac_ifstart(&sc->sc_if);
    181  1.1      matt }
    182  1.1      matt 
    183  1.1      matt static void
    184  1.1      matt lemac_txd_intr(
    185  1.1      matt     lemac_softc_t *sc,
    186  1.1      matt     unsigned cs_value)
    187  1.1      matt {
    188  1.1      matt     /*
    189  1.1      matt      * Read transmit status, remove transmit buffer from
    190  1.1      matt      * transmit queue and place on free memory queue,
    191  1.1      matt      * then reset transmitter.
    192  1.1      matt      * Increment appropriate counters.
    193  1.1      matt      */
    194  1.1      matt 
    195  1.1      matt     sc->sc_cntrs.cntr_txd_intrs++;
    196  1.1      matt     if (sc->sc_txctl & LEMAC_TX_STP) {
    197  1.1      matt 	sc->sc_if.if_oerrors++;
    198  1.1      matt 	/* return page to free queue */
    199  1.1      matt 	LEMAC_OUTB(sc, LEMAC_REG_FMQ, LEMAC_INB(sc, LEMAC_REG_TDQ));
    200  1.1      matt     }
    201  1.1      matt 
    202  1.1      matt     /* Turn back on transmitter if disabled */
    203  1.1      matt     LEMAC_OUTB(sc, LEMAC_REG_CS, cs_value & ~LEMAC_CS_TXD);
    204  1.1      matt     sc->sc_if.if_flags &= ~IFF_OACTIVE;
    205  1.1      matt }
    206  1.1      matt 
    207  1.1      matt static int
    209  1.1      matt lemac_read_eeprom(
    210  1.1      matt     lemac_softc_t *sc)
    211  1.1      matt {
    212  1.1      matt     int	word_off, cksum;
    213  1.1      matt 
    214  1.1      matt     u_char *ep;
    215  1.1      matt 
    216  1.1      matt     cksum = 0;
    217  1.1      matt     ep = sc->sc_eeprom;
    218  1.1      matt     for (word_off = 0; word_off < LEMAC_EEP_SIZE / 2; word_off++) {
    219  1.1      matt 	LEMAC_OUTB(sc, LEMAC_REG_PI1, word_off);
    220  1.1      matt 	LEMAC_OUTB(sc, LEMAC_REG_IOP, LEMAC_IOP_EEREAD);
    221  1.1      matt 
    222  1.1      matt 	DELAY(LEMAC_EEP_DELAY);
    223  1.1      matt 
    224  1.1      matt 	*ep = LEMAC_INB(sc, LEMAC_REG_EE1);	cksum += *ep++;
    225  1.1      matt 	*ep = LEMAC_INB(sc, LEMAC_REG_EE2);	cksum += *ep++;
    226  1.1      matt     }
    227  1.1      matt 
    228  1.1      matt     /*
    229  1.1      matt      *  Set up Transmit Control Byte for use later during transmit.
    230  1.1      matt      */
    231  1.1      matt 
    232  1.1      matt     sc->sc_txctl |= LEMAC_TX_FLAGS;
    233  1.1      matt 
    234  1.1      matt     if ((sc->sc_eeprom[LEMAC_EEP_SWFLAGS] & LEMAC_EEP_SW_SQE) == 0)
    235  1.1      matt 	sc->sc_txctl &= ~LEMAC_TX_SQE;
    236  1.1      matt 
    237  1.1      matt     if (sc->sc_eeprom[LEMAC_EEP_SWFLAGS] & LEMAC_EEP_SW_LAB)
    238  1.1      matt 	sc->sc_txctl |= LEMAC_TX_LAB;
    239  1.1      matt 
    240  1.1      matt     bcopy(&sc->sc_eeprom[LEMAC_EEP_PRDNM], sc->sc_prodname, LEMAC_EEP_PRDNMSZ);
    241  1.1      matt     sc->sc_prodname[LEMAC_EEP_PRDNMSZ] = '\0';
    242  1.1      matt 
    243  1.1      matt     return cksum % 256;
    244  1.1      matt }
    245  1.1      matt 
    246  1.1      matt static void
    248  1.1      matt lemac_init_adapmem(
    249  1.1      matt     lemac_softc_t *sc)
    250  1.1      matt {
    251  1.1      matt     int pg, conf;
    252  1.1      matt 
    253  1.1      matt     conf = LEMAC_INB(sc, LEMAC_REG_CNF);
    254  1.1      matt 
    255  1.1      matt     if ((sc->sc_eeprom[LEMAC_EEP_SETUP] & LEMAC_EEP_ST_DRAM) == 0) {
    256  1.1      matt 	sc->sc_lastpage = 63;
    257  1.1      matt 	conf &= ~LEMAC_CNF_DRAM;
    258  1.1      matt     } else {
    259  1.1      matt 	sc->sc_lastpage = 127;
    260  1.1      matt 	conf |= LEMAC_CNF_DRAM;
    261  1.1      matt     }
    262  1.1      matt 
    263  1.1      matt     LEMAC_OUTB(sc, LEMAC_REG_CNF, conf);
    264  1.1      matt 
    265  1.1      matt     for (pg = 1; pg <= sc->sc_lastpage; pg++)
    266  1.1      matt 	LEMAC_OUTB(sc, LEMAC_REG_FMQ, pg);
    267  1.1      matt }
    268  1.1      matt 
    269  1.1      matt static void
    271  1.1      matt lemac_input(
    272  1.1      matt     lemac_softc_t *sc,
    273  1.1      matt     bus_addr_t offset,
    274  1.1      matt     size_t length)
    275  1.1      matt {
    276  1.1      matt     struct ether_header eh;
    277  1.1      matt     struct mbuf *m;
    278  1.1      matt 
    279  1.1      matt     if (length - sizeof(eh) > ETHERMTU
    280  1.1      matt 	    || length - sizeof(eh) < ETHERMIN) {
    281  1.1      matt 	sc->sc_if.if_ierrors++;
    282  1.1      matt 	return;
    283  1.1      matt     }
    284  1.1      matt     if (LEMAC_USE_PIO_MODE(sc)) {
    285  1.1      matt 	LEMAC_INSB(sc, LEMAC_REG_DAT, sizeof(eh), (void *) &eh);
    286  1.1      matt     } else {
    287  1.1      matt 	LEMAC_GETBUF16(sc, offset, sizeof(eh) / 2, (void *) &eh);
    288  1.1      matt     }
    289  1.1      matt 
    290  1.1      matt     /*
    291  1.1      matt      * If this is single cast but not to us
    292  1.1      matt      * drop it!
    293  1.1      matt      */
    294  1.1      matt     if ((eh.ether_dhost[0] & 1) == 0
    295  1.1      matt #if NBPFILTER > 0
    296  1.1      matt 	    && (sc->sc_if.if_flags & IFF_PROMISC) == 0
    297  1.1      matt #endif
    298  1.1      matt 	    && !LEMAC_ADDREQUAL(eh.ether_dhost, LLADDR(sc->sc_if.if_sadl)))
    299  1.1      matt 	return;
    300  1.1      matt 
    301  1.1      matt     MGETHDR(m, M_DONTWAIT, MT_DATA);
    302  1.1      matt     if (m == NULL) {
    303  1.1      matt 	sc->sc_if.if_ierrors++;
    304  1.1      matt 	return;
    305  1.1      matt     }
    306  1.1      matt     if (length + 2 > MHLEN) {
    307  1.1      matt 	MCLGET(m, M_DONTWAIT);
    308  1.1      matt 	if ((m->m_flags & M_EXT) == 0) {
    309  1.1      matt 	    m_free(m);
    310  1.1      matt 	    sc->sc_if.if_ierrors++;
    311  1.1      matt 	    return;
    312  1.1      matt 	}
    313  1.1      matt     }
    314  1.1      matt     m->m_data += 2;
    315  1.1      matt     bcopy((caddr_t)&eh, m->m_data, sizeof(eh));
    316  1.1      matt     if (LEMAC_USE_PIO_MODE(sc)) {
    317  1.1      matt 	LEMAC_INSB(sc, LEMAC_REG_DAT, length - sizeof(eh),
    318  1.1      matt 		   mtod(m, caddr_t) + sizeof(eh));
    319  1.1      matt     } else {
    320  1.1      matt 	LEMAC_GETBUF16(sc, offset + sizeof(eh), (length - sizeof(eh)) / 2,
    321  1.1      matt 		      (void *) (mtod(m, caddr_t) + sizeof(eh)));
    322  1.1      matt 	if (length & 1)
    323  1.1      matt 	    m->m_data[length - 1] = LEMAC_GET8(sc, offset + length - 1);
    324  1.1      matt     }
    325  1.1      matt #if NBPFILTER > 0
    326  1.1      matt     if (sc->sc_if.if_bpf != NULL) {
    327  1.1      matt 	m->m_pkthdr.len = m->m_len = length;
    328  1.1      matt 	bpf_mtap(sc->sc_if.if_bpf, m);
    329  1.1      matt     }
    330  1.1      matt     /*
    331  1.1      matt      * If this is single cast but not to us
    332  1.1      matt      * drop it!
    333  1.1      matt      */
    334  1.1      matt     if ((eh.ether_dhost[0] & 1) == 0
    335  1.1      matt 	   && !LEMAC_ADDREQUAL(eh.ether_dhost, LLADDR(sc->sc_if.if_sadl))) {
    336  1.1      matt 	m_freem(m);
    337  1.1      matt 	return;
    338  1.1      matt     }
    339  1.1      matt #endif
    340  1.1      matt     m->m_pkthdr.len = m->m_len = length - sizeof(eh);
    341  1.1      matt     m->m_data += sizeof(eh);
    342  1.1      matt     m->m_pkthdr.rcvif = &sc->sc_if;
    343  1.1      matt     ether_input(&sc->sc_if, &eh, m);
    344  1.1      matt }
    345  1.1      matt 
    346  1.1      matt static void
    348  1.1      matt lemac_rne_intr(
    349  1.1      matt     lemac_softc_t *sc)
    350  1.1      matt {
    351  1.1      matt     int rxcount;
    352  1.1      matt 
    353  1.1      matt     sc->sc_cntrs.cntr_rne_intrs++;
    354  1.1      matt     rxcount = LEMAC_INB(sc, LEMAC_REG_RQC);
    355  1.1      matt     while (rxcount--) {
    356  1.1      matt 	unsigned rxpg = LEMAC_INB(sc, LEMAC_REG_RQ);
    357  1.1      matt 	u_int32_t rxlen;
    358  1.1      matt 
    359  1.1      matt 	sc->sc_if.if_ipackets++;
    360  1.1      matt 	if (LEMAC_USE_PIO_MODE(sc)) {
    361  1.1      matt 	    LEMAC_OUTB(sc, LEMAC_REG_IOP, rxpg);
    362  1.1      matt 	    LEMAC_OUTB(sc, LEMAC_REG_PI1, 0);
    363  1.1      matt 	    LEMAC_OUTB(sc, LEMAC_REG_PI2, 0);
    364  1.1      matt 	    LEMAC_INSB(sc, LEMAC_REG_DAT, sizeof(rxlen), (void *) &rxlen);
    365  1.1      matt 	} else {
    366  1.1      matt 	    LEMAC_OUTB(sc, LEMAC_REG_MPN, rxpg);
    367  1.1      matt 	    rxlen = LEMAC_GET32(sc, 0);
    368  1.1      matt 	}
    369  1.1      matt 	if (rxlen & LEMAC_RX_OK) {
    370  1.1      matt 	    sc->sc_flags |= LEMAC_LINKUP;
    371  1.1      matt 	    /*
    372  1.1      matt 	     * Get receive length - subtract out checksum.
    373  1.1      matt 	     */
    374  1.1      matt 	    rxlen = ((rxlen >> 8) & 0x7FF) - 4;
    375  1.1      matt 	    lemac_input(sc, sizeof(rxlen), rxlen);
    376  1.1      matt 	} else {
    377  1.1      matt 	    sc->sc_if.if_ierrors++;
    378  1.1      matt 	}
    379  1.1      matt 	LEMAC_OUTB(sc, LEMAC_REG_FMQ, rxpg);  /* Return this page to Free Memory Queue */
    380  1.1      matt     }  /* end while (recv_count--) */
    381  1.1      matt 
    382  1.1      matt     return;
    383  1.1      matt }
    384  1.1      matt 
    385  1.1      matt /*
    387  1.1      matt  *  This is the standard method of reading the DEC Address ROMS.
    388  1.1      matt  *  I don't understand it but it does work.
    389  1.1      matt  */
    390  1.1      matt static int
    391  1.1      matt lemac_read_macaddr(
    392  1.1      matt     unsigned char *hwaddr,
    393  1.1      matt     const bus_space_tag_t iot,
    394  1.1      matt     const bus_space_handle_t ioh,
    395  1.1      matt     const bus_addr_t ioreg,
    396  1.1      matt     int skippat)
    397  1.1      matt {
    398  1.1      matt     int cksum, rom_cksum;
    399  1.1      matt     unsigned char addrbuf[6];
    400  1.1      matt 
    401  1.1      matt     if (!skippat) {
    402  1.1      matt 	int idx, idx2, found, octet;
    403  1.1      matt 	static u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA };
    404  1.1      matt 	idx2 = found = 0;
    405  1.1      matt 
    406  1.1      matt 	for (idx = 0; idx < 32; idx++) {
    407  1.1      matt 	    octet = bus_space_read_1(iot, ioh, ioreg);
    408  1.1      matt 
    409  1.1      matt 	    if (octet == testpat[idx2]) {
    410  1.1      matt 		if (++idx2 == sizeof(testpat)) {
    411  1.1      matt 		    ++found;
    412  1.1      matt 		    break;
    413  1.1      matt 		}
    414  1.1      matt 	    } else {
    415  1.1      matt 		idx2 = 0;
    416  1.1      matt 	    }
    417  1.1      matt 	}
    418  1.1      matt 
    419  1.1      matt 	if (!found)
    420  1.1      matt 	    return -1;
    421  1.1      matt     }
    422  1.1      matt 
    423  1.1      matt     if (hwaddr == NULL)
    424  1.1      matt 	hwaddr = addrbuf;
    425  1.1      matt 
    426  1.1      matt     cksum = 0;
    427  1.1      matt     hwaddr[0] = bus_space_read_1(iot, ioh, ioreg);
    428  1.1      matt     hwaddr[1] = bus_space_read_1(iot, ioh, ioreg);
    429  1.1      matt 
    430  1.1      matt     /* hardware adddress can't be multicast */
    431  1.1      matt     if (hwaddr[0] & 1)
    432  1.1      matt 	return -1;
    433  1.1      matt 
    434  1.1      matt     cksum = *(u_short *) &hwaddr[0];
    435  1.1      matt 
    436  1.1      matt     hwaddr[2] = bus_space_read_1(iot, ioh, ioreg);
    437  1.1      matt     hwaddr[3] = bus_space_read_1(iot, ioh, ioreg);
    438  1.1      matt     cksum *= 2;
    439  1.1      matt     if (cksum > 65535) cksum -= 65535;
    440  1.1      matt     cksum += *(u_short *) &hwaddr[2];
    441  1.1      matt     if (cksum > 65535) cksum -= 65535;
    442  1.1      matt 
    443  1.1      matt     hwaddr[4] = bus_space_read_1(iot, ioh, ioreg);
    444  1.1      matt     hwaddr[5] = bus_space_read_1(iot, ioh, ioreg);
    445  1.1      matt     cksum *= 2;
    446  1.1      matt     if (cksum > 65535) cksum -= 65535;
    447  1.1      matt     cksum += *(u_short *) &hwaddr[4];
    448  1.1      matt     if (cksum >= 65535) cksum -= 65535;
    449  1.1      matt 
    450  1.1      matt     /* 00-00-00 is an illegal OUI */
    451  1.1      matt     if (hwaddr[0] == 0 && hwaddr[1] == 0 && hwaddr[2] == 0)
    452  1.1      matt 	return -1;
    453  1.1      matt 
    454  1.1      matt     rom_cksum = bus_space_read_1(iot, ioh, ioreg);
    455  1.1      matt     rom_cksum |= bus_space_read_1(iot, ioh, ioreg) << 8;
    456  1.1      matt 
    457  1.1      matt     if (cksum != rom_cksum)
    458  1.1      matt 	return -1;
    459  1.1      matt     return 0;
    460  1.1      matt }
    461  1.5   mycroft 
    462  1.5   mycroft static void
    464  1.5   mycroft lemac_multicast_op(
    465  1.5   mycroft     u_int16_t *mctbl,
    466  1.5   mycroft     const u_char *mca,
    467  1.5   mycroft     int enable)
    468  1.1      matt {
    469  1.4   mycroft     u_int idx, crc = 0xFFFFFFFFUL;
    470  1.5   mycroft     static u_int crctab[] = {
    471  1.5   mycroft 	0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
    472  1.5   mycroft 	0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
    473  1.4   mycroft 	0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
    474  1.1      matt 	0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
    475  1.1      matt     };
    476  1.1      matt 
    477  1.1      matt     for (idx = 0; idx < 6; idx++) {
    478  1.1      matt 	crc ^= *mca++;
    479  1.1      matt 	crc = (crc >> 4) ^ crctab[crc & 0xf];
    480  1.1      matt 	crc = (crc >> 4) ^ crctab[crc & 0xf];
    481  1.1      matt     }
    482  1.1      matt     /*
    483  1.1      matt      * The following two lines convert the N bit index into a longword index
    484  1.1      matt      * and a longword mask.
    485  1.1      matt      */
    486  1.1      matt #if LEMAC_MCTBL_BITS < 0
    487  1.1      matt     crc >>= (32 + LEMAC_MCTBL_BITS);
    488  1.1      matt     crc &= (1 << -LEMAC_MCTBL_BITS) - 1;
    489  1.1      matt #else
    490  1.1      matt     crc &= (1 << LEMAC_MCTBL_BITS) - 1;
    491  1.1      matt #endif
    492  1.1      matt     bit = 1 << (crc & 0x0F);
    493  1.1      matt     idx = crc >> 4;
    494  1.1      matt 
    495  1.1      matt     /*
    496  1.1      matt      * Set or clear hash filter bit in our table.
    497  1.1      matt      */
    498  1.1      matt     if (enable) {
    499  1.1      matt 	mctbl[idx] |= bit;		/* Set Bit */
    500  1.1      matt     } else {
    501  1.1      matt 	mctbl[idx] &= ~bit;		/* Clear Bit */
    502  1.1      matt     }
    503  1.1      matt }
    504  1.1      matt 
    505  1.1      matt static void
    507  1.1      matt lemac_multicast_filter(
    508  1.1      matt     lemac_softc_t *sc)
    509  1.1      matt {
    510  1.1      matt     struct ether_multistep step;
    511  1.1      matt     struct ether_multi *enm;
    512  1.1      matt 
    513  1.1      matt     bzero(sc->sc_mctbl, LEMAC_MCTBL_BITS / 8);
    514  1.1      matt 
    515  1.1      matt     lemac_multicast_op(sc->sc_mctbl, etherbroadcastaddr, TRUE);
    516  1.1      matt 
    517  1.1      matt     ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
    518  1.1      matt     while (enm != NULL) {
    519  1.1      matt 	if (!LEMAC_ADDREQUAL(enm->enm_addrlo, enm->enm_addrhi)) {
    520  1.1      matt 	    sc->sc_flags |= LEMAC_ALLMULTI;
    521  1.1      matt 	    sc->sc_if.if_flags |= IFF_ALLMULTI;
    522  1.1      matt 	    return;
    523  1.1      matt 	}
    524  1.1      matt 	lemac_multicast_op(sc->sc_mctbl, enm->enm_addrlo, TRUE);
    525  1.1      matt 	ETHER_NEXT_MULTI(step, enm);
    526  1.1      matt     }
    527  1.1      matt     sc->sc_flags &= ~LEMAC_ALLMULTI;
    528  1.1      matt     sc->sc_if.if_flags &= ~IFF_ALLMULTI;
    529  1.1      matt }
    530  1.1      matt 
    531  1.1      matt /*
    533  1.1      matt  * Do a hard reset of the board;
    534  1.1      matt  */
    535  1.1      matt static void
    536  1.1      matt lemac_reset(
    537  1.1      matt     lemac_softc_t * const sc)
    538  1.1      matt {
    539  1.1      matt     unsigned data;
    540  1.1      matt 
    541  1.1      matt     /*
    542  1.1      matt      * Initialize board..
    543  1.1      matt      */
    544  1.1      matt     sc->sc_flags &= ~LEMAC_LINKUP;
    545  1.1      matt     sc->sc_if.if_flags &= ~IFF_OACTIVE;
    546  1.1      matt     LEMAC_INTR_DISABLE(sc);
    547  1.1      matt 
    548  1.1      matt     LEMAC_OUTB(sc, LEMAC_REG_IOP, LEMAC_IOP_EEINIT);
    549  1.1      matt     DELAY(LEMAC_EEP_DELAY);
    550  1.1      matt 
    551  1.1      matt     /*
    552  1.1      matt      * Read EEPROM information.  NOTE - the placement of this function
    553  1.1      matt      * is important because functions hereafter may rely on information
    554  1.1      matt      * read from the EEPROM.
    555  1.1      matt      */
    556  1.1      matt     if ((data = lemac_read_eeprom(sc)) != LEMAC_EEP_CKSUM) {
    557  1.1      matt 	printf("%s: reset: EEPROM checksum failed (0x%x)\n",
    558  1.1      matt 	       sc->sc_if.if_xname, data);
    559  1.1      matt 	return;
    560  1.1      matt     }
    561  1.1      matt 
    562  1.1      matt     /*
    563  1.1      matt      * Update the control register to reflect the media choice
    564  1.1      matt      */
    565  1.1      matt     data = LEMAC_INB(sc, LEMAC_REG_CTL);
    566  1.1      matt     if ((data & (LEMAC_CTL_APD|LEMAC_CTL_PSL)) != sc->sc_ctlmode) {
    567  1.1      matt 	data &= ~(LEMAC_CTL_APD|LEMAC_CTL_PSL);
    568  1.1      matt 	data |= sc->sc_ctlmode;
    569  1.1      matt 	LEMAC_OUTB(sc, LEMAC_REG_CTL, data);
    570  1.1      matt     }
    571  1.1      matt 
    572  1.1      matt     /*
    573  1.1      matt      *  Force to 2K mode if not already configured.
    574  1.1      matt      */
    575  1.1      matt 
    576  1.1      matt     data = LEMAC_INB(sc, LEMAC_REG_MBR);
    577  1.1      matt     if (LEMAC_IS_2K_MODE(data)) {
    578  1.1      matt 	sc->sc_flags |= LEMAC_2K_MODE;
    579  1.1      matt     } else if (LEMAC_IS_64K_MODE(data)) {
    580  1.1      matt 	data = (((data * 2) & 0xF) << 4);
    581  1.1      matt 	sc->sc_flags |= LEMAC_WAS_64K_MODE;
    582  1.1      matt 	LEMAC_OUTB(sc, LEMAC_REG_MBR, data);
    583  1.1      matt     } else if (LEMAC_IS_32K_MODE(data)) {
    584  1.1      matt 	data = ((data & 0xF) << 4);
    585  1.1      matt 	sc->sc_flags |= LEMAC_WAS_32K_MODE;
    586  1.1      matt 	LEMAC_OUTB(sc, LEMAC_REG_MBR, data);
    587  1.1      matt     } else {
    588  1.1      matt 	sc->sc_flags |= LEMAC_PIO_MODE;
    589  1.1      matt 	/* PIO mode */
    590  1.1      matt     }
    591  1.1      matt 
    592  1.1      matt     /*
    593  1.1      matt      *  Initialize Free Memory Queue, Init mcast table with broadcast.
    594  1.1      matt      */
    595  1.1      matt 
    596  1.1      matt     lemac_init_adapmem(sc);
    597  1.1      matt     sc->sc_flags |= LEMAC_ALIVE;
    598  1.1      matt }
    599  1.1      matt 
    600  1.1      matt static void
    602  1.1      matt lemac_init(
    603  1.1      matt     lemac_softc_t * const sc)
    604  1.1      matt {
    605  1.1      matt     if ((sc->sc_flags & LEMAC_ALIVE) == 0)
    606  1.1      matt 	return;
    607  1.1      matt 
    608  1.1      matt     /*
    609  1.1      matt      * If the interface has the up flag
    610  1.1      matt      */
    611  1.1      matt     if (sc->sc_if.if_flags & IFF_UP) {
    612  1.1      matt 	int saved_cs = LEMAC_INB(sc, LEMAC_REG_CS);
    613  1.1      matt 	LEMAC_OUTB(sc, LEMAC_REG_CS, saved_cs | (LEMAC_CS_TXD | LEMAC_CS_RXD));
    614  1.1      matt 	LEMAC_OUTB(sc, LEMAC_REG_PA0, LLADDR(sc->sc_if.if_sadl)[0]);
    615  1.1      matt 	LEMAC_OUTB(sc, LEMAC_REG_PA1, LLADDR(sc->sc_if.if_sadl)[1]);
    616  1.1      matt 	LEMAC_OUTB(sc, LEMAC_REG_PA2, LLADDR(sc->sc_if.if_sadl)[2]);
    617  1.1      matt 	LEMAC_OUTB(sc, LEMAC_REG_PA3, LLADDR(sc->sc_if.if_sadl)[3]);
    618  1.1      matt 	LEMAC_OUTB(sc, LEMAC_REG_PA4, LLADDR(sc->sc_if.if_sadl)[4]);
    619  1.1      matt 	LEMAC_OUTB(sc, LEMAC_REG_PA5, LLADDR(sc->sc_if.if_sadl)[5]);
    620  1.1      matt 
    621  1.1      matt 	LEMAC_OUTB(sc, LEMAC_REG_IC, LEMAC_INB(sc, LEMAC_REG_IC) | LEMAC_IC_IE);
    622  1.1      matt 
    623  1.1      matt 	if (sc->sc_if.if_flags & IFF_PROMISC) {
    624  1.1      matt 	    LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_MCE | LEMAC_CS_PME);
    625  1.1      matt 	} else {
    626  1.1      matt 	    LEMAC_INTR_DISABLE(sc);
    627  1.1      matt 	    lemac_multicast_filter(sc);
    628  1.1      matt 	    if (sc->sc_flags & LEMAC_ALLMULTI)
    629  1.1      matt 		bcopy(lemac_allmulti_mctbl, sc->sc_mctbl, sizeof(sc->sc_mctbl));
    630  1.1      matt 	    if (LEMAC_USE_PIO_MODE(sc)) {
    631  1.1      matt 		LEMAC_OUTB(sc, LEMAC_REG_IOP, 0);
    632  1.1      matt 		LEMAC_OUTB(sc, LEMAC_REG_PI1, LEMAC_MCTBL_OFF & 0xFF);
    633  1.1      matt 		LEMAC_OUTB(sc, LEMAC_REG_PI2, LEMAC_MCTBL_OFF >> 8);
    634  1.1      matt 		LEMAC_OUTSB(sc, LEMAC_REG_DAT, sizeof(sc->sc_mctbl), (void *) sc->sc_mctbl);
    635  1.1      matt 	    } else {
    636  1.1      matt 		LEMAC_OUTB(sc, LEMAC_REG_MPN, 0);
    637  1.1      matt 		LEMAC_PUTBUF8(sc, LEMAC_MCTBL_OFF, sizeof(sc->sc_mctbl), (void *) sc->sc_mctbl);
    638  1.1      matt 	    }
    639  1.1      matt 
    640  1.1      matt 	    LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_MCE);
    641  1.1      matt 	}
    642  1.1      matt 
    643  1.1      matt 	LEMAC_OUTB(sc, LEMAC_REG_CTL, LEMAC_INB(sc, LEMAC_REG_CTL) ^ LEMAC_CTL_LED);
    644  1.1      matt 
    645  1.1      matt 	LEMAC_INTR_ENABLE(sc);
    646  1.1      matt 	sc->sc_if.if_flags |= IFF_RUNNING;
    647  1.1      matt 	lemac_ifstart(&sc->sc_if);
    648  1.1      matt     } else {
    649  1.1      matt 	LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_RXD|LEMAC_CS_TXD);
    650  1.1      matt 
    651  1.1      matt 	LEMAC_INTR_DISABLE(sc);
    652  1.1      matt 	sc->sc_if.if_flags &= ~IFF_RUNNING;
    653  1.1      matt     }
    654  1.1      matt }
    655  1.1      matt 
    656  1.1      matt static void
    658  1.1      matt lemac_ifstart(
    659  1.1      matt     struct ifnet *ifp)
    660  1.1      matt {
    661  1.1      matt     lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp);
    662  1.1      matt     struct ifqueue * const ifq = &ifp->if_snd;
    663  1.1      matt 
    664  1.1      matt     if ((ifp->if_flags & IFF_RUNNING) == 0)
    665  1.1      matt 	return;
    666  1.1      matt 
    667  1.1      matt     LEMAC_INTR_DISABLE(sc);
    668  1.1      matt 
    669  1.1      matt     while (ifq->ifq_head != NULL) {
    670  1.1      matt 	struct mbuf *m;
    671  1.1      matt 	struct mbuf *m0;
    672  1.1      matt 	int tx_pg;
    673  1.1      matt 
    674  1.1      matt 	if ((sc->sc_csr.csr_tqc = LEMAC_INB(sc, LEMAC_REG_TQC)) >= lemac_txmax) {
    675  1.1      matt 	    sc->sc_cntrs.cntr_txfull++;
    676  1.1      matt 	    ifp->if_flags |= IFF_OACTIVE;
    677  1.1      matt 	    break;
    678  1.1      matt 	}
    679  1.1      matt 
    680  1.1      matt 	/*
    681  1.1      matt 	 * get free memory page
    682  1.1      matt 	 */
    683  1.1      matt 	tx_pg = sc->sc_csr.csr_fmq = LEMAC_INB(sc, LEMAC_REG_FMQ);
    684  1.1      matt 	/*
    685  1.1      matt 	 * Check for good transmit page.
    686  1.1      matt 	 */
    687  1.1      matt 	if (tx_pg == 0 || tx_pg > sc->sc_lastpage) {
    688  1.1      matt 	    sc->sc_cntrs.cntr_txnospc++;
    689  1.1      matt 	    ifp->if_flags |= IFF_OACTIVE;
    690  1.1      matt 	    break;
    691  1.1      matt 	}
    692  1.1      matt 
    693  1.1      matt 	IF_DEQUEUE(ifq, m);
    694  1.1      matt 
    695  1.1      matt 	/*
    696  1.1      matt 	 * The first four bytes of each transmit buffer are for
    697  1.1      matt 	 * control information.  The first byte is the control
    698  1.1      matt 	 * byte, then the length (why not word aligned??), then
    699  1.1      matt 	 * the offset to the buffer.
    700  1.1      matt 	 */
    701  1.1      matt 
    702  1.1      matt 	if (LEMAC_USE_PIO_MODE(sc)) {
    703  1.1      matt 	    LEMAC_OUTB(sc, LEMAC_REG_IOP, tx_pg);	/* Shift 2K window. */
    704  1.1      matt 	    LEMAC_OUTB(sc, LEMAC_REG_PI1, 0);
    705  1.1      matt 	    LEMAC_OUTB(sc, LEMAC_REG_PI2, 0);
    706  1.1      matt 	    LEMAC_OUTB(sc, LEMAC_REG_DAT, sc->sc_txctl);
    707  1.1      matt 	    LEMAC_OUTB(sc, LEMAC_REG_DAT, (m->m_pkthdr.len >> 0) & 0xFF);
    708  1.1      matt 	    LEMAC_OUTB(sc, LEMAC_REG_DAT, (m->m_pkthdr.len >> 8) & 0xFF);
    709  1.1      matt 	    LEMAC_OUTB(sc, LEMAC_REG_DAT, LEMAC_TX_HDRSZ);
    710  1.1      matt 	    for (m0 = m; m0 != NULL; m0 = m0->m_next)
    711  1.1      matt 		LEMAC_OUTSB(sc, LEMAC_REG_DAT, m0->m_len, m0->m_data);
    712  1.1      matt 	} else {
    713  1.1      matt 	    bus_size_t txoff = /* (mtod(m, u_int32_t) & (sizeof(u_int32_t) - 1)) + */ LEMAC_TX_HDRSZ;
    714  1.1      matt 	    LEMAC_OUTB(sc, LEMAC_REG_MPN, tx_pg);	/* Shift 2K window. */
    715  1.1      matt 	    LEMAC_PUT8(sc, 0, sc->sc_txctl);
    716  1.1      matt 	    LEMAC_PUT8(sc, 1, (m->m_pkthdr.len >> 0) & 0xFF);
    717  1.1      matt 	    LEMAC_PUT8(sc, 2, (m->m_pkthdr.len >> 8) & 0xFF);
    718  1.1      matt 	    LEMAC_PUT8(sc, 3, txoff);
    719  1.1      matt 
    720  1.1      matt 	    /*
    721  1.1      matt 	     * Copy the packet to the board
    722  1.1      matt 	     */
    723  1.1      matt 	    for (m0 = m; m0 != NULL; m0 = m0->m_next) {
    724  1.1      matt #if 0
    725  1.1      matt 		LEMAC_PUTBUF8(sc, txoff, m0->m_len, m0->m_data);
    726  1.1      matt 		txoff += m0->m_len;
    727  1.1      matt #else
    728  1.1      matt 		const u_int8_t *cp = m0->m_data;
    729  1.1      matt 		int len = m0->m_len;
    730  1.1      matt #if 0
    731  1.1      matt 		if ((txoff & 3) == (((long)cp) & 3) && len >= 4) {
    732  1.1      matt 		    if (txoff & 3) {
    733  1.1      matt 			int alen = (~txoff & 3);
    734  1.1      matt 			LEMAC_PUTBUF8(sc, txoff, alen, cp);
    735  1.1      matt 			cp += alen; txoff += alen; len -= alen;
    736  1.1      matt 		    }
    737  1.1      matt 		    if (len >= 4) {
    738  1.1      matt 			LEMAC_PUTBUF32(sc, txoff, len / 4, cp);
    739  1.1      matt 			cp += len & ~3; txoff += len & ~3; len &= 3;
    740  1.1      matt 		    }
    741  1.1      matt 		}
    742  1.1      matt #endif
    743  1.1      matt 		if ((txoff & 1) == (((long)cp) & 1) && len >= 2) {
    744  1.1      matt 		    if (txoff & 1) {
    745  1.1      matt 			int alen = (~txoff & 1);
    746  1.1      matt 			LEMAC_PUTBUF8(sc, txoff, alen, cp);
    747  1.1      matt 			cp += alen; txoff += alen; len -= alen;
    748  1.1      matt 		    }
    749  1.1      matt 		    if (len >= 2) {
    750  1.1      matt 			LEMAC_PUTBUF16(sc, txoff, len / 2, (void *) cp);
    751  1.1      matt 			cp += len & ~1; txoff += len & ~1; len &= 1;
    752  1.1      matt 		    }
    753  1.1      matt 		}
    754  1.1      matt 		if (len > 0) {
    755  1.1      matt 		    LEMAC_PUTBUF8(sc, txoff, len, cp);
    756  1.1      matt 		    txoff += len;
    757  1.1      matt 		}
    758  1.1      matt #endif
    759  1.1      matt 	    }
    760  1.1      matt 	}
    761  1.1      matt 
    762  1.1      matt 	LEMAC_OUTB(sc, LEMAC_REG_TQ, tx_pg);	/* tell chip to transmit this packet */
    763  1.1      matt #if NBPFILTER > 0
    764  1.1      matt 	if (sc->sc_if.if_bpf != NULL)
    765  1.1      matt 	    bpf_mtap(sc->sc_if.if_bpf, m);
    766  1.1      matt #endif
    767  1.1      matt 	m_freem(m);			/* free the mbuf */
    768  1.1      matt     }
    769  1.1      matt     LEMAC_INTR_ENABLE(sc);
    770  1.1      matt }
    771  1.1      matt 
    772  1.1      matt static int
    774  1.1      matt lemac_ifioctl(
    775  1.1      matt     struct ifnet *ifp,
    776  1.1      matt     u_long cmd,
    777  1.1      matt     caddr_t data)
    778  1.1      matt {
    779  1.1      matt     lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp);
    780  1.1      matt     int s;
    781  1.1      matt     int error = 0;
    782  1.1      matt 
    783  1.1      matt     s = splnet();
    784  1.1      matt 
    785  1.1      matt     switch (cmd) {
    786  1.1      matt 	case SIOCSIFADDR: {
    787  1.1      matt 	    struct ifaddr *ifa = (struct ifaddr *)data;
    788  1.1      matt 
    789  1.1      matt 	    ifp->if_flags |= IFF_UP;
    790  1.1      matt 	    lemac_init(sc);
    791  1.1      matt 	    switch (ifa->ifa_addr->sa_family) {
    792  1.1      matt #ifdef INET
    793  1.1      matt 		case AF_INET: {
    794  1.1      matt 		    arp_ifinit(&sc->sc_if, ifa);
    795  1.1      matt 		    break;
    796  1.1      matt 		}
    797  1.1      matt #endif /* INET */
    798  1.1      matt 
    799  1.1      matt #ifdef NS
    800  1.1      matt 		/* This magic copied from if_is.c; I don't use XNS,
    801  1.1      matt 		 * so I have no way of telling if this actually
    802  1.1      matt 		 * works or not.
    803  1.1      matt 		 */
    804  1.1      matt 		case AF_NS: {
    805  1.1      matt 		    struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
    806  1.1      matt 		    if (ns_nullhost(*ina)) {
    807  1.1      matt 			ina->x_host = *(union ns_host *)LLADDR(ifp->if_sadl);
    808  1.1      matt 		    } else {
    809  1.1      matt 			bcopy((caddr_t)ina->x_host.c_host,
    810  1.1      matt 			      LLADDR(ifp->if_sadl), ifp->if_addrlen);
    811  1.1      matt 		    }
    812  1.1      matt 		    break;
    813  1.1      matt 		}
    814  1.1      matt #endif /* NS */
    815  1.1      matt 
    816  1.1      matt 		default: {
    817  1.1      matt 		    break;
    818  1.1      matt 		}
    819  1.1      matt 	    }
    820  1.1      matt 	    break;
    821  1.1      matt 	}
    822  1.1      matt 
    823  1.1      matt 	case SIOCSIFFLAGS: {
    824  1.1      matt 	    lemac_init(sc);
    825  1.1      matt 	    break;
    826  1.1      matt 	}
    827  1.1      matt 
    828  1.1      matt 	case SIOCADDMULTI:
    829  1.1      matt 	case SIOCDELMULTI: {
    830  1.1      matt 	    /*
    831  1.1      matt 	     * Update multicast listeners
    832  1.1      matt 	     */
    833  1.1      matt 	    if (cmd == SIOCADDMULTI)
    834  1.1      matt 		error = ether_addmulti((struct ifreq *)data, &sc->sc_ec);
    835  1.1      matt 	    else
    836  1.1      matt 		error = ether_delmulti((struct ifreq *)data, &sc->sc_ec);
    837  1.1      matt 
    838  1.1      matt 	    if (error == ENETRESET) {
    839  1.1      matt 
    840  1.1      matt 		/* reset multicast filtering */
    841  1.1      matt 		lemac_init(sc);
    842  1.1      matt 		error = 0;
    843  1.1      matt 	    }
    844  1.1      matt 	    break;
    845  1.1      matt 	}
    846  1.1      matt 
    847  1.1      matt 	case SIOCSIFMEDIA:
    848  1.1      matt 	case SIOCGIFMEDIA: {
    849  1.1      matt 	    error = ifmedia_ioctl(ifp, (struct ifreq *)data,
    850  1.1      matt 				  &sc->sc_ifmedia, cmd);
    851  1.1      matt 	    break;
    852  1.1      matt 	}
    853  1.1      matt 
    854  1.1      matt 	default: {
    855  1.1      matt 	    error = EINVAL;
    856  1.1      matt 	    break;
    857  1.1      matt 	}
    858  1.1      matt     }
    859  1.1      matt 
    860  1.1      matt     splx(s);
    861  1.1      matt     return error;
    862  1.1      matt }
    863  1.1      matt 
    864  1.1      matt static int
    866  1.1      matt lemac_ifmedia_change(
    867  1.1      matt     struct ifnet * const ifp)
    868  1.1      matt {
    869  1.1      matt     lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp);
    870  1.1      matt     unsigned new_ctl;
    871  1.1      matt 
    872  1.1      matt     switch (IFM_SUBTYPE(sc->sc_ifmedia.ifm_media)) {
    873  1.1      matt 	case IFM_10_T: new_ctl = LEMAC_CTL_APD; break;
    874  1.1      matt 	case IFM_10_2:
    875  1.1      matt 	case IFM_10_5: new_ctl = LEMAC_CTL_APD|LEMAC_CTL_PSL; break;
    876  1.1      matt 	case IFM_AUTO: new_ctl = 0; break;
    877  1.1      matt 	default:       return EINVAL;
    878  1.1      matt     }
    879  1.1      matt     if (sc->sc_ctlmode != new_ctl) {
    880  1.1      matt 	sc->sc_ctlmode = new_ctl;
    881  1.1      matt 	lemac_reset(sc);
    882  1.1      matt 	if (sc->sc_if.if_flags & IFF_UP)
    883  1.1      matt 	    lemac_init(sc);
    884  1.1      matt     }
    885  1.1      matt     return 0;
    886  1.1      matt }
    887  1.1      matt 
    888  1.1      matt /*
    889  1.1      matt  * Media status callback
    890  1.1      matt  */
    891  1.1      matt static void
    892  1.1      matt lemac_ifmedia_status(
    893  1.1      matt     struct ifnet * const ifp,
    894  1.1      matt     struct ifmediareq *req)
    895  1.1      matt {
    896  1.1      matt     lemac_softc_t *sc = LEMAC_IFP_TO_SOFTC(ifp);
    897  1.1      matt     unsigned data = LEMAC_INB(sc, LEMAC_REG_CNF);
    898  1.1      matt 
    899  1.1      matt     req->ifm_status = IFM_AVALID;
    900  1.1      matt     if (sc->sc_flags & LEMAC_LINKUP)
    901  1.1      matt 	req->ifm_status |= IFM_ACTIVE;
    902  1.1      matt 
    903  1.1      matt     if (sc->sc_ctlmode & LEMAC_CTL_APD) {
    904  1.1      matt 	if (sc->sc_ctlmode & LEMAC_CTL_PSL) {
    905  1.1      matt 	    req->ifm_active = IFM_10_5;
    906  1.1      matt 	} else {
    907  1.1      matt 	    req->ifm_active = IFM_10_T;
    908  1.1      matt 	}
    909  1.1      matt     } else {
    910  1.1      matt 	/*
    911  1.1      matt 	 * The link bit of the configuration register reflects the
    912  1.1      matt 	 * current media choice when auto-port is enabled.
    913  1.1      matt 	 */
    914  1.1      matt 	if (data & LEMAC_CNF_NOLINK) {
    915  1.1      matt 	    req->ifm_active = IFM_10_5;
    916  1.1      matt 	} else {
    917  1.1      matt 	    req->ifm_active = IFM_10_T;
    918  1.1      matt 	}
    919  1.1      matt     }
    920  1.1      matt 
    921  1.1      matt     req->ifm_active |= IFM_ETHER;
    922  1.1      matt }
    923  1.1      matt 
    924  1.1      matt int
    926  1.1      matt lemac_port_check(
    927  1.1      matt     const bus_space_tag_t iot,
    928  1.1      matt     const bus_space_handle_t ioh)
    929  1.1      matt {
    930  1.1      matt     unsigned char hwaddr[6];
    931  1.1      matt 
    932  1.1      matt     if (lemac_read_macaddr(hwaddr, iot, ioh, LEMAC_REG_APD, 0) == 0)
    933  1.1      matt 	return 1;
    934  1.1      matt     if (lemac_read_macaddr(hwaddr, iot, ioh, LEMAC_REG_APD, 1) == 0)
    935  1.1      matt 	return 1;
    936  1.1      matt     return 0;
    937  1.1      matt }
    938  1.1      matt 
    939  1.1      matt void
    941  1.1      matt lemac_info_get(
    942  1.1      matt     const bus_space_tag_t iot,
    943  1.1      matt     const bus_space_handle_t ioh,
    944  1.1      matt     bus_addr_t *maddr_p,
    945  1.1      matt     bus_size_t *msize_p,
    946  1.1      matt     int *irq_p)
    947  1.1      matt {
    948  1.1      matt     unsigned data;
    949  1.1      matt 
    950  1.1      matt     *irq_p = LEMAC_DECODEIRQ(bus_space_read_1(iot, ioh, LEMAC_REG_IC) & LEMAC_IC_IRQMSK);
    951  1.1      matt 
    952  1.1      matt     data = bus_space_read_1(iot, ioh, LEMAC_REG_MBR);
    953  1.1      matt     if (LEMAC_IS_2K_MODE(data)) {
    954  1.1      matt 	*maddr_p = data * (2 * 1024) + (512 * 1024);
    955  1.1      matt 	*msize_p =  2 * 1024;
    956  1.1      matt     } else if (LEMAC_IS_64K_MODE(data)) {
    957  1.1      matt 	*maddr_p = data * 64 * 1024;
    958  1.1      matt 	*msize_p = 64 * 1024;
    959  1.1      matt     } else if (LEMAC_IS_32K_MODE(data)) {
    960  1.1      matt 	*maddr_p = data * 32 * 1024;
    961  1.1      matt 	*msize_p = 32* 1024;
    962  1.1      matt     } else {
    963  1.1      matt 	*maddr_p = 0;
    964  1.1      matt 	*msize_p = 0;
    965  1.1      matt     }
    966  1.1      matt }
    967  1.1      matt 
    968  1.1      matt /*
    970  1.1      matt  * What to do upon receipt of an interrupt.
    971  1.1      matt  */
    972  1.1      matt int
    973  1.1      matt lemac_intr(
    974  1.1      matt     void *arg)
    975  1.1      matt {
    976  1.1      matt     lemac_softc_t * const sc = arg;
    977  1.1      matt     int cs_value;
    978  1.1      matt 
    979  1.1      matt     LEMAC_INTR_DISABLE(sc);	/* Mask interrupts */
    980  1.1      matt 
    981  1.1      matt     /*
    982  1.1      matt      * Determine cause of interrupt.  Receive events take
    983  1.1      matt      * priority over Transmit.
    984  1.1      matt      */
    985  1.1      matt 
    986  1.1      matt     cs_value = LEMAC_INB(sc, LEMAC_REG_CS);
    987  1.1      matt 
    988  1.1      matt     /*
    989  1.1      matt      * Check for Receive Queue not being empty.
    990  1.1      matt      * Check for Transmit Done Queue not being empty.
    991  1.1      matt      */
    992  1.1      matt 
    993  1.1      matt     if (cs_value & LEMAC_CS_RNE)
    994  1.1      matt 	lemac_rne_intr(sc);
    995  1.1      matt     if (cs_value & LEMAC_CS_TNE)
    996  1.1      matt 	lemac_tne_intr(sc);
    997  1.1      matt 
    998  1.1      matt     /*
    999  1.2  explorer      * Check for Transmitter Disabled.
   1000  1.2  explorer      * Check for Receiver Disabled.
   1001  1.2  explorer      */
   1002  1.2  explorer 
   1003  1.2  explorer     if (cs_value & LEMAC_CS_TXD)
   1004  1.2  explorer 	lemac_txd_intr(sc, cs_value);
   1005  1.1      matt     if (cs_value & LEMAC_CS_RXD)
   1006  1.1      matt 	lemac_rxd_intr(sc, cs_value);
   1007  1.1      matt 
   1008  1.1      matt     /*
   1009  1.1      matt      * Toggle LED and unmask interrupts.
   1010  1.1      matt      */
   1011  1.1      matt 
   1012  1.1      matt     sc->sc_csr.csr_cs = LEMAC_INB(sc, LEMAC_REG_CS);
   1013  1.1      matt 
   1014  1.1      matt     LEMAC_OUTB(sc, LEMAC_REG_CTL, LEMAC_INB(sc, LEMAC_REG_CTL) ^ LEMAC_CTL_LED);
   1015  1.1      matt     LEMAC_INTR_ENABLE(sc);		/* Unmask interrupts */
   1016  1.1      matt 
   1017  1.1      matt #if NRND > 0
   1018  1.1      matt     if (cs_value)
   1019  1.1      matt         rnd_add_uint32(&sc->rnd_source, cs_value);
   1020  1.1      matt #endif
   1021  1.1      matt 
   1022  1.1      matt     return 1;
   1023  1.1      matt }
   1024  1.1      matt 
   1025  1.1      matt void
   1026  1.1      matt lemac_shutdown(
   1027  1.1      matt     void *arg)
   1028  1.1      matt {
   1029  1.1      matt     lemac_reset((lemac_softc_t *) arg);
   1030  1.1      matt }
   1031  1.1      matt 
   1032  1.1      matt static const char * const lemac_modes[4] = {
   1034  1.1      matt     "PIO mode (internal 2KB window)",
   1035  1.1      matt     "2KB window",
   1036  1.1      matt     "changed 32KB window to 2KB",
   1037  1.1      matt     "changed 64KB window to 2KB",
   1038  1.1      matt };
   1039  1.1      matt 
   1040  1.1      matt void
   1041  1.1      matt lemac_ifattach(
   1042  1.1      matt     lemac_softc_t *sc)
   1043  1.1      matt {
   1044  1.1      matt     struct ifnet * const ifp = &sc->sc_if;
   1045  1.1      matt 
   1046  1.1      matt     bcopy(sc->sc_dv.dv_xname, ifp->if_xname, IFNAMSIZ);
   1047  1.1      matt 
   1048  1.1      matt     lemac_reset(sc);
   1049  1.1      matt 
   1050  1.1      matt     (void) lemac_read_macaddr(sc->sc_enaddr, sc->sc_iot, sc->sc_ioh,
   1051  1.1      matt 			      LEMAC_REG_APD, 0);
   1052  1.1      matt 
   1053  1.1      matt     printf(": %s\n", sc->sc_prodname);
   1054  1.1      matt 
   1055  1.1      matt     printf("%s: address %s, %dKB RAM, %s\n",
   1056  1.1      matt 	   ifp->if_xname,
   1057  1.1      matt 	   ether_sprintf(sc->sc_enaddr),
   1058  1.1      matt 	   sc->sc_lastpage * 2 + 2,
   1059  1.1      matt 	   lemac_modes[sc->sc_flags & LEMAC_MODE_MASK]);
   1060  1.1      matt 
   1061  1.1      matt     ifp->if_baudrate = 10000000;
   1062  1.1      matt     ifp->if_softc = (void *) sc;
   1063  1.1      matt     ifp->if_start = lemac_ifstart;
   1064  1.2  explorer     ifp->if_output = ether_output;
   1065  1.2  explorer     ifp->if_ioctl = lemac_ifioctl;
   1066  1.2  explorer 
   1067  1.2  explorer     ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX
   1068  1.2  explorer #ifdef IFF_NOTRAILERS
   1069  1.1      matt 	| IFF_NOTRAILERS
   1070  1.1      matt #endif
   1071  1.1      matt 	| IFF_MULTICAST;
   1072  1.1      matt 
   1073  1.1      matt     if (sc->sc_flags & LEMAC_ALIVE) {
   1074  1.1      matt 	int media;
   1075  1.1      matt 
   1076  1.1      matt 	if_attach(ifp);
   1077  1.1      matt 	ether_ifattach(ifp, sc->sc_enaddr);
   1078  1.1      matt 
   1079  1.1      matt #if NBPFILTER > 0
   1080  1.1      matt 	bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
   1081  1.1      matt #endif
   1082  1.1      matt 
   1083  1.1      matt #if NRND > 0
   1084  1.1      matt 	rnd_attach_source(&sc->rnd_source, sc->sc_dv.dv_xname, RND_TYPE_NET);
   1085  1.1      matt #endif
   1086  1.1      matt 
   1087  1.1      matt 	ifmedia_init(&sc->sc_ifmedia, 0,
   1088                		     lemac_ifmedia_change,
   1089                		     lemac_ifmedia_status);
   1090                	if (sc->sc_prodname[4] == '5')	/* DE205 is UTP/AUI */
   1091                	    ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0, 0);
   1092                	if (sc->sc_prodname[4] != '3')	/* DE204 & 205 have UTP */
   1093                	    ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_T, 0, 0);
   1094                	if (sc->sc_prodname[4] != '4')	/* DE203 & 205 have BNC */
   1095                	    ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_5, 0, 0);
   1096                	switch (sc->sc_prodname[4]) {
   1097                	    case '3': media = IFM_10_5; break;
   1098                	    case '4': media = IFM_10_T; break;
   1099                	    default:  media = IFM_AUTO; break;
   1100                	}
   1101                	ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | media);
   1102                    } else {
   1103                	printf("%s: disabled due to error\n", ifp->if_xname);
   1104                    }
   1105                }
   1106