[PATCH v3 3/5] net/zxdh: add link speed set and autoneg get support

Junlong Wang
2026-01-31T06:46:04Z

[-- Attachment #1.1.1: Type: text/plain, Size: 13505 bytes --]

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..4b29cb7c82 100644
--- a/drivers/net/zxdh/zxdh_ethdev_ops.c
+++ b/drivers/net/zxdh/zxdh_ethdev_ops.c
@@ -307,7 +307,6 @@ 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);
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 +321,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 +368,110 @@ 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:
+ PMD_DRV_LOG(ERR, "unsupported speed!");
+ 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;
+ uint8_t zxdh_msg_reply_info[ZXDH_ST_SZ_BYTES(msg_reply_info)];
+ void *reply_body_addr = ZXDH_ADDR_OF(msg_reply_info, zxdh_msg_reply_info, reply_body);
+ int32_t spm_speed_modes;
+ int32_t ret;
+
+ 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 this 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;
+ uint8_t zxdh_msg_reply_info[ZXDH_ST_SZ_BYTES(msg_reply_info)];
+ int32_t ret;
+
+ 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)];
+ int32_t ret;
+
+ 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..e20f4b503a 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, void *reps_buffer,
+ uint16_t *reps_len, void *eth_dev)
+{
+ 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 && sizeof(msg_payload) <= len) {
+ PMD_DRV_LOG(ERR, "param invalid, dev is NULL or msg_payload too long");
+ 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

[-- Attachment #1.1.2: Type: text/html , Size: 27490 bytes --]