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_put(struct iodesc *desc, void *pkt, size_t len) { volatile struct lereg1 *ler1 = le_softc.sc_r1; volatile struct lereg2 *ler2 = le_softc.sc_r2; volatile struct letmd *tmd; int timo = 100000, stat = 0; unsigned int a; int nifunit = ((struct netif *)desc->io_netif)->nif_unit; ler1->ler1_rap = LE_CSR0; if (ler1->ler1_rdp & LE_C0_ERR) le_error(desc->io_netif, "le_put(way before xmit)", ler1); tmd = &ler2->ler2_tmd[le_softc.next_tmd]; while (tmd->tmd1_bits & LE_T1_OWN) { printf("le%d: output buffer busy\n", nifunit); } memcpy((void *)ler2->ler2_tbuf[le_softc.next_tmd], pkt, len); if (len < 64) tmd->tmd2 = -64; else tmd->tmd2 = -len; tmd->tmd3 = 0; if (ler1->ler1_rdp & LE_C0_ERR) le_error(desc->io_netif, "le_put(before xmit)", ler1); tmd->tmd1_bits = LE_T1_STP | LE_T1_ENP | LE_T1_OWN; a = (u_int)&ler2->ler2_tbuf[le_softc.next_tmd]; tmd->tmd0 = a & LE_ADDR_LOW_MASK; tmd->tmd1_hadr = a >> 16; ler1->ler1_rdp = LE_C0_TDMD; if (ler1->ler1_rdp & LE_C0_ERR) le_error(desc->io_netif, "le_put(after xmit)", ler1); do { if (--timo == 0) { printf("le%d: transmit timeout, stat = 0x%x\n", nifunit, stat); if (ler1->ler1_rdp & LE_C0_ERR) le_error(desc->io_netif, "le_put(timeout)", ler1); break; } stat = ler1->ler1_rdp; } while ((stat & LE_C0_TINT) == 0); ler1->ler1_rdp = LE_C0_TINT; if (ler1->ler1_rdp & LE_C0_ERR) { if ((ler1->ler1_rdp & (LE_C0_BABL | LE_C0_CERR | LE_C0_MISS | LE_C0_MERR)) != LE_C0_CERR) printf("le_put: xmit error, buf %d\n", le_softc.next_tmd); le_error(desc->io_netif, "le_put(xmit error)", ler1); } le_softc.next_tmd = 0; /* (le_softc.next_tmd == (LETBUF - 1)) ? 0 : le_softc.next_tmd + 1;*/ if (tmd->tmd1_bits & LE_T1_DEF) le_stats.deferred++; if (tmd->tmd1_bits & LE_T1_ONE) le_stats.collisions++; if (tmd->tmd1_bits & LE_T1_MORE) le_stats.collisions += 2; if (tmd->tmd1_bits & LE_T1_ERR) { printf("le%d: transmit error, error = 0x%x\n", nifunit, tmd->tmd3); return -1; } if (le_debug) { printf("le%d: le_put() successful: sent %d\n", nifunit, len); printf("le%d: le_put(): tmd1_bits: %x tmd3: %x\n", nifunit, (unsigned int)tmd->tmd1_bits, (unsigned int)tmd->tmd3); } 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; }
int le_poll(struct iodesc *desc, void *pkt, int len) { struct lereg1 *ler1 = le_softc.sc_r1; struct lereg2 *ler2 = le_softc.sc_r2; unsigned int a; int length; struct lermd *rmd; ler1->ler1_rap = LE_CSR0; if ((ler1->ler1_rdp & LE_C0_RINT) != 0) ler1->ler1_rdp = LE_C0_RINT; rmd = &ler2->ler2_rmd[le_softc.next_rmd]; if (rmd->rmd1_bits & LE_R1_OWN) { return 0; } if (ler1->ler1_rdp & LE_C0_ERR) le_error(desc->io_netif, "le_poll", ler1); if (rmd->rmd1_bits & LE_R1_ERR) { printf("le%d_poll: rmd status 0x%x\n", ((struct netif *)desc->io_netif)->nif_unit, rmd->rmd1_bits); length = 0; goto cleanup; } if ((rmd->rmd1_bits & (LE_R1_STP | LE_R1_ENP)) != (LE_R1_STP | LE_R1_ENP)) panic("le_poll: chained packet"); length = rmd->rmd3; if (length >= LEMTU) { length = 0; panic("csr0 when bad things happen: %x", ler1->ler1_rdp); goto cleanup; } if (length == 0) goto cleanup; length -= 4; if (length > 0) { /* * if buffer is smaller than the packet truncate it. * (is this wise?) */ if (length > len) length = len; memcpy(pkt, (void *)&ler2->ler2_rbuf[le_softc.next_rmd], length); } cleanup: a = (u_int)&ler2->ler2_rbuf[le_softc.next_rmd]; rmd->rmd0 = a & LE_ADDR_LOW_MASK; rmd->rmd1_hadr = a >> 16; rmd->rmd2 = -LEMTU; le_softc.next_rmd = (le_softc.next_rmd == (LERBUF - 1)) ? 0 : (le_softc.next_rmd + 1); rmd->rmd1_bits = LE_R1_OWN; return length; }