📄 if_de.c
字号:
ds->ds_nxmit = nxmit; ds->ds_if.if_flags |= IFF_OACTIVE; if (ds->ds_flags & DSF_RUNNING) addr->pclow = PCSR0_INTE|CMD_PDMD; } else if (ds->ds_nxmit == NXMT) { /* LSC002 */ /* * poke device if we have something to send and * transmit ring is full. */ if (dedebug) { rp = &ds->ds_xrent[0]; mprintf("did not xmt: %d, %d, %d, flag0=%x, flag1=%x\n", ds->ds_xindex, ds->ds_nxmit, ds->ds_xfree, rp++->r_flags, rp->r_flags); } 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; int s; s = splimp(); /* SMP */ smp_lock(&ds->lk_de_softc, LK_RETRY); /* save flags right away - clear out interrupt bits */ csr0 = addr->pcsr0; addr->pchigh = csr0 >> 8; /* * Error condition interrupts. No recovery attempted - just * printf and leave the interface alone. */ if (csr0 & PCSR0_FATI) printf ("de%d: unsolicited state change, csr0=%b, csr1=0x%04x\n", unit, csr0, PCSR0_BITS, addr->pcsr1); if (csr0 & PCSR0_SERI) mprintf ("de%d: status error, csr0=%b\n", unit, csr0, PCSR0_BITS); /* * if receive, put receive buffer on mbuf * and hang the request again */ if ((ds->ds_rrent[ds->ds_rindex].r_flags & RFLG_OWN) == 0) 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_deuba.ifu_w[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 { /* no oerrors */ 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 */ }/*001*/ if ( ((rp->r_flags & XFLG_MTCH) && !(ds->ds_if.if_flags & IFF_LOOPBACK)) || (ds->ds_if.if_flags & IFF_PFCOPYALL) ) { /* received our own packet */ ds->ds_if.if_ipackets++; if (dedebug) mprintf("de%d: loop\n", unit); deread(ds, &ifxp->x_ifrw, rp->r_slen - sizeof (struct ether_header), ifxp->x_xtofree); ifxp->x_xtofree = 0; } } /* end else no oerrors */ } if (ifxp->x_xtofree) { m_freem(ifxp->x_xtofree); ifxp->x_xtofree = 0; } /* check if next transmit buffer also finished */ ds->ds_xindex++; if (ds->ds_xindex == NXMT) ds->ds_xindex = 0; } if (!(ds->ds_nxmit)) { ds->ds_if.if_flags &= ~IFF_OACTIVE; destart(unit); } /* * This may have happened for EITHER a user or system buffer * unavailable. In both cases, need to turn on interrupts and * tell the interface that receive buffers have been freed up. * The "de0: buffer unavailable" printf has been removed since * the counter block already records system and user buffer unavail. */ if (csr0 & PCSR0_RCBI) addr->pclow = PCSR0_INTE|CMD_PDMD; smp_unlock(&ds->lk_de_softc); splx(s);}/* * 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 ifnet *ifp = &ds->ds_if; register struct de_ring *rp; register struct ether_header *eh; 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.ifu_flags & UBA_NEEDBDP) UBAPURGE(ds->ds_deuba.ifu_uba, ds->ds_deuba.ifu_r[ds->ds_rindex].ifrw_bdp, ds->ds_deuba.ifu_uban); len = (rp->r_lenerr&RERR_MLEN) - sizeof (struct ether_header) - 4; /* don't forget checksum! */ if( ! (ifp->if_flags & IFF_LOOPBACK) ) { /* * check for errors * * Added Bit test RERR_OVRN <bit 12>, message overrun error * This bit is always zero for the DEUNA so no additional test * are needed. */ 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_OVRN|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_deuba.ifu_r[ds->ds_rindex], len, 0); } } else { eh = (struct ether_header *)ds->ds_deuba.ifu_r[ds->ds_rindex].ifrw_addr; if ( bcmp(eh->ether_dhost, ds->ds_addr, 6) == NULL ){ deread(ds, &ds->ds_deuba.ifu_r[ds->ds_rindex], len, 0); } } /* 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, swloop) register struct de_softc *ds; struct ifrw *ifrw; int len; struct mbuf *swloop;{ struct ether_header *eh, swloop_eh; struct mbuf *m, *swloop_tmp1, *swloop_tmp2; struct protosw *pr; int off, resid; struct ifqueue *inq; /* * Deal with trailer protocol: if type is trailer * get true type from first 16-bit word past data. * Remember that type was trailer by setting off. */ if (swloop) { eh = mtod(swloop, struct ether_header *); swloop_eh = *eh; eh = &swloop_eh; if ( swloop->m_len > sizeof(struct ether_header)) m_adj(swloop, sizeof(struct ether_header)); else { MFREE(swloop, swloop_tmp1); if ( ! swloop_tmp1 ) return; else swloop = swloop_tmp1; } } else 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 */ if (swloop) { struct mbuf *mprev, *m0 = swloop;/* need to check this against off */ mprev = m0; while (swloop->m_next){/*real header at end of chain*/ mprev = swloop; swloop = swloop->m_next; } /* move to beginning of chain */ mprev->m_next = 0; swloop->m_next = m0; eh->ether_type = ntohs( *mtod(swloop, u_short *)); } else { 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; deget 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. */ if (swloop) { m = m_copy(swloop, 0, M_COPYALL); m_freem(swloop); } else { m = deget(&ds->ds_deuba, ifrw, len, off); } if (m == 0) return; if (off) { m->m_off += 2 * sizeof (u_short); m->m_len -= 2 * sizeof (u_short); } /* Dispatch this packet */ net_read(&(ds->ds_ed), eh, m, len, (swloop != NULL), (off != 0));}/* * Routines supporting UNIBUS network interfaces. *//* * Init UNIBUS for interface on uban whose headers of size hlen are to * end on a page boundary. We allocate a UNIBUS map register for the page * with the header, and nmr more UNIBUS map registers for i/o on the adapter, * doing this for each receive and transmit buffer. We also * allocate page frames in the mbuffer pool for these pages. */de_ubainit(ifu, uban, hlen, nmr) register struct deuba *ifu; int uban, hlen, nmr;{ register caddr_t cp, dp; register struct ifrw *ifrw; register struct ifxmt *ifxp; int i, ncl; ncl = clrnd(nmr + CLSIZE) / CLSIZE; if (ifu->ifu_r[0].ifrw_addr) /* * If the first read buffer has a non-zero * address, it means we have already allocated core */ cp = ifu->ifu_r[0].ifrw_addr - (CLBYTES - hlen); else { cp = m_clalloc(NTOT * ncl, MPG_SPACE); if (cp == 0) return (0); ifu->ifu_hlen = hlen; ifu->ifu_uban = uban; ifu->ifu_uba = uba_hd[uban].uh_uba; dp = cp + CLBYTES - hlen; for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[NRCV]; ifrw++) { ifrw->ifrw_addr = dp; dp += ncl * CLBYTES; } for (ifxp = ifu->ifu_w; ifxp < &ifu->ifu_w[NXMT]; ifxp++) { ifxp->x_ifrw.ifrw_addr = dp; dp += ncl * CLBYTES; } } /* allocate for receive ring */ for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[NRCV]; ifrw++) { if (de_ubaalloc(ifu, ifrw, nmr) == 0) { struct ifrw *rw; for (rw = ifu->ifu_r; rw < ifrw; rw++) ubarelse(ifu->ifu_uban, &rw->ifrw_info); goto bad; } } /* and now transmit ring */ for (ifxp = ifu->ifu_w; ifxp < &ifu->ifu_w[NXMT]; ifxp++) { ifrw = &ifxp->x_ifrw; if (de_ubaalloc(ifu, ifrw, nmr) == 0) { struct ifxmt *xp; for (xp = ifu->ifu_w; xp < ifxp; xp++) ubarelse(ifu->ifu_uban, &xp->x_ifrw.ifrw_info); for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[NRCV]; ifrw++) ubarelse(ifu->ifu_uban, &ifrw->ifrw_info); goto bad; } for (i = 0; i < nmr; i++) ifxp->x_map[i] = ifrw->ifrw_mr[i]; ifxp->x_xswapd = 0; } return (1);bad: m_pgfree(cp, NTOT * ncl); ifu->ifu_r[0].ifrw_addr = 0; return(0);}/* * Setup either a ifrw structure by allocating UNIBUS map registers, * possibly a buffered data path, and initializing the fields of * the ifrw structure to minimize run-time overhead. */staticde_ubaalloc(ifu, ifrw, nmr) struct deuba *ifu; register struct ifrw *ifrw; int nmr;{ register int info; info = uballoc(ifu->ifu_uban, ifrw->ifrw_addr, nmr*NBPG + ifu->ifu_hlen, ifu->ifu_flags); if (info == 0) return (0); ifrw->ifrw_info = info; ifrw->ifrw_bdp = UBAI_BDP(info); ifrw->ifrw_proto = UBAMR_MRV | (UBAI_BDP(info) << UBAMR_DPSHIFT); ifrw->ifrw_mr = &ifu->ifu_uba->uba_map[UBAI_MR(info) + 1]; return (1);}/* * 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 * on the interface on cluster boundaries we can get them more * easily by remapping, and take advantage of this here. */struct mbuf *deget(ifu, ifrw, totlen, off0) register struct deuba *ifu; register struct ifrw *ifrw; int totlen, off0;{ struct mbuf *top, **mp, *m; int off = off0, len; register caddr_t cp = ifrw->ifrw_addr + ifu->ifu_hlen; top = 0; mp = ⊤ while (totlen > 0) { MGET(m, M_DONTWAIT, MT_DATA); if (m == 0) goto bad; if (off) { len = totlen - off; cp = ifrw->ifrw_addr + ifu->ifu_hlen + off; } else len = totlen; if (len == CLBYTES) { /* For now only 1 cluster */ /* May ultimately fix mapping */ struct mbuf *p; struct pte *cpte, *ppte; int x, *ip, i; MCLGET(m, p); if (p == 0) goto nopage; len = m->m_len = CLBYTES; if (!claligned(cp)) goto copy; /* faster just to copy in SMP case since we would have to sync up TB's */ if (smp) goto copy; /* * Switch pages mapped to UNIBUS with new page p, * as quick form of copy. Remap UNIBUS and invalidate. */ cpte = &kmempt[mtocl(cp)]; ppte = &kmempt[mtocl(p)]; x = btop(cp - ifrw->ifrw_addr); ip = (int *)&ifrw->ifrw_mr[x]; for (i = 0; i < CLSIZE; i++) { struct pte t; t = *ppte; *ppte++ = *cpte; *cpte = t; *ip++ = cpte++->pg_pfnum|ifrw->ifrw_proto; mtpr(TBIS, cp); cp += NBPG; mtpr(TBIS, (caddr_t)p); p += NBPG / sizeof (*p); } goto nocopy; }nopage: m->m_len = MIN(MLEN, len); m->m_off = MMINOFF;copy: bcopy(cp, mtod(m, caddr_t), (unsigned)m->m_len); cp += m->m_len;nocopy: *mp = m; mp = &m->m_next; if (off) { /* sort of an ALGOL-W style for statement... */ off += m->m_len; if (off == totlen) { cp = ifrw->ifrw_addr + ifu->ifu_hlen; off = 0; totlen = off0; } } else totlen -= m->m_len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -