📄 if_ln.c
字号:
} /* set STOP to clear INIT and IDON (and everything else) */ sc->ln_rdp = LN_STOP; return( sizeof(struct ln_initb));} /* * Interface exists: make available by filling in network interface * record. System will initialize the interface when it is ready * to accept packets. */lnattach(ui) struct uba_device *ui;{ register struct ln_softc *sc = ln_softc[ui->ui_unit]; register struct ifnet *ifp = &sc->is_if; register int i; register struct sockaddr_in *sin; /* Initialize the lock. */ lockinit(&sc->lk_ln_softc, &lock_device15_d); ifp->if_unit = ui->ui_unit; ifp->if_name = "ln"; ifp->lk_softc = &sc->lk_ln_softc; ifp->if_mtu = ETHERMTU; ifp->if_type = IFT_ETHER; ifp->if_flags |= IFF_BROADCAST | IFF_DYNPROTO | IFF_NOTRAILERS; ((struct arpcom *)ifp)->ac_ipaddr.s_addr = 0; /* * Read the address from the prom and save it. */ for ( i=0 ; i<6 ; i++ ) { sc->is_addr[i] = (u_char)((sc->ln_narom[i] >> sc->lnsw->ln_na_align) & 0xff); } sin = (struct sockaddr_in *)&ifp->if_addr; sin->sin_family = AF_INET; ifp->if_init = lninit; ifp->if_output = net_output; ifp->if_start = lnstart; ifp->if_ioctl = lnioctl; ifp->if_timer = 0; ifp->if_watchdog = lnwatch; ifp->if_reset = 0; ifp->d_affinity = ALLCPU; /* SMP */ bcopy("DEC LANCE Ethernet Interface", ifp->if_version, 28); ifp->if_version[28] = '\0'; printf("ln%d: %s, hardware address: %s \n", ui->ui_unit, ifp->if_version,ether_sprintf(sc->is_addr)); #if NPACKETFILTER > 0 attachpfilter(&(sc->is_ed));#endif NPACKETFILTER > 0 if_attach(ifp);}/* * Initialization of interface and allocation of mbufs for receive ring */lninit(unit) int unit;{ register struct ln_softc *sc = ln_softc[unit]; register struct ln_initb *initb = &sc->ln_initb; register struct lnsw *lnsw = sc->lnsw; register struct ifnet *ifp = &sc->is_if; int i,k; /* address not known */ if (ifp->if_addrlist == (struct ifaddr *)0) return; if (ifp->if_flags & IFF_RUNNING) return; /* * We only nail down our buffer addresses on the very * first call, then don't relinquish them again. */ k = splimp(); smp_lock(&sc->lk_ln_softc, LK_RETRY); sc->callno++; /* * Init the buffer descriptors and * indexes for each of the lists. */ for ( i = 0 ; i < nLNNRCV ; i++ ) { lnsw->lninitdesc (sc, sc->rring[i], &sc->rlbuf[i], (sc->callno == 1) ? LNALLOC : LNNOALLOC, i); /* give away rring */ lnsw->ln_setflag(sc->rring[i], LN_OWN); } for ( i = 0 ; i < nLNNXMT ; i++ ) { lninitdesc (sc, sc->tring[i], &sc->tlbuf[i], (sc->callno == 1) ? LNALLOC : LNNOALLOC); } sc->nxmit = sc->otindex = sc->tindex = sc->rindex = 0; /* * Take the interface out of reset, program the vector, * enable interrupts, and tell the world we are up. */ /* s=splimp(); */ /* SMP */ sc->ln_rap = LN_CSR0; if ( (ifp->if_flags & IFF_LOOPBACK) && (initb->ln_mode & LN_LOOP) == 0) { /* if not in loopback mode, do loopback */ initb->ln_mode &= ~LN_INTL; initb->ln_mode |= LN_LOOP; smp_unlock(&sc->lk_ln_softc); lnrestart(ifp); lninit(ifp->if_unit); splx(k); return; } /* start the Lance; enable interrupts, etc */ sc->ln_rdp = (LN_START | LN_INEA); ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; lnstart( unit ); sc->ztime = time.tv_sec; smp_unlock(&sc->lk_ln_softc); splx(k);} /* * Ethernet interface interrupt processor */lnintr(unit) int unit;{ register struct ln_softc *sc = ln_softc[unit]; register struct ifnet *ifp; register int s, oldcsr; ifp = &sc->is_if; s = splimp(); /* * If a set-1-to-reset bit is 1, then writing a 1 * back into the csr register will clear that bit. * This is OK; the intent is to clear the csr of all * errors/interrupts and then process the saved bits * in the old csr. We grab the "ln_flag" byte out of * the ring entry to check the ownership bit FIRST, * then grab the "ln_flag2" short word later to eliminate * a timing window in which the LANCE may update the * "ln_flag" before updating "ln_flag2". */ oldcsr = sc->ln_rdp; /* save the old csr */ oldcsr &= ~LN_INEA; /* clear interrupt enable */#ifdef mips if(cpu == DS_5000) { /* work around for R3000 bug */ rdpptr= (volatile unsigned long *)&sc->ln_rdp; *rdpptr = oldcsr; } else #endif sc->ln_rdp = oldcsr; sc->ln_rdp = LN_INEA; /* set interrupt enable */ /* * check error bits */ if ( oldcsr & LN_ERR ) { if (oldcsr & LN_MISS) { /* * LN_MISS is signaled when the LANCE receiver * loses a packet because it doesn't own a * receive descriptor. Rev. D LANCE chips, which * are no longer used, require a chip reset as * described below. */ lnmisscnt++; if (lndebug) mprintf("ln%d: missed packet (MISS)\n",unit); if(sc->ctrblk.est_sysbuf != 0xffff) sc->ctrblk.est_sysbuf++; /* This is a toss-up. We don't increment * data overrun here because it's most likely * the host's fault that packets were missed. * No way to tell from here whether the LANCE * is at fault. * if (sc->ctrblk.est_overrun != 0xffff) sc->ctrblk.est_overrun++; */ } if (oldcsr & LN_CERR) { if (sc->ctrblk.est_collis != 0xffff) sc->ctrblk.est_collis++; } if (oldcsr & LN_BABL) { lnbablcnt++; if (lndebug) mprintf("ln%d: transmitter timeout (BABL)\n",unit); } if (oldcsr & LN_MERR) { lnmerrcnt++; /* warn the user (printf on the terminal) */ mprintf("ln%d: memory error (MERR) \n", unit); if (((oldcsr & LN_RXON) == 0) || ((oldcsr & LN_TXON) == 0)) { lnrestart(ifp); lninit(ifp->if_unit); splx(s); return; } } } if ( oldcsr & LN_RINT ) lnrint( unit ); /* check for lance dma memory read error, happens on xmit only * disables DMA, times out lance, interrupts processor */ if (sc->lnsw->ln_dma) { caddr_t pa; struct tc_memerr_status status; if ( *(u_int *)(sc->siraddr) & BIT16SET) { pa = (caddr_t)((*(u_int *)(sc->ldpaddr)) >> 3); printf("ln%d: dma memory read error \n", unit); status.pa = pa; status.va = 0; status.log = TC_LOG_MEMERR; status.blocksize = 4; tc_isolate_memerr(&status); *(u_int *)(sc->siraddr) &= ~BIT16SET; *(u_int *)(sc->ssraddr) |= BIT16SET; lnrestart(ifp); lninit(ifp->if_unit); lndmareaderr++; splx(s); return; } } if ( oldcsr & LN_TINT ) lntint( unit ); if (oldcsr == (LN_INTR|LN_RXON|LN_TXON)) mprintf("ln%d: stray interrupt\n",unit); splx(s);} /* * Ethernet interface transmit interrupt. */lntint(unit) int unit;{ register struct ln_softc *sc = ln_softc[unit]; register int index; register int i; register struct ln_ring *rp = &sc->ln_ring; register struct lnsw *lnsw = sc->lnsw; struct mbuf *mp, *mp0; struct ifnet *ifp = &sc->is_if; struct ether_header *eh; short len; /* * While we haven't caught up to current transmit index, * AND the buffer is ours, AND there are still transmits * which haven't been pulled off the ring yet, proceed * around the ring in search of the last packet. We grab * the "ln_flag" byte out of the ring entry to check the * ownership bit FIRST, then grab the "ln_flag2" short * word later to eliminate a timing window in which the * LANCE may update the "ln_flag" before updating "ln_flag2". */ smp_lock(&sc->lk_ln_softc, LK_RETRY); lnsw->ln_cpyin(sc, sc->tring[sc->otindex], &rp->ln_flag, sizeof(u_char), (u_long)&rp->ln_flag - (u_long)rp); while ( (sc->otindex != sc->tindex) && !(rp->ln_flag & LN_OWN) && sc->nxmit > 0 ) { index = sc->otindex; /* * Found last buffer in the packet * (hence a valid string of descriptors) * so free things up. */ mp = sc->tmbuf[index]; sc->tmbuf[index] = (struct mbuf *)NULL; /* increment old index pointer, if it catches up * with current index pointer, we will break out * of the loop. Otherwise, go around again * looking for next end-of-packet cycle. */ if (!(--sc->nxmit)) { ifp->if_timer = 0; ifp->if_flags &= ~IFF_OACTIVE; } sc->is_if.if_opackets++; lnsw->ln_cpyin(sc, sc->tring[sc->otindex], &rp->ln_flag2, sizeof(u_short), (u_long)&rp->ln_flag2 - (u_long)rp); /* * DECnet statistics */ /* exactly one collision? */ if ((rp->ln_flag & LN_ONE) && !(rp->ln_flag2 & LN_LCOL)) { sc->is_if.if_collisions++; if (sc->ctrblk.est_single != (unsigned)0xffffffff) sc->ctrblk.est_single++; /* more than one collision? */ } else if (rp->ln_flag & LN_MORE) { sc->is_if.if_collisions += 2; if (sc->ctrblk.est_multiple != (unsigned)0xffffffff) sc->ctrblk.est_multiple++; } /* * Check for transmission errors. * This assumes that transmission errors * are always reported in the last packet. */ if (rp->ln_flag & LN_RT_ERR) { sc->is_if.if_oerrors++; if (sc->ctrblk.est_sendfail != 0xffff) { sc->ctrblk.est_sendfail++; if (rp->ln_flag2 & LN_RTRY) { /* excessive collisions */ if (lndebug) mprintf("ln%d: excessive collisions (RTRY)\n",unit); sc->ctrblk.est_sendfail_bm |= 1; } if (rp->ln_flag2 & LN_LCOL) { if (lndebug) mprintf("ln%d: late transmit collision (LCOL)\n",unit); ; /* not implemented */ } if (rp->ln_flag2 & LN_LCAR) { if (lndebug) mprintf("ln%d: lost carrier during transmit (LCAR)\n",unit); sc->ctrblk.est_sendfail_bm |= 2; } if (rp->ln_flag2 & LN_UFLO) { if (lndebug) mprintf("ln%d: packet truncated (UFLO)\n,unit"); } if (rp->ln_flag2 & LN_TBUFF) { if (lndebug) mprintf("ln%d: transmit buffer error (BUFF)\n,unit"); } } /* * Restart chip if transmitter got turned off * due to transmit errors: UFLO, TBUFF or RTRY. */ if (rp->ln_flag2 & (LN_UFLO | LN_TBUFF | LN_RTRY)) { smp_unlock(&sc->lk_ln_softc); /* * Need to free mp here, since we've * already destroyed its copy in the * "tmbuf" list. */ m_freem(mp); lnrestart(ifp); lninit(ifp->if_unit); return; } m_freem(mp); } else { /* * If this was a broadcast packet or if the * interface is in COPYALL mode, loop it * back, otherwise just free the packet. */ if (mp) { eh = mtod( mp, struct ether_header *); for (i=0; (i < 6) && (eh->ether_dhost[i] == 0xff); i++) ; /*nop*/ if ( (i == 6) || (ifp->if_flags & IFF_PFCOPYALL)) { for ( mp0 = mp, len=0 ; mp0 ; mp0 = mp0->m_next ) { len += mp0->m_len; } /* Bump up DECnet statistics */ if(eh->ether_dhost[0] & 1) { sc->ctrblk.est_mbytesent += len; if (sc->ctrblk.est_mbloksent != (unsigned) 0xffffffff) sc->ctrblk.est_mbloksent++; } lnread( sc, 0, len, mp, 0 ); } else { m_freem( mp ); } } } /* * Init the buffer descriptor */ lninitdesc(sc, sc->tring[index], &sc->tlbuf[index], LNNOALLOC); sc->otindex = ++index % nLNNXMT; lnsw->ln_cpyin(sc, sc->tring[sc->otindex],&rp->ln_flag, sizeof(u_char), (u_long)&rp->ln_flag - (u_long)rp); /* for the next time thru while */ } /* * Dequeue next transmit request, if any. */ if (!(ifp->if_flags & IFF_OACTIVE)) lnstart( unit ); smp_unlock(&sc->lk_ln_softc);} /* * 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. */lnrint(unit) int unit;{ register struct ln_softc *sc = ln_softc[unit]; register struct ln_ring *rp = &sc->ln_ring; register struct lnsw *lnsw = sc->lnsw; register int index, len; register struct ifnet *ifp = &sc->is_if; int first; u_char flag; /* saved status flag */ int ring_cnt;#ifdef lint unit = unit;#endif /* * Traverse the receive ring looking for packets to pass back. * The search is complete when we find a descriptor that is in * use (owned by Lance). */ smp_lock(&sc->lk_ln_softc, LK_RETRY); lnsw->ln_cpyin(sc, sc->rring[sc->rindex],&rp->ln_flag, sizeof(u_char),(u_long)&rp->ln_flag - (u_long)rp); for ( ; !(rp->ln_flag & LN_OWN); sc->rindex = ++index % nLNNRCV, lnsw->ln_cpyin(sc, sc->rring[sc->rindex],&rp->ln_flag, sizeof(u_char), (u_long)&rp->ln_flag - (u_long)rp)) { first = index = sc->rindex; /* * If not the start of a packet, error */ if ( !(rp->ln_flag & LN_STP)) { if (lndebug) { mprintf("ln%d: recv: start of packet expected #%d, flag=%02x\n", unit, index,(rp->ln_flag&0xff)); } lnsw->ln_setflag(sc->rring[first], LN_OWN); smp_unlock(&sc->lk_ln_softc); lnrestart(ifp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -