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;
  }




Reply via email to