svn commit: r215808 - head/sys/dev/e1000

Jack F Vogel jfv at FreeBSD.org
Wed Nov 24 22:24:08 UTC 2010


Author: jfv
Date: Wed Nov 24 22:24:07 2010
New Revision: 215808
URL: http://svn.freebsd.org/changeset/base/215808

Log:
  The purpose of this change is to add a routine to
  disable ASPM L0S and L1 LINK states on 82573, 82574,
  and 82583. The theory is that this is behind certain
  hangs being experienced by some customers.
  
  Also included a small optimization in the rxeof routine
  that was in my internal code.
  
  Change the PBA size for pchlan, it was incorrect.
  
  MFC after: 3 days

Modified:
  head/sys/dev/e1000/if_em.c

Modified: head/sys/dev/e1000/if_em.c
==============================================================================
--- head/sys/dev/e1000/if_em.c	Wed Nov 24 21:58:15 2010	(r215807)
+++ head/sys/dev/e1000/if_em.c	Wed Nov 24 22:24:07 2010	(r215808)
@@ -93,7 +93,7 @@ int	em_display_debug_stats = 0;
 /*********************************************************************
  *  Driver version:
  *********************************************************************/
-char em_driver_version[] = "7.1.7";
+char em_driver_version[] = "7.1.8";
 
 /*********************************************************************
  *  PCI Device ID Table
@@ -272,6 +272,7 @@ static void	em_get_wakeup(device_t);
 static void     em_enable_wakeup(device_t);
 static int	em_enable_phy_wakeup(struct adapter *);
 static void	em_led_func(void *, int);
+static void	em_disable_aspm(struct adapter *);
 
 static int	em_irq_fast(void *);
 
@@ -1229,9 +1230,9 @@ em_init_locked(struct adapter *adapter)
 		break;
 	case e1000_ich9lan:
 	case e1000_ich10lan:
-	case e1000_pchlan:
 		pba = E1000_PBA_10K;
 		break;
+	case e1000_pchlan:
 	case e1000_pch2lan:
 		pba = E1000_PBA_26K;
 		break;
@@ -2762,6 +2763,7 @@ em_reset(struct adapter *adapter)
 	/* Issue a global reset */
 	e1000_reset_hw(hw);
 	E1000_WRITE_REG(hw, E1000_WUC, 0);
+	em_disable_aspm(adapter);
 
 	if (e1000_init_hw(hw) < 0) {
 		device_printf(dev, "Hardware Initialization Failed\n");
@@ -4205,68 +4207,66 @@ em_rxeof(struct rx_ring *rxr, int count,
 
 		len = le16toh(cur->length);
 		eop = (status & E1000_RXD_STAT_EOP) != 0;
-		count--;
 
-		if (((cur->errors & E1000_RXD_ERR_FRAME_ERR_MASK) == 0) &&
-		    (rxr->discard == FALSE)) {
+		if ((rxr->discard == TRUE) || (cur->errors &
+		    E1000_RXD_ERR_FRAME_ERR_MASK)) {
+			ifp->if_ierrors++;
+			++rxr->rx_discarded;
+			if (!eop) /* Catch subsequent segs */
+				rxr->discard = TRUE;
+			else
+				rxr->discard = FALSE;
+			em_rx_discard(rxr, i);
+			goto next_desc;
+		}
 
-			/* Assign correct length to the current fragment */
-			mp = rxr->rx_buffers[i].m_head;
-			mp->m_len = len;
-
-			/* Trigger for refresh */
-			rxr->rx_buffers[i].m_head = NULL;
-
-			if (rxr->fmp == NULL) {
-				mp->m_pkthdr.len = len;
-				rxr->fmp = mp; /* Store the first mbuf */
-				rxr->lmp = mp;
-			} else {
-				/* Chain mbuf's together */
-				mp->m_flags &= ~M_PKTHDR;
-				rxr->lmp->m_next = mp;
-				rxr->lmp = rxr->lmp->m_next;
-				rxr->fmp->m_pkthdr.len += len;
-			}
+		/* Assign correct length to the current fragment */
+		mp = rxr->rx_buffers[i].m_head;
+		mp->m_len = len;
 
-			if (eop) {
-				rxr->fmp->m_pkthdr.rcvif = ifp;
-				ifp->if_ipackets++;
-				em_receive_checksum(cur, rxr->fmp);
+		/* Trigger for refresh */
+		rxr->rx_buffers[i].m_head = NULL;
+
+		/* First segment? */
+		if (rxr->fmp == NULL) {
+			mp->m_pkthdr.len = len;
+			rxr->fmp = rxr->lmp = mp;
+		} else {
+			/* Chain mbuf's together */
+			mp->m_flags &= ~M_PKTHDR;
+			rxr->lmp->m_next = mp;
+			rxr->lmp = mp;
+			rxr->fmp->m_pkthdr.len += len;
+		}
+
+		if (eop) {
+			--count;
+			sendmp = rxr->fmp;
+			sendmp->m_pkthdr.rcvif = ifp;
+			ifp->if_ipackets++;
+			em_receive_checksum(cur, sendmp);
 #ifndef __NO_STRICT_ALIGNMENT
-				if (adapter->max_frame_size >
-				    (MCLBYTES - ETHER_ALIGN) &&
-				    em_fixup_rx(rxr) != 0)
-					goto skip;
+			if (adapter->max_frame_size >
+			    (MCLBYTES - ETHER_ALIGN) &&
+			    em_fixup_rx(rxr) != 0)
+				goto skip;
 #endif
-				if (status & E1000_RXD_STAT_VP) {
-					rxr->fmp->m_pkthdr.ether_vtag =
-					    (le16toh(cur->special) &
-					    E1000_RXD_SPC_VLAN_MASK);
-					rxr->fmp->m_flags |= M_VLANTAG;
-				}
+			if (status & E1000_RXD_STAT_VP) {
+				sendmp->m_pkthdr.ether_vtag =
+				    (le16toh(cur->special) &
+				    E1000_RXD_SPC_VLAN_MASK);
+				sendmp->m_flags |= M_VLANTAG;
+			}
 #ifdef EM_MULTIQUEUE
-				rxr->fmp->m_pkthdr.flowid = rxr->msix;
-				rxr->fmp->m_flags |= M_FLOWID;
+			sendmp->m_pkthdr.flowid = rxr->msix;
+			sendmp->m_flags |= M_FLOWID;
 #endif
 #ifndef __NO_STRICT_ALIGNMENT
 skip:
 #endif
-				sendmp = rxr->fmp;
-				rxr->fmp = NULL;
-				rxr->lmp = NULL;
-			}
-		} else {
-			ifp->if_ierrors++;
-			++rxr->rx_discarded;
-			if (!eop) /* Catch subsequent segs */
-				rxr->discard = TRUE;
-			else
-				rxr->discard = FALSE;
-			em_rx_discard(rxr, i);
-			sendmp = NULL;
+			rxr->fmp = rxr->lmp = NULL;
 		}
-
+next_desc:
 		/* Zero out the receive descriptors status. */
 		cur->status = 0;
 		++rxdone;	/* cumulative for POLL */
@@ -4293,10 +4293,7 @@ skip:
 	}
 
 	/* Catch any remaining refresh work */
-	if (processed != 0) {
-		em_refresh_mbufs(rxr, i);
-		processed = 0;
-	}
+	em_refresh_mbufs(rxr, i);
 
 	rxr->next_to_check = i;
 	if (done != NULL)
@@ -4878,6 +4875,37 @@ em_led_func(void *arg, int onoff)
 	EM_CORE_UNLOCK(adapter);
 }
 
+/*
+** Disable the L0S and L1 LINK states
+*/
+static void
+em_disable_aspm(struct adapter *adapter)
+{
+	int		base, reg;
+	u16		link_cap,link_ctrl;
+	device_t	dev = adapter->dev;
+
+	switch (adapter->hw.mac.type) {
+		case e1000_82573:
+		case e1000_82574:
+		case e1000_82583:
+			break;
+		default:
+			return;
+	}
+	if (pci_find_extcap(dev, PCIY_EXPRESS, &base) != 0)
+		return;
+	reg = base + PCIR_EXPRESS_LINK_CAP;
+	link_cap = pci_read_config(dev, reg, 2);
+	if ((link_cap & PCIM_LINK_CAP_ASPM) == 0)
+		return;
+	reg = base + PCIR_EXPRESS_LINK_CTL;
+	link_ctrl = pci_read_config(dev, reg, 2);
+	link_ctrl &= 0xFFFC; /* turn off bit 1 and 2 */
+	pci_write_config(dev, reg, link_ctrl, 2);
+	return;
+}
+
 /**********************************************************************
  *
  *  Update the board statistics counters.


More information about the svn-src-head mailing list