Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / dev / ic / lemac.c
blob3cc66d86a7642335a58e0d260d8b9f01059b6c39
1 /* $NetBSD: lemac.c,v 1.35 2008/04/08 12:07:26 cegger Exp $ */
3 /*-
4 * Copyright (c) 1994, 1995, 1997 Matt Thomas <matt@3am-software.com>
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * DEC EtherWORKS 3 Ethernet Controllers
30 * Written by Matt Thomas
31 * BPF support code stolen directly from if_ec.c
33 * This driver supports the LEMAC DE203/204/205 cards.
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: lemac.c,v 1.35 2008/04/08 12:07:26 cegger Exp $");
39 #include "opt_inet.h"
40 #include "rnd.h"
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/mbuf.h>
45 #include <sys/protosw.h>
46 #include <sys/socket.h>
47 #include <sys/sockio.h>
48 #include <sys/errno.h>
49 #include <sys/malloc.h>
50 #include <sys/device.h>
51 #if NRND > 0
52 #include <sys/rnd.h>
53 #endif
55 #include <net/if.h>
56 #include <net/if_types.h>
57 #include <net/if_dl.h>
58 #include <net/route.h>
59 #include <net/if_ether.h>
60 #include <net/if_media.h>
62 #ifdef INET
63 #include <netinet/in.h>
64 #include <netinet/in_systm.h>
65 #include <netinet/in_var.h>
66 #include <netinet/ip.h>
67 #include <netinet/if_inarp.h>
68 #endif
71 #include <sys/bus.h>
73 #include <dev/ic/lemacreg.h>
74 #include <dev/ic/lemacvar.h>
75 #if 0
76 #include <i386/isa/decether.h>
77 #endif
79 #include <uvm/uvm_extern.h>
81 #include "bpfilter.h"
82 #if NBPFILTER > 0
83 #include <net/bpf.h>
84 #endif
86 static void lemac_init(lemac_softc_t *sc);
87 static void lemac_ifstart(struct ifnet *ifp);
88 static void lemac_reset(lemac_softc_t *sc);
89 static void lemac_rne_intr(lemac_softc_t *sc);
90 static void lemac_tne_intr(lemac_softc_t *sc);
91 static void lemac_txd_intr(lemac_softc_t *sc, unsigned cs_value);
92 static void lemac_rxd_intr(lemac_softc_t *sc, unsigned cs_value);
93 static int lemac_read_eeprom(lemac_softc_t *sc);
94 static void lemac_init_adapmem(lemac_softc_t *sc);
96 static const u_int16_t lemac_allmulti_mctbl[LEMAC_MCTBL_SIZE/sizeof(u_int16_t)] = {
97 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
98 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
99 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
100 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
101 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
102 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
103 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
104 0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
108 * Some tuning/monitoring variables.
110 unsigned lemac_txmax = 16;
112 static void
113 lemac_rxd_intr(
114 lemac_softc_t *sc,
115 unsigned cs_value)
118 * Handle CS_RXD (Receiver disabled) here.
120 * Check Free Memory Queue Count. If not equal to zero
121 * then just turn Receiver back on. If it is equal to
122 * zero then check to see if transmitter is disabled.
123 * Process transmit TXD loop once more. If all else
124 * fails then do software init (0xC0 to EEPROM Init)
125 * and rebuild Free Memory Queue.
128 sc->sc_cntrs.cntr_rxd_intrs++;
131 * Re-enable Receiver.
134 cs_value &= ~LEMAC_CS_RXD;
135 LEMAC_OUTB(sc, LEMAC_REG_CS, cs_value);
137 if (LEMAC_INB(sc, LEMAC_REG_FMC) > 0)
138 return;
140 if (cs_value & LEMAC_CS_TXD)
141 lemac_txd_intr(sc, cs_value);
143 if ((LEMAC_INB(sc, LEMAC_REG_CS) & LEMAC_CS_RXD) == 0)
144 return;
146 printf("%s: fatal RXD error, attempting recovery\n", sc->sc_if.if_xname);
148 lemac_reset(sc);
149 if (sc->sc_if.if_flags & IFF_UP) {
150 lemac_init(sc);
151 return;
155 * Error during initialization. Mark card as disabled.
157 printf("%s: recovery failed -- board disabled\n", sc->sc_if.if_xname);
160 static void
161 lemac_tne_intr(
162 lemac_softc_t *sc)
164 unsigned txcount = LEMAC_INB(sc, LEMAC_REG_TDC);
166 sc->sc_cntrs.cntr_tne_intrs++;
167 while (txcount-- > 0) {
168 unsigned txsts = LEMAC_INB(sc, LEMAC_REG_TDQ);
169 sc->sc_if.if_opackets++; /* another one done */
170 if ((txsts & (LEMAC_TDQ_LCL|LEMAC_TDQ_NCL))
171 || (txsts & LEMAC_TDQ_COL) == LEMAC_TDQ_EXCCOL) {
172 if (txsts & LEMAC_TDQ_NCL)
173 sc->sc_flags &= ~LEMAC_LINKUP;
174 sc->sc_if.if_oerrors++;
175 } else {
176 sc->sc_flags |= LEMAC_LINKUP;
177 if ((txsts & LEMAC_TDQ_COL) != LEMAC_TDQ_NOCOL)
178 sc->sc_if.if_collisions++;
181 sc->sc_if.if_flags &= ~IFF_OACTIVE;
182 lemac_ifstart(&sc->sc_if);
185 static void
186 lemac_txd_intr(
187 lemac_softc_t *sc,
188 unsigned cs_value)
191 * Read transmit status, remove transmit buffer from
192 * transmit queue and place on free memory queue,
193 * then reset transmitter.
194 * Increment appropriate counters.
197 sc->sc_cntrs.cntr_txd_intrs++;
198 if (sc->sc_txctl & LEMAC_TX_STP) {
199 sc->sc_if.if_oerrors++;
200 /* return page to free queue */
201 LEMAC_OUTB(sc, LEMAC_REG_FMQ, LEMAC_INB(sc, LEMAC_REG_TDQ));
204 /* Turn back on transmitter if disabled */
205 LEMAC_OUTB(sc, LEMAC_REG_CS, cs_value & ~LEMAC_CS_TXD);
206 sc->sc_if.if_flags &= ~IFF_OACTIVE;
209 static int
210 lemac_read_eeprom(
211 lemac_softc_t *sc)
213 int word_off, cksum;
215 u_char *ep;
217 cksum = 0;
218 ep = sc->sc_eeprom;
219 for (word_off = 0; word_off < LEMAC_EEP_SIZE / 2; word_off++) {
220 LEMAC_OUTB(sc, LEMAC_REG_PI1, word_off);
221 LEMAC_OUTB(sc, LEMAC_REG_IOP, LEMAC_IOP_EEREAD);
223 DELAY(LEMAC_EEP_DELAY);
225 *ep = LEMAC_INB(sc, LEMAC_REG_EE1); cksum += *ep++;
226 *ep = LEMAC_INB(sc, LEMAC_REG_EE2); cksum += *ep++;
230 * Set up Transmit Control Byte for use later during transmit.
233 sc->sc_txctl |= LEMAC_TX_FLAGS;
235 if ((sc->sc_eeprom[LEMAC_EEP_SWFLAGS] & LEMAC_EEP_SW_SQE) == 0)
236 sc->sc_txctl &= ~LEMAC_TX_SQE;
238 if (sc->sc_eeprom[LEMAC_EEP_SWFLAGS] & LEMAC_EEP_SW_LAB)
239 sc->sc_txctl |= LEMAC_TX_LAB;
241 memcpy(sc->sc_prodname, &sc->sc_eeprom[LEMAC_EEP_PRDNM], LEMAC_EEP_PRDNMSZ);
242 sc->sc_prodname[LEMAC_EEP_PRDNMSZ] = '\0';
244 return cksum % 256;
247 static void
248 lemac_init_adapmem(
249 lemac_softc_t *sc)
251 int pg, conf;
253 conf = LEMAC_INB(sc, LEMAC_REG_CNF);
255 if ((sc->sc_eeprom[LEMAC_EEP_SETUP] & LEMAC_EEP_ST_DRAM) == 0) {
256 sc->sc_lastpage = 63;
257 conf &= ~LEMAC_CNF_DRAM;
258 } else {
259 sc->sc_lastpage = 127;
260 conf |= LEMAC_CNF_DRAM;
263 LEMAC_OUTB(sc, LEMAC_REG_CNF, conf);
265 for (pg = 1; pg <= sc->sc_lastpage; pg++)
266 LEMAC_OUTB(sc, LEMAC_REG_FMQ, pg);
269 static void
270 lemac_input(
271 lemac_softc_t *sc,
272 bus_addr_t offset,
273 size_t length)
275 struct ether_header eh;
276 struct mbuf *m;
278 if (length - sizeof(eh) > ETHERMTU
279 || length - sizeof(eh) < ETHERMIN) {
280 sc->sc_if.if_ierrors++;
281 return;
283 if (LEMAC_USE_PIO_MODE(sc)) {
284 LEMAC_INSB(sc, LEMAC_REG_DAT, sizeof(eh), (void *) &eh);
285 } else {
286 LEMAC_GETBUF16(sc, offset, sizeof(eh) / 2, (void *) &eh);
289 MGETHDR(m, M_DONTWAIT, MT_DATA);
290 if (m == NULL) {
291 sc->sc_if.if_ierrors++;
292 return;
294 if (length + 2 > MHLEN) {
295 MCLGET(m, M_DONTWAIT);
296 if ((m->m_flags & M_EXT) == 0) {
297 m_free(m);
298 sc->sc_if.if_ierrors++;
299 return;
302 m->m_data += 2;
303 memcpy(m->m_data, (void *)&eh, sizeof(eh));
304 if (LEMAC_USE_PIO_MODE(sc)) {
305 LEMAC_INSB(sc, LEMAC_REG_DAT, length - sizeof(eh),
306 mtod(m, char *) + sizeof(eh));
307 } else {
308 LEMAC_GETBUF16(sc, offset + sizeof(eh), (length - sizeof(eh)) / 2,
309 (void *)(mtod(m, char *) + sizeof(eh)));
310 if (length & 1)
311 m->m_data[length - 1] = LEMAC_GET8(sc, offset + length - 1);
313 #if NBPFILTER > 0
314 if (sc->sc_if.if_bpf != NULL) {
315 m->m_pkthdr.len = m->m_len = length;
316 bpf_mtap(sc->sc_if.if_bpf, m);
319 * If this is single cast but not to us
320 * drop it!
322 if ((eh.ether_dhost[0] & 1) == 0
323 && !LEMAC_ADDREQUAL(eh.ether_dhost, sc->sc_enaddr)) {
324 m_freem(m);
325 return;
327 #endif
328 m->m_pkthdr.len = m->m_len = length;
329 m->m_pkthdr.rcvif = &sc->sc_if;
330 (*sc->sc_if.if_input)(&sc->sc_if, m);
333 static void
334 lemac_rne_intr(
335 lemac_softc_t *sc)
337 int rxcount;
339 sc->sc_cntrs.cntr_rne_intrs++;
340 rxcount = LEMAC_INB(sc, LEMAC_REG_RQC);
341 while (rxcount--) {
342 unsigned rxpg = LEMAC_INB(sc, LEMAC_REG_RQ);
343 u_int32_t rxlen;
345 sc->sc_if.if_ipackets++;
346 if (LEMAC_USE_PIO_MODE(sc)) {
347 LEMAC_OUTB(sc, LEMAC_REG_IOP, rxpg);
348 LEMAC_OUTB(sc, LEMAC_REG_PI1, 0);
349 LEMAC_OUTB(sc, LEMAC_REG_PI2, 0);
350 LEMAC_INSB(sc, LEMAC_REG_DAT, sizeof(rxlen), (void *) &rxlen);
351 } else {
352 LEMAC_OUTB(sc, LEMAC_REG_MPN, rxpg);
353 rxlen = LEMAC_GET32(sc, 0);
355 if (rxlen & LEMAC_RX_OK) {
356 sc->sc_flags |= LEMAC_LINKUP;
358 * Get receive length - subtract out checksum.
360 rxlen = ((rxlen >> 8) & 0x7FF) - 4;
361 lemac_input(sc, sizeof(rxlen), rxlen);
362 } else {
363 sc->sc_if.if_ierrors++;
365 LEMAC_OUTB(sc, LEMAC_REG_FMQ, rxpg); /* Return this page to Free Memory Queue */
366 } /* end while (recv_count--) */
368 return;
372 * This is the standard method of reading the DEC Address ROMS.
373 * I don't understand it but it does work.
375 static int
376 lemac_read_macaddr(
377 unsigned char *hwaddr,
378 const bus_space_tag_t iot,
379 const bus_space_handle_t ioh,
380 const bus_addr_t ioreg,
381 int skippat)
383 int cksum, rom_cksum;
384 unsigned char addrbuf[6];
386 if (!skippat) {
387 int idx, idx2, found, octet;
388 static u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA };
389 idx2 = found = 0;
391 for (idx = 0; idx < 32; idx++) {
392 octet = bus_space_read_1(iot, ioh, ioreg);
394 if (octet == testpat[idx2]) {
395 if (++idx2 == sizeof(testpat)) {
396 ++found;
397 break;
399 } else {
400 idx2 = 0;
404 if (!found)
405 return -1;
408 if (hwaddr == NULL)
409 hwaddr = addrbuf;
411 cksum = 0;
412 hwaddr[0] = bus_space_read_1(iot, ioh, ioreg);
413 hwaddr[1] = bus_space_read_1(iot, ioh, ioreg);
415 /* hardware address can't be multicast */
416 if (hwaddr[0] & 1)
417 return -1;
419 cksum = *(u_short *) &hwaddr[0];
421 hwaddr[2] = bus_space_read_1(iot, ioh, ioreg);
422 hwaddr[3] = bus_space_read_1(iot, ioh, ioreg);
423 cksum *= 2;
424 if (cksum > 65535) cksum -= 65535;
425 cksum += *(u_short *) &hwaddr[2];
426 if (cksum > 65535) cksum -= 65535;
428 hwaddr[4] = bus_space_read_1(iot, ioh, ioreg);
429 hwaddr[5] = bus_space_read_1(iot, ioh, ioreg);
430 cksum *= 2;
431 if (cksum > 65535) cksum -= 65535;
432 cksum += *(u_short *) &hwaddr[4];
433 if (cksum >= 65535) cksum -= 65535;
435 /* 00-00-00 is an illegal OUI */
436 if (hwaddr[0] == 0 && hwaddr[1] == 0 && hwaddr[2] == 0)
437 return -1;
439 rom_cksum = bus_space_read_1(iot, ioh, ioreg);
440 rom_cksum |= bus_space_read_1(iot, ioh, ioreg) << 8;
442 if (cksum != rom_cksum)
443 return -1;
444 return 0;
447 static void
448 lemac_multicast_op(
449 u_int16_t *mctbl,
450 const u_char *mca,
451 int enable)
453 u_int idx, bit, crc;
455 crc = ether_crc32_le(mca, ETHER_ADDR_LEN);
458 * The following two lines convert the N bit index into a longword index
459 * and a longword mask.
461 #if LEMAC_MCTBL_BITS < 0
462 crc >>= (32 + LEMAC_MCTBL_BITS);
463 crc &= (1 << -LEMAC_MCTBL_BITS) - 1;
464 #else
465 crc &= (1 << LEMAC_MCTBL_BITS) - 1;
466 #endif
467 bit = 1 << (crc & 0x0F);
468 idx = crc >> 4;
471 * Set or clear hash filter bit in our table.
473 if (enable) {
474 mctbl[idx] |= bit; /* Set Bit */
475 } else {
476 mctbl[idx] &= ~bit; /* Clear Bit */
480 static void
481 lemac_multicast_filter(
482 lemac_softc_t *sc)
484 struct ether_multistep step;
485 struct ether_multi *enm;
487 memset(sc->sc_mctbl, 0, LEMAC_MCTBL_BITS / 8);
489 lemac_multicast_op(sc->sc_mctbl, etherbroadcastaddr, TRUE);
491 ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
492 while (enm != NULL) {
493 if (!LEMAC_ADDREQUAL(enm->enm_addrlo, enm->enm_addrhi)) {
494 sc->sc_flags |= LEMAC_ALLMULTI;
495 sc->sc_if.if_flags |= IFF_ALLMULTI;
496 return;
498 lemac_multicast_op(sc->sc_mctbl, enm->enm_addrlo, TRUE);
499 ETHER_NEXT_MULTI(step, enm);
501 sc->sc_flags &= ~LEMAC_ALLMULTI;
502 sc->sc_if.if_flags &= ~IFF_ALLMULTI;
506 * Do a hard reset of the board;
508 static void
509 lemac_reset(
510 lemac_softc_t * const sc)
512 unsigned data;
515 * Initialize board..
517 sc->sc_flags &= ~LEMAC_LINKUP;
518 sc->sc_if.if_flags &= ~IFF_OACTIVE;
519 LEMAC_INTR_DISABLE(sc);
521 LEMAC_OUTB(sc, LEMAC_REG_IOP, LEMAC_IOP_EEINIT);
522 DELAY(LEMAC_EEP_DELAY);
525 * Read EEPROM information. NOTE - the placement of this function
526 * is important because functions hereafter may rely on information
527 * read from the EEPROM.
529 if ((data = lemac_read_eeprom(sc)) != LEMAC_EEP_CKSUM) {
530 printf("%s: reset: EEPROM checksum failed (0x%x)\n",
531 sc->sc_if.if_xname, data);
532 return;
536 * Update the control register to reflect the media choice
538 data = LEMAC_INB(sc, LEMAC_REG_CTL);
539 if ((data & (LEMAC_CTL_APD|LEMAC_CTL_PSL)) != sc->sc_ctlmode) {
540 data &= ~(LEMAC_CTL_APD|LEMAC_CTL_PSL);
541 data |= sc->sc_ctlmode;
542 LEMAC_OUTB(sc, LEMAC_REG_CTL, data);
546 * Force to 2K mode if not already configured.
549 data = LEMAC_INB(sc, LEMAC_REG_MBR);
550 if (LEMAC_IS_2K_MODE(data)) {
551 sc->sc_flags |= LEMAC_2K_MODE;
552 } else if (LEMAC_IS_64K_MODE(data)) {
553 data = (((data * 2) & 0xF) << 4);
554 sc->sc_flags |= LEMAC_WAS_64K_MODE;
555 LEMAC_OUTB(sc, LEMAC_REG_MBR, data);
556 } else if (LEMAC_IS_32K_MODE(data)) {
557 data = ((data & 0xF) << 4);
558 sc->sc_flags |= LEMAC_WAS_32K_MODE;
559 LEMAC_OUTB(sc, LEMAC_REG_MBR, data);
560 } else {
561 sc->sc_flags |= LEMAC_PIO_MODE;
562 /* PIO mode */
566 * Initialize Free Memory Queue, Init mcast table with broadcast.
569 lemac_init_adapmem(sc);
570 sc->sc_flags |= LEMAC_ALIVE;
573 static void
574 lemac_init(
575 lemac_softc_t * const sc)
577 if ((sc->sc_flags & LEMAC_ALIVE) == 0)
578 return;
581 * If the interface has the up flag
583 if (sc->sc_if.if_flags & IFF_UP) {
584 int saved_cs = LEMAC_INB(sc, LEMAC_REG_CS);
585 LEMAC_OUTB(sc, LEMAC_REG_CS, saved_cs | (LEMAC_CS_TXD | LEMAC_CS_RXD));
586 LEMAC_OUTB(sc, LEMAC_REG_PA0, sc->sc_enaddr[0]);
587 LEMAC_OUTB(sc, LEMAC_REG_PA1, sc->sc_enaddr[1]);
588 LEMAC_OUTB(sc, LEMAC_REG_PA2, sc->sc_enaddr[2]);
589 LEMAC_OUTB(sc, LEMAC_REG_PA3, sc->sc_enaddr[3]);
590 LEMAC_OUTB(sc, LEMAC_REG_PA4, sc->sc_enaddr[4]);
591 LEMAC_OUTB(sc, LEMAC_REG_PA5, sc->sc_enaddr[5]);
593 LEMAC_OUTB(sc, LEMAC_REG_IC, LEMAC_INB(sc, LEMAC_REG_IC) | LEMAC_IC_IE);
595 if (sc->sc_if.if_flags & IFF_PROMISC) {
596 LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_MCE | LEMAC_CS_PME);
597 } else {
598 LEMAC_INTR_DISABLE(sc);
599 lemac_multicast_filter(sc);
600 if (sc->sc_flags & LEMAC_ALLMULTI)
601 memcpy(sc->sc_mctbl, lemac_allmulti_mctbl,
602 sizeof(sc->sc_mctbl));
603 if (LEMAC_USE_PIO_MODE(sc)) {
604 LEMAC_OUTB(sc, LEMAC_REG_IOP, 0);
605 LEMAC_OUTB(sc, LEMAC_REG_PI1, LEMAC_MCTBL_OFF & 0xFF);
606 LEMAC_OUTB(sc, LEMAC_REG_PI2, LEMAC_MCTBL_OFF >> 8);
607 LEMAC_OUTSB(sc, LEMAC_REG_DAT, sizeof(sc->sc_mctbl), (void *) sc->sc_mctbl);
608 } else {
609 LEMAC_OUTB(sc, LEMAC_REG_MPN, 0);
610 LEMAC_PUTBUF8(sc, LEMAC_MCTBL_OFF, sizeof(sc->sc_mctbl), (void *) sc->sc_mctbl);
613 LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_MCE);
616 LEMAC_OUTB(sc, LEMAC_REG_CTL, LEMAC_INB(sc, LEMAC_REG_CTL) ^ LEMAC_CTL_LED);
618 LEMAC_INTR_ENABLE(sc);
619 sc->sc_if.if_flags |= IFF_RUNNING;
620 lemac_ifstart(&sc->sc_if);
621 } else {
622 LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_RXD|LEMAC_CS_TXD);
624 LEMAC_INTR_DISABLE(sc);
625 sc->sc_if.if_flags &= ~IFF_RUNNING;
629 static void
630 lemac_ifstart(
631 struct ifnet *ifp)
633 lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp);
635 if ((ifp->if_flags & IFF_RUNNING) == 0)
636 return;
638 LEMAC_INTR_DISABLE(sc);
640 for (;;) {
641 struct mbuf *m;
642 struct mbuf *m0;
643 int tx_pg;
645 IFQ_POLL(&ifp->if_snd, m);
646 if (m == NULL)
647 break;
649 if ((sc->sc_csr.csr_tqc = LEMAC_INB(sc, LEMAC_REG_TQC)) >= lemac_txmax) {
650 sc->sc_cntrs.cntr_txfull++;
651 ifp->if_flags |= IFF_OACTIVE;
652 break;
656 * get free memory page
658 tx_pg = sc->sc_csr.csr_fmq = LEMAC_INB(sc, LEMAC_REG_FMQ);
660 * Check for good transmit page.
662 if (tx_pg == 0 || tx_pg > sc->sc_lastpage) {
663 sc->sc_cntrs.cntr_txnospc++;
664 ifp->if_flags |= IFF_OACTIVE;
665 break;
668 IFQ_DEQUEUE(&ifp->if_snd, m);
671 * The first four bytes of each transmit buffer are for
672 * control information. The first byte is the control
673 * byte, then the length (why not word aligned?), then
674 * the offset to the buffer.
677 if (LEMAC_USE_PIO_MODE(sc)) {
678 LEMAC_OUTB(sc, LEMAC_REG_IOP, tx_pg); /* Shift 2K window. */
679 LEMAC_OUTB(sc, LEMAC_REG_PI1, 0);
680 LEMAC_OUTB(sc, LEMAC_REG_PI2, 0);
681 LEMAC_OUTB(sc, LEMAC_REG_DAT, sc->sc_txctl);
682 LEMAC_OUTB(sc, LEMAC_REG_DAT, (m->m_pkthdr.len >> 0) & 0xFF);
683 LEMAC_OUTB(sc, LEMAC_REG_DAT, (m->m_pkthdr.len >> 8) & 0xFF);
684 LEMAC_OUTB(sc, LEMAC_REG_DAT, LEMAC_TX_HDRSZ);
685 for (m0 = m; m0 != NULL; m0 = m0->m_next)
686 LEMAC_OUTSB(sc, LEMAC_REG_DAT, m0->m_len, m0->m_data);
687 } else {
688 bus_size_t txoff = /* (mtod(m, u_int32_t) & (sizeof(u_int32_t) - 1)) + */ LEMAC_TX_HDRSZ;
689 LEMAC_OUTB(sc, LEMAC_REG_MPN, tx_pg); /* Shift 2K window. */
690 LEMAC_PUT8(sc, 0, sc->sc_txctl);
691 LEMAC_PUT8(sc, 1, (m->m_pkthdr.len >> 0) & 0xFF);
692 LEMAC_PUT8(sc, 2, (m->m_pkthdr.len >> 8) & 0xFF);
693 LEMAC_PUT8(sc, 3, txoff);
696 * Copy the packet to the board
698 for (m0 = m; m0 != NULL; m0 = m0->m_next) {
699 #if 0
700 LEMAC_PUTBUF8(sc, txoff, m0->m_len, m0->m_data);
701 txoff += m0->m_len;
702 #else
703 const u_int8_t *cp = m0->m_data;
704 int len = m0->m_len;
705 #if 0
706 if ((txoff & 3) == (((long)cp) & 3) && len >= 4) {
707 if (txoff & 3) {
708 int alen = (~txoff & 3);
709 LEMAC_PUTBUF8(sc, txoff, alen, cp);
710 cp += alen; txoff += alen; len -= alen;
712 if (len >= 4) {
713 LEMAC_PUTBUF32(sc, txoff, len / 4, cp);
714 cp += len & ~3; txoff += len & ~3; len &= 3;
717 #endif
718 if ((txoff & 1) == (((long)cp) & 1) && len >= 2) {
719 if (txoff & 1) {
720 int alen = (~txoff & 1);
721 LEMAC_PUTBUF8(sc, txoff, alen, cp);
722 cp += alen; txoff += alen; len -= alen;
724 if (len >= 2) {
725 LEMAC_PUTBUF16(sc, txoff, len / 2, (const void *) cp);
726 cp += len & ~1; txoff += len & ~1; len &= 1;
729 if (len > 0) {
730 LEMAC_PUTBUF8(sc, txoff, len, cp);
731 txoff += len;
733 #endif
737 LEMAC_OUTB(sc, LEMAC_REG_TQ, tx_pg); /* tell chip to transmit this packet */
738 #if NBPFILTER > 0
739 if (sc->sc_if.if_bpf != NULL)
740 bpf_mtap(sc->sc_if.if_bpf, m);
741 #endif
742 m_freem(m); /* free the mbuf */
744 LEMAC_INTR_ENABLE(sc);
747 static int
748 lemac_ifioctl(
749 struct ifnet *ifp,
750 u_long cmd,
751 void *data)
753 lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp);
754 int s;
755 int error = 0;
757 s = splnet();
759 switch (cmd) {
760 case SIOCINITIFADDR: {
761 struct ifaddr *ifa = (struct ifaddr *)data;
763 ifp->if_flags |= IFF_UP;
764 lemac_init(sc);
765 switch (ifa->ifa_addr->sa_family) {
766 #ifdef INET
767 case AF_INET: {
768 arp_ifinit(&sc->sc_if, ifa);
769 break;
771 #endif /* INET */
774 default: {
775 break;
778 break;
781 case SIOCSIFFLAGS: {
782 if ((error = ifioctl_common(ifp, cmd, data)) != 0)
783 break;
784 lemac_init(sc);
785 break;
788 case SIOCADDMULTI:
789 case SIOCDELMULTI: {
791 * Update multicast listeners
793 if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) {
794 /* reset multicast filtering */
795 if (ifp->if_flags & IFF_RUNNING)
796 lemac_init(sc);
797 error = 0;
799 break;
802 case SIOCSIFMEDIA:
803 case SIOCGIFMEDIA: {
804 error = ifmedia_ioctl(ifp, (struct ifreq *)data,
805 &sc->sc_ifmedia, cmd);
806 break;
809 default: {
810 error = ether_ioctl(ifp, cmd, data);
811 break;
815 splx(s);
816 return error;
819 static int
820 lemac_ifmedia_change(
821 struct ifnet * const ifp)
823 lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp);
824 unsigned new_ctl;
826 switch (IFM_SUBTYPE(sc->sc_ifmedia.ifm_media)) {
827 case IFM_10_T: new_ctl = LEMAC_CTL_APD; break;
828 case IFM_10_2:
829 case IFM_10_5: new_ctl = LEMAC_CTL_APD|LEMAC_CTL_PSL; break;
830 case IFM_AUTO: new_ctl = 0; break;
831 default: return EINVAL;
833 if (sc->sc_ctlmode != new_ctl) {
834 sc->sc_ctlmode = new_ctl;
835 lemac_reset(sc);
836 if (sc->sc_if.if_flags & IFF_UP)
837 lemac_init(sc);
839 return 0;
843 * Media status callback
845 static void
846 lemac_ifmedia_status(
847 struct ifnet * const ifp,
848 struct ifmediareq *req)
850 lemac_softc_t *sc = LEMAC_IFP_TO_SOFTC(ifp);
851 unsigned data = LEMAC_INB(sc, LEMAC_REG_CNF);
853 req->ifm_status = IFM_AVALID;
854 if (sc->sc_flags & LEMAC_LINKUP)
855 req->ifm_status |= IFM_ACTIVE;
857 if (sc->sc_ctlmode & LEMAC_CTL_APD) {
858 if (sc->sc_ctlmode & LEMAC_CTL_PSL) {
859 req->ifm_active = IFM_10_5;
860 } else {
861 req->ifm_active = IFM_10_T;
863 } else {
865 * The link bit of the configuration register reflects the
866 * current media choice when auto-port is enabled.
868 if (data & LEMAC_CNF_NOLINK) {
869 req->ifm_active = IFM_10_5;
870 } else {
871 req->ifm_active = IFM_10_T;
875 req->ifm_active |= IFM_ETHER;
879 lemac_port_check(
880 const bus_space_tag_t iot,
881 const bus_space_handle_t ioh)
883 unsigned char hwaddr[6];
885 if (lemac_read_macaddr(hwaddr, iot, ioh, LEMAC_REG_APD, 0) == 0)
886 return 1;
887 if (lemac_read_macaddr(hwaddr, iot, ioh, LEMAC_REG_APD, 1) == 0)
888 return 1;
889 return 0;
892 void
893 lemac_info_get(
894 const bus_space_tag_t iot,
895 const bus_space_handle_t ioh,
896 bus_addr_t *maddr_p,
897 bus_size_t *msize_p,
898 int *irq_p)
900 unsigned data;
902 *irq_p = LEMAC_DECODEIRQ(bus_space_read_1(iot, ioh, LEMAC_REG_IC) & LEMAC_IC_IRQMSK);
904 data = bus_space_read_1(iot, ioh, LEMAC_REG_MBR);
905 if (LEMAC_IS_2K_MODE(data)) {
906 *maddr_p = data * (2 * 1024) + (512 * 1024);
907 *msize_p = 2 * 1024;
908 } else if (LEMAC_IS_64K_MODE(data)) {
909 *maddr_p = data * 64 * 1024;
910 *msize_p = 64 * 1024;
911 } else if (LEMAC_IS_32K_MODE(data)) {
912 *maddr_p = data * 32 * 1024;
913 *msize_p = 32* 1024;
914 } else {
915 *maddr_p = 0;
916 *msize_p = 0;
921 * What to do upon receipt of an interrupt.
924 lemac_intr(
925 void *arg)
927 lemac_softc_t * const sc = arg;
928 int cs_value;
930 LEMAC_INTR_DISABLE(sc); /* Mask interrupts */
933 * Determine cause of interrupt. Receive events take
934 * priority over Transmit.
937 cs_value = LEMAC_INB(sc, LEMAC_REG_CS);
940 * Check for Receive Queue not being empty.
941 * Check for Transmit Done Queue not being empty.
944 if (cs_value & LEMAC_CS_RNE)
945 lemac_rne_intr(sc);
946 if (cs_value & LEMAC_CS_TNE)
947 lemac_tne_intr(sc);
950 * Check for Transmitter Disabled.
951 * Check for Receiver Disabled.
954 if (cs_value & LEMAC_CS_TXD)
955 lemac_txd_intr(sc, cs_value);
956 if (cs_value & LEMAC_CS_RXD)
957 lemac_rxd_intr(sc, cs_value);
960 * Toggle LED and unmask interrupts.
963 sc->sc_csr.csr_cs = LEMAC_INB(sc, LEMAC_REG_CS);
965 LEMAC_OUTB(sc, LEMAC_REG_CTL, LEMAC_INB(sc, LEMAC_REG_CTL) ^ LEMAC_CTL_LED);
966 LEMAC_INTR_ENABLE(sc); /* Unmask interrupts */
968 #if NRND > 0
969 if (cs_value)
970 rnd_add_uint32(&sc->rnd_source, cs_value);
971 #endif
973 return 1;
976 void
977 lemac_shutdown(
978 void *arg)
980 lemac_reset((lemac_softc_t *) arg);
983 static const char * const lemac_modes[4] = {
984 "PIO mode (internal 2KB window)",
985 "2KB window",
986 "changed 32KB window to 2KB",
987 "changed 64KB window to 2KB",
990 void
991 lemac_ifattach(
992 lemac_softc_t *sc)
994 struct ifnet * const ifp = &sc->sc_if;
996 strlcpy(ifp->if_xname, device_xname(&sc->sc_dv), IFNAMSIZ);
998 lemac_reset(sc);
1000 (void) lemac_read_macaddr(sc->sc_enaddr, sc->sc_iot, sc->sc_ioh,
1001 LEMAC_REG_APD, 0);
1003 printf(": %s\n", sc->sc_prodname);
1005 printf("%s: address %s, %dKB RAM, %s\n",
1006 ifp->if_xname,
1007 ether_sprintf(sc->sc_enaddr),
1008 sc->sc_lastpage * 2 + 2,
1009 lemac_modes[sc->sc_flags & LEMAC_MODE_MASK]);
1011 ifp->if_softc = (void *) sc;
1012 ifp->if_start = lemac_ifstart;
1013 ifp->if_ioctl = lemac_ifioctl;
1015 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX
1016 #ifdef IFF_NOTRAILERS
1017 | IFF_NOTRAILERS
1018 #endif
1019 | IFF_MULTICAST;
1021 if (sc->sc_flags & LEMAC_ALIVE) {
1022 int media;
1024 IFQ_SET_READY(&ifp->if_snd);
1026 if_attach(ifp);
1027 ether_ifattach(ifp, sc->sc_enaddr);
1029 #if NRND > 0
1030 rnd_attach_source(&sc->rnd_source, device_xname(&sc->sc_dv),
1031 RND_TYPE_NET, 0);
1032 #endif
1034 ifmedia_init(&sc->sc_ifmedia, 0,
1035 lemac_ifmedia_change,
1036 lemac_ifmedia_status);
1037 if (sc->sc_prodname[4] == '5') /* DE205 is UTP/AUI */
1038 ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0, 0);
1039 if (sc->sc_prodname[4] != '3') /* DE204 & 205 have UTP */
1040 ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_T, 0, 0);
1041 if (sc->sc_prodname[4] != '4') /* DE203 & 205 have BNC */
1042 ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_5, 0, 0);
1043 switch (sc->sc_prodname[4]) {
1044 case '3': media = IFM_10_5; break;
1045 case '4': media = IFM_10_T; break;
1046 default: media = IFM_AUTO; break;
1048 ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | media);
1049 } else {
1050 printf("%s: disabled due to error\n", ifp->if_xname);