📄 if_qe.c
字号:
addr->qe_rcvlist_lo = (short)sc->rringaddr; addr->qe_rcvlist_hi = (short)((int)sc->rringaddr >> 16); ifp->if_flags |= IFF_UP | IFF_RUNNING; sc->qe_flags |= QEF_RUNNING; qesetup( sc ); (void) qestart( ifp ); sc->qe_if.if_timer = QESLOWTIMEOUT; /* Start watchdog */ splx( s );}/* * Start output on interface. * */qestart(ifp) struct ifnet *ifp;{ int unit = ifp->if_unit; struct uba_device *ui = qeinfo[unit]; register struct qe_softc *sc = &qe_softc[unit]; register struct qedevice *addr; register struct qe_ring *rp; register index; struct mbuf *m; int buf_addr, len, s; s = splimp(); addr = (struct qedevice *)ui->ui_addr; /* * The deqna doesn't look at anything but the valid bit * to determine if it should transmit this packet. If you have * a ring and fill it the device will loop indefinately on the * packet and continue to flood the net with packets until you * break the ring. For this reason we never queue more than n-1 * packets in the transmit ring. * * The microcoders should have obeyed their own defination of the * flag and status words, but instead we have to compensate. */ for( index = sc->tindex; sc->tring[index].qe_valid == 0 && sc->nxmit < (NXMT-1) ; sc->tindex = index = ++index % NXMT){ rp = &sc->tring[index]; if( sc->setupqueued ) { buf_addr = sc->setupaddr; len = 128; rp->qe_setup = 1; sc->setupqueued = 0; } else { IF_DEQUEUE(&sc->qe_if.if_snd, m); if( m == 0 ){ splx(s); return (0); } buf_addr = sc->qe_ifw[index].ifw_info; len = if_ubaput(&sc->qe_uba, &sc->qe_ifw[index], m); } if( len < MINDATA ) len = MINDATA; /* * Does buffer end on odd byte ? */ if( len & 1 ) { len++; rp->qe_odd_end = 1; } rp->qe_buf_len = -(len/2); buf_addr = UBAI_ADDR(buf_addr); rp->qe_flag = rp->qe_status1 = QE_NOTYET; rp->qe_addr_lo = (short)buf_addr; rp->qe_addr_hi = (short)(buf_addr >> 16); rp->qe_eomsg = 1; rp->qe_flag = rp->qe_status1 = QE_NOTYET; rp->qe_valid = 1; if (sc->nxmit++ == 0) { sc->qe_flags |= QEF_FASTTIMEO; sc->qe_if.if_timer = QETIMEOUT; } /* * See if the xmit list is invalid. */ if( addr->qe_csr & QE_XL_INVALID ) { buf_addr = (int)(sc->tringaddr+index); addr->qe_xmtlist_lo = (short)buf_addr; addr->qe_xmtlist_hi = (short)(buf_addr >> 16); } } splx( s ); return (0);}/* * Ethernet interface interrupt processor */qeintr(unit) int unit;{ register struct qe_softc *sc = &qe_softc[unit]; struct qedevice *addr = (struct qedevice *)qeinfo[unit]->ui_addr; int buf_addr, csr;#ifdef notdef splx(sc->ipl);#else (void) splimp();#endif if (!(sc->qe_flags & QEF_FASTTIMEO)) sc->qe_if.if_timer = QESLOWTIMEOUT; /* Restart timer clock */ csr = addr->qe_csr; addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT | QE_RCV_INT | QE_ILOOP; if( csr & QE_RCV_INT ) qerint( unit ); if( csr & QE_XMIT_INT ) qetint( unit ); if( csr & QE_NEX_MEM_INT ) printf("qe%d: Nonexistent memory interrupt\n", unit); if( addr->qe_csr & QE_RL_INVALID && sc->rring[sc->rindex].qe_status1 == QE_NOTYET ) { buf_addr = (int)&sc->rringaddr[sc->rindex]; addr->qe_rcvlist_lo = (short)buf_addr; addr->qe_rcvlist_hi = (short)(buf_addr >> 16); }}/* * Ethernet interface transmit interrupt. */qetint(unit) int unit;{ register struct qe_softc *sc = &qe_softc[unit]; register struct qe_ring *rp; register struct ifxmt *ifxp; int status1, setupflag; short len; while( sc->otindex != sc->tindex && sc->tring[sc->otindex].qe_status1 != QE_NOTYET && sc->nxmit > 0 ) { /* * Save the status words from the descriptor so that it can * be released. */ rp = &sc->tring[sc->otindex]; status1 = rp->qe_status1; setupflag = rp->qe_setup; len = (-rp->qe_buf_len) * 2; if( rp->qe_odd_end ) len++; /* * Init the buffer descriptor */ bzero((caddr_t)rp, sizeof(struct qe_ring)); if( --sc->nxmit == 0 ) { sc->qe_flags &= ~QEF_FASTTIMEO; sc->qe_if.if_timer = QESLOWTIMEOUT; } if( !setupflag ) { /* * Do some statistics. */ sc->qe_if.if_opackets++; sc->qe_if.if_collisions += ( status1 & QE_CCNT ) >> 4; if (status1 & QE_ERROR) sc->qe_if.if_oerrors++; ifxp = &sc->qe_ifw[sc->otindex]; if (ifxp->ifw_xtofree) { m_freem(ifxp->ifw_xtofree); ifxp->ifw_xtofree = 0; } } sc->otindex = ++sc->otindex % NXMT; } (void) qestart( &sc->qe_if );}/* * Ethernet interface receiver interrupt. * 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. */qerint(unit) int unit;{ register struct qe_softc *sc = &qe_softc[unit]; register struct qe_ring *rp; register int nrcv = 0; int len, status1, status2; int bufaddr; /* * Traverse the receive ring looking for packets to pass back. * The search is complete when we find a descriptor not in use. * * As in the transmit case the deqna doesn't honor it's own protocols * so there exists the possibility that the device can beat us around * the ring. The proper way to guard against this is to insure that * there is always at least one invalid descriptor. We chose instead * to make the ring large enough to minimize the problem. With a ring * size of 4 we haven't been able to see the problem. To be safe we * doubled that to 8. * */ while (sc->rring[sc->rindex].qe_status1 == QE_NOTYET && nrcv < NRCV) { /* * We got an interrupt but did not find an input packet * where we expected one to be, probably because the ring * was overrun. * We search forward to find a valid packet and start * processing from there. If no valid packet is found it * means we processed all the packets during a previous * interrupt and that the QE_RCV_INT bit was set while * we were processing one of these earlier packets. In * this case we can safely ignore the interrupt (by dropping * through the code below). */ sc->rindex = (sc->rindex + 1) % NRCV; nrcv++; } if (nrcv && nrcv < NRCV) log(LOG_ERR, "qe%d: ring overrun, resync'd by skipping %d\n", unit, nrcv); for( ; sc->rring[sc->rindex].qe_status1 != QE_NOTYET ; sc->rindex = ++sc->rindex % NRCV ){ rp = &sc->rring[sc->rindex]; status1 = rp->qe_status1; status2 = rp->qe_status2; bzero((caddr_t)rp, sizeof(struct qe_ring)); if( (status1 & QE_MASK) == QE_MASK ) panic("qe: chained packet"); len = ((status1 & QE_RBL_HI) | (status2 & QE_RBL_LO)) + 60; sc->qe_if.if_ipackets++; if (status1 & QE_ERROR) { if ((status1 & QE_RUNT) == 0) sc->qe_if.if_ierrors++; } else { /* * We don't process setup packets. */ if( !(status1 & QE_ESETUP) ) qeread(sc, &sc->qe_ifr[sc->rindex], len - sizeof(struct ether_header)); } /* * Return the buffer to the ring */ bufaddr = (int)UBAI_ADDR(sc->qe_ifr[sc->rindex].ifrw_info); 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; }}/* * 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 ifaddr *ifa = (struct ifaddr *)data; int s = splimp(), error = 0; switch (cmd) { 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#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 *)(sc->qe_addr); else qe_setaddr(ina->x_host.c_host, ifp->if_unit); break; }#endif } break; case SIOCSIFFLAGS: if ((ifp->if_flags & IFF_UP) == 0 && sc->qe_flags & QEF_RUNNING) { ((struct qedevice *) (qeinfo[ifp->if_unit]->ui_addr))->qe_csr = QE_RESET; sc->qe_flags &= ~QEF_RUNNING; } else if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_RUNNING && (sc->qe_flags & QEF_RUNNING) == 0) qerestart(sc); break; default: error = EINVAL; } splx(s); return (error);}/* * set ethernet address for unit */qe_setaddr(physaddr, unit) u_char *physaddr; int unit;{ register struct qe_softc *sc = &qe_softc[unit]; register int i; for (i = 0; i < 6; i++) sc->setup_pkt[i][1] = sc->qe_addr[i] = physaddr[i]; sc->qe_flags |= QEF_SETADDR; if (sc->qe_if.if_flags & IFF_RUNNING) qesetup(sc); qeinit(unit);}/* * Initialize a ring descriptor with mbuf allocation side effects */qeinitdesc(rp, addr, len) register struct qe_ring *rp; caddr_t addr; /* mapped address */ int len;{ /* * clear the entire descriptor */ bzero((caddr_t)rp, sizeof(struct qe_ring)); if( len ) { rp->qe_buf_len = -(len/2); rp->qe_addr_lo = (short)addr; rp->qe_addr_hi = (short)((int)addr >> 16); }}/* * Build a setup packet - the physical address will already be present * in first column. */qesetup( sc )struct qe_softc *sc;{ register i, j; /* * 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((caddr_t)sc->setup_pkt[0], (caddr_t)sc->setup_pkt[8], 64); /* * Fill in the broadcast (and ISO multicast) address(es). */ for ( i = 0; i < 6 ; i++ ) { sc->setup_pkt[i][2] = 0xff;#ifdef ISO sc->setup_pkt[i][3] = all_es_snpa[i]; sc->setup_pkt[i][4] = all_is_snpa[i]; sc->setup_pkt[i][5] = all_l1is_snpa[i]; sc->setup_pkt[i][6] = all_l2is_snpa[i];#endif } sc->setupqueued++;}/* * Pass a packet to the higher levels. * We deal with the trailer protocol here. */qeread(sc, ifrw, len) register struct qe_softc *sc; struct ifrw *ifrw; int len;{ struct ether_header *eh, ehm; struct mbuf *m; int off, resid, s; struct ifqueue *inq; /* * Deal with trailer protocol: if type is INET trailer * 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 qedataaddr(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(*qedataaddr(eh,off, u_short *)); resid = ntohs(*(qedataaddr(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; qeget 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. */ bcopy((caddr_t)eh, (caddr_t)&ehm, sizeof(ehm)); m = if_ubaget(&sc->qe_uba, ifrw, len, off, &sc->qe_if); if (m) ether_input(&sc->qe_if, &ehm, m);}/* * Watchdog timeout routine. There is a condition in the hardware that * causes the board to lock up under heavy load. This routine detects * the hang up and restarts the device. */qetimeout(unit) int unit;{ register struct qe_softc *sc; sc = &qe_softc[unit];#ifdef notdef log(LOG_ERR, "qe%d: transmit timeout, restarted %d\n", unit, sc->qe_restarts++);#endif qerestart(sc);}/* * Restart for board lockup problem. */qerestart(sc) register struct qe_softc *sc;{ register struct ifnet *ifp = &sc->qe_if; register struct qedevice *addr = sc->addr; register struct qe_ring *rp; register i; addr->qe_csr = QE_RESET; addr->qe_csr &= ~QE_RESET; qesetup( sc ); for (i = 0, rp = sc->tring; i < NXMT; rp++, i++) { rp->qe_flag = rp->qe_status1 = QE_NOTYET; rp->qe_valid = 0; } sc->nxmit = sc->otindex = sc->tindex = sc->rindex = 0; addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT | QE_RCV_INT | QE_ILOOP; addr->qe_rcvlist_lo = (short)sc->rringaddr; addr->qe_rcvlist_hi = (short)((int)sc->rringaddr >> 16); sc->qe_flags |= QEF_RUNNING; (void) qestart(ifp);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -