All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jason Wang <jasowang@redhat.com>
To: qemu-devel@nongnu.org, peter.maydell@linaro.org
Cc: Akihiko Odaki <akihiko.odaki@daynix.com>,
	Jason Wang <jasowang@redhat.com>
Subject: [PULL 44/50] e1000e: Notify only new interrupts
Date: Tue, 23 May 2023 15:32:32 +0800	[thread overview]
Message-ID: <20230523073238.54236-45-jasowang@redhat.com> (raw)
In-Reply-To: <20230523073238.54236-1-jasowang@redhat.com>

From: Akihiko Odaki <akihiko.odaki@daynix.com>

In MSI-X mode, if there are interrupts already notified but not cleared
and a new interrupt arrives, e1000e incorrectly notifies the notified
ones again along with the new one.

To fix this issue, replace e1000e_update_interrupt_state() with
two new functions: e1000e_raise_interrupts() and
e1000e_lower_interrupts(). These functions don't only raise or lower
interrupts, but it also performs register writes which updates the
interrupt state. Before it performs a register write, these function
determines the interrupts already raised, and compares with the
interrupts raised after the register write to determine the interrupts
to notify.

The introduction of these functions made tracepoints which assumes that
the caller of e1000e_update_interrupt_state() performs register writes
obsolete. These tracepoints are now removed, and alternative ones are
added to the new functions.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
 hw/net/e1000e_core.c | 153 ++++++++++++++++++++++-----------------------------
 hw/net/e1000e_core.h |   2 -
 hw/net/trace-events  |   2 +
 3 files changed, 69 insertions(+), 88 deletions(-)

diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c
index d601386..9f185d0 100644
--- a/hw/net/e1000e_core.c
+++ b/hw/net/e1000e_core.c
@@ -165,14 +165,14 @@ e1000e_intrmgr_on_throttling_timer(void *opaque)
 
     timer->running = false;
 
-    if (msi_enabled(timer->core->owner)) {
-        trace_e1000e_irq_msi_notify_postponed();
-        /* Clear msi_causes_pending to fire MSI eventually */
-        timer->core->msi_causes_pending = 0;
-        e1000e_set_interrupt_cause(timer->core, 0);
-    } else {
-        trace_e1000e_irq_legacy_notify_postponed();
-        e1000e_set_interrupt_cause(timer->core, 0);
+    if (timer->core->mac[IMS] & timer->core->mac[ICR]) {
+        if (msi_enabled(timer->core->owner)) {
+            trace_e1000e_irq_msi_notify_postponed();
+            msi_notify(timer->core->owner, 0);
+        } else {
+            trace_e1000e_irq_legacy_notify_postponed();
+            e1000e_raise_legacy_irq(timer->core);
+        }
     }
 }
 
@@ -366,10 +366,6 @@ static void
 e1000e_intrmgr_fire_all_timers(E1000ECore *core)
 {
     int i;
-    uint32_t val = e1000e_intmgr_collect_delayed_causes(core);
-
-    trace_e1000e_irq_adding_delayed_causes(val, core->mac[ICR]);
-    core->mac[ICR] |= val;
 
     if (core->itr.running) {
         timer_del(core->itr.timer);
@@ -1974,13 +1970,6 @@ void(*e1000e_phyreg_writeops[E1000E_PHY_PAGES][E1000E_PHY_PAGE_SIZE])
     }
 };
 
-static inline void
-e1000e_clear_ims_bits(E1000ECore *core, uint32_t bits)
-{
-    trace_e1000e_irq_clear_ims(bits, core->mac[IMS], core->mac[IMS] & ~bits);
-    core->mac[IMS] &= ~bits;
-}
-
 static inline bool
 e1000e_postpone_interrupt(E1000IntrDelayTimer *timer)
 {
@@ -2038,7 +2027,6 @@ e1000e_msix_notify_one(E1000ECore *core, uint32_t cause, uint32_t int_cfg)
     effective_eiac = core->mac[EIAC] & cause;
 
     core->mac[ICR] &= ~effective_eiac;
-    core->msi_causes_pending &= ~effective_eiac;
 
     if (!(core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) {
         core->mac[IMS] &= ~effective_eiac;
@@ -2130,33 +2118,17 @@ e1000e_fix_icr_asserted(E1000ECore *core)
     trace_e1000e_irq_fix_icr_asserted(core->mac[ICR]);
 }
 
-static void
-e1000e_send_msi(E1000ECore *core, bool msix)
+static void e1000e_raise_interrupts(E1000ECore *core,
+                                    size_t index, uint32_t causes)
 {
-    uint32_t causes = core->mac[ICR] & core->mac[IMS] & ~E1000_ICR_ASSERTED;
-
-    core->msi_causes_pending &= causes;
-    causes ^= core->msi_causes_pending;
-    if (causes == 0) {
-        return;
-    }
-    core->msi_causes_pending |= causes;
+    bool is_msix = msix_enabled(core->owner);
+    uint32_t old_causes = core->mac[IMS] & core->mac[ICR];
+    uint32_t raised_causes;
 
-    if (msix) {
-        e1000e_msix_notify(core, causes);
-    } else {
-        if (!e1000e_itr_should_postpone(core)) {
-            trace_e1000e_irq_msi_notify(causes);
-            msi_notify(core->owner, 0);
-        }
-    }
-}
+    trace_e1000e_irq_set(index << 2,
+                         core->mac[index], core->mac[index] | causes);
 
-static void
-e1000e_update_interrupt_state(E1000ECore *core)
-{
-    bool interrupts_pending;
-    bool is_msix = msix_enabled(core->owner);
+    core->mac[index] |= causes;
 
     /* Set ICR[OTHER] for MSI-X */
     if (is_msix) {
@@ -2178,40 +2150,58 @@ e1000e_update_interrupt_state(E1000ECore *core)
      */
     core->mac[ICS] = core->mac[ICR];
 
-    interrupts_pending = (core->mac[IMS] & core->mac[ICR]) ? true : false;
-    if (!interrupts_pending) {
-        core->msi_causes_pending = 0;
-    }
-
     trace_e1000e_irq_pending_interrupts(core->mac[ICR] & core->mac[IMS],
                                         core->mac[ICR], core->mac[IMS]);
 
-    if (is_msix || msi_enabled(core->owner)) {
-        if (interrupts_pending) {
-            e1000e_send_msi(core, is_msix);
-        }
-    } else {
-        if (interrupts_pending) {
-            if (!e1000e_itr_should_postpone(core)) {
-                e1000e_raise_legacy_irq(core);
-            }
+    raised_causes = core->mac[IMS] & core->mac[ICR] & ~old_causes;
+    if (!raised_causes) {
+        return;
+    }
+
+    if (is_msix) {
+        e1000e_msix_notify(core, raised_causes & ~E1000_ICR_ASSERTED);
+    } else if (!e1000e_itr_should_postpone(core)) {
+        if (msi_enabled(core->owner)) {
+            trace_e1000e_irq_msi_notify(raised_causes);
+            msi_notify(core->owner, 0);
         } else {
-            e1000e_lower_legacy_irq(core);
+            e1000e_raise_legacy_irq(core);
         }
     }
 }
 
-static void
-e1000e_set_interrupt_cause(E1000ECore *core, uint32_t val)
+static void e1000e_lower_interrupts(E1000ECore *core,
+                                    size_t index, uint32_t causes)
 {
-    trace_e1000e_irq_set_cause_entry(val, core->mac[ICR]);
+    trace_e1000e_irq_clear(index << 2,
+                           core->mac[index], core->mac[index] & ~causes);
 
-    val |= e1000e_intmgr_collect_delayed_causes(core);
-    core->mac[ICR] |= val;
+    core->mac[index] &= ~causes;
 
-    trace_e1000e_irq_set_cause_exit(val, core->mac[ICR]);
+    /*
+     * Make sure ICR and ICS registers have the same value.
+     * The spec says that the ICS register is write-only.  However in practice,
+     * on real hardware ICS is readable, and for reads it has the same value as
+     * ICR (except that ICS does not have the clear on read behaviour of ICR).
+     *
+     * The VxWorks PRO/1000 driver uses this behaviour.
+     */
+    core->mac[ICS] = core->mac[ICR];
+
+    trace_e1000e_irq_pending_interrupts(core->mac[ICR] & core->mac[IMS],
+                                        core->mac[ICR], core->mac[IMS]);
 
-    e1000e_update_interrupt_state(core);
+    if (!(core->mac[IMS] & core->mac[ICR]) &&
+        !msix_enabled(core->owner) && !msi_enabled(core->owner)) {
+        e1000e_lower_legacy_irq(core);
+    }
+}
+
+static void
+e1000e_set_interrupt_cause(E1000ECore *core, uint32_t val)
+{
+    val |= e1000e_intmgr_collect_delayed_causes(core);
+    e1000e_raise_interrupts(core, ICR, val);
 }
 
 static inline void
@@ -2477,30 +2467,27 @@ e1000e_set_ics(E1000ECore *core, int index, uint32_t val)
 static void
 e1000e_set_icr(E1000ECore *core, int index, uint32_t val)
 {
-    uint32_t icr = 0;
     if ((core->mac[ICR] & E1000_ICR_ASSERTED) &&
         (core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) {
         trace_e1000e_irq_icr_process_iame();
-        e1000e_clear_ims_bits(core, core->mac[IAM]);
+        e1000e_lower_interrupts(core, IMS, core->mac[IAM]);
     }
 
-    icr = core->mac[ICR] & ~val;
     /*
      * Windows driver expects that the "receive overrun" bit and other
      * ones to be cleared when the "Other" bit (#24) is cleared.
      */
-    icr = (val & E1000_ICR_OTHER) ? (icr & ~E1000_ICR_OTHER_CAUSES) : icr;
-    trace_e1000e_irq_icr_write(val, core->mac[ICR], icr);
-    core->mac[ICR] = icr;
-    e1000e_update_interrupt_state(core);
+    if (val & E1000_ICR_OTHER) {
+        val |= E1000_ICR_OTHER_CAUSES;
+    }
+    e1000e_lower_interrupts(core, ICR, val);
 }
 
 static void
 e1000e_set_imc(E1000ECore *core, int index, uint32_t val)
 {
     trace_e1000e_irq_ims_clear_set_imc(val);
-    e1000e_clear_ims_bits(core, val);
-    e1000e_update_interrupt_state(core);
+    e1000e_lower_interrupts(core, IMS, val);
 }
 
 static void
@@ -2521,9 +2508,6 @@ e1000e_set_ims(E1000ECore *core, int index, uint32_t val)
 
     uint32_t valid_val = val & ims_valid_mask;
 
-    trace_e1000e_irq_set_ims(val, core->mac[IMS], core->mac[IMS] | valid_val);
-    core->mac[IMS] |= valid_val;
-
     if ((valid_val & ims_ext_mask) &&
         (core->mac[CTRL_EXT] & E1000_CTRL_EXT_PBA_CLR) &&
         msix_enabled(core->owner)) {
@@ -2536,7 +2520,7 @@ e1000e_set_ims(E1000ECore *core, int index, uint32_t val)
         e1000e_intrmgr_fire_all_timers(core);
     }
 
-    e1000e_update_interrupt_state(core);
+    e1000e_raise_interrupts(core, IMS, valid_val);
 }
 
 static void
@@ -2609,28 +2593,25 @@ static uint32_t
 e1000e_mac_icr_read(E1000ECore *core, int index)
 {
     uint32_t ret = core->mac[ICR];
-    trace_e1000e_irq_icr_read_entry(ret);
 
     if (core->mac[IMS] == 0) {
         trace_e1000e_irq_icr_clear_zero_ims();
-        core->mac[ICR] = 0;
+        e1000e_lower_interrupts(core, ICR, 0xffffffff);
     }
 
     if (!msix_enabled(core->owner)) {
         trace_e1000e_irq_icr_clear_nonmsix_icr_read();
-        core->mac[ICR] = 0;
+        e1000e_lower_interrupts(core, ICR, 0xffffffff);
     }
 
     if ((core->mac[ICR] & E1000_ICR_ASSERTED) &&
         (core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) {
         trace_e1000e_irq_icr_clear_iame();
-        core->mac[ICR] = 0;
+        e1000e_lower_interrupts(core, ICR, 0xffffffff);
         trace_e1000e_irq_icr_process_iame();
-        e1000e_clear_ims_bits(core, core->mac[IAM]);
+        e1000e_lower_interrupts(core, IMS, core->mac[IAM]);
     }
 
-    trace_e1000e_irq_icr_read_exit(core->mac[ICR]);
-    e1000e_update_interrupt_state(core);
     return ret;
 }
 
diff --git a/hw/net/e1000e_core.h b/hw/net/e1000e_core.h
index 213a705..66b025c 100644
--- a/hw/net/e1000e_core.h
+++ b/hw/net/e1000e_core.h
@@ -111,8 +111,6 @@ struct E1000Core {
     PCIDevice *owner;
     void (*owner_start_recv)(PCIDevice *d);
 
-    uint32_t msi_causes_pending;
-
     int64_t timadj;
 };
 
diff --git a/hw/net/trace-events b/hw/net/trace-events
index 64d776b..d171dc81 100644
--- a/hw/net/trace-events
+++ b/hw/net/trace-events
@@ -205,6 +205,8 @@ e1000e_irq_msix_notify_postponed_vec(int idx) "Sending MSI-X postponed by EITR[%
 e1000e_irq_legacy_notify(bool level) "IRQ line state: %d"
 e1000e_irq_msix_notify_vec(uint32_t vector) "MSI-X notify vector 0x%x"
 e1000e_irq_postponed_by_xitr(uint32_t reg) "Interrupt postponed by [E]ITR register 0x%x"
+e1000e_irq_clear(uint32_t offset, uint32_t old, uint32_t new) "Clearing interrupt register 0x%x: 0x%x --> 0x%x"
+e1000e_irq_set(uint32_t offset, uint32_t old, uint32_t new) "Setting interrupt register 0x%x: 0x%x --> 0x%x"
 e1000e_irq_clear_ims(uint32_t bits, uint32_t old_ims, uint32_t new_ims) "Clearing IMS bits 0x%x: 0x%x --> 0x%x"
 e1000e_irq_set_ims(uint32_t bits, uint32_t old_ims, uint32_t new_ims) "Setting IMS bits 0x%x: 0x%x --> 0x%x"
 e1000e_irq_fix_icr_asserted(uint32_t new_val) "ICR_ASSERTED bit fixed: 0x%x"
-- 
2.7.4



  parent reply	other threads:[~2023-05-23  7:37 UTC|newest]

Thread overview: 55+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-23  7:31 [PULL 00/50] Net patches Jason Wang
2023-05-23  7:31 ` [PULL 01/50] e1000e: Fix tx/rx counters Jason Wang
2023-05-23  7:31 ` [PULL 02/50] hw/net/net_tx_pkt: Decouple implementation from PCI Jason Wang
2023-05-23  7:31 ` [PULL 03/50] hw/net/net_tx_pkt: Decouple interface " Jason Wang
2023-05-23  7:31 ` [PULL 04/50] e1000x: Fix BPRC and MPRC Jason Wang
2023-05-23  7:31 ` [PULL 05/50] igb: Fix Rx packet type encoding Jason Wang
2023-05-23  7:31 ` [PULL 06/50] igb: Do not require CTRL.VME for tx VLAN tagging Jason Wang
2023-05-23  7:31 ` [PULL 07/50] igb: Clear IMS bits when committing ICR access Jason Wang
2023-05-23  7:31 ` [PULL 08/50] net/net_rx_pkt: Use iovec for net_rx_pkt_set_protocols() Jason Wang
2023-05-23  7:31 ` [PULL 09/50] e1000e: Always copy ethernet header Jason Wang
2023-05-23  7:31 ` [PULL 10/50] igb: " Jason Wang
2023-05-23  7:31 ` [PULL 11/50] Fix references to igb Avocado test Jason Wang
2023-05-23  7:32 ` [PULL 12/50] tests/avocado: Remove unused imports Jason Wang
2023-05-23  7:32 ` [PULL 13/50] tests/avocado: Remove test_igb_nomsi_kvm Jason Wang
2023-05-23  7:32 ` [PULL 14/50] hw/net/net_tx_pkt: Remove net_rx_pkt_get_l4_info Jason Wang
2023-05-23  7:32 ` [PULL 15/50] net/eth: Rename eth_setup_vlan_headers_ex Jason Wang
2023-05-23  7:32 ` [PULL 16/50] e1000x: Share more Rx filtering logic Jason Wang
2023-05-23  7:32 ` [PULL 17/50] e1000x: Take CRC into consideration for size check Jason Wang
2023-05-23  7:32 ` [PULL 18/50] e1000x: Rename TcpIpv6 into TcpIpv6Ex Jason Wang
2023-05-23  7:32 ` [PULL 19/50] e1000e: Always log status after building rx metadata Jason Wang
2023-05-23  7:32 ` [PULL 20/50] igb: " Jason Wang
2023-05-23  7:32 ` [PULL 21/50] igb: Remove goto Jason Wang
2023-05-23  7:32 ` [PULL 22/50] igb: Read DCMD.VLE of the first Tx descriptor Jason Wang
2023-05-23  7:32 ` [PULL 23/50] e1000e: Reset packet state after emptying Tx queue Jason Wang
2023-05-23  7:32 ` [PULL 24/50] vmxnet3: " Jason Wang
2023-05-23  7:32 ` [PULL 25/50] igb: Add more definitions for Tx descriptor Jason Wang
2023-05-23  7:32 ` [PULL 26/50] igb: Share common VF constants Jason Wang
2023-05-23  7:32 ` [PULL 27/50] igb: Fix igb_mac_reg_init coding style alignment Jason Wang
2023-05-23  7:32 ` [PULL 28/50] igb: Clear EICR bits for delayed MSI-X interrupts Jason Wang
2023-05-23  7:32 ` [PULL 29/50] e1000e: Rename a variable in e1000e_receive_internal() Jason Wang
2023-05-23  7:32 ` [PULL 30/50] igb: Rename a variable in igb_receive_internal() Jason Wang
2023-05-23  7:32 ` [PULL 31/50] net/eth: Use void pointers Jason Wang
2023-05-23  7:32 ` [PULL 32/50] net/eth: Always add VLAN tag Jason Wang
2023-05-23  7:32 ` [PULL 33/50] hw/net/net_rx_pkt: Enforce alignment for eth_header Jason Wang
2023-05-23  7:32 ` [PULL 34/50] tests/qtest/libqos/igb: Set GPIE.Multiple_MSIX Jason Wang
2023-05-23  7:32 ` [PULL 35/50] igb: Implement MSI-X single vector mode Jason Wang
2023-05-23  7:32 ` [PULL 36/50] igb: Use UDP for RSS hash Jason Wang
2023-05-23  7:32 ` [PULL 37/50] igb: Implement Rx SCTP CSO Jason Wang
2023-05-23  7:32 ` [PULL 38/50] igb: Implement Tx " Jason Wang
2023-05-23  7:32 ` [PULL 39/50] igb: Strip the second VLAN tag for extended VLAN Jason Wang
2023-05-23  7:32 ` [PULL 40/50] igb: Filter with " Jason Wang
2023-05-23  7:32 ` [PULL 41/50] igb: Implement igb-specific oversize check Jason Wang
2023-05-23  7:32 ` [PULL 42/50] igb: Implement Rx PTP2 timestamp Jason Wang
2023-05-23  7:32 ` [PULL 43/50] igb: Implement Tx timestamp Jason Wang
2023-05-23  7:32 ` Jason Wang [this message]
2023-05-23  7:32 ` [PULL 45/50] igb: Notify only new interrupts Jason Wang
2023-05-23  7:32 ` [PULL 46/50] igb: Clear-on-read ICR when ICR.INTA is set Jason Wang
2023-05-23  7:32 ` [PULL 47/50] vmxnet3: Do not depend on PC Jason Wang
2023-05-23  7:32 ` [PULL 48/50] MAINTAINERS: Add a reviewer for network packet abstractions Jason Wang
2023-05-23  7:32 ` [PULL 49/50] docs/system/devices/igb: Note igb is tested for DPDK Jason Wang
2023-05-23  7:32 ` [PULL 50/50] rtl8139: fix large_send_mss divide-by-zero Jason Wang
2023-05-23 17:56 ` [PULL 00/50] Net patches Richard Henderson
2023-05-23 19:53 ` Michael Tokarev
2023-05-24  4:06   ` Jason Wang
2023-05-24  4:21     ` Akihiko Odaki

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230523073238.54236-45-jasowang@redhat.com \
    --to=jasowang@redhat.com \
    --cc=akihiko.odaki@daynix.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.