📄 if_qe.c
字号:
#ifdef mips /* * Flush the cache memory for the * receiver ring buffer */ clean_dcache(PHYS_TO_K0(svtophy(sc->qeuba.ifu_r[sc->rindex].ifrw_addr)),len);#endif mips qeread(sc, &sc->qeuba.ifu_r[sc->rindex], len - sizeof(struct ether_header),0); } } } else {#ifdef mips /* * Flush the cache memory for the * receiver ring buffer */ clean_dcache(PHYS_TO_K0(svtophy(sc->qeuba.ifu_r[sc->rindex].ifrw_addr)),len);#endif mips eh = (struct ether_header *)sc->qeuba.ifu_r[sc->rindex].ifrw_addr; if ( bcmp(eh->ether_dhost, sc->is_addr, 6) == NULL ) qeread(sc, &sc->qeuba.ifu_r[sc->rindex], len - sizeof(struct ether_header),0); } /* * Return the buffer(s) to the ring. Only have multiple * buffers on chained packets. */drop: bufaddr = sc->qeuba.ifu_r[sc->rindex].ifrw_info & mask; rp->qe_buf_len = -((MAXPACKETSIZE)/2); rp->qe_addr_lo = (short)bufaddr; rp->qe_addr_hi = (short)((int)bufaddr >> 16); rp->qe_flag = rp->qe_status1 = QE_NOTYET; rp->qe_valid = 1; if (sc->rindex != last) { sc->rindex = ++sc->rindex % nNRCV; goto drop; } }}/* * Process an ioctl request. */qeioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ struct qe_softc *sc = qe_softc[ifp->if_unit]; struct uba_device *ui = qeinfo[ifp->if_unit]; struct qedevice *addr = (struct qedevice *)ui->ui_addr; struct ifreq *ifr = (struct ifreq *)data; struct ifdevea *ifd = (struct ifdevea *)data; struct ctrreq *ctr = (struct ctrreq *)data; struct protosw *pr; struct ifaddr *ifa = (struct ifaddr *)data; int i,j = -1,s = splimp(), error = 0; switch (cmd) { case SIOCENABLBACK: printf("qe%d: internal loopback enable requested\n", ifp->if_unit); ifp->if_flags |= IFF_LOOPBACK;#ifdef notdef if((ifp->if_flags |= IFF_LOOPBACK) & IFF_RUNNING) if_rtinit(ifp, -1);#endif qerestart( sc ); break; case SIOCDISABLBACK: printf("qe%d: internal loopback disable requested\n", ifp->if_unit); ifp->if_flags &= ~IFF_LOOPBACK;#ifdef notdef if((ifp->if_flags &= ~IFF_LOOPBACK) & IFF_RUNNING) if_rtinit(ifp, -1);#endif qerestart( sc ); qeinit( ifp->if_unit ); break; case SIOCRPHYSADDR: bcopy(sc->is_addr, ifd->current_pa, 6); for( i = 0; i < 6; i++ ) ifd->default_pa[i] = (u_char)addr->qe_sta_addr[i]; break; case SIOCSPHYSADDR: bcopy(ifr->ifr_addr.sa_data,sc->is_addr,MULTISIZE);#if NPACKETFILTER > 0 pfilt_newaddress(sc->qe_ed.ess_enetunit, sc->is_addr);#endif NPACKETFILTER > 0 for ( i = 0; i < 6; i++ ) sc->setup_pkt[i][1] = sc->is_addr[i]; if (ifp->if_flags & IFF_RUNNING) { qesetup( sc ); } qeinit(ifp->if_unit); break; case SIOCDELMULTI: case SIOCADDMULTI: if (cmd == SIOCDELMULTI) { for (i = 0; i < NMULTI; i++) if (bcmp(&sc->multi[i],ifr->ifr_addr.sa_data,MULTISIZE) == 0) { if (--sc->muse[i] == 0) bcopy(qunused_multi,&sc->multi[i],MULTISIZE); } } else { for (i = 0; i < NMULTI; i++) { if (bcmp(&sc->multi[i],ifr->ifr_addr.sa_data,MULTISIZE) == 0) { sc->muse[i]++; goto done; } if (bcmp(&sc->multi[i],qunused_multi,MULTISIZE) == 0) j = i; } if (j == -1) { printf("qe%d: SIOCADDMULTI failed, multicast list full: %d\n",ui->ui_unit,NMULTI); error = ENOBUFS; goto done; } bcopy(ifr->ifr_addr.sa_data, &sc->multi[j], MULTISIZE); sc->muse[j]++; } for ( i = 0; i < 6; i++ ) sc->setup_pkt[i][1] = sc->is_addr[i]; if (ifp->if_flags & IFF_RUNNING) { qesetup( sc ); } break; case SIOCRDCTRS: case SIOCRDZCTRS: ctr->ctr_ether = sc->ctrblk; ctr->ctr_type = CTR_ETHER; ctr->ctr_ether.est_seconds = (time.tv_sec - sc->ztime) > 0xfffe ? 0xffff : (time.tv_sec - sc->ztime); if (cmd == SIOCRDZCTRS) { sc->ztime = time.tv_sec; bzero(&sc->ctrblk, sizeof(struct estat)); qe_runt = 0; } break; case SIOCSIFADDR: ifp->if_flags |= IFF_UP; qeinit(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 default: if (pr=iffamily_to_proto(ifa->ifa_addr.sa_family)) { error = (*pr->pr_ifioctl)(ifp, cmd, data); } break; } break;#ifdef IFF_PROMISC /* IFF_ALLMULTI and NPACKETFILTER, as well */ case SIOCSIFFLAGS: /* * Run a setup packet in case things have changed; * someone may be trying to turn on (or off) promiscuous * mode, for example. */ if (ifp->if_flags & IFF_RUNNING) qesetup(sc); break;#endif IFF_PROMISC default: error = EINVAL; }done: splx(s); return (error);} /* * Initialize a ring descriptor with mbuf allocation side effects */qeinitdesc( rp, buf, len ) register struct qe_ring *rp; char *buf; /* mapped address */ short len;{ /* * clear the entire descriptor */ bzero( rp, sizeof(struct qe_ring)); if( len ) { rp->qe_buf_len = (short)(-(len/2)); rp->qe_addr_lo = (short)buf; rp->qe_addr_hi = (short)((int)buf >> 16); }}/* * Build a setup packet - the physical address will already be present * in first column. */qesetup( sc )struct qe_softc *sc;{ int i, j, offset = 0, next = 3; /* * Copy the target address to the rest of the entries in this row. */ for ( j = 0; j < 6 ; j++ ) for ( i = 2 ; i < 8 ; i++ ) sc->setup_pkt[j][i] = sc->setup_pkt[j][1]; /* * Duplicate the first half. */ bcopy(sc->setup_pkt, sc->setup_pkt[8], 64); /* * Fill in the broadcast address. */ for ( i = 0; i < 6 ; i++ ) sc->setup_pkt[i][2] = 0xff; /* * If the device structure is available fill in the multicast address * in the rest of the setup packet. */ for ( i = 0; i < NMULTI; i++ ) { if (bcmp(&sc->multi[i],qunused_multi,MULTISIZE) != 0) { for ( j = 0; j < 6; j++ ) sc->setup_pkt[offset+j][next] = sc->multi[i].qm_char[j]; if (++next == 8) { next = 1; offset = 8; } } } sc->setupqueued++;}/* * Routines supporting Q-BUS 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 Q-BUS 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. */qe_ubainit(ifu, uban, hlen, nmr, mptr,unit) register struct qeuba *ifu; int uban, hlen, nmr,unit; char *mptr;{ register caddr_t cp, dp; register struct ifrw *ifrw; register struct ifxmt *ifxp; int i, ncl, flag, X_info, R_info, T_info; 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 = mptr; 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[nNRCV]; ifrw++) { ifrw->ifrw_addr = dp; ifrw->ifrw_info = 0; dp += MAXPACKETSIZE + CLBYTES; } for (ifxp = ifu->ifu_w; ifxp < &ifu->ifu_w[nNXMT]; ifxp++) { ifxp->x_ifrw.ifrw_addr = dp; dp += MAXPACKETSIZE; } } /* allocate for receive ring */ for (ifrw = ifu->ifu_r, flag=0; ifrw < &ifu->ifu_r[nNRCV]; ifrw++, flag++) { if((qe_ubaalloc(ifu, ifrw, nmr*2, -1, unit)) == 0) goto release; } /* and now transmit ring */ for (ifxp = ifu->ifu_w, flag=0; ifxp < &ifu->ifu_w[nNXMT]; ifxp++, flag++) { ifrw = &ifxp->x_ifrw; T_info=qe_ubaalloc(ifu, ifrw, (nmr * nNXMT) + nNXMT, flag,unit); if( flag == 0) X_info = T_info; if (T_info == 0) { if(flag > 0) qbarelse(ifu->ifu_uban, &X_info); goto release; } for (i = 0; i < nmr; i++) ifxp->x_map[i] = ifrw->ifrw_mr[i]; ifxp->x_xswapd = 0; } return (1);release: for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[nNRCV]; ifrw) { if(ifrw->ifrw_info) qbarelse(ifu->ifu_uban, &ifrw->ifrw_info); } m_pgfree(cp, nNTOT * ncl); ifu->ifu_r[0].ifrw_addr = 0; return(0);}/* * This routine sets up the buffers and maps to the Q-bus. The * mapping is the same as the UNIBUS, ie 496 map registers. The flag * input must be zero on the first call, this maps the memory. Successive * calls (flags is non-zero) breaks the mapped area up into buffers * and sets up ifrw structures. * Setup either a 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. */qe_ubaalloc(ifu, ifrw, nmr, do_alloc,unit) struct qeuba *ifu; register struct ifrw *ifrw; int nmr; int do_alloc, unit;{ static int info=0; static int ubai; static int numubai; int rinfo; register int nbpg; if(do_alloc == 0) { info = qballoc(ifu->ifu_uban, ifrw->ifrw_addr, nmr*NBPG , ifu->ifu_flags); if (info == 0){ return (0); } ubai=QBAI_MR(info); numubai=QBAI_NMR(info); numubai *= 8; } else if(do_alloc == -1) { info = qballoc(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 = 0; ifrw->ifrw_proto = UBAMR_MRV ; ifrw->ifrw_mr = &ifu->ifu_uba->uba_map[QBAI_MR(info) + 1]; return(1); } /* micro vax 1 is contigus phy. mem */ if(uba_hd[ifu->ifu_uban].uba_type & UBAUVI) { ifrw->ifrw_info = info; ifrw->ifrw_bdp = 0; ifrw->ifrw_proto = UBAMR_MRV ; ifrw->ifrw_mr = &ifu->ifu_uba->uba_map[UBAI_MR(info) + 1]; rinfo = info; info = info + (((int)((MAXPACKETSIZE+(NBPG - 1))/NBPG)+1) * NBPG); return(rinfo); } info = (info & ~(0xfffffe00)); /* * using the same QBUS mapping register for transmit buffer on both VAX * and MIPS architecture */#ifdef vax nbpg=NBPG;#else nbpg=512;#endif /* * The number of mapping registers ( info<30:22> ) will not affect the * mapping at all. */ info = info | (ubai << 9) | (((int)((MAXPACKETSIZE + (nbpg - 1))/nbpg)+1) << 22); ifrw->ifrw_info = info; ifrw->ifrw_bdp = 0; ifrw->ifrw_proto = UBAMR_MRV ; ifrw->ifrw_mr = &ifu->ifu_uba->uba_map[QBAI_MR(info) + 1]; if(numubai >= (int)((MAXPACKETSIZE + (nbpg - 1))/nbpg)) { numubai = numubai - ((int)((MAXPACKETSIZE + (nbpg - 1))/nbpg)); ubai = ubai + ((int)((MAXPACKETSIZE + (nbpg - 1))/nbpg)); } else { return (0); } return (info);}/* * 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. */#define pgaligned(x) (((int)(x)&(NBPG-1)) == 0)struct mbuf *qeget(ifu, ifrw, totlen, off0) register struct qeuba *ifu; register struct ifrw *ifrw; int totlen, off0;{ struct mbuf *top, **mp, *m, *p; int off = off0, len, tlen=0; register caddr_t cp = ifrw->ifrw_addr + ifu->ifu_hlen; top = 0; mp = ⊤#ifdef mips/* use bcopy instead of switch the page */ MGET(m, M_DONTWAIT, MT_DATA); if (m == 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -