net: hns3: add support for get_regs
authorFuyun Liang <liangfuyun1@huawei.com>
Fri, 19 Jan 2018 06:41:09 +0000 (14:41 +0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 22 Jan 2018 21:05:48 +0000 (16:05 -0500)
This patch adds get_regs support for ethtool cmd.

Signed-off-by: Fuyun Liang <liangfuyun1@huawei.com>
Signed-off-by: Peng Li <lipeng321@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/hisilicon/hns3/hnae3.h
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 634e932..d104ce5 100644 (file)
@@ -356,7 +356,8 @@ struct hnae3_ae_ops {
                            u32 stringset, u8 *data);
        int (*get_sset_count)(struct hnae3_handle *handle, int stringset);
 
-       void (*get_regs)(struct hnae3_handle *handle, void *data);
+       void (*get_regs)(struct hnae3_handle *handle, u32 *version,
+                        void *data);
        int (*get_regs_len)(struct hnae3_handle *handle);
 
        u32 (*get_rss_key_size)(struct hnae3_handle *handle);
index 358f780..1c8b293 100644 (file)
@@ -1063,6 +1063,27 @@ static int hns3_set_coalesce(struct net_device *netdev,
        return 0;
 }
 
+static int hns3_get_regs_len(struct net_device *netdev)
+{
+       struct hnae3_handle *h = hns3_get_handle(netdev);
+
+       if (!h->ae_algo->ops->get_regs_len)
+               return -EOPNOTSUPP;
+
+       return h->ae_algo->ops->get_regs_len(h);
+}
+
+static void hns3_get_regs(struct net_device *netdev,
+                         struct ethtool_regs *cmd, void *data)
+{
+       struct hnae3_handle *h = hns3_get_handle(netdev);
+
+       if (!h->ae_algo->ops->get_regs)
+               return;
+
+       h->ae_algo->ops->get_regs(h, &cmd->version, data);
+}
+
 static const struct ethtool_ops hns3vf_ethtool_ops = {
        .get_drvinfo = hns3_get_drvinfo,
        .get_ringparam = hns3_get_ringparam,
@@ -1103,6 +1124,8 @@ static const struct ethtool_ops hns3_ethtool_ops = {
        .set_channels = hns3_set_channels,
        .get_coalesce = hns3_get_coalesce,
        .set_coalesce = hns3_set_coalesce,
+       .get_regs_len = hns3_get_regs_len,
+       .get_regs = hns3_get_regs,
 };
 
 void hns3_ethtool_set_ops(struct net_device *netdev)
index 3c3159b..2561e7a 100644 (file)
@@ -102,6 +102,10 @@ enum hclge_opcode_type {
        HCLGE_OPC_STATS_64_BIT          = 0x0030,
        HCLGE_OPC_STATS_32_BIT          = 0x0031,
        HCLGE_OPC_STATS_MAC             = 0x0032,
+
+       HCLGE_OPC_QUERY_REG_NUM         = 0x0040,
+       HCLGE_OPC_QUERY_32_BIT_REG      = 0x0041,
+       HCLGE_OPC_QUERY_64_BIT_REG      = 0x0042,
        /* Device management command */
 
        /* MAC commond */
index 27f0ab6..c3d2cca 100644 (file)
@@ -5544,6 +5544,180 @@ static int hclge_set_channels(struct hnae3_handle *handle, u32 new_tqps_num)
        return ret;
 }
 
+static int hclge_get_regs_num(struct hclge_dev *hdev, u32 *regs_num_32_bit,
+                             u32 *regs_num_64_bit)
+{
+       struct hclge_desc desc;
+       u32 total_num;
+       int ret;
+
+       hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QUERY_REG_NUM, true);
+       ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+       if (ret) {
+               dev_err(&hdev->pdev->dev,
+                       "Query register number cmd failed, ret = %d.\n", ret);
+               return ret;
+       }
+
+       *regs_num_32_bit = le32_to_cpu(desc.data[0]);
+       *regs_num_64_bit = le32_to_cpu(desc.data[1]);
+
+       total_num = *regs_num_32_bit + *regs_num_64_bit;
+       if (!total_num)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int hclge_get_32_bit_regs(struct hclge_dev *hdev, u32 regs_num,
+                                void *data)
+{
+#define HCLGE_32_BIT_REG_RTN_DATANUM 8
+
+       struct hclge_desc *desc;
+       u32 *reg_val = data;
+       __le32 *desc_data;
+       int cmd_num;
+       int i, k, n;
+       int ret;
+
+       if (regs_num == 0)
+               return 0;
+
+       cmd_num = DIV_ROUND_UP(regs_num + 2, HCLGE_32_BIT_REG_RTN_DATANUM);
+       desc = kcalloc(cmd_num, sizeof(struct hclge_desc), GFP_KERNEL);
+       if (!desc)
+               return -ENOMEM;
+
+       hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_QUERY_32_BIT_REG, true);
+       ret = hclge_cmd_send(&hdev->hw, desc, cmd_num);
+       if (ret) {
+               dev_err(&hdev->pdev->dev,
+                       "Query 32 bit register cmd failed, ret = %d.\n", ret);
+               kfree(desc);
+               return ret;
+       }
+
+       for (i = 0; i < cmd_num; i++) {
+               if (i == 0) {
+                       desc_data = (__le32 *)(&desc[i].data[0]);
+                       n = HCLGE_32_BIT_REG_RTN_DATANUM - 2;
+               } else {
+                       desc_data = (__le32 *)(&desc[i]);
+                       n = HCLGE_32_BIT_REG_RTN_DATANUM;
+               }
+               for (k = 0; k < n; k++) {
+                       *reg_val++ = le32_to_cpu(*desc_data++);
+
+                       regs_num--;
+                       if (!regs_num)
+                               break;
+               }
+       }
+
+       kfree(desc);
+       return 0;
+}
+
+static int hclge_get_64_bit_regs(struct hclge_dev *hdev, u32 regs_num,
+                                void *data)
+{
+#define HCLGE_64_BIT_REG_RTN_DATANUM 4
+
+       struct hclge_desc *desc;
+       u64 *reg_val = data;
+       __le64 *desc_data;
+       int cmd_num;
+       int i, k, n;
+       int ret;
+
+       if (regs_num == 0)
+               return 0;
+
+       cmd_num = DIV_ROUND_UP(regs_num + 1, HCLGE_64_BIT_REG_RTN_DATANUM);
+       desc = kcalloc(cmd_num, sizeof(struct hclge_desc), GFP_KERNEL);
+       if (!desc)
+               return -ENOMEM;
+
+       hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_QUERY_64_BIT_REG, true);
+       ret = hclge_cmd_send(&hdev->hw, desc, cmd_num);
+       if (ret) {
+               dev_err(&hdev->pdev->dev,
+                       "Query 64 bit register cmd failed, ret = %d.\n", ret);
+               kfree(desc);
+               return ret;
+       }
+
+       for (i = 0; i < cmd_num; i++) {
+               if (i == 0) {
+                       desc_data = (__le64 *)(&desc[i].data[0]);
+                       n = HCLGE_64_BIT_REG_RTN_DATANUM - 1;
+               } else {
+                       desc_data = (__le64 *)(&desc[i]);
+                       n = HCLGE_64_BIT_REG_RTN_DATANUM;
+               }
+               for (k = 0; k < n; k++) {
+                       *reg_val++ = le64_to_cpu(*desc_data++);
+
+                       regs_num--;
+                       if (!regs_num)
+                               break;
+               }
+       }
+
+       kfree(desc);
+       return 0;
+}
+
+static int hclge_get_regs_len(struct hnae3_handle *handle)
+{
+       struct hclge_vport *vport = hclge_get_vport(handle);
+       struct hclge_dev *hdev = vport->back;
+       u32 regs_num_32_bit, regs_num_64_bit;
+       int ret;
+
+       ret = hclge_get_regs_num(hdev, &regs_num_32_bit, &regs_num_64_bit);
+       if (ret) {
+               dev_err(&hdev->pdev->dev,
+                       "Get register number failed, ret = %d.\n", ret);
+               return -EOPNOTSUPP;
+       }
+
+       return regs_num_32_bit * sizeof(u32) + regs_num_64_bit * sizeof(u64);
+}
+
+static void hclge_get_regs(struct hnae3_handle *handle, u32 *version,
+                          void *data)
+{
+       struct hclge_vport *vport = hclge_get_vport(handle);
+       struct hclge_dev *hdev = vport->back;
+       u32 regs_num_32_bit, regs_num_64_bit;
+       int ret;
+
+       *version = hdev->fw_version;
+
+       ret = hclge_get_regs_num(hdev, &regs_num_32_bit, &regs_num_64_bit);
+       if (ret) {
+               dev_err(&hdev->pdev->dev,
+                       "Get register number failed, ret = %d.\n", ret);
+               return;
+       }
+
+       ret = hclge_get_32_bit_regs(hdev, regs_num_32_bit, data);
+       if (ret) {
+               dev_err(&hdev->pdev->dev,
+                       "Get 32 bit register failed, ret = %d.\n", ret);
+               return;
+       }
+
+       data = (u32 *)data + regs_num_32_bit;
+       ret = hclge_get_64_bit_regs(hdev, regs_num_64_bit,
+                                   data);
+       if (ret)
+               dev_err(&hdev->pdev->dev,
+                       "Get 64 bit register failed, ret = %d.\n", ret);
+}
+
 static const struct hnae3_ae_ops hclge_ops = {
        .init_ae_dev = hclge_init_ae_dev,
        .uninit_ae_dev = hclge_uninit_ae_dev,
@@ -5595,6 +5769,8 @@ static const struct hnae3_ae_ops hclge_ops = {
        .set_channels = hclge_set_channels,
        .get_channels = hclge_get_channels,
        .get_flowctrl_adv = hclge_get_flowctrl_adv,
+       .get_regs_len = hclge_get_regs_len,
+       .get_regs = hclge_get_regs,
 };
 
 static struct hnae3_ae_algo ae_algo = {