void le_reset(int unit, u_char *myea) { struct le_softc *sc = &le_softc[unit]; u_long a; int timo = 100000; #ifdef LE_DEBUG if (le_debug) { printf("le%d: le_reset called\n", unit); printf(" r0=%x, r1=%x, mem=%x, addr=%x:%x:%x:%x:%x:%x\n", sc->sc_r0, sc->sc_r1, sc->sc_mem, sc->sc_addr[0], sc->sc_addr[1], sc->sc_addr[2], sc->sc_addr[3], sc->sc_addr[4], sc->sc_addr[5]); } #endif lewrcsr(sc, 0, LE_STOP); for (timo = 1000; timo; timo--); sc->sc_next_rd = sc->sc_next_td = 0; /* Set up LANCE init block. */ lememinit(sc); if (myea) bcopy(sc->sc_addr, myea, ETHER_ADDR_LEN); /* Turn on byte swapping. */ lewrcsr(sc, 3, LE_BSWP); /* Give LANCE the physical address of its init block. */ a = LANCE_ADDR(sc, sc->sc_init); lewrcsr(sc, 1, a); lewrcsr(sc, 2, (a >> 16) & 0xff); #ifdef LE_DEBUG if (le_debug) printf("le%d: before init\n", unit); #endif /* Try to initialize the LANCE. */ lewrcsr(sc, 0, LE_INIT); /* Wait for initialization to finish. */ for (timo = 100000; timo; timo--) if (lerdcsr(sc, 0) & LE_IDON) break; if (lerdcsr(sc, 0) & LE_IDON) { /* Start the LANCE. */ lewrcsr(sc, 0, LE_INEA | LE_STRT | LE_IDON); } else printf("le%d: card failed to initialize\n", unit); #ifdef LE_DEBUG if (le_debug) printf("le%d: after init\n", unit); #endif }
int le_put(struct iodesc *desc, void *pkt, size_t len) { int unit = /*nif->nif_unit*/0; struct le_softc *sc = &le_softc[unit]; volatile struct mds *cdm; int timo, stat; #if 0 int i; #endif le_put_loop: timo = 100000; #ifdef LE_DEBUG if (le_debug) printf("le%d: le_put called. next_td=%d\n", unit, sc->sc_next_td); #endif stat = lerdcsr(sc, 0); lewrcsr(sc, 0, stat & (LE_BABL | LE_MISS | LE_MERR | LE_TINT)); if (stat & (LE_BABL | LE_CERR | LE_MISS | LE_MERR)) le_error(unit, "le_put(way before xmit)", stat); cdm = &sc->sc_td[sc->sc_next_td]; #if 0 i = 0; while (cdm->flags & LE_OWN) { if ((i % 100) == 0) printf("le%d: output buffer busy - flags=%x\n", unit, cdm->flags); if (i++ > 500) break; } if (cdm->flags & LE_OWN) getchar(); #else while (cdm->flags & LE_OWN); #endif memcpy(sc->sc_tbuf + (BUFSIZE * sc->sc_next_td), pkt, len); if (len < ETHER_MIN_LEN) cdm->bcnt = -ETHER_MIN_LEN; else cdm->bcnt = -len; cdm->mcnt = 0; cdm->flags |= LE_OWN | LE_STP | LE_ENP; stat = lerdcsr(sc, 0); if (stat & (LE_BABL | LE_CERR | LE_MISS | LE_MERR)) le_error(unit, "le_put(before xmit)", stat); lewrcsr(sc, 0, LE_TDMD); stat = lerdcsr(sc, 0); if (stat & (LE_BABL | LE_CERR | LE_MISS | LE_MERR)) le_error(unit, "le_put(after xmit)", stat); do { if (--timo == 0) { printf("le%d: transmit timeout, stat = 0x%x\n", unit, stat); if (stat & LE_SERR) le_error(unit, "le_put(timeout)", stat); if (stat & LE_INIT) { printf("le%d: reset and retry packet\n", unit); lewrcsr(sc, 0, LE_TINT); /* sanity */ leinit(); goto le_put_loop; } break; } stat = lerdcsr(sc, 0); } while ((stat & LE_TINT) == 0); lewrcsr(sc, 0, LE_TINT); if (stat & (LE_BABL |/* LE_CERR |*/ LE_MISS | LE_MERR)) { printf("le_put: xmit error, buf %d\n", sc->sc_next_td); le_error(unit, "le_put(xmit error)", stat); } if (++sc->sc_next_td >= NTBUF) sc->sc_next_td = 0; if (cdm->flags & LE_DEF) le_stats[unit].deferred++; if (cdm->flags & LE_ONE) le_stats[unit].collisions++; if (cdm->flags & LE_MORE) le_stats[unit].collisions += 2; if (cdm->flags & LE_ERR) { if (cdm->mcnt & LE_UFLO) printf("le%d: transmit underflow\n", unit); if (cdm->mcnt & LE_LCOL) le_stats[unit].collisions++; if (cdm->mcnt & LE_LCAR) printf("le%d: lost carrier\n", unit); if (cdm->mcnt & LE_RTRY) le_stats[unit].collisions += 16; return -1; } #ifdef LE_DEBUG if (le_debug) { printf("le%d: le_put() successful: sent %d\n", unit, len); printf("le%d: le_put(): flags: %x mcnt: %x\n", unit, (unsigned int) cdm->flags, (unsigned int) cdm->mcnt); } #endif return len; }
int le_poll(struct iodesc *desc, void *pkt, int len) { int unit = /*nif->nif_unit*/0; struct le_softc *sc = &le_softc[unit]; int length; volatile struct mds *cdm; int stat; #ifdef LE_DEBUG if (/*le_debug*/0) printf("le%d: le_poll called. next_rd=%d\n", unit, sc->sc_next_rd); #endif stat = lerdcsr(sc, 0); lewrcsr(sc, 0, stat & (LE_BABL | LE_MISS | LE_MERR | LE_RINT)); cdm = &sc->sc_rd[sc->sc_next_rd]; if (cdm->flags & LE_OWN) return 0; #ifdef LE_DEBUG if (le_debug) { printf("next_rd %d\n", sc->sc_next_rd); printf("cdm->flags %x\n", cdm->flags); printf("cdm->bcnt %x, cdm->mcnt %x\n", cdm->bcnt, cdm->mcnt); printf("cdm->rbuf msg %d buf %d\n", cdm->mcnt, -cdm->bcnt ); } #endif if (stat & (LE_BABL | LE_CERR | LE_MISS | LE_MERR)) le_error(unit, "le_poll", stat); if (cdm->flags & (LE_FRAM | LE_OFLO | LE_CRC | LE_RBUFF)) { printf("le%d_poll: rmd status 0x%x\n", unit, cdm->flags); length = 0; goto cleanup; } if ((cdm->flags & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) panic("le_poll: chained packet"); length = cdm->mcnt; #ifdef LE_DEBUG if (le_debug) printf("le_poll: length %d\n", length); #endif if (length >= BUFSIZE) { length = 0; panic("csr0 when bad things happen: %x", stat); goto cleanup; } if (!length) goto cleanup; length -= 4; if (length > 0) { /* * If the length of the packet is greater than the size of the * buffer, we have to truncate it, to avoid Bad Things. * XXX Is this the right thing to do? */ if (length > len) length = len; memcpy(pkt, sc->sc_rbuf + (BUFSIZE * sc->sc_next_rd), length); } cleanup: cdm->mcnt = 0; cdm->flags |= LE_OWN; if (++sc->sc_next_rd >= NRBUF) sc->sc_next_rd = 0; #ifdef LE_DEBUG if (le_debug) printf("new next_rd %d\n", sc->sc_next_rd); #endif return length; }