net: hns3: add support for external loopback test
[platform/kernel/linux-starfive.git] / drivers / net / ethernet / hisilicon / hns3 / hns3_ethtool.c
index 45cd19e..cdf76fb 100644 (file)
@@ -69,7 +69,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
@@ -95,6 +94,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:
@@ -304,6 +304,10 @@ out:
 
 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;
@@ -322,17 +326,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);
 
@@ -371,18 +369,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])
@@ -401,6 +396,20 @@ 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_self_test - self test
  * @ndev: net device
@@ -410,7 +419,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)) {
@@ -418,13 +429,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,