]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
net: hns3: Add support for serdes loopback selftest
authorPeng Li <lipeng321@huawei.com>
Tue, 14 Aug 2018 16:13:12 +0000 (17:13 +0100)
committerKleber Sacilotto de Souza <kleber.souza@canonical.com>
Wed, 5 Sep 2018 12:18:41 +0000 (14:18 +0200)
BugLink: https://bugs.launchpad.net/bugs/1787477
This patch adds support for serdes loopback selftest in hns3
driver.

Signed-off-by: Yunsheng Lin <linyunsheng@huawei.com>
Signed-off-by: Peng Li <lipeng321@huawei.com>
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 5fd50ac38fb66451672b75f8d143dbef6081dd3a)
Signed-off-by: dann frazier <dann.frazier@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
Acked-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c

index 80ba95d76260ac796bbb0aa64b54d1b68015e53e..f70ee6910ee27a436575734b068a2ee3599a78ae 100644 (file)
@@ -53,7 +53,7 @@ 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_TPYE_NUM                1
+#define HNS3_SELF_TEST_TYPE_NUM                2
 #define HNS3_NIC_LB_TEST_PKT_NUM       1
 #define HNS3_NIC_LB_TEST_RING_ID       0
 #define HNS3_NIC_LB_TEST_PACKET_SIZE   128
@@ -78,6 +78,7 @@ static int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop, bool en)
                return -EOPNOTSUPP;
 
        switch (loop) {
+       case HNAE3_MAC_INTER_LOOP_SERDES:
        case HNAE3_MAC_INTER_LOOP_MAC:
                ret = h->ae_algo->ops->set_loopback(h, loop, en);
                break;
@@ -287,7 +288,7 @@ static void hns3_self_test(struct net_device *ndev,
 {
        struct hns3_nic_priv *priv = netdev_priv(ndev);
        struct hnae3_handle *h = priv->ae_handle;
-       int st_param[HNS3_SELF_TEST_TPYE_NUM][2];
+       int st_param[HNS3_SELF_TEST_TYPE_NUM][2];
        bool if_running = netif_running(ndev);
 #if IS_ENABLED(CONFIG_VLAN_8021Q)
        bool dis_vlan_filter;
@@ -303,6 +304,10 @@ static void hns3_self_test(struct net_device *ndev,
        st_param[HNAE3_MAC_INTER_LOOP_MAC][1] =
                        h->flags & HNAE3_SUPPORT_MAC_LOOPBACK;
 
+       st_param[HNAE3_MAC_INTER_LOOP_SERDES][0] = HNAE3_MAC_INTER_LOOP_SERDES;
+       st_param[HNAE3_MAC_INTER_LOOP_SERDES][1] =
+                       h->flags & HNAE3_SUPPORT_SERDES_LOOPBACK;
+
        if (if_running)
                dev_close(ndev);
 
@@ -316,7 +321,7 @@ static void hns3_self_test(struct net_device *ndev,
 
        set_bit(HNS3_NIC_STATE_TESTING, &priv->state);
 
-       for (i = 0; i < HNS3_SELF_TEST_TPYE_NUM; i++) {
+       for (i = 0; i < HNS3_SELF_TEST_TYPE_NUM; i++) {
                enum hnae3_loop loop_type = (enum hnae3_loop)st_param[i][0];
 
                if (!st_param[i][1])
index 5cd22f9bbdec94f80d72b38efe7fee6b156cf4e6..564d54b6e07d733b0eb618c54e2ef1f49cd6a1b6 100644 (file)
@@ -94,6 +94,7 @@ enum hclge_opcode_type {
        HCLGE_OPC_QUERY_LINK_STATUS     = 0x0307,
        HCLGE_OPC_CONFIG_MAX_FRM_SIZE   = 0x0308,
        HCLGE_OPC_CONFIG_SPEED_DUP      = 0x0309,
+       HCLGE_OPC_SERDES_LOOPBACK       = 0x0315,
 
        /* PFC/Pause commands */
        HCLGE_OPC_CFG_MAC_PAUSE_EN      = 0x0701,
@@ -773,6 +774,17 @@ struct hclge_reset_cmd {
        u8 fun_reset_vfid;
        u8 rsv[22];
 };
+
+#define HCLGE_CMD_SERDES_SERIAL_INNER_LOOP_B   BIT(0)
+#define HCLGE_CMD_SERDES_DONE_B                        BIT(0)
+#define HCLGE_CMD_SERDES_SUCCESS_B             BIT(1)
+struct hclge_serdes_lb_cmd {
+       u8 mask;
+       u8 enable;
+       u8 result;
+       u8 rsv[21];
+};
+
 #define HCLGE_DEFAULT_TX_BUF           0x4000   /* 16k  bytes */
 #define HCLGE_TOTAL_PKT_BUF            0x108000 /* 1.03125M bytes */
 #define HCLGE_DEFAULT_DV               0xA000   /* 40k byte */
index 8caaca13f68f2f524dfdd052e3d1579c2e87d172..db9db688b08e757a2e41bb9b487d327927303fa3 100644 (file)
@@ -787,9 +787,10 @@ static int hclge_get_sset_count(struct hnae3_handle *handle, int stringset)
                    hdev->hw.mac.speed == HCLGE_MAC_SPEED_1G) {
                        count += 1;
                        handle->flags |= HNAE3_SUPPORT_MAC_LOOPBACK;
-               } else {
-                       count = -EOPNOTSUPP;
                }
+
+               count++;
+               handle->flags |= HNAE3_SUPPORT_SERDES_LOOPBACK;
        } else if (stringset == ETH_SS_STATS) {
                count = ARRAY_SIZE(g_mac_stats_string) +
                        ARRAY_SIZE(g_all_32bit_stats_string) +
@@ -3686,6 +3687,55 @@ static int hclge_set_mac_loopback(struct hclge_dev *hdev, bool en)
        return ret;
 }
 
+static int hclge_set_serdes_loopback(struct hclge_dev *hdev, bool en)
+{
+#define HCLGE_SERDES_RETRY_MS  10
+#define HCLGE_SERDES_RETRY_NUM 100
+       struct hclge_serdes_lb_cmd *req;
+       struct hclge_desc desc;
+       int ret, i = 0;
+
+       req = (struct hclge_serdes_lb_cmd *)&desc.data[0];
+       hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SERDES_LOOPBACK, false);
+
+       if (en) {
+               req->enable = HCLGE_CMD_SERDES_SERIAL_INNER_LOOP_B;
+               req->mask = HCLGE_CMD_SERDES_SERIAL_INNER_LOOP_B;
+       } else {
+               req->mask = HCLGE_CMD_SERDES_SERIAL_INNER_LOOP_B;
+       }
+
+       ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+       if (ret) {
+               dev_err(&hdev->pdev->dev,
+                       "serdes loopback set fail, ret = %d\n", ret);
+               return ret;
+       }
+
+       do {
+               msleep(HCLGE_SERDES_RETRY_MS);
+               hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_SERDES_LOOPBACK,
+                                          true);
+               ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+               if (ret) {
+                       dev_err(&hdev->pdev->dev,
+                               "serdes loopback get, ret = %d\n", ret);
+                       return ret;
+               }
+       } while (++i < HCLGE_SERDES_RETRY_NUM &&
+                !(req->result & HCLGE_CMD_SERDES_DONE_B));
+
+       if (!(req->result & HCLGE_CMD_SERDES_DONE_B)) {
+               dev_err(&hdev->pdev->dev, "serdes loopback set timeout\n");
+               return -EBUSY;
+       } else if (!(req->result & HCLGE_CMD_SERDES_SUCCESS_B)) {
+               dev_err(&hdev->pdev->dev, "serdes loopback set failed in fw\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
 static int hclge_set_loopback(struct hnae3_handle *handle,
                              enum hnae3_loop loop_mode, bool en)
 {
@@ -3697,6 +3747,9 @@ static int hclge_set_loopback(struct hnae3_handle *handle,
        case HNAE3_MAC_INTER_LOOP_MAC:
                ret = hclge_set_mac_loopback(hdev, en);
                break;
+       case HNAE3_MAC_INTER_LOOP_SERDES:
+               ret = hclge_set_serdes_loopback(hdev, en);
+               break;
        default:
                ret = -ENOTSUPP;
                dev_err(&hdev->pdev->dev,