zte's code,first commit

Change-Id: I9a04da59e459a9bc0d67f101f700d9d7dc8d681b
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/ddr/ddrnet.c b/ap/os/linux/linux-3.4.x/drivers/net/ddr/ddrnet.c
new file mode 100644
index 0000000..9f1422f
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/ddr/ddrnet.c
@@ -0,0 +1,985 @@
+#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, &param);
+
+
+	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, &param);
+
+    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");