From 9a6dc843b9099bdb7ae97f323e9938049deeb7f4 Mon Sep 17 00:00:00 2001 From: Keming Yang Date: Sat, 24 Oct 2026 06:42:33 +0800 Subject: [PATCH] net: yusur: yk3: report RSS mailbox failures to callers The VF RSS key and indirection-table helpers discard mailbox errors. Their ethtool callbacks then return success even when a read failed or a configuration request was not delivered. A failed multi-chunk table operation can therefore leave partial state without notifying userspace. Return status from the four RSS helpers and propagate it through both ethtool compatibility interfaces and the direct cdev RETA caller. Stop after the first failed operation while releasing the existing state mutex on every exit. Keep successful PF MMIO operations unchanged. Mailbox transport failures use positive internal status values. Convert L2 failure to -EIO and missing reply to -ETIMEDOUT, preserving existing negative errno values. Use the same conversion for table initialization. Do not change the wire protocol, reply mode, chunking or success path. Previously completed chunks are not rolled back. Exact-source component comparisons cover 84 RSS requests and 24 table initialization cases. A private OCK guest also exercises real ethtool ioctls and the exact cdev handler through a test adapter, with a modeled mailbox and MMIO backend. Baseline failures reported as success become negative errno results; normal configuration and recovery readback stay correct. The complete target YK3 composite object builds before and after. No physical NIC, traffic distribution or concurrency validation is claimed. Upstream status: downstream-only Fixes: b3fe1bfec4e2 ("net: ethernet: yusur: add YK3 Ethernet driver") Signed-off-by: Keming Yang --- drivers/net/ethernet/yusur/yk3/yk3_cdev.c | 2 +- drivers/net/ethernet/yusur/yk3/yk3_ethtool.c | 52 ++++++++++++------ drivers/net/ethernet/yusur/yk3/yk3_rss.c | 55 +++++++++++++++----- drivers/net/ethernet/yusur/yk3/yk3_rss.h | 8 +-- 4 files changed, 82 insertions(+), 35 deletions(-) diff --git a/drivers/net/ethernet/yusur/yk3/yk3_cdev.c b/drivers/net/ethernet/yusur/yk3/yk3_cdev.c index 920ce9366452..dc5f5d7afaba 100644 --- a/drivers/net/ethernet/yusur/yk3/yk3_cdev.c +++ b/drivers/net/ethernet/yusur/yk3/yk3_cdev.c @@ -1271,7 +1271,7 @@ static long yk3_net_rss_reta(struct file *file, unsigned int cmd, unsigned long memcpy(indir_buf, rss_reta.indir, indir_size * sizeof(u32)); /* we need qcount as a parameter, cannot use ndo_ops set_rxfh */ - yk3_rss_indir_table_set(ndev, indir_buf, rss_reta.qcount); + ret = yk3_rss_indir_table_set(ndev, indir_buf, rss_reta.qcount); break; default: ret = -EINVAL; diff --git a/drivers/net/ethernet/yusur/yk3/yk3_ethtool.c b/drivers/net/ethernet/yusur/yk3/yk3_ethtool.c index f07bbd4c6934..563e60563835 100644 --- a/drivers/net/ethernet/yusur/yk3/yk3_ethtool.c +++ b/drivers/net/ethernet/yusur/yk3/yk3_ethtool.c @@ -428,40 +428,50 @@ static u32 yk3_get_rxfh_key_size(struct net_device *ndev) static int yk3_get_rxfh(struct net_device *ndev, struct ethtool_rxfh_param *param) { struct yk3_ndev_priv *ndev_priv = netdev_priv(ndev); + int ret = 0; mutex_lock(&ndev_priv->state_mlock); - if (param->indir) - yk3_rss_indir_table_get(ndev, param->indir); + if (param->indir) { + ret = yk3_rss_indir_table_get(ndev, param->indir); + if (ret) + goto out; + } if (param->hfunc) param->hfunc = ETH_RSS_HASH_TOP; if (param->key) - yk3_rss_key_get(ndev, param->key); + ret = yk3_rss_key_get(ndev, param->key); +out: mutex_unlock(&ndev_priv->state_mlock); - return 0; + return ret; } #else static int yk3_get_rxfh(struct net_device *ndev, u32 *indir, u8 *key, u8 *hfunc) { struct yk3_ndev_priv *ndev_priv = netdev_priv(ndev); + int ret = 0; mutex_lock(&ndev_priv->state_mlock); - if (indir) - yk3_rss_indir_table_get(ndev, indir); + if (indir) { + ret = yk3_rss_indir_table_get(ndev, indir); + if (ret) + goto out; + } if (hfunc) *hfunc = ETH_RSS_HASH_TOP; if (key) - yk3_rss_key_get(ndev, key); + ret = yk3_rss_key_get(ndev, key); +out: mutex_unlock(&ndev_priv->state_mlock); - return 0; + return ret; } #endif /* YK3_HAVE_ETHTOOL_GET_RXFH_PARAM */ @@ -471,39 +481,49 @@ static int yk3_set_rxfh(struct net_device *ndev, struct netlink_ext_ack *extack) { struct yk3_ndev_priv *ndev_priv = netdev_priv(ndev); + int ret = 0; if (param->hfunc != ETH_RSS_HASH_NO_CHANGE && param->hfunc != ETH_RSS_HASH_TOP) return -EOPNOTSUPP; mutex_lock(&ndev_priv->state_mlock); - if (param->key) - yk3_rss_key_set(ndev, param->key); + if (param->key) { + ret = yk3_rss_key_set(ndev, param->key); + if (ret) + goto out; + } if (param->indir) - yk3_rss_indir_table_set(ndev, param->indir, ndev->real_num_rx_queues); + ret = yk3_rss_indir_table_set(ndev, param->indir, ndev->real_num_rx_queues); +out: mutex_unlock(&ndev_priv->state_mlock); - return 0; + return ret; } #else static int yk3_set_rxfh(struct net_device *ndev, const u32 *indir, const u8 *key, const u8 hfunc) { struct yk3_ndev_priv *ndev_priv = netdev_priv(ndev); + int ret = 0; if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) return -EOPNOTSUPP; mutex_lock(&ndev_priv->state_mlock); - if (key) - yk3_rss_key_set(ndev, key); + if (key) { + ret = yk3_rss_key_set(ndev, key); + if (ret) + goto out; + } if (indir) - yk3_rss_indir_table_set(ndev, indir, ndev->real_num_rx_queues); + ret = yk3_rss_indir_table_set(ndev, indir, ndev->real_num_rx_queues); +out: mutex_unlock(&ndev_priv->state_mlock); - return 0; + return ret; } #endif /* YK3_HAVE_ETHTOOL_SET_RXFH_PARAM */ diff --git a/drivers/net/ethernet/yusur/yk3/yk3_rss.c b/drivers/net/ethernet/yusur/yk3/yk3_rss.c index 2eaeff805bdd..34d1644d9907 100644 --- a/drivers/net/ethernet/yusur/yk3/yk3_rss.c +++ b/drivers/net/ethernet/yusur/yk3/yk3_rss.c @@ -74,7 +74,20 @@ static void yk3_pf_hash_key_get(void __iomem *hw_addr, u8 *out) } } -void yk3_rss_indir_table_set(struct net_device *ndev, const u32 *indir, u16 qcount) +static int yk3_rss_send_msg(struct yk3_pdev_priv *pdev_priv, + struct yk3_mbox_msg *msg, + struct yk3_mbox_option *opt, + struct yk3_mbox_msg *reply) +{ + int ret = yk3_mbox_send_msg(pdev_priv, msg, opt, reply); + + if (ret == YK3_MBOX_SEND_L3_NO_ACK) + return -ETIMEDOUT; + + return ret > 0 ? -EIO : ret; +} + +int yk3_rss_indir_table_set(struct net_device *ndev, const u32 *indir, u16 qcount) { struct yk3_ndev_priv *ndev_priv = netdev_priv(ndev); struct yk3_pdev_priv *pdev_priv = ndev_priv->pdev_priv; @@ -85,6 +98,7 @@ void yk3_rss_indir_table_set(struct net_device *ndev, const u32 *indir, u16 qcou u32 i = 0, val = 0; u16 qstart = ndev_priv->qbase[YK3_QUEUE_T_GLOBAL].start; u16 q_done = 0, q_left = 0; + int ret; if (yk3_ndev_is_vf(ndev_priv)) { mbox_msg.opcode = YK3_MBOX_OPCODE_RSS_INDIRECT; @@ -98,8 +112,9 @@ void yk3_rss_indir_table_set(struct net_device *ndev, const u32 *indir, u16 qcou cmd->qstart = qstart + q_done; for (i = 0; i < 4 * cmd->qnb; i++) cmd->cmd_data[i] = (u8)(indir[4 * q_done + i] & 0xff); - if (yk3_mbox_send_msg(pdev_priv, &mbox_msg, &mbox_opt, NULL)) - return; + ret = yk3_rss_send_msg(pdev_priv, &mbox_msg, &mbox_opt, NULL); + if (ret) + return ret; q_done += cmd->qnb; } } else { @@ -109,9 +124,11 @@ void yk3_rss_indir_table_set(struct net_device *ndev, const u32 *indir, u16 qcou yk3_wr32(hw_addr, YK3_RSS_INDIRECT_BASE + 4 * qstart + i, val); } } + + return 0; } -void yk3_rss_indir_table_get(struct net_device *ndev, u32 *indir) +int yk3_rss_indir_table_get(struct net_device *ndev, u32 *indir) { struct yk3_ndev_priv *ndev_priv = netdev_priv(ndev); struct yk3_pdev_priv *pdev_priv = ndev_priv->pdev_priv; @@ -123,6 +140,7 @@ void yk3_rss_indir_table_get(struct net_device *ndev, u32 *indir) u16 q_done = 0, q_left = 0; u16 qstart = ndev_priv->qbase[YK3_QUEUE_T_GLOBAL].start; u32 qcount = ndev->real_num_rx_queues; + int ret; if (yk3_ndev_is_vf(ndev_priv)) { mbox_msg.opcode = YK3_MBOX_OPCODE_RSS_INDIRECT; @@ -136,8 +154,9 @@ void yk3_rss_indir_table_get(struct net_device *ndev, u32 *indir) q_left = qcount - q_done; cmd->qnb = min_t(u16, q_left, YK3_RSS_INDIR_Q_CHUNK_SIZE); cmd->qstart = qstart + q_done; - if (yk3_mbox_send_msg(pdev_priv, &mbox_msg, &mbox_opt, &ack_msg)) - return; + ret = yk3_rss_send_msg(pdev_priv, &mbox_msg, &mbox_opt, &ack_msg); + if (ret) + return ret; ack_cmd = (struct yk3_mbox_rss_indir_cmd *)ack_msg.data; for (i = 0; i < 4 * cmd->qnb; i++) indir[4 * q_done + i] = ack_cmd->cmd_data[i]; @@ -153,9 +172,11 @@ void yk3_rss_indir_table_get(struct net_device *ndev, u32 *indir) indir[j++] = (val >> 24) & 0xff; } } + + return 0; } -void yk3_rss_key_set(struct net_device *ndev, const u8 *key) +int yk3_rss_key_set(struct net_device *ndev, const u8 *key) { struct yk3_ndev_priv *ndev_priv = netdev_priv(ndev); struct yk3_pdev_priv *pdev_priv = ndev_priv->pdev_priv; @@ -174,13 +195,15 @@ void yk3_rss_key_set(struct net_device *ndev, const u8 *key) cmd->qstart = qstart; cmd->qnb = (u16)(qcount); memcpy(cmd->cmd_data, key, YK3_RSS_HASH_KEY_SIZE); - yk3_mbox_send_msg(pdev_priv, &mbox_msg, &mbox_opt, NULL); + return yk3_rss_send_msg(pdev_priv, &mbox_msg, &mbox_opt, NULL); } else { yk3_pf_hash_key_set(hw_addr, key); } + + return 0; } -void yk3_rss_key_get(struct net_device *ndev, u8 *key) +int yk3_rss_key_get(struct net_device *ndev, u8 *key) { struct yk3_ndev_priv *ndev_priv = netdev_priv(ndev); struct yk3_pdev_priv *pdev_priv = ndev_priv->pdev_priv; @@ -190,6 +213,7 @@ void yk3_rss_key_get(struct net_device *ndev, u8 *key) void __iomem *hw_addr = pdev_priv->bar_addr[0] + YK3_RSS_BAR_BASE; u16 qstart = ndev_priv->qbase[YK3_QUEUE_T_GLOBAL].start; u32 qcount = ndev->real_num_rx_queues; + int ret; if (yk3_ndev_is_vf(ndev_priv)) { mbox_msg.opcode = YK3_MBOX_OPCODE_RSS_INDIRECT; @@ -200,13 +224,16 @@ void yk3_rss_key_get(struct net_device *ndev, u8 *key) cmd->qnb = (u16)(qcount); mbox_opt.wait_reply = MB_WAIT_REPLY; mbox_opt.timeout = 1000; - if (!yk3_mbox_send_msg(pdev_priv, &mbox_msg, &mbox_opt, &ack_msg)) { - ack_cmd = (struct yk3_mbox_rss_indir_cmd *)ack_msg.data; - memcpy(key, ack_cmd->cmd_data, YK3_RSS_HASH_KEY_SIZE); - } + ret = yk3_rss_send_msg(pdev_priv, &mbox_msg, &mbox_opt, &ack_msg); + if (ret) + return ret; + ack_cmd = (struct yk3_mbox_rss_indir_cmd *)ack_msg.data; + memcpy(key, ack_cmd->cmd_data, YK3_RSS_HASH_KEY_SIZE); } else { yk3_pf_hash_key_get(hw_addr, key); } + + return 0; } int yk3_rss_indir_table_init(struct yk3_ndev_priv *ndev_priv, u16 rxqnum) @@ -226,7 +253,7 @@ int yk3_rss_indir_table_init(struct yk3_ndev_priv *ndev_priv, u16 rxqnum) cmd->cmd_type = YK3_CMD_RSS_INDIRECT_TABLE_INIT; cmd->qstart = qstart; cmd->qnb = rxqnum; - return yk3_mbox_send_msg(pdev_priv, &mbox_msg, &mbox_opt, NULL); + return yk3_rss_send_msg(pdev_priv, &mbox_msg, &mbox_opt, NULL); } yk3_pf_rss_indir_table_default(hw_addr, qstart, rxqnum); diff --git a/drivers/net/ethernet/yusur/yk3/yk3_rss.h b/drivers/net/ethernet/yusur/yk3/yk3_rss.h index c5cde3b8cc89..0cdf8e752f75 100644 --- a/drivers/net/ethernet/yusur/yk3/yk3_rss.h +++ b/drivers/net/ethernet/yusur/yk3/yk3_rss.h @@ -3,10 +3,10 @@ #ifndef _YK3_RSS_H_ #define _YK3_RSS_H_ -void yk3_rss_indir_table_set(struct net_device *ndev, const u32 *indir, u16 qcount); -void yk3_rss_indir_table_get(struct net_device *ndev, u32 *indir); -void yk3_rss_key_set(struct net_device *ndev, const u8 *key); -void yk3_rss_key_get(struct net_device *ndev, u8 *key); +int yk3_rss_indir_table_set(struct net_device *ndev, const u32 *indir, u16 qcount); +int yk3_rss_indir_table_get(struct net_device *ndev, u32 *indir); +int yk3_rss_key_set(struct net_device *ndev, const u8 *key); +int yk3_rss_key_get(struct net_device *ndev, u8 *key); int yk3_rss_indir_table_init(struct yk3_ndev_priv *ndev_priv, u16 rxqnum); u32 yk3_rss_key_size(void); int yk3_rss_init(struct yk3_pdev_priv *pdev_priv); -- Gitee