[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, ¶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");
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, ¶m);
+
+ 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, ¶m);
+
+ 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_ */