diff options
author | Jonathan Gray <jsg@cvs.openbsd.org> | 2010-06-27 20:13:05 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@cvs.openbsd.org> | 2010-06-27 20:13:05 +0000 |
commit | 97c473adbcea31108e6a401540b5fd9fa54bd1f4 (patch) | |
tree | 76e37209bea9c49b4d722e4776f3af4ebfb45bac | |
parent | ca99ab8a1fc9fe04e4f1e10f0019407601ecb9a8 (diff) |
More PCH/82577 bits from FreeBSD, this does not include
all the workarounds but is enough to make things run at
faster than 10 Mbit speeds, though these aren't always
reflecting in ifmedia properly just yet.
ok claudio@
-rw-r--r-- | sys/dev/pci/if_em.c | 12 | ||||
-rw-r--r-- | sys/dev/pci/if_em_hw.c | 214 | ||||
-rw-r--r-- | sys/dev/pci/if_em_hw.h | 32 |
3 files changed, 249 insertions, 9 deletions
diff --git a/sys/dev/pci/if_em.c b/sys/dev/pci/if_em.c index fc75b239b21..2c13e27faf0 100644 --- a/sys/dev/pci/if_em.c +++ b/sys/dev/pci/if_em.c @@ -31,7 +31,7 @@ POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ -/* $OpenBSD: if_em.c,v 1.238 2010/06/21 21:11:52 jsg Exp $ */ +/* $OpenBSD: if_em.c,v 1.239 2010/06/27 20:13:04 jsg Exp $ */ /* $FreeBSD: if_em.c,v 1.46 2004/09/29 18:28:28 mlaier Exp $ */ #include <dev/pci/if_em.h> @@ -1533,9 +1533,6 @@ em_identify_hardware(struct em_softc *sc) sc->hw.vendor_id = PCI_VENDOR(pa->pa_id); sc->hw.device_id = PCI_PRODUCT(pa->pa_id); - reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CLASS_REG); - sc->hw.revision_id = PCI_REVISION(reg); - reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); sc->hw.subsystem_vendor_id = PCI_VENDOR(reg); sc->hw.subsystem_id = PCI_PRODUCT(reg); @@ -1544,6 +1541,13 @@ em_identify_hardware(struct em_softc *sc) if (em_set_mac_type(&sc->hw)) printf("%s: Unknown MAC Type\n", sc->sc_dv.dv_xname); + if (sc->hw.mac_type == em_pchlan) + sc->hw.revision_id = PCI_PRODUCT(pa->pa_id) & 0x0f; + else { + reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CLASS_REG); + sc->hw.revision_id = PCI_REVISION(reg); + } + if (sc->hw.mac_type == em_82541 || sc->hw.mac_type == em_82541_rev_2 || sc->hw.mac_type == em_82547 || diff --git a/sys/dev/pci/if_em_hw.c b/sys/dev/pci/if_em_hw.c index 164e9b38a6e..68113cfbf69 100644 --- a/sys/dev/pci/if_em_hw.c +++ b/sys/dev/pci/if_em_hw.c @@ -31,7 +31,7 @@ *******************************************************************************/ -/* $OpenBSD: if_em_hw.c,v 1.50 2010/06/26 18:32:38 jsg Exp $ */ +/* $OpenBSD: if_em_hw.c,v 1.51 2010/06/27 20:13:04 jsg Exp $ */ /* * if_em_hw.c Shared functions for accessing and configuring the MAC */ @@ -164,6 +164,9 @@ static uint8_t em_calculate_mng_checksum(char *, uint32_t); static int32_t em_configure_kmrn_for_10_100(struct em_hw *, uint16_t); static int32_t em_configure_kmrn_for_1000(struct em_hw *); static int32_t em_set_pciex_completion_timeout(struct em_hw *hw); +int32_t em_hv_phy_workarounds_ich8lan(struct em_hw *); +void em_initialize_hw_bits_ich8lan(struct em_hw *); +int32_t em_configure_k1_ich8lan(struct em_hw *, boolean_t); /* IGP cable length table */ static const uint16_t @@ -774,6 +777,11 @@ em_reset_hw(struct em_hw *hw) E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST)); break; } + + if (hw->mac_type == em_pchlan) { + em_hv_phy_workarounds_ich8lan(hw); + } + /* * After MAC reset, force reload of EEPROM to restore power-on * settings to device. Later controllers reload the EEPROM @@ -958,6 +966,9 @@ em_initialize_hardware_bits(struct em_hw *hw) reg_ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); reg_ctrl_ext |= 0x00400000; /* Set bit 22 */ + /* Enable PHY low-power state when MAC is at D3 w/o WoL */ + if (hw->mac_type >= em_pchlan) + reg_ctrl_ext |= E1000_CTRL_EXT_PHYPDEN; E1000_WRITE_REG(hw, CTRL_EXT, reg_ctrl_ext); reg_tarc0 |= 0x0d800000; /* Set TARC0 bits 23, @@ -1403,6 +1414,12 @@ em_setup_link(struct em_hw *hw) E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW); } E1000_WRITE_REG(hw, FCTTV, hw->fc_pause_time); + + if (hw->phy_type == em_phy_82577) { + em_write_phy_reg(hw, PHY_REG(BM_PORT_CTRL_PAGE, 27), + hw->fc_pause_time); + } + /* * Set the flow control receive threshold registers. Normally, these * registers will be set to a default threshold that may be adjusted @@ -2115,11 +2132,20 @@ em_copper_link_82577_setup(struct em_hw *hw) ret_val = em_write_phy_reg(hw, I82577_PHY_CFG_REG, phy_data); if (ret_val) return ret_val; - + /* Wait 15ms for MAC to configure PHY from eeprom settings */ msec_delay(15); led_ctl = hw->ledctl_mode1; + + /* disable lplu d0 during driver init */ + ret_val = em_set_lplu_state_pchlan(hw, FALSE); + if (ret_val) { + DEBUGOUT("Error Disabling LPLU D0\n"); + return ret_val; + } + E1000_WRITE_REG(hw, LEDCTL, led_ctl); + return E1000_SUCCESS; } @@ -7489,7 +7515,7 @@ em_set_d0_lplu_state(struct em_hw *hw, boolean_t active) * auto-neg as hw would do. D3 and D0 LPLU will call the same function * since it configures the same bit. **/ -STATIC int32_t +int32_t em_set_lplu_state_pchlan(struct em_hw *hw, boolean_t active) { int32_t ret_val = E1000_SUCCESS; @@ -8915,7 +8941,8 @@ em_init_lcd_from_nvm(struct em_hw *hw) /* Check if SW needs configure the PHY */ if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_M_AMT) || - (hw->device_id == E1000_DEV_ID_ICH8_IGP_M)) + (hw->device_id == E1000_DEV_ID_ICH8_IGP_M) || + (hw->mac_type == em_pchlan)) sw_cfg_mask = FEXTNVM_SW_CONFIG_ICH8M; else sw_cfg_mask = FEXTNVM_SW_CONFIG; @@ -9027,3 +9054,182 @@ out: E1000_WRITE_REG(hw, GCR, gcr); return ret_val; } + +/** + * e1000_set_mdio_slow_mode_hv - Set slow MDIO access mode + * @hw: pointer to the HW structure + **/ +static int32_t +em_set_mdio_slow_mode_hv(struct em_hw *hw) +{ + int32_t ret_val; + uint16_t data; + + ret_val = em_read_phy_reg(hw, HV_KMRN_MODE_CTRL, &data); + if (ret_val) + return ret_val; + + data |= HV_KMRN_MDIO_SLOW; + + ret_val = em_write_phy_reg(hw, HV_KMRN_MODE_CTRL, data); + + return ret_val; +} + +/** + * em_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be + * done after every PHY reset. + **/ +int32_t +em_hv_phy_workarounds_ich8lan(struct em_hw *hw) +{ + int32_t ret_val = E1000_SUCCESS; + uint16_t phy_data; + uint16_t swfw; + + if (hw->mac_type != em_pchlan) + goto out; + + swfw = E1000_SWFW_PHY0_SM; + + /* Set MDIO slow mode before any other MDIO access */ + if (hw->phy_type == em_phy_82577) { + ret_val = em_set_mdio_slow_mode_hv(hw); + if (ret_val) + goto out; + } + + /* Hanksville M Phy init for IEEE. */ + if ((hw->revision_id == 2) && + (hw->phy_type == em_phy_82577) && + ((hw->phy_revision == 2) || (hw->phy_revision == 3))) { + em_write_phy_reg(hw, 0x10, 0x8823); + em_write_phy_reg(hw, 0x11, 0x0018); + em_write_phy_reg(hw, 0x10, 0x8824); + em_write_phy_reg(hw, 0x11, 0x0016); + em_write_phy_reg(hw, 0x10, 0x8825); + em_write_phy_reg(hw, 0x11, 0x001A); + em_write_phy_reg(hw, 0x10, 0x888C); + em_write_phy_reg(hw, 0x11, 0x0007); + em_write_phy_reg(hw, 0x10, 0x888D); + em_write_phy_reg(hw, 0x11, 0x0007); + em_write_phy_reg(hw, 0x10, 0x888E); + em_write_phy_reg(hw, 0x11, 0x0007); + em_write_phy_reg(hw, 0x10, 0x8827); + em_write_phy_reg(hw, 0x11, 0x0001); + em_write_phy_reg(hw, 0x10, 0x8835); + em_write_phy_reg(hw, 0x11, 0x0001); + em_write_phy_reg(hw, 0x10, 0x8834); + em_write_phy_reg(hw, 0x11, 0x0001); + em_write_phy_reg(hw, 0x10, 0x8833); + em_write_phy_reg(hw, 0x11, 0x0002); + } + + if (((hw->phy_type == em_phy_82577) && + ((hw->phy_revision == 1) || (hw->phy_revision == 2)))) { + /* Disable generation of early preamble */ + ret_val = em_write_phy_reg(hw, PHY_REG(769, 25), 0x4431); + if (ret_val) + goto out; + + /* Preamble tuning for SSC */ + ret_val = em_write_phy_reg(hw, PHY_REG(770, 16), 0xA204); + if (ret_val) + goto out; + } + + if ((hw->revision_id == 2) && + (hw->phy_type == em_phy_82577) && + ((hw->phy_revision == 2) || (hw->phy_revision == 3))) { + /* + * Workaround for OEM (GbE) not operating after reset - + * restart AN (twice) + */ + ret_val = em_write_phy_reg(hw, PHY_REG(768, 25), 0x0400); + if (ret_val) + goto out; + ret_val = em_write_phy_reg(hw, PHY_REG(768, 25), 0x0400); + if (ret_val) + goto out; + } + + /* Select page 0 */ + ret_val = em_swfw_sync_acquire(hw, swfw); + if (ret_val) + goto out; + + hw->phy_addr = 1; + ret_val = em_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0); + em_swfw_sync_release(hw, swfw); + if (ret_val) + goto out; + + /* Workaround for link disconnects on a busy hub in half duplex */ + ret_val = em_read_phy_reg(hw, + PHY_REG(BM_PORT_CTRL_PAGE, 17), + &phy_data); + if (ret_val) + goto release; + ret_val = em_write_phy_reg(hw, + PHY_REG(BM_PORT_CTRL_PAGE, 17), + phy_data & 0x00FF); +release: +out: + return ret_val; +} + +/** + * e1000_configure_k1_ich8lan - Configure K1 power state + * @hw: pointer to the HW structure + * @enable: K1 state to configure + * + * Configure the K1 power state based on the provided parameter. + * Assumes semaphore already acquired. + * + * Success returns 0, Failure returns -E1000_ERR_PHY (-2) + **/ +int32_t +em_configure_k1_ich8lan(struct em_hw *hw, boolean_t k1_enable) +{ + int32_t ret_val = E1000_SUCCESS; + uint32_t ctrl_reg = 0; + uint32_t ctrl_ext = 0; + uint32_t reg = 0; + uint16_t kmrn_reg = 0; + + ret_val = em_read_kmrn_reg(hw, + E1000_KMRNCTRLSTA_K1_CONFIG, + &kmrn_reg); + if (ret_val) + goto out; + + if (k1_enable) + kmrn_reg |= E1000_KMRNCTRLSTA_K1_ENABLE; + else + kmrn_reg &= ~E1000_KMRNCTRLSTA_K1_ENABLE; + + ret_val = em_write_kmrn_reg(hw, + E1000_KMRNCTRLSTA_K1_CONFIG, + kmrn_reg); + if (ret_val) + goto out; + + usec_delay(20); + ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); + ctrl_reg = E1000_READ_REG(hw, CTRL); + + reg = ctrl_reg & ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); + reg |= E1000_CTRL_FRCSPD; + E1000_WRITE_REG(hw, CTRL, reg); + + E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_SPD_BYPS); + usec_delay(20); + E1000_WRITE_REG(hw, CTRL, ctrl_reg); + E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); + usec_delay(20); + +out: + return ret_val; +} + + diff --git a/sys/dev/pci/if_em_hw.h b/sys/dev/pci/if_em_hw.h index 9eb68b848c4..74808fc2124 100644 --- a/sys/dev/pci/if_em_hw.h +++ b/sys/dev/pci/if_em_hw.h @@ -31,7 +31,7 @@ *******************************************************************************/ -/* $OpenBSD: if_em_hw.h,v 1.40 2010/06/26 18:32:38 jsg Exp $ */ +/* $OpenBSD: if_em_hw.h,v 1.41 2010/06/27 20:13:04 jsg Exp $ */ /* $FreeBSD: if_em_hw.h,v 1.15 2005/05/26 23:32:02 tackerman Exp $ */ /* if_em_hw.h @@ -1546,6 +1546,7 @@ struct em_hw { #define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */ #define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through PHYRST_N pin */ #define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external LINK_0 and LINK_1 pins */ +#define E1000_CTRL_EXT_PHYPDEN 0x00100000 #define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ #define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ #define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */ @@ -2646,6 +2647,7 @@ struct em_host_command_info { #define BM_PHY_PAGE_SELECT 22 /* Page Select for BM */ #define BM_REG_BIAS1 29 #define BM_REG_BIAS2 30 +#define BM_PORT_CTRL_PAGE 769 #define IGP01E1000_IEEE_REGS_PAGE 0x0000 #define IGP01E1000_IEEE_RESTART_AUTONEG 0x3300 @@ -3480,4 +3482,32 @@ union ich8_hws_flash_regacc { #define HV_OEM_BITS_GBE_DIS 0x0040 /* Gigabit Disable */ #define HV_OEM_BITS_RESTART_AN 0x0400 /* Restart Auto-negotiation */ +#define HV_KMRN_MODE_CTRL PHY_REG(769, 16) +#define HV_KMRN_MDIO_SLOW 0x0400 + +#define E1000_NVM_K1_CONFIG 0x1B /* NVM K1 Config Word */ +#define E1000_NVM_K1_ENABLE 0x1 /* NVM Enable K1 bit */ + +#define E1000_KMRNCTRLSTA_OFFSET 0x001F0000 +#define E1000_KMRNCTRLSTA_OFFSET_SHIFT 16 +#define E1000_KMRNCTRLSTA_REN 0x00200000 +#define E1000_KMRNCTRLSTA_DIAG_OFFSET 0x3 /* Diagnostic */ +#define E1000_KMRNCTRLSTA_TIMEOUTS 0x4 /* Timeouts */ +#define E1000_KMRNCTRLSTA_INBAND_PARAM 0x9 /* InBand Parameters */ +#define E1000_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Loopback mode */ +#define E1000_KMRNCTRLSTA_K1_CONFIG 0x7 +#define E1000_KMRNCTRLSTA_K1_ENABLE 0x0002 + + +/* Extended Configuration Control and Size */ +#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020 +#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001 +#define E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE 0x00000008 +#define E1000_EXTCNF_CTRL_SWFLAG 0x00000020 +#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK 0x00FF0000 +#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT 16 +#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK 0x0FFF0000 +#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT 16 + + #endif /* _EM_HW_H_ */ |