350 lines
12 KiB
Diff
350 lines
12 KiB
Diff
From 59d968eb403e67c339cdfdc1ad156aff70ceda31 Mon Sep 17 00:00:00 2001
|
|
From: Yonglong Liu <liuyonglong@huawei.com>
|
|
Date: Tue, 11 Oct 2022 23:14:19 +0800
|
|
Subject: [PATCH 182/283] net: hns3: add support for external loopback test
|
|
|
|
mainline inclusion
|
|
from mainline-v6.0-rc4
|
|
commit 04b6ba143521f4485b7f2c36c655b262a79dae97
|
|
category: feature
|
|
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I8EN3D
|
|
CVE: NA
|
|
|
|
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=04b6ba143521
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
This patch add support for external loopback test.
|
|
The successful test need the link is up with duplex full. The
|
|
driver do external loopback first, and then the whole offline
|
|
test.
|
|
|
|
Signed-off-by: Yonglong Liu <liuyonglong@huawei.com>
|
|
Signed-off-by: Guangbin Huang <huangguangbin2@huawei.com>
|
|
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
|
Signed-off-by: Jiantao Xiao <xiaojiantao1@h-partners.com>
|
|
Reviewed-by: Jian Shen <shenjian15@huawei.com>
|
|
Reviewed-by: YueHaibing <yuehaibing@huawei.com>
|
|
Signed-off-by: Zheng Zengkai <zhengzengkai@huawei.com>
|
|
Signed-off-by: Xiaodong Li <lixiaodong67@huawei.com>
|
|
|
|
Conflicts:
|
|
drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
|
|
---
|
|
drivers/net/ethernet/hisilicon/hns3/hnae3.h | 2 +
|
|
.../net/ethernet/hisilicon/hns3/hns3_enet.c | 51 +++++++++++++++
|
|
.../net/ethernet/hisilicon/hns3/hns3_enet.h | 3 +
|
|
.../ethernet/hisilicon/hns3/hns3_ethtool.c | 63 ++++++++++++++-----
|
|
.../hisilicon/hns3/hns3pf/hclge_main.c | 26 +++++---
|
|
5 files changed, 121 insertions(+), 24 deletions(-)
|
|
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
|
|
index 4d35bce95147..2963f3d816fd 100644
|
|
--- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
|
|
@@ -183,6 +183,7 @@ struct hns3_mac_stats {
|
|
|
|
/* hnae3 loop mode */
|
|
enum hnae3_loop {
|
|
+ HNAE3_LOOP_EXTERNAL,
|
|
HNAE3_LOOP_APP,
|
|
HNAE3_LOOP_SERIAL_SERDES,
|
|
HNAE3_LOOP_PARALLEL_SERDES,
|
|
@@ -865,6 +866,7 @@ struct hnae3_unic_private_info {
|
|
#define HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK BIT(2)
|
|
#define HNAE3_SUPPORT_VF BIT(3)
|
|
#define HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK BIT(4)
|
|
+#define HNAE3_SUPPORT_EXTERNAL_LOOPBACK BIT(5)
|
|
|
|
#define HNAE3_USER_UPE BIT(0) /* unicast promisc enabled by user */
|
|
#define HNAE3_USER_MPE BIT(1) /* mulitcast promisc enabled by user */
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
|
|
index 43b38e267e5b..66fd6c870cc3 100644
|
|
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
|
|
@@ -5346,6 +5346,57 @@ int hns3_set_channels(struct net_device *netdev,
|
|
return 0;
|
|
}
|
|
|
|
+void hns3_external_lb_prepare(struct net_device *ndev, bool if_running)
|
|
+{
|
|
+ struct hns3_nic_priv *priv = netdev_priv(ndev);
|
|
+ struct hnae3_handle *h = priv->ae_handle;
|
|
+ int i;
|
|
+
|
|
+ if (!if_running)
|
|
+ return;
|
|
+
|
|
+ netif_carrier_off(ndev);
|
|
+ netif_tx_disable(ndev);
|
|
+
|
|
+ for (i = 0; i < priv->vector_num; i++)
|
|
+ hns3_vector_disable(&priv->tqp_vector[i]);
|
|
+
|
|
+ for (i = 0; i < h->kinfo.num_tqps; i++)
|
|
+ hns3_tqp_disable(h->kinfo.tqp[i]);
|
|
+
|
|
+ /* delay ring buffer clearing to hns3_reset_notify_uninit_enet
|
|
+ * during reset process, because driver may not be able
|
|
+ * to disable the ring through firmware when downing the netdev.
|
|
+ */
|
|
+ if (!hns3_nic_resetting(ndev))
|
|
+ hns3_nic_reset_all_ring(priv->ae_handle);
|
|
+
|
|
+ hns3_reset_tx_queue(priv->ae_handle);
|
|
+}
|
|
+
|
|
+void hns3_external_lb_restore(struct net_device *ndev, bool if_running)
|
|
+{
|
|
+ struct hns3_nic_priv *priv = netdev_priv(ndev);
|
|
+ struct hnae3_handle *h = priv->ae_handle;
|
|
+ int i;
|
|
+
|
|
+ if (!if_running)
|
|
+ return;
|
|
+
|
|
+ hns3_nic_reset_all_ring(priv->ae_handle);
|
|
+
|
|
+ for (i = 0; i < priv->vector_num; i++)
|
|
+ hns3_vector_enable(&priv->tqp_vector[i]);
|
|
+
|
|
+ for (i = 0; i < h->kinfo.num_tqps; i++)
|
|
+ hns3_tqp_enable(h->kinfo.tqp[i]);
|
|
+
|
|
+ netif_tx_wake_all_queues(ndev);
|
|
+
|
|
+ if (h->ae_algo->ops->get_status(h))
|
|
+ netif_carrier_on(ndev);
|
|
+}
|
|
+
|
|
static const struct hns3_hw_error_info hns3_hw_err[] = {
|
|
{ .type = HNAE3_PPU_POISON_ERROR,
|
|
.msg = "PPU poison" },
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
|
|
index 2377e69818a5..f2d5adb54cdc 100644
|
|
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h
|
|
@@ -714,4 +714,7 @@ void hns3_dbg_register_debugfs(const char *debugfs_dir_name);
|
|
void hns3_dbg_unregister_debugfs(void);
|
|
void hns3_shinfo_pack(struct skb_shared_info *shinfo, __u32 *size);
|
|
u16 hns3_get_max_available_channels(struct hnae3_handle *h);
|
|
+
|
|
+void hns3_external_lb_prepare(struct net_device *ndev, bool if_running);
|
|
+void hns3_external_lb_restore(struct net_device *ndev, bool if_running);
|
|
#endif
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
|
|
index c9a24d010260..568cc9e57c9c 100644
|
|
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
|
|
@@ -72,7 +72,6 @@ static const struct hns3_stats hns3_rxq_stats[] = {
|
|
|
|
#define HNS3_TQP_STATS_COUNT (HNS3_TXQ_STATS_COUNT + HNS3_RXQ_STATS_COUNT)
|
|
|
|
-#define HNS3_SELF_TEST_TYPE_NUM 4
|
|
#define HNS3_NIC_LB_TEST_PKT_NUM 1
|
|
#define HNS3_NIC_LB_TEST_RING_ID 0
|
|
#define HNS3_NIC_LB_TEST_PACKET_SIZE 128
|
|
@@ -98,6 +97,7 @@ static int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop, bool en)
|
|
case HNAE3_LOOP_PARALLEL_SERDES:
|
|
case HNAE3_LOOP_APP:
|
|
case HNAE3_LOOP_PHY:
|
|
+ case HNAE3_LOOP_EXTERNAL:
|
|
ret = h->ae_algo->ops->set_loopback(h, loop, en);
|
|
break;
|
|
default:
|
|
@@ -312,6 +312,10 @@ static int hns3_lp_run_test(struct net_device *ndev, enum hnae3_loop mode)
|
|
|
|
static void hns3_set_selftest_param(struct hnae3_handle *h, int (*st_param)[2])
|
|
{
|
|
+ st_param[HNAE3_LOOP_EXTERNAL][0] = HNAE3_LOOP_EXTERNAL;
|
|
+ st_param[HNAE3_LOOP_EXTERNAL][1] =
|
|
+ h->flags & HNAE3_SUPPORT_EXTERNAL_LOOPBACK;
|
|
+
|
|
st_param[HNAE3_LOOP_APP][0] = HNAE3_LOOP_APP;
|
|
st_param[HNAE3_LOOP_APP][1] =
|
|
h->flags & HNAE3_SUPPORT_APP_LOOPBACK;
|
|
@@ -330,17 +334,11 @@ static void hns3_set_selftest_param(struct hnae3_handle *h, int (*st_param)[2])
|
|
h->flags & HNAE3_SUPPORT_PHY_LOOPBACK;
|
|
}
|
|
|
|
-static void hns3_selftest_prepare(struct net_device *ndev,
|
|
- bool if_running, int (*st_param)[2])
|
|
+static void hns3_selftest_prepare(struct net_device *ndev, bool if_running)
|
|
{
|
|
struct hns3_nic_priv *priv = netdev_priv(ndev);
|
|
struct hnae3_handle *h = priv->ae_handle;
|
|
|
|
- if (netif_msg_ifdown(h))
|
|
- netdev_info(ndev, "self test start\n");
|
|
-
|
|
- hns3_set_selftest_param(h, st_param);
|
|
-
|
|
if (if_running)
|
|
ndev->netdev_ops->ndo_stop(ndev);
|
|
|
|
@@ -379,18 +377,15 @@ static void hns3_selftest_restore(struct net_device *ndev, bool if_running)
|
|
|
|
if (if_running)
|
|
ndev->netdev_ops->ndo_open(ndev);
|
|
-
|
|
- if (netif_msg_ifdown(h))
|
|
- netdev_info(ndev, "self test end\n");
|
|
}
|
|
|
|
static void hns3_do_selftest(struct net_device *ndev, int (*st_param)[2],
|
|
struct ethtool_test *eth_test, u64 *data)
|
|
{
|
|
- int test_index = 0;
|
|
+ int test_index = HNAE3_LOOP_APP;
|
|
u32 i;
|
|
|
|
- for (i = 0; i < HNS3_SELF_TEST_TYPE_NUM; i++) {
|
|
+ for (i = HNAE3_LOOP_APP; i < HNAE3_LOOP_NONE; i++) {
|
|
enum hnae3_loop loop_type = (enum hnae3_loop)st_param[i][0];
|
|
|
|
if (!st_param[i][1])
|
|
@@ -409,6 +404,22 @@ static void hns3_do_selftest(struct net_device *ndev, int (*st_param)[2],
|
|
}
|
|
}
|
|
|
|
+static void hns3_do_external_lb(struct net_device *ndev,
|
|
+ struct ethtool_test *eth_test, u64 *data)
|
|
+{
|
|
+ data[HNAE3_LOOP_EXTERNAL] = hns3_lp_up(ndev, HNAE3_LOOP_EXTERNAL);
|
|
+ if (!data[HNAE3_LOOP_EXTERNAL])
|
|
+ data[HNAE3_LOOP_EXTERNAL] = (
|
|
+ hns3_lp_run_test(ndev, HNAE3_LOOP_EXTERNAL)
|
|
+ );
|
|
+ hns3_lp_down(ndev, HNAE3_LOOP_EXTERNAL);
|
|
+
|
|
+ if (data[HNAE3_LOOP_EXTERNAL])
|
|
+ eth_test->flags |= ETH_TEST_FL_FAILED;
|
|
+
|
|
+ eth_test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
|
|
+}
|
|
+
|
|
/**
|
|
* hns3_nic_self_test - self test
|
|
* @ndev: net device
|
|
@@ -418,7 +429,9 @@ static void hns3_do_selftest(struct net_device *ndev, int (*st_param)[2],
|
|
static void hns3_self_test(struct net_device *ndev,
|
|
struct ethtool_test *eth_test, u64 *data)
|
|
{
|
|
- int st_param[HNS3_SELF_TEST_TYPE_NUM][2];
|
|
+ struct hns3_nic_priv *priv = netdev_priv(ndev);
|
|
+ struct hnae3_handle *h = priv->ae_handle;
|
|
+ int st_param[HNAE3_LOOP_NONE][2];
|
|
bool if_running = netif_running(ndev);
|
|
|
|
if (hns3_nic_resetting(ndev)) {
|
|
@@ -426,13 +439,29 @@ static void hns3_self_test(struct net_device *ndev,
|
|
return;
|
|
}
|
|
|
|
- /* Only do offline selftest, or pass by default */
|
|
- if (eth_test->flags != ETH_TEST_FL_OFFLINE)
|
|
+ if (!(eth_test->flags & ETH_TEST_FL_OFFLINE))
|
|
return;
|
|
|
|
- hns3_selftest_prepare(ndev, if_running, st_param);
|
|
+ if (netif_msg_ifdown(h))
|
|
+ netdev_info(ndev, "self test start\n");
|
|
+
|
|
+ hns3_set_selftest_param(h, st_param);
|
|
+
|
|
+ /* external loopback test requires that the link is up and the duplex is
|
|
+ * full, do external test first to reduce the whole test time
|
|
+ */
|
|
+ if (eth_test->flags & ETH_TEST_FL_EXTERNAL_LB) {
|
|
+ hns3_external_lb_prepare(ndev, if_running);
|
|
+ hns3_do_external_lb(ndev, eth_test, data);
|
|
+ hns3_external_lb_restore(ndev, if_running);
|
|
+ }
|
|
+
|
|
+ hns3_selftest_prepare(ndev, if_running);
|
|
hns3_do_selftest(ndev, st_param, eth_test, data);
|
|
hns3_selftest_restore(ndev, if_running);
|
|
+
|
|
+ if (netif_msg_ifdown(h))
|
|
+ netdev_info(ndev, "self test end\n");
|
|
}
|
|
|
|
static void hns3_update_limit_promisc_mode(struct net_device *netdev,
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
|
|
index ee10aea14eb1..aeb776403ff0 100644
|
|
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
|
|
@@ -144,10 +144,11 @@ static const u32 tqp_intr_reg_addr_list[] = {HCLGE_TQP_INTR_CTRL_REG,
|
|
HCLGE_TQP_INTR_RL_REG};
|
|
|
|
static const char hns3_nic_test_strs[][ETH_GSTRING_LEN] = {
|
|
- "App Loopback test",
|
|
- "Serdes serial Loopback test",
|
|
- "Serdes parallel Loopback test",
|
|
- "Phy Loopback test"
|
|
+ "External Loopback test",
|
|
+ "App Loopback test",
|
|
+ "Serdes serial Loopback test",
|
|
+ "Serdes parallel Loopback test",
|
|
+ "Phy Loopback test"
|
|
};
|
|
|
|
static const struct hclge_comm_stats_str g_mac_stats_string[] = {
|
|
@@ -785,7 +786,8 @@ static int hclge_get_sset_count(struct hnae3_handle *handle, int stringset)
|
|
#define HCLGE_LOOPBACK_TEST_FLAGS (HNAE3_SUPPORT_APP_LOOPBACK | \
|
|
HNAE3_SUPPORT_PHY_LOOPBACK | \
|
|
HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK | \
|
|
- HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK)
|
|
+ HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK | \
|
|
+ HNAE3_SUPPORT_EXTERNAL_LOOPBACK)
|
|
|
|
struct hclge_vport *vport = hclge_get_vport(handle);
|
|
struct hclge_dev *hdev = vport->back;
|
|
@@ -807,9 +809,12 @@ static int hclge_get_sset_count(struct hnae3_handle *handle, int stringset)
|
|
handle->flags |= HNAE3_SUPPORT_APP_LOOPBACK;
|
|
}
|
|
|
|
- count += 2;
|
|
+ count += 1;
|
|
handle->flags |= HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK;
|
|
+ count += 1;
|
|
handle->flags |= HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK;
|
|
+ count += 1;
|
|
+ handle->flags |= HNAE3_SUPPORT_EXTERNAL_LOOPBACK;
|
|
|
|
if ((hdev->hw.mac.phydev && hdev->hw.mac.phydev->drv &&
|
|
hdev->hw.mac.phydev->drv->set_loopback) ||
|
|
@@ -840,6 +845,11 @@ static void hclge_get_strings(struct hnae3_handle *handle, u32 stringset,
|
|
size, p);
|
|
p = hclge_tqps_get_strings(handle, p);
|
|
} else if (stringset == ETH_SS_TEST) {
|
|
+ if (handle->flags & HNAE3_SUPPORT_EXTERNAL_LOOPBACK) {
|
|
+ memcpy(p, hns3_nic_test_strs[HNAE3_LOOP_EXTERNAL],
|
|
+ ETH_GSTRING_LEN);
|
|
+ p += ETH_GSTRING_LEN;
|
|
+ }
|
|
if (handle->flags & HNAE3_SUPPORT_APP_LOOPBACK) {
|
|
memcpy(p, hns3_nic_test_strs[HNAE3_LOOP_APP],
|
|
ETH_GSTRING_LEN);
|
|
@@ -7467,7 +7477,7 @@ static int hclge_set_loopback(struct hnae3_handle *handle,
|
|
{
|
|
struct hclge_vport *vport = hclge_get_vport(handle);
|
|
struct hclge_dev *hdev = vport->back;
|
|
- int ret;
|
|
+ int ret = 0;
|
|
|
|
/* Loopback can be enabled in three places: SSU, MAC, and serdes. By
|
|
* default, SSU loopback is enabled, so if the SMAC and the DMAC are
|
|
@@ -7494,6 +7504,8 @@ static int hclge_set_loopback(struct hnae3_handle *handle,
|
|
case HNAE3_LOOP_PHY:
|
|
ret = hclge_set_phy_loopback(hdev, en);
|
|
break;
|
|
+ case HNAE3_LOOP_EXTERNAL:
|
|
+ break;
|
|
default:
|
|
ret = -ENOTSUPP;
|
|
dev_err(&hdev->pdev->dev,
|
|
--
|
|
2.34.1
|
|
|