📄 if_dmv.c
字号:
if ((sc->sc_flag & (DMV_ALLOC | DMV_BMAPPED)) == (DMV_ALLOC | DMV_BMAPPED) && ( sc->sc_flag & DMV_RESTART) == 0 ) { sc->sc_flag |= DMV_RESTART; sc->sc_if.if_flags &= ~IFF_UP; sc->sc_dmvcs.if_dstate = IFS_HALTING; dmvrestart(sc->sc_if.if_unit); } break; case SIOCDISABLBACK: /* * place device out of loopback */ if ( ! dmvsuser() ) return(EACCES); printf("dmv%d: internal loopback disable requested\n", ifp->if_unit); ifp->if_flags &= ~IFF_LOOPBACK; if ((sc->sc_flag & (DMV_ALLOC | DMV_BMAPPED)) == (DMV_ALLOC | DMV_BMAPPED) && ( sc->sc_flag & DMV_RESTART) == 0 ) { sc->sc_flag |= DMV_RESTART; sc->sc_if.if_flags &= ~IFF_UP; sc->sc_dmvcs.if_dstate = IFS_HALTING; dmvrestart(sc->sc_if.if_unit); } break; case SIOCRDCTRS: case SIOCRDZCTRS: /* * reading and zeroing line counters */ { u_char rqflg; register struct ctrreq *ctr = (struct ctrreq *)data; /* * Since this code is not reentrant, only one process * can call it at any one time. */ if ( (sc->sc_ctrmask & DMV_MSK_BUSY) == DMV_MSK_BUSY ) return(EBUSY); sc->sc_ctrmask = DMV_MSK_BUSY; if ( cmd == SIOCRDZCTRS ) { rqflg = DMV_CNTL_READZ; } else rqflg = DMV_CNTL_READ; /* * issue request for counters. */ dmv_issue_ctl( sc, DMV_TRIB_POINT, 0, (rqflg | DMV_KEY_SELINT) ); dmv_issue_ctl( sc, DMV_TRIB_POINT, 0, (rqflg | DMV_KEY_DEOUT) ); dmv_issue_ctl( sc, DMV_TRIB_POINT, 0, (rqflg | DMV_KEY_DEIN) ); dmv_issue_ctl( sc, DMV_TRIB_POINT, 0, (rqflg | DMV_KEY_LBERR) ); dmv_issue_ctl( sc, DMV_TRIB_POINT, 0, (rqflg | DMV_KEY_RBERR) ); dmv_issue_ctl( sc, DMV_TRIB_POINT, 0, (rqflg | DMV_KEY_SELTO) ); dmv_issue_ctl( sc, DMV_TRIB_POINT, 0, (rqflg | DMV_KEY_REPTO) ); dmv_issue_ctl( sc, 0, 0, (rqflg | DMV_KEY_RSERR) ); dmv_issue_ctl( sc, 0, 0, (rqflg | DMV_KEY_LSERR) ); /* * wait for response from device. * * If on interrupt stack, call came from timer routine. * Return without sleep. Call ifioctl later when done. */ if ( ! (movpsl() & PSL_IS)) { while ( sc->sc_ctrmask != DMV_MSK_CMPLT ) sleep((caddr_t) &sc->sc_ctrmask, PZERO+1); } else { dmv_instack[sc->sc_if.if_unit] = 1; error = EINVAL; break; } /* * format counters */ ctr->ctr_type = CTR_DDCMP; sc->sc_errctrs.ctr_ddcmp.dst_seconds = (time.tv_sec - sc->sc_ztime) > 0xfffe ? 0xffff : (time.tv_sec - sc->sc_ztime); ctr->ctr_ddcmp = sc->sc_errctrs.ctr_ddcmp; if ( cmd == SIOCRDZCTRS ) { sc->sc_ztime = time.tv_sec; sc->sc_errctrs.ctr_ddcmp.dst_bytercvd = 0; sc->sc_errctrs.ctr_ddcmp.dst_bytesent = 0; sc->sc_errctrs.ctr_ddcmp.dst_blockrcvd = 0; sc->sc_errctrs.ctr_ddcmp.dst_blocksent = 0; } sc->sc_ctrmask = 0; break; } case SIOCSIFADDR: ifp->if_flags |= IFF_UP; if ((ifp->if_flags & IFF_RUNNING) == 0) dmvinit(ifp->if_unit); break; case SIOCSIFDSTADDR: if ((ifp->if_flags & IFF_RUNNING) == 0) dmvinit(ifp->if_unit); break; default: error = EINVAL; } splx(s); return(error);}/* * Routines supporting UNIBUS network interfaces. *//* * Init Q-BUS for interface on uban whose headers of size hlen are to * end on a page boundary. We allocate a Q-BUS 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. */dmv_ubainit(ifu, uban, hlen, nmr, bufres) register struct dmvuba *ifu; int uban, hlen, nmr; struct dmvbufres *bufres;{ register caddr_t cp, dp; register struct ifrw *ifrw; register struct ifxmt *ifxp; int i, ncl; ncl = clrnd(nmr + (hlen? CLSIZE: 0)) / 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 - (hlen? (CLBYTES - hlen): 0); else { cp = bufres->buffers; if (cp == 0) return (0); ifu->ifu_hlen = hlen; ifu->ifu_uban = uban; ifu->ifu_uba = uba_hd[uban].uh_uba; dp = cp + (hlen? (CLBYTES - hlen): 0); for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[bufres->nrcv]; ifrw++) { ifrw->ifrw_addr = dp; dp += ncl * CLBYTES; } for (ifxp = ifu->ifu_w; ifxp < &ifu->ifu_w[bufres->nxmt]; ifxp++) { ifxp->x_ifrw.ifrw_addr = dp; dp += ncl * CLBYTES; } } /* allocate for receive ring */ for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[bufres->nrcv]; ifrw++) { if (dmv_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[bufres->nxmt]; ifxp++) { ifrw = &ifxp->x_ifrw; if (dmv_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[bufres->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, bufres->ntot * ncl); ifu->ifu_r[0].ifrw_addr = 0; return(0);}/* * Setup either an ifrw structure by allocating Q-BUS map registers, * possibly a buffered data path, and initializing the fields of * the ifrw structure to minimize run-time overhead. */staticdmv_ubaalloc(ifu, ifrw, nmr) struct dmvuba *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) +(ifu->ifu_hlen? 1: 0)]; 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 *dmv_get(ifu, ifrw, totlen, off0, dmv_header) register struct dmvuba *ifu; register struct ifrw *ifrw; int totlen, off0, dmv_header;{ struct mbuf *top, **mp, *m; int off = off0, len; register caddr_t cp = ifrw->ifrw_addr; register short hlen = 0; if ( dmv_header ) { hlen = ifu->ifu_hlen; cp += 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 + hlen + off; } else len = totlen; if (len >= CLBYTES) { 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; /* * Switch pages mapped to Q-BUS with new page p, * as quick form of copy. Remap Q-BUS 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 + hlen; off = 0; totlen = off0; } } else totlen -= m->m_len; } return (top);bad: m_freem(top); return (0);}/* * Map a chain of mbufs onto a network interface * in preparation for an i/o operation. * The argument chain of mbufs includes the local network * header which is copied to be in the mapped, aligned * i/o space. */dmvput(ifu, n, m) struct dmvuba *ifu; int n; register struct mbuf *m;{ register struct mbuf *mp; register caddr_t cp; register struct ifxmt *ifxp; register struct ifrw *ifrw; register int i; int xswapd = 0; int x, cc, t; caddr_t dp; ifxp = &ifu->ifu_w[n]; ifrw = &ifxp->x_ifrw; cp = ifrw->ifrw_addr; while (m) { dp = mtod(m, char *); if (claligned(cp) && claligned(dp) && m->m_len == CLBYTES) { struct pte *pte; int *ip; pte = &kmempt[mtocl(dp)]; x = btop(cp - ifrw->ifrw_addr); ip = (int *)&ifrw->ifrw_mr[x]; for (i = 0; i < CLSIZE; i++) *ip++ = ifrw->ifrw_proto | pte++->pg_pfnum; xswapd |= 1 << (x>>(CLSHIFT-PGSHIFT)); mp = m->m_next; m->m_next = ifxp->x_xtofree; ifxp->x_xtofree = m; cp += m->m_len; } else { bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len); cp += m->m_len; MFREE(m, mp); } m = mp; } /* * Xswapd is the set of clusters we just mapped out. Ifxp->x_xswapd * is the set of clusters mapped out from before. We compute * the number of clusters involved in this operation in x. * Clusters mapped out before and involved in this operation * should be unmapped so original pages will be accessed by the device. */ cc = cp - ifrw->ifrw_addr; x = ((cc - ifu->ifu_hlen) + CLBYTES - 1) >> CLSHIFT; ifxp->x_xswapd &= ~xswapd; while (i = ffs(ifxp->x_xswapd)) { i--; if (i >= x) break; ifxp->x_xswapd &= ~(1<<i); i *= CLSIZE; for (t = 0; t < CLSIZE; t++) { ifrw->ifrw_mr[i] = ifxp->x_map[i]; i++; } } ifxp->x_xswapd |= xswapd; return (cc);}/* * Restart after a fatal error. * Clear device and reinitialize. */dmvrestart(unit) int unit;{ register struct dmv_softc *sc = &dmv_softc[unit]; register struct uba_device *ui = dmvinfo[unit]; register struct dmvdevice *addr; register struct ifxmt *ifxp; register int i; register struct mbuf *m; struct dmvuba *ifu; addr = (struct dmvdevice *)ui->ui_addr; ifu = &sc->sc_ifuba; /* * Let the DMV finish the MCLR. At 1 Mbit, it should do so * in about a max of 6.4 milliseconds with diagnostics enabled. */ addr->bsel1 = DMV_MCLR; for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) ; /* Did the timer expire or did the DMR finish? */ if ((addr->bsel1 & DMV_RUN) == 0) { printf("dmv%d: Startup Diagnostics Test Failed\n", unit); return; } /* purge send queue */ IF_DEQUEUE(&sc->sc_if.if_snd, m); while (m) { m_freem(m); IF_DEQUEUE(&sc->sc_if.if_snd, m); } for (ifxp = ifu->ifu_w; ifxp < &ifu->ifu_w[sc->sc_bufres.nxmt]; ifxp++) { if (ifxp->x_xtofree) { (void) m_freem(ifxp->x_xtofree); ifxp->x_xtofree = 0; } } /* restart DMV */ dmvinit(unit); sc->sc_flag &= ~DMV_RESTART; sc->sc_if.if_collisions++; /* why not? */}/* * Check to see that transmitted packets don't * lose interrupts. The device has to be active. */dmvwatch(){ register struct uba_device *ui; register struct dmv_softc *sc; struct dmvdevice *addr; register int i; for (i = 0; i < nNDMV; i++) { sc = &dmv_softc[i]; if ((sc->sc_flag & DMV_ACTIVE) == 0) continue; if ((ui = dmvinfo[i]) == 0 || ui->ui_alive == 0) continue; if (sc->sc_oused) { sc->sc_nticks++; if (sc->sc_nticks > dmv_timeout) { sc->sc_nticks = 0; addr = (struct dmvdevice *)ui->ui_addr; printd("dmvwatch: dmv%d hung, bsel0 = 0x%x, bsel1 = 0x%x, bsel2 = 0x%x\n", i, addr->bsel0 & 0xff, addr->bsel1 & 0xff, addr->bsel2 & 0xff); if (( sc->sc_flag & DMV_RESTART) == 0 ) { sc->sc_flag |= DMV_RESTART; sc->sc_if.if_flags &= ~IFF_UP; sc->sc_dmvcs.if_dstate = IFS_HALTING; dmvrestart(i); } } } } timeout(dmvwatch, (caddr_t) 0, hz);}/* * Check to make sure requestor is priveleged. suser is * called when not on interrupt stack or when * there is a system process. */dmvsuser(){ if ( ! (movpsl() & PSL_IS)) return(suser()); return(1);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -