📄 am7990.c
字号:
if (tlen < LEMINSIZE) { (*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen); tlen = LEMINSIZE; } return (tlen);}/* * Pull data off an interface. * Len is length of data, with local net header stripped. * We copy the data into mbufs. When full cluster sized units are present * we copy into clusters. */integrate struct mbuf *am7990_get(sc, boff, totlen) struct am7990_softc *sc; int boff, totlen;{ register struct mbuf *m; struct mbuf *top, **mp; int len, pad; MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == 0) return (0); m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = totlen; pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header); m->m_data += pad; len = MHLEN - pad; top = 0; mp = ⊤ while (totlen > 0) { if (top) { MGET(m, M_DONTWAIT, MT_DATA); if (m == 0) { m_freem(top); return 0; } len = MLEN; } if (top && totlen >= MINCLSIZE) { MCLGET(m, M_DONTWAIT); if (m->m_flags & M_EXT) len = MCLBYTES; } m->m_len = len = min(totlen, len); (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len); boff += len; totlen -= len; *mp = m; mp = &m->m_next; } return (top);}/* * Pass a packet to the higher levels. */integrate voidam7990_read(sc, boff, len) register struct am7990_softc *sc; int boff, len;{ struct mbuf *m; struct ether_header *eh; if (len <= sizeof(struct ether_header) || len > ETHERMTU + sizeof(struct ether_header)) {#ifdef LEDEBUG printf("%s: invalid packet size %d; dropping\n", sc->sc_dev.dv_xname, len);#endif ifp->if_ierrors++; return; } /* Pull packet off interface. */ m = am7990_get(sc, boff, len); if (m == 0) { ifp->if_ierrors++; return; } ifp->if_ipackets++; /* We assume that the header fit entirely in one mbuf. */ eh = mtod(m, struct ether_header *);#if NBPFILTER > 0 /* * Check if there's a BPF listener on this interface. * If so, hand off the raw packet to BPF. */ if (ifp->if_bpf) bpf_mtap(ifp->if_bpf, m);#endif#ifdef LANCE_REVC_BUG /* * The old LANCE (Rev. C) chips have a bug which causes * garbage to be inserted in front of the received packet. * The work-around is to ignore packets with an invalid * destination address (garbage will usually not match). * Of course, this precludes multicast support... */ if (ETHER_CMP(eh->ether_dhost, sc->sc_arpcom.ac_enaddr) && ETHER_CMP(eh->ether_dhost, etherbroadcastaddr)) { m_freem(m); return; }#endif#if defined(__bsdi__) || defined(PROM) eh->ether_type = ntohs(eh->ether_type);#endif /* Pass the packet up, with the ether header sort-of removed. */ m_adj(m, sizeof(struct ether_header)); ether_input(ifp, eh, m);}integrate voidam7990_rint(sc) struct am7990_softc *sc;{ register int bix; int rp; struct lermd rmd; bix = sc->sc_last_rd; /* Process all buffers with valid data. */ for (;;) { rp = LE_RMDADDR(sc, bix); (*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd)); if (rmd.rmd1_bits & LE_R1_OWN) break; if (rmd.rmd1_bits & LE_R1_ERR) { if (rmd.rmd1_bits & LE_R1_ENP) {#ifdef LEDEBUG if ((rmd.rmd1_bits & LE_R1_OFLO) == 0) { if (rmd.rmd1_bits & LE_R1_FRAM) printf("%s: framing error\n", sc->sc_dev.dv_xname); if (rmd.rmd1_bits & LE_R1_CRC) printf("%s: crc mismatch\n", sc->sc_dev.dv_xname); }#endif } else { if (rmd.rmd1_bits & LE_R1_OFLO) printf("%s: overflow\n", sc->sc_dev.dv_xname); } if (rmd.rmd1_bits & LE_R1_BUFF) printf("%s: receive buffer error\n", sc->sc_dev.dv_xname); ifp->if_ierrors++; } else if ((rmd.rmd1_bits & (LE_R1_STP | LE_R1_ENP)) != (LE_R1_STP | LE_R1_ENP)) { printf("%s: dropping chained buffer\n", sc->sc_dev.dv_xname); ifp->if_ierrors++; } else {#ifdef LEDEBUG if (sc->sc_debug) am7990_recv_print(sc, sc->sc_last_rd);#endif am7990_read(sc, LE_RBUFADDR(sc, bix), (int)mtohs(rmd.rmd3) - 4); } rmd.rmd1_bits = LE_R1_OWN; rmd.rmd2 = htoms(-LEBLEN | LE_XMD2_ONES); rmd.rmd3 = htoms(0); (*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd));#ifdef LEDEBUG if (sc->sc_debug) printf("sc->sc_last_rd = %x, rmd: " "ladr %04x, hadr %02x, flags %02x, " "bcnt %04x, mcnt %04x\n", sc->sc_last_rd, rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits, rmd.rmd2, rmd.rmd3);#endif if (++bix == sc->sc_nrbuf) bix = 0; } sc->sc_last_rd = bix;}integrate voidam7990_tint(sc) register struct am7990_softc *sc;{ register int bix; struct letmd tmd; bix = sc->sc_first_td; for (;;) { if (sc->sc_no_td <= 0) break; (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, bix), sizeof(tmd));#ifdef LEDEBUG if (sc->sc_debug) printf("trans tmd: " "ladr %04x, hadr %02x, flags %02x, " "bcnt %04x, mcnt %04x\n", tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits, tmd.tmd2, tmd.tmd3);#endif if (tmd.tmd1_bits & LE_T1_OWN) break; ifp->if_flags &= ~IFF_OACTIVE; if (tmd.tmd1_bits & LE_T1_ERR) { if (mtohs(tmd.tmd3) & LE_T3_BUFF) printf("%s: transmit buffer error\n", sc->sc_dev.dv_xname); else if (mtohs(tmd.tmd3) & LE_T3_UFLO) printf("%s: underflow\n", sc->sc_dev.dv_xname); if (mtohs(tmd.tmd3) & (LE_T3_BUFF | LE_T3_UFLO)) { am7990_reset(sc); return; } if (mtohs(tmd.tmd3) & LE_T3_LCAR) { if (sc->sc_nocarrier) (*sc->sc_nocarrier)(sc); else printf("%s: lost carrier\n", sc->sc_dev.dv_xname); } if (mtohs(tmd.tmd3) & LE_T3_LCOL) ifp->if_collisions++; if (mtohs(tmd.tmd3) & LE_T3_RTRY) { printf("%s: excessive collisions, tdr %d\n", sc->sc_dev.dv_xname, mtohs(tmd.tmd3) & LE_T3_TDR_MASK); ifp->if_collisions += 16; } ifp->if_oerrors++; } else { if (tmd.tmd1_bits & LE_T1_ONE) ifp->if_collisions++; else if (tmd.tmd1_bits & LE_T1_MORE) /* Real number is unknown. */ ifp->if_collisions += 2; ifp->if_opackets++; } if (++bix == sc->sc_ntbuf) bix = 0; --sc->sc_no_td; } sc->sc_first_td = bix; am7990_start(ifp); if (sc->sc_no_td == 0) ifp->if_timer = 0;}/* * Controller interrupt. */intam7990_intr(arg) register void *arg;{ register struct am7990_softc *sc = arg; register u_int16_t isr; isr = (*sc->sc_rdcsr)(sc, LE_CSR0); if ((isr & LE_C0_INTR) == 0) return (0); (*sc->sc_wrcsr)(sc, LE_CSR0, isr & (LE_C0_INEA | LE_C0_BABL | LE_C0_MISS | LE_C0_MERR | LE_C0_RINT | LE_C0_TINT | LE_C0_IDON)); if (isr & LE_C0_ERR) { if (isr & LE_C0_BABL) {#ifdef LEDEBUG printf("%s: babble\n", sc->sc_dev.dv_xname);#endif ifp->if_oerrors++; }#if 0 if (isr & LE_C0_CERR) { printf("%s: collision error\n", sc->sc_dev.dv_xname); ifp->if_collisions++; }#endif if (isr & LE_C0_MISS) {#ifdef LEDEBUG printf("%s: missed packet\n", sc->sc_dev.dv_xname);#endif ifp->if_ierrors++; } if (isr & LE_C0_MERR) { printf("%s: memory error\n", sc->sc_dev.dv_xname); am7990_reset(sc); return (1); } } if ((isr & LE_C0_RXON) == 0) { printf("%s: receiver disabled\n", sc->sc_dev.dv_xname); ifp->if_ierrors++; am7990_reset(sc); return (1); } if ((isr & LE_C0_TXON) == 0) { printf("%s: transmitter disabled\n", sc->sc_dev.dv_xname); ifp->if_oerrors++; am7990_reset(sc); return (1); } if (isr & LE_C0_RINT) am7990_rint(sc); if (isr & LE_C0_TINT) am7990_tint(sc); return (1);}#undef ifp#ifdef PROMam7990_watchdog(int unit)#elseam7990_watchdog(struct ifnet *ifp)#endif{#ifdef PROM struct am7990_softc *sc = UNIT_TO_SOFTC(unit);#else struct am7990_softc *sc = IFP_TO_SOFTC(ifp);#endif log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);#ifndef PROM ++ifp->if_oerrors;#endif am7990_reset(sc);}/* * Setup output on interface. * Get another datagram to send off of the interface queue, and map it to the * interface before starting the output. * Called only at splimp or interrupt level. */ifnet_ret_tam7990_start(ifp) register struct ifnet *ifp;{ register struct am7990_softc *sc = IFP_TO_SOFTC(ifp); register int bix; register struct mbuf *m; struct letmd tmd; int rp; int len; if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) return;#ifdef PROM if (!am7990_linkstatus (sc)) return;#endif bix = sc->sc_last_td; for (;;) { rp = LE_TMDADDR(sc, bix); (*sc->sc_copyfromdesc)(sc, &tmd, rp, sizeof(tmd)); if (tmd.tmd1_bits & LE_T1_OWN) { ifp->if_flags |= IFF_OACTIVE; printf("missing buffer, no_td = %d, last_td = %d\n", sc->sc_no_td, sc->sc_last_td); } IF_DEQUEUE(&ifp->if_snd, m); if (m == 0) break;#if NBPFILTER > 0 /* * If BPF is listening on this interface, let it see the packet * before we commit it to the wire. */ if (ifp->if_bpf) bpf_mtap(ifp->if_bpf, m);#endif /* * Copy the mbuf chain into the transmit buffer. */ len = am7990_put(sc, LE_TBUFADDR(sc, bix), m);#ifdef LEDEBUG if (len > ETHERMTU + sizeof(struct ether_header)) printf("packet length %d\n", len);#endif ifp->if_timer = 5; /* * Init transmit registers, and set transmit start flag. */ tmd.tmd1_bits = LE_T1_OWN | LE_T1_STP | LE_T1_ENP; tmd.tmd2 = htoms(-len | LE_XMD2_ONES); tmd.tmd3 = htoms(0); (*sc->sc_copytodesc)(sc, &tmd, rp, sizeof(tmd));#ifdef LEDEBUG if (sc->sc_debug) am7990_xmit_print(sc, sc->sc_last_td);#endif (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD); if (++bix == sc->sc_ntbuf) bix = 0; if (++sc->sc_no_td == sc->sc_ntbuf) { ifp->if_flags |= IFF_OACTIVE; break; } } sc->sc_last_td = bix;}/* * Process an ioctl request. */intam7990_ioctl(ifp, cmd, data) register struct ifnet *ifp; u_long cmd; caddr_t data;{ register struct am7990_softc *sc = IFP_TO_SOFTC(ifp); struct ifaddr *ifa = (struct ifaddr *)data; struct ifreq *ifr = (struct ifreq *)data; int s, error = 0; s = splimp();#ifndef PROM if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) { splx(s); return error; }#endif switch (cmd) {#ifdef PROM case SIOCPOLL:/*printf ("am7990_iocyl: poll\n");*/ am7990_intr(sc); break;#endif case SIOCSIFADDR: ifp->if_flags |= IFF_UP;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -