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

📄 if_sonic.c

📁 很好的一个嵌入式linux平台下的bootloader
💻 C
📖 第 1 页 / 共 3 页
字号:
    struct ether_header *eh;    caddr_t addr;    struct mbuf *m;    int len, i;     int toff, tlen;    /*     * Get input data length.     * Get pointer to ethernet header (in input buffer).     * Deal with trailer protocol: if type is PUP trailer     * get true type from first 16-bit word past data.     * Remember that type was trailer by setting off.     */    len = rxp->byte_count - FCSSIZE;    if (IS_K0SEG (rba))	addr = (caddr_t) PHYS_TO_K0 ((rxp->pkt_ptrhi << 16) | rxp->pkt_ptrlo);    else	addr = (caddr_t) PHYS_TO_K1 ((rxp->pkt_ptrhi << 16) | rxp->pkt_ptrlo);#ifdef MIPSEL    snswapb (addr, addr, len);#endif#ifdef XDSSONICBUG    xds_compress_buffer (addr, len);#endif    eh = (struct ether_header  *)addr;    eh->ether_type = ntohs((u_short)eh->ether_type);    addr += sizeof (struct ether_header);    len -= sizeof (struct ether_header);    if (len < ETHERMIN || len > ETHERMTU) {	log (LOG_WARNING, "%s%d: bad packet length received: %d bytes\n",	     sn->sn_if.if_name, sn->sn_if.if_unit, len);	return 0;    }        if (eh->ether_type >= ETHERTYPE_TRAIL &&	eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {	toff = (eh->ether_type - ETHERTYPE_TRAIL) * 512;	if (toff >= ETHERMTU) {	    log (LOG_WARNING, "%s%d: trailer offset %d >= ETHERMTU\n",		 sn->sn_if.if_name, sn->sn_if.if_unit, toff);	    return 0;	}	eh->ether_type = ntohs(*(u_short *)(addr + toff));	tlen = ntohs(*(u_short *)(addr + toff + sizeof(u_short)));	if (toff + tlen > len) {	    log (LOG_WARNING, "%s%d: bad trailer toff=%d tlen=%d plen=%d\n",		 sn->sn_if.if_name, sn->sn_if.if_unit, toff, tlen, len);	    return 0;	}	len = toff;		/* sizeof data only */	toff += 2*sizeof(u_short);	tlen -= 2*sizeof(u_short);    }    else {	toff = tlen = 0;    }        if (T_rxp) {	printf("rcvd 0x%x status=0x%x len=%d type=0x%x from %s",	       addr, rxp->status, len, eh->ether_type,	       ether_sprintf (eh->ether_shost));	printf(" (to %s)\n", ether_sprintf (eh->ether_dhost));    }    /*     * Pull packet off interface.  Off is nonzero if packet     * has trailing header; sonic_get 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.     */    m = snget (sn, addr, len, toff, tlen);    if (!m)      return 0;    ether_input (&sn->sn_if, eh, m);    return 1;}/* * munge the received packet into an mbuf chain * because we are using stupid buffer management this  * is slow. */static struct mbuf *snget (struct sn_softc *sn, caddr_t addr, int dlen, int toff, int tlen){    struct mbuf *top = 0;    struct mbuf **mp = &top;    register struct mbuf *m;    register int len;    caddr_t sp;    if (dlen + tlen == 0)      return 0;    MGETHDR (m, M_DONTWAIT, MT_DATA);    if (!m)      return 0;    m->m_pkthdr.rcvif = &sn->sn_if;    m->m_pkthdr.len = dlen + tlen;    m->m_len = MHLEN;    sp = addr + toff;    len = tlen;    while (1) {	if (len == 0) {	    if (dlen == 0)	      return top;	/* all done */	    sp = addr;	    len = dlen;	    dlen = 0;	}	if (top) {	    /* get next mbuf */	    MGET (m, M_DONTWAIT, MT_DATA);	    if (!m) {		m_freem (top);		return 0;	    }	    m->m_len = MLEN;	}	if (len >= MINCLSIZE) {	    MCLGET (m, M_DONTWAIT);	    if (m->m_flags & M_EXT)	      m->m_len = MCLBYTES;	} 	else if (top == 0 && len + max_linkhdr <= m->m_len) {	    /* place initial small packet/header at end of mbuf */	    m->m_data += max_linkhdr;	}			if (m->m_len > len)	  m->m_len = len;	bcopy (sp, mtod(m, caddr_t), m->m_len);	sp += m->m_len;	len -= m->m_len;	*mp = m;	mp = &m->m_next;    }}static voidmtd_free (struct mtd *mtd){  mtd->mtd_mbuf = (struct mbuf *)0;  mtd->mtd_link = mtdfree;  mtdfree = mtd;}static struct mtd *mtd_alloc (){  struct mtd *mtd;  mtd = mtdfree;  if (mtd) {    mtdfree = mtd->mtd_link;    mtd->mtd_link = 0;  }  return (mtd);}/* * CAM support */static voidcaminitialise (){  int i;  bzero ((char *)cda, CDASIZE);  for (i = 0; i < MAXCAM; i++)    cda->desc[i].cam_ep = i;  cda->enable = 0;}static voidcamentry (int entry, u_char *ea){  cda->desc[entry].cam_ep = entry;  cda->desc[entry].cam_ap2 = (ea[5]<<8) | ea[4];  cda->desc[entry].cam_ap1 = (ea[3]<<8) | ea[2];  cda->desc[entry].cam_ap0 = (ea[1]<<8) | ea[0];  cda->enable |= (1 << entry);}static intcamprogram(struct sn_softc *sn){  volatile struct sn_reg *csr;  int timeout;  int i;  csr = sn->sn_csr;  csr->s_cdp = LOWER(cda);  csr->s_cdc = MAXCAM; wbflush ();  csr->s_cr = CR_LCAM; wbflush ();  timeout = 1000;  while ((csr->s_cr & CR_LCAM) && --timeout > 0)    DELAY (100);		/* let it get at the bus */  if (timeout <= 0) {      log (LOG_ERR, "sonic: CAM init failed\n");      return 0;  }  timeout = 1000;  while ((csr->s_isr & ISR_LCD) == 0 && --timeout > 0)    DELAY (100);  csr->s_isr = ISR_LCD; wbflush();  if (timeout <= 0) {      log (LOG_ERR, "sonic: CAM init didn't interrupt\n");      return 0;  }  return 1;}#ifdef notdefstatic voidcamdump(){  printf ("CAM entries:\n");  csr->s_cr = CR_RST;  wbflush ();     for (i = 0; i < 16; i++) {    u_short ap2, ap1, ap0;    csr->s_cep = i;    wbflush ();    ap2 = csr->s_cap2;    ap1 = csr->s_cap1;    ap0 = csr->s_cap0;    printf ("%d: ap2=0x%x ap1=0x%x ap0=0x%x\n", i, ap2, ap1, ap0);  }  printf ("CAM enable 0x%x\n", csr->s_cep);     csr->s_cr = 0;  wbflush ();}#endif/* * because the sonic is basically a 16 bit device it 'concatenates' * a higher buffer address to a 16 bit offset this can cause wrap * around problems near 64k boundaries !! */static intallocatebuffers (){    void *buf;    u_long p, lo, hi;#if defined(XDS)    rba = (char *)PHYS_TO_K0(SRAM_NET);    tba = rba + NRBA * RBASIZE;    buf = tba + NTDA * TBASIZE;#else    buf = malloc (SONICBUFSIZE, M_DEVBUF, 0);    if (!buf)      return (ENOBUFS);    rba = (char *) malloc (NRBA * RBASIZE, M_DEVBUF, 0);    if (!rba) {	free (buf, M_DEVBUF);	return (ENOBUFS);    }#endif#ifdef R4000    /* flush dirty data first */    if (IS_K0SEG (buf)) {	clean_dcache (buf, SONICBUFSIZE);	clean_dcache (rba, NRBA * RBASIZE);#ifdef XDS	clean_dcache (tba, NTDA * TBASIZE);#endif    }#endif    /* force into kseg1, and align correctly */    p = ((u_long) K0_TO_K1 (buf) + SONICALIGN - 1) & ~(SONICALIGN - 1);    /* RRA and CDA must fit inside 64k region */    if ((p ^ (p+RRASIZE+CDASIZE)) & ~0xffff)      p = (p+0x10000) & ~0xffff;    rra = (struct RXrsrc *)p; p += RRASIZE;    cda = (struct CDA *)p; p += CDASIZE;        /* RDA must fit inside 64k region */    if ((p ^ (p+RDASIZE)) & ~0xffff)      p = (p+0x10000) & ~0xffff;    rda = (struct RXpkt *)p; p += RDASIZE;        /* TDA must fit inside 64k region */    if ((p ^ (p+TDASIZE)) & ~0xffff)      p = (p+0x10000) & ~0xffff;    tda = (struct TXpkt *)p; p += TDASIZE;        /* check sanity of buffer addresese */    lo = (u_long) K0_TO_K1 (buf);     hi = lo + SONICBUFSIZE;    if ((unsigned)rra < lo || (unsigned)rra >= hi ||	(unsigned)cda < lo || (unsigned)cda >= hi ||	(unsigned)rda < lo || (unsigned)rda >= hi ||	(unsigned)tda < lo || (unsigned)tda >= hi) {	log (LOG_ERR, "sonic descriptors out of range\n");	return ENOMEM;    }    /* return errno */    return 0;}static voidinitialise_tda (struct sn_softc *sn){  volatile struct sn_reg *csr = sn->sn_csr;  struct mtd *mtd;  int i;  bzero ((char *)tda, TDASIZE);  mtdfree = mtdhead = mtdtail = (struct mtd *)0;  for (i = 0; i < NTDA; i++) {    mtd = &mtda[i];    mtd->mtd_txp = &tda[i];    mtd_free(mtd);#ifdef XDS    mtd->mtd_tba = tba + i*TBASIZE;#endif     }  mtdnext = mtd_alloc ();    csr->s_utda = UPPER(tda); wbflush();  csr->s_ctda = LOWER(mtdnext->mtd_txp); wbflush();}static voidinitialise_rda (struct sn_softc *sn){  volatile struct sn_reg *csr = sn->sn_csr;  int i;      /* link the RDA's together into a circular list   */  bzero ((char *)rda, RDASIZE);  for (i = 0; i < (NRDA-1); i++) {    rda[i].rlink = LOWER(&rda[i+1]);    rda[i].in_use = ~0;  }  rda[NRDA-1].in_use = ~0;  rda[NRDA-1].rlink =  LOWER(&rda[0]) | EOL;  /* mark end of receive descriptor list */  sn->sn_lrxp = &rda[NRDA-1];  sn->sn_rxmark = 0;  csr->s_urda = UPPER(rda);  csr->s_crda = LOWER(rda);  wbflush();}static voidinitialise_rra (struct sn_softc *sn){  volatile struct sn_reg *csr = sn->sn_csr;  char *rb;  int i;  bzero ((char *)rra, RRASIZE);  csr->s_eobc = EOBC / 2;  csr->s_urra = UPPER(rra);  csr->s_rsa = LOWER(rra);  csr->s_rea = LOWER(&rra[NRRA]);      /*   * fill up SOME of the rra with buffers    */  for (i = 0, rb = rba; i < NRBA; i++, rb += RBASIZE) {    rra[i].buff_ptrhi = UPPER(rb);    rra[i].buff_ptrlo = LOWER(rb);#ifdef XDSSONICBUG    rra[i].buff_wchi = (RBASIZE / 4) >> 16;    rra[i].buff_wclo = (RBASIZE / 4);#else    rra[i].buff_wchi = (RBASIZE / 2) >> 16;    rra[i].buff_wclo = (RBASIZE / 2);#endif  }  sn->sn_rramark = NRBA;  csr->s_rrp = LOWER(rra);  csr->s_rwp = LOWER(&rra[sn->sn_rramark]);  wbflush();}/* * snwatch(): interface watchdog timer *  * Called if any Tx packets remain unsent after 5 seconds, * In all cases we just reset the chip, and any retransmission  * will be handled by higher level protocol timeouts. */static intsnwatch (int unit){    struct sn_softc *sn = &sn_softc[unit];    int s = splimp();        if (mtdhead && mtdhead != mtdnext) {	/* something still pending for transmit */	log (LOG_WARNING, "%s%d: Tx - %s\n",	     sn->sn_if.if_name, sn->sn_if.if_unit,	     (mtdhead->mtd_txp->status == 0) ? "timeout" : "lost interrupt");	snrestart (sn);    }    (void) splx (s);    return 0;}/* * sn_pullup(): reorganise part of an mbuf chain to satisfy SONIC. *  * It doesn't free mbufs that reduce to zero length.   * This is in case they are NFS mbufs which point to disk buffers. * and the buffers must not be released until after the packet has flown. */static struct mbuf *sn_pullup (n, len)    register struct mbuf *n;    register int len;{    register struct mbuf *m;    register int count;        /* check it will fit in an ordinary mbuf */    if (len > MLEN)      goto bad;    if ((n->m_flags & M_EXT) == 0) {	/* ordinary mbuf */	if (n->m_data + len > &n->m_dat[MLEN]) {	    /* not enough space: must realign buffer start */	    bcopy (n->m_data, n->m_dat, n->m_len);	    n->m_data = n->m_dat;	}    }    else {	/* external cluster (must be only user) */	if (mclrefcnt[mtocl(n->m_data)] != 1) {	    log (LOG_NOTICE, "snpullup: shared ext cluster\n");	    goto bad;	}	if (n->m_data + len > n->m_ext.ext_buf + n->m_ext.ext_size) {	    /* not enough space: must realign cluster start */#ifdef DEBUG	    if (len <= n->m_ext.ext_size) {		log (LOG_NOTICE, "snpullup: ext buf too small (%d < %d)\n",		     n->m_ext.ext_size, len);		goto bad;	    }#endif	    bcopy (n->m_data, n->m_ext.ext_buf, n->m_len);	    n->m_data = n->m_ext.ext_buf;	}    }    /* now ok to append in place */    m = n;    n = n->m_next;    len -= m->m_len;    while (len > 0 && n) {	count = MIN(len, n->m_len);	bcopy(mtod(n, caddr_t), mtod(m, caddr_t)+m->m_len, (unsigned)count);	len -= count;	m->m_len += count;	n->m_len -= count;	if (n->m_len)	  n->m_data += count;	else	  n = n->m_next;    }    return (m); bad:    m_freem(n);    return (0);}/* * Fillup a whole chain, so that each mbuf has a sensible minimum * length, to avoid transmit underflows. */static struct mbuf *sn_fillup (m, minlen)    register struct mbuf *m;    register int minlen;{    struct mbuf *m0 = 0;    register struct mbuf *mprev = (struct mbuf *)&m0;    while (m) {	if (m->m_len && m->m_len < minlen && m->m_next)	  m = sn_pullup (m, minlen);	mprev->m_next = m;	mprev = m;	m = m->m_next;    }    return m0;}#ifdef MIPSELstatic voidsnswapb (s, d, len)    u_char *s, *d;    int len;{    while (len > 0) {	*(unsigned int *)d = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];	d += 4;	s += 4;	len -= 4;    }}static struct mbuf *snswapm (m0)    struct mbuf *m0;{    struct mbuf *m;    caddr_t s;    for (m = m0; m; m = m->m_next) {	if ((m->m_flags & M_EXT) && mclrefcnt[mtocl(m->m_data)] != 1)	    /* external cluster (must be only user) */	    panic ("snswapm: shared ext cluster");	s = m->m_data;	if ((unsigned)s & 3) {	    /* buffer is unaligned: must align data in buffer */	    caddr_t dat, d;	    unsigned int msz;	    	    /* determine data buffer base and size */	    if (m->m_flags & M_EXT) {		dat = m->m_ext.ext_buf;		msz = m->m_ext.ext_size;	    } else if (m->m_flags & M_PKTHDR) {		dat = m->m_pktdat;		msz = MHLEN;	    } else {		dat = m->m_dat;		msz = MLEN;	    }	    /* round buffer base up to word boundary */	    d = (caddr_t) (((unsigned long)dat + 3) & ~3);	    /* can we shuffle the data down to start of buffer? */	    if (m->m_data > d)		m->m_data = d;	    else {		/* is there room after the current data? */		d = (caddr_t) (((unsigned long)m->m_data + m->m_len + 3) & ~3);		if (d + ((m->m_len + 3) & ~3) <= dat + msz)		    m->m_data = d;		else		    /* this shouldn't happen!! */		    panic ("snswapm");	    }	}	snswapb (s, m->m_data, m->m_len);    }    return m0;}#endif#ifdef XDSSONICBUG/* * compress buffer in SRAM after it has been received */voidxds_compress_buffer (addr, len)caddr_t addr;int len;{    int words = (len + 3) >> 2;    unsigned int *sp, *dp;    /* ASSERT(IS_K0SEG(addr)); */    sp = dp = (unsigned int *)addr;    while (words-- > 0) {	*sp = *dp;	sp++;	dp += 2;    }}/* * expand buffer in SRAM before it is sent */voidxds_expand_buffer (addr, len)caddr_t addr;int len;{    int words = (len + 3) >> 2;    unsigned int *sp, *dp;    /* ASSERT(IS_K0SEG(addr)); */    sp = (unsigned int *)addr + words;    dp = sp + words;    while (words-- > 0) {	*(dp+1) = 0xdeaddead;	*dp = *sp;	sp--;	dp -= 2;    }    clean_dcache (addr, len * 2);}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -