Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F167825801
D59024.id184427.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D59024.id184427.diff
View Options
Index: sys/dev/ice/ice_iov.h
===================================================================
--- sys/dev/ice/ice_iov.h
+++ sys/dev/ice/ice_iov.h
@@ -132,6 +132,7 @@
void ice_iov_handle_vflr(struct ice_softc *sc);
void ice_iov_notify_vfs_reset(struct ice_softc *sc);
+int ice_iov_quiesce_vfs_for_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);
Index: sys/dev/ice/ice_iov.c
===================================================================
--- sys/dev/ice/ice_iov.c
+++ sys/dev/ice/ice_iov.c
@@ -72,7 +72,7 @@
static void ice_iov_clear_vf_queue_state(struct ice_vf *vf);
static void ice_iov_ready_vf(struct ice_softc *sc, struct ice_vf *vf);
static int ice_reset_vf(struct ice_softc *sc, struct ice_vf *vf,
- bool trigger_vflr);
+ bool trigger_reset, bool release_vf);
static void ice_iov_setup_intr_mapping(struct ice_softc *sc, struct ice_vf *vf);
static void ice_vc_version_msg(struct ice_softc *sc, struct ice_vf *vf,
@@ -739,7 +739,7 @@
{
struct ice_hw *hw = &sc->hw;
struct ice_vf *vf;
- u32 reg, reg_idx, bit_idx;
+ u32 reg, reg_idx, bit_idx, vf_flags;
for (int i = 0; i < sc->num_vfs; i++) {
vf = &sc->vfs[i];
@@ -749,9 +749,15 @@
reg = rd32(hw, GLGEN_VFLRSTAT(reg_idx));
if ((reg & BIT(bit_idx)) == 0)
continue;
- if ((atomic_load_acq_32(&vf->vf_flags) &
- VF_FLAG_ENABLED) != 0 && vf->vsi != NULL) {
- ice_reset_vf(sc, vf, false);
+ vf_flags = atomic_load_acq_32(&vf->vf_flags);
+ if ((vf_flags & VF_FLAG_ENABLED) != 0 && vf->vsi != NULL) {
+ if ((vf_flags & VF_FLAG_REBUILD_FAILED) != 0) {
+ /* Consume the event but leave the invalid VF held. */
+ wr32(hw, GLGEN_VFLRSTAT(reg_idx), BIT(bit_idx));
+ ice_flush(hw);
+ continue;
+ }
+ ice_reset_vf(sc, vf, false, true);
continue;
}
@@ -899,56 +905,43 @@
* ice_reset_vf - Perform a hardware reset (VFR) on a VF
* @sc: device softc structure
* @vf: driver's VF structure for VF to be reset
- * @trigger_vflr: trigger a reset or only handle already executed reset
+ * @trigger_reset: trigger a reset or only handle an already executed reset
+ * @release_vf: publish VFACTIVE after reset; otherwise leave the VF held
*
* Performs a VFR for the given VF. This function busy waits until the reset
* completes in the HW and publishes VFACTIVE only after every mandatory
- * reset stage succeeds.
+ * reset stage succeeds. In quiesce mode, it returns with VFSWR asserted and
+ * without restoring interrupt mappings or publishing VFACTIVE.
*
- * @remark This also sets up the PF<->VF interrupt mapping and allocations in
- * the hardware after the hardware reset is finished, via
+ * @remark Release mode also sets up the PF<->VF interrupt mapping and
+ * allocations in the hardware after the hardware reset is finished, via
* ice_iov_setup_intr_mapping()
*/
static int
-ice_reset_vf(struct ice_softc *sc, struct ice_vf *vf, bool trigger_vflr)
+ice_reset_vf(struct ice_softc *sc, struct ice_vf *vf, bool trigger_reset,
+ bool release_vf)
{
u16 global_vf_num, reg_idx, bit_idx;
struct ice_hw *hw = &sc->hw;
+ bool reset_done;
int error, status;
u32 reg;
- int i;
+ int bit, i;
+
+ /* A VFR cannot recover PF-owned VSI state lost during PF rebuild. */
+ if (release_vf && (atomic_load_acq_32(&vf->vf_flags) &
+ VF_FLAG_REBUILD_FAILED) != 0)
+ return (EIO);
global_vf_num = vf->vf_num + hw->func_caps.vf_base_id;
atomic_clear_32(&vf->vf_flags, VF_FLAG_INITIALIZED);
error = 0;
- if (trigger_vflr) {
+ if (trigger_reset) {
reg = rd32(hw, VPGEN_VFRTRIG(vf->vf_num));
reg |= VPGEN_VFRTRIG_VFSWR_M;
wr32(hw, VPGEN_VFRTRIG(vf->vf_num), reg);
- }
-
- /* clear the VFLR bit for the VF in a GLGEN_VFLRSTAT register */
- reg_idx = (global_vf_num) / 32;
- bit_idx = (global_vf_num) % 32;
- wr32(hw, GLGEN_VFLRSTAT(reg_idx), BIT(bit_idx));
- ice_flush(hw);
-
- /* Wait until there are no pending PCI transactions */
- wr32(hw, PF_PCI_CIAA,
- ICE_PCIE_DEV_STATUS | (global_vf_num << PF_PCI_CIAA_VF_NUM_S));
-
- for (i = 0; i < ICE_PCI_CIAD_WAIT_COUNT; i++) {
- reg = rd32(hw, PF_PCI_CIAD);
- if (!(reg & PCIEM_STA_TRANSACTION_PND))
- break;
-
- DELAY(ICE_PCI_CIAD_WAIT_DELAY_US);
- }
- if (i == ICE_PCI_CIAD_WAIT_COUNT) {
- device_printf(sc->dev,
- "VF-%d PCI transactions stuck\n", vf->vf_num);
- error = ETIMEDOUT;
+ ice_flush(hw);
}
/*
@@ -974,19 +967,56 @@
error = EIO;
}
- /* Then check for the VF reset to finish in HW */
+ /* Then check for the VF reset to finish in HW. */
+ reset_done = false;
for (i = 0; i < ICE_VPGEN_VFRSTAT_WAIT_COUNT; i++) {
reg = rd32(hw, VPGEN_VFRSTAT(vf->vf_num));
- if ((reg & VPGEN_VFRSTAT_VFRD_M))
+ if ((reg & VPGEN_VFRSTAT_VFRD_M)) {
+ reset_done = true;
break;
+ }
DELAY(ICE_VPGEN_VFRSTAT_WAIT_DELAY_US);
}
- if (i == ICE_VPGEN_VFRSTAT_WAIT_COUNT) {
+ if (!reset_done) {
device_printf(sc->dev,
"VF-%d Reset is stuck\n", vf->vf_num);
if (error == 0)
error = ETIMEDOUT;
+ } else {
+ /* VFLR status is W1C only after the hardware drain completes. */
+ reg_idx = global_vf_num / 32;
+ bit_idx = global_vf_num % 32;
+ wr32(hw, GLGEN_VFLRSTAT(reg_idx), BIT(bit_idx));
+ ice_flush(hw);
+
+ /* Hardware resets Tx queues; the PF must disable every Rx. */
+ for (bit = 0; bit < vf->vsi->num_rx_queues; bit++) {
+ status = ice_control_rx_queue(vf->vsi, bit, false);
+ if (status != 0) {
+ device_printf(sc->dev,
+ "Unable to disable VF-%d Rx queue %d: %s\n",
+ vf->vf_num, bit, ice_err_str(status));
+ if (error == 0)
+ error = status;
+ }
+ }
+ }
+
+ /* Verify that post-drain cleanup left no outstanding DMA. */
+ wr32(hw, PF_PCI_CIAA,
+ ICE_PCIE_DEV_STATUS | (global_vf_num << PF_PCI_CIAA_VF_NUM_S));
+ for (i = 0; i < ICE_PCI_CIAD_WAIT_COUNT; i++) {
+ reg = rd32(hw, PF_PCI_CIAD);
+ if (!(reg & PCIEM_STA_TRANSACTION_PND))
+ break;
+ DELAY(ICE_PCI_CIAD_WAIT_DELAY_US);
+ }
+ if (i == ICE_PCI_CIAD_WAIT_COUNT) {
+ device_printf(sc->dev,
+ "VF-%d PCI transactions remain after reset\n", vf->vf_num);
+ if (error == 0)
+ error = ETIMEDOUT;
}
if (error != 0) {
@@ -994,12 +1024,10 @@
return (error);
}
- atomic_clear_32(&vf->vf_flags, VF_FLAG_RESET_FAILED);
-
- /* 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 (EIO);
+ if (!release_vf) {
+ atomic_clear_32(&vf->vf_flags, VF_FLAG_RESET_FAILED);
+ return (0);
+ }
error = ice_iov_restore_vf_host_config(sc, vf);
if (error != 0) {
@@ -1007,10 +1035,73 @@
return (error);
}
+ atomic_clear_32(&vf->vf_flags, VF_FLAG_RESET_FAILED);
ice_iov_ready_vf(sc, vf);
return (0);
}
+/**
+ * ice_iov_quiesce_vfs_for_reset - Hold configured VFs before device reset
+ * @sc: device softc structure
+ *
+ * Gate VF master accesses, drain each VF data path, and leave VFSWR asserted.
+ * Process VFs serially to remain below the E810 limit of four concurrent
+ * VM/VF reset flows. A successful VSI rebuild releases each VF individually.
+ */
+int
+ice_iov_quiesce_vfs_for_reset(struct ice_softc *sc)
+{
+ struct virtchnl_pf_event event = {};
+ struct ice_hw *hw = &sc->hw;
+ struct ice_vf *vf;
+ int error, first_error;
+ u32 reg, vf_flags;
+ bool notify;
+
+ notify = ice_check_sq_alive(hw, &hw->mailboxq);
+ event.event = VIRTCHNL_EVENT_RESET_IMPENDING;
+ event.severity = PF_EVENT_SEVERITY_CERTAIN_DOOM;
+
+ /* Notify and then gate each VF before it can release its buffers. */
+ for (int i = 0; i < sc->num_vfs; i++) {
+ vf = &sc->vfs[i];
+ vf_flags = atomic_load_acq_32(&vf->vf_flags);
+ if ((vf_flags & VF_FLAG_ENABLED) == 0 || vf->vsi == NULL)
+ continue;
+ if (notify && (vf_flags & VF_FLAG_INITIALIZED) != 0)
+ ice_aq_send_msg_to_vf(hw, vf->vf_num,
+ VIRTCHNL_OP_EVENT, VIRTCHNL_STATUS_SUCCESS,
+ (u8 *)&event, sizeof(event), NULL);
+
+ /* Block mailbox reconfiguration before asserting reset. */
+ atomic_clear_32(&vf->vf_flags, VF_FLAG_INITIALIZED);
+ atomic_set_32(&vf->vf_flags, VF_FLAG_REBUILD_FAILED);
+ reg = rd32(hw, VPGEN_VFRTRIG(vf->vf_num));
+ reg |= VPGEN_VFRTRIG_VFSWR_M;
+ wr32(hw, VPGEN_VFRTRIG(vf->vf_num), reg);
+ }
+ ice_flush(hw);
+
+ /* Firmware data-path drains remain serialized below its limit. */
+ first_error = 0;
+ for (int i = 0; i < sc->num_vfs; i++) {
+ vf = &sc->vfs[i];
+ vf_flags = atomic_load_acq_32(&vf->vf_flags);
+ if ((vf_flags & VF_FLAG_ENABLED) == 0 || vf->vsi == NULL)
+ continue;
+ error = ice_reset_vf(sc, vf, false, false);
+ if (error != 0) {
+ device_printf(sc->dev,
+ "Failed to quiesce VF-%d for device reset: %d\n",
+ vf->vf_num, error);
+ if (first_error == 0)
+ first_error = error;
+ }
+ }
+
+ return (first_error);
+}
+
/**
* ice_vc_get_vf_res_msg - Handle VIRTCHNL_OP_GET_VF_RESOURCES msg from VF
* @sc: device private structure
@@ -2495,7 +2586,10 @@
if ((vf_flags & VF_FLAG_ENABLED) == 0 || vf->vsi == NULL)
return;
- /* Only a later PF rebuild can restore an invalid firmware VSI. */
+ /*
+ * Permit only reset negotiation while VF hardware state is unsafe.
+ * A VFR can retry RESET_FAILED; REBUILD_FAILED requires a PF rebuild.
+ */
if ((vf_flags & (VF_FLAG_REBUILD_FAILED | VF_FLAG_RESET_FAILED)) != 0 &&
v_opcode != VIRTCHNL_OP_VERSION &&
v_opcode != VIRTCHNL_OP_RESET_VF) {
@@ -2509,7 +2603,7 @@
ice_vc_version_msg(sc, vf, msg);
break;
case VIRTCHNL_OP_RESET_VF:
- ice_reset_vf(sc, vf, true);
+ ice_reset_vf(sc, vf, true, true);
break;
case VIRTCHNL_OP_GET_VF_RESOURCES:
ice_vc_get_vf_res_msg(sc, vf, msg);
Index: sys/dev/ice/if_ice_iflib.c
===================================================================
--- sys/dev/ice/if_ice_iflib.c
+++ sys/dev/ice/if_ice_iflib.c
@@ -2518,6 +2518,9 @@
ice_prepare_for_reset(struct ice_softc *sc)
{
struct ice_hw *hw = &sc->hw;
+#ifdef PCI_IOV
+ int error;
+#endif
/* If we're already prepared, there's nothing to do */
if (ice_testandset_state(&sc->state, ICE_STATE_PREPARED_FOR_RESET))
@@ -2530,8 +2533,17 @@
return;
#ifdef PCI_IOV
- /* Notify initialized VFs while the mailbox queue is still available. */
- ice_iov_notify_vfs_reset(sc);
+ /*
+ * A reset already reported by OICR gates DMA in hardware and rejects
+ * new function resets. Otherwise notify and hold VFs while AdminQ is
+ * still usable, before releasing any firmware topology.
+ */
+ if (!hw->reset_ongoing) {
+ error = ice_iov_quiesce_vfs_for_reset(sc);
+ if (error != 0)
+ device_printf(sc->dev,
+ "Failed to quiesce one or more VFs: %d\n", error);
+ }
#endif
/* Restore identification while the control queues are still usable. */
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Aug 25, 7:41 PM (17 h, 6 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37242566
Default Alt Text
D59024.id184427.diff (10 KB)
Attached To
Mode
D59024: ice: Quiesce VFs before device reset
Attached
Detach File
Event Timeline
Log In to Comment