[PATCH net-next v10 12/12] enic: re-establish V2 VF admin channel and PF registration after reset

From: Satish Kharat

Date: Mon Jun 29 2026 - 13:33:25 EST


The reset paths (enic_reset/enic_tx_hang_reset) tore down and re-opened
the V2 admin/MBOX channel only for the PF: the close/reopen was gated on
enic_sriov_enabled() && vf_type == ENIC_VF_TYPE_V2, which is never true on
a VF (vf_type is set only on the PF; VFs are identified by
enic_is_sriov_vf_v2()). A VF-initiated reset therefore left the VF admin
QP wiped by the reset but never re-opened, and the VF never re-registered
with the PF, so VF<->PF MBOX traffic (link state, MAC, packet filter)
stopped working until the VF was re-probed.

Factor the decision into enic_has_admin_chan() (true for a V2 PF while
SR-IOV is enabled and for every V2 VF) and the reopen sequence into
enic_admin_chan_reopen(). For a VF the helper additionally re-runs the
probe-time handshake (enic_mbox_vf_capability_check() +
enic_mbox_vf_register()) so the PF learns about the VF again; for a PF it
re-pushes the current link state as before.

Signed-off-by: Satish Kharat <satishkh@xxxxxxxxx>
---
drivers/net/ethernet/cisco/enic/enic_main.c | 105 +++++++++++++++++-----------
1 file changed, 65 insertions(+), 40 deletions(-)

diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c
index abb30e5457c1..de90332dc40c 100644
--- a/drivers/net/ethernet/cisco/enic/enic_main.c
+++ b/drivers/net/ethernet/cisco/enic/enic_main.c
@@ -2171,6 +2171,57 @@ static void enic_set_api_busy(struct enic *enic, bool busy)
spin_unlock(&enic->enic_api_lock);
}

+/* The admin/MBOX channel exists on a V2 PF while SR-IOV is enabled and on
+ * every V2 VF. A reset wipes the admin WQ/RQ/CQ, so such devices must tear
+ * the channel down before the reset and re-establish it afterwards.
+ */
+static bool enic_has_admin_chan(struct enic *enic)
+{
+ return enic_is_sriov_vf_v2(enic) ||
+ (enic_sriov_enabled(enic) && enic->vf_type == ENIC_VF_TYPE_V2);
+}
+
+/* Re-establish the admin/MBOX channel after a reset has re-created the data
+ * path. Mirrors the relevant part of the probe / SR-IOV-enable sequence:
+ * reopen the channel and reinitialise MBOX, then for a VF re-run the PF
+ * handshake (its admin QP and PF-side registration were torn down by the
+ * reset), or for a PF re-push the current link state to registered VFs.
+ */
+static void enic_admin_chan_reopen(struct enic *enic)
+{
+ int err;
+
+ err = enic_admin_channel_open(enic);
+ if (err) {
+ netdev_err(enic->netdev,
+ "admin channel reopen after reset failed: %d\n", err);
+ return;
+ }
+
+ enic_mbox_init(enic);
+
+ if (enic_is_sriov_vf_v2(enic)) {
+ err = enic_mbox_vf_capability_check(enic);
+ if (err) {
+ netdev_err(enic->netdev,
+ "MBOX capability check after reset failed: %d\n",
+ err);
+ return;
+ }
+ err = enic_mbox_vf_register(enic);
+ if (err)
+ netdev_err(enic->netdev,
+ "MBOX VF re-registration after reset failed: %d\n",
+ err);
+ } else {
+ /* The link came back up during enic_open() above while MBOX
+ * sends were still disabled (channel not yet reopened), so that
+ * link-notify was dropped. Re-push current link state now.
+ */
+ schedule_work(&enic->link_notify_work);
+ }
+}
+
static void enic_reset(struct work_struct *work)
{
struct enic *enic = container_of(work, struct enic, reset);
@@ -2189,8 +2240,7 @@ static void enic_reset(struct work_struct *work)
* DMAs from the about-to-be-reset rings) and frees the admin resources
* so they are cleanly re-allocated afterwards.
*/
- if (enic_sriov_enabled(enic) &&
- enic->vf_type == ENIC_VF_TYPE_V2)
+ if (enic_has_admin_chan(enic))
enic_admin_channel_close(enic);

enic_stop(enic->netdev);
@@ -2204,25 +2254,13 @@ static void enic_reset(struct work_struct *work)

enic_open(enic->netdev);

- /* Re-establish the admin/MBOX channel after the data path is back up,
- * mirroring the SR-IOV enable path (channel open + mbox init). The
- * channel was fully torn down by enic_admin_channel_close() above.
+ /* Re-establish the admin/MBOX channel after the data path is back up.
+ * It was fully torn down by enic_admin_channel_close() above;
+ * enic_admin_chan_reopen() reopens it and, for a PF re-pushes link
+ * state, or for a VF re-runs the probe-time PF handshake.
*/
- if (enic_sriov_enabled(enic) &&
- enic->vf_type == ENIC_VF_TYPE_V2) {
- if (enic_admin_channel_open(enic)) {
- netdev_err(enic->netdev,
- "admin channel reopen after reset failed\n");
- } else {
- enic_mbox_init(enic);
- /* The link came back up during enic_open() above
- * while MBOX sends were still disabled (channel not
- * yet reopened), so that link-notify was dropped.
- * Re-push current link state to registered VFs now.
- */
- schedule_work(&enic->link_notify_work);
- }
- }
+ if (enic_has_admin_chan(enic))
+ enic_admin_chan_reopen(enic);

/* Allow infiniband to fiddle with the device again */
enic_set_api_busy(enic, false);
@@ -2245,8 +2283,7 @@ static void enic_tx_hang_reset(struct work_struct *work)
* the same reason as the soft reset path: stop the admin QP and free
* the admin resources before the hardware queues are wiped.
*/
- if (enic_sriov_enabled(enic) &&
- enic->vf_type == ENIC_VF_TYPE_V2)
+ if (enic_has_admin_chan(enic))
enic_admin_channel_close(enic);

enic_dev_hang_notify(enic);
@@ -2261,25 +2298,13 @@ static void enic_tx_hang_reset(struct work_struct *work)

enic_open(enic->netdev);

- /* Re-establish the admin/MBOX channel after the data path is back up,
- * mirroring the SR-IOV enable path (channel open + mbox init). The
- * channel was fully torn down by enic_admin_channel_close() above.
+ /* Re-establish the admin/MBOX channel after the data path is back up.
+ * It was fully torn down by enic_admin_channel_close() above;
+ * enic_admin_chan_reopen() reopens it and, for a PF re-pushes link
+ * state, or for a VF re-runs the probe-time PF handshake.
*/
- if (enic_sriov_enabled(enic) &&
- enic->vf_type == ENIC_VF_TYPE_V2) {
- if (enic_admin_channel_open(enic)) {
- netdev_err(enic->netdev,
- "admin channel reopen after reset failed\n");
- } else {
- enic_mbox_init(enic);
- /* The link came back up during enic_open() above
- * while MBOX sends were still disabled (channel not
- * yet reopened), so that link-notify was dropped.
- * Re-push current link state to registered VFs now.
- */
- schedule_work(&enic->link_notify_work);
- }
- }
+ if (enic_has_admin_chan(enic))
+ enic_admin_chan_reopen(enic);

/* Allow infiniband to fiddle with the device again */
enic_set_api_busy(enic, false);

--
2.43.0