| #include <linux/module.h> |
| #include <linux/etherdevice.h> |
| |
| #include <net/SI/ext_mem.h> |
| |
| #include "ddrnet.h" |
| |
| #define DDRNET_DEBUG 1 |
| #ifdef USE_DDRNET_PACKET |
| #define TAG_SIZE 4 |
| |
| static unsigned char B_TAG[TAG_SIZE] = {0xaa, 0xaa, 0x55, 0x55}; |
| static unsigned char E_TAG[TAG_SIZE] = {0x55, 0x55, 0xaa, 0xaa}; |
| #endif |
| |
| #define pswan1 ICP_CHANNEL_WAN1 |
| #define pswan2 ICP_CHANNEL_WAN2 |
| #define pswan3 ICP_CHANNEL_WAN3 |
| #define pswan4 ICP_CHANNEL_WAN4 |
| |
| |
| #ifdef dbg |
| #undef dbg |
| #endif |
| #if DDRNET_DEBUG |
| #define dbg(format, arg...) printk(KERN_DEBUG " ddrnet.c<%s>: " format "\n" , \ |
| __func__ , ## arg) |
| #else |
| #define dbg(format, arg...) do {} while (0) |
| #endif |
| |
| #ifdef err |
| #undef err |
| #endif |
| #define err(format, arg...) printk(KERN_ERR " ddrnet.c<%s>: " format "\n" , \ |
| __func__ , ## arg) |
| |
| #ifdef warn |
| #undef warn |
| #endif |
| #define warn(format, arg...) printk(KERN_WARNING " ddrnet.c<%s>: " format "\n" , \ |
| __func__ , ## arg) |
| |
| #ifdef info |
| #undef info |
| #endif |
| #define info(format, arg...) printk(KERN_ERR " ddrnet.c<%s>: " format "\n" , \ |
| __func__ , ## arg) |
| |
| |
| |
| |
| enum{ |
| //DDR_DEV_LAN = 0, |
| //DDR_DEV_WAN, |
| DDR_DEV_WAN1 = 0, |
| DDR_DEV_WAN2, |
| DDR_DEV_WAN3, |
| DDR_DEV_WAN4, |
| DDR_DEV_MAX, |
| |
| }; |
| |
| #define NET_LAN 0x10 |
| #define NET_WAN 0x11 |
| /* NET NUMBER; channel id; lan/wan*/ |
| |
| static unsigned int ddr_net_collect[DDR_DEV_MAX][3]= { |
| //{DDR_DEV_LAN, LAN1, NET_LAN}, |
| //{DDR_DEV_WAN, WAN, NET_WAN}, |
| {DDR_DEV_WAN1, pswan1, NET_WAN}, |
| {DDR_DEV_WAN2, pswan2, NET_WAN}, |
| {DDR_DEV_WAN3, pswan3, NET_WAN}, |
| {DDR_DEV_WAN4, pswan4, NET_WAN}, |
| |
| }; |
| |
| |
| |
| #define WATCHDOG_TIMEO (5*HZ) |
| #define ICP_CHANNEL_SIZE (8 * 1024 *2) |
| |
| #define ICP_PSBUFF_LEN 8 |
| |
| #define SKB_DATA_PTR_LEN 4 |
| |
| |
| //ps_buff lenth |
| #define SKB_DATA_LEN 1860 |
| #define SKB_DATA_DLPSBUFF_OFFSET (0x23100000 + 0x476018 + 0x400) |
| |
| #ifdef USE_DDRNET_PACKET |
| u32 g_ddrnet_rx = 0; |
| u32 g_ddrnet_rx_drop = 0; |
| |
| u32 g_ddrnet_rx_free = 0; |
| u32 g_ddrnet_rx_free_drop = 0; |
| |
| extern u32 g_ddrnet_wrap_num; |
| #endif |
| static struct net_device *ddrnet_dev[DDR_DEV_MAX]; |
| |
| static struct ddrnet *debug_ddrnet[DDR_DEV_MAX]; |
| |
| #ifdef USE_DDRNET_PACKET |
| struct ddrnet_queue free_psb_que; |
| struct ddrnet_queue free_psb_que_free; |
| |
| struct semaphore freepsb_que_sem; |
| struct task_struct* freepsb_wrap_thread = NULL; |
| struct timer_list freepsb_wrap_timer; |
| |
| u32 g_ddrnet_psbuf_nr = 0; |
| module_param(g_ddrnet_psbuf_nr, int, 0444); |
| struct spinlock g_psbuf_nr_lock; |
| #endif |
| |
| extern int (*fast_from_driver)(struct sk_buff *skb, struct net_device* dev); |
| |
| static void channelResult(int result) |
| { |
| if (result == 0) { |
| dbg("channel: success, len = %d", result); |
| return; |
| } |
| |
| switch (result) { |
| case RPMSG_INT_NOCLEAR: |
| dbg("channel: int not clear"); |
| break; |
| case RPMSG_ERROR: |
| err("channel: error"); |
| break; |
| case RPMSG_INVALID_PARAMETER: |
| err("channel: Invalid Parameter"); |
| break; |
| case RPMSG_SPACE_NOT_ENOUGH: |
| err("channel: space not enough"); |
| break; |
| case RPMSG_CHANNEL_ALREADY_EXIST: |
| err("channel: channel already existed"); |
| break; |
| case RPMSG_CHANNEL_INEXISTANCE: |
| err("channel: channel is not existed"); |
| break; |
| case RPMSG_CHANNEL_MSG_ERR: |
| err("channel: channel msg error"); |
| break; |
| case RPMSG_CHANNEL_ERROR: |
| err("channel: channel error"); |
| break; |
| case RPMSG_NO_MSG: |
| err("channel: no msg"); |
| break; |
| default: |
| err("channel: unknown error, result = %d",result); |
| } |
| } |
| |
| int g_zpr_ddrnet_flag1 = 0; |
| module_param(g_zpr_ddrnet_flag1, int, 0644); |
| static int ddrnet_icp_receive_thread(void * __dev) |
| { |
| struct ddrnet *dev = (struct ddrnet *)__dev; |
| int retval; |
| T_ZDrvRpMsg_Msg msg = { 0 }; |
| #ifdef USE_DDRNET_PACKET |
| struct ddrnet_package pkg = {0}; |
| int loop = 0; |
| int pkg_len = 0; |
| u8* cursor = NULL; |
| u32 spin_flag = 0; |
| u32 drop_nr = 0; |
| #endif |
| struct T_FromExt_mem psData = { 0 }; |
| |
| volatile int i = 0xFFFFFFFF; |
| unsigned long flags; |
| info("ddrnet_icp_receive_thread, lan = %d, actor_id = %d, channel_id = %d", dev->lan, dev->actor_id, dev->channel_id); |
| |
| //struct sched_param param = { .sched_priority = 1 }; |
| //param.sched_priority = 40; |
| //sched_setscheduler(current, SCHED_FIFO, ¶m); |
| |
| |
| while(1) { |
| #ifdef USE_DDRNET_PACKET |
| struct sk_buff *skb; |
| msg.actorID = dev->actor_id; |
| msg.chID = dev->channel_id; |
| msg.buf = &pkg; |
| msg.len = sizeof(struct ddrnet_package); |
| if(g_zpr_ddrnet_flag1 == 0 && dev->lan) |
| { |
| msleep(5); |
| continue; |
| } |
| spin_lock_irqsave(&g_psbuf_nr_lock, spin_flag); |
| if(g_ddrnet_psbuf_nr >= DDRNET_PACKET_QUEUE_COUNT - DDRNET_TRANS_THREDHOLD) |
| { |
| spin_unlock_irqrestore(&g_psbuf_nr_lock, spin_flag); |
| printk("g_ddrnet_psbuf_nr >= DDRNET_PACKET_QUEUE_COUNT - g_ddrnet_wrap_num"); |
| msleep(100); |
| continue; |
| } |
| spin_unlock_irqrestore(&g_psbuf_nr_lock, spin_flag); |
| retval = zDrvRpMsg_Read(&msg); |
| if (retval <= 0) { |
| err("no msg or thread exited"); |
| msleep(100); |
| continue; |
| } |
| pkg_len = pkg.pkg_length; |
| cursor = pkg.contents; |
| retval = memcmp(cursor, B_TAG, TAG_SIZE); |
| cursor += TAG_SIZE; |
| if (retval == 0) |
| retval = memcmp(cursor + pkg_len * DDRNET_PSB_PACKET_UNIT_SIZE, E_TAG, TAG_SIZE); |
| if(retval == 0) |
| { |
| //g_ddrnet_rx++; |
| //drop_nr = 0; |
| //printk("g_ddrnet_rx %d\n", g_ddrnet_rx); |
| for(loop = 0; loop < pkg_len; loop++) |
| { |
| memcpy(&psData, cursor, DDRNET_PSB_PACKET_UNIT_SIZE); |
| cursor += DDRNET_PSB_PACKET_UNIT_SIZE; |
| //printk("psbuf data:head %x:%x\n", psData.pbuf_data, psData.pbuf_head); |
| skb = skb_build_psbuf(&psData); //DL DATA, NO FREE |
| |
| if (!skb) { |
| err("ddrnet_icp_receive_thread can not allocate skb. drop the package"); |
| dev->net->stats.rx_dropped++; |
| //drop_nr++; |
| } else { |
| skb_push(skb, ETH_HLEN); |
| |
| if(loop == pkg_len - 1) |
| { |
| skb_set_last_pkg(skb); |
| } |
| if (set_protocol_by_version(skb) < 0) |
| continue; |
| if (fast_from_driver && fast_from_driver(skb, dev->net)) |
| { |
| continue; |
| } |
| memcpy(skb->data, dev->net->dev_addr, ETH_ALEN); |
| memcpy(skb->data + ETH_ALEN, dev->net->dev_addr, ETH_ALEN); |
| spin_lock_irqsave(&dev->rxq.lock, flags); |
| __skb_queue_tail (&dev->rxq, skb); |
| spin_unlock_irqrestore(&dev->rxq.lock, flags); |
| tasklet_schedule (&dev->bh); |
| } |
| |
| } |
| |
| spin_lock_irqsave(&g_psbuf_nr_lock, spin_flag); |
| g_ddrnet_psbuf_nr = g_ddrnet_psbuf_nr + pkg_len;// - drop_nr; |
| spin_unlock_irqrestore(&g_psbuf_nr_lock, spin_flag); |
| |
| g_ddrnet_rx = g_ddrnet_rx + pkg_len;// - drop_nr; |
| |
| } |
| else |
| { |
| g_ddrnet_rx_drop++; |
| printk(KERN_WARNING " ICP data recived ERR, g_ddrnet_rx_drop %d\n", g_ddrnet_rx_drop); |
| } |
| #else |
| //while(!kthread_should_stop()) { |
| struct sk_buff *skb; |
| |
| msg.actorID = dev->actor_id; |
| msg.chID = dev->channel_id; |
| msg.buf = &psData; |
| msg.len = sizeof(struct T_FromExt_mem); |
| // msg.flag |= RPMSG_READ_POLL; |
| |
| //TODO Èç¹û½ø³ÌÍ˳öÇÒÒ»Ö±¶ÁÈ¡²»µ½Êý¾Ý£¬Õâ¸öµØ·½»á·ñÒ»Ö±¿¨×¡? |
| //while(i--); |
| if(g_zpr_ddrnet_flag1 == 0 && dev->lan) |
| { |
| msleep(5); |
| continue; |
| } |
| retval = zDrvRpMsg_Read(&msg); |
| //dbg("zDrvRpMsg_Read retval = %d, len = %d", retval, msg.len); |
| if (retval <= 0) { |
| err("no msg or threand exited"); |
| msleep(1000); |
| continue; |
| } |
| |
| skb = skb_build_psbuf(&psData); |
| |
| |
| //only test --- need check how to adjust len with peirong |
| //dbg("skb original len = %d", skb->len); |
| //skb_put(skb, psData.len); |
| //dbg("skb_put len = %d", skb->len); |
| //end |
| |
| if (!skb) { |
| err("ddrnet_icp_receive_thread can not allocate skb. drop the package"); |
| dev->net->stats.rx_dropped++; |
| } else { |
| //PSBUF_OUT( skb->head, PSBUF_MDL_AP_DDRNET_BASE, PSBUF_MDL_AP_NET_BASE ); |
| //spin_lock(&dev->rxq.lock); |
| skb_push(skb, ETH_HLEN); |
| |
| if (set_protocol_by_version(skb) < 0) |
| continue; |
| |
| if (fast_from_driver && fast_from_driver(skb, dev->net)) |
| { |
| continue; |
| } |
| |
| memcpy(skb->data, dev->net->dev_addr, ETH_ALEN); |
| memcpy(skb->data + ETH_ALEN, dev->net->dev_addr, ETH_ALEN); |
| |
| spin_lock_irqsave(&dev->rxq.lock, flags); |
| __skb_queue_tail (&dev->rxq, skb); |
| spin_unlock_irqrestore(&dev->rxq.lock, flags); |
| //spin_unlock(&dev->rxq.lock); |
| tasklet_schedule (&dev->bh); |
| } |
| #endif |
| } |
| return 0; |
| } |
| |
| static int ddrnet_icp_release_thread(void * __dev) |
| { |
| struct ddrnet *dev = (struct ddrnet *)__dev; |
| int retval; |
| #ifdef USE_DDRNET_PACKET |
| |
| struct ddrnet_package pkg = {0}; |
| int loop = 0; |
| int pkg_len = 0; |
| u8* cursor = NULL; |
| |
| #endif |
| struct sched_param param = { .sched_priority = 1 }; |
| param.sched_priority = 40; |
| //sched_setscheduler(current, SCHED_FIFO, ¶m); |
| |
| T_ZDrvRpMsg_Msg msg = { 0 }; |
| void *skb; |
| |
| //dev->channel_id = channel_8; // »ñȡͨµÀºÅ |
| |
| while(1) { |
| //while(!kthread_should_stop()) { |
| #ifdef USE_DDRNET_PACKET |
| struct sk_buff *skb; |
| msg.actorID = dev->actor_id; |
| msg.chID = channel_8; |
| msg.buf = &pkg; |
| msg.len = sizeof(struct ddrnet_package); |
| //msg.flag |= RPMSG_READ_POLL; |
| |
| retval = zDrvRpMsg_Read(&msg); |
| if (retval <= 0) { |
| err("no msg or threand exited"); |
| msleep(1000); |
| continue; |
| } |
| pkg_len = pkg.pkg_length; |
| cursor = pkg.contents; |
| //printk("release thread, pkg_len %d\n", pkg_len); |
| retval = memcmp(cursor, B_TAG, TAG_SIZE); |
| cursor += TAG_SIZE; |
| if (retval == 0) |
| retval = memcmp(cursor + pkg_len * SKB_DATA_PTR_LEN, E_TAG, TAG_SIZE); |
| if(retval == 0) |
| { |
| g_ddrnet_rx_free += pkg_len; |
| //printk("g_ddrnet_rx_free %d\n", g_ddrnet_rx_free); |
| for(loop = 0; loop < pkg_len; loop++) |
| { |
| memcpy(&skb, cursor, SKB_DATA_PTR_LEN); |
| //printk("release thread, free skb addr %#x\n", skb); |
| free_toext_mem(skb); |
| cursor += SKB_DATA_PTR_LEN; |
| } |
| } |
| else |
| { |
| g_ddrnet_rx_free_drop++; |
| printk(KERN_WARNING "ICP READ FREEBUF DATA ERR, g_ddrnet_rx_free_drop %d\n", g_ddrnet_rx_free_drop); |
| } |
| #else |
| struct sk_buff *skb; |
| msg.actorID = dev->actor_id; |
| msg.chID = channel_8; |
| msg.buf = (unsigned char *)(&skb); // Êý¾Ý |
| msg.len = SKB_DATA_PTR_LEN; // ¶ÁÈ¡µÄ³¤¶È |
| //msg.flag |= RPMSG_READ_POLL; |
| |
| retval = zDrvRpMsg_Read(&msg); // ¶ÁÈ¡»·ÐζÓÁÐÖÐÒ»¸ö½Úµã£¬ |
| if (retval <= 0) { |
| err("no msg or threand exited"); |
| msleep(1000); |
| continue; |
| } |
| //ÈôºóÐøÎ´·¢ÏÖ´æÔں˼äskbй©£¬¿ÉÒÔÖ±½ÓʹÓÃkfree_skb(skb);½Ó¿Ú½øÐÐÕý³£µÄskbÊÍ·Å,µ«ÐèÒªÓëinsert_toext_memÒ»ÆðÈ¥³ý |
| free_toext_mem(skb); |
| |
| #endif |
| } |
| } |
| static int ddrnet_start(struct net_device *net) |
| { |
| struct ddrnet *dev = netdev_priv(net); |
| int retval; |
| struct task_struct *th; |
| struct task_struct *re; |
| info("ddrnet_open %s", dev->net->name); |
| |
| if(net->flags & IFF_UP) { |
| dbg("the %s has been opened!", dev->net->name); |
| return -EBUSY; |
| } |
| netif_start_queue (net); |
| |
| //read msg from icp |
| //th = kthread_run(ddrnet_icp_receive_thread, dev, "receive-thread"); |
| if (dev->rcv_thread == NULL) { |
| th = kthread_run(ddrnet_icp_receive_thread, dev, "receive-thread"); |
| if (IS_ERR(th)) { |
| err("Unable to start receive thread."); |
| return PTR_ERR(th); |
| } |
| dev->rcv_thread = th; |
| } |
| if(dev->rel_thread == NULL) { |
| re = kthread_run(ddrnet_icp_release_thread, dev, "release-thread"); |
| if (IS_ERR(re)) { |
| err("Unable to start release thread."); |
| return PTR_ERR(re); |
| } |
| dev->rel_thread = re; |
| } |
| #ifdef USE_DDRNET_PACKET |
| if(dev->skb_wrap_thread == NULL) { |
| re = kthread_run(ddrnet_skb_wrap_thread, dev, "skb-wrap-thread"); |
| if (IS_ERR(re)) { |
| err("Unable to start packet wrap thread."); |
| return PTR_ERR(re); |
| } |
| dev->skb_wrap_thread = re; |
| } |
| |
| #endif |
| return 0; |
| } |
| |
| static int ddrnet_open(struct net_device *net) |
| { |
| info("ddrnet_open"); |
| ddrnet_start(net); |
| /* |
| struct ddrnet *dev = netdev_priv(net); |
| int retval; |
| struct task_struct *th; |
| |
| if(net->flags & IFF_UP) { |
| dbg("the %s has been opened!", dev->net->name); |
| return -EBUSY; |
| } |
| netif_start_queue (net); |
| |
| //read msg from icp |
| th = kthread_run(ddrnet_icp_receive_thread, dev, "receive-thread"); |
| |
| if (IS_ERR(th)) { |
| err("Unable to start receive thread."); |
| return PTR_ERR(th); |
| } |
| dev->rcv_thread = th; |
| */ |
| return 0; |
| } |
| |
| static int ddrnet_close(struct net_device *net) |
| { |
| struct ddrnet *dev = netdev_priv(net); |
| |
| info("ddrnet_close"); |
| |
| netif_stop_queue(net); |
| #if 0 |
| if(dev->rcv_thread) |
| kthread_stop(dev->rcv_thread); |
| dev->rcv_thread = NULL; |
| if(dev->rel_thread) |
| kthread_stop(dev->rel_thread); |
| dev->rel_thread = NULL; |
| #endif |
| tasklet_kill (&dev->bh); |
| } |
| |
| static int ddrnet_write_icp_message(struct ddrnet *dev,struct T_ToExt_info *psData) |
| { |
| T_ZDrvRpMsg_Msg msg; |
| |
| memset(&msg, 0, sizeof(T_ZDrvRpMsg_Msg)); |
| msg.actorID = dev->actor_id; |
| msg.chID = dev->channel_id; |
| msg.flag |= RPMSG_WRITE_INT; |
| |
| msg.buf = psData; |
| msg.len = sizeof(struct T_ToExt_info); |
| |
| return zDrvRpMsg_WriteLockIrq(&msg); |
| } |
| |
| //½«CP²à´«µÝÀ´µÄpsbufÖ¸ÕëдÈëDDR£¬ÒÔICP·½Ê½Í¨ÖªCP²à |
| void write_freepsbuf(void *head) |
| { |
| int ret = 0; |
| |
| #ifdef USE_DDRNET_PACKET |
| Try_enqueue: |
| ret = ddrnet_freepsb_packet_enqueue(head); |
| if(ret < 0) |
| { |
| printk(KERN_WARNING "ddrnet_freepsb_packet_enqueue fail, try again...ret : %d!!!!!!", ret); |
| goto Try_enqueue; |
| } |
| |
| #else |
| T_ZDrvRpMsg_Msg msg = { .actorID = PS_ID, |
| .chID = ICP_CHANNEL_DEV_BUFFREE, |
| .flag = RPMSG_WRITE_INT, |
| .buf = NULL, |
| .len = 4 }; |
| |
| msg.buf = head; |
| |
| ret = zDrvRpMsg_WriteLockIrq(&msg); |
| #endif |
| if(ret <= 0) |
| panic("write ddr err, ret : %d!!!!!!", ret); |
| |
| } |
| |
| /* Called by the kernel in order to transmit a packet. */ |
| unsigned long g_ddrnet_cpnum = 0; |
| unsigned long g_ddrnet_othernum = 0; |
| unsigned long g_ddrnet_failnum1 = 0; |
| unsigned long g_ddrnet_failnum = 0; |
| int test_retval=11; |
| static netdev_tx_t ddrnet_tx_packet(struct sk_buff *skb, struct net_device *net) |
| { |
| int length; |
| unsigned char *psbuff; |
| struct ddrnet *dev = netdev_priv(net); |
| int retval = RPMSG_ERROR; |
| unsigned long phy; |
| int needFreePsbuff = 0; |
| struct T_ToExt_info skb_info={0}; |
| struct sk_buff *skb_new; |
| |
| if (!skb) { |
| panic("skb err!!!!"); |
| } |
| //Æ«ÒÆÖÁipÍ· |
| skb_pull(skb, ETH_HLEN); |
| |
| //Ë¢ÐÂcache |
| skb = flush_skbuf(skb); |
| |
| skb_info.skb_data = virtaddr_to_phys(skb->data); |
| skb_info.skb_head = virtaddr_to_phys(skb->head); |
| skb_info.skb = skb; |
| skb_info.datalen = skb->len; |
| |
| //ÈôºóÐøÎ޺˼äskbÄÚ´æÐ¹Â©£¬¿ÉÈ¥³ý¸Ã½Ó¿Ú£¬µ«ÐèÓëfree_toext_mem½Ó¿ÚÒ»ÆðÈ¥³ý |
| insert_toext_mem(skb); |
| #ifdef USE_DDRNET_PACKET |
| retval = ddrnet_skb_packet_enqueue(dev, &skb_info); |
| #else |
| retval = ddrnet_write_icp_message(dev, &skb_info); |
| #endif |
| test_retval = retval; |
| if (retval > 0) { |
| net->trans_start = jiffies; |
| net->stats.tx_packets++; |
| net->stats.tx_bytes += skb->len; |
| return NET_XMIT_SUCCESS; |
| } else { |
| //panic("write err, ret : %d!!!!", retval); |
| printk("write err, ret : %d!!!!", retval); |
| free_toext_mem(skb); |
| //return NET_XMIT_DROP; |
| return NET_XMIT_SUCCESS; |
| } |
| |
| } |
| |
| #if 0 |
| { |
| int length; |
| unsigned char *psbuff; |
| struct ddrnet *dev = netdev_priv(net); |
| int retval = RPMSG_ERROR; |
| unsigned long phy; |
| int needFreePsbuff = 0; |
| |
| //dbg("in ddr_ap_tx_packet, location = %d, data = 0x%X, len = %d\n", skb->location, skb->data, skb->len); |
| |
| if (!skb) { |
| err("ddrnet_tx_packet psbuff null"); |
| return NET_XMIT_DROP; |
| } |
| |
| length = skb->len; |
| |
| if (SKB_LOCATION_AP == skb->location || skb->cloned == 1) { |
| psbuff = alloc_psbuff(); |
| if (!psbuff) { |
| //err("ddrnet_tx_packet can not alloc_psbuff"); |
| net->stats.tx_dropped++; |
| g_ddrnet_failnum1++; |
| goto out; |
| //return NET_XMIT_DROP; |
| } |
| memcpy(psbuff, skb->data, length); |
| PSBUF_IN( psbuff, PSBUF_MDL_AP_DDRNET_BASE+1 ); |
| } else { |
| //err("ddrnet_tx_packet location is not AP"); |
| |
| if(SKB_LOCATION_CP == skb->location) |
| { |
| g_ddrnet_cpnum++; |
| psbuff = skb->data; |
| } |
| else |
| { |
| err("@!@ddrnet_tx_packet location is not AP %d",skb->location); |
| g_ddrnet_othernum++; |
| } |
| PSBUF_IN( skb->head, PSBUF_MDL_AP_DDRNET_BASE+2 ); |
| } |
| |
| /* if(dev->channel_id == LAN1) |
| { |
| memmove(psbuff - 2, psbuff, length); |
| psbuff = psbuff - 2; |
| } |
| |
| */ |
| if (psbuff_virt_to_phys(psbuff, &phy) != 1) { |
| //free_psbuff(psbuff); |
| |
| err("ddrnet_tx_packet psbuff_virt_to_phys error psbuff: 0x%x", psbuff); |
| net->stats.tx_dropped++; |
| g_ddrnet_failnum++; |
| goto out; |
| //return NET_XMIT_DROP; |
| } |
| #if 0 |
| if((dev->channel_id == channel_4) ||(dev->channel_id == channel_5) |
| ||(dev->channel_id == channel_6) ||(dev->channel_id == channel_10)) |
| { |
| #endif |
| if(phy > SKB_DATA_DLPSBUFF_OFFSET) |
| { |
| needFreePsbuff = 1; |
| goto out; |
| } |
| //} |
| |
| //dbg("ddr_ap_tx_packet virtual = 0x%X, phy = 0x%X", psbuff, phy); |
| |
| PSBUF_OUT( psbuff, PSBUF_MDL_AP_DDRNET_BASE, PSBUF_MDL_CP_CTRM_BASE ); |
| retval = ddrnet_write_icp_message(dev, phy, length); |
| //retval = ddrnet_write_icp_message(dev, psbuff, length); |
| if (retval > 0) { |
| net->trans_start = jiffies; |
| net->stats.tx_packets++; |
| net->stats.tx_bytes += length; |
| //dbg("> tx, len %d, type 0x%x", length, skb->protocol); |
| } else { |
| net->stats.tx_dropped++; |
| channelResult(retval); |
| needFreePsbuff = 1; |
| } |
| |
| out: |
| if (SKB_LOCATION_CP != skb->location || skb->cloned == 1 || needFreePsbuff) { |
| dev_kfree_skb_any (skb); |
| } else { |
| kfree_7510_skb(skb); |
| } |
| |
| //dbg("transmit result = %d\n", retval); |
| |
| if (retval > 0) |
| return NET_XMIT_SUCCESS; |
| else |
| return NET_XMIT_DROP; |
| } |
| #endif |
| |
| /* Called by the kernel when transmit times out */ |
| static void ddrnet_tx_timeout(struct net_device *net) |
| { |
| err("sent timeout!"); |
| net->stats.tx_errors++; |
| netif_wake_queue(net); |
| } |
| |
| static struct net_device_stats *ddrnet_get_stats(struct net_device *net) |
| { |
| // dbg("%s: request for stats\n", net->name); |
| return &net->stats; |
| } |
| |
| static const struct net_device_ops ddr_netdev_ops = { |
| .ndo_open = ddrnet_open, |
| .ndo_stop = ddrnet_close, |
| .ndo_start_xmit = ddrnet_tx_packet, |
| .ndo_tx_timeout = ddrnet_tx_timeout, |
| .ndo_get_stats = ddrnet_get_stats, |
| }; |
| |
| static inline void ddrnet_init_netdev(struct net_device *net) |
| { |
| //memset(net->dev_addr, 0xfe, ETH_ALEN); |
| #if 0 |
| u8 mac[ETH_ALEN] = {0x0, 0xa0, 0xc6, 0x11, 0x22, 0x33}; |
| memcpy(net->dev_addr, mac, ETH_ALEN); |
| #else |
| // randomly generated ethernet address |
| static u8 node_id [ETH_ALEN]; |
| random_ether_addr(node_id); |
| memcpy (net->dev_addr, node_id, sizeof node_id); |
| #endif |
| net->netdev_ops = &ddr_netdev_ops; |
| net->watchdog_timeo = WATCHDOG_TIMEO; |
| net->flags |= IFF_NOARP; |
| } |
| |
| static inline int ddrnet_createIcpChannel(struct ddrnet *dev) |
| { |
| int retval; |
| |
| //creata channel --- send/receive use the same channel |
| retval = zDrvRpMsg_CreateChannel (dev->actor_id, dev->channel_id, dev->channel_size); |
| channelResult(retval); |
| if(retval != RPMSG_SUCCESS && retval != RPMSG_CHANNEL_ALREADY_EXIST) |
| goto out; |
| |
| return retval; |
| |
| out: |
| err("could not create channel."); |
| return retval; |
| } |
| |
| #ifdef USE_DDRNET_PACKET |
| static inline void ddrnet_init_wraper(struct ddrnet* dev) |
| { |
| u32 spin_flag = 0; |
| struct ddrnet_skb_packet* packet = NULL; |
| u32 loop = 0; |
| |
| ddrnet_init_queue(&dev->skb_que); |
| ddrnet_init_queue(&dev->skb_que_free); |
| packet = (struct ddrnet_skb_packet*)kmalloc(DDRNET_SKB_PACKET_SIZE * DDRNET_PACKET_QUEUE_COUNT, GFP_ATOMIC); |
| |
| spin_lock_irqsave(&dev->skb_que_free.lock, spin_flag); |
| |
| for (loop = 0; loop < DDRNET_PACKET_QUEUE_COUNT; loop++) |
| { |
| ddrnet_list_insert_tail(&packet->list, &dev->skb_que_free.queue); |
| packet++; |
| } |
| dev->skb_que_free.qlen = DDRNET_PACKET_QUEUE_COUNT; |
| |
| spin_unlock_irqrestore(&dev->skb_que_free.lock, spin_flag); |
| sema_init(&dev->skb_que_sem,1); |
| |
| init_timer(&dev->wrap_timer); |
| dev->wrap_timer.data = (u32) dev; |
| dev->wrap_timer.function = ddrnet_skb_Wrap_TimerCallBack; |
| add_timer(&dev->wrap_timer); |
| |
| } |
| #endif |
| static inline void ddrnet_init_lan(struct net_device *net, unsigned int index) |
| { |
| struct ddrnet *dev; |
| dev = netdev_priv(net); |
| dev->net = net; |
| strcpy(net->name, "lan%d"); |
| dev->lan = 1; |
| dev->actor_id = PS_ID; |
| // dev->channel_id = LAN1; |
| dev->channel_id = ddr_net_collect[index][1]; |
| dev->channel_size = ICP_CHANNEL_SIZE; |
| skb_queue_head_init (&dev->rxq); |
| } |
| |
| static inline void ddrnet_init_wan(struct net_device *net, unsigned int index) |
| { |
| struct ddrnet *dev; |
| unsigned wan_index; |
| dev = netdev_priv(net); |
| dev->net = net; |
| //strcpy(net->name, "wan%d"); |
| wan_index = index + 1; // WAN1, WAN2,.... |
| sprintf(net->name, "wan%d", wan_index); |
| dev->lan = 0; |
| dev->actor_id = PS_ID; |
| //dev->channel_id = WAN; |
| dev->channel_id = ddr_net_collect[index][1]; |
| dev->channel_size = ICP_CHANNEL_SIZE; |
| skb_queue_head_init (&dev->rxq); |
| } |
| |
| static void ddrnet_skb_return (struct ddrnet *dev, struct sk_buff *skb) |
| { |
| int status; |
| |
| skb->protocol = eth_type_trans (skb, dev->net); |
| |
| status = netif_rx (skb); |
| if (status == NET_RX_SUCCESS) { |
| dev->net->stats.rx_packets++; |
| dev->net->stats.rx_bytes += skb->len; |
| } else { |
| dev->net->stats.rx_errors++; |
| err("netif_rx status %d.", status); |
| } |
| } |
| |
| static void ddrnet_bh (unsigned long param) |
| { |
| struct ddrnet *dev = (struct ddrnet *)param; |
| struct sk_buff *skb; |
| |
| while(skb = skb_dequeue(&dev->rxq)) { |
| if (skb->len) |
| ddrnet_skb_return(dev, skb); |
| else { |
| dev->net->stats.rx_errors++; |
| |
| dev_kfree_skb (skb); |
| err("drop!!!ddrnet_bh skb len == 0."); |
| } |
| } |
| } |
| int flag_zDrvRpMsg=0x5a; |
| int *vir_addr_ddrnet = NULL; |
| EXPORT_SYMBOL(vir_addr_ddrnet); |
| |
| static int __init ddrnet_init(void) |
| { |
| int i; |
| int err; |
| struct ddrnet *dev; |
| struct net_device *net; |
| |
| #ifdef USE_DDRNET_PACKET |
| u32 loop = 0; |
| u32 spin_flag = 0; |
| struct ddrnet_psbuf_packet* packet = NULL; |
| #endif |
| dbg("ddr_ap_net_lan_init.\n"); |
| |
| err = -ENOMEM; |
| for (i = 0; i < DDR_DEV_MAX; i++){ |
| //for (i = 0; i < 1; i++) { |
| net = alloc_etherdev(sizeof(struct ddrnet)); |
| if (!net) { |
| printk(KERN_ERR "could not allocate device.\n"); |
| return err; |
| } |
| |
| //È·±£ËùÓз¢Íùcp²àµÄÊý¾ÝÍ·²¿Ô¤Áô×ã¹»£¬±ÜÃâË¢cacheµÄʱºòÖØÐÂÉêÇëskb |
| net->needed_headroom += NET_SKB_PAD - ETH_HLEN; |
| |
| dev = netdev_priv(net); |
| debug_ddrnet[i] = dev; |
| |
| if(ddr_net_collect[i][2] == NET_LAN) |
| ddrnet_init_lan(net, i); |
| else if (ddr_net_collect[i][2] == NET_WAN) |
| ddrnet_init_wan(net, i); |
| else |
| goto out_free_netdev; |
| |
| dev->net = net; |
| dev->bh.func = ddrnet_bh; |
| dev->bh.data = (unsigned long) dev; |
| dev->rcv_thread = NULL; |
| dev->rel_thread = NULL; |
| #ifdef USE_DDRNET_PACKET |
| dev->skb_wrap_thread == NULL; |
| #endif |
| ddrnet_init_netdev(net); |
| ddrnet_createIcpChannel(dev); |
| #ifdef USE_DDRNET_PACKET |
| ddrnet_init_wraper(dev); |
| #endif |
| err = register_netdev(net); |
| if (err) |
| goto out_free_netdev; |
| ddrnet_dev[i] = net; |
| |
| // ddrnet_start(net); |
| } |
| |
| { |
| flag_zDrvRpMsg=zDrvRpMsg_CreateChannel (PS_ID, ICP_CHANNEL_DEV_BUFFREE, 16*1024); |
| #ifdef USE_DDRNET_PACKET |
| spin_lock_init(&g_psbuf_nr_lock); |
| ddrnet_init_queue(&free_psb_que); |
| ddrnet_init_queue(&free_psb_que_free); |
| sema_init(&freepsb_que_sem, 1); |
| packet = (struct ddrnet_psbuf_packet*)kmalloc(DDRNET_PSB_PACKET_SIZE * DDRNET_PACKET_QUEUE_COUNT, GFP_ATOMIC); |
| |
| spin_lock_irqsave(&free_psb_que_free.lock, spin_flag); |
| for (loop = 0; loop < DDRNET_PACKET_QUEUE_COUNT; loop++) |
| { |
| ddrnet_list_insert_tail(&packet->list, &free_psb_que_free.queue); |
| packet++; |
| } |
| free_psb_que_free.qlen = DDRNET_PACKET_QUEUE_COUNT; |
| spin_unlock_irqrestore(&free_psb_que_free.lock, spin_flag); |
| |
| if(freepsb_wrap_thread == NULL) { |
| freepsb_wrap_thread = kthread_run(ddrnet_freepsb_wrap_thread, 0, "freepsb-wrap-thread"); |
| if (IS_ERR(freepsb_wrap_thread)) { |
| err("Unable to start packet wrap thread."); |
| return PTR_ERR(freepsb_wrap_thread); |
| } |
| } |
| init_timer(&freepsb_wrap_timer); |
| freepsb_wrap_timer.data = NULL; |
| freepsb_wrap_timer.function = ddrnet_freepsb_Wrap_TimerCallBack; |
| add_timer(&freepsb_wrap_timer); |
| #endif |
| } |
| |
| |
| vir_addr_ddrnet = ioremap_cached(PSBUFFER_MEM_BASE, PSBUFFER_MEM_SIZE); |
| if(vir_addr_ddrnet == NULL) |
| { |
| printk(KERN_WARNING "Warning: [zx297510] cp ps_buf mmap failed.\n"); |
| panic("Warning: [zx297510] cp ps_buf mmap failed.\n"); |
| } |
| |
| return 0; |
| |
| out_free_netdev: |
| free_netdev(net); |
| return err; |
| } |
| late_initcall(ddrnet_init); |
| |
| static void __exit ddrnet_exit(void) |
| { |
| int i; |
| struct net_device *net; |
| |
| for (i = 0; i < DDR_DEV_MAX; i++) { |
| if ((net = ddrnet_dev[i])) { |
| unregister_netdev(net); |
| free_netdev(net); |
| ddrnet_dev[i] = NULL; |
| } |
| } |
| } |
| module_exit(ddrnet_exit); |
| |
| MODULE_AUTHOR("P96G"); |
| MODULE_DESCRIPTION("7510 AP Lan Net Device"); |
| MODULE_LICENSE("GPL"); |