Re: [PATCH net-next v09 1/5] hinic3: Add ethtool queue ops

From: Harshitha Ramamurthy

Date: Fri Jun 12 2026 - 18:10:24 EST


On Wed, Jun 10, 2026 at 12:05 AM Fan Gong <gongfan1@xxxxxxxxxx> wrote:
>
> Implement following ethtool callback function:
> .get_ringparam
> .set_ringparam
>
> These callbacks allow users to utilize ethtool for detailed
> queue depth configuration and monitoring.

The patch adds a new mutex. Would be good to call it out in the commit message.

>
> Co-developed-by: Wu Di <wudi234@xxxxxxxxxx>
> Signed-off-by: Wu Di <wudi234@xxxxxxxxxx>
> Co-developed-by: Teng Peisen <tengpeisen@xxxxxxxxxx>
> Signed-off-by: Teng Peisen <tengpeisen@xxxxxxxxxx>
> Signed-off-by: Fan Gong <gongfan1@xxxxxxxxxx>
> ---
> .../ethernet/huawei/hinic3/hinic3_ethtool.c | 93 ++++++++++++++++
> .../net/ethernet/huawei/hinic3/hinic3_irq.c | 5 +-
> .../net/ethernet/huawei/hinic3/hinic3_main.c | 6 +
> .../huawei/hinic3/hinic3_netdev_ops.c | 104 ++++++++++++++++--
> .../ethernet/huawei/hinic3/hinic3_nic_dev.h | 9 ++
> .../ethernet/huawei/hinic3/hinic3_nic_io.c | 4 +-
> .../ethernet/huawei/hinic3/hinic3_nic_io.h | 8 +-
> .../net/ethernet/huawei/hinic3/hinic3_rx.c | 2 +-
> 8 files changed, 217 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c b/drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c
> index 90fc16288de9..be9992a235f7 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c
> @@ -9,6 +9,7 @@
> #include <linux/errno.h>
> #include <linux/etherdevice.h>
> #include <linux/netdevice.h>
> +#include <linux/netlink.h>
> #include <linux/ethtool.h>
>
> #include "hinic3_lld.h"
> @@ -409,6 +410,96 @@ hinic3_get_link_ksettings(struct net_device *netdev,
> return 0;
> }
>
> +static void hinic3_get_ringparam(struct net_device *netdev,
> + struct ethtool_ringparam *ring,
> + struct kernel_ethtool_ringparam *kernel_ring,
> + struct netlink_ext_ack *extack)
> +{
> + struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
> +
> + ring->rx_max_pending = HINIC3_MAX_RX_QUEUE_DEPTH;
> + ring->tx_max_pending = HINIC3_MAX_TX_QUEUE_DEPTH;
> + ring->rx_pending = nic_dev->q_params.rq_depth;
> + ring->rx_pending = nic_dev->q_params.sq_depth;

copy-paste error

> +}
> +
> +static void hinic3_update_qp_depth(struct net_device *netdev,
> + u32 sq_depth, u32 rq_depth)
> +{
> + struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
> + u16 i;
> +
> + nic_dev->q_params.sq_depth = sq_depth;
> + nic_dev->q_params.rq_depth = rq_depth;
> + for (i = 0; i < nic_dev->max_qps; i++) {
> + nic_dev->txqs[i].q_depth = sq_depth;
> + nic_dev->txqs[i].q_mask = sq_depth - 1;
> + nic_dev->rxqs[i].q_depth = rq_depth;
> + nic_dev->rxqs[i].q_mask = rq_depth - 1;
> + }
> +}
> +
> +static int hinic3_check_ringparam_valid(struct net_device *netdev,
> + const struct ethtool_ringparam *ring,
> + struct netlink_ext_ack *extack)
> +{
> + if (ring->tx_pending < HINIC3_MIN_QUEUE_DEPTH ||
> + ring->rx_pending < HINIC3_MIN_QUEUE_DEPTH) {
> + NL_SET_ERR_MSG_FMT_MOD(extack,
> + "Queue depth out of range tx[%d-%d] rx[%d-%d]",
> + HINIC3_MIN_QUEUE_DEPTH,
> + HINIC3_MAX_TX_QUEUE_DEPTH,
> + HINIC3_MIN_QUEUE_DEPTH,
> + HINIC3_MAX_RX_QUEUE_DEPTH);

Consider updating this error message to only call out when the ring
sizes are below the minimum supported value - since that's the check
introduced here and also since ethtool core will reject any values
that are higher than the maximum supported ring sizes.

> +
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int hinic3_set_ringparam(struct net_device *netdev,
> + struct ethtool_ringparam *ring,
> + struct kernel_ethtool_ringparam *kernel_ring,
> + struct netlink_ext_ack *extack)
> +{
> + struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
> + struct hinic3_dyna_txrxq_params q_params = {};
> + u32 new_sq_depth, new_rq_depth;
> + int err;
> +
> + err = hinic3_check_ringparam_valid(netdev, ring, extack);
> + if (err)
> + return err;
> +
> + new_sq_depth = 1U << ilog2(ring->tx_pending);
> + new_rq_depth = 1U << ilog2(ring->rx_pending);

Why not use rounddown_pow_of_two()? More readable...

> + if (new_sq_depth == nic_dev->q_params.sq_depth &&
> + new_rq_depth == nic_dev->q_params.rq_depth)
> + return 0;
> +
> + if (new_sq_depth != ring->tx_pending ||
> + new_rq_depth != ring->rx_pending)
> + NL_SET_ERR_MSG_FMT_MOD(extack,
> + "Requested Tx/Rx ring depth %u/%u trimmed to %u/%u",
> + ring->tx_pending, ring->rx_pending,
> + new_sq_depth, new_rq_depth);
> +
> + if (!netif_running(netdev)) {
> + hinic3_update_qp_depth(netdev, new_sq_depth, new_rq_depth);
> + } else {
> + q_params = nic_dev->q_params;
> + q_params.sq_depth = new_sq_depth;
> + q_params.rq_depth = new_rq_depth;
> +
> + err = hinic3_change_channel_settings(netdev, &q_params);
> + if (err)
> + return err;
> + }
> +
> + return 0;
> +}
> +
> static const struct ethtool_ops hinic3_ethtool_ops = {
> .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
> ETHTOOL_COALESCE_PKT_RATE_RX_USECS,
> @@ -417,6 +508,8 @@ static const struct ethtool_ops hinic3_ethtool_ops = {
> .get_msglevel = hinic3_get_msglevel,
> .set_msglevel = hinic3_set_msglevel,
> .get_link = ethtool_op_get_link,
> + .get_ringparam = hinic3_get_ringparam,
> + .set_ringparam = hinic3_set_ringparam,
> };
>
> void hinic3_set_ethtool_ops(struct net_device *netdev)
> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c b/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c
> index e7d6c2033b45..bc4d879f9be4 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c
> @@ -137,7 +137,8 @@ static int hinic3_set_interrupt_moder(struct net_device *netdev, u16 q_id,
> struct hinic3_interrupt_info info = {};
> int err;
>
> - if (q_id >= nic_dev->q_params.num_qps)
> + if (q_id >= nic_dev->q_params.num_qps ||
> + !mutex_trylock(&nic_dev->change_res_mutex))
> return 0;
>
> info.interrupt_coalesc_set = 1;
> @@ -156,6 +157,8 @@ static int hinic3_set_interrupt_moder(struct net_device *netdev, u16 q_id,
> nic_dev->rxqs[q_id].last_pending_limit = pending_limit;
> }
>
> + mutex_unlock(&nic_dev->change_res_mutex);
> +
> return err;
> }
>
> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
> index 0a888fe4c975..c87624a5e5dc 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c
> @@ -179,6 +179,7 @@ static int hinic3_sw_init(struct net_device *netdev)
> int err;
>
> mutex_init(&nic_dev->port_state_mutex);
> + mutex_init(&nic_dev->change_res_mutex);
>
> nic_dev->q_params.sq_depth = HINIC3_SQ_DEPTH;
> nic_dev->q_params.rq_depth = HINIC3_RQ_DEPTH;
> @@ -315,6 +316,9 @@ static void hinic3_link_status_change(struct net_device *netdev,
> {
> struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
>
> + if (!mutex_trylock(&nic_dev->change_res_mutex))
> + return;
> +
> if (link_status_up) {
> if (netif_carrier_ok(netdev))
> return;
> @@ -330,6 +334,8 @@ static void hinic3_link_status_change(struct net_device *netdev,
> netif_carrier_off(netdev);
> netdev_dbg(netdev, "Link is down\n");
> }
> +
> + mutex_unlock(&nic_dev->change_res_mutex);
> }
>
> static void hinic3_port_module_event_handler(struct net_device *netdev,
> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
> index da73811641a9..047214cfc753 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c
> @@ -288,7 +288,8 @@ static void hinic3_free_channel_resources(struct net_device *netdev,
> hinic3_free_qps(nic_dev, qp_params);
> }
>
> -static int hinic3_open_channel(struct net_device *netdev)
> +static int hinic3_prepare_channel(struct net_device *netdev,
> + struct hinic3_dyna_txrxq_params *qp_params)
> {
> struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
> int err;
> @@ -299,16 +300,28 @@ static int hinic3_open_channel(struct net_device *netdev)
> return err;
> }
>
> - err = hinic3_configure_txrxqs(netdev, &nic_dev->q_params);
> + err = hinic3_configure_txrxqs(netdev, qp_params);
> if (err) {
> netdev_err(netdev, "Failed to configure txrxqs\n");
> goto err_free_qp_ctxts;
> }
>
> + return 0;
> +
> +err_free_qp_ctxts:
> + hinic3_free_qp_ctxts(nic_dev);
> +
> + return err;
> +}
> +
> +static int hinic3_open_channel(struct net_device *netdev)
> +{
> + int err;
> +
> err = hinic3_qps_irq_init(netdev);
> if (err) {
> netdev_err(netdev, "Failed to init txrxq irq\n");
> - goto err_free_qp_ctxts;
> + return err;
> }
>
> err = hinic3_configure(netdev);
> @@ -321,8 +334,6 @@ static int hinic3_open_channel(struct net_device *netdev)
>
> err_uninit_qps_irq:
> hinic3_qps_irq_uninit(netdev);
> -err_free_qp_ctxts:
> - hinic3_free_qp_ctxts(nic_dev);
>
> return err;
> }
> @@ -428,6 +439,74 @@ static void hinic3_vport_down(struct net_device *netdev)
> }
> }
>
> +int
> +hinic3_change_channel_settings(struct net_device *netdev,
> + struct hinic3_dyna_txrxq_params *trxq_params)
> +{
> + struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
> + struct hinic3_dyna_txrxq_params cur_trxq_params = {};
> + struct hinic3_dyna_qp_params new_qp_params = {};
> + struct hinic3_dyna_qp_params cur_qp_params = {};
> + int err;
> +
> + cur_trxq_params = nic_dev->q_params;
> +
> + hinic3_config_num_qps(netdev, trxq_params);
> +
> + err = hinic3_alloc_channel_resources(netdev, &new_qp_params,
> + trxq_params);
> + if (err) {
> + netdev_err(netdev, "Failed to alloc channel resources\n");
> + return err;
> + }
> +
> + mutex_lock(&nic_dev->change_res_mutex);
> + hinic3_vport_down(netdev);
> + hinic3_close_channel(netdev);
> + hinic3_get_cur_qps(nic_dev, &cur_qp_params);
> +
> + hinic3_init_qps(nic_dev, &new_qp_params);
> +
> + err = hinic3_prepare_channel(netdev, trxq_params);
> + if (err)
> + goto err_uninit_qps;
> +
> + if (nic_dev->num_qp_irq > trxq_params->num_qps)
> + hinic3_qp_irq_change(netdev, trxq_params->num_qps);
> +
> + nic_dev->q_params = *trxq_params;
> +
> + err = hinic3_open_channel(netdev);
> + if (err)
> + goto err_qp_irq_reset;
> +
> + err = hinic3_vport_up(netdev);
> + if (err)
> + goto err_close_channel;
> +
> + hinic3_free_channel_resources(netdev, &cur_qp_params, &cur_trxq_params);
> +
> + mutex_unlock(&nic_dev->change_res_mutex);
> +
> + return 0;
> +
> +err_close_channel:
> + hinic3_close_channel(netdev);
> +err_qp_irq_reset:
> + nic_dev->q_params = cur_trxq_params;
> +
> + if (trxq_params->num_qps > cur_trxq_params.num_qps)
> + hinic3_qp_irq_change(netdev, cur_trxq_params.num_qps);
> + hinic3_free_qp_ctxts(nic_dev);
> +err_uninit_qps:
> + hinic3_get_cur_qps(nic_dev, &new_qp_params);
> + hinic3_free_channel_resources(netdev, &new_qp_params, trxq_params);
> + hinic3_free_channel_resources(netdev, &cur_qp_params, &cur_trxq_params);
> + mutex_unlock(&nic_dev->change_res_mutex);
> +
> + return err;
> +}
> +
> static int hinic3_open(struct net_device *netdev)
> {
> struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
> @@ -458,6 +537,10 @@ static int hinic3_open(struct net_device *netdev)
>
> hinic3_init_qps(nic_dev, &qp_params);
>
> + err = hinic3_prepare_channel(netdev, &nic_dev->q_params);
> + if (err)
> + goto err_uninit_qps;
> +
> err = hinic3_open_channel(netdev);
> if (err)
> goto err_uninit_qps;
> @@ -473,7 +556,7 @@ static int hinic3_open(struct net_device *netdev)
> err_close_channel:
> hinic3_close_channel(netdev);
> err_uninit_qps:
> - hinic3_uninit_qps(nic_dev, &qp_params);
> + hinic3_get_cur_qps(nic_dev, &qp_params);
> hinic3_free_channel_resources(netdev, &qp_params, &nic_dev->q_params);
> err_destroy_num_qps:
> hinic3_destroy_num_qps(netdev);
> @@ -493,10 +576,15 @@ static int hinic3_close(struct net_device *netdev)
> return 0;
> }
>
> + mutex_lock(&nic_dev->change_res_mutex);
> hinic3_vport_down(netdev);
> hinic3_close_channel(netdev);
> - hinic3_uninit_qps(nic_dev, &qp_params);
> - hinic3_free_channel_resources(netdev, &qp_params, &nic_dev->q_params);
> + hinic3_get_cur_qps(nic_dev, &qp_params);
> + hinic3_free_channel_resources(netdev, &qp_params,
> + &nic_dev->q_params);
> + hinic3_free_nicio_res(nic_dev);
> + hinic3_destroy_num_qps(netdev);
> + mutex_unlock(&nic_dev->change_res_mutex);
>
> return 0;
> }
> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h
> index 9502293ff710..005b2c01a988 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h
> @@ -10,6 +10,9 @@
> #include "hinic3_hw_cfg.h"
> #include "hinic3_hwdev.h"
> #include "hinic3_mgmt_interface.h"
> +#include "hinic3_nic_io.h"
> +#include "hinic3_tx.h"
> +#include "hinic3_rx.h"
>
> #define HINIC3_VLAN_BITMAP_BYTE_SIZE(nic_dev) (sizeof(*(nic_dev)->vlan_bitmap))
> #define HINIC3_VLAN_BITMAP_SIZE(nic_dev) \
> @@ -129,6 +132,8 @@ struct hinic3_nic_dev {
> struct work_struct rx_mode_work;
> /* lock for enable/disable port */
> struct mutex port_state_mutex;
> + /* mutex to serialize channel/resource changes */
> + struct mutex change_res_mutex;
>
> struct list_head uc_filter_list;
> struct list_head mc_filter_list;
> @@ -143,6 +148,10 @@ struct hinic3_nic_dev {
>
> void hinic3_set_netdev_ops(struct net_device *netdev);
> int hinic3_set_hw_features(struct net_device *netdev);
> +int
> +hinic3_change_channel_settings(struct net_device *netdev,
> + struct hinic3_dyna_txrxq_params *trxq_params);
> +
> int hinic3_qps_irq_init(struct net_device *netdev);
> void hinic3_qps_irq_uninit(struct net_device *netdev);
>
> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_io.c b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_io.c
> index 87e736adba02..0e7a0ccfba98 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_io.c
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_io.c
> @@ -484,8 +484,8 @@ void hinic3_init_qps(struct hinic3_nic_dev *nic_dev,
> }
> }
>
> -void hinic3_uninit_qps(struct hinic3_nic_dev *nic_dev,
> - struct hinic3_dyna_qp_params *qp_params)
> +void hinic3_get_cur_qps(struct hinic3_nic_dev *nic_dev,
> + struct hinic3_dyna_qp_params *qp_params)
> {
> struct hinic3_nic_io *nic_io = nic_dev->nic_io;
>
> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_io.h b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_io.h
> index 12eefabcf1db..571b34d63950 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_io.h
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_io.h
> @@ -14,6 +14,10 @@ struct hinic3_nic_dev;
> #define HINIC3_RQ_WQEBB_SHIFT 3
> #define HINIC3_SQ_WQEBB_SIZE BIT(HINIC3_SQ_WQEBB_SHIFT)
>
> +#define HINIC3_MAX_TX_QUEUE_DEPTH 65536
> +#define HINIC3_MAX_RX_QUEUE_DEPTH 16384
> +#define HINIC3_MIN_QUEUE_DEPTH 128
> +
> /* ******************** RQ_CTRL ******************** */
> enum hinic3_rq_wqe_type {
> HINIC3_NORMAL_RQ_WQE = 1,
> @@ -136,8 +140,8 @@ void hinic3_free_qps(struct hinic3_nic_dev *nic_dev,
> struct hinic3_dyna_qp_params *qp_params);
> void hinic3_init_qps(struct hinic3_nic_dev *nic_dev,
> struct hinic3_dyna_qp_params *qp_params);
> -void hinic3_uninit_qps(struct hinic3_nic_dev *nic_dev,
> - struct hinic3_dyna_qp_params *qp_params);
> +void hinic3_get_cur_qps(struct hinic3_nic_dev *nic_dev,
> + struct hinic3_dyna_qp_params *qp_params);
>
> int hinic3_init_qp_ctxts(struct hinic3_nic_dev *nic_dev);
> void hinic3_free_qp_ctxts(struct hinic3_nic_dev *nic_dev);
> diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_rx.c b/drivers/net/ethernet/huawei/hinic3/hinic3_rx.c
> index 309ab5901379..b5b601469517 100644
> --- a/drivers/net/ethernet/huawei/hinic3/hinic3_rx.c
> +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_rx.c
> @@ -541,7 +541,7 @@ int hinic3_configure_rxqs(struct net_device *netdev, u16 num_rq,
> rq_associate_cqes(rxq);
>
> pkts = hinic3_rx_fill_buffers(rxq);
> - if (!pkts) {
> + if (pkts < rxq->q_depth - 1) {
> netdev_err(netdev, "Failed to fill Rx buffer\n");
> return -ENOMEM;
> }
> --
> 2.43.0
>
>