kernel: add pending e1000e fixes
authorStijn Tintel <stijn@linux-ipv6.be>
Thu, 28 Jun 2018 09:44:10 +0000 (11:44 +0200)
committerStijn Tintel <stijn@linux-ipv6.be>
Tue, 31 Jul 2018 02:11:34 +0000 (05:11 +0300)
The previous round of fixes for the 82574 chip cause an issue with
emulated e1000e devices in VMware ESXi 6.5. It also contains changes
that are not strictly necessary. These patches fix the issues introduced
in the previous series, revert the unnecessary changes to avoid
unforeseen fallout, and avoid a case where interrupts can be missed.

The final two patches of this series are already in the kernel, so no
need to include them here.

Patchwork: https://patchwork.ozlabs.org/cover/881776/

Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
target/linux/generic/pending-4.14/191-1-6-e1000e-Remove-Other-from-EIAC.diff [new file with mode: 0644]
target/linux/generic/pending-4.14/191-2-6-Partial-revert-e1000e-Avoid-receiver-overrun-interrupt-bursts.diff [new file with mode: 0644]
target/linux/generic/pending-4.14/191-3-6-e1000e-Fix-queue-interrupt-re-raising-in-Other-interrupt.diff [new file with mode: 0644]
target/linux/generic/pending-4.14/191-4-6-e1000e-Avoid-missed-interrupts-following-ICR-read.diff [new file with mode: 0644]

diff --git a/target/linux/generic/pending-4.14/191-1-6-e1000e-Remove-Other-from-EIAC.diff b/target/linux/generic/pending-4.14/191-1-6-e1000e-Remove-Other-from-EIAC.diff
new file mode 100644 (file)
index 0000000..9ce01aa
--- /dev/null
@@ -0,0 +1,66 @@
+From patchwork Mon Mar  5 21:40:25 2018
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [net,v2,1/6] e1000e: Remove Other from EIAC
+X-Patchwork-Submitter: "Kirsher, Jeffrey T" <jeffrey.t.kirsher@intel.com>
+X-Patchwork-Id: 881773
+X-Patchwork-Delegate: davem@davemloft.net
+Message-Id: <20180305214030.25141-2-jeffrey.t.kirsher@intel.com>
+To: davem@davemloft.net
+Cc: Benjamin Poirier <bpoirier@suse.com>, netdev@vger.kernel.org,
+ nhorman@redhat.com, sassmann@redhat.com, jogreene@redhat.com,
+ Jeff Kirsher <jeffrey.t.kirsher@intel.com>
+Date: Mon,  5 Mar 2018 13:40:25 -0800
+From: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
+List-Id: <netdev.vger.kernel.org>
+
+From: Benjamin Poirier <bpoirier@suse.com>
+
+It was reported that emulated e1000e devices in vmware esxi 6.5 Build
+7526125 do not link up after commit 4aea7a5c5e94 ("e1000e: Avoid receiver
+overrun interrupt bursts", v4.15-rc1). Some tracing shows that after
+e1000e_trigger_lsc() is called, ICR reads out as 0x0 in e1000_msix_other()
+on emulated e1000e devices. In comparison, on real e1000e 82574 hardware,
+icr=0x80000004 (_INT_ASSERTED | _LSC) in the same situation.
+
+Some experimentation showed that this flaw in vmware e1000e emulation can
+be worked around by not setting Other in EIAC. This is how it was before
+16ecba59bc33 ("e1000e: Do not read ICR in Other interrupt", v4.5-rc1).
+
+Fixes: 4aea7a5c5e94 ("e1000e: Avoid receiver overrun interrupt bursts")
+Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
+Tested-by: Aaron Brown <aaron.f.brown@intel.com>
+Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
+---
+ drivers/net/ethernet/intel/e1000e/netdev.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/intel/e1000e/netdev.c
++++ b/drivers/net/ethernet/intel/e1000e/netdev.c
+@@ -1914,6 +1914,8 @@ static irqreturn_t e1000_msix_other(int
+       bool enable = true;
+       icr = er32(ICR);
++      ew32(ICR, E1000_ICR_OTHER);
++
+       if (icr & E1000_ICR_RXO) {
+               ew32(ICR, E1000_ICR_RXO);
+               enable = false;
+@@ -2036,7 +2038,6 @@ static void e1000_configure_msix(struct
+                      hw->hw_addr + E1000_EITR_82574(vector));
+       else
+               writel(1, hw->hw_addr + E1000_EITR_82574(vector));
+-      adapter->eiac_mask |= E1000_IMS_OTHER;
+       /* Cause Tx interrupts on every write back */
+       ivar |= BIT(31);
+@@ -2261,7 +2262,7 @@ static void e1000_irq_enable(struct e100
+       if (adapter->msix_entries) {
+               ew32(EIAC_82574, adapter->eiac_mask & E1000_EIAC_MASK_82574);
+-              ew32(IMS, adapter->eiac_mask | E1000_IMS_LSC);
++              ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER | E1000_IMS_LSC);
+       } else if (hw->mac.type >= e1000_pch_lpt) {
+               ew32(IMS, IMS_ENABLE_MASK | E1000_IMS_ECCER);
+       } else {
diff --git a/target/linux/generic/pending-4.14/191-2-6-Partial-revert-e1000e-Avoid-receiver-overrun-interrupt-bursts.diff b/target/linux/generic/pending-4.14/191-2-6-Partial-revert-e1000e-Avoid-receiver-overrun-interrupt-bursts.diff
new file mode 100644 (file)
index 0000000..2800e6f
--- /dev/null
@@ -0,0 +1,84 @@
+From patchwork Mon Mar  5 21:40:26 2018
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [net, v2,
+ 2/6] Partial revert "e1000e: Avoid receiver overrun interrupt bursts"
+X-Patchwork-Submitter: "Kirsher, Jeffrey T" <jeffrey.t.kirsher@intel.com>
+X-Patchwork-Id: 881769
+X-Patchwork-Delegate: davem@davemloft.net
+Message-Id: <20180305214030.25141-3-jeffrey.t.kirsher@intel.com>
+To: davem@davemloft.net
+Cc: Benjamin Poirier <bpoirier@suse.com>, netdev@vger.kernel.org,
+ nhorman@redhat.com, sassmann@redhat.com, jogreene@redhat.com,
+ Jeff Kirsher <jeffrey.t.kirsher@intel.com>
+Date: Mon,  5 Mar 2018 13:40:26 -0800
+From: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
+List-Id: <netdev.vger.kernel.org>
+
+From: Benjamin Poirier <bpoirier@suse.com>
+
+This partially reverts commit 4aea7a5c5e940c1723add439f4088844cd26196d.
+
+We keep the fix for the first part of the problem (1) described in the log
+of that commit, that is to read ICR in the other interrupt handler. We
+remove the fix for the second part of the problem (2), Other interrupt
+throttling.
+
+Bursts of "Other" interrupts may once again occur during rxo (receive
+overflow) traffic conditions. This is deemed acceptable in the interest of
+avoiding unforeseen fallout from changes that are not strictly necessary.
+As discussed, the e1000e driver should be in "maintenance mode".
+
+Link: https://www.spinics.net/lists/netdev/msg480675.html
+Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
+Acked-by: Alexander Duyck <alexander.h.duyck@intel.com>
+Tested-by: Aaron Brown <aaron.f.brown@intel.com>
+Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
+---
+ drivers/net/ethernet/intel/e1000e/netdev.c | 16 ++--------------
+ 1 file changed, 2 insertions(+), 14 deletions(-)
+
+--- a/drivers/net/ethernet/intel/e1000e/netdev.c
++++ b/drivers/net/ethernet/intel/e1000e/netdev.c
+@@ -1911,21 +1911,10 @@ static irqreturn_t e1000_msix_other(int
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       u32 icr;
+-      bool enable = true;
+       icr = er32(ICR);
+       ew32(ICR, E1000_ICR_OTHER);
+-      if (icr & E1000_ICR_RXO) {
+-              ew32(ICR, E1000_ICR_RXO);
+-              enable = false;
+-              /* napi poll will re-enable Other, make sure it runs */
+-              if (napi_schedule_prep(&adapter->napi)) {
+-                      adapter->total_rx_bytes = 0;
+-                      adapter->total_rx_packets = 0;
+-                      __napi_schedule(&adapter->napi);
+-              }
+-      }
+       if (icr & E1000_ICR_LSC) {
+               ew32(ICR, E1000_ICR_LSC);
+               hw->mac.get_link_status = true;
+@@ -1934,7 +1923,7 @@ static irqreturn_t e1000_msix_other(int
+                       mod_timer(&adapter->watchdog_timer, jiffies + 1);
+       }
+-      if (enable && !test_bit(__E1000_DOWN, &adapter->state))
++      if (!test_bit(__E1000_DOWN, &adapter->state))
+               ew32(IMS, E1000_IMS_OTHER);
+       return IRQ_HANDLED;
+@@ -2704,8 +2693,7 @@ static int e1000e_poll(struct napi_struc
+               napi_complete_done(napi, work_done);
+               if (!test_bit(__E1000_DOWN, &adapter->state)) {
+                       if (adapter->msix_entries)
+-                              ew32(IMS, adapter->rx_ring->ims_val |
+-                                   E1000_IMS_OTHER);
++                              ew32(IMS, adapter->rx_ring->ims_val);
+                       else
+                               e1000_irq_enable(adapter);
+               }
diff --git a/target/linux/generic/pending-4.14/191-3-6-e1000e-Fix-queue-interrupt-re-raising-in-Other-interrupt.diff b/target/linux/generic/pending-4.14/191-3-6-e1000e-Fix-queue-interrupt-re-raising-in-Other-interrupt.diff
new file mode 100644 (file)
index 0000000..8ad13ba
--- /dev/null
@@ -0,0 +1,50 @@
+From patchwork Mon Mar  5 21:40:27 2018
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [net, v2,
+ 3/6] e1000e: Fix queue interrupt re-raising in Other interrupt
+X-Patchwork-Submitter: "Kirsher, Jeffrey T" <jeffrey.t.kirsher@intel.com>
+X-Patchwork-Id: 881775
+X-Patchwork-Delegate: davem@davemloft.net
+Message-Id: <20180305214030.25141-4-jeffrey.t.kirsher@intel.com>
+To: davem@davemloft.net
+Cc: Benjamin Poirier <bpoirier@suse.com>, netdev@vger.kernel.org,
+ nhorman@redhat.com, sassmann@redhat.com, jogreene@redhat.com,
+ Jeff Kirsher <jeffrey.t.kirsher@intel.com>
+Date: Mon,  5 Mar 2018 13:40:27 -0800
+From: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
+List-Id: <netdev.vger.kernel.org>
+
+From: Benjamin Poirier <bpoirier@suse.com>
+
+Restores the ICS write for Rx/Tx queue interrupts which was present before
+commit 16ecba59bc33 ("e1000e: Do not read ICR in Other interrupt", v4.5-rc1)
+but was not restored in commit 4aea7a5c5e94
+("e1000e: Avoid receiver overrun interrupt bursts", v4.15-rc1).
+
+This re-raises the queue interrupts in case the txq or rxq bits were set in
+ICR and the Other interrupt handler read and cleared ICR before the queue
+interrupt was raised.
+
+Fixes: 4aea7a5c5e94 ("e1000e: Avoid receiver overrun interrupt bursts")
+Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
+Acked-by: Alexander Duyck <alexander.h.duyck@intel.com>
+Tested-by: Aaron Brown <aaron.f.brown@intel.com>
+Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
+---
+ drivers/net/ethernet/intel/e1000e/netdev.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/net/ethernet/intel/e1000e/netdev.c
++++ b/drivers/net/ethernet/intel/e1000e/netdev.c
+@@ -1915,6 +1915,9 @@ static irqreturn_t e1000_msix_other(int
+       icr = er32(ICR);
+       ew32(ICR, E1000_ICR_OTHER);
++      if (icr & adapter->eiac_mask)
++              ew32(ICS, (icr & adapter->eiac_mask));
++
+       if (icr & E1000_ICR_LSC) {
+               ew32(ICR, E1000_ICR_LSC);
+               hw->mac.get_link_status = true;
diff --git a/target/linux/generic/pending-4.14/191-4-6-e1000e-Avoid-missed-interrupts-following-ICR-read.diff b/target/linux/generic/pending-4.14/191-4-6-e1000e-Avoid-missed-interrupts-following-ICR-read.diff
new file mode 100644 (file)
index 0000000..f218f34
--- /dev/null
@@ -0,0 +1,131 @@
+From patchwork Mon Mar  5 21:40:28 2018
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [net,v2,4/6] e1000e: Avoid missed interrupts following ICR read
+X-Patchwork-Submitter: "Kirsher, Jeffrey T" <jeffrey.t.kirsher@intel.com>
+X-Patchwork-Id: 881771
+X-Patchwork-Delegate: davem@davemloft.net
+Message-Id: <20180305214030.25141-5-jeffrey.t.kirsher@intel.com>
+To: davem@davemloft.net
+Cc: Benjamin Poirier <bpoirier@suse.com>, netdev@vger.kernel.org,
+ nhorman@redhat.com, sassmann@redhat.com, jogreene@redhat.com,
+ Jeff Kirsher <jeffrey.t.kirsher@intel.com>
+Date: Mon,  5 Mar 2018 13:40:28 -0800
+From: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
+List-Id: <netdev.vger.kernel.org>
+
+From: Benjamin Poirier <bpoirier@suse.com>
+
+The 82574 specification update errata 12 states that interrupts may be
+missed if ICR is read while INT_ASSERTED is not set. Avoid that problem by
+setting all bits related to events that can trigger the Other interrupt in
+IMS.
+
+The Other interrupt is raised for such events regardless of whether or not
+they are set in IMS. However, only when they are set is the INT_ASSERTED
+bit also set in ICR.
+
+By doing this, we ensure that INT_ASSERTED is always set when we read ICR
+in e1000_msix_other() and steer clear of the errata. This also ensures that
+ICR will automatically be cleared on read, therefore we no longer need to
+clear bits explicitly.
+
+Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
+Acked-by: Alexander Duyck <alexander.h.duyck@intel.com>
+Tested-by: Aaron Brown <aaron.f.brown@intel.com>
+Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
+---
+ drivers/net/ethernet/intel/e1000e/defines.h | 21 ++++++++++++++++++++-
+ drivers/net/ethernet/intel/e1000e/netdev.c  | 11 ++++-------
+ 2 files changed, 24 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/ethernet/intel/e1000e/defines.h
++++ b/drivers/net/ethernet/intel/e1000e/defines.h
+@@ -400,6 +400,10 @@
+ #define E1000_ICR_RXDMT0        0x00000010 /* Rx desc min. threshold (0) */
+ #define E1000_ICR_RXO           0x00000040 /* Receiver Overrun */
+ #define E1000_ICR_RXT0          0x00000080 /* Rx timer intr (ring 0) */
++#define E1000_ICR_MDAC          0x00000200 /* MDIO Access Complete */
++#define E1000_ICR_SRPD          0x00010000 /* Small Receive Packet Detected */
++#define E1000_ICR_ACK           0x00020000 /* Receive ACK Frame Detected */
++#define E1000_ICR_MNG           0x00040000 /* Manageability Event Detected */
+ #define E1000_ICR_ECCER         0x00400000 /* Uncorrectable ECC Error */
+ /* If this bit asserted, the driver should claim the interrupt */
+ #define E1000_ICR_INT_ASSERTED        0x80000000
+@@ -407,7 +411,7 @@
+ #define E1000_ICR_RXQ1          0x00200000 /* Rx Queue 1 Interrupt */
+ #define E1000_ICR_TXQ0          0x00400000 /* Tx Queue 0 Interrupt */
+ #define E1000_ICR_TXQ1          0x00800000 /* Tx Queue 1 Interrupt */
+-#define E1000_ICR_OTHER         0x01000000 /* Other Interrupts */
++#define E1000_ICR_OTHER         0x01000000 /* Other Interrupt */
+ /* PBA ECC Register */
+ #define E1000_PBA_ECC_COUNTER_MASK  0xFFF00000 /* ECC counter mask */
+@@ -431,12 +435,27 @@
+       E1000_IMS_RXSEQ  |    \
+       E1000_IMS_LSC)
++/* These are all of the events related to the OTHER interrupt.
++ */
++#define IMS_OTHER_MASK ( \
++      E1000_IMS_LSC  | \
++      E1000_IMS_RXO  | \
++      E1000_IMS_MDAC | \
++      E1000_IMS_SRPD | \
++      E1000_IMS_ACK  | \
++      E1000_IMS_MNG)
++
+ /* Interrupt Mask Set */
+ #define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
+ #define E1000_IMS_LSC       E1000_ICR_LSC       /* Link Status Change */
+ #define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* Rx sequence error */
+ #define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* Rx desc min. threshold */
++#define E1000_IMS_RXO       E1000_ICR_RXO       /* Receiver Overrun */
+ #define E1000_IMS_RXT0      E1000_ICR_RXT0      /* Rx timer intr */
++#define E1000_IMS_MDAC      E1000_ICR_MDAC      /* MDIO Access Complete */
++#define E1000_IMS_SRPD      E1000_ICR_SRPD      /* Small Receive Packet */
++#define E1000_IMS_ACK       E1000_ICR_ACK       /* Receive ACK Frame Detected */
++#define E1000_IMS_MNG       E1000_ICR_MNG       /* Manageability Event */
+ #define E1000_IMS_ECCER     E1000_ICR_ECCER     /* Uncorrectable ECC Error */
+ #define E1000_IMS_RXQ0      E1000_ICR_RXQ0      /* Rx Queue 0 Interrupt */
+ #define E1000_IMS_RXQ1      E1000_ICR_RXQ1      /* Rx Queue 1 Interrupt */
+--- a/drivers/net/ethernet/intel/e1000e/netdev.c
++++ b/drivers/net/ethernet/intel/e1000e/netdev.c
+@@ -1910,16 +1910,12 @@ static irqreturn_t e1000_msix_other(int
+       struct net_device *netdev = data;
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+-      u32 icr;
+-
+-      icr = er32(ICR);
+-      ew32(ICR, E1000_ICR_OTHER);
++      u32 icr = er32(ICR);
+       if (icr & adapter->eiac_mask)
+               ew32(ICS, (icr & adapter->eiac_mask));
+       if (icr & E1000_ICR_LSC) {
+-              ew32(ICR, E1000_ICR_LSC);
+               hw->mac.get_link_status = true;
+               /* guard against interrupt when we're going down */
+               if (!test_bit(__E1000_DOWN, &adapter->state))
+@@ -1927,7 +1923,7 @@ static irqreturn_t e1000_msix_other(int
+       }
+       if (!test_bit(__E1000_DOWN, &adapter->state))
+-              ew32(IMS, E1000_IMS_OTHER);
++              ew32(IMS, E1000_IMS_OTHER | IMS_OTHER_MASK);
+       return IRQ_HANDLED;
+ }
+@@ -2254,7 +2250,8 @@ static void e1000_irq_enable(struct e100
+       if (adapter->msix_entries) {
+               ew32(EIAC_82574, adapter->eiac_mask & E1000_EIAC_MASK_82574);
+-              ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER | E1000_IMS_LSC);
++              ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER |
++                   IMS_OTHER_MASK);
+       } else if (hw->mac.type >= e1000_pch_lpt) {
+               ew32(IMS, IMS_ENABLE_MASK | E1000_IMS_ECCER);
+       } else {