/******************************************************************************* | |
* °æÈ¨ËùÓÐ (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 |