Add post-load fixups in igbvf_mig_load() to propagate VF interrupt
state that the register load path bypasses by writing directly to
mac[] without triggering register handler side effects.

igb_core_vf_propagate_irqs() ORs PVT shadow values back into the PF
aggregates (EIMS/EIAC/EIAM) and clears stale VF bits from EICR.

igb_core_vf_propagate_ivar() re-applies VTIVAR routing to the shared
IVAR0 entries that the L1 PF driver may have overwritten after L0
vmstate restore.

Assisted-by: Claude
Signed-off-by: Cédric Le Goater <[email protected]>
---
 hw/net/igb_core.h      |  2 ++
 hw/net/igb_core.c      | 56 ++++++++++++++++++++++++++++++++++++++++++
 hw/net/igb_migration.c |  7 ++++++
 3 files changed, 65 insertions(+)

diff --git a/hw/net/igb_core.h b/hw/net/igb_core.h
index 58d4f57c99bb..150567eb346d 100644
--- a/hw/net/igb_core.h
+++ b/hw/net/igb_core.h
@@ -144,4 +144,6 @@ void
 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 45d8fd795b84..2565dd7f96d3 100644
--- a/hw/net/igb_core.c
+++ b/hw/net/igb_core.c
@@ -4550,3 +4550,59 @@ 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 pvt_idx;
+
+    pvt_idx = PVTEIMS0 + vfn * 0x40;
+    core->mac[EIMS] |= (core->mac[pvt_idx] & 0x7) << shift;
+    pvt_idx = PVTEIAC0 + vfn * 0x40;
+    core->mac[EIAC] |= (core->mac[pvt_idx] & 0x7) << shift;
+    pvt_idx = PVTEIAM0 + vfn * 0x40;
+    core->mac[EIAM] |= (core->mac[pvt_idx] & 0x7) << shift;
+
+    core->mac[EICR] &= ~(0x7 << shift);
+}
+
+/*
+ * 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;
+
+    if (vtivar & E1000_IVAR_VALID) {
+        n = igb_ivar_entry_rx(vfn);
+        ent = E1000_IVAR_VALID |
+              (24 - vfn * IGBVF_MSIX_VEC_NUM - (2 - (vtivar & 0x7)));
+        mask = 0xffU << (8 * (n % 4));
+        core->mac[IVAR0 + n / 4] =
+            (core->mac[IVAR0 + n / 4] & ~mask) |
+            ((uint32_t)ent << (8 * (n % 4)));
+    }
+
+    ent = vtivar >> 8;
+    if (ent & E1000_IVAR_VALID) {
+        n = igb_ivar_entry_tx(vfn);
+        ent = E1000_IVAR_VALID |
+              (24 - vfn * IGBVF_MSIX_VEC_NUM - (2 - (ent & 0x7)));
+        mask = 0xffU << (8 * (n % 4));
+        core->mac[IVAR0 + n / 4] =
+            (core->mac[IVAR0 + n / 4] & ~mask) |
+            ((uint32_t)ent << (8 * (n % 4)));
+    }
+}
diff --git a/hw/net/igb_migration.c b/hw/net/igb_migration.c
index 61cf155a188d..4f123df6795d 100644
--- a/hw/net/igb_migration.c
+++ b/hw/net/igb_migration.c
@@ -382,6 +382,7 @@ static int igb_core_vf_load_state(IgbVfState *s,
 
 static int igbvf_mig_load(IgbVfState *s, const void *buf, size_t size)
 {
+    IGBCore *core = igbvf_get_core(s);
     int ret;
 
     ret = igb_core_vf_load_state(s, buf, size);
@@ -389,6 +390,12 @@ static int igbvf_mig_load(IgbVfState *s, const void *buf, 
size_t size)
         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;
 }
 
-- 
2.55.0


Reply via email to