On Sun, Mar 25, 2012 at 10:21:58PM +0900, Yoshihisa Matsushita wrote:
> >Synopsis: Intel 82579LM auto negotiation fails at boot
> >Category: amd64 kernel system
> >Environment:
> System : OpenBSD 5.1
> Details : OpenBSD 5.1-current (GENERIC.MP) #227: Thu Mar 22
> 11:10:40 MDT 2012
>
> [email protected]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
>
> Architecture: OpenBSD.amd64
> Machine : amd64
> >Description:
> em(4) describes 82579LM is one of supported chips, but
> auto-negotiation fails at boot, always links at 100Mbps on
> Thinkpad X220 (4286CTO).
>
> Despite of "sudo ifconfig em0 media" showing 1000BaseT
> capability, manually select 'media 1000baseT mediaopt
> full-duplex' also 'media 1000baseT' with ifconfig bring no
> links at all.
>
> >How-To-Repeat:
> Rebooting system.
> >Fix:
> Following patch fix my problems, auto-negotiation at boot and
> "ifconfig media" works as expected. I haven't checked any other
> em_pch2lan machines since I don't have any. Tests needed.
This points to a general problem with reset on 82579/pch2.
It seems we are writing the wrong registers to disable the management
interference with the chip in non managed mode.
I think we need something along the lines of the following,
untested as I don't have any machines with pch2.
Index: if_em_hw.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_em_hw.c,v
retrieving revision 1.68
diff -u -p -r1.68 if_em_hw.c
--- if_em_hw.c 29 Nov 2011 04:10:59 -0000 1.68
+++ if_em_hw.c 26 Mar 2012 02:33:16 -0000
@@ -158,7 +158,9 @@ static void em_release_eeprom(struct em_
static void em_standby_eeprom(struct em_hw *);
static int32_t em_set_vco_speed(struct em_hw *);
static int32_t em_polarity_reversal_workaround(struct em_hw *);
+#if 0
static void em_pch2lan_disable_hw_config(struct em_hw *, boolean_t);
+#endif
static int32_t em_set_phy_mode(struct em_hw *);
static int32_t em_host_if_read_cookie(struct em_hw *, uint8_t *);
static uint8_t em_calculate_mng_checksum(char *, uint32_t);
@@ -171,6 +173,7 @@ int32_t em_link_stall_workaround_hv(str
int32_t em_k1_gig_workaround_hv(struct em_hw *, boolean_t);
int32_t em_k1_workaround_lv(struct em_hw *);
int32_t em_configure_k1_ich8lan(struct em_hw *, boolean_t);
+void em_gate_hw_phy_config_ich8lan(struct em_hw *, boolean_t);
int32_t em_access_phy_wakeup_reg_bm(struct em_hw *, uint32_t,
uint16_t *, boolean_t);
int32_t em_access_phy_debug_regs_hv(struct em_hw *, uint32_t,
@@ -836,12 +839,18 @@ em_reset_hw(struct em_hw *hw)
if ((hw->mac_type == em_pch2lan) &&
!(E1000_READ_REG(hw, FWSM) &
E1000_FWSM_FW_VALID)) {
- em_pch2lan_disable_hw_config(hw, TRUE);
+ em_gate_hw_phy_config_ich8lan(hw, TRUE);
}
}
em_get_software_flag(hw);
E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
msec_delay(5);
+
+ if (hw->mac_type == em_pch2lan && !hw->phy_reset_disable &&
+ !(E1000_READ_REG(hw, FWSM) & E1000_FWSM_FW_VALID)) {
+ msec_delay(10);
+ em_gate_hw_phy_config_ich8lan(hw, FALSE);
+ }
break;
default:
E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
@@ -1156,7 +1165,7 @@ em_init_hw(struct em_hw *hw)
}
if (hw->mac_type == em_pch2lan)
- em_pch2lan_disable_hw_config(hw, TRUE);
+ em_gate_hw_phy_config_ich8lan(hw, TRUE);
/*
* Reset the PHY before any acccess to it. Doing so,
@@ -1169,7 +1178,7 @@ em_init_hw(struct em_hw *hw)
if (hw->mac_type == em_pch2lan &&
(fwsm & E1000_FWSM_FW_VALID) == 0)
- em_pch2lan_disable_hw_config(hw, FALSE);
+ em_gate_hw_phy_config_ich8lan(hw, FALSE);
/* Set MDIO slow mode before any other MDIO access */
ret_val = em_set_mdio_slow_mode_hv(hw);
@@ -8532,6 +8541,7 @@ em_polarity_reversal_workaround(struct e
return E1000_SUCCESS;
}
+#if 0
/*
* Set whether the PHY self-configures itself in hardware
*/
@@ -8549,6 +8559,7 @@ static void em_pch2lan_disable_hw_config
E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
}
+#endif
/******************************************************************************
*
@@ -10141,3 +10152,32 @@ em_configure_k1_ich8lan(struct em_hw *hw
out:
return ret_val;
}
+
+/**
+ * e1000_gate_hw_phy_config_ich8lan - disable PHY config via hardware
+ * @hw: pointer to the HW structure
+ * @gate: boolean set to TRUE to gate, FALSE to ungate
+ *
+ * Gate/ungate the automatic PHY configuration via hardware; perform
+ * the configuration via software instead.
+ **/
+void
+em_gate_hw_phy_config_ich8lan(struct em_hw *hw, boolean_t gate)
+{
+ uint32_t extcnf_ctrl;
+
+ DEBUGFUNC("em_gate_hw_phy_config_ich8lan");
+
+ if (hw->mac_type != em_pch2lan)
+ return;
+
+ extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL);
+
+ if (gate)
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_GATE_PHY_CFG;
+ else
+ extcnf_ctrl &= ~E1000_EXTCNF_CTRL_GATE_PHY_CFG;
+
+ E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl);
+}
+
Index: if_em_hw.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_em_hw.h,v
retrieving revision 1.52
diff -u -p -r1.52 if_em_hw.h
--- if_em_hw.h 5 Oct 2011 02:52:10 -0000 1.52
+++ if_em_hw.h 26 Mar 2012 02:15:06 -0000
@@ -2557,6 +2557,7 @@ struct em_host_command_info {
#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH 0x00FF0000
#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001
#define E1000_EXTCNF_CTRL_SWFLAG 0x00000020
+#define E1000_EXTCNF_CTRL_GATE_PHY_CFG 0x00000080
/* PBA constants */
#define E1000_PBA_8K 0x0008 /* 8KB, default Rx allocation */