kern/136168: em driver initialization fails on Intel 5000PSL motherboard

Stephen Sanders ssanders at opnet.com
Mon Jun 29 20:40:05 UTC 2009


>Number:         136168
>Category:       kern
>Synopsis:       em driver initialization fails on Intel 5000PSL motherboard
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Jun 29 20:40:04 UTC 2009
>Closed-Date:
>Last-Modified:
>Originator:     Stephen Sanders
>Release:        FreeBSD 6.3
>Organization:
OPNET
>Environment:
FreeBSD alt-4100-2.lab.opnet.com 6.3-RELEASE FreeBSD 6.3-RELEASE #0: Mon Jun 29 15:59:00 EDT 2009     root at vm6-3-64-dev.opnet.com:/root/Projects/FreeBSD/package/NPbabkernel/bld-tmp/sys/amd64/compile/NPBAB  amd64
>Description:
For roughly 1 in 30 reboot cycles, the em driver attempts to initialize the 82563EB PHY and the attempt fails.  The code looks ok but the chip returns a funny value.

Putting the hardware initialization routine in a loop in if_em.c fixes the issue.  (see attached patch).

I'm pretty sure that is will be a problem in all releases of FreeBSD 6.x-8.x.


>How-To-Repeat:
Reboot a Intel 5000PSL based machine 30 plus times.   Look for "Hardware Initialization Failed" in the message log.  The em device may not appear in an ifconfig -a listing or the networking will not function.  Try "host www.cnn.com" as a quick check.
>Fix:
Attached Patch.

Alternatively, check return code of e1000_init_hw in if_em.c:em_hardware_init().  If if fails, loop up to three times.  The loop should encompass e1000_reset_hw().


Patch attached with submission follows:

diff -uNr ./dev/em/if_em.c ../sys.new/dev/em/if_em.c
--- ./dev/em/if_em.c	2007-11-06 20:33:28.000000000 -0500
+++ ../sys.new/dev/em/if_em.c	2009-06-29 15:51:07.000000000 -0400
@@ -344,6 +344,7 @@
 #define EM_TICKS_TO_USECS(ticks)	((1024 * (ticks) + 500) / 1000)
 #define EM_USECS_TO_TICKS(usecs)	((1000 * (usecs) + 512) / 1024)
 #define M_TSO_LEN			66
+#define DEVICE_INIT_RETRIES 3
 
 /* Allow common code without TSO */
 #ifndef CSUM_TSO
@@ -2839,66 +2840,77 @@
 {
 	device_t dev = adapter->dev;
 	uint16_t rx_buffer_size;
+	int i = 0;
 
 	INIT_DEBUGOUT("em_hardware_init: begin");
 
-	/* Issue a global reset */
-	e1000_reset_hw(&adapter->hw);
-
-	/* Get control from any management/hw control */
-	if (((adapter->hw.mac.type == e1000_82573) ||
-	    (adapter->hw.mac.type == e1000_ich8lan) ||
-	    (adapter->hw.mac.type == e1000_ich9lan)) &&
-	    e1000_check_mng_mode(&adapter->hw))
-		em_get_hw_control(adapter);
+	for( i=0; i< DEVICE_INIT_RETRIES; i++ ) {
 
-	/* When hardware is reset, fifo_head is also reset */
-	adapter->tx_fifo_head = 0;
+            /* Issue a global reset */
+            e1000_reset_hw(&adapter->hw);
 
-	/* Set up smart power down as default off on newer adapters. */
-	if (!em_smart_pwr_down && (adapter->hw.mac.type == e1000_82571 ||
-	    adapter->hw.mac.type == e1000_82572)) {
-		uint16_t phy_tmp = 0;
-
-		/* Speed up time to link by disabling smart power down. */
-		e1000_read_phy_reg(&adapter->hw,
-		    IGP02E1000_PHY_POWER_MGMT, &phy_tmp);
-		phy_tmp &= ~IGP02E1000_PM_SPD;
-		e1000_write_phy_reg(&adapter->hw,
-		    IGP02E1000_PHY_POWER_MGMT, phy_tmp);
-	}
-
-	/*
-	 * These parameters control the automatic generation (Tx) and
-	 * response (Rx) to Ethernet PAUSE frames.
-	 * - High water mark should allow for at least two frames to be
-	 *   received after sending an XOFF.
-	 * - Low water mark works best when it is very near the high water mark.
-	 *   This allows the receiver to restart by sending XON when it has
-	 *   drained a bit. Here we use an arbitary value of 1500 which will
-	 *   restart after one full frame is pulled from the buffer. There
-	 *   could be several smaller frames in the buffer and if so they will
-	 *   not trigger the XON until their total number reduces the buffer
-	 *   by 1500.
-	 * - The pause time is fairly large at 1000 x 512ns = 512 usec.
-	 */
-	rx_buffer_size = ((E1000_READ_REG(&adapter->hw, E1000_PBA) &
-	    0xffff) << 10 );
-
-	adapter->hw.fc.high_water = rx_buffer_size -
-	    roundup2(adapter->max_frame_size, 1024);
-	adapter->hw.fc.low_water = adapter->hw.fc.high_water - 1500;
-
-	if (adapter->hw.mac.type == e1000_80003es2lan)
-		adapter->hw.fc.pause_time = 0xFFFF;
-	else
-		adapter->hw.fc.pause_time = EM_FC_PAUSE_TIME;
-	adapter->hw.fc.send_xon = TRUE;
-	adapter->hw.fc.type = e1000_fc_full;
-
-	if (e1000_init_hw(&adapter->hw) < 0) {
-		device_printf(dev, "Hardware Initialization Failed\n");
-		return (EIO);
+            /* Get control from any management/hw control */
+            if (((adapter->hw.mac.type == e1000_82573) ||
+                (adapter->hw.mac.type == e1000_ich8lan) ||
+                (adapter->hw.mac.type == e1000_ich9lan)) &&
+                e1000_check_mng_mode(&adapter->hw))
+                em_get_hw_control(adapter);
+
+            /* When hardware is reset, fifo_head is also reset */
+            adapter->tx_fifo_head = 0;
+
+            /* Set up smart power down as default off on newer adapters. */
+            if (!em_smart_pwr_down && (adapter->hw.mac.type == e1000_82571 ||
+                adapter->hw.mac.type == e1000_82572)) {
+                uint16_t phy_tmp = 0;
+
+                /* Speed up time to link by disabling smart power down. */
+                e1000_read_phy_reg(&adapter->hw,
+                    IGP02E1000_PHY_POWER_MGMT, &phy_tmp);
+                phy_tmp &= ~IGP02E1000_PM_SPD;
+                e1000_write_phy_reg(&adapter->hw,
+                    IGP02E1000_PHY_POWER_MGMT, phy_tmp);
+            }
+    
+            /*
+             * These parameters control the automatic generation (Tx) and
+             * response (Rx) to Ethernet PAUSE frames.
+             * - High water mark should allow for at least two frames to be
+             *   received after sending an XOFF.
+             * - Low water mark works best when it is very near the high water mark.
+             *   This allows the receiver to restart by sending XON when it has
+             *   drained a bit. Here we use an arbitary value of 1500 which will
+             *   restart after one full frame is pulled from the buffer. There
+             *   could be several smaller frames in the buffer and if so they will
+             *   not trigger the XON until their total number reduces the buffer
+             *   by 1500.
+             * - The pause time is fairly large at 1000 x 512ns = 512 usec.
+             */
+            rx_buffer_size = ((E1000_READ_REG(&adapter->hw, E1000_PBA) &
+                0xffff) << 10 );
+
+            adapter->hw.fc.high_water = rx_buffer_size -
+                roundup2(adapter->max_frame_size, 1024);
+            adapter->hw.fc.low_water = adapter->hw.fc.high_water - 1500;
+
+            if (adapter->hw.mac.type == e1000_80003es2lan)
+                adapter->hw.fc.pause_time = 0xFFFF;
+            else
+                adapter->hw.fc.pause_time = EM_FC_PAUSE_TIME;
+            adapter->hw.fc.send_xon = TRUE;
+            adapter->hw.fc.type = e1000_fc_full;
+
+            if (e1000_init_hw(&adapter->hw) < 0) {
+                device_printf(dev,
+                        "Hardware Initialization Failed %d of %d\n",
+                            i+1, DEVICE_INIT_RETRIES );
+
+                if( i < DEVICE_INIT_RETRIES)
+                    continue;
+
+                return (EIO);
+            }
+            break;
 	}
 
 	e1000_check_for_link(&adapter->hw);


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list