以太网 rx tx delay动态补丁测试

参考源码:x3399_nougat_industry 内核版本4.4 

diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
old mode 100644
new mode 100755
index 44a3c2d..530c248
--- a/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -1062,6 +1062,13 @@ static void rv1108_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
 	}
 }
 
+void SET_RGMII(struct stmmac_priv *priv, int tx_delay, int rx_delay)
+{
+	struct rk_priv_data *bsp_priv = priv->plat->bsp_priv;
+
+	bsp_priv->ops->set_to_rgmii(bsp_priv, tx_delay, rx_delay);
+	return;
+}
 static const struct rk_gmac_ops rv1108_ops = {
 	.set_to_rmii = rv1108_set_to_rmii,
 	.set_rmii_speed = rv1108_set_rmii_speed,
diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
old mode 100644
new mode 100755
index a534672..8cd33a6
--- a/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -124,6 +124,27 @@ static void stmmac_exit_fs(struct net_device *dev);
 
 #define STMMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x))
 
+enum loopback_type {
+	LOOPBACK_TYPE_GMAC,
+	LOOPBACK_TYPE_PHY,
+	LOOPBACK_TYPE_RJ45
+};
+
+enum loopback_speed {
+	LOOPBACK_SPEED_10	= 10,
+	LOOPBACK_SPEED_100	= 100,
+	LOOPBACK_SPEED_1000	= 1000
+};
+
+struct stmmac_loopback {
+	bool enabled;
+	enum loopback_speed	speed;
+	enum loopback_type	type;
+	struct sk_buff * rx_skb;
+	struct sk_buff * tx_skb;
+};
+
+static struct stmmac_loopback g_loopback;
 /**
  * stmmac_verify_args - verify the driver parameters.
  * Description: it checks the driver parameters and set a default in case of
@@ -701,6 +722,8 @@ static void stmmac_adjust_link(struct net_device *dev)
 	int new_state = 0;
 	unsigned int fc = priv->flow_ctrl, pause_time = priv->pause;
 
+	if (g_loopback.enabled) return;
+
 	if (phydev == NULL)
 		return;
 
@@ -805,6 +828,107 @@ static void stmmac_check_pcs_mode(struct stmmac_priv *priv)
 	}
 }
 
+int run_loopback(struct stmmac_priv *priv, int delay_test, enum loopback_type type);
+
+static ssize_t show_phy_loopback(struct device *dev,
+					struct device_attribute *attr, char *buf) {
+	int ret;
+	struct stmmac_priv * priv = dev_get_drvdata(dev);
+
+	ret = run_loopback(priv, 0, LOOPBACK_TYPE_PHY);
+
+	if (!ret)
+		ret = snprintf(buf, PAGE_SIZE, "PHY loopback: PASS\n");
+	else
+		ret = snprintf(buf, PAGE_SIZE, "PHY loopback: FAIL\n");
+
+	return ret;
+}
+
+static ssize_t show_rj45_loopback(struct device *dev,
+					struct device_attribute *attr, char *buf) {
+	int ret;
+	struct stmmac_priv * priv = dev_get_drvdata(dev);
+
+	ret = run_loopback(priv, 0, LOOPBACK_TYPE_RJ45);
+
+	if (!ret)
+		ret = snprintf(buf, PAGE_SIZE, "RJ45 loopback: PASS\n");
+	else
+		ret = snprintf(buf, PAGE_SIZE, "RJ45 loopback: FAIL\n");
+
+	return ret;
+}
+
+static ssize_t show_loopback_speed(struct device *dev,
+					struct device_attribute *attr,
+					char *buf) {
+	int ret;
+
+
+	ret = snprintf(buf, PAGE_SIZE, "%d\n", g_loopback.speed);
+	return ret;
+}
+
+static ssize_t set_loopback_speed(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count) {
+	int speed;
+	int ret;
+
+	ret = kstrtoint(buf, 0, &speed);
+
+	g_loopback.speed = speed;
+	return count;
+}
+
+static ssize_t show_delay_test(struct device *dev,
+					struct device_attribute *attr, char *buf) {
+	int ret;
+	struct stmmac_priv * priv = dev_get_drvdata(dev);
+
+	run_loopback(priv, 1, LOOPBACK_TYPE_PHY);
+
+	ret = snprintf(buf, PAGE_SIZE, "done\n");
+
+	return ret;
+}
+
+static struct device_attribute phy_reg_attrs[] = {
+	__ATTR(loopback_speed, S_IRUGO | S_IWUSR, show_loopback_speed, set_loopback_speed),
+	__ATTR(phy_loopback, S_IRUGO, show_phy_loopback, NULL),
+	__ATTR(rj45_loopback, S_IRUGO, show_rj45_loopback, NULL),
+	__ATTR(delay_test, S_IRUGO, show_delay_test, NULL)
+};
+
+int gmac_create_sysfs(struct phy_device * phy_dev, struct stmmac_priv *priv) {
+	int r;
+	int t;
+
+	dev_set_drvdata(&phy_dev->dev, priv);
+	for (t = 0; t < ARRAY_SIZE(phy_reg_attrs); t++) {
+		r = device_create_file(&phy_dev->dev,&phy_reg_attrs[t]);
+		if (r) {
+			dev_err(&phy_dev->dev, "failed to create sysfs file\n");
+			return r;
+		}
+	}
+
+	return 0;
+}
+
+int gmac_remove_sysfs(struct phy_device * phy_dev) {
+	int t;
+
+	for (t = 0; t < ARRAY_SIZE(phy_reg_attrs); t++) {
+		device_remove_file(&phy_dev->dev,&phy_reg_attrs[t]);
+	}
+
+	return 0;
+}
+
+static int created_sysfs = 0;
+
 /**
  * stmmac_init_phy - PHY initialization
  * @dev: net device structure
@@ -876,6 +1000,11 @@ static int stmmac_init_phy(struct net_device *dev)
 
 	priv->phydev = phydev;
 
+	if (!created_sysfs) {
+		created_sysfs = 1;
+		gmac_create_sysfs(phydev, priv);
+	}
+
 	return 0;
 }
 
@@ -1797,6 +1926,9 @@ static int stmmac_open(struct net_device *dev)
 	struct stmmac_priv *priv = netdev_priv(dev);
 	int ret;
 
+	g_loopback.enabled = false;
+	g_loopback.speed = 100;
+
 	stmmac_check_ether_addr(priv);
 
 	if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI &&
@@ -2283,6 +2415,11 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
 				pr_debug("frame received (%dbytes)", frame_len);
 				print_pkt(skb->data, frame_len);
 			}
+			
+			if (g_loopback.enabled) {
+				memcpy(g_loopback.rx_skb->data, skb->data, frame_len);
+				g_loopback.rx_skb->len = frame_len;
+			}
 
 			stmmac_rx_vlan(priv->dev, skb);
 
@@ -2293,7 +2430,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
 			else
 				skb->ip_summed = CHECKSUM_UNNECESSARY;
 
-			napi_gro_receive(&priv->napi, skb);
+			if (!g_loopback.enabled)
+				napi_gro_receive(&priv->napi, skb);
 
 			priv->dev->stats.rx_packets++;
 			priv->dev->stats.rx_bytes += frame_len;
@@ -3225,6 +3363,245 @@ static void __exit stmmac_exit(void)
 #endif
 }
 
+void create_loopback_frames(struct sk_buff *skb,
+			    unsigned int frame_size)
+{
+	memset(skb->data, 0xFF, frame_size);
+	frame_size &= ~1;
+	memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1);
+	memset(&skb->data[frame_size / 2 + 10], 0xBE, 1);
+	memset(&skb->data[frame_size / 2 + 12], 0xAF, 1);
+}
+
+int check_loopback_frames(struct sk_buff *skb,
+			  unsigned int frame_size)
+{
+	frame_size &= ~1;
+	if (*(skb->data + 3) == 0xFF)
+		if ((*(skb->data + frame_size / 2 + 10) == 0xBE) &&
+			(*(skb->data + frame_size / 2 + 12) == 0xAF))
+			return 0;
+	return 13;
+}
+
+void enable_loopback(struct stmmac_priv * priv,
+			 enum loopback_type type,
+			 enum loopback_speed speed)
+{
+	u32 ctrl;
+
+	g_loopback.enabled = true;
+
+	ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
+	ctrl |= priv->hw->link.duplex;
+
+	if (speed == LOOPBACK_SPEED_1000)
+		ctrl &= ~priv->hw->link.port;
+	else
+		ctrl |= priv->hw->link.port;
+
+	writel(ctrl, priv->ioaddr + MAC_CTRL_REG);
+
+	if ((type == LOOPBACK_TYPE_PHY) || (type == LOOPBACK_TYPE_RJ45)) {
+		int val;
+		val = phy_read(priv->phydev, MII_BMCR);
+		//printk("MII_BMCR--1: 0x%x\n", val);
+
+		val &= ~(BMCR_ANENABLE);
+		if (type == LOOPBACK_TYPE_PHY)
+			val |= BMCR_LOOPBACK;
+		else
+			val &= (~BMCR_LOOPBACK);
+
+		if (speed == 1000) {
+			val |= BMCR_SPEED1000;
+		}
+		else if (speed == 100) {
+			val &= ~BMCR_SPEED1000;
+			val |= BMCR_SPEED100;
+		}
+		else if (speed == 10) {
+			val &= ~BMCR_SPEED1000;
+			val &= ~BMCR_SPEED100;
+		}
+
+		val |= BMCR_FULLDPLX;
+
+		phy_write(priv->phydev, MII_BMCR, val);
+
+		val = phy_read(priv->phydev, MII_BMCR);
+		//printk("MII_BMCR--2: 0x%x\n", val);
+	}
+
+	if (likely(priv->plat->fix_mac_speed))
+		priv->plat->fix_mac_speed(priv->plat->bsp_priv, speed);
+}
+
+void disable_phy_loopback(struct stmmac_priv *priv)
+{	
+	int val;
+	val = phy_read(priv->phydev, MII_BMCR);
+	val |= BMCR_ANENABLE;
+	val &= (~BMCR_LOOPBACK);
+	phy_write(priv->phydev, MII_BMCR, val);
+
+	val = phy_read(priv->phydev, MII_BMCR);
+	//printk("MII_BMCR--3: 0x%x\n", val);
+
+	g_loopback.enabled = false;
+}
+
+int loopback_txrx(struct stmmac_priv * priv, struct stmmac_loopback *lb) 
+{
+	struct sk_buff *tx_skb;
+	struct net_device *ndev = priv->dev;
+	int i;
+	int ret;
+
+        //disable_irq(ndev->irq);
+#if 1
+	netif_device_detach(ndev);
+	netif_stop_queue(ndev);
+	napi_disable(&priv->napi);
+#endif
+	tx_skb = alloc_skb(lb->tx_skb->len, GFP_KERNEL);
+	if (!tx_skb) {
+		printk("%s: tx_skb alloc_skb failed\n", __FUNCTION__);
+	}
+
+	memcpy(tx_skb->data, lb->tx_skb->data, lb->tx_skb->len);
+	//tx_skb->len = lb->tx_skb->len;
+
+	skb_put(tx_skb, lb->tx_skb->len);
+
+	stmmac_tx_clean(priv);
+	stmmac_xmit(tx_skb, priv->dev);
+
+	if (lb->speed == LOOPBACK_SPEED_1000)
+		udelay(20);
+	else if (lb->speed == LOOPBACK_SPEED_100)
+		udelay(200);
+	else
+		udelay(2000);
+
+	stmmac_rx(priv, 64);
+
+	for (i=0; i<lb->tx_skb->len; i++) {
+		if (lb->tx_skb->data[i] != lb->rx_skb->data[i]) {
+			//printk("TX[%d]=0x%x\n", i, lb->tx_skb->data[i]);
+			//printk("RX[%d]=0x%x\n", i, lb->rx_skb->data[i]);
+			break;
+		}
+	}
+
+	if (i < lb->tx_skb->len) {
+		ret = -1;
+	} else {
+		ret = 0;
+	}
+#if 1
+	netif_device_attach(ndev);
+	netif_start_queue(ndev);
+	napi_enable(&priv->napi);
+#endif
+        //enable_irq(ndev->irq);
+
+	//kfree_skb(tx_skb);
+	return ret;
+}
+
+static void find_result(int tx, int rx, int fail) {
+	static int tx_sum = 0;
+	static int rx_sum = 0;    
+	static int count_sum = 0;
+
+	if (!fail) {
+		tx_sum += tx;
+		rx_sum += rx;
+		count_sum ++;
+	}
+	
+	if (tx == 0x7F && rx == 0x7F) {
+		int tx_delay, rx_delay;
+		
+		tx_delay = tx_sum / count_sum;
+		rx_delay = rx_sum / count_sum;
+		printk("\n\nfind tx_delay = 0x%02x, rx_delay = 0x%02x\n\n\n",
+					tx_delay, rx_delay);
+		tx_sum = 0;
+		rx_sum = 0;
+		count_sum = 0;
+	}
+}
+
+extern void SET_RGMII(struct stmmac_priv *priv, int tx_delay, int rx_delay);
+int run_loopback(struct stmmac_priv *priv, int delay_test, enum loopback_type type)
+{
+	int ret = 0;
+	int skb_size = 1024;
+
+	printk("%s: %d Mbps loopback from PHY\n", __FUNCTION__, g_loopback.speed);
+
+	g_loopback.type = type;
+	if (g_loopback.speed == 0)
+		g_loopback.speed = 100;
+
+	enable_loopback(priv, type, g_loopback.speed);
+
+	g_loopback.rx_skb = alloc_skb(skb_size, GFP_KERNEL);
+	if (!g_loopback.rx_skb) {
+		printk("%s: g_loopback.rx_skb alloc_skb failed\n", __FUNCTION__);
+	}
+
+	g_loopback.tx_skb = alloc_skb(skb_size, GFP_KERNEL);
+	if (!g_loopback.tx_skb) {
+		printk("%s: g_loopback.x_skb alloc_skb failed\n", __FUNCTION__);
+	}
+
+	create_loopback_frames(g_loopback.tx_skb, skb_size);
+	skb_put(g_loopback.tx_skb, skb_size);
+
+	msleep(100);
+
+	if (delay_test) {
+		int tx_delay = 0;
+		int rx_delay = 0;
+
+		for (tx_delay = 0x0; tx_delay <= 0x7F; tx_delay++ ) {
+			printk("TX(0x%x): ", tx_delay);
+			for (rx_delay = 0x0; rx_delay <= 0x7F; rx_delay++ ) {
+				memset(g_loopback.rx_skb->data, 0, skb_size);
+				g_loopback.rx_skb->len = 0;
+#if 1
+				SET_RGMII(priv, tx_delay, rx_delay);
+#else
+				ctrl = (0xffff << 16) | (rx_delay << 7) | tx_delay;
+				regmap_write(bsp_priv->grf, 0x0900, ctrl);
+#endif
+				ret = loopback_txrx(priv, &g_loopback);
+				if (!ret) printk("O");
+				else printk(" ");
+				find_result(tx_delay, rx_delay, ret);
+				udelay(20);
+			}
+			printk("\n");
+		}
+		ret = 0;
+	} else {
+		memset(g_loopback.rx_skb->data, 0, skb_size);
+		g_loopback.rx_skb->len = 0;
+
+		ret = loopback_txrx(priv, &g_loopback);
+	}
+
+	kfree(g_loopback.rx_skb);
+	kfree(g_loopback.tx_skb);
+
+	g_loopback.enabled = false;
+	return ret;
+}
+
+
 module_init(stmmac_init)
 module_exit(stmmac_exit)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小猿东哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值