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