On Fri, Mar 20, 2026 at 05:28:42PM -0700, Long Li wrote:
> When an RSS QP is destroyed (e.g. DPDK exit), mana_ib_destroy_qp_rss()
> destroys the RX WQ objects but does not disable vPort RX steering in
> firmware. This leaves stale steering configuration that still points to
> the destroyed RX objects.
> 
> If traffic continues to arrive (e.g. peer VM is still transmitting) and
> the VF interface is subsequently brought up (mana_open), the firmware
> may deliver completions using stale CQ IDs from the old RX objects.
> These CQ IDs can be reused by the ethernet driver for new TX CQs,
> causing RX completions to land on TX CQs:
> 
>   WARNING: mana_poll_tx_cq+0x1b8/0x220 [mana]  (is_sq == false)
>   WARNING: mana_gd_process_eq_events+0x209/0x290 (cq_table lookup fails)
> 
> Fix this by disabling vPort RX steering before destroying RX WQ objects.
> Note that mana_fence_rqs() cannot be used here because the fence
> completion is delivered on the CQ, which is polled by user-mode (e.g.
> DPDK) and not visible to the kernel driver.
> 
> Refactor the disable logic into a shared mana_disable_vport_rx() in
> mana_en, exported for use by mana_ib, replacing the duplicate code.
> The ethernet driver's mana_dealloc_queues() is also updated to call
> this common function.
> 
> Fixes: 0266a177631d ("RDMA/mana_ib: Add a driver for Microsoft Azure Network 
> Adapter")
> Cc: [email protected]
> Signed-off-by: Long Li <[email protected]>
> ---
>  drivers/infiniband/hw/mana/qp.c               | 17 ++++++++++++++++-
>  drivers/net/ethernet/microsoft/mana/mana_en.c | 11 ++++++++++-
>  include/net/mana/mana.h                       |  1 +
>  3 files changed, 27 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/infiniband/hw/mana/qp.c b/drivers/infiniband/hw/mana/qp.c
> index 80cf4ade4b75..b27084c53a14 100644
> --- a/drivers/infiniband/hw/mana/qp.c
> +++ b/drivers/infiniband/hw/mana/qp.c
> @@ -829,11 +829,26 @@ static int mana_ib_destroy_qp_rss(struct mana_ib_qp *qp,
>       struct net_device *ndev;
>       struct mana_ib_wq *wq;
>       struct ib_wq *ibwq;
> -     int i;
> +     int i, err;
>  
>       ndev = mana_ib_get_netdev(qp->ibqp.device, qp->port);
>       mpc = netdev_priv(ndev);
>  
> +     /* Disable vPort RX steering before destroying RX WQ objects.
> +      * Otherwise firmware still routes traffic to the destroyed queues,
> +      * which can cause bogus completions on reused CQ IDs when the
> +      * ethernet driver later creates new queues on mana_open().
> +      *
> +      * Unlike the ethernet teardown path, mana_fence_rqs() cannot be
> +      * used here because the fence completion CQE is delivered on the
> +      * CQ which is polled by userspace (e.g. DPDK), so there is no way
> +      * for the kernel to wait for fence completion.
> +      */
> +     err = mana_disable_vport_rx(mpc);
> +     if (err)
> +             ibdev_err(&mdev->ib_dev,
> +                       "Failed to disable vPort RX: %d\n", err);

mana_cfg_vport_steering() is already prints in all failure scenarios.

Thanks

> +
>       for (i = 0; i < (1 << ind_tbl->log_ind_tbl_size); i++) {
>               ibwq = ind_tbl->ind_tbl[i];
>               wq = container_of(ibwq, struct mana_ib_wq, ibwq);
> diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c 
> b/drivers/net/ethernet/microsoft/mana/mana_en.c
> index 22444c7530a5..51719ef1c09b 100644
> --- a/drivers/net/ethernet/microsoft/mana/mana_en.c
> +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
> @@ -2934,6 +2934,13 @@ static void mana_rss_table_init(struct 
> mana_port_context *apc)
>                       ethtool_rxfh_indir_default(i, apc->num_queues);
>  }
>  
> +int mana_disable_vport_rx(struct mana_port_context *apc)
> +{
> +     return mana_cfg_vport_steering(apc, TRI_STATE_FALSE, false, false,
> +                                    false);
> +}
> +EXPORT_SYMBOL_NS(mana_disable_vport_rx, "NET_MANA");
> +
>  int mana_config_rss(struct mana_port_context *apc, enum TRI_STATE rx,
>                   bool update_hash, bool update_tab)
>  {
> @@ -3339,10 +3346,12 @@ static int mana_dealloc_queues(struct net_device 
> *ndev)
>        */
>  
>       apc->rss_state = TRI_STATE_FALSE;
> -     err = mana_config_rss(apc, TRI_STATE_FALSE, false, false);
> +     err = mana_disable_vport_rx(apc);
>       if (err && mana_en_need_log(apc, err))
>               netdev_err(ndev, "Failed to disable vPort: %d\n", err);
>  
> +     mana_fence_rqs(apc);
> +
>       /* Even in err case, still need to cleanup the vPort */
>       mana_destroy_rxqs(apc);
>       mana_destroy_txq(apc);
> diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h
> index 204c2b612a62..2634e9135eed 100644
> --- a/include/net/mana/mana.h
> +++ b/include/net/mana/mana.h
> @@ -574,6 +574,7 @@ struct mana_port_context {
>  netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev);
>  int mana_config_rss(struct mana_port_context *ac, enum TRI_STATE rx,
>                   bool update_hash, bool update_tab);
> +int mana_disable_vport_rx(struct mana_port_context *apc);
>  
>  int mana_alloc_queues(struct net_device *ndev);
>  int mana_attach(struct net_device *ndev);
> -- 
> 2.43.0
> 

Reply via email to