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