[Feature][T106]ZXW P56U09 code

Only Configure: Yes
Affected branch: master
Affected module: unknow
Is it affected on both ZXIC and MTK: only ZXIC
Self-test: No
Doc Update: No

Change-Id: I3cbd8b420271eb20c2b40ebe5c78f83059cd42f3
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/ddr/Kconfig b/ap/os/linux/linux-3.4.x/drivers/net/ddr/Kconfig
new file mode 100644
index 0000000..1f986fc
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/ddr/Kconfig
@@ -0,0 +1,7 @@
+#
+# Appletalk driver configuration
+#
+config 7510_DDR_AP_NET
+	tristate "ZTE 7510 AP LAN AND WAN"
+	default y
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/ddr/Makefile b/ap/os/linux/linux-3.4.x/drivers/net/ddr/Makefile
new file mode 100644
index 0000000..4f11ab0
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/ddr/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the Linux Wireless network device drivers.
+#
+
+obj-$(CONFIG_7510_DDR_AP_NET) += ddrnet.o
+obj-$(CONFIG_7510_DDR_AP_NET) += ddrnet_packet.o
\ No newline at end of file
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");
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/ddr/ddrnet.h b/ap/os/linux/linux-3.4.x/drivers/net/ddr/ddrnet.h
new file mode 100644
index 0000000..0db7b28
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/ddr/ddrnet.h
@@ -0,0 +1,74 @@
+#ifndef _DDRNET_H_
+#define _DDRNET_H_
+
+#include <linux/interrupt.h>
+
+#include <linux/netdevice.h>
+
+#include <linux/kthread.h>
+
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/semaphore.h>
+
+#include <linux/soc/zte/rpm/rpmsg.h>
+
+
+#define USE_DDRNET_PACKET
+#include "ddrnet_queue.h"
+#ifdef USE_DDRNET_PACKET
+#define PACKET_SIZE_LIMIT         1000
+#define WRAP_PACKET_THRESHHOLD  10
+#define WRAP_FREE_PACKET_THRESHHOLD 10
+#define DDRNET_PACKET_QUEUE_COUNT   5000//1024
+#define DDRNET_WRAP_TIMER_OUT_MS    10
+#define DDRNET_TRANS_THREDHOLD	   50
+
+#define WRAP_CONTENT_SIZE     1024
+#define DDRNET_PSB_PACKET_UNIT_SIZE            sizeof(struct T_FromExt_mem)
+#define DDRNET_SKB_PACKET_UNIT_SIZE            sizeof(struct  T_ToExt_info)
+#endif
+struct ddrnet {
+    struct net_device  *net;
+
+    /*lan0 or wan0*/
+    unsigned char lan;
+
+    T_ZDrvRpMsg_ActorID actor_id;
+    T_ZDrvRpMsg_ChID channel_id;
+    unsigned int channel_size;
+
+    //struct sk_buff_head txq;
+    struct sk_buff_head rxq;
+    //struct sk_buff_head done;
+
+    struct task_struct *rcv_thread;     /* the receive thread   */
+    struct task_struct *rel_thread;   
+#ifdef USE_DDRNET_PACKET
+    struct task_struct *skb_wrap_thread;
+#endif
+    struct tasklet_struct bh;
+#ifdef USE_DDRNET_PACKET
+    struct ddrnet_queue skb_que;
+    struct ddrnet_queue skb_que_free;
+    struct timer_list       wrap_timer;
+    struct semaphore  skb_que_sem;
+#endif
+
+};
+#ifdef USE_DDRNET_PACKET
+struct  ddrnet_package{
+        u32               pkg_length;                                        // package length
+        u8               contents[WRAP_CONTENT_SIZE];           // package contents
+};
+s32 ddrnet_skb_pkg_xmit(struct ddrnet * dev, struct ddrnet_package* pkg);
+s32 ddrnet_freepsb_pkg_xmit(struct ddrnet_package* pkg);
+void ddrnet_skb_Wrap_TimerCallBack(u32 hnd);
+void ddrnet_freepsb_Wrap_TimerCallBack(u32 hnd);
+s32 ddrnet_skb_wrap_thread(void * __dev);
+s32 ddrnet_freepsb_wrap_thread(void);
+s32 ddrnet_skb_packet_enqueue(struct ddrnet* dev, struct T_ToExt_info* buf);
+s32 ddrnet_freepsb_packet_enqueue(void *addr);
+#endif
+#endif  /*  _DDRNET_H_  */
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/ddr/ddrnet_packet.c b/ap/os/linux/linux-3.4.x/drivers/net/ddr/ddrnet_packet.c
new file mode 100644
index 0000000..2eccc55
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/ddr/ddrnet_packet.c
@@ -0,0 +1,342 @@
+#include <linux/module.h>
+#include "ddrnet.h"
+#ifdef USE_DDRNET_PACKET
+#define PSB_DATA_PTR_LEN 4
+
+#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};
+
+
+
+//u32 g_ddrnet_tx = 0;
+//u32 g_ddrnet_tx_drop = 0;
+//u32 g_ddrnet_tx_free = 0;
+//u32 g_ddrnet_tx_free_drop = 0;
+extern struct ddrnet_queue free_psb_que;
+extern struct ddrnet_queue free_psb_que_free;
+
+extern struct semaphore  freepsb_que_sem;
+extern struct timer_list freepsb_wrap_timer;
+extern struct spinlock g_psbuf_nr_lock;
+extern u32 g_ddrnet_psbuf_nr;
+
+
+
+u32 g_ddrnet_wrap_num = 10;
+module_param(g_ddrnet_wrap_num, int, 0644);
+u32 g_ddrnet_time_interval = 10;
+module_param(g_ddrnet_time_interval, int, 0644);
+
+u32 g_ddrnet_skb_timer_nr = 0;
+module_param(g_ddrnet_skb_timer_nr, int, 0444);
+u32 g_ddrnet_freepsb_timer_nr = 0;
+module_param(g_ddrnet_freepsb_timer_nr, int, 0444);
+u32 g_ddrnet_skb_pkg_unfull_nr = 0;
+module_param(g_ddrnet_skb_pkg_unfull_nr, int, 0444);
+
+
+
+void ddrnet_skb_Wrap_TimerCallBack(u32 hnd)
+{
+    struct  ddrnet *dev = (struct ddrnet *)hnd;	
+    up(&dev->skb_que_sem);
+    g_ddrnet_skb_timer_nr++;
+    //printk("#########ddrnet_skb_Wrap_TimerCallBack#########\n");
+}
+void ddrnet_freepsb_Wrap_TimerCallBack(u32 hnd)
+{
+    up(&freepsb_que_sem);
+    g_ddrnet_freepsb_timer_nr++;
+    //printk("#########ddrnet_freepsb_Wrap_TimerCallBack#########\n");
+}
+s32 ddrnet_freepsb_pkg_xmit(struct ddrnet_package* pkg)
+{
+    int ret = 0;    
+    T_ZDrvRpMsg_Msg msg = { .actorID = PS_ID,
+                           .chID = ICP_CHANNEL_DEV_BUFFREE,
+                           .flag = RPMSG_WRITE_INT,
+                           .buf = NULL,
+                           /*.len = sizeof(struct ddrnet_package)*/ };
+
+    msg.buf = pkg;	
+    msg.len = sizeof(u32) + pkg->pkg_length * PSB_DATA_PTR_LEN + TAG_SIZE * 2;
+    do
+    {
+        ret = zDrvRpMsg_WriteLockIrq(&msg);
+        if(ret <= 0)
+        {
+            printk("ddrnet_freepsb_pkg_xmit faile ret : %d\n", ret);
+            msleep(100);
+        }
+
+    }while(ret <= 0);
+    return ret;
+}
+
+
+s32 ddrnet_skb_pkg_xmit(struct ddrnet * dev, struct ddrnet_package* pkg)
+{
+    int ret = 0;  
+    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 = pkg;
+    //msg.len = sizeof(struct ddrnet_package);
+    msg.len = sizeof(u32) + pkg->pkg_length * DDRNET_SKB_PACKET_UNIT_SIZE + TAG_SIZE * 2;
+    do
+    {
+        ret = zDrvRpMsg_WriteLockIrq(&msg);
+        if(ret <= 0)
+        {
+            printk("ddrnet_skb_pkg_xmit faile ret : %d\n", ret);
+            msleep(100);
+        }
+    }while(ret <= 0);
+    
+    return ret;
+
+}
+
+s32 ddrnet_skb_wrap_thread(void * __dev)
+{
+    struct ddrnet *dev = (struct ddrnet *)__dev;
+    struct ddrnet_queue* que = &dev->skb_que;
+    struct ddrnet_queue* que_free = &dev->skb_que_free;
+    struct ddrnet_package pkg = {0};
+    struct ddrnet_skb_packet* pkt = NULL;
+    struct list_head* phead = NULL;
+    struct list_head* plist = NULL;
+    u8 loop = 0;
+    u8 cursor = 0;
+    u32 spin_flag = 0;
+    
+    struct sched_param param = { .sched_priority = 1 };
+    param.sched_priority = 37;
+    //sched_setscheduler(current, SCHED_FIFO, &param);
+    
+    while(1) {
+        down(&dev->skb_que_sem);
+        spin_lock_irqsave(&que->lock, spin_flag);
+        if(que->qlen <= 0)
+        {
+            spin_unlock_irqrestore(&que->lock, spin_flag);
+            continue;
+        }
+        spin_unlock_irqrestore(&que->lock, spin_flag);
+        //cursor = 0;
+        memcpy(pkg.contents, B_TAG, TAG_SIZE);
+        cursor = TAG_SIZE; 
+        phead = &que->queue;
+        for(loop = 0; loop < g_ddrnet_wrap_num/*WRAP_PACKET_THRESHHOLD*/; loop++)
+        {
+            
+            spin_lock_irqsave(&que->lock, spin_flag);
+            if(ddrnet_is_list_empty(phead))
+            {
+                spin_unlock_irqrestore(&que->lock, spin_flag);
+                break;
+            }
+            pkt = list_first_entry(phead, struct ddrnet_skb_packet, list);
+
+            ddrnet_list_delete(&pkt->list);
+            que->qlen--;
+            spin_unlock_irqrestore(&que->lock, spin_flag);
+            
+            memcpy(pkg.contents + cursor, &pkt->packet, DDRNET_SKB_PACKET_UNIT_SIZE);
+            //printk("wrap thread, skb head:data %x:%x, skb %#x\n ", pkt->packet.skb_head, pkt->packet.skb_data, pkt->packet.skb);
+            cursor += DDRNET_SKB_PACKET_UNIT_SIZE;
+            
+            spin_lock_irqsave(&que_free->lock, spin_flag);
+            ddrnet_list_insert_tail(&pkt->list, &que_free->queue);
+            que_free->qlen++;
+            spin_unlock_irqrestore(&que_free->lock, spin_flag);   
+        }            
+        pkg.pkg_length = loop;
+        if(loop < g_ddrnet_wrap_num)
+            g_ddrnet_skb_pkg_unfull_nr++;
+            //printk("########### skb big package not full, volume : %d ########\n", loop);
+        memcpy(pkg.contents + cursor, E_TAG, TAG_SIZE);
+        ddrnet_skb_pkg_xmit(dev, &pkg);
+        //g_ddrnet_tx++;
+        //printk("g_ddrnet_tx  %d\n", g_ddrnet_tx);
+    }
+    return 0;
+}
+int ddrnet_freepsb_wrap_thread(void)
+{
+    struct ddrnet_queue* que = &free_psb_que;
+    struct ddrnet_queue* que_free = &free_psb_que_free;
+    struct ddrnet_package pkg = {0};
+    struct ddrnet_psbuf_packet* pkt = NULL;
+    struct list_head* phead = NULL;
+    struct list_head* plist = NULL;
+    void* phy_addr = NULL;
+    u8 loop = 0;
+    u8 cursor = 0;
+    u32 spin_flag = 0;
+    int ret = 0;
+
+    struct sched_param param = { .sched_priority = 1 };
+    param.sched_priority = 37;
+    sched_setscheduler(current, SCHED_FIFO, &param);
+    
+    while(1) {
+        down(&freepsb_que_sem);
+        spin_lock_irqsave(&que->lock, spin_flag);
+        if(que->qlen <= 0)
+        {
+            spin_unlock_irqrestore(&que->lock, spin_flag);
+            continue;
+        }
+        spin_unlock_irqrestore(&que->lock, spin_flag);
+        cursor = 0;
+        memcpy(pkg.contents, B_TAG, TAG_SIZE);
+        cursor += TAG_SIZE; 
+        phead = &que->queue;
+        for(loop = 0; loop < g_ddrnet_wrap_num/*WRAP_FREE_PACKET_THRESHHOLD*/; loop++)
+        {
+            spin_lock_irqsave(&que->lock, spin_flag);
+            
+            if(ddrnet_is_list_empty(phead))
+            {
+                spin_unlock_irqrestore(&que->lock, spin_flag);
+                break;
+            }
+            //plist = get_next(phead);
+            pkt = list_first_entry(phead, struct ddrnet_psbuf_packet, list);
+            plist = &pkt->list;
+            ddrnet_list_delete(plist);
+            
+            que->qlen--;
+            spin_unlock_irqrestore(&que->lock, spin_flag);
+            
+            //pkt = LIST_CONTAINOR(plist, struct ddrnet_skb_packet, list);
+            //phy_addr = (void *)virtaddr_to_phys(pkt->packet);
+            memcpy(pkg.contents + cursor, &pkt->packet, PSB_DATA_PTR_LEN);
+            cursor += PSB_DATA_PTR_LEN;
+
+            spin_lock_irqsave(&que_free->lock, spin_flag);
+            ddrnet_list_insert_tail(plist, &que_free->queue);
+            que_free->qlen++;
+            spin_unlock_irqrestore(&que_free->lock, spin_flag);                        
+        }
+        pkg.pkg_length = loop;
+        memcpy(pkg.contents + cursor, E_TAG, TAG_SIZE);
+        ret = ddrnet_freepsb_pkg_xmit(&pkg);
+        if(ret > 0)
+        {
+            //g_ddrnet_tx_free++;
+            spin_lock_irqsave(&g_psbuf_nr_lock, spin_flag);
+            if(g_ddrnet_psbuf_nr < loop)
+                printk("g_ddrnet_psbuf_nr state err.");
+            g_ddrnet_psbuf_nr = g_ddrnet_psbuf_nr - loop;
+            spin_unlock_irqrestore(&g_psbuf_nr_lock, spin_flag);
+        }
+        //printk("g_ddrnet_tx_free  %d\n", g_ddrnet_tx_free);
+    }        
+    
+    return 0;
+}
+
+s32 ddrnet_skb_packet_enqueue(struct ddrnet* dev, struct T_ToExt_info* buf)
+{
+    struct ddrnet_queue* que = &dev->skb_que;
+    struct ddrnet_queue* que_free = &dev->skb_que_free;
+    struct list_head* phead = &que_free->queue;
+    struct list_head* plist = NULL;
+    u8 timer_flag = 0;
+    struct ddrnet_skb_packet* skb_packet = NULL;
+
+    struct T_ToExt_info* skb_info = buf;
+    u32 spin_flag = 0;
+    spin_lock_irqsave(&que_free->lock, spin_flag);
+    if(que->qlen >= DDRNET_PACKET_QUEUE_COUNT || ddrnet_is_list_empty(&que_free->queue))
+    {
+        spin_unlock_irqrestore(&que_free->lock, spin_flag);
+        return -1;
+    }
+    //plist = get_next(phead);
+    skb_packet = list_first_entry(phead, struct ddrnet_skb_packet, list);
+    plist = &skb_packet->list;
+    ddrnet_list_delete(plist);
+    que_free->qlen--;
+    spin_unlock_irqrestore(&que_free->lock, spin_flag);
+    
+    memcpy(&skb_packet->packet, skb_info, sizeof(*skb_info));
+    //printk("skb enqueue addr %#x:%#x, skb %#x\n", skb_packet->packet.skb_head, skb_packet->packet.skb_data, skb_packet->packet.skb);
+
+    spin_lock_irqsave(&que->lock, spin_flag);    
+    phead = &que->queue;
+    ddrnet_list_insert_tail(plist, phead);
+    que->qlen++;
+    timer_flag = que->qlen%g_ddrnet_wrap_num;/*WRAP_PACKET_THRESHHOLD*/
+    spin_unlock_irqrestore(&que->lock, spin_flag);
+    
+    if((PACKET_SIZE_LIMIT < skb_info->datalen) && !(skb_get_last_pkg(buf->skb)))
+    {
+        if(que->qlen >= g_ddrnet_wrap_num/*WRAP_PACKET_THRESHHOLD*/)
+        {
+            up(&dev->skb_que_sem);
+        }
+        else{
+            if(timer_flag == 1)
+                mod_timer(&dev->wrap_timer, jiffies + msecs_to_jiffies(g_ddrnet_time_interval)/*DDRNET_WRAP_TIMER_OUT_MS*/);
+        }
+    }
+    else
+    {
+        up(&dev->skb_que_sem);
+    }
+
+    return sizeof(struct T_ToExt_info);
+}
+s32 ddrnet_freepsb_packet_enqueue(void *addr)
+{
+    
+    struct list_head* phead = &free_psb_que_free.queue;
+    struct list_head* plist = NULL;
+    struct ddrnet_psbuf_packet* psb_packet = NULL;
+    u32 spin_flag = 0;    
+    u8 timer_flag = 0;
+    spin_lock_irqsave(&free_psb_que_free.lock, spin_flag);
+
+    if(free_psb_que.qlen >= DDRNET_PACKET_QUEUE_COUNT || ddrnet_is_list_empty(phead))
+    {
+        spin_unlock_irqrestore(&free_psb_que_free.lock, spin_flag);
+        return -1;
+    }
+    //plist = get_next(phead);
+    psb_packet = list_first_entry(phead, struct ddrnet_psbuf_packet, list);
+    plist = &psb_packet->list;
+    ddrnet_list_delete(plist);
+    free_psb_que_free.qlen --;    
+    spin_unlock_irqrestore(&free_psb_que_free.lock, spin_flag);
+    
+    spin_lock_irqsave(&free_psb_que.lock, spin_flag);    
+    phead = &free_psb_que.queue;
+    psb_packet->packet = (void *)(*(u32 *)(addr));
+    ddrnet_list_insert_tail(plist, phead);    
+    free_psb_que.qlen++;
+    spin_unlock_irqrestore(&free_psb_que.lock, spin_flag);
+
+    
+    if(free_psb_que.qlen >= g_ddrnet_wrap_num/*WRAP_FREE_PACKET_THRESHHOLD*/)
+    {
+        up(&freepsb_que_sem);
+    }
+    else
+    {
+        timer_flag = free_psb_que.qlen%g_ddrnet_wrap_num;/*WRAP_FREE_PACKET_THRESHHOLD*/
+        if(timer_flag == 1)
+            mod_timer(&freepsb_wrap_timer, jiffies + msecs_to_jiffies(g_ddrnet_time_interval) /*WRAP_FREE_PACKET_THRESHHOLD*/);
+    }
+
+     return PSB_DATA_PTR_LEN;
+}
+#endif
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/ddr/ddrnet_queue.h b/ap/os/linux/linux-3.4.x/drivers/net/ddr/ddrnet_queue.h
new file mode 100644
index 0000000..d4bc427
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/ddr/ddrnet_queue.h
@@ -0,0 +1,93 @@
+#ifndef _DDRNET_QUEUE_H_
+#define _DDRNET_QUEUE_H_
+#ifdef USE_DDRNET_PACKET
+#include <linux/spinlock.h>
+#include <linux/semaphore.h>
+
+//typedef struct list_head _list;
+//typedef struct spinlock _lock;
+typedef __kernel_size_t		SIZE_T;
+
+
+#define DDRNET_SKB_PACKET_SIZE  sizeof(struct ddrnet_skb_packet)
+#define DDRNET_PSB_PACKET_SIZE  sizeof(struct ddrnet_psbuf_packet)
+
+
+struct ddrnet_queue {
+    struct list_head queue;
+    int qlen;
+    struct spinlock lock;
+};
+
+struct ddrnet_skb_packet {
+	struct list_head list;
+      struct  T_ToExt_info packet;
+};
+
+struct ddrnet_psbuf_packet {
+	struct list_head list;
+      void* packet;
+};
+
+__inline static void ddrnet_init_listhead(struct list_head *list)
+{
+        INIT_LIST_HEAD(list);
+}
+
+__inline static void ddrnet_init_queue(struct ddrnet_queue *pqueue)
+{
+	INIT_LIST_HEAD(&(pqueue->queue));
+	spin_lock_init(&(pqueue->lock));
+	pqueue->qlen = 0;
+}
+
+__inline static void ddrnet_list_insert_head(struct list_head *plist, struct list_head *phead)
+{
+	list_add(plist, phead);
+}
+
+__inline static void ddrnet_list_insert_tail(struct list_head *plist, struct list_head *phead)
+{
+	list_add_tail(plist, phead);
+}
+ __inline static void ddrnet_list_del(struct list_head * prev, struct list_head * next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+ __inline static void ddrnet_list_del_entry(struct list_head *entry)
+ {
+     ddrnet_list_del(entry->prev, entry->next);
+ }
+
+__inline static void ddrnet_list_delete(struct list_head *plist)
+{
+	//list_del_init(plist);
+	list_del(plist);
+}
+
+
+
+__inline static struct list_head *get_next(struct list_head *list)
+{
+	return list->next;
+}
+
+__inline static u32	ddrnet_is_list_empty(struct list_head *phead)
+{
+	return (list_empty(phead) ? TRUE: FALSE);
+}
+
+__inline static void ddrnet_spinlock(struct spinlock *plock, u32 flag)
+{
+	spin_lock_irqsave(plock, flag);
+	//spin_lock(plock);
+}
+
+__inline static void ddrnet_spinunlock(struct spinlock *plock, u32 flag)
+{
+	spin_unlock_irqrestore(plock, flag);
+	//spin_unlock(plock);
+}
+#endif
+#endif  /*  _DDRNET_QUEUE_H_  */