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