📄 if_ne.c
字号:
while ((inb(nec+ds0_isr) & DSIS_RDC) == 0) ; outb(nec+ds0_isr, DSIS_RDC); outb(nec+ds_cmd, cmd); /* Clear remote DMA */ /* * Init transmit length registers, and set transmit start flag. */ if (len < ETHER_MIN_LEN) len = ETHER_MIN_LEN; outb(nec+ds0_tbcr0, len); outb(nec+ds0_tbcr1, len >> 8); outb(nec+ds0_tpsr, ns->ns_tbuf); outb(nec+ds_cmd, DSCM_TRANS|DSCM_NODMA|DSCM_START); m_freem(m0);}/* * Controller interrupt. */neintr(ns) register struct ne_softc *ns;{ register nec = ns->ns_base; u_char cmd, isr; /* Save cmd, clear interrupt */ cmd = inb(nec+ds_cmd);loop: isr = inb(nec+ds0_isr);#ifdef PROM if (isr == 0) return 1;#endif outb(nec+ds_cmd,DSCM_NODMA|DSCM_START); outb(nec+ds0_isr, isr); /* Packet Transmitted or Transmit error */ if (isr & (DSIS_TX|DSIS_TXE)) { ns->ns_if.if_flags &= ~IFF_OACTIVE; /* Need to read these registers to clear status */ ++ns->ns_if.if_opackets; ns->ns_if.if_collisions += inb(nec+ds0_tbcr0) & 0xf; if (isr & DSIS_TXE) ns->ns_if.if_oerrors++; } /* Receiver error */ if (isr & DSIS_RXE) { /* need to read these registers to clear status */ (void) inb(nec + ds0_rsr); (void) inb(nec + ds0_rcvalctr); (void) inb(nec + ds0_rcvcrcctr); (void) inb(nec + ds0_rcvfrmctr); ns->ns_if.if_ierrors++; } /* We received something; rummage thru tiny ring buffer */ if (isr & (DSIS_RX|DSIS_RXE)) { u_char pend, lastfree; outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1); pend = inb(nec+ds1_curr); outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0); lastfree = inb(nec+ds0_bnry); /* Have we wrapped? */ if (lastfree >= ns->ns_rbufend) /* should not happen */ lastfree = ns->ns_rbuf; if (pend < lastfree && ns->ns_cur <= pend) lastfree = ns->ns_cur; else if (ns->ns_cur > lastfree) lastfree = ns->ns_cur;#ifdef NEDEBUG else if (lastfree != ns->ns_cur) printf("ne lastfree? (%x %x %x)\n", lastfree, pend, ns->ns_cur);#endif /* Something in the buffer? */ while (pend != lastfree) { u_char nxt; /* Extract header from microcephalic board */ nefetch(nec, ns->ns_ne1000, (caddr_t)&ns->ns_ph, lastfree * DS_PGSIZE, sizeof(ns->ns_ph)); ns->ns_ba = lastfree * DS_PGSIZE + sizeof(ns->ns_ph); /* Incipient paranoia */ if (ns->ns_ph.pr_status == DSRS_RPC || /* for dequna's */ ns->ns_ph.pr_status == 0x21) nerecv(ns);/*#ifdef NEDEBUG*/ else if (ns->ns_if.if_flags & IFF_DEBUG) { printf("ne: cur %x pnd %x lfr %x ", ns->ns_cur, pend, lastfree); printf("nxt %x len %x ", ns->ns_ph.pr_nxtpg, (ns->ns_ph.pr_sz1 << 8) + ns->ns_ph.pr_sz0); printf("Bogus Sts %x\n", ns->ns_ph.pr_status); }/*#endif*/ nxt = ns->ns_ph.pr_nxtpg; /* Sanity check */ if (nxt >= ns->ns_rbuf && nxt <= ns->ns_rbufend /*&& nxt <= pend*/) /* XXX */ ns->ns_cur = nxt; else { if (ns->ns_if.if_flags & IFF_DEBUG) printf("ne: bad nxt: %x (pend %x, cur %x)\n", nxt, pend, ns->ns_cur); ns->ns_cur = nxt = pend; } /* Set the boundaries */ lastfree = nxt; if (--nxt < ns->ns_rbuf) nxt = ns->ns_rbufend - 1; outb(nec+ds0_bnry, nxt); outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1); pend = inb(nec+ds1_curr); outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0); } outb(nec+ds_cmd, DSCM_START|DSCM_NODMA); }#if 0 /* Receiver ovverun? */ if (isr & DSIS_ROVRN) { log(LOG_ERR, "ne%d: error: isr %x\n", ns->ne_dev.dv_unit, isr /*, DSIS_BITS*/); outb(nec+ds0_rbcr0, 0); outb(nec+ds0_rbcr1, 0); outb(nec+ds0_tcr, DSTC_LB0); outb(nec+ds0_rcr, DSRC_MON); outb(nec+ds_cmd, DSCM_START|DSCM_NODMA); outb(nec+ds0_rcr, DSRC_AB); outb(nec+ds0_tcr, 0); }#endif if ((isr & (DSIS_RX|DSIS_RXE|DSIS_TX|DSIS_TXE)) == 0 && ns->ns_if.if_flags & IFF_DEBUG) log(LOG_ERR, "ne%d: intr status %x\n", ns->ns_if.if_unit, isr); /* Any more to send? */ outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START); if ((ns->ns_if.if_flags & IFF_OACTIVE) == 0) nestart(&ns->ns_if); outb(nec+ds_cmd, cmd); outb(nec+ds0_imr, 0xff); /* Still more to do? */ isr = inb(nec+ds0_isr); if (isr) goto loop; return (1);}/* * Ethernet interface receiver interface. * If input error just drop packet. * Otherwise examine packet to determine type. If can't determine length * from type, then have to drop packet. Othewise decapsulate * packet based on type and pass to type specific higher-level * input routine. */voidnerecv(ns) register struct ne_softc *ns;{ int len; int b; register int l; register caddr_t p; register nec = ns->ns_base; ns->ns_if.if_ipackets++; len = ns->ns_ph.pr_sz0 + (ns->ns_ph.pr_sz1 << 8); if(len < ETHER_MIN_LEN || len > ETHER_MAX_LEN) return; /* this need not be so torturous - one/two bcopys at most into mbufs */ nefetch(nec, ns->ns_ne1000, ns->ns_pb, ns->ns_ba, min(len, DS_PGSIZE - sizeof(ns->ns_ph))); if (len > DS_PGSIZE - sizeof(ns->ns_ph)) { l = len - (DS_PGSIZE - sizeof(ns->ns_ph)); p = ns->ns_pb + (DS_PGSIZE - sizeof(ns->ns_ph)); if(++ns->ns_cur >= ns->ns_rbufend) ns->ns_cur = ns->ns_rbuf; b = ns->ns_cur*DS_PGSIZE; while (l >= DS_PGSIZE) { nefetch(nec, ns->ns_ne1000, p, b, DS_PGSIZE); p += DS_PGSIZE; l -= DS_PGSIZE; if(++ns->ns_cur >= ns->ns_rbufend) ns->ns_cur = ns->ns_rbuf; b = ns->ns_cur*DS_PGSIZE; } if (l > 0) nefetch(nec, ns->ns_ne1000, p, b, l); } /* don't forget checksum! */ len -= sizeof(struct ether_header) + sizeof(long); neread(ns, (caddr_t)(ns->ns_pb), len);}/* * Fetch from onboard ROM/RAM */voidnefetch(nec, ne1000, up, ad, len) register nec; int ne1000; caddr_t up; int ad, len;{ u_char cmd; int cnt; if (!ne1000 && len & 01) len++; cmd = inb(nec+ds_cmd); outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START); /* Setup remote dma */ outb(nec+ds0_isr, DSIS_RDC); outb(nec+ds0_rbcr0, len); outb(nec+ds0_rbcr1, len >> 8); outb(nec+ds0_rsar0, ad); outb(nec+ds0_rsar1, ad >> 8); /* Execute & extract from card */ outb(nec+ds_cmd, DSCM_RREAD|DSCM_PG0|DSCM_START); if (ne1000) insb(nec+ne_data, up, len); else insw(nec+ne_data, up, len / 2); /* Wait till done, then shutdown feature */ cnt = 10000; while ((inb(nec+ds0_isr) & DSIS_RDC) == 0 && --cnt) ; outb(nec+ds0_isr, DSIS_RDC); outb(nec+ds_cmd, cmd);}/* * Put to onboard RAM. */voidneput(nec, ne1000, up, ad, len) register int nec; int ne1000; caddr_t up; int ad, len;{ u_char cmd; int cnt; if (!ne1000 && len & 01) len++; cmd = inb(nec+ds_cmd); outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START); /* Setup for remote dma */ outb(nec+ds0_isr, DSIS_RDC); outb(nec+ds0_rbcr0, len); outb(nec+ds0_rbcr1, len >> 8); outb(nec+ds0_rsar0, ad); outb(nec+ds0_rsar1, ad >> 8); /* Execute & stuff to card */ outb(nec+ds_cmd, DSCM_RWRITE|DSCM_PG0|DSCM_START); if (ne1000) outsb(nec+ne_data, up, len); else outsw(nec+ne_data, up, len / 2); /* Wait till done, then shutdown feature */ cnt = 10000; while ((inb(nec+ds0_isr) & DSIS_RDC) == 0 && --cnt) ; outb(nec+ds0_isr, DSIS_RDC); outb(nec+ds_cmd, cmd);}/* * Pass a packet to the higher levels. * We deal with the trailer protocol here. */voidneread(ns, buf, len) register struct ne_softc *ns; char *buf; int len;{ register struct ether_header *eh; struct mbuf *m; int off, resid; /* * Deal with trailer protocol: if type is trailer type * get true type from first 16-bit word past data. * Remember that type was trailer by setting off. */ eh = (struct ether_header *)buf; eh->ether_type = ntohs((u_short)eh->ether_type);#define nedataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off)))) if (eh->ether_type >= ETHERTYPE_TRAIL && eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; if (off >= ETHERMTU) return; /* sanity */ eh->ether_type = ntohs(*nedataaddr(eh, off, u_short *)); resid = ntohs(*(nedataaddr(eh, off + 2, u_short *))); if (off + resid > len) return; /* sanity */ len = off + resid; } else off = 0; if (len <= 0) return;#if NBPFILTER > 0 /* For BPF. */ /* * Check if there's a bpf filter listening on this interface. * If so, hand off the raw packet to bpf, which must deal with * trailers in its own way. */ if (ns->ns_if.if_bpf) { eh->ether_type = htons((u_short)eh->ether_type); bpf_tap(ns->ns_if.if_bpf, buf, len + sizeof(struct ether_header)); eh->ether_type = ntohs((u_short)eh->ether_type); /* * Note that the interface cannot be in promiscuous mode if * there are no bpf listeners. And if we are in promiscuous * mode, we have to check if this packet is really ours. */ if ((ns->ns_if.if_flags & IFF_PROMISC) && bcmp(eh->ether_dhost, ns->sc_addr, sizeof(eh->ether_dhost)) != 0 &&#ifdef MULTICAST /* non-multicast (also non-broadcast) */ !ETHER_IS_MULTICAST(eh->ether_dhost)#else bcmp(eh->ether_dhost, etherbroadcastaddr, sizeof(eh->ether_dhost)) != 0#endif ) return; }#endif /* NBPFILTER > 0 */#if 0 /* * Promiscuous multicast hack will cause us to receive * packets we don't want. Be paranoid and always filter. */ if (!ETHER_IS_MULTICAST(eh->ether_dhost) && bcmp(eh->ether_dhost, ns->sc_addr, sizeof(eh->ether_dhost)) != 0) return;#endif /* * Pull packet off interface. Off is nonzero if packet * has trailing header; neget will then force this header * information to be at the front, but we still have to drop * the type and length which are at the front of any trailer data. */ m = neget(buf, len, off, &ns->ns_if); if (m == 0) return; ether_input(&ns->ns_if, eh, m);}/* * Supporting routines *//* * Pull read data off a interface. * Len is length of data, with local net header stripped. * Off is non-zero if a trailer protocol was used, and * gives the offset of the trailer information. * We copy the trailer information and then all the normal * data into mbufs. When full cluster sized units are present * we copy into clusters. */struct mbuf *neget(buf, totlen, off0, ifp) caddr_t buf; int totlen, off0; struct ifnet *ifp;{ struct mbuf *top, **mp, *m; int off = off0, len; register caddr_t cp = buf; char *epkt; buf += sizeof(struct ether_header); cp = buf; epkt = cp + totlen; if (off) { cp += off + 2 * sizeof(u_short); totlen -= 2 * sizeof(u_short); } MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == 0) return (0); m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = totlen; m->m_len = MHLEN; top = 0; mp = ⊤ while (totlen > 0) { if (top) { MGET(m, M_DONTWAIT, MT_DATA); if (m == 0) { m_freem(top); return (0); } m->m_len = MLEN; } len = min(totlen, epkt - cp); if (len >= MINCLSIZE) { MCLGET(m, M_DONTWAIT); if (m->m_flags & M_EXT) m->m_len = len = min(len, MCLBYTES); else len = m->m_len; } else { /* * Place initial small packet/header at end of mbuf. */ if (len < m->m_len) { if (top == 0 && len + max_linkhdr <= m->m_len) m->m_data += max_linkhdr; m->m_len = len; } else len = m->m_len; } bcopy(cp, mtod(m, caddr_t), (unsigned)len); cp += len; *mp = m; mp = &m->m_next; totlen -= len; if (cp == epkt) cp = buf; } return (top);}/* * Process an ioctl request. */neioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ register struct ifaddr *ifa = (struct ifaddr *)data; struct ne_softc *ns = (struct ne_softc *) necd.cd_devs[ifp->if_unit]; register nec = ns->ns_base; int s; int error = 0; s = splimp(); switch (cmd) {#ifdef PROM case SIOCPOLL: if (ns->ns_if.if_flags & IFF_RUNNING) neintr (ns); break;#endif case SIOCSIFADDR: ifp->if_flags |= IFF_UP; switch (ifa->ifa_addr->sa_family) {#ifdef INET case AF_INET: neinit(ifp->if_unit); arp_ifinit((struct arpcom *)ifp, ifa); break;#endif#ifdef NS case AF_NS: { register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); if (ns_nullhost(*ina)) ina->x_host = *(union ns_host *)(ns->sc_addr); else { /* * The manual says we can't change the address * while the receiver is armed, * so reset everything */ ifp->if_flags &= ~IFF_RUNNING; bcopy((caddr_t)ina->x_host.c_host, (caddr_t)ns->sc_addr, sizeof(ns->sc_addr)); } neinit(ifp->if_unit); /* does ne_setaddr() */ break; }#endif default: neinit(ifp->if_unit); break; } break; case SIOCSIFFLAGS: if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) { ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); outb(nec+ds_cmd, DSCM_STOP|DSCM_NODMA); } else neinit(ifp->if_unit); break;#ifdef MULTICAST /* * Update our multicast list. */ case SIOCADDMULTI: error = ether_addmulti((struct ifreq *)data, &ns->ns_ac); goto reset; case SIOCDELMULTI: error = ether_delmulti((struct ifreq *)data, &ns->ns_ac); reset: if (error == ENETRESET) { neinit(ifp->if_unit); error = 0; } break;#endif#ifdef notdef case SIOCGHWADDR: bcopy((caddr_t)ns->sc_addr, (caddr_t) &ifr->ifr_data, sizeof(ns->sc_addr)); break;#endif default: error = EINVAL; } ns->ns_ifoldflags = ifp->if_flags; splx(s); return (error);}#ifdef PROM/* * eninit(): initialise ethernet *//* probe these i/o port addresses only */static const int neports[] = {0x320, 0x340, 0x360, -1};inteninit (){ static struct isa_attach_args ia; static struct ne_softc sc; static struct cfdata cf; static void *devs[2]; unsigned int i; cf.cf_unit = 0; ia.ia_unit = 0; for (i = 0; neports[i] > 0; i++) { ia.ia_iobase = neports[i]; if (neprobe (NULL, &cf, &ia)) { necd.cd_devs = devs; necd.cd_devs[0] = ≻ neattach (NULL, (struct device *)&sc, &ia); return 1; } } return 0;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -