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