⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 if_sonic.c

📁 很好的一个嵌入式linux平台下的bootloader
💻 C
📖 第 1 页 / 共 3 页
字号:
	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;}#endifstatic 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;}#endifvoidsnintr (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 + -