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