diff options
-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_ */ |