add support ops to set link speed in usermode, and
get autoneg stats.

Signed-off-by: Junlong Wang <wang.junlong1@zte.com.cn>
---
 drivers/net/zxdh/zxdh_ethdev.c     |   6 ++
 drivers/net/zxdh/zxdh_ethdev.h     |   7 +-
 drivers/net/zxdh/zxdh_ethdev_ops.c | 116 ++++++++++++++++++++++++++---
 drivers/net/zxdh/zxdh_ethdev_ops.h |  15 ++++
 drivers/net/zxdh/zxdh_msg.c        |  49 ++++++++++++
 drivers/net/zxdh/zxdh_msg.h        |  24 +++++-
 6 files changed, 202 insertions(+), 15 deletions(-)

diff --git a/drivers/net/zxdh/zxdh_ethdev.c b/drivers/net/zxdh/zxdh_ethdev.c
index 2fc2d78aff..823b1ffb5c 100644
--- a/drivers/net/zxdh/zxdh_ethdev.c
+++ b/drivers/net/zxdh/zxdh_ethdev.c
@@ -1432,6 +1432,10 @@ zxdh_dev_start(struct rte_eth_dev *dev)
         zxdh_queue_notify(vq);
     }
 
+    if (hw->is_pf)
+        zxdh_link_speed_set(dev);
+    zxdh_autoneg_stats_get(dev);
+
     hw->admin_status = RTE_ETH_LINK_UP;
     zxdh_dev_link_update(dev, 0);
 
@@ -1604,6 +1608,8 @@ zxdh_agent_comm(struct rte_eth_dev *eth_dev, struct zxdh_hw *hw)
         return -1;
     }
 
+    zxdh_speed_modes_get(eth_dev);
+
     if (hw->switchoffload)
         hw->phyport = 9;
 
diff --git a/drivers/net/zxdh/zxdh_ethdev.h b/drivers/net/zxdh/zxdh_ethdev.h
index 411d287f32..81b385ecb8 100644
--- a/drivers/net/zxdh/zxdh_ethdev.h
+++ b/drivers/net/zxdh/zxdh_ethdev.h
@@ -125,7 +125,7 @@ struct zxdh_hw {
     uint64_t host_features;
     uint64_t guest_features;
     uint32_t speed;
-    uint32_t speed_mode;
+    int32_t speed_mode;
     uint32_t notify_off_multiplier;
     union zxdh_virport_num vport;
     uint16_t max_queue_pairs;
@@ -173,9 +173,10 @@ struct zxdh_hw {
     struct zxdh_vlan_offload_cfg vlan_offload_cfg;
     uint16_t queue_pool_count;
     uint16_t queue_pool_start;
-    uint8_t dl_net_hdr_len;
     uint16_t vxlan_fd_num;
-    uint8_t rsv1[1];
+    uint32_t support_speed_modes;
+    uint8_t dl_net_hdr_len;
+    uint8_t autoneg;
 
     struct dh_flow_list dh_flow_list;
 };
diff --git a/drivers/net/zxdh/zxdh_ethdev_ops.c b/drivers/net/zxdh/zxdh_ethdev_ops.c
index cabf81107e..8fb315eeac 100644
--- a/drivers/net/zxdh/zxdh_ethdev_ops.c
+++ b/drivers/net/zxdh/zxdh_ethdev_ops.c
@@ -307,7 +307,7 @@ zxdh_link_info_get(struct rte_eth_dev *dev, struct rte_eth_link *link)
         }
 
         link->link_speed = ZXDH_GET(link_info_msg, link_msg_addr, speed);
-        link->link_autoneg = ZXDH_GET(link_info_msg, link_msg_addr, autoneg);
+        // link->link_autoneg = ZXDH_GET(link_info_msg, link_msg_addr, autoneg);
         hw->speed_mode = ZXDH_GET(link_info_msg, link_msg_addr, speed_modes);
         if ((ZXDH_GET(link_info_msg, link_msg_addr, duplex) & RTE_ETH_LINK_FULL_DUPLEX) ==
                 RTE_ETH_LINK_FULL_DUPLEX)
@@ -322,6 +322,7 @@ zxdh_link_info_get(struct rte_eth_dev *dev, struct rte_eth_link *link)
         link->link_autoneg = RTE_ETH_LINK_AUTONEG;
         link->link_status = RTE_ETH_LINK_UP;
     }
+    link->link_autoneg = hw->autoneg;
     hw->speed = link->link_speed;
 
     return 0;
@@ -368,6 +369,109 @@ int zxdh_dev_set_link_up(struct rte_eth_dev *dev)
     return ret;
 }
 
+static int32_t zxdh_speed_mode_to_spm(uint32_t link_speed_modes)
+{
+    switch (link_speed_modes) {
+    case RTE_ETH_LINK_SPEED_1G:   return ZXDH_SPM_SPEED_1X_1G;
+    case RTE_ETH_LINK_SPEED_10G:  return ZXDH_SPM_SPEED_1X_10G;
+    case RTE_ETH_LINK_SPEED_25G:  return ZXDH_SPM_SPEED_1X_25G;
+    case RTE_ETH_LINK_SPEED_50G:  return ZXDH_SPM_SPEED_1X_50G;
+    case RTE_ETH_LINK_SPEED_100G: return ZXDH_SPM_SPEED_4X_100G;
+    case RTE_ETH_LINK_SPEED_200G: return ZXDH_SPM_SPEED_4X_200G;
+    default: return -1;
+    }
+}
+
+int32_t zxdh_link_speed_set(struct rte_eth_dev *dev)
+{
+    struct zxdh_hw *hw = dev->data->dev_private;
+    struct zxdh_msg_info msg = {0};
+    uint8_t zxdh_msg_reply_info[ZXDH_ST_SZ_BYTES(msg_reply_info)] = {0};
+    void *reply_body_addr = ZXDH_ADDR_OF(msg_reply_info, zxdh_msg_reply_info, reply_body);
+    uint32_t link_speed = 0;
+    int32_t spm_speed_modes = 0;
+    int32_t ret = 0;
+
+    spm_speed_modes =
+        zxdh_speed_mode_to_spm(dev->data->dev_conf.link_speeds & ~RTE_ETH_LINK_SPEED_FIXED);
+    if (spm_speed_modes == -1 || spm_speed_modes == hw->speed_mode) {
+        PMD_DRV_LOG(DEBUG, "not need update speed");
+        return 0;
+    }
+    if ((spm_speed_modes & hw->support_speed_modes) == 0)  {
+        PMD_DRV_LOG(ERR, "not support configure speed :%d ", link_speed);
+        return 0;
+    }
+
+    zxdh_agent_msg_build(hw, ZXDH_MAC_SPEED_SET, &msg);
+    msg.data.link_msg.autoneg = 0;
+    msg.data.link_msg.speed_modes = spm_speed_modes & hw->support_speed_modes;
+
+    ret = zxdh_send_msg_to_riscv(dev, &msg, sizeof(struct zxdh_msg_info),
+                zxdh_msg_reply_info, ZXDH_ST_SZ_BYTES(msg_reply_info),
+                ZXDH_BAR_MODULE_MAC);
+    uint8_t flag = ZXDH_GET(msg_reply_body, reply_body_addr, flag);
+    if (flag != ZXDH_REPS_SUCC || ret) {
+        PMD_DRV_LOG(ERR, "failed to set link speed!");
+        return -1;
+    }
+
+    return 0;
+}
+
+void
+zxdh_speed_modes_get(struct rte_eth_dev *dev)
+{
+    struct zxdh_hw *hw = dev->data->dev_private;
+    struct zxdh_msg_info msg = {0};
+    uint8_t zxdh_msg_reply_info[ZXDH_ST_SZ_BYTES(msg_reply_info)] = {0};
+    int32_t ret = 0;
+
+    if (!hw->is_pf)
+        return;
+
+    msg.agent_msg_head.msg_type = ZXDH_MAC_PHYPORT_INIT;
+    msg.agent_msg_head.init = 1;
+
+    ret = zxdh_send_msg_to_riscv(dev, &msg, sizeof(struct zxdh_msg_info),
+                zxdh_msg_reply_info, ZXDH_ST_SZ_BYTES(msg_reply_info),
+                ZXDH_BAR_MODULE_MAC);
+    if (ret)
+        PMD_DRV_LOG(ERR, "Failed to get speed mode info");
+
+    void *reply_body_addr = ZXDH_ADDR_OF(msg_reply_info, zxdh_msg_reply_info, reply_body);
+    void *link_msg_addr = ZXDH_ADDR_OF(msg_reply_body, reply_body_addr, link_msg);
+    uint32_t speed_modes = ZXDH_GET(link_info_msg, link_msg_addr, speed_modes);
+
+    hw->support_speed_modes = speed_modes;
+}
+
+int32_t zxdh_autoneg_stats_get(struct rte_eth_dev *dev)
+{
+    struct zxdh_hw *hw = dev->data->dev_private;
+    struct zxdh_msg_info msg;
+    uint8_t zxdh_msg_reply_info[ZXDH_ST_SZ_BYTES(msg_reply_info)] = {0};
+    int32_t ret = 0;
+
+    zxdh_agent_msg_build(hw, ZXDH_MAC_AUTONEG_GET, &msg);
+
+    ret = zxdh_send_msg_to_riscv(dev, &msg, sizeof(struct zxdh_msg_info),
+                zxdh_msg_reply_info, ZXDH_ST_SZ_BYTES(msg_reply_info),
+                ZXDH_BAR_MODULE_MAC);
+    if (ret) {
+        PMD_DRV_LOG(ERR, "Failed to get link autoneg stats!");
+        return -1;
+    }
+    void *reply_body_addr = ZXDH_ADDR_OF(msg_reply_info, zxdh_msg_reply_info, reply_body);
+    void *link_addr = ZXDH_ADDR_OF(msg_reply_body, reply_body_addr, link_msg);
+    void *link_autoeng_addr = ZXDH_ADDR_OF(link_info_msg, link_addr, autoneg);
+
+    hw->autoneg = *(uint8_t *)link_autoeng_addr;
+    PMD_DRV_LOG(DEBUG, "autoneg stats is: %d", hw->autoneg);
+
+    return 0;
+}
+
 int32_t zxdh_dev_link_update(struct rte_eth_dev *dev, int32_t wait_to_complete __rte_unused)
 {
     struct rte_eth_link link;
@@ -384,17 +488,7 @@ int32_t zxdh_dev_link_update(struct rte_eth_dev *dev, int32_t wait_to_complete _
         PMD_DRV_LOG(ERR, "Failed to get link status from hw");
         return ret;
     }
-    link.link_status &= hw->admin_status;
-    if (link.link_status == RTE_ETH_LINK_DOWN) {
-        PMD_DRV_LOG(DEBUG, "dev link status is down.");
-        goto link_down;
-    }
-    goto out;
 
-link_down:
-    link.link_status = RTE_ETH_LINK_DOWN;
-    link.link_speed  = RTE_ETH_SPEED_NUM_UNKNOWN;
-out:
     if (link.link_status != dev->data->dev_link.link_status) {
         ret = zxdh_config_port_status(dev, link.link_status);
         if (ret != 0) {
diff --git a/drivers/net/zxdh/zxdh_ethdev_ops.h b/drivers/net/zxdh/zxdh_ethdev_ops.h
index 85e926887b..6dfe4be473 100644
--- a/drivers/net/zxdh/zxdh_ethdev_ops.h
+++ b/drivers/net/zxdh/zxdh_ethdev_ops.h
@@ -27,6 +27,18 @@
 #define ZXDH_RSS_HF  ((ZXDH_HF_MAC_VLAN_ETH | ZXDH_HF_F3_ETH | ZXDH_HF_F5_ETH))
 
 #define ZXDH_ETHER_MIN_MTU      68
+#define ZXDH_SPM_SPEED_1X_10M          RTE_BIT32(0)
+#define ZXDH_SPM_SPEED_1X_100M         RTE_BIT32(1)
+#define ZXDH_SPM_SPEED_1X_1G           RTE_BIT32(2)
+#define ZXDH_SPM_SPEED_1X_2DOT5G       RTE_BIT32(3)
+#define ZXDH_SPM_SPEED_1X_5G           RTE_BIT32(4)
+#define ZXDH_SPM_SPEED_1X_10G          RTE_BIT32(5)
+#define ZXDH_SPM_SPEED_1X_25G          RTE_BIT32(6)
+#define ZXDH_SPM_SPEED_1X_50G          RTE_BIT32(7)
+#define ZXDH_SPM_SPEED_2X_100G         RTE_BIT32(8)
+#define ZXDH_SPM_SPEED_4X_40G          RTE_BIT32(9)
+#define ZXDH_SPM_SPEED_4X_100G         RTE_BIT32(10)
+#define ZXDH_SPM_SPEED_4X_200G         RTE_BIT32(11)
 
 struct zxdh_np_stats_data {
     uint64_t n_pkts_dropped;
@@ -144,5 +156,8 @@ int zxdh_dev_get_module_info(struct rte_eth_dev *dev, struct rte_eth_dev_module_
 int zxdh_dev_get_module_eeprom(struct rte_eth_dev *dev, struct rte_dev_eeprom_info *info);
 int zxdh_meter_ops_get(struct rte_eth_dev *dev, void *arg);
 uint16_t zxdh_hw_qid_to_logic_qid(struct rte_eth_dev *dev, uint16_t qid);
+int32_t zxdh_link_speed_set(struct rte_eth_dev *dev);
+void zxdh_speed_modes_get(struct rte_eth_dev *dev);
+int32_t zxdh_autoneg_stats_get(struct rte_eth_dev *dev);
 
 #endif /* ZXDH_ETHDEV_OPS_H */
diff --git a/drivers/net/zxdh/zxdh_msg.c b/drivers/net/zxdh/zxdh_msg.c
index 196e27f91c..ff2d11706c 100644
--- a/drivers/net/zxdh/zxdh_msg.c
+++ b/drivers/net/zxdh/zxdh_msg.c
@@ -2450,9 +2450,58 @@ pf_recv_bar_msg(void *pay_load, uint16_t len, void *reps_buffer,
     return ret;
 }
 
+static int vf_recv_link_state_msg(struct rte_eth_dev *dev, void *payload,
+        void *reply_body __rte_unused, uint16_t *reps_len)
+{
+    struct zxdh_hw *hw = dev->data->dev_private;
+    void *link_autoneg_addr = ZXDH_ADDR_OF(zxdh_link_state_msg, payload, autoneg_enable);
+
+    hw->autoneg = *(uint8_t *)link_autoneg_addr;
+    dev->data->dev_link.link_autoneg = hw->autoneg;
+    *reps_len = ZXDH_ST_SZ_BYTES(zxdh_link_state_msg);
+
+    return 0;
+}
+
+static int
+vf_recv_bar_msg(void *payload, uint16_t len __rte_unused, void *reps_buffer,
+    uint16_t *reps_len, void *eth_dev __rte_unused)
+{
+    struct zxdh_msg_info *msg_payload = (struct zxdh_msg_info *)payload;
+    uint16_t pcieid = msg_payload->msg_to_vf.pcieid;
+    uint16_t opcode = msg_payload->msg_to_vf.opcode;
+    struct rte_eth_dev *dev = (struct rte_eth_dev *)eth_dev;
+    struct zxdh_ifc_msg_reply_body_bits *reply_body;
+    reply_body = (struct zxdh_ifc_msg_reply_body_bits *)
+        ZXDH_ADDR_OF(msg_reply_body, reps_buffer, flag);
+    int32_t ret = 0;
+
+    if (dev == NULL) {
+        PMD_DRV_LOG(ERR, "param invalid, dev is NULL");
+        ret = -2;
+        return ret;
+    }
+
+    switch (opcode) {
+    case ZXDH_SET_VF_LINK_STATE:
+        PMD_DRV_LOG(DEBUG, "PF(pcieid:%d ) set VF's link state", pcieid);
+        vf_recv_link_state_msg(dev, &msg_payload->data, reps_buffer, reps_len);
+        reply_body->flag[0] = ZXDH_REPS_SUCC;
+        break;
+    default:
+        ZXDH_SET(msg_reply_body, reps_buffer, flag, ZXDH_REPS_INVALID);
+        PMD_DRV_LOG(ERR, "[VF GET MSG FROM PF]--unknown msg opcode:%d", opcode);
+        ret = -1;
+        break;
+    }
+    return ret;
+}
+
 void
 zxdh_msg_cb_reg(struct zxdh_hw *hw)
 {
     if (hw->is_pf)
         zxdh_bar_chan_msg_recv_register(ZXDH_MODULE_BAR_MSG_TO_PF, pf_recv_bar_msg);
+    else
+        zxdh_bar_chan_msg_recv_register(ZXDH_MODULE_BAR_MSG_TO_VF, vf_recv_bar_msg);
 }
diff --git a/drivers/net/zxdh/zxdh_msg.h b/drivers/net/zxdh/zxdh_msg.h
index 61a3da878e..0fc9bff75d 100644
--- a/drivers/net/zxdh/zxdh_msg.h
+++ b/drivers/net/zxdh/zxdh_msg.h
@@ -205,6 +205,8 @@ enum zxdh_module_id {
 enum zxdh_agent_msg_type {
     ZXDH_MAC_STATS_GET = 10,
     ZXDH_MAC_STATS_RESET,
+    ZXDH_MAC_PHYPORT_INIT,
+    ZXDH_MAC_SPEED_SET,
     ZXDH_MAC_LINK_GET = 14,
     ZXDH_MAC_MODULE_EEPROM_READ = 20,
     ZXDH_VQM_DEV_STATS_GET = 21,
@@ -212,6 +214,7 @@ enum zxdh_agent_msg_type {
     ZXDH_FLASH_FIR_VERSION_GET = 23,
     ZXDH_VQM_QUEUE_STATS_GET = 24,
     ZXDH_VQM_QUEUE_STATS_RESET,
+    ZXDH_MAC_AUTONEG_GET = 44,
 };
 
 enum zxdh_msg_type {
@@ -233,6 +236,7 @@ enum zxdh_msg_type {
 
     ZXDH_PORT_ATTRS_SET = 25,
     ZXDH_PORT_PROMISC_SET = 26,
+    ZXDH_SET_VF_LINK_STATE = 28,
 
     ZXDH_GET_NP_STATS = 31,
     ZXDH_PLCR_CAR_PROFILE_ID_ADD = 36,
@@ -408,6 +412,17 @@ struct zxdh_ifc_agent_mac_module_eeprom_msg_bits {
     uint8_t data[ZXDH_MODULE_EEPROM_DATA_LEN * 8];
 };
 
+struct zxdh_ifc_zxdh_link_state_msg_bits {
+    uint8_t is_link_force_set[0x8];
+    uint8_t link_forced[0x8];
+    uint8_t link_up[0x8];
+    uint8_t speed[0x20];
+    uint8_t autoneg_enable[0x20];
+    uint8_t supported_speed_modes[0x20];
+    uint8_t advertising_speed_modes[0x20];
+    uint8_t duplex[0x8];
+};
+
 struct zxdh_flash_msg {
     uint8_t firmware_version[ZXDH_FWVERS_LEN];
 };
@@ -454,6 +469,7 @@ struct zxdh_ifc_msg_reply_body_bits {
         struct zxdh_ifc_mtr_profile_info_bits  mtr_profile_info;
         struct zxdh_ifc_mtr_stats_bits hw_mtr_stats;
         struct zxdh_flow_op_rsp  flow_rsp;
+        struct zxdh_ifc_zxdh_link_state_msg_bits link_state_msg;
     };
 };
 
@@ -482,6 +498,11 @@ struct __rte_packed_begin zxdh_msg_head {
     uint16_t pcieid;
 } __rte_packed_end;
 
+struct __rte_packed_begin zxdh_msg_head_to_vf {
+    uint8_t opcode;
+    uint16_t pcieid;
+} __rte_packed_end;
+
 struct zxdh_port_attr_set_msg {
     uint32_t mode;
     uint32_t value;
@@ -521,7 +542,7 @@ struct zxdh_agent_msg_head {
     uint8_t msg_type;
     uint8_t panel_id;
     uint8_t phyport;
-    uint8_t rsv;
+    uint8_t init;
     uint16_t vf_id;
     uint16_t pcie_id;
 };
@@ -570,6 +591,7 @@ struct zxdh_msg_info {
         uint8_t head_len[ZXDH_MSG_HEAD_LEN];
         struct zxdh_msg_head msg_head;
         struct zxdh_agent_msg_head agent_msg_head;
+        struct zxdh_msg_head_to_vf msg_to_vf;
     };
     union {
         uint8_t datainfo[ZXDH_MSG_REQ_BODY_MAX_LEN];
-- 
2.27.0