Page MenuHomeFreeBSD

D58905.diff
No OneTemporary

D58905.diff

diff --git a/share/man/man4/ice.4 b/share/man/man4/ice.4
--- a/share/man/man4/ice.4
+++ b/share/man/man4/ice.4
@@ -32,7 +32,7 @@
.\"
.\" * Other names and brands may be claimed as the property of others.
.\"
-.Dd August 11, 2026
+.Dd August 19, 2026
.Dt ICE 4
.Os
.Sh NAME
@@ -1145,6 +1145,14 @@
By default, this is set to 64.
.El
.Pp
+PF and device resets discard the hardware state of every VF.
+The driver keeps each configured VF inactive while reconstructing its VSI and
+allows it to renegotiate resources only after reconstruction succeeds.
+If one VF cannot be reconstructed, it remains configured but uninitialized
+while the PF and its sibling VFs continue recovering.
+A VF function-level reset cannot recreate this PF-owned VSI state; another PF
+or device reset, or SR-IOV configuration recreation, is required.
+.Pp
For each configured VF,
.Xr ifconfig 8
with the
diff --git a/sys/dev/ice/ice_iov.h b/sys/dev/ice/ice_iov.h
--- a/sys/dev/ice/ice_iov.h
+++ b/sys/dev/ice/ice_iov.h
@@ -70,6 +70,7 @@
VF_FLAG_PROMISC_CAP = BIT(3),
VF_FLAG_MAC_ANTI_SPOOF = BIT(4),
VF_FLAG_INITIALIZED = BIT(5),
+ VF_FLAG_REBUILD_FAILED = BIT(6),
};
/**
@@ -115,11 +116,13 @@
int ice_iov_init(struct ice_softc *sc, uint16_t num_vfs, const nvlist_t *params);
int ice_iov_add_vf(struct ice_softc *sc, uint16_t vfnum, const nvlist_t *params);
+int ice_iov_rebuild_vf(struct ice_softc *sc, struct ice_vsi *vsi);
struct if_vf_status;
int ice_iov_vf_status(struct ice_softc *sc, struct if_vf_status **statusp);
void ice_iov_uninit(struct ice_softc *sc);
void ice_iov_handle_vflr(struct ice_softc *sc);
+void ice_iov_notify_vfs_reset(struct ice_softc *sc);
void ice_vc_handle_vf_msg(struct ice_softc *sc, struct ice_rq_event_info *event);
void ice_vc_notify_all_vfs_link_state(struct ice_softc *sc);
diff --git a/sys/dev/ice/ice_iov.c b/sys/dev/ice/ice_iov.c
--- a/sys/dev/ice/ice_iov.c
+++ b/sys/dev/ice/ice_iov.c
@@ -590,6 +590,36 @@
}
}
+/**
+ * ice_iov_notify_vfs_reset - Notify initialized VFs of an impending reset
+ * @sc: device softc structure
+ *
+ * Give VF drivers advance notice while the mailbox control queue is still
+ * alive. Ignore individual send failures so one VF cannot prevent the PF from
+ * notifying its siblings or proceeding with the reset.
+ */
+void
+ice_iov_notify_vfs_reset(struct ice_softc *sc)
+{
+ struct virtchnl_pf_event event = {};
+ struct ice_hw *hw = &sc->hw;
+ struct ice_vf *vf;
+
+ if (!ice_check_sq_alive(hw, &hw->mailboxq))
+ return;
+
+ event.event = VIRTCHNL_EVENT_RESET_IMPENDING;
+ event.severity = PF_EVENT_SEVERITY_CERTAIN_DOOM;
+ for (int i = 0; i < sc->num_vfs; i++) {
+ vf = &sc->vfs[i];
+ if ((atomic_load_acq_32(&vf->vf_flags) &
+ VF_FLAG_INITIALIZED) == 0)
+ continue;
+ (void)ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_EVENT,
+ VIRTCHNL_STATUS_SUCCESS, (u8 *)&event, sizeof(event), NULL);
+ }
+}
+
/**
* ice_iov_ready_vf - Setup VF interrupts and mark it as ready
* @sc: device softc structure
@@ -619,6 +649,54 @@
ice_flush(hw);
}
+/**
+ * ice_iov_rebuild_vf - Rebuild a VF VSI after a PF or device reset
+ * @sc: device softc structure
+ * @vsi: VF VSI to rebuild
+ *
+ * PF and device resets discard the hardware VSI and interrupt state for every
+ * VF. Re-add the VSI and replay its configuration before reporting the VF as
+ * active. A failed rebuild leaves the VF inactive while allowing the PF and
+ * other VFs to recover.
+ */
+int
+ice_iov_rebuild_vf(struct ice_softc *sc, struct ice_vsi *vsi)
+{
+ struct ice_eth_stats accumulated_stats;
+ struct ice_hw *hw = &sc->hw;
+ struct ice_vf *vf;
+ int error, status;
+
+ MPASS(vsi->type == ICE_VSI_VF);
+ vf = ice_iov_get_vf(sc, vsi->vf_num);
+ atomic_clear_32(&vf->vf_flags, VF_FLAG_INITIALIZED);
+ atomic_set_32(&vf->vf_flags, VF_FLAG_REBUILD_FAILED);
+
+ /* A new hardware VSI starts a new raw statistics epoch. */
+ accumulated_stats = vsi->hw_stats.cur;
+ error = ice_initialize_vsi(vsi);
+ if (error != 0) {
+ device_printf(sc->dev,
+ "Unable to re-initialize VF %d VSI, err %s\n",
+ vf->vf_num, ice_err_str(error));
+ return (error);
+ }
+ vsi->hw_stats.cur = accumulated_stats;
+
+ status = ice_replay_vsi(hw, vsi->idx);
+ if (status != 0) {
+ device_printf(sc->dev,
+ "Failed to replay VF %d VSI, err %s aq_err %s\n",
+ vf->vf_num, ice_status_str(status),
+ ice_aq_str(hw->adminq.sq_last_status));
+ return (EIO);
+ }
+
+ atomic_clear_32(&vf->vf_flags, VF_FLAG_REBUILD_FAILED);
+ ice_iov_ready_vf(sc, vf);
+ return (0);
+}
+
/**
* ice_reset_vf - Perform a hardware reset (VFR) on a VF
* @sc: device softc structure
@@ -672,14 +750,14 @@
device_printf(sc->dev,
"VF-%d PCI transactions stuck\n", vf->vf_num);
- /* Disable TX queues, which is required during VF reset */
- status = ice_dis_vsi_txq(hw->port_info, vf->vsi->idx, 0, 0, NULL, NULL,
- NULL, ICE_VF_RESET, vf->vf_num, NULL);
+ /* This zero-queue command is required to complete every VF reset. */
+ status = ice_dis_vsi_txq(hw->port_info, vf->vsi->idx, 0, 0,
+ NULL, NULL, NULL, ICE_VF_RESET, vf->vf_num, NULL);
if (status)
device_printf(sc->dev,
- "%s: Failed to disable LAN Tx queues: err %s aq_err %s\n",
- __func__, ice_status_str(status),
- ice_aq_str(hw->adminq.sq_last_status));
+ "%s: Failed to disable LAN Tx queues: err %s aq_err %s\n",
+ __func__, ice_status_str(status),
+ ice_aq_str(hw->adminq.sq_last_status));
/* Then check for the VF reset to finish in HW */
for (i = 0; i < ICE_VPGEN_VFRSTAT_WAIT_COUNT; i++) {
@@ -693,6 +771,11 @@
device_printf(sc->dev,
"VF-%d Reset is stuck\n", vf->vf_num);
+ /* A VFR cannot recover PF-owned VSI state lost during PF rebuild. */
+ if ((atomic_load_acq_32(&vf->vf_flags) &
+ VF_FLAG_REBUILD_FAILED) != 0)
+ return;
+
ice_iov_ready_vf(sc, vf);
}
@@ -1587,6 +1670,7 @@
__func__, vf->vf_num, vqs->vsi_id, vsi->idx);
ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_GET_STATS,
VIRTCHNL_STATUS_ERR_PARAM, NULL, 0, NULL);
+ return;
}
ice_update_vsi_hw_stats(vf->vsi);
@@ -1765,6 +1849,7 @@
device_t dev = sc->dev;
struct ice_vf *vf;
int err = 0;
+ u32 vf_flags;
u32 v_opcode = event->desc.cookie_high;
u16 v_id = event->desc.retval;
@@ -1788,6 +1873,19 @@
return;
}
+ vf_flags = atomic_load_acq_32(&vf->vf_flags);
+ if ((vf_flags & VF_FLAG_ENABLED) == 0 || vf->vsi == NULL)
+ return;
+
+ /* Only a later PF rebuild can restore an invalid firmware VSI. */
+ if ((vf_flags & VF_FLAG_REBUILD_FAILED) != 0 &&
+ v_opcode != VIRTCHNL_OP_VERSION &&
+ v_opcode != VIRTCHNL_OP_RESET_VF) {
+ ice_aq_send_msg_to_vf(hw, v_id, v_opcode,
+ VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR, NULL, 0, NULL);
+ return;
+ }
+
switch (v_opcode) {
case VIRTCHNL_OP_VERSION:
ice_vc_version_msg(sc, vf, msg);
diff --git a/sys/dev/ice/ice_lib.c b/sys/dev/ice/ice_lib.c
--- a/sys/dev/ice/ice_lib.c
+++ b/sys/dev/ice/ice_lib.c
@@ -6457,6 +6457,9 @@
* interrupt on all PFs. Initiate the reset now. Preparation and
* rebuild logic will be handled by the admin status task.
*/
+#ifdef PCI_IOV
+ ice_iov_notify_vfs_reset(sc);
+#endif
status = ice_reset(hw, reset_type);
/*
@@ -7855,6 +7858,17 @@
if (!vsi)
continue;
+#ifdef PCI_IOV
+ if (vsi->type == ICE_VSI_VF) {
+ status = ice_iov_rebuild_vf(sc, vsi);
+ if (status != 0)
+ device_printf(sc->dev,
+ "Failed to rebuild VF %d VSI; leaving VF disabled\n",
+ vsi->vf_num);
+ continue;
+ }
+#endif
+
status = ice_replay_vsi(hw, vsi->idx);
if (status) {
device_printf(sc->dev, "Failed to replay VSI %d, err %s aq_err %s\n",
diff --git a/sys/dev/ice/if_ice_iflib.c b/sys/dev/ice/if_ice_iflib.c
--- a/sys/dev/ice/if_ice_iflib.c
+++ b/sys/dev/ice/if_ice_iflib.c
@@ -2529,6 +2529,11 @@
if (ice_test_state(&sc->state, ICE_STATE_RECOVERY_MODE))
return;
+#ifdef PCI_IOV
+ /* Notify initialized VFs while the mailbox queue is still available. */
+ ice_iov_notify_vfs_reset(sc);
+#endif
+
/* Restore identification while the control queues are still usable. */
ice_led_restore(sc);

File Metadata

Mime Type
text/plain
Expires
Fri, Aug 21, 6:30 PM (15 h, 21 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37045603
Default Alt Text
D58905.diff (7 KB)

Event Timeline