netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/4] e1000e msi-x fixes
@ 2015-10-30 17:31 Benjamin Poirier
  2015-10-30 17:31 ` [PATCH v2 1/4] e1000e: Remove unreachable code Benjamin Poirier
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Benjamin Poirier @ 2015-10-30 17:31 UTC (permalink / raw)
  To: Jeff Kirsher
  Cc: Alexander Duyck, Frank Steiner, Jesse Brandeburg, Shannon Nelson,
	Carolyn Wyborny, Don Skidmore, Matthew Vick, John Ronciak,
	Mitch Williams, intel-wired-lan, netdev, linux-kernel

Hi,

For this series:


Benjamin Poirier (4):
  e1000e: Remove unreachable code
  e1000e: Do not read icr in Other interrupt
  e1000e: Do not write lsc to ics in msi-x mode
  e1000e: Fix msi-x interrupt automask

 drivers/net/ethernet/intel/e1000e/defines.h |  3 +-
 drivers/net/ethernet/intel/e1000e/netdev.c  | 65 +++++++++++++----------------
 2 files changed, 30 insertions(+), 38 deletions(-)

Changes in v2:
Address review comments from Alexander Duyck: extend cleanup of Other
interrupt handler and use tx_ring->ims_val.


The first three patches cleanup handling of Other interrupts and the
last patch fixes tx and rx interrupts. Please consider reading the
description for that patch before proceeding. I believe that the
following simple tracing statements are helpful in detecting the problem
fixed by the last patch.

diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 8881256..707a525 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -1952,6 +1952,9 @@ static irqreturn_t e1000_intr_msix_rx(int __always_unused irq, void *data)
 	struct net_device *netdev = data;
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_ring *rx_ring = adapter->rx_ring;
+	struct e1000_hw *hw = &adapter->hw;
+
+	trace_printk("%s: rxq0 irq ims 0x%08x\n", netdev->name, er32(IMS));
 
 	/* Write the ITR value calculated at the end of the
 	 * previous interrupt.
@@ -1966,6 +1969,7 @@ static irqreturn_t e1000_intr_msix_rx(int __always_unused irq, void *data)
 		adapter->total_rx_bytes = 0;
 		adapter->total_rx_packets = 0;
 		__napi_schedule(&adapter->napi);
+		trace_printk("%s: scheduling napi\n", netdev->name);
 	}
 	return IRQ_HANDLED;
 }
@@ -2672,6 +2676,8 @@ static int e1000e_poll(struct napi_struct *napi, int weight)
 	struct net_device *poll_dev = adapter->netdev;
 	int tx_cleaned = 1, work_done = 0;
 
+	trace_printk("%s: poll starting ims 0x%08x\n", poll_dev->name,
+		     er32(IMS));
 	adapter = netdev_priv(poll_dev);
 
 	if (!adapter->msix_entries ||
@@ -2689,6 +2695,8 @@ static int e1000e_poll(struct napi_struct *napi, int weight)
 			e1000_set_itr(adapter);
 		napi_complete_done(napi, work_done);
 		if (!test_bit(__E1000_DOWN, &adapter->state)) {
+			trace_printk("%s: will enable rxq0 irq\n",
+				     poll_dev->name);
 			if (adapter->msix_entries)
 				ew32(IMS, adapter->rx_ring->ims_val);
 			else

-------- 8< --------

With that patch but without the patches in this series we can see that rx irqs
occur at unexpected times:

          <idle>-0     [000] .Ns.  1986.887517: e1000e_poll: eth1: will enable rxq0 irq
          <idle>-0     [000] d.h.  1986.896654: e1000_intr_msix_rx: eth1: rxq0 irq ims 0x01500004
          <idle>-0     [000] d.h.  1986.896657: e1000_intr_msix_rx: eth1: scheduling napi
          <idle>-0     [000] d.H.  1986.896662: e1000_intr_msix_rx: eth1: rxq0 irq ims 0x01500004
          <idle>-0     [000] ..s.  1986.896667: e1000e_poll: eth1: poll starting ims 0x01500004
Warning: many interrupts (2) before napi
          <idle>-0     [000] ..s.  1986.896685: e1000e_poll: eth1: will enable rxq0 irq

          <idle>-0     [000] d.h.  1990.688870: e1000_intr_msix_rx: eth1: scheduling napi
          <idle>-0     [000] ..s.  1990.688875: e1000e_poll: eth1: poll starting ims 0x01500004
          <idle>-0     [000] dNH.  1990.688913: e1000_intr_msix_rx: eth1: rxq0 irq ims 0x01500004
Warning: interrupt inside napi
          <idle>-0     [000] .Ns.  1990.688916: e1000e_poll: eth1: will enable rxq0 irq
          <idle>-0     [000] d.h.  1990.729688: e1000_intr_msix_rx: eth1: rxq0 irq ims 0x01500004

Here's a typical sequence after applying the patches in this series. Notice
that ims is changed. Another printk at the end of e1000e_poll would show it to
be 0x01500000.

          <idle>-0     [000] d.h. 672874.016104: e1000_intr_msix_rx: eth1: rxq0 irq ims 0x01400000
          <idle>-0     [000] d.h. 672874.016107: e1000_intr_msix_rx: eth1: scheduling napi
          <idle>-0     [000] ..s. 672874.016112: e1000e_poll: eth1: poll starting ims 0x01400000
          <idle>-0     [000] ..s. 672874.016126: e1000e_poll: eth1: will enable rxq0 irq

Finally, here's the script I used to generate the warnings above:

#!/usr/bin/python3

import sys
import re
import pprint


class NaE(Exception):
    "Not an Event"
    pass

class Event:
    def __init__(self, line):
        # sample events:
        #  <idle>-0     [000] d.h.  2025.256536: e1000_intr_msix_rx: eth1: rxq0 irq ims 0x01500004
        #  <idle>-0     [000] d.h.  2025.256539: e1000_intr_msix_rx: eth1: scheduling napi
        #  <idle>-0     [000] ..s.  2025.256544: e1000e_poll: eth1: poll starting ims 0x01500004
        #  <idle>-0     [000] ..s.  2025.256558: e1000e_poll: eth1: will enable rxq0 irq
        retval = re.match(" +<?(?P<comm>.*)>?-(?P<pid>[0-9]+) +\[(?P<cpu>.*)\] (?P<flags>[^ ]+) +(?P<time>[0-9.]+): (?P<funcname>[^:]+): (?P<ifname>[^:]+): (?P<args>.*)", line)
        if retval:
            self.comm = retval.group("comm")
            self.pid = retval.group("pid")
            self.cpu = retval.group("cpu")
            self.flags = retval.group("flags")
            self.time = retval.group("time")
            self.funcname = retval.group("funcname")
            self.ifname = retval.group("ifname")
            self.args = retval.group("args")
        else:
            raise NaE


class Machine:
    pass

class State:
    def __init__(self, machine):
        self.machine = machine

    def entry(self, event):
        pass

    def transition(self, event):
        "self.machine should be considered read-only in transition"
        return State(self.machine)

    def run(self, event):
        pass

    def exit(self, event):
        pass

    def advance(self, event):
            nextState = self.transition(event)
            if (nextState != self):
                self.exit(event)
                nextState.entry(event)
            nextState.run(event)
            return nextState

# general receive processing machine
def enteringNapi(machine, event):
    if event.args.startswith("poll starting"):
        return True
    else:
        return False

def exitingNapi(machine, event):
    if event.args.startswith("will enable"):
        return True
    else:
        return False

class OutsideNapi(State):
    def entry(self, event):
        self.machine.intr = []

    def transition(self, event):
        if enteringNapi(self.machine, event):
            return InsideNapi(self.machine)
        else:
            return self

    def run(self, event):
        if event.args.startswith("rxq0 irq"):
            self.machine.intr.append(event)

    def exit(self, event):
        if len(self.machine.intr) > 1:
            print("Warning: many interrupts (%d) before napi at %s" % (
                len(self.machine.intr), event.time,))

class InsideNapi(State):
    def transition(self, event):
        if exitingNapi(self.machine, event):
            return OutsideNapi(self.machine)
        else:
            return self

    def run(self, event):
        if event.args.startswith("rxq0 irq"):
            print("Warning: interrupt inside napi")

class UnknownState(State):
    def transition(self, event):
        if enteringNapi(self.machine, event):
            return InsideNapi(self.machine)
        elif exitingNapi(self.machine, event):
            return ExitingNapi(self.machine)
        else:
            return self


if __name__ == '__main__':
    debug = False

    state = UnknownState(Machine())

    for line in sys.stdin:
        print(line, end='')
        try:
            event = Event(line)
        except NaE:
            pass
        else:
            if debug:
                pprinter.pprint(event)
            state = state.advance(event)

-- 
2.6.0

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 1/4] e1000e: Remove unreachable code
  2015-10-30 17:31 [PATCH v2 0/4] e1000e msi-x fixes Benjamin Poirier
@ 2015-10-30 17:31 ` Benjamin Poirier
  2015-10-30 17:31 ` [PATCH v2 2/4] e1000e: Do not read icr in Other interrupt Benjamin Poirier
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 8+ messages in thread
From: Benjamin Poirier @ 2015-10-30 17:31 UTC (permalink / raw)
  To: Jeff Kirsher
  Cc: Alexander Duyck, Frank Steiner, Jesse Brandeburg, Shannon Nelson,
	Carolyn Wyborny, Don Skidmore, Matthew Vick, John Ronciak,
	Mitch Williams, intel-wired-lan, netdev, linux-kernel

msi-x interrupts are not shared so there's no need to check if the
interrupt was really from this adapter.

Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
---
 drivers/net/ethernet/intel/e1000e/netdev.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 0a854a4..a228167 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -1907,12 +1907,6 @@ static irqreturn_t e1000_msix_other(int __always_unused irq, void *data)
 	struct e1000_hw *hw = &adapter->hw;
 	u32 icr = er32(ICR);
 
-	if (!(icr & E1000_ICR_INT_ASSERTED)) {
-		if (!test_bit(__E1000_DOWN, &adapter->state))
-			ew32(IMS, E1000_IMS_OTHER);
-		return IRQ_NONE;
-	}
-
 	if (icr & adapter->eiac_mask)
 		ew32(ICS, (icr & adapter->eiac_mask));
 
-- 
2.6.0

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 2/4] e1000e: Do not read icr in Other interrupt
  2015-10-30 17:31 [PATCH v2 0/4] e1000e msi-x fixes Benjamin Poirier
  2015-10-30 17:31 ` [PATCH v2 1/4] e1000e: Remove unreachable code Benjamin Poirier
@ 2015-10-30 17:31 ` Benjamin Poirier
  2015-10-30 19:19   ` Alexander Duyck
  2015-10-30 17:31 ` [PATCH v2 3/4] e1000e: Do not write lsc to ics in msi-x mode Benjamin Poirier
  2015-10-30 17:31 ` [PATCH v2 4/4] e1000e: Fix msi-x interrupt automask Benjamin Poirier
  3 siblings, 1 reply; 8+ messages in thread
From: Benjamin Poirier @ 2015-10-30 17:31 UTC (permalink / raw)
  To: Jeff Kirsher
  Cc: Alexander Duyck, Frank Steiner, Jesse Brandeburg, Shannon Nelson,
	Carolyn Wyborny, Don Skidmore, Matthew Vick, John Ronciak,
	Mitch Williams, intel-wired-lan, netdev, linux-kernel

Using eiac instead of reading icr allows us to avoid interference with
rx and tx interrupts in the Other interrupt handler.

According to the 82574 datasheet section 10.2.4.1, interrupt causes that
trigger the Other interrupt are
1) Link Status Change.
2) Receiver Overrun.
3) MDIO Access Complete.
4) Small Receive Packet Detected.
5) Receive ACK Frame Detected.
6) Manageability Event Detected.

Causes 3, 4, 5 are related to features which are not enabled by the
driver. Always assume that cause 1 is what triggered the Other interrupt
and set get_link_status. Cause 2 and 6 should be rare enough that the
extra cost of needlessly re-reading the link status is negligible.

Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
---
 drivers/net/ethernet/intel/e1000e/netdev.c | 23 ++++++++---------------
 1 file changed, 8 insertions(+), 15 deletions(-)

diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index a228167..602fcc9 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -1905,24 +1905,16 @@ static irqreturn_t e1000_msix_other(int __always_unused irq, void *data)
 	struct net_device *netdev = data;
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
-	u32 icr = er32(ICR);
 
-	if (icr & adapter->eiac_mask)
-		ew32(ICS, (icr & adapter->eiac_mask));
+	/* Assume that the Other interrupt was triggered by LSC */
+	hw->mac.get_link_status = true;
 
-	if (icr & E1000_ICR_OTHER) {
-		if (!(icr & E1000_ICR_LSC))
-			goto no_link_interrupt;
-		hw->mac.get_link_status = true;
-		/* guard against interrupt when we're going down */
-		if (!test_bit(__E1000_DOWN, &adapter->state))
-			mod_timer(&adapter->watchdog_timer, jiffies + 1);
+	/* guard against interrupt when we're going down */
+	if (!test_bit(__E1000_DOWN, &adapter->state)) {
+		mod_timer(&adapter->watchdog_timer, jiffies + 1);
+		ew32(IMS, E1000_IMS_OTHER);
 	}
 
-no_link_interrupt:
-	if (!test_bit(__E1000_DOWN, &adapter->state))
-		ew32(IMS, E1000_IMS_LSC | E1000_IMS_OTHER);
-
 	return IRQ_HANDLED;
 }
 
@@ -2019,6 +2011,7 @@ static void e1000_configure_msix(struct e1000_adapter *adapter)
 		       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 |= (1 << 31);
@@ -2247,7 +2240,7 @@ static void e1000_irq_enable(struct e1000_adapter *adapter)
 
 	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);
 	} else if ((hw->mac.type == e1000_pch_lpt) ||
 		   (hw->mac.type == e1000_pch_spt)) {
 		ew32(IMS, IMS_ENABLE_MASK | E1000_IMS_ECCER);
-- 
2.6.0

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 3/4] e1000e: Do not write lsc to ics in msi-x mode
  2015-10-30 17:31 [PATCH v2 0/4] e1000e msi-x fixes Benjamin Poirier
  2015-10-30 17:31 ` [PATCH v2 1/4] e1000e: Remove unreachable code Benjamin Poirier
  2015-10-30 17:31 ` [PATCH v2 2/4] e1000e: Do not read icr in Other interrupt Benjamin Poirier
@ 2015-10-30 17:31 ` Benjamin Poirier
  2015-10-30 17:31 ` [PATCH v2 4/4] e1000e: Fix msi-x interrupt automask Benjamin Poirier
  3 siblings, 0 replies; 8+ messages in thread
From: Benjamin Poirier @ 2015-10-30 17:31 UTC (permalink / raw)
  To: Jeff Kirsher
  Cc: Alexander Duyck, Frank Steiner, Jesse Brandeburg, Shannon Nelson,
	Carolyn Wyborny, Don Skidmore, Matthew Vick, John Ronciak,
	Mitch Williams, intel-wired-lan, netdev, linux-kernel

In msi-x mode, there is no handler for the lsc interrupt so there is no
point in writing that to ics now that we always assume Other interrupts
are caused by lsc.

Reviewed-by: Jasna Hodzic <jhodzic@ucdavis.edu>
Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
---
 drivers/net/ethernet/intel/e1000e/defines.h |  3 ++-
 drivers/net/ethernet/intel/e1000e/netdev.c  | 27 ++++++++++++++++-----------
 2 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h
index 133d407..f7c7804 100644
--- a/drivers/net/ethernet/intel/e1000e/defines.h
+++ b/drivers/net/ethernet/intel/e1000e/defines.h
@@ -441,12 +441,13 @@
 #define E1000_IMS_RXQ1      E1000_ICR_RXQ1      /* Rx Queue 1 Interrupt */
 #define E1000_IMS_TXQ0      E1000_ICR_TXQ0      /* Tx Queue 0 Interrupt */
 #define E1000_IMS_TXQ1      E1000_ICR_TXQ1      /* Tx Queue 1 Interrupt */
-#define E1000_IMS_OTHER     E1000_ICR_OTHER     /* Other Interrupts */
+#define E1000_IMS_OTHER     E1000_ICR_OTHER     /* Other Interrupt */
 
 /* Interrupt Cause Set */
 #define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
 #define E1000_ICS_RXSEQ     E1000_ICR_RXSEQ     /* Rx sequence error */
 #define E1000_ICS_RXDMT0    E1000_ICR_RXDMT0    /* Rx desc min. threshold */
+#define E1000_ICS_OTHER     E1000_ICR_OTHER     /* Other Interrupt */
 
 /* Transmit Descriptor Control */
 #define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 602fcc9..639fbe8 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -4131,10 +4131,23 @@ void e1000e_reset(struct e1000_adapter *adapter)
 
 }
 
-int e1000e_up(struct e1000_adapter *adapter)
+/**
+ * e1000e_trigger_lsc - trigger a lsc interrupt
+ *
+ * Fire a link status change interrupt to start the watchdog.
+ **/
+static void e1000e_trigger_lsc(struct e1000_adapter *adapter)
 {
 	struct e1000_hw *hw = &adapter->hw;
 
+	if (adapter->msix_entries)
+		ew32(ICS, E1000_ICS_OTHER);
+	else
+		ew32(ICS, E1000_ICS_LSC);
+}
+
+int e1000e_up(struct e1000_adapter *adapter)
+{
 	/* hardware has been reset, we need to reload some things */
 	e1000_configure(adapter);
 
@@ -4146,11 +4159,7 @@ int e1000e_up(struct e1000_adapter *adapter)
 
 	netif_start_queue(adapter->netdev);
 
-	/* fire a link change interrupt to start the watchdog */
-	if (adapter->msix_entries)
-		ew32(ICS, E1000_ICS_LSC | E1000_ICR_OTHER);
-	else
-		ew32(ICS, E1000_ICS_LSC);
+	e1000e_trigger_lsc(adapter);
 
 	return 0;
 }
@@ -4577,11 +4586,7 @@ static int e1000_open(struct net_device *netdev)
 	hw->mac.get_link_status = true;
 	pm_runtime_put(&pdev->dev);
 
-	/* fire a link status change interrupt to start the watchdog */
-	if (adapter->msix_entries)
-		ew32(ICS, E1000_ICS_LSC | E1000_ICR_OTHER);
-	else
-		ew32(ICS, E1000_ICS_LSC);
+	e1000e_trigger_lsc(adapter);
 
 	return 0;
 
-- 
2.6.0

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 4/4] e1000e: Fix msi-x interrupt automask
  2015-10-30 17:31 [PATCH v2 0/4] e1000e msi-x fixes Benjamin Poirier
                   ` (2 preceding siblings ...)
  2015-10-30 17:31 ` [PATCH v2 3/4] e1000e: Do not write lsc to ics in msi-x mode Benjamin Poirier
@ 2015-10-30 17:31 ` Benjamin Poirier
  3 siblings, 0 replies; 8+ messages in thread
From: Benjamin Poirier @ 2015-10-30 17:31 UTC (permalink / raw)
  To: Jeff Kirsher
  Cc: Alexander Duyck, Frank Steiner, Jesse Brandeburg, Shannon Nelson,
	Carolyn Wyborny, Don Skidmore, Matthew Vick, John Ronciak,
	Mitch Williams, intel-wired-lan, netdev, linux-kernel

Since the introduction of 82574 support in e1000e, the driver has worked
on the assumption that msi-x interrupt generation is automatically
disabled after each irq. As it turns out, this is not the case.
Currently, rx interrupts can fire multiple times before and during napi
processing. This can be a problem for users because frames that arrive
in a certain window (after adapter->clean_rx() but before
napi_complete_done() has cleared NAPI_STATE_SCHED) generate an interrupt
which does not lead to napi_schedule(). These frames sit in the rx queue
until another frame arrives (a tcp retransmit for example).

While the EIAC and CTRL_EXT registers are properly configured for irq
automask, the modification of IAM in e1000_configure_msix() is what
prevents automask from working as intended.

This patch removes that erroneous write and fixes interrupt rearming for
tx interrupts.

Reported-by: Frank Steiner <steiner-reg@bio.ifi.lmu.de>
Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
---
 drivers/net/ethernet/intel/e1000e/netdev.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 639fbe8..b5549d1 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -1932,6 +1932,9 @@ static irqreturn_t e1000_intr_msix_tx(int __always_unused irq, void *data)
 		/* Ring was not completely cleaned, so fire another interrupt */
 		ew32(ICS, tx_ring->ims_val);
 
+	if (!test_bit(__E1000_DOWN, &adapter->state))
+		ew32(IMS, adapter->tx_ring->ims_val);
+
 	return IRQ_HANDLED;
 }
 
@@ -2020,11 +2023,7 @@ static void e1000_configure_msix(struct e1000_adapter *adapter)
 
 	/* enable MSI-X PBA support */
 	ctrl_ext = er32(CTRL_EXT);
-	ctrl_ext |= E1000_CTRL_EXT_PBA_CLR;
-
-	/* Auto-Mask Other interrupts upon ICR read */
-	ew32(IAM, ~E1000_EIAC_MASK_82574 | E1000_IMS_OTHER);
-	ctrl_ext |= E1000_CTRL_EXT_EIAME;
+	ctrl_ext |= E1000_CTRL_EXT_PBA_CLR | E1000_CTRL_EXT_EIAME;
 	ew32(CTRL_EXT, ctrl_ext);
 	e1e_flush();
 }
-- 
2.6.0

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/4] e1000e: Do not read icr in Other interrupt
  2015-10-30 17:31 ` [PATCH v2 2/4] e1000e: Do not read icr in Other interrupt Benjamin Poirier
@ 2015-10-30 19:19   ` Alexander Duyck
  2015-11-04 23:19     ` Benjamin Poirier
  0 siblings, 1 reply; 8+ messages in thread
From: Alexander Duyck @ 2015-10-30 19:19 UTC (permalink / raw)
  To: Benjamin Poirier, Jeff Kirsher
  Cc: Frank Steiner, Jesse Brandeburg, Shannon Nelson, Carolyn Wyborny,
	Don Skidmore, Matthew Vick, John Ronciak, Mitch Williams,
	intel-wired-lan, netdev, linux-kernel

On 10/30/2015 10:31 AM, Benjamin Poirier wrote:
> Using eiac instead of reading icr allows us to avoid interference with
> rx and tx interrupts in the Other interrupt handler.
>
> According to the 82574 datasheet section 10.2.4.1, interrupt causes that
> trigger the Other interrupt are
> 1) Link Status Change.
> 2) Receiver Overrun.
> 3) MDIO Access Complete.
> 4) Small Receive Packet Detected.
> 5) Receive ACK Frame Detected.
> 6) Manageability Event Detected.
>
> Causes 3, 4, 5 are related to features which are not enabled by the
> driver. Always assume that cause 1 is what triggered the Other interrupt
> and set get_link_status. Cause 2 and 6 should be rare enough that the
> extra cost of needlessly re-reading the link status is negligible.
>
> Signed-off-by: Benjamin Poirier <bpoirier@suse.com>

You might want to instead use a write of LSC to the ICR instead of just 
using auto-clear and not enabling LSC.  My concern is that you might no 
longer be getting link status change events at all.  An easy test is to 
just unplug/plug the cable a few times, or run "ethtool -r" on the link 
partner if connected back to back.  You should see messages appear in 
the dmesg log indicating that the link state changed.

In addition you should probably clear the IAME bit in the CTRL_EXT 
register so that you don't risk masking the interrupts on the ICR read 
or write.

> ---
>   drivers/net/ethernet/intel/e1000e/netdev.c | 23 ++++++++---------------
>   1 file changed, 8 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
> index a228167..602fcc9 100644
> --- a/drivers/net/ethernet/intel/e1000e/netdev.c
> +++ b/drivers/net/ethernet/intel/e1000e/netdev.c
> @@ -1905,24 +1905,16 @@ static irqreturn_t e1000_msix_other(int __always_unused irq, void *data)
>   	struct net_device *netdev = data;
>   	struct e1000_adapter *adapter = netdev_priv(netdev);
>   	struct e1000_hw *hw = &adapter->hw;
> -	u32 icr = er32(ICR);
>
> -	if (icr & adapter->eiac_mask)
> -		ew32(ICS, (icr & adapter->eiac_mask));
> +	/* Assume that the Other interrupt was triggered by LSC */
> +	hw->mac.get_link_status = true;
>
> -	if (icr & E1000_ICR_OTHER) {
> -		if (!(icr & E1000_ICR_LSC))
> -			goto no_link_interrupt;
> -		hw->mac.get_link_status = true;
> -		/* guard against interrupt when we're going down */
> -		if (!test_bit(__E1000_DOWN, &adapter->state))
> -			mod_timer(&adapter->watchdog_timer, jiffies + 1);

You could probably just pop a write to the ICR register here to clear 
the LSC bit since you are auto clearing the OTHER bit.

> +	/* guard against interrupt when we're going down */
> +	if (!test_bit(__E1000_DOWN, &adapter->state)) {
> +		mod_timer(&adapter->watchdog_timer, jiffies + 1);
> +		ew32(IMS, E1000_IMS_OTHER);
>   	}
>
> -no_link_interrupt:
> -	if (!test_bit(__E1000_DOWN, &adapter->state))
> -		ew32(IMS, E1000_IMS_LSC | E1000_IMS_OTHER);
> -
>   	return IRQ_HANDLED;
>   }
>
> @@ -2019,6 +2011,7 @@ static void e1000_configure_msix(struct e1000_adapter *adapter)
>   		       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 |= (1 << 31);
> @@ -2247,7 +2240,7 @@ static void e1000_irq_enable(struct e1000_adapter *adapter)
>
>   	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);

You might want to consider adding a write to IAM here that would limit 
the auto masking to same bits you are auto clearing.

I would probably leave E1000_IMS_LSC set in the IMS.  No need to 
auto-mask it since the mask for other will keep it from triggering more 
than once.

>   	} else if ((hw->mac.type == e1000_pch_lpt) ||
>   		   (hw->mac.type == e1000_pch_spt)) {
>   		ew32(IMS, IMS_ENABLE_MASK | E1000_IMS_ECCER);
>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/4] e1000e: Do not read icr in Other interrupt
  2015-10-30 19:19   ` Alexander Duyck
@ 2015-11-04 23:19     ` Benjamin Poirier
  2015-11-04 23:26       ` Alexander Duyck
  0 siblings, 1 reply; 8+ messages in thread
From: Benjamin Poirier @ 2015-11-04 23:19 UTC (permalink / raw)
  To: Alexander Duyck
  Cc: Jeff Kirsher, Frank Steiner, Jesse Brandeburg, Shannon Nelson,
	Carolyn Wyborny, Don Skidmore, Matthew Vick, John Ronciak,
	Mitch Williams, intel-wired-lan, netdev, linux-kernel

On 2015/10/30 12:19, Alexander Duyck wrote:
> On 10/30/2015 10:31 AM, Benjamin Poirier wrote:
> >Using eiac instead of reading icr allows us to avoid interference with
> >rx and tx interrupts in the Other interrupt handler.
> >
> >According to the 82574 datasheet section 10.2.4.1, interrupt causes that
> >trigger the Other interrupt are
> >1) Link Status Change.
> >2) Receiver Overrun.
> >3) MDIO Access Complete.
> >4) Small Receive Packet Detected.
> >5) Receive ACK Frame Detected.
> >6) Manageability Event Detected.
> >
> >Causes 3, 4, 5 are related to features which are not enabled by the
> >driver. Always assume that cause 1 is what triggered the Other interrupt
> >and set get_link_status. Cause 2 and 6 should be rare enough that the
> >extra cost of needlessly re-reading the link status is negligible.
> >
> >Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
> 
> You might want to instead use a write of LSC to the ICR instead of just
> using auto-clear and not enabling LSC.  My concern is that you might no
> longer be getting link status change events at all.  An easy test is to just
> unplug/plug the cable a few times, or run "ethtool -r" on the link partner
> if connected back to back.  You should see messages appear in the dmesg log
> indicating that the link state changed.
> 
> In addition you should probably clear the IAME bit in the CTRL_EXT register
> so that you don't risk masking the interrupts on the ICR read or write.

Thanks, your concern about not getting LSC events was right. After more
experimentation I noticed that in order for the Other interrupt to be
raised for each of these six conditions, the IMS bit for that condition
must also be set. I've restored setting LSC in IMS. OTOH, I don't see a
need to clear LSC from ICR. Even without an ICR read or write-to-clear
to clear the LSC bit, Other interrupts are raised to signal LSC events.

I'll wait for net-next to reopen and send v3.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/4] e1000e: Do not read icr in Other interrupt
  2015-11-04 23:19     ` Benjamin Poirier
@ 2015-11-04 23:26       ` Alexander Duyck
  0 siblings, 0 replies; 8+ messages in thread
From: Alexander Duyck @ 2015-11-04 23:26 UTC (permalink / raw)
  To: Benjamin Poirier
  Cc: Jeff Kirsher, Frank Steiner, Jesse Brandeburg, Shannon Nelson,
	Carolyn Wyborny, Don Skidmore, Matthew Vick, John Ronciak,
	Mitch Williams, intel-wired-lan, netdev, linux-kernel

On 11/04/2015 03:19 PM, Benjamin Poirier wrote:
> On 2015/10/30 12:19, Alexander Duyck wrote:
>> On 10/30/2015 10:31 AM, Benjamin Poirier wrote:
>>> Using eiac instead of reading icr allows us to avoid interference with
>>> rx and tx interrupts in the Other interrupt handler.
>>>
>>> According to the 82574 datasheet section 10.2.4.1, interrupt causes that
>>> trigger the Other interrupt are
>>> 1) Link Status Change.
>>> 2) Receiver Overrun.
>>> 3) MDIO Access Complete.
>>> 4) Small Receive Packet Detected.
>>> 5) Receive ACK Frame Detected.
>>> 6) Manageability Event Detected.
>>>
>>> Causes 3, 4, 5 are related to features which are not enabled by the
>>> driver. Always assume that cause 1 is what triggered the Other interrupt
>>> and set get_link_status. Cause 2 and 6 should be rare enough that the
>>> extra cost of needlessly re-reading the link status is negligible.
>>>
>>> Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
>> You might want to instead use a write of LSC to the ICR instead of just
>> using auto-clear and not enabling LSC.  My concern is that you might no
>> longer be getting link status change events at all.  An easy test is to just
>> unplug/plug the cable a few times, or run "ethtool -r" on the link partner
>> if connected back to back.  You should see messages appear in the dmesg log
>> indicating that the link state changed.
>>
>> In addition you should probably clear the IAME bit in the CTRL_EXT register
>> so that you don't risk masking the interrupts on the ICR read or write.
> Thanks, your concern about not getting LSC events was right. After more
> experimentation I noticed that in order for the Other interrupt to be
> raised for each of these six conditions, the IMS bit for that condition
> must also be set. I've restored setting LSC in IMS. OTOH, I don't see a
> need to clear LSC from ICR. Even without an ICR read or write-to-clear
> to clear the LSC bit, Other interrupts are raised to signal LSC events.
>
> I'll wait for net-next to reopen and send v3.

You probably don't need to wait.  The Intel-wired tree operates outside 
of Dave's merge window, and it will take some time for the patches to be 
validated before the Jeff can submit them to Dave.

- Alex

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2015-11-04 23:26 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-10-30 17:31 [PATCH v2 0/4] e1000e msi-x fixes Benjamin Poirier
2015-10-30 17:31 ` [PATCH v2 1/4] e1000e: Remove unreachable code Benjamin Poirier
2015-10-30 17:31 ` [PATCH v2 2/4] e1000e: Do not read icr in Other interrupt Benjamin Poirier
2015-10-30 19:19   ` Alexander Duyck
2015-11-04 23:19     ` Benjamin Poirier
2015-11-04 23:26       ` Alexander Duyck
2015-10-30 17:31 ` [PATCH v2 3/4] e1000e: Do not write lsc to ics in msi-x mode Benjamin Poirier
2015-10-30 17:31 ` [PATCH v2 4/4] e1000e: Fix msi-x interrupt automask Benjamin Poirier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).