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

📄 dev_sb1250_ethernet.c

📁 一个很好的嵌入式linux平台下的bootloader
💻 C
📖 第 1 页 / 共 5 页
字号:
			    unsigned int regval){    int mac_mdio_genc;        sbeth_mii_sync(s);    sbeth_mii_senddata(s,MII_COMMAND_START,2);    sbeth_mii_senddata(s,MII_COMMAND_WRITE,2);    sbeth_mii_senddata(s,phyaddr, 5);    sbeth_mii_senddata(s,regidx, 5);    sbeth_mii_senddata(s,MII_COMMAND_ACK,2);    sbeth_mii_senddata(s,regval,16);    mac_mdio_genc = SBETH_READCSR(s->sbe_mdio) & M_MAC_GENC;        SBETH_WRITECSR(s->sbe_mdio,M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc);}/*  *********************************************************************    *  SBDMA_INITCHAN(s,d)    *      *  Initialize the DMA channel, programming the CSRs to the     *  values calculated in the SBDMA_INITCTX routine.    *      *  Input parameters:     *  	   s - sbeth structure    *  	   d - sbdma structure    *  	       *  Return value:    *  	   nothing    ********************************************************************* */static void sbdma_initchan(sbeth_t *s,			   sbethdma_t *d){    /*     * Turn on the DMA channel     */    SBETH_WRITECSR(d->sbdma_config1,0);    SBETH_WRITECSR(d->sbdma_dscrbase,d->sbdma_dscrtable_phys);    SBETH_WRITECSR(d->sbdma_config0,		   V_DMA_RINGSZ(d->sbdma_maxdescr) |		   0);}/*  *********************************************************************    *  SBDMA_INITCTX(s,d,chan,txrx,maxdescr,callback)    *      *  Initialize a DMA channel context.  Since there are potentially    *  eight DMA channels per MAC, it's nice to do this in a standard    *  way.      *      *  Input parameters:     *  	   s - sbeth_t structure (pointer to a MAC)    *  	   d - sbethdma_t structure (DMA channel context)    *  	   chan - channel number (0..1 right now)    *  	   txrx - Identifies DMA_TX or DMA_RX for channel direction    *  	   maxdescr - number of descriptors to allocate for the ring    *  	       *  Return value:    *  	   nothing    ********************************************************************* */static void sbdma_initctx(sbeth_t *s,			  sbethdma_t *d,			  int chan,			  int txrx,			  int maxdescr,			  void (*callback)(void *,int,void *,uint64_t,unsigned int)){    /*      * Save away interesting stuff in the structure      */    d->sbdma_eth       = s;    d->sbdma_channel   = chan;    d->sbdma_txdir     = txrx;    d->sbdma_maxdescr  = maxdescr;    /*      * initialize register pointers      */    d->sbdma_config0 = SBETH_PORT(s->sbe_baseaddr + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG0));    d->sbdma_config1 = SBETH_PORT(s->sbe_baseaddr + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG1));    d->sbdma_dscrbase = SBETH_PORT(s->sbe_baseaddr + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_BASE));    d->sbdma_dscrcnt = SBETH_PORT(s->sbe_baseaddr + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_CNT));    d->sbdma_curdscr = 	SBETH_PORT(s->sbe_baseaddr + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CUR_DSCRADDR));    /*     * initialize the ring     */    d->sbdma_dscrtable = (sbdmadscr_t *) 	KMALLOC(maxdescr*sizeof(sbdmadscr_t),sizeof(sbdmadscr_t));    d->sbdma_dscrtable_end = d->sbdma_dscrtable + maxdescr;    d->sbdma_dscrtable_phys = SBETH_VTOP(d->sbdma_dscrtable);    d->sbdma_addptr = d->sbdma_dscrtable;    d->sbdma_remptr = d->sbdma_dscrtable;    d->sbdma_ctxtable = (void **) 	KMALLOC(maxdescr*sizeof(void *),sizeof(void *));    /*     * install callback     */    d->sbdma_upcall = callback;}/*  *********************************************************************    *  SBDMA_RESET(d)    *      *  Reset the software-maintained state for the specified    *  DMA channel.    *      *  Input parameters:     *  	   d - dma channel    *  	       *  Return value:    *  	   nothing    ********************************************************************* */static void sbdma_reset(sbethdma_t *d){    d->sbdma_addptr = d->sbdma_dscrtable;    d->sbdma_remptr = d->sbdma_dscrtable;    d->sbdma_onring = 0;}/*  *********************************************************************    *  SBDMA_PROCBUFFERS(d,procfunc)    *      *  Process "completed" buffers on the specified DMA channel.      *  This is normally called within the interrupt service routine.    *  Note that this isn't really ideal for priority channels, since    *  it processes all of the packets on a given channel before     *  returning.     *    *  Input parameters:     *  	   d - DMA channel context    *  	   procfunc - routine to call for each completed buffer.  This    *  	              is called with the context for the completed buffer,    *  	              the status from the descriptor, and the length from    *  	              the descriptor.    *  	       *  Return value:    *  	   number of packets processed.    ********************************************************************* */static int sbdma_procbuffers(sbethdma_t *d,			     void (*procfunc)(void *ifctx,int chan,void *ctx,					      uint64_t status,					      unsigned int pktlen)){    int curidx;    int hwidx;    int count = 0;    sbdmadscr_t *dsc;    for (;;) {	/* 	 * figure out where we are (as an index) and where	 * the hardware is (also as an index)	 *	 * This could be done faster if (for example) the 	 * descriptor table was page-aligned and contiguous in	 * both virtual and physical memory -- you could then	 * just compare the low-order bits of the virtual address	 * (sbdma_remptr) and the physical address (sbdma_curdscr CSR)	 */	curidx = d->sbdma_remptr - d->sbdma_dscrtable;	{	    uint64_t tmp;	    tmp = SBETH_READCSR(d->sbdma_curdscr);	    if (!tmp) {	        break;	        }	    hwidx = (int) (((tmp & M_DMA_CURDSCR_ADDR) -				d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));	}	/*	 * If they're the same, that means we've processed all	 * of the descriptors up to (but not including) the one that	 * the hardware is working on right now.	 */	if (curidx == hwidx) break;	/*	 * Remove packet from the on-ring count.	 */	d->sbdma_onring--;	/*	 * Otherwise, issue the upcall.	 */	dsc = &(d->sbdma_dscrtable[curidx]);	(*procfunc)(d->sbdma_eth->sbe_ifctx,		    d->sbdma_channel,		    d->sbdma_ctxtable[curidx],		    dsc->dscr_a & M_DMA_DSCRA_STATUS,		    (int)G_DMA_DSCRB_PKT_SIZE(dsc->dscr_b));	count++;	/* 	 * .. and advance to the next buffer.	 */	d->sbdma_remptr = sbdma_nextbuf(d,sbdma_remptr);	}    return count;}/*  *********************************************************************    *  SBDMA_ADDBUFFER(d,ptr,length,ctx)    *      *  Add a buffer to the specified DMA channel.  For transmit channels,    *  this causes a transmission to start.  For receive channels,    *  this queues a buffer for inbound packets.    *      *  Input parameters:     *  	   d - DMA channel descriptor    *  	   ptr - pointer to buffer (must by physically contiguous)    *  	   length - length of buffer    *  	   ctx - arbitrary data to be passed back when descriptor completes    *  	         (for example, mbuf pointers, etc.)    *  	       *  Return value:    *  	   0 if buffer could not be added (ring is full)    *  	   1 if buffer added successfully    ********************************************************************* */static int sbdma_addbuffer(sbethdma_t *d,uint8_t *ptr,int length,void *ctx){    sbdmadscr_t *dsc;    sbdmadscr_t *nextdsc;    sbeth_t         *s = d->sbdma_eth;    /* get pointer to our current place in the ring */    dsc = d->sbdma_addptr;    nextdsc = sbdma_nextbuf(d,sbdma_addptr);    /*     * figure out if the ring is full - if the next descriptor     * is the same as the one that we're going to remove from     * the ring, the ring is full     */    if (nextdsc == d->sbdma_remptr) {	return 0;	}    /*     * fill in the descriptor      */    if (d->sbdma_txdir) {	/* transmitting: set outbound options and length */	dsc->dscr_a = SBETH_VTOP(ptr) |	    V_DMA_DSCRA_A_SIZE(SBDMA_NUMCACHEBLKS(((uint64_t) length))) |	    M_DMA_DSCRA_INTERRUPT |	    M_DMA_ETHTX_SOP;	if (s->fifo_mode) {	    dsc->dscr_b = V_DMA_DSCRB_OPTIONS(K_DMA_ETHTX_NOMODS) |		V_DMA_DSCRB_PKT_SIZE(length);	    	    }	else {	    dsc->dscr_b = V_DMA_DSCRB_OPTIONS(K_DMA_ETHTX_APPENDCRC_APPENDPAD) |		V_DMA_DSCRB_PKT_SIZE(length);	    }	}    else {	/* receiving: no options */	dsc->dscr_a = SBETH_VTOP(ptr) |	    V_DMA_DSCRA_A_SIZE(SBDMA_NUMCACHEBLKS(((uint64_t) length))) |	    M_DMA_DSCRA_INTERRUPT;	dsc->dscr_b = 0;	}    /*     * fill in the context      */    d->sbdma_ctxtable[dsc-d->sbdma_dscrtable] = ctx;    /*      * point at next packet      */    d->sbdma_addptr = nextdsc;    /*      * Give the packet to the hardware     */    d->sbdma_onring++;    SBETH_WRITECSR(d->sbdma_dscrcnt,1);	    return 1;					/* we did it */}/*  *********************************************************************    *  SBETH_INITFREELIST(s)    *      *  Initialize the buffer free list for this mac.  The memory    *  allocated to the free list is carved up and placed on a linked    *  list of buffers for use by the mac.    *      *  Input parameters:     *  	   s - sbeth structure    *  	       *  Return value:    *  	   nothing    ********************************************************************* */static void sbeth_initfreelist(sbeth_t *s){    int idx;    unsigned char *ptr;    sbeth_pkt_t *pkt;    s->sbe_freelist = NULL;    /* Must empty rxqueue, as we're about to free all the pkts on it */    s->sbe_rxqueue = NULL;    ptr = s->sbe_pktpool;    for (idx = 0; idx < SBETH_PKTPOOL_SIZE; idx++) {	pkt = (sbeth_pkt_t *) ptr;	sbeth_free_pkt(s,pkt);	ptr += SBETH_PKTBUF_SIZE;	}}/*  *********************************************************************    *  SBETH_ALLOC_PKT(s)    *      *  Allocate a packet from the free list.    *      *  Input parameters:     *  	   s - sbeth structure    *  	       *  Return value:    *  	   pointer to packet structure, or NULL if none available    ********************************************************************* */static sbeth_pkt_t *sbeth_alloc_pkt(sbeth_t *s){    uintptr_t addr;    sbeth_pkt_t *pkt = s->sbe_freelist;    if (!pkt) return NULL;    s->sbe_freelist = pkt->next;    pkt->next = NULL;    addr = (uintptr_t) (pkt+1);    if (addr & (SBDMA_CACHESIZE-1)) {	addr = (addr + SBDMA_CACHESIZE) & ~(SBDMA_CACHESIZE-1);	}    pkt->buffer = (unsigned char *) addr;    pkt->length = SBETH_PKT_SIZE;    return pkt;}/*  *********************************************************************    *  SBETH_FREE_PKT(s,pkt)    *      *  Return a packet to the free list    *      *  Input parameters:     *  	   s - sbmac structure    *  	   pkt - packet to return    *  	       *  Return value:    *  	   nothing    ********************************************************************* */static void sbeth_free_pkt(sbeth_t *s,sbeth_pkt_t *pkt){    pkt->next = s->sbe_freelist;    s->sbe_freelist = pkt;}/*  *********************************************************************    *  SBETH_TX_CALLBACK(ifctx,chan,ctx,status,pktsize)    *      *  Transmit callback routine.  This routine is invoked when a    *  queued transmit operation completes.  In this simple driver,    *  all we do is free the packet and try to re-fill the receive ring.    *      *  Input parameters:     *  	   ifctx - interface context (sbeth structure)    *  	   chan - DMA Channel    *  	   ctx - packet context (sbeth_pkt structure)    *  	   status - Ethernet status from descriptor    *  	   pktsize - length of packet (unused for transmits)    *  	       *  Return value:    *  	   nothing    ********************************************************************* */static void sbeth_tx_callback(void *ifctx,int chan,void *ctx,		       uint64_t status,unsigned int pktsize){    sbeth_t *s = ifctx;    sbeth_pkt_t *pkt = ctx;    sbeth_free_pkt(s,pkt);		/* return packet to pool */    sbeth_fillrxring(s,chan);		/* re-fill the receive ring */}/*  *********************************************************************    *  SBETH_RX_CALLBACK(ifctx,chan,ctx,status,pktsize)    *      *  Receive callback routine.  This routine is invoked when a    *  buffer queued for receives is filled. In this simple driver,    *  all we do is add the packet to a per-MAC queue for later    *  processing, and try to put a new packet in the place of the one    *  that was removed from the queue.    *      *  Input parameters:     *  	   ifctx - interface context (sbeth structure)    *  	   chan - DMA Channel    *  	   ctx - packet context (sbeth_pkt structure)    *  	   status - Ethernet status from descriptor    *  	   pktsize - length of packet (unused for transmits)    *  	       *  Return value:    *  	   nothing    ********************************************************************* */static void sbeth_rx_callback(void *ifctx,int chan,void *ctx,		       uint64_t status,unsigned int pktsize){    sbeth_t *s = ifctx;    sbeth_pkt_t *pkt = ctx;    sbeth_pkt_t *listptr;    if (!(status & M_DMA_ETHRX_BAD)) {

⌨️ 快捷键说明

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