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