📄 if_sonic.c
字号:
sn->sn_if.if_flags &= ~IFF_RUNNING; log (LOG_DEBUG, "%s%d: reprogrammed by client, PMON ignoring\n", sn->sn_if.if_name, sn->sn_if.if_unit); return 0; } return 1;}#endifstatic intsnifstart (struct ifnet *ifp){ register struct sn_softc *sn = &sn_softc[ifp->if_unit]; int s;#ifdef PROM if (!sncheckclient (sn)) return ENETDOWN;#endif /* * start feeding any queued packets to chip */ s = splimp (); for (;;) { struct mbuf *m; IF_DEQUEUE (&ifp->if_snd, m); if (m == 0) /* nothing left to send */ break; if (!snput (sn, m)) { /* not enough space */ IF_PREPEND (&ifp->if_snd, m); ifp->if_flags |= IFF_OACTIVE; ifp->if_oerrors++; break; } } (void) splx (s); return 0;}/* * stuff packet into sonic (at splimp) */#if defined(XDS)static intsnput (struct sn_softc *sn, struct mbuf *m0){ volatile struct sn_reg *csr = sn->sn_csr; register volatile union frag *fr; register struct mtd *mtdnew; register volatile struct TXpkt *txp; register struct mbuf *m; int len, i; unsigned char *ptba; unsigned int pa; if (!csr) return 0; /* grab the replacement mtd */ if ((mtdnew = mtd_alloc()) == 0) return 0; /* this packet goes in mtdnext */ txp = mtdnext->mtd_txp; txp->config = 0; txp->status = 0;#ifdef MIPSEL /* Byte-swap the mbuf chain */ m0 = snswapm (m0);#endif /* copy the data into the static RAM buffer */ fr = &txp->frags[0]; ptba = mtdnext->mtd_tba; /* ASSERT (IS_K0SEG (ptba)); */ len = 0; for (m = m0; m; m = m->m_next) { bcopy (mtod (m, char *), ptba, m->m_len); ptba += m->m_len; len += m->m_len; } /* pad out last fragment for minimum size */ if (len < ETHERMIN + sizeof(struct ether_header)) len = ETHERMIN + sizeof(struct ether_header);#ifdef XDSSONICBUG xds_expand_buffer (mtdnext->mtf_tba, len);#else#if defined(R4000) /* flush data to static RAM */ clean_dcache(mtdnext->mtd_tba, len);#endif#endif pa = K0_TO_PHYS(mtdnext->mtd_tba); txp->frag_count = 1; txp->pkt_size = len; fr->frag_ptrlo = pa; fr->frag_ptrhi = pa >> 16; fr->frag_size = len; /* link onto the next mtd that will be used */ fr->tlink = LOWER(mtdnew->mtd_txp) | EOL; if (!mtdhead) { /* no current transmit list, so start with this one */ mtdhead = mtdnext; } else { /* have an existing transmit list, so append it to end of list * note mtdnext is already physically linked to mtdtail in * mtdtail->mtd_txp->frags[mtdtail->mtd_txp->frag_count].tlink */ mtdtail->mtd_txp->frags[mtdtail->mtd_txp->frag_count].tlink &= ~EOL; wbflush (); } /* kick transmitter */ csr->s_cr = CR_TXP; wbflush (); /* update s/w linkage */ mtdnext->mtd_mbuf = m0; /* to be freed on txint */ mtdnext->mtd_link = mtdnew; mtdtail = mtdnext; mtdnext = mtdnew; sn->sn_if.if_timer = 5; /* 5 second watchdog */ return 1;}#elsestatic intsnput (struct sn_softc *sn, struct mbuf *m0){ volatile struct sn_reg *csr = sn->sn_csr; register volatile union frag *fr; register struct mtd *mtdnew; register volatile struct TXpkt *txp; register struct mbuf *m; int firstattempt = 1; int len, nfr, i, tinyfrags, needcompress; if (!csr) return 0; /* grab the replacement mtd */ if ((mtdnew = mtd_alloc()) == 0) return 0; /* this packet goes in mtdnext */ txp = mtdnext->mtd_txp; txp->config = 0; txp->status = 0; retry: /* see whether it will fit in the TDA */ tinyfrags = needcompress = len = nfr = 0; fr = &txp->frags[0]; for (m = m0; m; m = m->m_next) { unsigned va = mtod (m, unsigned); int resid = m->m_len; len += resid; while (resid) { unsigned n = resid;#ifndef PROM if (IS_KSEG2 (va)) { /* this could cross a page boundary */ n = NBPC - (va & (NBPC - 1)); if (n > resid) n = resid; }#endif /* heuristic to prevent transmit underflow */ if (n < TINYFRAG) { if (++tinyfrags > MAXTINIES && tinyfrags > needcompress) needcompress = tinyfrags; /* remember maximum */ } else tinyfrags = 0; nfr++; va += n; resid -= n; } } if (needcompress != 0 || nfr > FRAGMAX) { if (firstattempt) { /* try to compress chain */ m0 = sn_fillup (m0, ETHERMTU / FRAGMAX + 1); firstattempt = 0; goto retry; } mtd_free (mtdnew); m_freem (m0); log (LOG_WARNING, "%s%d: frag compress failed (%d frags, %d tiny)\n", sn->sn_if.if_name, sn->sn_if.if_unit, nfr, needcompress); sn->sn_if.if_oerrors++; return 1; }#ifdef MIPSEL /* Byte-swap the mbuf chain */ m0 = snswapm (m0);#endif#ifdef R4000 /* hand mbuf data over to Sonic */ if (IS_K0SEG (m0)) for (m = m0; m; m = m->m_next) if (m->m_len) clean_dcache (mtod(m, caddr_t), m->m_len);#endif /* Now fill up the txd fragment list */ fr = &txp->frags[0]; for (m = m0; m; m = m->m_next) { unsigned va = mtod (m, unsigned); int resid = m->m_len; while (resid) { u_long pa; unsigned n = resid;#ifndef PROM pa = kvtophys (va); if (IS_KSEG2 (va)) { /* this could cross a page boundary */ n = NBPC - (pa & (NBPC - 1)); if (n > resid) n = resid; }#else pa = K1_TO_PHYS (va);#endif fr->frag_ptrlo = pa; fr->frag_ptrhi = pa >> 16; fr->frag_size = n; fr++; va += n; resid -= n; } } /* pad out last fragment for minimum size */ if (len < ETHERMIN + sizeof(struct ether_header)) { int pad = (ETHERMIN + sizeof(struct ether_header)) - len; (fr-1)->frag_size += pad; len = ETHERMIN + sizeof(struct ether_header); } txp->frag_count = nfr; txp->pkt_size = len; /* link onto the next mtd that will be used */ fr->tlink = LOWER(mtdnew->mtd_txp) | EOL; if (!mtdhead) { /* no current transmit list, so start with this one */ mtdhead = mtdnext; } else { /* have an existing transmit list, so append it to end of list * note mtdnext is already physically linked to mtdtail in * mtdtail->mtd_txp->frags[mtdtail->mtd_txp->frag_count].tlink */ mtdtail->mtd_txp->frags[mtdtail->mtd_txp->frag_count].tlink &= ~EOL; wbflush (); } /* kick transmitter */ csr->s_cr = CR_TXP; wbflush (); /* update s/w linkage */ mtdnext->mtd_mbuf = m0; /* to be freed on txint */ mtdnext->mtd_link = mtdnew; mtdtail = mtdnext; mtdnext = mtdnew; sn->sn_if.if_timer = 5; /* 5 second watchdog */ return 1;}#endifvoidsnintr (int unit){ struct sn_softc *sn = &sn_softc[unit]; volatile struct sn_reg *csr = sn->sn_csr; register u_int isr; if (unit >= NSONIC || !csr) return; #ifdef PROM /* Timer may be used by programmers, ignore TC interrupt */ while (isr = (csr->s_isr & ~ISR_TC)) {#else while (isr = csr->s_isr) {#endif#ifdef PROM if (!sncheckclient (sn)) return;#endif /* scrub the interrupts that we are going to service */ csr->s_isr = isr & ~ISR_RBE; wbflush (); if (isr & ISR_BR) { log (LOG_WARNING, "%s%d: bus error\n", sn->sn_if.if_name, sn->sn_if.if_unit); snrestart (sn); break; } if (isr & (ISR_LCD|ISR_PINT|ISR_TC)) log (LOG_WARNING, "%s%d: unexpected interrupt status 0x%x\n", sn->sn_if.if_name, sn->sn_if.if_unit, isr); if (isr & (ISR_TXDN|ISR_TXER)) sntxint (sn); if (isr & ISR_PKTRX) snrxint (sn); if (isr & ISR_ERRS) { if (snerrint (sn, isr)) break; } else { sn->sn_rbe = 0; } }}/* * Error interrupt routine */static intsnerrint (struct sn_softc *sn, u_int isr){ if (isr & ISR_RBE) { sn->sn_if.if_ierrors++; sn->sn_sum.ss_rbuff++; log (LOG_INFO, "%s%d: receive buffer exhausted, isr=0x%x\n", sn->sn_if.if_name, sn->sn_if.if_unit, isr); if (!sn->sn_rbe || (isr & ISR_PKTRX)) { /* probably managed to free some rx space, try again */ sn->sn_csr->s_isr = ISR_RBE; wbflush (); sn->sn_rbe = 1; } else if (sn->sn_rbe) { log (LOG_INFO, "%s%d: and no rx data to free\n", sn->sn_if.if_name, sn->sn_if.if_unit); snrestart (sn); return (1); } } if (isr & ISR_RDE) { sn->sn_if.if_ierrors++; sn->sn_sum.ss_rbuff++; log (LOG_INFO, "%s%d: rx descriptors exhausted, isr=0x%x\n", sn->sn_if.if_name, sn->sn_if.if_unit, isr); } else if (isr & ISR_RBAE) { sn->sn_if.if_ierrors++; sn->sn_sum.ss_rbuff++; log (LOG_INFO, "%s%d: rx buffer area exceeded, isr=0x%x\n", sn->sn_if.if_name, sn->sn_if.if_unit, isr); } else if (isr & ISR_RFO) { sn->sn_if.if_ierrors++; sn->sn_sum.ss_roflo++; log (LOG_INFO, "%s%d: rx fifo overflow, isr=0x%x\n", sn->sn_if.if_name, sn->sn_if.if_unit, isr); } if (isr & ISR_HBL) sn->sn_sum.ss_noheart++; if (isr & ISR_CRC) sn->sn_crct += 0x10000; if (isr & ISR_FAE) sn->sn_faet += 0x10000; if (isr & ISR_MP) sn->sn_mpt += 0x10000; return (0);}/* * Transmit interrupt routine */static voidsntxint (struct sn_softc *sn){ struct mtd *mtd; register volatile struct TXpkt *txp; register u_int status, ncol; while (mtd = mtdhead) { txp = mtd->mtd_txp; if ((status = txp->status) == 0) { /* this packet isn't sent yet */ break; } txp->status = 0;#ifdef DEBUG if (T_txp) { struct ether_header *eh=mtod(mtd->mtd_mbuf,struct ether_header *); printf ("xmit status=0x%x len=%d type=0x%x from %s", status, txp->pkt_size, ntohs(eh->ether_type), ether_sprintf(eh->ether_shost)); printf(" (to %s)\n", ether_sprintf (eh->ether_dhost)); }#endif if (status & TSR_PTX) { /* tx packet has flown, free the packet mbufs */ sntxdone (sn, mtd); /* update statistics for this packet */ sn->sn_sum.ss_tpacks++; sn->sn_if.if_opackets++; if (status & TSR_DEF) { sn->sn_sum.ss_tdef++; } if (status & TSR_OWC) { sn->sn_sum.ss_tlcol++; sn->sn_if.if_oerrors++; log (LOG_NOTICE, "%s%d: late collision (noisy network?)\n", sn->sn_if.if_name, sn->sn_if.if_unit); } if (status & (TSR_NCRS|TSR_CRSL)) { sn->sn_sum.ss_tlcar++; sn->sn_if.if_oerrors++; log (LOG_NOTICE, "%s%d: no carrier (check cables?)\n", sn->sn_if.if_name, sn->sn_if.if_unit); } if (ncol = (status & TSR_NC) >> TSR_NCSHFT) { sn->sn_if.if_collisions += ncol; if (ncol == 1) sn->sn_sum.ss_tone++; else sn->sn_sum.ss_tmore++; } } else { /* tx failed: CTDA still points at failing packet */ sn->sn_if.if_oerrors++; if (status & (TSR_EXD|TSR_EXC)) { sn->sn_sum.ss_cerr++; log (LOG_NOTICE, "%s%d: excessive %s (network jammed?)\n", sn->sn_if.if_name, sn->sn_if.if_unit, (status & TSR_EXD) ? "deferrals" : "collisions"); status &= ~TSR_BCM; /* ignore bcm error */ } if (status & TSR_FU) { sn->sn_sum.ss_tuflo++; log (LOG_INFO, "%s%d: tx fifo underflow\n", sn->sn_if.if_name, sn->sn_if.if_unit); if (sn->sn_if.if_flags & IFF_DEBUG) sntxdump (txp); } if (status & TSR_BCM) { int fr, frag_total; sn->sn_sum.ss_tbuff++; for (fr = 0, frag_total = 0; fr < txp->frag_count; fr++) frag_total += txp->frags[fr].frag_size; if ((sn->sn_if.if_flags & IFF_DEBUG) || frag_total != txp->pkt_size) { log (LOG_WARNING, "%s%d: tx byte count mismatch, psz=%d, %d in %d frags\n", sn->sn_if.if_name, sn->sn_if.if_unit, txp->pkt_size, frag_total, txp->frag_count); sntxdump (txp); } /* pointless attempt to fix error! */ txp->pkt_size = frag_total; } if (sn->sn_retries++ >= SNRETRIES) { /* give up on this packet */ log (LOG_INFO, "%s%d: tx retry count exceeded\n", sn->sn_if.if_name, sn->sn_if.if_unit); sntxdone (sn, mtd); /* manually advance to next packet: * strictly we only need to set CTDA here, but we are * paranoid and reset it for all errors, below. */ } if (mtdhead) { /* restart transmission */ register volatile struct sn_reg *csr = sn->sn_csr; csr->s_ctda = LOWER(mtdhead->mtd_txp); wbflush(); csr->s_cr = CR_TXP; wbflush(); break; } } } /* dequeue some new packets, if possible */ if (!(sn->sn_if.if_flags & IFF_OACTIVE)) snifstart (&sn->sn_if);}static voidsntxdone (struct sn_softc *sn, struct mtd *mtd){ sn->sn_if.if_flags &= ~IFF_OACTIVE; sn->sn_retries = 0; if (mtd->mtd_mbuf) { m_freem (mtd->mtd_mbuf); mtd->mtd_mbuf = 0; } mtdhead = mtd->mtd_link; if (mtdhead == mtdnext) mtdhead = 0; mtd_free (mtd);}static voidsntxdump (volatile struct TXpkt *txp){ int fr; printf (" frags:"); for (fr = 0; fr < txp->frag_count; fr++) printf (" %d", txp->frags[fr].frag_size); printf ("\n");}/* * Receive interrupt routine */static voidsnrxint (struct sn_softc *sn){ volatile struct sn_reg *csr = sn->sn_csr; volatile struct RXpkt *rxp; rxp = &rda[sn->sn_rxmark]; while (rxp->in_use == 0) { if ((rxp->status & RCR_LPKT) == 0) log (LOG_WARNING, "%s%d: more than one packet in RBA\n", sn->sn_if.if_name, sn->sn_if.if_unit); #ifdef DEBUG if (SEQNO_PKT (rxp->seqno) != 0) log (LOG_WARNING, "%s%d: bad psn sequence no. %d\n", sn->sn_if.if_name, sn->sn_if.if_unit, SEQNO_PKT (rxp->seqno));#endif if (rxp->status & RCR_PRX) { if (snread (sn, rxp)) { sn->sn_if.if_ipackets++; sn->sn_sum.ss_rpacks++; } } else { log (LOG_INFO, "%s%d: rx packet error 0x%x\n", rxp->status); sn->sn_if.if_ierrors++; } /* give receive buffer area back to chip * XXX what buffer did the sonic use for this descriptor * answer look at the rba sequence number !! */ { int orra = SEQNO_RBA (rxp->seqno) & RRAMASK; volatile struct RXrsrc *orr = &rra[orra]; #ifdef DEBUG if (rxp->pkt_ptrhi != orr->buff_ptrhi || rxp->pkt_ptrlo != orr->buff_ptrlo || orr->buff_wclo == 0) log (LOG_WARNING, "%s%d: bad rx pkt pointers\n", sn->sn_if.if_name, sn->sn_if.if_unit);#endif /* orra is now empty of packets and can be freed * (if snread didnt copy it out, but instead passed * pointers around then we would have to wait for * higher levels to free it up) * * (dont bother add it back in again straight away) */ if (IS_K0SEG (rba)) /* hand data buffer over to Sonic */ clean_dcache (PHYS_TO_K0 ((orr->buff_ptrhi << 16) | orr->buff_ptrlo), RBASIZE); rra[sn->sn_rramark] = *orr; /* zap old rra */ orr->buff_wchi = orr->buff_wclo = 0; sn->sn_rramark = (sn->sn_rramark + 1) & RRAMASK; csr->s_rwp = LOWER(&rra[sn->sn_rramark]); wbflush (); } /* * give receive descriptor back to chip * simple list is circular */ rxp->in_use = ~0; rxp->rlink |= EOL; sn->sn_lrxp->rlink &= ~EOL; sn->sn_lrxp = rxp; if (++sn->sn_rxmark >= NRDA) sn->sn_rxmark = 0; rxp = &rda[sn->sn_rxmark]; }}/* * snread -- pull packet off interface and forward to appropriate * protocol handler */static intsnread (struct sn_softc *sn, volatile struct RXpkt *rxp){ struct ifqueue *inq; extern char *ether_sprintf();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -