diff options
author | Miles Xu, Sun Microsystems <Min.Xu@Sun.COM> | 2009-11-10 11:52:20 +0800 |
---|---|---|
committer | Miles Xu, Sun Microsystems <Min.Xu@Sun.COM> | 2009-11-10 11:52:20 +0800 |
commit | bd9f6899328e19cbb74e3ad02f5c32002285887e (patch) | |
tree | b7fc6650f149e4e8d904b8a1c74a632066147e86 /usr/src | |
parent | 98c507c4288789fc67365c4cb51f80eb641e7182 (diff) | |
download | illumos-gate-bd9f6899328e19cbb74e3ad02f5c32002285887e.tar.gz |
6893285 e1000g 'pciex8086,105e' with PHY type igp I/O devices have been retired
6895459 e1000g share code update v3-1-10-1
Diffstat (limited to 'usr/src')
27 files changed, 873 insertions, 310 deletions
diff --git a/usr/src/uts/common/io/e1000g/README b/usr/src/uts/common/io/e1000g/README index bb3f892d29..47b86d6050 100644 --- a/usr/src/uts/common/io/e1000g/README +++ b/usr/src/uts/common/io/e1000g/README @@ -714,3 +714,8 @@ Notes on packaging: 6881588 e1000g functions should return when e1000g_check_dma_handle() fails 6888320 e1000g emits scary mutex message on the console +5.3.17 +====== + This version has the following fixes: + 6893285 e1000g 'pciex8086,105e' with PHY type igp I/O devices have been retired + 6895459 e1000g share code update v3-1-10-1 diff --git a/usr/src/uts/common/io/e1000g/e1000_80003es2lan.c b/usr/src/uts/common/io/e1000g/e1000_80003es2lan.c index 48d8e64e98..4481425959 100644 --- a/usr/src/uts/common/io/e1000g/e1000_80003es2lan.c +++ b/usr/src/uts/common/io/e1000g/e1000_80003es2lan.c @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.86 v3-1-3_2009-8-20 + * IntelVersion: 1.86 v3-1-10-1_2009-9-18_Release14-6 */ /* * 80003ES2LAN Gigabit Ethernet Controller (Copper) diff --git a/usr/src/uts/common/io/e1000g/e1000_80003es2lan.h b/usr/src/uts/common/io/e1000g/e1000_80003es2lan.h index f020b59fd7..2b2fbac500 100644 --- a/usr/src/uts/common/io/e1000g/e1000_80003es2lan.h +++ b/usr/src/uts/common/io/e1000g/e1000_80003es2lan.h @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.10 v3-1-3_2009-8-20 + * IntelVersion: 1.10 v3-1-10-1_2009-9-18_Release14-6 */ #ifndef _E1000_80003ES2LAN_H_ #define _E1000_80003ES2LAN_H_ diff --git a/usr/src/uts/common/io/e1000g/e1000_82540.c b/usr/src/uts/common/io/e1000g/e1000_82540.c index 6ffa02b27e..3d9781e259 100644 --- a/usr/src/uts/common/io/e1000g/e1000_82540.c +++ b/usr/src/uts/common/io/e1000g/e1000_82540.c @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.57 v3-1-3_2009-8-20 + * IntelVersion: 1.57 v3-1-10-1_2009-9-18_Release14-6 */ /* diff --git a/usr/src/uts/common/io/e1000g/e1000_82541.c b/usr/src/uts/common/io/e1000g/e1000_82541.c index 636d12da95..e57e2d3acd 100644 --- a/usr/src/uts/common/io/e1000g/e1000_82541.c +++ b/usr/src/uts/common/io/e1000g/e1000_82541.c @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.68 v3-1-3_2009-8-20 + * IntelVersion: 1.68 v3-1-10-1_2009-9-18_Release14-6 */ /* diff --git a/usr/src/uts/common/io/e1000g/e1000_82541.h b/usr/src/uts/common/io/e1000g/e1000_82541.h index 7b304cc8c5..9dba90a1df 100644 --- a/usr/src/uts/common/io/e1000g/e1000_82541.h +++ b/usr/src/uts/common/io/e1000g/e1000_82541.h @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.9 v3-1-3_2009-8-20 + * IntelVersion: 1.9 v3-1-10-1_2009-9-18_Release14-6 */ #ifndef _E1000_82541_H_ #define _E1000_82541_H_ diff --git a/usr/src/uts/common/io/e1000g/e1000_82542.c b/usr/src/uts/common/io/e1000g/e1000_82542.c index 60aeae7084..d4e8636f16 100644 --- a/usr/src/uts/common/io/e1000g/e1000_82542.c +++ b/usr/src/uts/common/io/e1000g/e1000_82542.c @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.53 v3-1-3_2009-8-20 + * IntelVersion: 1.53 v3-1-10-1_2009-9-18_Release14-6 */ /* diff --git a/usr/src/uts/common/io/e1000g/e1000_82543.c b/usr/src/uts/common/io/e1000g/e1000_82543.c index b11e27372b..6979501cbc 100644 --- a/usr/src/uts/common/io/e1000g/e1000_82543.c +++ b/usr/src/uts/common/io/e1000g/e1000_82543.c @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.68 v3-1-3_2009-8-20 + * IntelVersion: 1.68 v3-1-10-1_2009-9-18_Release14-6 */ /* diff --git a/usr/src/uts/common/io/e1000g/e1000_82543.h b/usr/src/uts/common/io/e1000g/e1000_82543.h index 11adce4366..149f306b00 100644 --- a/usr/src/uts/common/io/e1000g/e1000_82543.h +++ b/usr/src/uts/common/io/e1000g/e1000_82543.h @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.8 v3-1-3_2009-8-20 + * IntelVersion: 1.8 v3-1-10-1_2009-9-18_Release14-6 */ #ifndef _E1000_82543_H_ #define _E1000_82543_H_ diff --git a/usr/src/uts/common/io/e1000g/e1000_82571.c b/usr/src/uts/common/io/e1000g/e1000_82571.c index be20186c07..b13be36f38 100644 --- a/usr/src/uts/common/io/e1000g/e1000_82571.c +++ b/usr/src/uts/common/io/e1000g/e1000_82571.c @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.113 v3-1-3_2009-8-20 + * IntelVersion: 1.113 v3-1-10-1_2009-9-18_Release14-6 */ /* @@ -845,7 +845,6 @@ e1000_get_cfg_done_82571(struct e1000_hw *hw) } if (!timeout) { DEBUGOUT("MNG configuration cycle has not completed.\n"); - ret_val = -E1000_ERR_RESET; goto out; } diff --git a/usr/src/uts/common/io/e1000g/e1000_82571.h b/usr/src/uts/common/io/e1000g/e1000_82571.h index f548a82d30..98279ddd49 100644 --- a/usr/src/uts/common/io/e1000g/e1000_82571.h +++ b/usr/src/uts/common/io/e1000g/e1000_82571.h @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.16 v3-1-3_2009-8-20 + * IntelVersion: 1.16 v3-1-10-1_2009-9-18_Release14-6 */ #ifndef _E1000_82571_H_ #define _E1000_82571_H_ diff --git a/usr/src/uts/common/io/e1000g/e1000_api.c b/usr/src/uts/common/io/e1000g/e1000_api.c index 5b1873a237..44cd74d164 100644 --- a/usr/src/uts/common/io/e1000g/e1000_api.c +++ b/usr/src/uts/common/io/e1000g/e1000_api.c @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.124 v3-1-3_2009-8-20 + * IntelVersion: 1.125 v3-1-10-1_2009-9-18_Release14-6 */ #include "e1000_api.h" diff --git a/usr/src/uts/common/io/e1000g/e1000_api.h b/usr/src/uts/common/io/e1000g/e1000_api.h index 6a2cf0c89b..a2ba7bcab1 100644 --- a/usr/src/uts/common/io/e1000g/e1000_api.h +++ b/usr/src/uts/common/io/e1000g/e1000_api.h @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.53 v3-1-3_2009-8-20 + * IntelVersion: 1.53 v3-1-10-1_2009-9-18_Release14-6 */ #ifndef _E1000_API_H_ #define _E1000_API_H_ diff --git a/usr/src/uts/common/io/e1000g/e1000_defines.h b/usr/src/uts/common/io/e1000g/e1000_defines.h index 449ffc9473..5927c6a263 100644 --- a/usr/src/uts/common/io/e1000g/e1000_defines.h +++ b/usr/src/uts/common/io/e1000g/e1000_defines.h @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.116 v3-1-3_2009-8-20 + * IntelVersion: 1.118 v3-1-10-1_2009-9-18_Release14-6 */ #ifndef _E1000_DEFINES_H_ #define _E1000_DEFINES_H_ @@ -691,6 +691,7 @@ /* 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 diff --git a/usr/src/uts/common/io/e1000g/e1000_hw.h b/usr/src/uts/common/io/e1000g/e1000_hw.h index 9a4dbdfa64..723ca8ee27 100644 --- a/usr/src/uts/common/io/e1000g/e1000_hw.h +++ b/usr/src/uts/common/io/e1000g/e1000_hw.h @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.432 v3-1-3_2009-8-20 + * IntelVersion: 1.439 v3-1-10-1_2009-9-18_Release14-6 */ #ifndef _E1000_HW_H_ #define _E1000_HW_H_ @@ -603,11 +603,13 @@ struct e1000_phy_operations { s32 (*get_cable_length)(struct e1000_hw *); s32 (*get_info)(struct e1000_hw *); s32 (*read_reg)(struct e1000_hw *, u32, u16 *); + s32 (*read_reg_locked)(struct e1000_hw *, u32, u16 *); void (*release)(struct e1000_hw *); s32 (*reset)(struct e1000_hw *); s32 (*set_d0_lplu_state)(struct e1000_hw *, bool); s32 (*set_d3_lplu_state)(struct e1000_hw *, bool); s32 (*write_reg)(struct e1000_hw *, u32, u16); + s32 (*write_reg_locked)(struct e1000_hw *, u32, u16); void (*power_up)(struct e1000_hw *); void (*power_down)(struct e1000_hw *); }; @@ -774,6 +776,8 @@ struct e1000_dev_spec_ich8lan { struct e1000_shadow_ram shadow_ram[E1000_SHADOW_RAM_WORDS]; E1000_MUTEX nvm_mutex; E1000_MUTEX swflag_mutex; + bool nvm_k1_enabled; + bool nvm_lcd_config_enabled; }; struct e1000_hw { diff --git a/usr/src/uts/common/io/e1000g/e1000_ich8lan.c b/usr/src/uts/common/io/e1000g/e1000_ich8lan.c index cd62381fdf..13494bcbd4 100644 --- a/usr/src/uts/common/io/e1000g/e1000_ich8lan.c +++ b/usr/src/uts/common/io/e1000g/e1000_ich8lan.c @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.180 v3-1-3_2009-8-20 + * IntelVersion: 1.186.2.1 v3-1-10-1_2009-9-18_Release14-6 */ /* @@ -69,6 +69,7 @@ static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw); static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw); static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw); static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw); +static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active); static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active); static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, @@ -92,10 +93,11 @@ static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw); static s32 e1000_led_on_ich8lan(struct e1000_hw *hw); static s32 e1000_led_off_ich8lan(struct e1000_hw *hw); -static s32 e1000_setup_led_pchlan(struct e1000_hw *hw); -static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw); -static s32 e1000_led_on_pchlan(struct e1000_hw *hw); -static s32 e1000_led_off_pchlan(struct e1000_hw *hw); +static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link); +static s32 e1000_setup_led_pchlan(struct e1000_hw *hw); +static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw); +static s32 e1000_led_on_pchlan(struct e1000_hw *hw); +static s32 e1000_led_off_pchlan(struct e1000_hw *hw); static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw); static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank); static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout); @@ -118,6 +120,8 @@ static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw); static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw); static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw); +static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw); +static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw); /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */ /* Offset 04h HSFSTS */ @@ -185,11 +189,13 @@ e1000_init_phy_params_pchlan(struct e1000_hw *hw) phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan; phy->ops.get_info = e1000_get_phy_info_ich8lan; phy->ops.read_reg = e1000_read_phy_reg_hv; + phy->ops.read_reg_locked = e1000_read_phy_reg_hv_locked; phy->ops.release = e1000_release_swflag_ich8lan; phy->ops.reset = e1000_phy_hw_reset_ich8lan; - phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan; - phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan; + phy->ops.set_d0_lplu_state = e1000_set_lplu_state_pchlan; + phy->ops.set_d3_lplu_state = e1000_set_lplu_state_pchlan; phy->ops.write_reg = e1000_write_phy_reg_hv; + phy->ops.write_reg_locked = e1000_write_phy_reg_hv_locked; phy->ops.power_up = e1000_power_up_phy_copper; phy->ops.power_down = e1000_power_down_phy_copper_ich8lan; phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; @@ -273,6 +279,8 @@ e1000_init_phy_params_ich8lan(struct e1000_hw *hw) case IGP03E1000_E_PHY_ID: phy->type = e1000_phy_igp_3; phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; + phy->ops.read_reg_locked = e1000_read_phy_reg_igp_locked; + phy->ops.write_reg_locked = e1000_write_phy_reg_igp_locked; break; case IFE_E_PHY_ID: case IFE_PLUS_E_PHY_ID: @@ -491,14 +499,6 @@ e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) goto out; } - if (hw->mac.type == e1000_pchlan) { - ret_val = e1000_write_kmrn_reg_generic(hw, - E1000_KMRNCTRLSTA_K1_CONFIG, - E1000_KMRNCTRLSTA_K1_ENABLE); - if (ret_val) - goto out; - } - /* * First we want to see if the MII Status Register reports * link. If so, then we want to get the current speed/duplex @@ -508,6 +508,12 @@ e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) if (ret_val) goto out; + if (hw->mac.type == e1000_pchlan) { + ret_val = e1000_k1_gig_workaround_hv(hw, link); + if (ret_val) + goto out; + } + if (!link) goto out; /* No link detected */ @@ -616,9 +622,8 @@ e1000_release_nvm_ich8lan(struct e1000_hw *hw) * e1000_acquire_swflag_ich8lan - Acquire software control flag * @hw: pointer to the HW structure * - * Acquires the software control flag for performing NVM and PHY - * operations. This is a function pointer entry point only called by - * read/write routines for the PHY and NVM parts. + * Acquires the software control flag for performing PHY and select + * MAC CSR accesses. */ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) @@ -652,9 +657,9 @@ e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); while (timeout) { - extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); - if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) - break; + extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); + if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) + break; msec_delay_irq(1); timeout--; @@ -679,9 +684,8 @@ out: * e1000_release_swflag_ich8lan - Release software control flag * @hw: pointer to the HW structure * - * Releases the software control flag for performing NVM and PHY operations. - * This is a function pointer entry point only called by read/write - * routines for the PHY and NVM parts. + * Releases the software control flag for performing PHY and select + * MAC CSR accesses. */ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw) @@ -740,6 +744,343 @@ e1000_check_reset_block_ich8lan(struct e1000_hw *hw) } /* + * e1000_sw_lcd_config_ich8lan - SW-based LCD Configuration + * @hw: pointer to the HW structure + * + * SW should configure the LCD from the NVM extended configuration region + * as a workaround for certain parts. + */ +static s32 +e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw) +{ + struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; + struct e1000_phy_info *phy = &hw->phy; + u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask; + s32 ret_val; + u16 word_addr, reg_data, reg_addr, phy_page = 0; + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return (ret_val); + + /* + * Initialize the PHY from the NVM on ICH platforms. This + * is needed due to an issue where the NVM configuration is + * not properly autoloaded after power transitions. + * Therefore, after each PHY reset, we will load the + * configuration data out of the NVM manually. + */ + if ((hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) || + (hw->mac.type == e1000_pchlan)) { + /* Check if SW needs to configure the PHY */ + if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_M_AMT) || + (hw->device_id == E1000_DEV_ID_ICH8_IGP_M) || + (hw->mac.type == e1000_pchlan)) + sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M; + else + sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG; + + data = E1000_READ_REG(hw, E1000_FEXTNVM); + if (!(data & sw_cfg_mask)) + goto out; + + /* Wait for basic configuration completes before proceeding */ + e1000_lan_init_done_ich8lan(hw); + + /* + * Make sure HW does not configure LCD from PHY + * extended configuration before SW configuration + */ + data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); + if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) + goto out; + + cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE); + cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK; + cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT; + if (!cnf_size) + goto out; + + cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK; + cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT; + + if (!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) && + hw->mac.type == e1000_pchlan) { + /* + * HW configures the SMBus address and LEDs when the + * OEM and LCD Write Enable bits are set in the NVM. + * When both NVM bits are cleared, SW will configure + * them instead. + */ + data = E1000_READ_REG(hw, E1000_STRAP); + data &= E1000_STRAP_SMBUS_ADDRESS_MASK; + reg_data = data >> E1000_STRAP_SMBUS_ADDRESS_SHIFT; + reg_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID; + ret_val = e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR, + reg_data); + if (ret_val) + goto out; + + data = E1000_READ_REG(hw, E1000_LEDCTL); + ret_val = e1000_write_phy_reg_hv_locked(hw, + HV_LED_CONFIG, (u16)data); + if (ret_val) + goto out; + + dev_spec->nvm_lcd_config_enabled = true; + } + /* Configure LCD from extended configuration region. */ + + /* cnf_base_addr is in DWORD */ + word_addr = (u16)(cnf_base_addr << 1); + + for (i = 0; i < cnf_size; i++) { + ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2), 1, + ®_data); + if (ret_val) + goto out; + + ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2 + 1), + 1, ®_addr); + if (ret_val) + goto out; + + /* Save off the PHY page for future writes. */ + if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) { + phy_page = reg_data; + continue; + } + /* + * Bit 5 in the LCD config word contains the phy + * address for PCH + */ + if (hw->mac.type == e1000_pchlan) { + phy->addr = 1; + if (reg_addr & LCD_CFG_PHY_ADDR_BIT) { + phy->addr = 2; + reg_addr &= PHY_REG_MASK; + } + } + + reg_addr |= phy_page; + + ret_val = phy->ops.write_reg_locked(hw, (u32)reg_addr, + reg_data); + if (ret_val) + goto out; + } + + if (hw->mac.type == e1000_pchlan) + dev_spec->nvm_lcd_config_enabled = false; + } + +out: + hw->phy.ops.release(hw); + return (ret_val); +} + +/* + * e1000_k1_gig_workaround_hv - K1 Si workaround + * @hw: pointer to the HW structure + * @link: link up bool flag + * + * If K1 is enabled for 1Gbps, the MAC might stall when transitioning + * from a lower speed. This workaround disables K1 whenever link is at 1Gig + * If link is down, the function will restore the default K1 setting located + * in the NVM. + */ +static s32 +e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link) +{ + s32 ret_val = E1000_SUCCESS; + u16 status_reg = 0; + bool k1_enable = hw->dev_spec.ich8lan.nvm_k1_enabled; + + DEBUGFUNC("e1000_k1_gig_workaround_hv"); + + if (hw->mac.type != e1000_pchlan) + goto out; + + /* Wrap the whole flow with the sw flag */ + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + + /* Disable K1 when link is 1Gbps, otherwise use the NVM setting */ + if (link) { + if (hw->phy.type == e1000_phy_82578) { + ret_val = hw->phy.ops.read_reg_locked(hw, BM_CS_STATUS, + &status_reg); + if (ret_val) + goto release; + + status_reg &= BM_CS_STATUS_LINK_UP | + BM_CS_STATUS_RESOLVED | + BM_CS_STATUS_SPEED_MASK; + + if (status_reg == (BM_CS_STATUS_LINK_UP | + BM_CS_STATUS_RESOLVED | + BM_CS_STATUS_SPEED_1000)) + k1_enable = false; + } + + if (hw->phy.type == e1000_phy_82577) { + ret_val = hw->phy.ops.read_reg_locked(hw, HV_M_STATUS, + &status_reg); + if (ret_val) + goto release; + + status_reg &= HV_M_STATUS_LINK_UP | + HV_M_STATUS_AUTONEG_COMPLETE | + HV_M_STATUS_SPEED_MASK; + + if (status_reg == (HV_M_STATUS_LINK_UP | + HV_M_STATUS_AUTONEG_COMPLETE | + HV_M_STATUS_SPEED_1000)) + k1_enable = false; + } + + /* Link stall fix for link up */ + ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19), + 0x0100); + if (ret_val) + goto release; + + } else { + /* Link stall fix for link down */ + ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19), + 0x4100); + if (ret_val) + goto release; + } + + ret_val = e1000_configure_k1_ich8lan(hw, k1_enable); + +release: + hw->phy.ops.release(hw); +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) + */ +s32 +e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable) +{ + s32 ret_val = E1000_SUCCESS; + u32 ctrl_reg = 0; + u32 ctrl_ext = 0; + u32 reg = 0; + u16 kmrn_reg = 0; + + ret_val = e1000_read_kmrn_reg_locked(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 = e1000_write_kmrn_reg_locked(hw, + E1000_KMRNCTRLSTA_K1_CONFIG, + kmrn_reg); + if (ret_val) + goto out; + + usec_delay(20); + ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); + ctrl_reg = E1000_READ_REG(hw, E1000_CTRL); + + reg = ctrl_reg & ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); + reg |= E1000_CTRL_FRCSPD; + E1000_WRITE_REG(hw, E1000_CTRL, reg); + + E1000_WRITE_REG(hw, + E1000_CTRL_EXT, + ctrl_ext | E1000_CTRL_EXT_SPD_BYPS); + usec_delay(20); + E1000_WRITE_REG(hw, E1000_CTRL, ctrl_reg); + E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); + usec_delay(20); + +out: + return (ret_val); +} + +/* + * e1000_oem_bits_config_ich8lan - SW-based LCD Configuration + * @hw: pointer to the HW structure + * @d0_state: boolean if entering d0 or d3 device state + * + * SW will configure Gbe Disable and LPLU based on the NVM. The four bits are + * collectively called OEM bits. The OEM Write Enable bit and SW Config bit + * in NVM determines whether HW should configure LPLU and Gbe Disable. + */ +s32 +e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state) +{ + s32 ret_val = 0; + u32 mac_reg; + u16 oem_reg; + + if (hw->mac.type != e1000_pchlan) + return (ret_val); + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return (ret_val); + + mac_reg = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); + if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) + goto out; + + mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM); + if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M)) + goto out; + + mac_reg = E1000_READ_REG(hw, E1000_PHY_CTRL); + + ret_val = hw->phy.ops.read_reg_locked(hw, HV_OEM_BITS, &oem_reg); + if (ret_val) + goto out; + + oem_reg &= ~(HV_OEM_BITS_GBE_DIS | HV_OEM_BITS_LPLU); + + if (d0_state) { + if (mac_reg & E1000_PHY_CTRL_GBE_DISABLE) + oem_reg |= HV_OEM_BITS_GBE_DIS; + + if (mac_reg & E1000_PHY_CTRL_D0A_LPLU) + oem_reg |= HV_OEM_BITS_LPLU; + } else { + if (mac_reg & E1000_PHY_CTRL_NOND0A_GBE_DISABLE) + oem_reg |= HV_OEM_BITS_GBE_DIS; + + if (mac_reg & E1000_PHY_CTRL_NOND0A_LPLU) + oem_reg |= HV_OEM_BITS_LPLU; + } + /* Restart auto-neg to activate the bits */ + oem_reg |= HV_OEM_BITS_RESTART_AN; + ret_val = hw->phy.ops.write_reg_locked(hw, HV_OEM_BITS, oem_reg); + +out: + hw->phy.ops.release(hw); + + return (ret_val); +} + +/* * e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be * done after every PHY reset. */ @@ -749,7 +1090,7 @@ e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw) s32 ret_val = E1000_SUCCESS; if (hw->mac.type != e1000_pchlan) - return (ret_val); + goto out; if (((hw->phy.type == e1000_phy_82577) && ((hw->phy.revision == 1) || (hw->phy.revision == 2))) || @@ -757,12 +1098,12 @@ e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw) /* Disable generation of early preamble */ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431); if (ret_val) - return (ret_val); + goto out; /* Preamble tuning for SSC */ ret_val = hw->phy.ops.write_reg(hw, PHY_REG(770, 16), 0xA204); if (ret_val) - return (ret_val); + goto out; } if (hw->phy.type == e1000_phy_82578) { @@ -780,12 +1121,21 @@ e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw) /* Select page 0 */ ret_val = hw->phy.ops.acquire(hw); if (ret_val) - return (ret_val); + goto out; hw->phy.addr = 1; - e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0); + ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0); + if (ret_val) + goto out; hw->phy.ops.release(hw); + /* + * Configure the K1 Si workaround during phy reset assuming there is + * link so that it disables K1 if link is in 1Gbps. + */ + ret_val = e1000_k1_gig_workaround_hv(hw, true); + +out: return (ret_val); } @@ -862,10 +1212,8 @@ e1000_lan_init_done_ich8lan(struct e1000_hw *hw) static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw) { - struct e1000_phy_info *phy = &hw->phy; - u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask; - s32 ret_val; - u16 word_addr, reg_data, reg_addr, phy_page = 0; + s32 ret_val = E1000_SUCCESS; + u16 reg; DEBUGFUNC("e1000_phy_hw_reset_ich8lan"); @@ -888,86 +1236,22 @@ e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw) goto out; } - /* - * Initialize the PHY from the NVM on ICH platforms. This is needed - * due to an issue where the NVM configuration is not properly - * autoloaded after power transitions. Therefore, after each PHY - * reset, we will load the configuration data out of the NVM manually. - */ - if (hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) { - /* 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)) - sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M; - else - sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG; - - data = E1000_READ_REG(hw, E1000_FEXTNVM); - if (!(data & sw_cfg_mask)) - goto out; - - /* Wait for basic configuration completes before proceeding */ - e1000_lan_init_done_ich8lan(hw); - - /* - * Make sure HW does not configure LCD from PHY extended - * configuration before SW configuration - */ - data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); - if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) - goto out; - - cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE); - cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK; - cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT; - if (!cnf_size) - goto out; - - cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK; - cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT; - - /* - * Configure LCD from extended configuration region. - */ - - /* cnf_base_addr is in DWORD */ - word_addr = (u16)(cnf_base_addr << 1); - - for (i = 0; i < cnf_size; i++) { - ret_val = hw->nvm.ops.read(hw, - (word_addr + i * 2), - 1, - ®_data); - if (ret_val) - goto out; - - ret_val = hw->nvm.ops.read(hw, - (word_addr + i * 2 + 1), - 1, - ®_addr); - if (ret_val) - goto out; - - /* Save off the PHY page for future writes. */ - if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) { - phy_page = reg_data; - continue; - } + /* Dummy read to clear the phy wakeup bit after lcd reset */ + if (hw->mac.type == e1000_pchlan) + hw->phy.ops.read_reg(hw, BM_WUC, ®); - reg_addr |= phy_page; + /* Configure the LCD with the extended configuration region in NVM */ + ret_val = e1000_sw_lcd_config_ich8lan(hw); + if (ret_val) + goto out; - ret_val = phy->ops.write_reg(hw, - (u32)reg_addr, - reg_data); - if (ret_val) - goto out; - } - } + /* Configure the LCD with the OEM bits in NVM */ + if (hw->mac.type == e1000_pchlan) + ret_val = e1000_oem_bits_config_ich8lan(hw, true); out: return (ret_val); } - /* * e1000_get_phy_info_ich8lan - Calls appropriate PHY type get_phy_info * @hw: pointer to the HW structure @@ -1059,6 +1343,41 @@ out: } /* + * e1000_set_lplu_state_pchlan - Set Low Power Link Up state + * @hw: pointer to the HW structure + * @active: true to enable LPLU, false to disable + * + * Sets the LPLU state according to the active flag. For PCH, if OEM write + * bit are disabled in the NVM, writing the LPLU bits in the MAC will not set + * the phy speed. This function will manually set the LPLU bit and restart + * auto-neg as hw would do. D3 and D0 LPLU will call the same function + * since it configures the same bit. + */ +static s32 +e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active) +{ + s32 ret_val = E1000_SUCCESS; + u16 oem_reg; + + DEBUGFUNC("e1000_set_lplu_state_pchlan"); + + ret_val = hw->phy.ops.read_reg(hw, HV_OEM_BITS, &oem_reg); + if (ret_val) + goto out; + + if (active) + oem_reg |= HV_OEM_BITS_LPLU; + else + oem_reg &= ~HV_OEM_BITS_LPLU; + + oem_reg |= HV_OEM_BITS_RESTART_AN; + ret_val = hw->phy.ops.write_reg(hw, HV_OEM_BITS, oem_reg); + +out: + return (ret_val); +} + +/* * e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state * @hw: pointer to the HW structure * @active: true to enable LPLU, false to disable @@ -2288,6 +2607,8 @@ e1000_get_bus_info_ich8lan(struct e1000_hw *hw) static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) { + struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; + u16 reg; u32 ctrl, kab; s32 ret_val; @@ -2323,6 +2644,18 @@ e1000_reset_hw_ich8lan(struct e1000_hw *hw) E1000_WRITE_REG(hw, E1000_PBS, E1000_PBS_16K); } + if (hw->mac.type == e1000_pchlan) { + /* Save the NVM K1 bit setting */ + ret_val = e1000_read_nvm(hw, E1000_NVM_K1_CONFIG, 1, ®); + if (ret_val) + return (ret_val); + + if (reg & E1000_NVM_K1_ENABLE) + dev_spec->nvm_k1_enabled = true; + else + dev_spec->nvm_k1_enabled = false; + } + ctrl = E1000_READ_REG(hw, E1000_CTRL); if (!hw->phy.ops.check_reset_block(hw) && !hw->phy.reset_disable) { @@ -2367,6 +2700,20 @@ e1000_reset_hw_ich8lan(struct e1000_hw *hw) } } + /* Dummy read to clear the phy wakeup bit after lcd reset */ + if (hw->mac.type == e1000_pchlan) + hw->phy.ops.read_reg(hw, BM_WUC, ®); + + ret_val = e1000_sw_lcd_config_ich8lan(hw); + if (ret_val) + goto out; + + if (hw->mac.type == e1000_pchlan) { + ret_val = e1000_oem_bits_config_ich8lan(hw, true); + if (ret_val) + goto out; + } + /* * For PCH, this write will make sure that any noise * will be detected as a CRC error and be dropped rather than show up @@ -2712,14 +3059,6 @@ e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed, u16 *duplex) if (ret_val) goto out; - if ((hw->mac.type == e1000_pchlan) && (*speed == SPEED_1000)) { - ret_val = e1000_write_kmrn_reg_generic(hw, - E1000_KMRNCTRLSTA_K1_CONFIG, - E1000_KMRNCTRLSTA_K1_DISABLE); - if (ret_val) - goto out; - } - if ((hw->mac.type == e1000_ich8lan) && (hw->phy.type == e1000_phy_igp_3) && (*speed == SPEED_1000)) { @@ -2951,9 +3290,8 @@ e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw) E1000_PHY_CTRL_GBE_DISABLE; E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); - /* Workaround SWFLAG unexpectedly set during S0->Sx */ if (hw->mac.type == e1000_pchlan) - usec_delay(500); + e1000_phy_hw_reset_ich8lan(hw); default: break; } diff --git a/usr/src/uts/common/io/e1000g/e1000_ich8lan.h b/usr/src/uts/common/io/e1000g/e1000_ich8lan.h index 3164e889df..48d0f95c12 100644 --- a/usr/src/uts/common/io/e1000g/e1000_ich8lan.h +++ b/usr/src/uts/common/io/e1000g/e1000_ich8lan.h @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.37 v3-1-3_2009-8-20 + * IntelVersion: 1.41 v3-1-10-1_2009-9-18_Release14-6 */ #ifndef _E1000_ICH8LAN_H_ #define _E1000_ICH8LAN_H_ @@ -140,6 +140,28 @@ extern "C" { /* PCH Flow Control Refresh Timer Value */ #define E1000_FCRTV_PCH 0x05F40 + +#define E1000_NVM_K1_CONFIG 0x1B /* NVM K1 Config Word */ +#define E1000_NVM_K1_ENABLE 0x1 /* NVM Enable K1 bit */ + +/* SMBus Address Phy Register */ +#define HV_SMB_ADDR PHY_REG(768, 26) +#define HV_SMB_ADDR_PEC_EN 0x0200 +#define HV_SMB_ADDR_VALID 0x0080 + +/* Strapping Option Register - RO */ +#define E1000_STRAP 0x0000C +#define E1000_STRAP_SMBUS_ADDRESS_MASK 0x00FE0000 +#define E1000_STRAP_SMBUS_ADDRESS_SHIFT 17 + +/* OEM Bits Phy Register */ +#define HV_OEM_BITS PHY_REG(768, 25) +#define HV_OEM_BITS_LPLU 0x0004 /* Low Power Link Up */ +#define HV_OEM_BITS_GBE_DIS 0x0040 /* Gigabit Disable */ +#define HV_OEM_BITS_RESTART_AN 0x0400 /* Restart Auto-negotiation */ +/* Phy address bit from LCD Config word */ +#define LCD_CFG_PHY_ADDR_BIT 0x0020 + /* SW Semaphore flag timeout in milliseconds */ #define SW_FLAG_TIMEOUT 400 @@ -172,6 +194,8 @@ void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw); void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw); void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw); +s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable); +s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_config); #ifdef __cplusplus } diff --git a/usr/src/uts/common/io/e1000g/e1000_mac.c b/usr/src/uts/common/io/e1000g/e1000_mac.c index 69cdc6f412..0a9f4dccdb 100644 --- a/usr/src/uts/common/io/e1000g/e1000_mac.c +++ b/usr/src/uts/common/io/e1000g/e1000_mac.c @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.108 v3-1-3_2009-8-20 + * IntelVersion: 1.108 v3-1-10-1_2009-9-18_Release14-6 */ #include "e1000_api.h" @@ -2184,7 +2184,7 @@ e1000_update_adaptive_generic(struct e1000_hw *hw) * Verify that when not using auto-negotiation that MDI/MDIx is correctly * set, which is forced to MDI mode only. */ -s32 +static s32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw) { s32 ret_val = E1000_SUCCESS; diff --git a/usr/src/uts/common/io/e1000g/e1000_mac.h b/usr/src/uts/common/io/e1000g/e1000_mac.h index 210d83399e..022798b5a7 100644 --- a/usr/src/uts/common/io/e1000g/e1000_mac.h +++ b/usr/src/uts/common/io/e1000g/e1000_mac.h @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.32 v3-1-3_2009-8-20 + * IntelVersion: 1.32 v3-1-10-1_2009-9-18_Release14-6 */ #ifndef _E1000_MAC_H_ #define _E1000_MAC_H_ diff --git a/usr/src/uts/common/io/e1000g/e1000_manage.c b/usr/src/uts/common/io/e1000g/e1000_manage.c index 440eb4b10d..aa4c2d14b2 100644 --- a/usr/src/uts/common/io/e1000g/e1000_manage.c +++ b/usr/src/uts/common/io/e1000g/e1000_manage.c @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.27 v3-1-3_2009-8-20 + * IntelVersion: 1.27 v3-1-10-1_2009-9-18_Release14-6 */ #include "e1000_api.h" diff --git a/usr/src/uts/common/io/e1000g/e1000_manage.h b/usr/src/uts/common/io/e1000g/e1000_manage.h index cb9f186356..0bae703485 100644 --- a/usr/src/uts/common/io/e1000g/e1000_manage.h +++ b/usr/src/uts/common/io/e1000g/e1000_manage.h @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.18 v3-1-3_2009-8-20 + * IntelVersion: 1.18 v3-1-10-1_2009-9-18_Release14-6 */ #ifndef _E1000_MANAGE_H_ #define _E1000_MANAGE_H_ diff --git a/usr/src/uts/common/io/e1000g/e1000_nvm.c b/usr/src/uts/common/io/e1000g/e1000_nvm.c index 1c00498071..10a904af34 100644 --- a/usr/src/uts/common/io/e1000g/e1000_nvm.c +++ b/usr/src/uts/common/io/e1000g/e1000_nvm.c @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.49 v3-1-3_2009-8-20 + * IntelVersion: 1.49 v3-1-10-1_2009-9-18_Release14-6 */ #include "e1000_api.h" diff --git a/usr/src/uts/common/io/e1000g/e1000_nvm.h b/usr/src/uts/common/io/e1000g/e1000_nvm.h index 28a645a22a..9bb72407f5 100644 --- a/usr/src/uts/common/io/e1000g/e1000_nvm.h +++ b/usr/src/uts/common/io/e1000g/e1000_nvm.h @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.18 v3-1-3_2009-8-20 + * IntelVersion: 1.18 v3-1-10-1_2009-9-18_Release14-6 */ #ifndef _E1000_NVM_H_ #define _E1000_NVM_H_ diff --git a/usr/src/uts/common/io/e1000g/e1000_phy.c b/usr/src/uts/common/io/e1000g/e1000_phy.c index 87dfb78adc..b1e8166353 100644 --- a/usr/src/uts/common/io/e1000g/e1000_phy.c +++ b/usr/src/uts/common/io/e1000g/e1000_phy.c @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.143 v3-1-3_2009-8-20 + * IntelVersion: 1.151 v3-1-10-1_2009-9-18_Release14-6 */ #include "e1000_api.h" @@ -81,11 +81,13 @@ e1000_init_phy_ops_generic(struct e1000_hw *hw) phy->ops.get_cable_length = e1000_null_ops_generic; phy->ops.get_info = e1000_null_ops_generic; phy->ops.read_reg = e1000_null_read_reg; + phy->ops.read_reg_locked = e1000_null_read_reg; phy->ops.release = e1000_null_phy_generic; phy->ops.reset = e1000_null_ops_generic; phy->ops.set_d0_lplu_state = e1000_null_lplu_state; phy->ops.set_d3_lplu_state = e1000_null_lplu_state; phy->ops.write_reg = e1000_null_write_reg; + phy->ops.write_reg_locked = e1000_null_write_reg; phy->ops.power_up = e1000_null_phy_generic; phy->ops.power_down = e1000_null_phy_generic; phy->ops.cfg_on_link_up = e1000_null_ops_generic; @@ -197,21 +199,30 @@ e1000_get_phy_id(struct e1000_hw *hw) goto out; /* - * If the PHY ID is still unknown, we may have an 82577 without - * link. We will try again after setting Slow MDIC mode. No - * harm in trying again in this case since the PHY ID is - * unknown at this point anyway + * If the PHY ID is still unknown, we may have an 82577 + * without link. We will try again after setting Slow MDIC + * mode. No harm in trying again in this case since the PHY + * ID is unknown at this point anyway. */ + ret_val = phy->ops.acquire(hw); + if (ret_val) + goto out; ret_val = e1000_set_mdio_slow_mode_hv(hw, true); if (ret_val) goto out; + phy->ops.release(hw); retry_count++; } out: /* Revert to MDIO fast mode, if applicable */ - if (retry_count) + if (retry_count) { + ret_val = phy->ops.acquire(hw); + if (ret_val) + return (ret_val); ret_val = e1000_set_mdio_slow_mode_hv(hw, false); + phy->ops.release(hw); + } return (ret_val); } @@ -425,111 +436,179 @@ out: * @hw: pointer to the HW structure * @offset: register offset to be read * @data: pointer to the read data + * @locked: semaphore has already been acquired or not * * Acquires semaphore, if necessary, then reads the PHY register at offset - * and storing the retrieved information in data. Release any acquired + * and stores the retrieved information in data. Release any acquired * semaphores before exiting. */ -s32 -e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data) +static s32 +__e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data, + bool locked) { s32 ret_val = E1000_SUCCESS; - DEBUGFUNC("e1000_read_phy_reg_igp"); + DEBUGFUNC("__e1000_read_phy_reg_igp"); - if (!(hw->phy.ops.acquire)) - goto out; + if (!locked) { + if (!(hw->phy.ops.acquire)) + goto out; - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + } if (offset > MAX_PHY_MULTI_PAGE_REG) { ret_val = e1000_write_phy_reg_mdic(hw, - IGP01E1000_PHY_PAGE_SELECT, - (u16)offset); - if (ret_val) { - hw->phy.ops.release(hw); - goto out; - } + IGP01E1000_PHY_PAGE_SELECT, (u16)offset); + if (ret_val) + goto release; } - ret_val = e1000_read_phy_reg_mdic(hw, - MAX_PHY_REG_ADDRESS & offset, - data); - hw->phy.ops.release(hw); + ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, + data); +release: + if (!locked) + hw->phy.ops.release(hw); out: return (ret_val); } /* + * e1000_read_phy_reg_igp - Read igp PHY register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquires semaphore then reads the PHY register at offset and stores the + * retrieved information in data. + * Release the acquired semaphore before exiting. + */ +s32 +e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data) +{ + return (__e1000_read_phy_reg_igp(hw, offset, data, false)); +} + +/* + * e1000_read_phy_reg_igp_locked - Read igp PHY register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Reads the PHY register at offset and stores the retrieved information + * in data. Assumes semaphore already acquired. + */ +s32 +e1000_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data) +{ + return (__e1000_read_phy_reg_igp(hw, offset, data, true)); +} + +/* * e1000_write_phy_reg_igp - Write igp PHY register * @hw: pointer to the HW structure * @offset: register offset to write to * @data: data to write at register offset + * @locked: semaphore has already been acquired or not * * Acquires semaphore, if necessary, then writes the data to PHY register * at the offset. Release any acquired semaphores before exiting. */ -s32 -e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data) +static s32 +__e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data, + bool locked) { s32 ret_val = E1000_SUCCESS; DEBUGFUNC("e1000_write_phy_reg_igp"); - if (!(hw->phy.ops.acquire)) - goto out; + if (!locked) { + if (!(hw->phy.ops.acquire)) + goto out; - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + } if (offset > MAX_PHY_MULTI_PAGE_REG) { ret_val = e1000_write_phy_reg_mdic(hw, - IGP01E1000_PHY_PAGE_SELECT, - (u16)offset); - if (ret_val) { - hw->phy.ops.release(hw); - goto out; - } + IGP01E1000_PHY_PAGE_SELECT, (u16)offset); + if (ret_val) + goto release; } - ret_val = e1000_write_phy_reg_mdic(hw, - MAX_PHY_REG_ADDRESS & offset, + ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, data); - hw->phy.ops.release(hw); +release: + if (!locked) + hw->phy.ops.release(hw); out: return (ret_val); } /* - * e1000_read_kmrn_reg_generic - Read kumeran register + * e1000_write_phy_reg_igp - Write igp PHY register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquires semaphore then writes the data to PHY register + * at the offset. Release any acquired semaphores before exiting. + */ +s32 +e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data) +{ + return (__e1000_write_phy_reg_igp(hw, offset, data, false)); +} + +/* + * e1000_write_phy_reg_igp_locked - Write igp PHY register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Writes the data to PHY register at the offset. + * Assumes semaphore already acquired. + */ +s32 +e1000_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data) +{ + return (__e1000_write_phy_reg_igp(hw, offset, data, true)); +} + +/* + * __e1000_read_kmrn_reg - Read kumeran register * @hw: pointer to the HW structure * @offset: register offset to be read * @data: pointer to the read data + * @locked: semaphore has already been acquired or not * - * Acquires semaphore, if necessary. Then reads the PHY register at offset - * using the kumeran interface. The information retrieved is stored in data. + * Acquires semaphore, if necessary. Then reads the PHY register at offset + * using the kumeran interface. The information retrieved is stored in data. * Release any acquired semaphores before exiting. */ -s32 -e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data) +static s32 +__e1000_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data, bool locked) { u32 kmrnctrlsta; s32 ret_val = E1000_SUCCESS; - DEBUGFUNC("e1000_read_kmrn_reg_generic"); + DEBUGFUNC("__e1000_read_kmrn_reg"); - if (!(hw->phy.ops.acquire)) - goto out; + if (!locked) { + if (!(hw->phy.ops.acquire)) + goto out; - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + } kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN; @@ -540,49 +619,117 @@ e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data) kmrnctrlsta = E1000_READ_REG(hw, E1000_KMRNCTRLSTA); *data = (u16)kmrnctrlsta; - hw->phy.ops.release(hw); + if (!locked) + hw->phy.ops.release(hw); out: return (ret_val); } /* - * e1000_write_kmrn_reg_generic - Write kumeran register + * e1000_read_kmrn_reg_generic - Read kumeran register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquires semaphore then reads the PHY register at offset using the + * kumeran interface. The information retrieved is stored in data. + * Release the acquired semaphore before exiting. + */ +s32 +e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data) +{ + return (__e1000_read_kmrn_reg(hw, offset, data, false)); +} + +/* + * e1000_read_kmrn_reg_locked - Read kumeran register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Reads the PHY register at offset using the kumeran interface. The + * information retrieved is stored in data. + * Assumes semaphore already acquired. + */ +s32 +e1000_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data) +{ + return (__e1000_read_kmrn_reg(hw, offset, data, true)); +} + +/* + * __e1000_write_kmrn_reg - Write kumeran register * @hw: pointer to the HW structure * @offset: register offset to write to * @data: data to write at register offset + * @locked: semaphore has already been acquired or not * * Acquires semaphore, if necessary. Then write the data to PHY register * at the offset using the kumeran interface. Release any acquired semaphores * before exiting. */ -s32 -e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data) +static s32 +__e1000_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data, bool locked) { u32 kmrnctrlsta; s32 ret_val = E1000_SUCCESS; DEBUGFUNC("e1000_write_kmrn_reg_generic"); - if (!(hw->phy.ops.acquire)) - goto out; + if (!locked) { + if (!(hw->phy.ops.acquire)) + goto out; - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + } kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & E1000_KMRNCTRLSTA_OFFSET) | data; E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta); usec_delay(2); - hw->phy.ops.release(hw); + + if (!locked) + hw->phy.ops.release(hw); out: return (ret_val); } /* + * e1000_write_kmrn_reg_generic - Write kumeran register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquires semaphore then writes the data to the PHY register at the offset + * using the kumeran interface. Release the acquired semaphore before exiting. + */ +s32 +e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data) +{ + return (__e1000_write_kmrn_reg(hw, offset, data, false)); +} + +/* + * e1000_write_kmrn_reg_locked - Write kumeran register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Write the data to PHY register at the offset using the kumeran interface. + * Assumes semaphore already acquired. + */ +s32 +e1000_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data) +{ + return (__e1000_write_kmrn_reg(hw, offset, data, true)); +} + +/* * e1000_copper_link_setup_82577 - Setup 82577 PHY for copper link * @hw: pointer to the HW structure * @@ -1863,8 +2010,7 @@ e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, */ usec_delay(usec_interval); } - ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, - &phy_status); + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); if (ret_val) break; if (phy_status & MII_SR_LINK_STATUS) @@ -2460,15 +2606,16 @@ e1000_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data) DEBUGFUNC("e1000_write_phy_reg_bm"); + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + /* Page 800 works differently than the rest so it has its own func */ if (page == BM_WUC_PAGE) { ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data, false); goto out; } - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset); @@ -2489,19 +2636,16 @@ e1000_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data) /* Page is shifted left, PHY expects (page x 32) */ ret_val = e1000_write_phy_reg_mdic(hw, page_select, (page << page_shift)); - if (ret_val) { - hw->phy.ops.release(hw); + if (ret_val) goto out; - } } ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, data); - hw->phy.ops.release(hw); - out: + hw->phy.ops.release(hw); return (ret_val); } @@ -2525,15 +2669,16 @@ e1000_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data) DEBUGFUNC("e1000_read_phy_reg_bm"); + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + /* Page 800 works differently than the rest so it has its own func */ if (page == BM_WUC_PAGE) { ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data, true); goto out; } - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset); @@ -2554,18 +2699,16 @@ e1000_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data) /* Page is shifted left, PHY expects (page x 32) */ ret_val = e1000_write_phy_reg_mdic(hw, page_select, (page << page_shift)); - if (ret_val) { - hw->phy.ops.release(hw); + if (ret_val) goto out; - } } ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, data); - hw->phy.ops.release(hw); out: + hw->phy.ops.release(hw); return (ret_val); } @@ -2587,6 +2730,10 @@ e1000_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data) DEBUGFUNC("e1000_write_phy_reg_bm2"); + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + /* Page 800 works differently than the rest so it has its own func */ if (page == BM_WUC_PAGE) { ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data, @@ -2594,10 +2741,6 @@ e1000_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data) goto out; } - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - hw->phy.addr = 1; if (offset > MAX_PHY_MULTI_PAGE_REG) { @@ -2606,17 +2749,15 @@ e1000_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data) ret_val = e1000_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT, page); - if (ret_val) { - hw->phy.ops.release(hw); + if (ret_val) goto out; - } } ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, data); - hw->phy.ops.release(hw); out: + hw->phy.ops.release(hw); return (ret_val); } @@ -2637,6 +2778,10 @@ e1000_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data) DEBUGFUNC("e1000_write_phy_reg_bm2"); + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + /* Page 800 works differently than the rest so it has its own func */ if (page == BM_WUC_PAGE) { ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data, @@ -2644,10 +2789,6 @@ e1000_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data) goto out; } - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - hw->phy.addr = 1; if (offset > MAX_PHY_MULTI_PAGE_REG) { @@ -2655,18 +2796,15 @@ e1000_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data) ret_val = e1000_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT, page); - if (ret_val) { - hw->phy.ops.release(hw); + if (ret_val) goto out; - } } ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, data); - hw->phy.ops.release(hw); - out: + hw->phy.ops.release(hw); return (ret_val); } @@ -2686,6 +2824,8 @@ out: * 3) Write the address using the address opcode (0x11) * 4) Read or write the data using the data opcode (0x12) * 5) Restore 769_17.2 to its original value + * + * Assumes semaphore already acquired. */ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, @@ -2694,7 +2834,6 @@ e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, s32 ret_val; u16 reg = BM_PHY_REG_NUM(offset); u16 phy_reg = 0; - u8 phy_acquired = 1; DEBUGFUNC("e1000_access_phy_wakeup_reg_bm"); @@ -2704,13 +2843,6 @@ e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, E1000_PHY_CTRL_GBE_DISABLE))) DEBUGOUT("Attempting to access page 800 while gig enabled.\n"); - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) { - DEBUGOUT("Could not acquire PHY\n"); - phy_acquired = 0; - goto out; - } - /* All operations in this function are phy address 1 */ hw->phy.addr = 1; @@ -2781,8 +2913,6 @@ e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, } out: - if (phy_acquired == 1) - hw->phy.ops.release(hw); return (ret_val); } @@ -2825,16 +2955,19 @@ e1000_power_down_phy_copper(struct e1000_hw *hw) msec_delay(1); } +/* + * e1000_set_mdio_slow_mode_hv - Set slow MDIO access mode + * @hw: pointer to the HW structure + * @slow: true for slow mode, false for normal mode + * + * Assumes semaphore already acquired. + */ s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow) { s32 ret_val = E1000_SUCCESS; u16 data = 0; - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - return (ret_val); - /* Set MDIO mode - page 769, register 16: 0x2580==slow, 0x2180==fast */ hw->phy.addr = 1; ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, @@ -2853,22 +2986,23 @@ e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow) ret_val = e1000_read_phy_reg_mdic(hw, BM_CS_CTRL1, &data); out: - hw->phy.ops.release(hw); return (ret_val); } /* - * e1000_read_phy_reg_hv - Read HV PHY register + * __e1000_read_phy_reg_hv - Read HV PHY register * @hw: pointer to the HW structure * @offset: register offset to be read * @data: pointer to the read data + * @locked: semaphore has already been acquired or not * * Acquires semaphore, if necessary, then reads the PHY register at offset - * and storing the retrieved information in data. Release any acquired + * and stores the retrieved information in data. Release any acquired * semaphore before exiting. */ -s32 -e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data) +static s32 +__e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data, + bool locked) { s32 ret_val; u16 page = BM_PHY_REG_PAGE(offset); @@ -2877,6 +3011,12 @@ e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data) DEBUGFUNC("e1000_read_phy_reg_hv"); + if (!locked) { + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return (ret_val); + } + /* Workaround failure in MDIO access while cable is disconnected */ if ((hw->phy.type == e1000_phy_82577) && !(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) { @@ -2900,10 +3040,6 @@ e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data) goto out; } - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - hw->phy.addr = e1000_get_phy_addr_for_hv_page(page); if (page == HV_INTC_FC_PAGE_START) @@ -2911,51 +3047,86 @@ e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data) if (reg > MAX_PHY_MULTI_PAGE_REG) { u32 phy_addr = hw->phy.addr; + hw->phy.addr = 1; /* Page is shifted left, PHY expects (page x 32) */ ret_val = e1000_write_phy_reg_mdic(hw, - IGP01E1000_PHY_PAGE_SELECT, - (page << IGP_PAGE_SHIFT)); + IGP01E1000_PHY_PAGE_SELECT, (page << IGP_PAGE_SHIFT)); hw->phy.addr = phy_addr; - - if (ret_val) { - hw->phy.ops.release(hw); - goto out; - } } - ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg, - data); - hw->phy.ops.release(hw); - + ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg, data); out: /* Revert to MDIO fast mode, if applicable */ if ((hw->phy.type == e1000_phy_82577) && in_slow_mode) ret_val = e1000_set_mdio_slow_mode_hv(hw, false); + if (!locked) + hw->phy.ops.release(hw); + return (ret_val); } /* - * e1000_write_phy_reg_hv - Write HV PHY register + * e1000_read_phy_reg_hv - Read HV PHY register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquires semaphore then reads the PHY register at offset and stores + * the retrieved information in data. Release the acquired semaphore + * before exiting. + */ +s32 +e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data) +{ + return (__e1000_read_phy_reg_hv(hw, offset, data, false)); +} + +/* + * e1000_read_phy_reg_hv_locked - Read HV PHY register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Reads the PHY register at offset and stores the retrieved information + * in data. Assumes semaphore already acquired. + */ +s32 +e1000_read_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 *data) +{ + return (__e1000_read_phy_reg_hv(hw, offset, data, true)); +} + +/* + * __e1000_write_phy_reg_hv - Write HV PHY register * @hw: pointer to the HW structure * @offset: register offset to write to * @data: data to write at register offset + * @locked: semaphore has already been acquired or not * * Acquires semaphore, if necessary, then writes the data to PHY register * at the offset. Release any acquired semaphores before exiting. */ -s32 -e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data) +static s32 +__e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data, + bool locked) { s32 ret_val; u16 page = BM_PHY_REG_PAGE(offset); u16 reg = BM_PHY_REG_NUM(offset); bool in_slow_mode = false; + struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; DEBUGFUNC("e1000_write_phy_reg_hv"); + if (!locked) { + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return (ret_val); + } + /* Workaround failure in MDIO access while cable is disconnected */ if ((hw->phy.type == e1000_phy_82577) && !(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) { @@ -2979,11 +3150,9 @@ e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data) goto out; } - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - - hw->phy.addr = e1000_get_phy_addr_for_hv_page(page); + /* The LCD Config workaround provides the phy address to use */ + if (dev_spec->nvm_lcd_config_enabled == false) + hw->phy.addr = e1000_get_phy_addr_for_hv_page(page); if (page == HV_INTC_FC_PAGE_START) page = 0; @@ -2998,46 +3167,68 @@ e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data) ((MAX_PHY_REG_ADDRESS & reg) == 0) && (data & (1 << 11))) { u16 data2 = 0x7EFF; - hw->phy.ops.release(hw); ret_val = e1000_access_phy_debug_regs_hv(hw, (1 << 6) | 0x3, &data2, false); if (ret_val) goto out; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; } if (reg > MAX_PHY_MULTI_PAGE_REG) { u32 phy_addr = hw->phy.addr; + hw->phy.addr = 1; /* Page is shifted left, PHY expects (page x 32) */ ret_val = e1000_write_phy_reg_mdic(hw, - IGP01E1000_PHY_PAGE_SELECT, - (page << IGP_PAGE_SHIFT)); + IGP01E1000_PHY_PAGE_SELECT, (page << IGP_PAGE_SHIFT)); hw->phy.addr = phy_addr; - - if (ret_val) { - hw->phy.ops.release(hw); - goto out; - } } ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg, data); - hw->phy.ops.release(hw); out: /* Revert to MDIO fast mode, if applicable */ if ((hw->phy.type == e1000_phy_82577) && in_slow_mode) ret_val = e1000_set_mdio_slow_mode_hv(hw, false); + if (!locked) + hw->phy.ops.release(hw); + return (ret_val); } /* + * e1000_write_phy_reg_hv - Write HV PHY register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquires semaphore then writes the data to PHY register at the offset. + * Release the acquired semaphores before exiting. + */ +s32 +e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data) +{ + return (__e1000_write_phy_reg_hv(hw, offset, data, false)); +} + +/* + * e1000_write_phy_reg_hv_locked - Write HV PHY register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Writes the data to PHY register at the offset. Assumes semaphore + * already acquired. + */ +s32 +e1000_write_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 data) +{ + return (__e1000_write_phy_reg_hv(hw, offset, data, true)); +} + +/* * e1000_get_phy_addr_for_hv_page - Get PHY adrress based on page * @page: page to be accessed */ @@ -3059,10 +3250,9 @@ e1000_get_phy_addr_for_hv_page(u32 page) * @data: pointer to the data to be read or written * @read: determines if operation is read or written * - * Acquires semaphore, if necessary, then reads the PHY register at offset - * and storing the retreived information in data. Release any acquired - * semaphores before exiting. Note that the procedure to read these regs - * uses the address port and data port to read/write. + * Reads the PHY register at offset and stores the retreived information + * in data. Assumes semaphore already acquired. Note that the procedure + * to read these regs uses the address port and data port to read/write. */ static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset, @@ -3071,7 +3261,6 @@ e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset, s32 ret_val; u32 addr_reg = 0; u32 data_reg = 0; - u8 phy_acquired = 1; DEBUGFUNC("e1000_access_phy_debug_regs_hv"); @@ -3080,13 +3269,6 @@ e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset, I82578_ADDR_REG : I82577_ADDR_REG; data_reg = addr_reg + 1; - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) { - DEBUGOUT("Could not acquire PHY\n"); - phy_acquired = 0; - goto out; - } - /* All operations in this function are phy address 2 */ hw->phy.addr = 2; @@ -3109,8 +3291,6 @@ e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset, } out: - if (phy_acquired == 1) - hw->phy.ops.release(hw); return (ret_val); } diff --git a/usr/src/uts/common/io/e1000g/e1000_phy.h b/usr/src/uts/common/io/e1000g/e1000_phy.h index 48423fa88b..e052cabeb1 100644 --- a/usr/src/uts/common/io/e1000g/e1000_phy.h +++ b/usr/src/uts/common/io/e1000g/e1000_phy.h @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.70 v3-1-3_2009-8-20 + * IntelVersion: 1.74 v3-1-10-1_2009-9-18_Release14-6 */ #ifndef _E1000_PHY_H_ #define _E1000_PHY_H_ @@ -61,13 +61,17 @@ s32 e1000_phy_hw_reset_generic(struct e1000_hw *hw); s32 e1000_phy_reset_dsp_generic(struct e1000_hw *hw); s32 e1000_phy_setup_autoneg(struct e1000_hw *hw); s32 e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data); +s32 e1000_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data); s32 e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data); +s32 e1000_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data); s32 e1000_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data); s32 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active); s32 e1000_setup_copper_link_generic(struct e1000_hw *hw); s32 e1000_wait_autoneg_generic(struct e1000_hw *hw); s32 e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data); +s32 e1000_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data); s32 e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data); +s32 e1000_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data); s32 e1000_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data); s32 e1000_phy_reset_dsp(struct e1000_hw *hw); s32 e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, @@ -84,7 +88,9 @@ void e1000_power_down_phy_copper(struct e1000_hw *hw); s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data); s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data); s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data); +s32 e1000_read_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 *data); s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data); +s32 e1000_write_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 data); s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow); s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw); s32 e1000_copper_link_setup_82577(struct e1000_hw *hw); @@ -173,6 +179,13 @@ s32 e1000_get_cable_length_82577(struct e1000_hw *hw); #define BM_CS_STATUS_SPEED_MASK 0xC000 #define BM_CS_STATUS_SPEED_1000 0x8000 +/* 82577 Mobile Phy Status Register */ +#define HV_M_STATUS 26 +#define HV_M_STATUS_AUTONEG_COMPLETE 0x1000 +#define HV_M_STATUS_SPEED_MASK 0x0300 +#define HV_M_STATUS_SPEED_1000 0x0200 +#define HV_M_STATUS_LINK_UP 0x0040 + #define IGP01E1000_PHY_PCS_INIT_REG 0x00B4 #define IGP01E1000_PHY_POLARITY_MASK 0x0078 @@ -219,8 +232,7 @@ s32 e1000_get_cable_length_82577(struct e1000_hw *hw); #define E1000_KMRNCTRLSTA_INBAND_PARAM 0x9 /* Kumeran InBand Parameters */ #define E1000_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Nearend Loopback mode */ #define E1000_KMRNCTRLSTA_K1_CONFIG 0x7 -#define E1000_KMRNCTRLSTA_K1_ENABLE 0x140E -#define E1000_KMRNCTRLSTA_K1_DISABLE 0x1400 +#define E1000_KMRNCTRLSTA_K1_ENABLE 0x0002 #define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10 #define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Control */ diff --git a/usr/src/uts/common/io/e1000g/e1000_regs.h b/usr/src/uts/common/io/e1000g/e1000_regs.h index af6529c281..c7a350a619 100644 --- a/usr/src/uts/common/io/e1000g/e1000_regs.h +++ b/usr/src/uts/common/io/e1000g/e1000_regs.h @@ -24,7 +24,7 @@ */ /* - * IntelVersion: 1.76 v3-1-3_2009-8-20 + * IntelVersion: 1.76 v3-1-10-1_2009-9-18_Release14-6 */ #ifndef _E1000_REGS_H_ #define _E1000_REGS_H_ diff --git a/usr/src/uts/common/io/e1000g/e1000g_main.c b/usr/src/uts/common/io/e1000g/e1000g_main.c index 5dbce69bd2..01dad50d1f 100644 --- a/usr/src/uts/common/io/e1000g/e1000g_main.c +++ b/usr/src/uts/common/io/e1000g/e1000g_main.c @@ -46,7 +46,7 @@ static char ident[] = "Intel PRO/1000 Ethernet"; static char e1000g_string[] = "Intel(R) PRO/1000 Network Connection"; -static char e1000g_version[] = "Driver Ver. 5.3.16"; +static char e1000g_version[] = "Driver Ver. 5.3.17"; /* * Proto types for DDI entry points |