Cause auto-clearing and masking should be performed during msix interrupt processing.
Signed-off-by: Nicholas Piggin <npig...@gmail.com> --- hw/net/e1000e_core.c | 86 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 69 insertions(+), 17 deletions(-) diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c index f8e6522f810..5969f49e8fd 100644 --- a/hw/net/e1000e_core.c +++ b/hw/net/e1000e_core.c @@ -178,16 +178,62 @@ e1000e_intrmgr_on_throttling_timer(void *opaque) } } +/* returns the bitmap of causes that are mapped to a given vector */ +static uint32_t find_msix_causes(E1000ECore *core, int vec) +{ + uint32_t causes = 0; + uint32_t int_cfg; + + int_cfg = E1000_IVAR_RXQ0(core->mac[IVAR]); + if (E1000_IVAR_ENTRY_VALID(int_cfg) && + E1000_IVAR_ENTRY_VEC(int_cfg) == vec) { + causes |= E1000_ICR_RXQ0; + } + + int_cfg = E1000_IVAR_RXQ1(core->mac[IVAR]); + if (E1000_IVAR_ENTRY_VALID(int_cfg) && + E1000_IVAR_ENTRY_VEC(int_cfg) == vec) { + causes |= E1000_ICR_RXQ1; + } + + int_cfg = E1000_IVAR_TXQ0(core->mac[IVAR]); + if (E1000_IVAR_ENTRY_VALID(int_cfg) && + E1000_IVAR_ENTRY_VEC(int_cfg) == vec) { + causes |= E1000_ICR_TXQ0; + } + + int_cfg = E1000_IVAR_TXQ1(core->mac[IVAR]); + if (E1000_IVAR_ENTRY_VALID(int_cfg) && + E1000_IVAR_ENTRY_VEC(int_cfg) == vec) { + causes |= E1000_ICR_TXQ1; + } + + int_cfg = E1000_IVAR_OTHER(core->mac[IVAR]); + if (E1000_IVAR_ENTRY_VALID(int_cfg) && + E1000_IVAR_ENTRY_VEC(int_cfg) == vec) { + causes |= E1000_ICR_OTHER; + } + + return causes; +} + +static void +e1000e_msix_auto_clear_mask(E1000ECore *core, uint32_t cause); + static void e1000e_intrmgr_on_msix_throttling_timer(void *opaque) { E1000IntrDelayTimer *timer = opaque; - int idx = timer - &timer->core->eitr[0]; + E1000ECore *core = timer->core; + int idx = timer - &core->eitr[0]; + uint32_t causes; timer->running = false; + causes = find_msix_causes(core, idx); trace_e1000e_irq_msix_notify_postponed_vec(idx); - msix_notify(timer->core->owner, idx); + msix_notify(core->owner, idx); + e1000e_msix_auto_clear_mask(core, causes); } static void @@ -1985,24 +2031,10 @@ e1000e_eitr_should_postpone(E1000ECore *core, int idx) } static void -e1000e_msix_notify_one(E1000ECore *core, uint32_t cause, uint32_t int_cfg) +e1000e_msix_auto_clear_mask(E1000ECore *core, uint32_t cause) { uint32_t effective_eiac; - if (E1000_IVAR_ENTRY_VALID(int_cfg)) { - uint32_t vec = E1000_IVAR_ENTRY_VEC(int_cfg); - if (vec < E1000E_MSIX_VEC_NUM) { - if (!e1000e_eitr_should_postpone(core, vec)) { - trace_e1000e_irq_msix_notify_vec(vec); - msix_notify(core->owner, vec); - } - } else { - trace_e1000e_wrn_msix_vec_wrong(cause, int_cfg); - } - } else { - trace_e1000e_wrn_msix_invalid(cause, int_cfg); - } - if (core->mac[CTRL_EXT] & E1000_CTRL_EXT_EIAME) { trace_e1000e_irq_iam_clear_eiame(core->mac[IAM], cause); core->mac[IAM] &= ~cause; @@ -2019,6 +2051,26 @@ e1000e_msix_notify_one(E1000ECore *core, uint32_t cause, uint32_t int_cfg) } } +static void +e1000e_msix_notify_one(E1000ECore *core, uint32_t cause, uint32_t int_cfg) +{ + if (E1000_IVAR_ENTRY_VALID(int_cfg)) { + uint32_t vec = E1000_IVAR_ENTRY_VEC(int_cfg); + if (vec < E1000E_MSIX_VEC_NUM) { + if (!e1000e_eitr_should_postpone(core, vec)) { + trace_e1000e_irq_msix_notify_vec(vec); + msix_notify(core->owner, vec); + } + } else { + trace_e1000e_wrn_msix_vec_wrong(cause, int_cfg); + } + } else { + trace_e1000e_wrn_msix_invalid(cause, int_cfg); + } + + e1000e_msix_auto_clear_mask(core, cause); +} + static void e1000e_msix_notify(E1000ECore *core, uint32_t causes) { -- 2.47.1