/*
 * fec.c
 *
 *  Created on: 2019-8-30
 *      Author: sunxi
 */

//sunxi 20220411: 暂时屏蔽
//#ifndef __LIGHT_DIFF_ACT_PRO__
//#define __LIGHT_DIFF_ACT_PRO__
//#endif


#ifndef __SAVE_TO_BUFF_FOR_READ__
#define __SAVE_TO_BUFF_FOR_READ__
#endif



#ifdef __LIGHT_DIFF_ACT_PRO__ // sunxi 20190904 光差保护

#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <asm/cacheflush.h>

#include <my_include/fec.h>
#include <my_include/fec_ring.h>

#include "rt.h"
#include "bsp.h"

#include "fec.h"

#ifdef __SAVE_TO_BUFF_FOR_READ__ // 由采样中断读取读取临时缓冲区的数据，因为使用了 memcpy 拷贝了两次数据，效率会低一些

#define FEC_LP_TXBUF_CNT	256		// 发送缓冲区数量最大值

static unsigned char fec2_lp_txbuf[FEC_LP_TXBUF_CNT][FEC_LP_BUF_MAX];

#if 0 // sunxi 20191015
unsigned char fec2_lp_rx_head = 0;
unsigned char fec2_lp_rx_tail = 0;
struct fec_lp_rx_buf fec2_lp_rxbuf[FEC_LP_BUF_CNT_MAX];
#else // sunxi 20191015
struct fec_lp_rx_buf fec2_lp_rxbuf;
unsigned int fec2_lp_rx_cnt = 0;
#endif

#endif // __SAVE_TO_BUFF_FOR_READ__

#define POLL_FRAME			0x50	//巡检报文
#define	SAMP_FRAME			0xA0	//采样报文

#define POLL_FRAME_WORD     (12+4*9)    //轮巡帧6个字，12字节
#define SAMP_FRAME_WORD	    32	//采样帧16个字，32字节  

/* Interrupt events/masks.
*/
#define FEC_ENET_HBERR	((uint)0x80000000)	/* Heartbeat error */
#define FEC_ENET_BABR	((uint)0x40000000)	/* Babbling receiver */
#define FEC_ENET_BABT	((uint)0x20000000)	/* Babbling transmitter */
#define FEC_ENET_GRA	((uint)0x10000000)	/* Graceful stop complete */
#define FEC_ENET_TXF	((uint)0x08000000)	/* Full frame transmitted */
#define FEC_ENET_TXB	((uint)0x04000000)	/* A buffer was transmitted */
#define FEC_ENET_RXF	((uint)0x02000000)	/* Full frame received */
#define FEC_ENET_RXB	((uint)0x01000000)	/* A buffer was received */
#define FEC_ENET_MII	((uint)0x00800000)	/* MII interrupt */
#define FEC_ENET_EBERR	((uint)0x00400000)	/* SDMA bus error */
#define FEC_ENET_TS_AVAIL       ((uint)0x00010000)
#define FEC_ENET_TS_TIMER       ((uint)0x00008000)


static struct net_device *g_fec2_netdev = NULL;
struct	sk_buff	g_fec2_skb[FEC_LP_TXBUF_CNT];

#ifdef __FEC2_LDAP_TEST__
#define TEST_BUF_MAX	64
static unsigned char g_test_buf[TEST_BUF_MAX] = {0x00};
static unsigned long g_fec2_us1, g_fec2_us2, g_fec2_us3;
#endif // __FEC2_LDAP_TEST__

static int fec2_lp_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
	struct fec_enet_private *fep;
	volatile fec_t	*fecp;
	volatile cbd_t	*bdp, *bdp_tmp;
	unsigned short	status;

	fep = netdev_priv(dev);
	fecp = (volatile fec_t *)dev->base_addr;

	if (!fep->link) {
		/* Link is down or autonegotiation is in progress. */
		return 1;
	}

	/* Fill in a Tx ring entry */
	bdp = fep->cur_tx;

	status = bdp->cbd_sc;
#ifndef final_version
	if (status & BD_ENET_TX_READY) {
		/* Ooops.  All transmit buffers are full.  Bail out.
		 * This should not happen, since dev->tbusy should be set.
		 */
		// sunxi 20190814 printk(KERN_ERR "%s: tx queue full!.\n", dev->name);

		return 1;
	}
#endif

	/* Clear all of the status flags.
	 */
	status &= ~BD_ENET_TX_STATS;

	/* Set buffer length and buffer pointer.
	*/
	bdp->cbd_bufaddr = __pa(skb->data);
	bdp->cbd_datlen = skb->len;

	/*
	 *	On some FEC implementations data must be aligned on
	 *	4-byte boundaries. Use bounce buffers to copy data
	 *	and get it aligned. Ugh.
	 */
	/*if (bdp->cbd_bufaddr & 0x3) {
		unsigned int index1;
		index1 = bdp - fep->tx_bd_base;
		memcpy(fep->tx_bounce[index1],
		       (void *)skb->data, bdp->cbd_datlen);
		bdp->cbd_bufaddr = __pa(fep->tx_bounce[index1]);
	} */

	dev->stats.tx_bytes += skb->len;

	/* Push the data cache so the CPM does not get stale memory
	 * data.
	 */
	flush_dcache_range((unsigned long)skb->data,
			   (unsigned long)skb->data + skb->len);

	/* Send it on its way.  Tell FEC it's ready, interrupt when done,
	 * it's the last BD of the frame, and to put the CRC on the end.
	 */

	status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
			| BD_ENET_TX_LAST | BD_ENET_TX_TC);
	bdp->cbd_sc = status;

	dev->trans_start = jiffies;

	/* Trigger transmission start */
	fecp->fec_x_des_active = 0;

	/* If this was the last BD in the ring, start at the beginning again.
	*/
	if (status & BD_ENET_TX_WRAP)
		bdp = fep->tx_bd_base;
	else
		bdp++;

	if (bdp == fep->dirty_tx) {
		fep->tx_full = 1;
		// sunxi 20200812 由于缓冲区满了后会调用该函数，导致后面调用 netif_wake_queue函数时导致内核出错，因此进行屏蔽，满了的缓冲区丢弃掉最前面一帧数据 netif_stop_queue(dev);
		// sunxi 20200812 added
		bdp_tmp = bdp;
		bdp_tmp ++;
		fep->dirty_tx = (cbd_t *)bdp_tmp;
	}

	fep->cur_tx = (cbd_t *)bdp;

#ifdef __FEC2_LDAP_TEST__
	g_fec2_us2 = ustimer_get_origin();
#endif // __FEC2_LDAP_TEST__

	return 0;
}

int fec2_lp_start_xmit(unsigned char *data, int len)
{
	struct	sk_buff	*skb;
	static unsigned char skb_index = 0;
	unsigned long flags;

	if((g_fec2_netdev == NULL) || (data == NULL) || (len <= 0) || (len > FEC_LP_BUF_MAX))
		return 0;

	rt_irq_save(flags);

	skb = &g_fec2_skb[skb_index];
	skb->data = fec2_lp_txbuf[skb_index];

	//拷贝用户数据到skb->data
	memcpy(skb->data, data, len);
	//指定长度
	skb->len = len;

	skb_index ++;

	if(fec2_lp_enet_start_xmit(skb, g_fec2_netdev))
		len = 0;

	rt_irq_restore(flags);

	return len;
}

static void fec2_enet_tx(struct net_device *dev)
{
	struct	fec_enet_private *fep;
	volatile cbd_t	*bdp;
	unsigned short status;
	unsigned long flags;

	fep = netdev_priv(dev);
	// sunxi 20191015 spin_lock_irqsave(&fep->hw_lock, flags);
	rt_irq_save(flags);
	bdp = fep->dirty_tx;
#ifdef __FEC2_LDAP_TEST__
	g_fec2_us3 = ustimer_get_origin();
#endif // __FEC2_LDAP_TEST__

	while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
		if (bdp == fep->cur_tx && fep->tx_full == 0)
			break;

		/* Check for errors. */
		if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
				   BD_ENET_TX_RL | BD_ENET_TX_UN |
				   BD_ENET_TX_CSL)) {
			dev->stats.tx_errors++;
			if (status & BD_ENET_TX_HB)  /* No heartbeat */
				dev->stats.tx_heartbeat_errors++;
			if (status & BD_ENET_TX_LC)  /* Late collision */
				dev->stats.tx_window_errors++;
			if (status & BD_ENET_TX_RL)  /* Retrans limit */
				dev->stats.tx_aborted_errors++;
			if (status & BD_ENET_TX_UN)  /* Underrun */
				dev->stats.tx_fifo_errors++;
			if (status & BD_ENET_TX_CSL) /* Carrier lost */
				dev->stats.tx_carrier_errors++;
		} else {
			dev->stats.tx_packets++;
		}

#ifndef final_version
		if (status & BD_ENET_TX_READY)
			printk(KERN_ERR "HEY! "
				"Enet xmit interrupt and TX_READY.\n");
#endif
		/* Deferred means some collisions occurred during transmit,
		 * but we eventually sent the packet OK.
		 */
		if (status & BD_ENET_TX_DEF)
			dev->stats.collisions++;

		/* Update pointer to next buffer descriptor to be transmitted.
		 */
		if (status & BD_ENET_TX_WRAP)
			bdp = fep->tx_bd_base;
		else
			bdp++;

		/* Since we have freed up a buffer, the ring is no longer
		 * full.
		 * sunxi 20200812 前面发送接口判断如果缓冲区满了，进行数据丢弃，因此不会出现以下情况，不会导致调用以下函数导致内核出错
		 */
		if (fep->tx_full) {
			fep->tx_full = 0;
			// sunxi 20200812 if (netif_queue_stopped(dev))
			// sunxi 20200812 	netif_wake_queue(dev);
		}
	}
	fep->dirty_tx = (cbd_t *)bdp;

#ifdef __FEC2_LDAP_TEST__
	rt_printf("us1 = %lu, us2 = %lu, us3 = %lu\n", g_fec2_us1, g_fec2_us2, g_fec2_us3);
	g_fec2_us1 = 0;
	g_fec2_us2 = 0;
	g_fec2_us3 = 0;
#endif // __FEC2_LDAP_TEST__
	// sunxi 20191015 spin_unlock_irqrestore(&fep->hw_lock, flags);
	rt_irq_restore(flags);
}


extern void fec2_lp_frame_handle(unsigned char *data, bool bGoodPacket,int errtype);

static void fec2_enet_rx(struct net_device *dev)
{
	struct	fec_enet_private *fep;
	volatile fec_t	*fecp;
	volatile cbd_t *bdp;
	unsigned short status;
	int errtype=0;
#if 0
	struct	sk_buff	*skb;
#endif
	ushort	pkt_len;
	__u8 *data;
	unsigned long flags;
	int frame_count;

	ushort i, wRecvCnt;
	ushort wCRC=0;
	ushort ucrc;
	u8 *rdptr = 0;
	bool bGoodPacket = false;

	fep = netdev_priv(dev);
	fecp = (volatile fec_t *)dev->base_addr;

	// sunxi 20190920 spin_lock_irqsave(&fep->hw_lock, flags);
	rt_irq_save(flags);

	/* First, grab all of the stats for the incoming packet.
	 * These get messed up if we get called due to a busy condition.
	 */
	bdp = fep->cur_rx;

	frame_count = 0;
	while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {

#if 1 //xbtong 目前流量控制好像不起作用，但在MCF54452上经测试是可以起作用的。
	//流控制，防止广播风暴
		frame_count++;
		if(frame_count > 2)
		{
		//  opd寄存器存放发送给对方的PAUSE时间，以slot time(512 bit times ,5.12us) 为单位
		//	printk("rx(%d):%d\n", fep->index, frame_count);
		//	fecp->fec_r_fifo_section_empty = 0;
		//  fecp->fec_opd = 0xfff0;
			// sunxi 20190731 fecp->fec_opd = 0x400;
			fecp->fec_opd = 0x80;
			fecp->fec_x_cntrl |= 0x0008;
		}
#endif

#ifndef final_version
		/* Since we have allocated space to hold a complete frame,
		 * the last indicator should be set.
		 */
		if ((status & BD_ENET_RX_LAST) == 0){
			printk(KERN_INFO "FEC ENET: rcv is not +last\n");
			//非法数据长度处理
			if(bdp->cbd_datlen > FEC_ENET_RX_FRSIZE )
				goto rx_processing_done;
		}
#endif

		if (!fep->opened)
			goto rx_processing_done;

		/* Check for errors. */
		if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
				   BD_ENET_RX_CR | BD_ENET_RX_OV)) {
			dev->stats.rx_errors++;
			if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
				/* Frame too long or too short. */
				dev->stats.rx_length_errors++;
			}
			if (status & BD_ENET_RX_NO)	/* Frame alignment */
				dev->stats.rx_frame_errors++;
			if (status & BD_ENET_RX_CR)	/* CRC Error */
				dev->stats.rx_crc_errors++;
			if (status & BD_ENET_RX_OV)	/* FIFO overrun */
				dev->stats.rx_fifo_errors++;
		}

		/* Report late collisions as a frame error.
		 * On this error, the BD is closed, but we don't know what we
		 * have in the buffer.  So, just drop this frame on the floor.
		 */
		if (status & BD_ENET_RX_CL) {
			dev->stats.rx_errors++;
			dev->stats.rx_frame_errors++;
			goto rx_processing_done;
		}

		/* Process the incoming frame.
		 */
		dev->stats.rx_packets++;
		pkt_len = bdp->cbd_datlen;
		dev->stats.rx_bytes += pkt_len;
		data = (__u8 *)__va(bdp->cbd_bufaddr);
		data+=12;

		// 以下为光差保护数据接收处理
		/* 1. 光纤保护的数据帧，根据ut的协议帧，不是以太网数据帧格式（6字节目标mac地址，接着6字节源mac地址，再两字节帧类型，然后就是帧数据）
		 * 2. 光纤保护的数据帧：两字节帧类型，0x5000是轮询帧，中间8字节的帧数据，最后加上两字节wCRC，一共10字节，
		 * 3. 0xA000是采样帧，中间26字节的帧数据，最后加上两字节wCRC，一共是28字节。
		 * 4. wCRC 是包括两个字节的帧类型和帧数据的异或
		 */
		rdptr = (u8 *)data;
	    switch( data[0] & 0xF0 )
	    {
	    case POLL_FRAME:  //轮巡帧
	        wRecvCnt = POLL_FRAME_WORD;
	        break;
	    case SAMP_FRAME:  //采样帧
	        wRecvCnt = SAMP_FRAME_WORD;
	        break;
	    default:
	        wRecvCnt = 0;
	        break;
	    }
	    if( wRecvCnt )
	    {
	    	rdptr = (u8 *)data;
	        for( i = 0; i < wRecvCnt-2; i++ )
	        {
			wCRC += *rdptr++;
	        }

	        ucrc=(ushort )rdptr[0]|(rdptr[1]<<8);
	        if( wCRC == ucrc )                //效验成功
	        {
	        	bGoodPacket = true;
	        }
	        else
	        {
			errtype=1;
	        }
	    }
	    else
	    {
	    	memset(data, 0x00, (SAMP_FRAME_WORD ));
	    	wRecvCnt = 0;
	    	errtype=2;
	    }
#ifdef __SAVE_TO_BUFF_FOR_READ__ // 保存在临时缓冲区，由采样中断读取，因为使用了 memcpy 拷贝了两次数据，效率会低一些
		// 把正确的数据保存到缓冲区

#if 0 // sunxi 20191015
		fec2_lp_rx_head=0;  //为保证采样数据的实效性，只处理一帧数据，不做缓存
		
		fec2_lp_rxbuf[fec2_lp_rx_head].bvalid = bGoodPacket;
		fec2_lp_rxbuf[fec2_lp_rx_head].len = wRecvCnt;
		if(wRecvCnt > 0)
			memcpy(fec2_lp_rxbuf[fec2_lp_rx_head].buf, data, wRecvCnt);
		fec2_lp_rx_head ++;
		if(fec2_lp_rx_head == fec2_lp_rx_tail)
			fec2_lp_rx_tail ++;
#else // sunxi 20191015
		fec2_lp_rx_cnt = 0;
		fec2_lp_rxbuf.bvalid = bGoodPacket;
		fec2_lp_rxbuf.len = wRecvCnt;
		if(wRecvCnt > 0)
			memcpy(fec2_lp_rxbuf.buf, data, wRecvCnt);
		fec2_lp_rx_cnt = 1;
#endif // sunxi 20191015
		// 数据直接网口2接收中断里面进行处理，调用app那边的接口，效率比较高
		fec2_lp_frame_handle(data, bGoodPacket,errtype);	 //接收报文处理
#ifdef __FEC2_LDAP_TEST__
		for(i = 0; i < 256; i ++)
			data[i] = i;
		g_fec2_us1 = ustimer_get_origin();
		fec2_lp_start_xmit(g_test_buf, TEST_BUF_MAX);
#endif // __FEC2_LDAP_TEST__

#endif // __SAVE_TO_BUFF_FOR_READ__

rx_processing_done:

		/* Clear the status flags for this buffer.
		*/
		status &= ~BD_ENET_RX_STATS;

		/* Mark the buffer empty.
		*/
		status |= BD_ENET_RX_EMPTY;
		bdp->cbd_sc = status;

		/* Update BD pointer to next entry.
		*/
		if (status & BD_ENET_RX_WRAP)
			bdp = fep->rx_bd_base;
		else
			bdp++;


		/* Doing this here will keep the FEC running while we process
		 * incoming frames.  On a heavily loaded network, we should be
		 * able to keep up at the expense of system resources.
		 */
		fecp->fec_r_des_active = 0;

	} /* while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) */
	fep->cur_rx = (cbd_t *)bdp;

	// sunxi 20190920 spin_unlock_irqrestore(&fep->hw_lock, flags);
	rt_irq_restore(flags);
}

/* The interrupt handler.
 * This is called from the MPC core interrupt.
 */
static void fec2_enet_interrupt(void)
{
	struct	net_device *dev = g_fec2_netdev;
	volatile fec_t	*fecp;
	uint	int_events;
	if(dev == NULL) // sunxi 20200811 added
		return;
	fecp = (volatile fec_t *)dev->base_addr;

	/* Get the interrupt events that caused us to be here.
	*/
	do {
		int_events = fecp->fec_ievent;
		fecp->fec_ievent = int_events; // & (FEC_ENET_GRA | FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_TXB | FEC_ENET_RXB);

		/* Handle receive event in its own function.
		 */
		if (int_events & FEC_ENET_RXF) {
			fec2_enet_rx(dev);
		}

		/* Transmit OK, or non-fatal error. Update the buffer
		   descriptors. FEC handles all errors, we just discover
		   them as part of the transmit process.
		*/
		if (int_events & FEC_ENET_TXF) {
			fec2_enet_tx(dev);
		}

	} while (int_events);
}

// sunxi 20191217 增加以下4个接口，当模块在手动卸载后，不会出现网口看门狗动作出现的网口2重启的内核出错信息，也不会在手动关闭和打开网口2时出现内核出错信息。
static int fec2_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
	return 0;
}
static void fec2_timeout(struct net_device *dev)
{
}
static int fec2_enet_open(struct net_device *dev)
{
	return 0;
}
static int fec2_enet_close(struct net_device *dev)
{
	return 0;
}

extern struct net_device *fec_get_net_device(int idx);
static const int fec_idx = 1; // sunxi 20200722 增加该变量，使用光纤通信可以不止是网口2，也可以是网口1，但是应用那边也需要对应改动。最好在调用fec2_reinit接口时可以把索引号传进来。
int fec2_reinit(void)
{
#ifdef __FEC2_LDAP_TEST__
	int i;
#endif // __FEC2_LDAP_TEST__
	g_fec2_netdev = fec_get_net_device(fec_idx);
	if(g_fec2_netdev == NULL)
	{
		return 0;
	}

#ifdef __FEC2_LDAP_TEST__
	for(i = 0; i < TEST_BUF_MAX; i ++ )
		g_test_buf[i] = i;
#endif // __FEC2_LDAP_TEST__

	if(g_fec2_netdev->stop != fec2_enet_close)
	{
		g_fec2_netdev->stop(g_fec2_netdev);
		g_fec2_netdev->stop = fec2_enet_close;
		// 重新定位新的网口2中断处理函数
		if(fec_idx == 1)
		{
			//free_irq(113, (void *)g_fec2_netdev);
			//free_irq(117, (void *)g_fec2_netdev);
		}
		else if(!fec_idx)
		{
			//free_irq(100, (void *)g_fec2_netdev);
			//free_irq(104, (void *)g_fec2_netdev);
		}
	}

	// 防止网口2的网络数据在其它地方来发送
	if(g_fec2_netdev->hard_start_xmit != fec2_enet_start_xmit)
	{
		g_fec2_netdev->hard_start_xmit = fec2_enet_start_xmit;
		g_fec2_netdev->tx_timeout = fec2_timeout;
	}

	if(fec_idx == 1)
	{
		rt_request_irq(113, 6, fec2_enet_interrupt, "fec2(TXF)");
		rt_request_irq(117, 6, fec2_enet_interrupt, "fec2(RXF)");
	}
	else if(!fec_idx)
	{
		rt_request_irq(100, 6, fec2_enet_interrupt, "fec1(TXF)");
		rt_request_irq(104, 6, fec2_enet_interrupt, "fec1(RXF)");
	}

	if(g_fec2_netdev->open != fec2_enet_open)
	{
		g_fec2_netdev->open(g_fec2_netdev);
		g_fec2_netdev->open = fec2_enet_open;
	}

	return 0;
}

int fec2_exit(void)
{
	if(g_fec2_netdev == NULL)
	{
		return 0;
	}

	msleep(10); // 让有足够时间把数据都发送出去了再释放实时中断，不然会触发数据发送的看门狗动作。
	if(fec_idx == 1)
	{
		rt_free_irq(117);
		rt_free_irq(113);
	}
	else if(!fec_idx)
	{
		rt_free_irq(104);
		rt_free_irq(100);
	}

	return 0;
}

#endif // __LIGHT_DIFF_ACT_PRO__

