[PATCH RFC net-next 2/2] net: hibmcge: add support for selftest

Jijie Shao posted 2 patches 9 months, 3 weeks ago
[PATCH RFC net-next 2/2] net: hibmcge: add support for selftest
Posted by Jijie Shao 9 months, 3 weeks ago
This patch implements selftest, including MAC and SerDes selftest,
which is the driver's own test. The .enable() is implemented by the driver.

In addition, the driver sets extra_flags to
test the carrier status, full duplex, and PHY.

For example:
ethtool -t enp132s0f1
The test result is PASS
The test extra info:
 1. MAC internal loopback      	 0
 2. Serdes internal loopback   	 0
 3. Carrier                    	 0
 4. Full Duplex                	 0
 5. PHY internal loopback      	 0

Signed-off-by: Jijie Shao <shaojijie@huawei.com>
---
 .../ethernet/hisilicon/hibmcge/hbg_common.h   |  2 +
 .../ethernet/hisilicon/hibmcge/hbg_ethtool.c  | 60 ++++++++++++++++---
 .../net/ethernet/hisilicon/hibmcge/hbg_hw.c   |  6 ++
 .../net/ethernet/hisilicon/hibmcge/hbg_hw.h   |  1 +
 .../net/ethernet/hisilicon/hibmcge/hbg_reg.h  |  1 +
 .../net/ethernet/hisilicon/hibmcge/hbg_txrx.c |  3 +-
 6 files changed, 65 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h
index 7725cb0c5c8a..876933f88329 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h
@@ -84,6 +84,8 @@ enum hbg_hw_event_type {
 	HBG_HW_EVENT_INIT, /* driver is loading */
 	HBG_HW_EVENT_RESET,
 	HBG_HW_EVENT_CORE_RESET,
+	HBG_HW_EVENT_SERDES_LOOP_ENABLE,
+	HBG_HW_EVENT_SERDES_LOOP_DISABLE = 5,
 };
 
 struct hbg_dev_specs {
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_ethtool.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_ethtool.c
index 8f1107b85fbb..cc60bd76890d 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_ethtool.c
@@ -4,6 +4,7 @@
 #include <linux/ethtool.h>
 #include <linux/phy.h>
 #include <linux/rtnetlink.h>
+#include <net/selftests.h>
 #include "hbg_common.h"
 #include "hbg_err.h"
 #include "hbg_ethtool.h"
@@ -339,12 +340,55 @@ void hbg_update_stats(struct hbg_priv *priv)
 				 ARRAY_SIZE(hbg_ethtool_ctrl_stats_info));
 }
 
+static int hbg_test_mac_loopback_enable(struct net_device *ndev,
+					bool enable)
+{
+	struct hbg_priv *priv = netdev_priv(ndev);
+
+	hbg_hw_loop_enable(priv, enable);
+	return 0;
+}
+
+static int hbg_test_serdes_loopback_enable(struct net_device *ndev,
+					   bool enable)
+{
+	struct hbg_priv *priv = netdev_priv(ndev);
+	u32 event = enable ? HBG_HW_EVENT_SERDES_LOOP_ENABLE :
+			     HBG_HW_EVENT_SERDES_LOOP_DISABLE;
+
+	return hbg_hw_event_notify(priv, event);
+}
+
+static const struct net_test hbg_test = {
+	.extra_flags = NET_EXTRA_CARRIER_TEST |
+		       NET_EXTRA_FULL_DUPLEX_TEST |
+		       NET_EXTRA_PHY_TEST,
+	.entries = {
+		NET_TEST_E("MAC internal loopback",
+			   hbg_test_mac_loopback_enable,
+			   NET_TEST_UDP_MAX_MTU | NET_TEST_TCP),
+		NET_TEST_E("Serdes internal loopback",
+			   hbg_test_serdes_loopback_enable,
+			   NET_TEST_UDP_MAX_MTU | NET_TEST_TCP),
+	},
+	.count = 2,
+};
+
+static void hbg_ethtool_self_test(struct net_device *netdev,
+				  struct ethtool_test *etest,
+				  u64 *buf)
+{
+	net_selftest_custom(netdev, &hbg_test, etest, buf);
+}
+
 static int hbg_ethtool_get_sset_count(struct net_device *netdev, int stringset)
 {
-	if (stringset != ETH_SS_STATS)
-		return -EOPNOTSUPP;
+	if (stringset == ETH_SS_STATS)
+		return ARRAY_SIZE(hbg_ethtool_stats_info);
+	else if (stringset == ETH_SS_TEST)
+		return net_selftest_get_count_custom(&hbg_test);
 
-	return ARRAY_SIZE(hbg_ethtool_stats_info);
+	return -EOPNOTSUPP;
 }
 
 static void hbg_ethtool_get_strings(struct net_device *netdev,
@@ -352,11 +396,12 @@ static void hbg_ethtool_get_strings(struct net_device *netdev,
 {
 	u32 i;
 
-	if (stringset != ETH_SS_STATS)
-		return;
+	if (stringset == ETH_SS_STATS)
+		for (i = 0; i < ARRAY_SIZE(hbg_ethtool_stats_info); i++)
+			ethtool_puts(&data, hbg_ethtool_stats_info[i].name);
+	else if (stringset == ETH_SS_TEST)
+		net_selftest_get_strings_custom(&hbg_test, data);
 
-	for (i = 0; i < ARRAY_SIZE(hbg_ethtool_stats_info); i++)
-		ethtool_puts(&data, hbg_ethtool_stats_info[i].name);
 }
 
 static void hbg_ethtool_get_stats(struct net_device *netdev,
@@ -488,6 +533,7 @@ static const struct ethtool_ops hbg_ethtool_ops = {
 	.get_eth_mac_stats	= hbg_ethtool_get_eth_mac_stats,
 	.get_eth_ctrl_stats	= hbg_ethtool_get_eth_ctrl_stats,
 	.get_rmon_stats		= hbg_ethtool_get_rmon_stats,
+	.self_test		= hbg_ethtool_self_test,
 };
 
 void hbg_ethtool_set_ops(struct net_device *netdev)
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c
index 9b65eef62b3f..ad3fc572bc13 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c
@@ -264,6 +264,12 @@ void hbg_hw_set_rx_pause_mac_addr(struct hbg_priv *priv, u64 mac_addr)
 	hbg_reg_write64(priv, HBG_REG_FD_FC_ADDR_LOW_ADDR, mac_addr);
 }
 
+void hbg_hw_loop_enable(struct hbg_priv *priv, u32 enable)
+{
+	hbg_reg_write_field(priv, HBG_REG_LOOP_REG_ADDR,
+			    HBG_REG_CF_CG2MI_LP_EN_B, enable);
+}
+
 static void hbg_hw_init_transmit_ctrl(struct hbg_priv *priv)
 {
 	u32 ctrl = 0;
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h
index a4a049b5121d..f7917a5353c2 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h
@@ -59,5 +59,6 @@ void hbg_hw_set_mac_filter_enable(struct hbg_priv *priv, u32 enable);
 void hbg_hw_set_pause_enable(struct hbg_priv *priv, u32 tx_en, u32 rx_en);
 void hbg_hw_get_pause_enable(struct hbg_priv *priv, u32 *tx_en, u32 *rx_en);
 void hbg_hw_set_rx_pause_mac_addr(struct hbg_priv *priv, u64 mac_addr);
+void hbg_hw_loop_enable(struct hbg_priv *priv, u32 enable);
 
 #endif
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h
index a6e7f5e62b48..85b46f35b876 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h
@@ -117,6 +117,7 @@
 #define HBG_REG_MODE_CHANGE_EN_ADDR		(HBG_REG_SGMII_BASE + 0x01B4)
 #define HBG_REG_MODE_CHANGE_EN_B		BIT(0)
 #define HBG_REG_LOOP_REG_ADDR			(HBG_REG_SGMII_BASE + 0x01DC)
+#define HBG_REG_CF_CG2MI_LP_EN_B		BIT(2)
 #define HBG_REG_RECV_CTRL_ADDR			(HBG_REG_SGMII_BASE + 0x01E0)
 #define HBG_REG_RECV_CTRL_STRIP_PAD_EN_B	BIT(3)
 #define HBG_REG_VLAN_CODE_ADDR			(HBG_REG_SGMII_BASE + 0x01E8)
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.c
index 8d814c8f19ea..5802748f3a13 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.c
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.c
@@ -258,7 +258,8 @@ static bool hbg_rx_check_l3l4_error(struct hbg_priv *priv,
 		break;
 	case HBG_L4_ZERO_PORT_NUM:
 		priv->stats.rx_desc_l4_zero_port_num_cnt++;
-		return false;
+		/* Don't drop packets whose L4 port number is 0. */
+		break;
 	default:
 		priv->stats.rx_desc_l4_other_cnt++;
 		return false;
-- 
2.33.0