On 2026/09/15 16:58, Cédric Le Goater wrote:
On 9/8/26 10:10, Akihiko Odaki wrote:
On 2026/09/03 4:20, Cédric Le Goater wrote:
After restoring per-VF register state, propagate the VF's PVT shadow
values back into the PF's aggregate EIMS/EIAC/EIAM registers and
re-apply the VTIVAR interrupt vector routing to the shared IVAR0.
AI-used-for: analysis, code (prototype)
Signed-off-by: Cédric Le Goater <[email protected]>
---
hw/net/igb_core.h | 3 ++
hw/net/igb_core.c | 66 ++++++++++++++++++++++++++++++++++++++++++
hw/net/igb_migration.c | 7 +++++
3 files changed, 76 insertions(+)
diff --git a/hw/net/igb_core.h b/hw/net/igb_core.h
index 60724e2824ab..22e10e4e6d0b 100644
--- a/hw/net/igb_core.h
+++ b/hw/net/igb_core.h
@@ -145,4 +145,7 @@ igb_start_recv(IGBCore *core);
IGBCore *igb_pf_get_core(void *pf);
+void igb_core_vf_propagate_irqs(IGBCore *core, uint16_t vfn);
+void igb_core_vf_propagate_ivar(IGBCore *core, uint16_t vfn);
+
#endif
diff --git a/hw/net/igb_core.c b/hw/net/igb_core.c
index 2a4883907353..01745fe756d0 100644
--- a/hw/net/igb_core.c
+++ b/hw/net/igb_core.c
@@ -4552,3 +4552,69 @@ igb_core_post_load(IGBCore *core)
return 0;
}
+
+/*
+ * Propagate VF interrupt state to PF aggregates after loading VF
+ * registers. The load path writes directly to mac[] bypassing the
+ * register handlers that OR VF bits into EIMS/EIAC/EIAM. Also clear
+ * stale VF bits in EICR that may have been set by packets arriving
+ * between PF vmstate restore and VF state load.
+ */
+void igb_core_vf_propagate_irqs(IGBCore *core, uint16_t vfn)
+{
+ uint32_t shift = 22 - vfn * IGBVF_MSIX_VEC_NUM;
+ uint32_t vf_mask = 0x7 << shift;
+ uint32_t pvt_idx;
+
+ core->mac[EIMS] &= ~vf_mask;
Restore the effective interrupt mask rather than the last EIMS write.
This clears the destination VF mask and copies PVTEIMS, but that
shadow records only the last write: igb_set_vteims() assigns it before
applying set-bit semantics to aggregate EIMS. For example, source
writes EIMS=1, then EIMS=2, leave effective mask 3 and shadow 2;
migration restores 2, suppressing vector 0 until explicitly enabled
again. Conversely, EIMC updates aggregate EIMS without updating
PVTEIMS, so migration reenables explicitly masked vectors. Patch 7
repeats this fixup on unquiesce without repairing the bookkeeping.
ok. I guess we can save and restore the VF's effective mask bits directly
and drop the fixup then. Same for EIAC/EIAM. It should simplify the flow.
How's that ?
Yes, saving and restoring the VF's effective bits in EIMS/EIAC/EIAM
would address my concern and remove the need for that shadow-based
fixup. Restore only this VF's bits, preserving the PF and other VFs
bits in those shared registers.
Please also ensure that the saved EIMS bits reflect the mask before
quiescing disables interrupts, and that unquiesce restores that saved
mask rather than reconstructing it from PVTEIMS.
Regards,
Akihiko Odaki
Thanks
C.
Regards,
Akihiko Odaki
+ pvt_idx = PVTEIMS0 + vfn * 0x40;
+ core->mac[EIMS] |= (core->mac[pvt_idx] & 0x7) << shift;
+
+ core->mac[EIAC] &= ~vf_mask;
+ pvt_idx = PVTEIAC0 + vfn * 0x40;
+ core->mac[EIAC] |= (core->mac[pvt_idx] & 0x7) << shift;
+
+ core->mac[EIAM] &= ~vf_mask;
+ pvt_idx = PVTEIAM0 + vfn * 0x40;
+ core->mac[EIAM] |= (core->mac[pvt_idx] & 0x7) << shift;
+
+ core->mac[EICR] &= ~vf_mask;
+}
+
+/*
+ * Re-apply VTIVAR -> IVAR0 interrupt routing. The L1 PF driver
+ * may have overwritten the shared IVAR0 entries with its own
+ * queue routing after L0 vmstate restore.
+ */
+void igb_core_vf_propagate_ivar(IGBCore *core, uint16_t vfn)
+{
+ uint32_t vtivar = core->mac[VTIVAR + vfn];
+ int n;
+ uint8_t ent;
+ uint32_t mask;
+
+ n = igb_ivar_entry_rx(vfn);
+ mask = 0xffU << (8 * (n % 4));
+ if (vtivar & E1000_IVAR_VALID) {
+ ent = E1000_IVAR_VALID |
+ (24 - vfn * IGBVF_MSIX_VEC_NUM - (2 - (vtivar & 0x7)));
+ core->mac[IVAR0 + n / 4] =
+ (core->mac[IVAR0 + n / 4] & ~mask) |
+ ((uint32_t)ent << (8 * (n % 4)));
+ } else {
+ core->mac[IVAR0 + n / 4] &= ~mask;
+ }
+
+ n = igb_ivar_entry_tx(vfn);
+ mask = 0xffU << (8 * (n % 4));
+ ent = vtivar >> 8;
+ if (ent & E1000_IVAR_VALID) {
+ ent = E1000_IVAR_VALID |
+ (24 - vfn * IGBVF_MSIX_VEC_NUM - (2 - (ent & 0x7)));
+ core->mac[IVAR0 + n / 4] =
+ (core->mac[IVAR0 + n / 4] & ~mask) |
+ ((uint32_t)ent << (8 * (n % 4)));
+ } else {
+ core->mac[IVAR0 + n / 4] &= ~mask;
+ }
+}
diff --git a/hw/net/igb_migration.c b/hw/net/igb_migration.c
index c34035974620..af7257ccc4fd 100644
--- a/hw/net/igb_migration.c
+++ b/hw/net/igb_migration.c
@@ -384,12 +384,19 @@ static int igb_core_vf_load_state(IgbVfState
*s, const void *buf, size_t size)
static int igbvf_mig_load(IgbVfState *s, const void *buf, size_t size)
{
int ret;
+ IGBCore *core = igbvf_get_core(s);
ret = igb_core_vf_load_state(s, buf, size);
if (ret < 0) {
return ret;
}
+ /*
+ * Post-load: sync VF interrupt and routing state to PF aggregates
+ */
+ igb_core_vf_propagate_irqs(core, s->vfn);
+ igb_core_vf_propagate_ivar(core, s->vfn);
+
return 0;
}