📄 if_de.c
字号:
for (rp = &ds->ds_rrent[0]; rp < &ds->ds_rrent[NRCV]; rp++) { rp->r_slen = sizeof (struct de_buf); rp->r_segbl = ifrw->ifrw_info & 0xffff; rp->r_segbh = (ifrw->ifrw_info >> 16) & 0x3; rp->r_flags = RFLG_OWN; /* hang receive */ ifrw++; } /* start up the board (rah rah) */ s = splimp(); ds->ds_rindex = ds->ds_xindex = ds->ds_xfree = ds->ds_nxmit = 0; ds->ds_if.if_flags |= IFF_RUNNING; addr->pclow = PCSR0_INTE; /* avoid interlock */ destart(&ds->ds_if); /* queue output packets */ ds->ds_flags |= DSF_RUNNING; /* need before de_setaddr */ if (ds->ds_flags & DSF_SETADDR) de_setaddr(ds->ds_addr, unit); addr->pclow = CMD_START | PCSR0_INTE; splx(s);}/* * Setup output on interface. * Get another datagram to send off of the interface queue, * and map it to the interface before starting the output. * Must be called from ipl >= our interrupt level. */destart(ifp) struct ifnet *ifp;{ int len; int unit = ifp->if_unit; struct uba_device *ui = deinfo[unit]; struct dedevice *addr = (struct dedevice *)ui->ui_addr; register struct de_softc *ds = &de_softc[unit]; register struct de_ring *rp; struct mbuf *m; register int nxmit; /* * the following test is necessary, since * the code is not reentrant and we have * multiple transmission buffers. */ if (ds->ds_if.if_flags & IFF_OACTIVE) return; for (nxmit = ds->ds_nxmit; nxmit < NXMT; nxmit++) { IF_DEQUEUE(&ds->ds_if.if_snd, m); if (m == 0) break; rp = &ds->ds_xrent[ds->ds_xfree]; if (rp->r_flags & XFLG_OWN) panic("deuna xmit in progress"); len = if_ubaput(&ds->ds_deuba, &ds->ds_ifw[ds->ds_xfree], m); if (ds->ds_deuba.iff_flags & UBA_NEEDBDP) UBAPURGE(ds->ds_deuba.iff_uba, ds->ds_ifw[ds->ds_xfree].ifw_bdp); rp->r_slen = len; rp->r_tdrerr = 0; rp->r_flags = XFLG_STP|XFLG_ENP|XFLG_OWN; ds->ds_xfree++; if (ds->ds_xfree == NXMT) ds->ds_xfree = 0; } if (ds->ds_nxmit != nxmit) { ds->ds_nxmit = nxmit; if (ds->ds_flags & DSF_RUNNING) addr->pclow = PCSR0_INTE|CMD_PDMD; }}/* * Command done interrupt. */deintr(unit) int unit;{ struct uba_device *ui = deinfo[unit]; register struct dedevice *addr = (struct dedevice *)ui->ui_addr; register struct de_softc *ds = &de_softc[unit]; register struct de_ring *rp; register struct ifxmt *ifxp; short csr0; /* save flags right away - clear out interrupt bits */ csr0 = addr->pcsr0; addr->pchigh = csr0 >> 8; ds->ds_if.if_flags |= IFF_OACTIVE; /* prevent entering destart */ /* * if receive, put receive buffer on mbuf * and hang the request again */ derecv(unit); /* * Poll transmit ring and check status. * Be careful about loopback requests. * Then free buffer space and check for * more transmit requests. */ for ( ; ds->ds_nxmit > 0; ds->ds_nxmit--) { rp = &ds->ds_xrent[ds->ds_xindex]; if (rp->r_flags & XFLG_OWN) break; ds->ds_if.if_opackets++; ifxp = &ds->ds_ifw[ds->ds_xindex]; /* check for unusual conditions */ if (rp->r_flags & (XFLG_ERRS|XFLG_MTCH|XFLG_ONE|XFLG_MORE)) { if (rp->r_flags & XFLG_ERRS) { /* output error */ ds->ds_if.if_oerrors++; if (dedebug) printf("de%d: oerror, flags=%b tdrerr=%b (len=%d)\n", unit, rp->r_flags, XFLG_BITS, rp->r_tdrerr, XERR_BITS, rp->r_slen); } else if (rp->r_flags & XFLG_ONE) { /* one collision */ ds->ds_if.if_collisions++; } else if (rp->r_flags & XFLG_MORE) { /* more than one collision */ ds->ds_if.if_collisions += 2; /* guess */ } else if (rp->r_flags & XFLG_MTCH) { /* received our own packet */ ds->ds_if.if_ipackets++; deread(ds, &ifxp->ifrw, rp->r_slen - sizeof (struct ether_header)); } } if (ifxp->ifw_xtofree) { m_freem(ifxp->ifw_xtofree); ifxp->ifw_xtofree = 0; } /* check if next transmit buffer also finished */ ds->ds_xindex++; if (ds->ds_xindex == NXMT) ds->ds_xindex = 0; } ds->ds_if.if_flags &= ~IFF_OACTIVE; destart(&ds->ds_if); if (csr0 & PCSR0_RCBI) { if (dedebug) log(LOG_WARNING, "de%d: buffer unavailable\n", unit); addr->pclow = PCSR0_INTE|CMD_PDMD; }}/* * Ethernet interface receiver interface. * If input error just drop packet. * Otherwise purge input buffered data path and 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. */derecv(unit) int unit;{ register struct de_softc *ds = &de_softc[unit]; register struct de_ring *rp; int len; rp = &ds->ds_rrent[ds->ds_rindex]; while ((rp->r_flags & RFLG_OWN) == 0) { ds->ds_if.if_ipackets++; if (ds->ds_deuba.iff_flags & UBA_NEEDBDP) UBAPURGE(ds->ds_deuba.iff_uba, ds->ds_ifr[ds->ds_rindex].ifrw_bdp); len = (rp->r_lenerr&RERR_MLEN) - sizeof (struct ether_header) - 4; /* don't forget checksum! */ /* check for errors */ if ((rp->r_flags & (RFLG_ERRS|RFLG_FRAM|RFLG_OFLO|RFLG_CRC)) || (rp->r_flags&(RFLG_STP|RFLG_ENP)) != (RFLG_STP|RFLG_ENP) || (rp->r_lenerr & (RERR_BUFL|RERR_UBTO|RERR_NCHN)) || len < ETHERMIN || len > ETHERMTU) { ds->ds_if.if_ierrors++; if (dedebug) printf("de%d: ierror, flags=%b lenerr=%b (len=%d)\n", unit, rp->r_flags, RFLG_BITS, rp->r_lenerr, RERR_BITS, len); } else deread(ds, &ds->ds_ifr[ds->ds_rindex], len); /* hang the receive buffer again */ rp->r_lenerr = 0; rp->r_flags = RFLG_OWN; /* check next receive buffer */ ds->ds_rindex++; if (ds->ds_rindex == NRCV) ds->ds_rindex = 0; rp = &ds->ds_rrent[ds->ds_rindex]; }}/* * Pass a packet to the higher levels. * We deal with the trailer protocol here. */deread(ds, ifrw, len) register struct de_softc *ds; struct ifrw *ifrw; int len;{ struct ether_header *eh; struct mbuf *m; int off, resid; int s; register struct ifqueue *inq; /* * 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 *)ifrw->ifrw_addr; eh->ether_type = ntohs((u_short)eh->ether_type);#define dedataaddr(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(*dedataaddr(eh, off, u_short *)); resid = ntohs(*(dedataaddr(eh, off+2, u_short *))); if (off + resid > len) return; /* sanity */ len = off + resid; } else off = 0; if (len == 0) return; /* * Pull packet off interface. Off is nonzero if packet * has trailing header; if_ubaget will then force this header * information to be at the front. */ m = if_ubaget(&ds->ds_deuba, ifrw, len, off, &ds->ds_if); if (m) ether_input(&ds->ds_if, eh, m);}/* * Process an ioctl request. */deioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ register struct ifaddr *ifa = (struct ifaddr *)data; register struct de_softc *ds = &de_softc[ifp->if_unit]; int s = splimp(), error = 0; switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; deinit(ifp->if_unit); switch (ifa->ifa_addr->sa_family) {#ifdef INET case AF_INET: ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr; arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 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 *)(ds->ds_addr); else de_setaddr(ina->x_host.c_host,ifp->if_unit); break; }#endif } break; case SIOCSIFFLAGS: if ((ifp->if_flags & IFF_UP) == 0 && ds->ds_flags & DSF_RUNNING) { ((struct dedevice *) (deinfo[ifp->if_unit]->ui_addr))->pclow = 0; DELAY(100); ((struct dedevice *) (deinfo[ifp->if_unit]->ui_addr))->pclow = PCSR0_RSET; ds->ds_flags &= ~DSF_RUNNING; ds->ds_if.if_flags &= ~IFF_OACTIVE; } else if (ifp->if_flags & IFF_UP && (ds->ds_flags & DSF_RUNNING) == 0) deinit(ifp->if_unit); break; default: error = EINVAL; } splx(s); return (error);}/* * set ethernet address for unit */de_setaddr(physaddr, unit) u_char *physaddr; int unit;{ register struct de_softc *ds = &de_softc[unit]; struct uba_device *ui = deinfo[unit]; register struct dedevice *addr= (struct dedevice *)ui->ui_addr; if (! (ds->ds_flags & DSF_RUNNING)) return; bcopy((caddr_t) physaddr, (caddr_t) &ds->ds_pcbb.pcbb2, 6); ds->ds_pcbb.pcbb0 = FC_WTPHYAD; addr->pclow = PCSR0_INTE|CMD_GETCMD; if (dewait(ui, "address change") == 0) { ds->ds_flags |= DSF_SETADDR; bcopy((caddr_t) physaddr, (caddr_t) ds->ds_addr, 6); }}/* * Await completion of the named function * and check for errors. */dewait(ui, fn) register struct uba_device *ui; char *fn;{ register struct dedevice *addr = (struct dedevice *)ui->ui_addr; register csr0; while ((addr->pcsr0 & PCSR0_INTR) == 0) ; csr0 = addr->pcsr0; addr->pchigh = csr0 >> 8; if (csr0 & PCSR0_PCEI) printf("de%d: %s failed, csr0=%b csr1=%b\n", ui->ui_unit, fn, csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS); return (csr0 & PCSR0_PCEI);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -