git: 6f940ca879cb - main - ixgbe: clear VF head write-back state on reset

From: Kevin Bowling <kbowling_at_FreeBSD.org>
Date: Fri, 31 Jul 2026 12:14:50 UTC
The branch main has been updated by kbowling:

URL: https://cgit.FreeBSD.org/src/commit/?id=6f940ca879cbf691ddf5605d852770cef27847b2

commit 6f940ca879cbf691ddf5605d852770cef27847b2
Author:     Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-07-28 11:26:28 +0000
Commit:     Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-07-31 12:14:36 +0000

    ixgbe: clear VF head write-back state on reset
    
    VF reset and FLR do not clear the transmit head write-back address
    registers.  A previous VF driver can therefore leave DMA write-back
    enabled with a stale address for the next driver instance.
    
    After consuming the reset request and disabling the VF queues, clear the
    address registers for each queue belonging to that VF.  Derive the queue
    count from the active IOV mode so peer queue state is not touched.
    
    Linux commit dbf231af81a7 documents the hardware behavior.  The FreeBSD
    implementation follows the local queue mapping and register interfaces.
    
    MFC after:      1 week
---
 sys/dev/ixgbe/if_sriov.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/sys/dev/ixgbe/if_sriov.c b/sys/dev/ixgbe/if_sriov.c
index 8d4e20fcf8bf..b9e5205cf1b9 100644
--- a/sys/dev/ixgbe/if_sriov.c
+++ b/sys/dev/ixgbe/if_sriov.c
@@ -353,6 +353,7 @@ ixgbe_vf_reset_msg(struct ixgbe_softc *sc, struct ixgbe_vf *vf, uint32_t *msg)
 	struct ixgbe_hw *hw;
 	uint32_t ack;
 	uint32_t resp[IXGBE_VF_PERMADDR_MSG_LEN];
+	int i, queue_count;
 
 	hw = &sc->hw;
 
@@ -363,6 +364,18 @@ ixgbe_vf_reset_msg(struct ixgbe_softc *sc, struct ixgbe_vf *vf, uint32_t *msg)
 	 */
 	ixgbe_clear_mbx(hw, vf->pool);
 
+	/*
+	 * VF reset does not clear the transmit head write-back addresses.
+	 * The queues were disabled by ixgbe_process_vf_reset().
+	 */
+	queue_count = ixgbe_vf_queues(sc->iov_mode);
+	for (i = 0; i < queue_count; i++) {
+		IXGBE_WRITE_REG(hw,
+		    IXGBE_PVFTDWBAHn(queue_count, vf->pool, i), 0);
+		IXGBE_WRITE_REG(hw,
+		    IXGBE_PVFTDWBALn(queue_count, vf->pool, i), 0);
+	}
+
 	if (ixgbe_validate_mac_addr(vf->ether_addr) == 0) {
 		ixgbe_set_rar(&sc->hw, vf->rar_index, vf->ether_addr,
 		    vf->pool, true);