> 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
I'm sending v2 with this message removed.
Thanks,
Long
>
> > +
> > 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
> >