| /******************************************************************************* | |
| * °æÈ¨ËùÓÐ (C)2011, ÉîÛÚÊÐÖÐÐËͨѶ¹É·ÝÓÐÏÞ¹«Ë¾¡£ | |
| * | |
| * ÎļþÃû³Æ: net.c | |
| * Îļþ±êʶ: | |
| * ÄÚÈÝÕªÒª: ¸ºÔðCPUºÍPPÄ£¿éÖ®¼äµÄÊý¾Ý½»»¥ | |
| * ÆäËü˵Ã÷: | |
| * µ±Ç°°æ±¾: 1.0 | |
| * ×÷¡¡¡¡Õß: ±«Ð¡ÔÆ | |
| * Íê³ÉÈÕÆÚ: 2012-1-12 16:22:32 | |
| * | |
| * Ð޸ļǼ1 | |
| * ÐÞ¸ÄÈÕÆÚ: | |
| * °æ±¾¡¡ºÅ: | |
| * Ð޸ġ¡ÈË: | |
| * ÐÞ¸ÄÄÚÈÝ: | |
| * | |
| *******************************************************************************/ | |
| #include <common.h> | |
| #include <asm/errno.h> | |
| #include <malloc.h> | |
| #include <net.h> | |
| #include <asm/arch/gmac.h> | |
| #if 0 | |
| #include <tm/io.h> | |
| #include <tm/tm.h> | |
| #include <tm/pon.h> | |
| #include <tm/pp/dma.h> | |
| #include <tm/pp/bmu.h> | |
| #include <tm/pp/red.h> | |
| #include <tm/pp/pp.h> | |
| #include <tm/pp/net.h> | |
| #include <tm/switch/smac.h> | |
| #endif | |
| #ifdef CONFIG_CMD_NET | |
| #define CACHE_ALIGNED(x) ((x)&(~0x1f)) | |
| #if 0 | |
| typedef struct _queue_ctrl{ | |
| u8 *pFirst; | |
| u32 nextToProc; | |
| } NET_QUEUE_CTRL; | |
| #endif | |
| u8 default_mac[6]={0x00,0xd0,0xd0,0x01,0x02,0x03}; | |
| /*NET_QUEUE_CTRL queue_ctrl[PP_MAX_QUEUE]; | |
| int pp_net_debug=0;*/ | |
| void (* volatile net_recv) (u8 * buf, int len) = NULL; | |
| void register_net_recv(void *handle) | |
| { | |
| net_recv = handle; | |
| } | |
| /* | |
| * Get pointer to next RX descriptor to be processed by SW | |
| */ | |
| #if 0 | |
| static inline struct pp_desc * pp_get_next_rxdesc(int rxq) | |
| { | |
| struct pp_desc *desc; | |
| NET_QUEUE_CTRL *qc; | |
| qc = &queue_ctrl[rxq]; | |
| desc = (struct pp_desc *)(qc->nextToProc * PP_DESC_SIZE + qc->pFirst); | |
| if(unlikely(++qc->nextToProc >= PP_QUEUE_SIZE)){ | |
| qc->nextToProc = 0; | |
| } | |
| return desc; | |
| } | |
| static void dump_net_data(u8 *data, u32 len) | |
| { | |
| int i; | |
| len = len > 64?64:len; | |
| for(i=0;i<len;i++){ | |
| printf("%.2x ",data[i]); | |
| if((i&0xf) == 0xf) | |
| printf("\n"); | |
| } | |
| printf("\n"); | |
| } | |
| void dump_desc(struct pp_desc *desc) | |
| { | |
| u32 *data = (u32 *)desc; | |
| printf("%.8x:0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",(u32)desc,data[0],data[1],data[2],data[3]); | |
| printf("bp %u gem %u len %u\n",desc->BP,desc->Gemport_ID,desc->Pkt_Len); | |
| } | |
| static void free_desc(struct pp_desc *desc,int bp) | |
| { | |
| // free desc | |
| #ifdef CONFIG_ZX279112 | |
| if(soft_release_rx_desc(desc->Direction, desc->CPU_Queue_ID,desc->Buffer_Type) < 0) | |
| #else | |
| if(soft_release_rx_desc(desc->CPU_Queue_ID,desc->Buffer_Type) < 0) | |
| #endif | |
| printf("failed to rls rx desc1\n"); | |
| // free bp | |
| if(pp_bmu_free_bp((u16)bp) < 0) | |
| printf("failed to rls bp\n"); | |
| } | |
| static inline int pp_net_rx(struct eth_device* dev,int cnt,int rxq) | |
| { | |
| int i,bp,len; | |
| struct pp_desc *desc ; | |
| u8 *buf; | |
| // receive packet | |
| #ifdef CONFIG_SYS_ARM_CACHE_WRITETHROUGH | |
| invalidate_dcache_all(); | |
| #endif | |
| for(i=0;i<cnt;i++){ | |
| //get desc, invalid cache, and prefetch | |
| desc = pp_get_next_rxdesc(rxq); | |
| #if !defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH) && !defined(CONFIG_SYS_DCACHE_OFF) | |
| invalidate_dcache_range((u32)desc,(u32)desc+16); | |
| #endif | |
| bp = desc->BP; | |
| // check bp | |
| if(unlikely(bp >= BP_NUMBERS)){ | |
| printf("invalid bp %u\n",bp); | |
| dump_desc(desc); | |
| //error handle | |
| #ifdef CONFIG_ZX279112 | |
| soft_release_rx_desc(desc->Direction, rxq,1); | |
| #else | |
| soft_release_rx_desc(rxq,1); | |
| #endif | |
| continue; | |
| } | |
| buf = (u8 *)(BP_TO_ADDR(bp)) + desc->Offset; | |
| len = desc->Pkt_Len; | |
| #if !defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH) && !defined(CONFIG_SYS_DCACHE_OFF) | |
| invalidate_dcache_range((u32)buf,(u32)buf+len); | |
| #endif | |
| if(pp_net_debug>0){ | |
| dump_desc(desc); | |
| printf("receive len %u, BP %d ,gem %d,addr %x\n",len, | |
| bp,desc->Gemport_ID,(u32)buf); | |
| dump_net_data(buf,len); | |
| pp_net_debug--; | |
| } | |
| if(net_recv == NULL) | |
| NetReceive(buf, len); | |
| else | |
| net_recv(buf, len); | |
| free_desc(desc,bp); | |
| } | |
| return cnt; | |
| } | |
| /* | |
| * get the count of unprocess packet | |
| */ | |
| static inline int pp_get_rx_cnt(u32 queue) | |
| { | |
| return ZX_REG_READ(PP_DMA_CPU_QUEUE_CNT(queue)); | |
| } | |
| #endif | |
| int max_rx_delay=1000; | |
| /* | |
| * pp net poll interface | |
| */ | |
| static int gmac_net_poll(struct eth_device* dev) | |
| { | |
| int i,len=0,trxlen=0; | |
| // unsigned char *rxbuf; | |
| unsigned char rxbuf[256]; | |
| //for(i=2;i>0;i--) | |
| for(i=0;i<2;i++) | |
| { | |
| if(zx_gmac_getbd(i)!=0) | |
| { | |
| trxlen=zx_gmac_rx(rxbuf,&len,i); | |
| if(net_recv == NULL) | |
| NetReceive(rxbuf, trxlen); | |
| else | |
| net_recv(rxbuf, trxlen); | |
| if(zx_gmac_getbd(i)!=0) | |
| /* new packet arrived or hardware has update rx cnt, wait for a while */ | |
| udelay(1); | |
| } | |
| } | |
| return 0; | |
| } | |
| #if 0 | |
| int pp_data_raw_send(u8 *data, u32 len,struct pp_desc *desc) | |
| { | |
| int bp; | |
| u8 *buf; | |
| /* get the tx descriptor */ | |
| /* alloc bp to save data */ | |
| if((bp = pp_bmu_alloc_bp())<0){ | |
| PON_NET_DBG("alloc bp failed\n"); | |
| return -1; | |
| } | |
| /* check bp */ | |
| if(unlikely(bp >= BP_NUMBERS)){ | |
| PON_NET_DBG("invalid bp %d\n",bp); | |
| return -1; | |
| } | |
| /* copy data to bp */ | |
| buf = (u8 *)BP_TO_ADDR(bp)+16; | |
| memcpy(buf,data,len); | |
| /* make desc */ | |
| desc->BP = bp; | |
| desc->Pkt_Len = len; | |
| desc->Pkt_Len_Changed = len; | |
| desc->Offset = 16; | |
| if(pp_net_debug>0){ | |
| printf("send len %u, BP %d ,addr %x\n",len, | |
| bp,(u32)buf); | |
| dump_desc(desc); | |
| dump_net_data(buf,len); | |
| pp_net_debug--; | |
| } | |
| #if !defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH) && !defined(CONFIG_SYS_DCACHE_OFF) | |
| flush_dcache_range((u32)buf,(u32)buf+len); | |
| #endif | |
| /* insert desc */ | |
| if(soft_insert_tx_desc((u32 *)desc)<0){ | |
| PON_NET_DBG("insert desc failed\n"); | |
| return -2; | |
| } | |
| return 0; | |
| } | |
| #endif | |
| /* | |
| * send packet to sw, | |
| */ | |
| static int gmac_net_sw_tx(struct eth_device* dev, volatile void* packet, int length) | |
| { | |
| if(zx_gmac_send((u8 *)packet,length) != 0) | |
| { | |
| printf("gmac send error\n"); | |
| return 1; | |
| } | |
| return 0; | |
| } | |
| #if 0 | |
| void pp_queue_init(void) | |
| { | |
| int i; | |
| NET_QUEUE_CTRL *qc; | |
| /* init inner rx queue status */ | |
| for(i=0;i<PP_MAX_QUEUE;i++){ | |
| qc = &queue_ctrl[i]; | |
| qc->pFirst = (u8 *)(PP_VA_DESC_BASE + 0x10000 * (PP_RX_QUEUE_OFF+i)); | |
| qc->nextToProc = 0; | |
| } | |
| } | |
| #endif | |
| int gmac_eth_init(struct eth_device* dev, bd_t* bd) | |
| { | |
| zx_gmac_init(); | |
| return 0; | |
| } | |
| void gmac_eth_halt(struct eth_device* dev) | |
| { | |
| udelay(100); /* wait for send complete */ | |
| zx_gmac_stop(); | |
| } | |
| /*int pp_net_init(void) | |
| { | |
| tm_set_onu_mac(ONU_MAC1,default_mac); | |
| pp_queue_init(); | |
| return 0; | |
| }*/ | |
| void gmac_net_register(void) | |
| { | |
| struct eth_device *dev; | |
| dev = malloc(sizeof(*dev)); | |
| if (!dev) { | |
| free(dev); | |
| return ; | |
| } | |
| memset(dev, 0, sizeof(*dev)); | |
| dev->init = gmac_eth_init; | |
| dev->halt = gmac_eth_halt; | |
| dev->send = gmac_net_sw_tx; | |
| dev->recv = gmac_net_poll; | |
| sprintf(dev->name, "eth0"); | |
| /* get mac */ | |
| if(!eth_getenv_enetaddr("ethaddr", dev->enetaddr)){ | |
| puts("Please set MAC address\n"); | |
| } | |
| else{ | |
| memcpy(default_mac,dev->enetaddr,6); | |
| } | |
| eth_register(dev); | |
| } | |
| #endif |