git: 1fb96c59b4ce - stable/13 - e1000: Rework em_msi_link interrupt filter

Kevin Bowling kbowling at FreeBSD.org
Fri May 28 05:50:49 UTC 2021


The branch stable/13 has been updated by kbowling (ports committer):

URL: https://cgit.FreeBSD.org/src/commit/?id=1fb96c59b4ce265ea94eddef5a97c7c075ceaec5

commit 1fb96c59b4ce265ea94eddef5a97c7c075ceaec5
Author:     Kevin Bowling <kbowling at FreeBSD.org>
AuthorDate: 2021-04-25 08:22:23 +0000
Commit:     Kevin Bowling <kbowling at FreeBSD.org>
CommitDate: 2021-05-28 05:50:07 +0000

    e1000: Rework em_msi_link interrupt filter
    
    * Fix 82574 Link Status Changes, carrying the OTHER mask bit around as
      needed.
    * Move igb-class LSC re-arming out of FAST back into the handler.
    * Clarify spurious/other interrupt re-arms in FAST.
    
    In MSI-X mode, 82574 and igb-class devices use an interrupt filter to
    handle Link Status Changes. We want to do LSC re-arms in the handler
    to take advantage of autoclear (EIAC) single shot behavior.
    
    82574 uses 'Other' in ICR and IMS for LSC interrupt types when in MSI-X
    mode, so we need to set and re-arm the 'Other' bit during attach and
    after ICR reads in the FAST handler if not an LSC or after handling on
    LSC due to autoclearing.
    
    This work was primarily done to address the referenced PR, but inspired
    some clarification and improvement for igb-class devices once the
    intentions of previous bug fix attempts became clearer.
    
    PR:             211219
    Reported by:    Alexey <aserp3 at gmail.com>
    Tested by:      kbowling (I210 lagg), markj (I210)
    Approved by:    markj
    MFC after:      1 month
    Differential Revision:  https://reviews.freebsd.org/D29943
    
    (cherry picked from commit eea55de7b10808b86277d7fdbed2d05d3c6db1b2)
---
 sys/dev/e1000/if_em.c | 41 ++++++++++++++++++++++++-----------------
 sys/dev/e1000/if_em.h |  2 --
 2 files changed, 24 insertions(+), 19 deletions(-)

diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c
index f7dab611c13f..c9a6648b34a0 100644
--- a/sys/dev/e1000/if_em.c
+++ b/sys/dev/e1000/if_em.c
@@ -1504,6 +1504,7 @@ em_msix_link(void *arg)
 {
 	struct adapter *adapter = arg;
 	u32 reg_icr;
+	bool notlink = false;
 
 	++adapter->link_irq;
 	MPASS(adapter->hw.back != NULL);
@@ -1512,15 +1513,19 @@ em_msix_link(void *arg)
 	if (reg_icr & E1000_ICR_RXO)
 		adapter->rx_overruns++;
 
-	if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+	if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC))
 		em_handle_link(adapter->ctx);
-	} else if (adapter->hw.mac.type == e1000_82574) {
-		/* Only re-arm 82574 if em_if_update_admin_status() won't. */
-		E1000_WRITE_REG(&adapter->hw, E1000_IMS, EM_MSIX_LINK |
-		    E1000_IMS_LSC);
-	}
+	else
+		notlink = true;
 
-	if (adapter->hw.mac.type == e1000_82574) {
+	/* Re-arm for other/spurious interrupts */
+	if (notlink && adapter->hw.mac.type >= igb_mac_min) {
+		E1000_WRITE_REG(&adapter->hw, E1000_IMS, E1000_IMS_LSC);
+		E1000_WRITE_REG(&adapter->hw, E1000_EIMS, adapter->link_mask);
+	} else if (adapter->hw.mac.type == e1000_82574) {
+		if (notlink)
+			E1000_WRITE_REG(&adapter->hw, E1000_IMS, E1000_IMS_LSC |
+			    E1000_IMS_OTHER);
 		/*
 		 * Because we must read the ICR for this interrupt it may
 		 * clear other causes using autoclear, for this reason we
@@ -1528,10 +1533,6 @@ em_msix_link(void *arg)
 		 */
 		if (reg_icr)
 			E1000_WRITE_REG(&adapter->hw, E1000_ICS, adapter->ims);
-	} else {
-		/* Re-arm unconditionally */
-		E1000_WRITE_REG(&adapter->hw, E1000_IMS, E1000_IMS_LSC);
-		E1000_WRITE_REG(&adapter->hw, E1000_EIMS, adapter->link_mask);
 	}
 
 	return (FILTER_HANDLED);
@@ -1876,10 +1877,13 @@ em_if_update_admin_status(if_ctx_t ctx)
 
 	if (hw->mac.type < em_mac_min)
 		lem_smartspeed(adapter);
-	else if (hw->mac.type == e1000_82574 &&
+	else if (hw->mac.type >= igb_mac_min &&
+	    adapter->intr_type == IFLIB_INTR_MSIX) {
+		E1000_WRITE_REG(&adapter->hw, E1000_IMS, E1000_IMS_LSC);
+		E1000_WRITE_REG(&adapter->hw, E1000_EIMS, adapter->link_mask);
+	} else if (hw->mac.type == e1000_82574 &&
 	    adapter->intr_type == IFLIB_INTR_MSIX)
-		E1000_WRITE_REG(&adapter->hw, E1000_IMS, EM_MSIX_LINK |
-		    E1000_IMS_LSC);
+		E1000_WRITE_REG(hw, E1000_IMS, E1000_IMS_LSC | E1000_IMS_OTHER);
 }
 
 static void
@@ -2091,7 +2095,10 @@ em_if_msix_intr_assign(if_ctx_t ctx, int msix)
 	if (adapter->hw.mac.type < igb_mac_min) {
 		adapter->ivars |=  (8 | rx_vectors) << 16;
 		adapter->ivars |= 0x80000000;
+		/* Enable the "Other" interrupt type for link status change */
+		adapter->ims |= E1000_IMS_OTHER;
 	}
+
 	return (0);
 fail:
 	iflib_irq_free(ctx, &adapter->irq);
@@ -3474,8 +3481,8 @@ em_if_intr_enable(if_ctx_t ctx)
 	struct e1000_hw *hw = &adapter->hw;
 	u32 ims_mask = IMS_ENABLE_MASK;
 
-	if (hw->mac.type == e1000_82574) {
-		E1000_WRITE_REG(hw, EM_EIAC, EM_MSIX_MASK);
+	if (adapter->intr_type == IFLIB_INTR_MSIX) {
+		E1000_WRITE_REG(hw, EM_EIAC, adapter->ims);
 		ims_mask |= adapter->ims;
 	}
 	E1000_WRITE_REG(hw, E1000_IMS, ims_mask);
@@ -3487,7 +3494,7 @@ em_if_intr_disable(if_ctx_t ctx)
 	struct adapter *adapter = iflib_get_softc(ctx);
 	struct e1000_hw *hw = &adapter->hw;
 
-	if (hw->mac.type == e1000_82574)
+	if (adapter->intr_type == IFLIB_INTR_MSIX)
 		E1000_WRITE_REG(hw, EM_EIAC, 0);
 	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
 }
diff --git a/sys/dev/e1000/if_em.h b/sys/dev/e1000/if_em.h
index d685b4aedc26..b1f179a3842e 100644
--- a/sys/dev/e1000/if_em.h
+++ b/sys/dev/e1000/if_em.h
@@ -341,8 +341,6 @@
 #define EM_VFTA_SIZE		128
 #define EM_TSO_SIZE		65535
 #define EM_TSO_SEG_SIZE		4096	/* Max dma segment size */
-#define EM_MSIX_MASK		0x01F00000 /* For 82574 use */
-#define EM_MSIX_LINK		0x01000000 /* For 82574 use */
 #define ETH_ZLEN		60
 #define EM_CSUM_OFFLOAD		(CSUM_IP | CSUM_IP_UDP | CSUM_IP_TCP) /* Offload bits in mbuf flag */
 #define IGB_CSUM_OFFLOAD	(CSUM_IP | CSUM_IP_UDP | CSUM_IP_TCP | \


More information about the dev-commits-src-all mailing list