Date: Mon, 29 Jun 2009 20:31:11 GMT From: Stephen Sanders <ssanders@opnet.com> To: freebsd-gnats-submit@FreeBSD.org Subject: kern/136168: em driver initialization fails on Intel 5000PSL motherboard Message-ID: <200906292031.n5TKVBib076571@www.freebsd.org> Resent-Message-ID: <200906292040.n5TKe4w6090264@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>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@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:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200906292031.n5TKVBib076571>