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