summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjfv <jfv@FreeBSD.org>2010-11-24 22:24:07 +0000
committerjfv <jfv@FreeBSD.org>2010-11-24 22:24:07 +0000
commita0f20794078b6e9c703227cfc2438a2ba45ca7ea (patch)
treee05a3b327fa6dc87e9ab99306f44c156d34aed25
parent9f53799703c37397a93e1233ceddba0211a8d851 (diff)
downloadFreeBSD-src-a0f20794078b6e9c703227cfc2438a2ba45ca7ea.zip
FreeBSD-src-a0f20794078b6e9c703227cfc2438a2ba45ca7ea.tar.gz
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
-rw-r--r--sys/dev/e1000/if_em.c138
1 files changed, 83 insertions, 55 deletions
diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c
index c41e144..6728a98 100644
--- a/sys/dev/e1000/if_em.c
+++ b/sys/dev/e1000/if_em.c
@@ -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, int *done)
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;
+ /* 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;
+ /* 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;
- }
+ /* 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) {
- rxr->fmp->m_pkthdr.rcvif = ifp;
- ifp->if_ipackets++;
- em_receive_checksum(cur, rxr->fmp);
+ 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.
OpenPOWER on IntegriCloud