diff options
-rw-r--r-- | drivers/net/e1000e/82571.c | 26 | ||||
-rw-r--r-- | drivers/net/e1000e/e1000.h | 2 | ||||
-rw-r--r-- | drivers/net/e1000e/es2lan.c | 21 | ||||
-rw-r--r-- | drivers/net/e1000e/hw.h | 2 | ||||
-rw-r--r-- | drivers/net/e1000e/ich8lan.c | 23 | ||||
-rw-r--r-- | drivers/net/e1000e/netdev.c | 50 | ||||
-rw-r--r-- | drivers/net/e1000e/phy.c | 37 |
7 files changed, 122 insertions, 39 deletions
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index 8ea3ed7e536..26ea5d57a35 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -69,6 +69,7 @@ static void e1000_clear_vfta_82571(struct e1000_hw *hw); static bool e1000_check_mng_mode_82574(struct e1000_hw *hw); static s32 e1000_led_on_82574(struct e1000_hw *hw); static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw); +static void e1000_power_down_phy_copper_82571(struct e1000_hw *hw); /** * e1000_init_phy_params_82571 - Init PHY func ptrs. @@ -88,6 +89,9 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw) phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; phy->reset_delay_us = 100; + phy->ops.power_up = e1000_power_up_phy_copper; + phy->ops.power_down = e1000_power_down_phy_copper_82571; + switch (hw->mac.type) { case e1000_82571: case e1000_82572: @@ -1601,6 +1605,28 @@ static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw) } /** + * e1000_power_down_phy_copper_82571 - Remove link during PHY power down + * @hw: pointer to the HW structure + * + * In the case of a PHY power down to save power, or to turn off link during a + * driver unload, or wake on lan is not enabled, remove the link. + **/ +static void e1000_power_down_phy_copper_82571(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + struct e1000_mac_info *mac = &hw->mac; + + if (!(phy->ops.check_reset_block)) + return; + + /* If the management interface is not enabled, then power down */ + if (!(mac->ops.check_mng_mode(hw) || phy->ops.check_reset_block(hw))) + e1000_power_down_phy_copper(hw); + + return; +} + +/** * e1000_clear_hw_cntrs_82571 - Clear device specific hardware counters * @hw: pointer to the HW structure * diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index 4c08752b824..c4e861fb386 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -568,6 +568,8 @@ extern s32 e1000e_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, extern s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, u32 usec_interval, bool *success); extern s32 e1000e_phy_reset_dsp(struct e1000_hw *hw); +extern void e1000_power_up_phy_copper(struct e1000_hw *hw); +extern void e1000_power_down_phy_copper(struct e1000_hw *hw); extern s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data); extern s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data); extern s32 e1000e_check_downshift(struct e1000_hw *hw); diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c index 3f435c16608..c7bc657b5da 100644 --- a/drivers/net/e1000e/es2lan.c +++ b/drivers/net/e1000e/es2lan.c @@ -114,6 +114,7 @@ static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, u16 *data); static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, u16 data); +static void e1000_power_down_phy_copper_80003es2lan(struct e1000_hw *hw); /** * e1000_init_phy_params_80003es2lan - Init ESB2 PHY func ptrs. @@ -127,6 +128,9 @@ static s32 e1000_init_phy_params_80003es2lan(struct e1000_hw *hw) if (hw->phy.media_type != e1000_media_type_copper) { phy->type = e1000_phy_none; return 0; + } else { + phy->ops.power_up = e1000_power_up_phy_copper; + phy->ops.power_down = e1000_power_down_phy_copper_80003es2lan; } phy->addr = 1; @@ -1303,6 +1307,23 @@ static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, } /** + * e1000_power_down_phy_copper_80003es2lan - Remove link during PHY power down + * @hw: pointer to the HW structure + * + * In the case of a PHY power down to save power, or to turn off link during a + * driver unload, or wake on lan is not enabled, remove the link. + **/ +static void e1000_power_down_phy_copper_80003es2lan(struct e1000_hw *hw) +{ + /* If the management interface is not enabled, then power down */ + if (!(hw->mac.ops.check_mng_mode(hw) || + hw->phy.ops.check_reset_block(hw))) + e1000_power_down_phy_copper(hw); + + return; +} + +/** * e1000_clear_hw_cntrs_80003es2lan - Clear device specific hardware counters * @hw: pointer to the HW structure * diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index 6c3d55fc775..e0addf3eea8 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h @@ -774,6 +774,8 @@ struct e1000_phy_operations { 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 *); }; /* Function pointers for the NVM. */ diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index 7530fc5d81c..9c389559892 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -217,6 +217,7 @@ 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_set_lplu_state_pchlan(struct e1000_hw *hw, bool active); +static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw); static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw); static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link); @@ -266,6 +267,8 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) 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; phy->id = e1000_phy_unknown; @@ -299,6 +302,9 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) phy->addr = 1; phy->reset_delay_us = 100; + phy->ops.power_up = e1000_power_up_phy_copper; + phy->ops.power_down = e1000_power_down_phy_copper_ich8lan; + /* * We may need to do this twice - once for IGP and if that fails, * we'll set BM func pointers and try again @@ -3392,6 +3398,23 @@ static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw) } /** + * e1000_power_down_phy_copper_ich8lan - Remove link during PHY power down + * @hw: pointer to the HW structure + * + * In the case of a PHY power down to save power, or to turn off link during a + * driver unload, or wake on lan is not enabled, remove the link. + **/ +static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw) +{ + /* If the management interface is not enabled, then power down */ + if (!(hw->mac.ops.check_mng_mode(hw) || + hw->phy.ops.check_reset_block(hw))) + e1000_power_down_phy_copper(hw); + + return; +} + +/** * e1000_clear_hw_cntrs_ich8lan - Clear statistical counters * @hw: pointer to the HW structure * diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 2381cb76f17..ab4db5266f1 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -2641,18 +2641,8 @@ static void e1000_configure(struct e1000_adapter *adapter) **/ void e1000e_power_up_phy(struct e1000_adapter *adapter) { - u16 mii_reg = 0; - - /* Just clear the power down bit to wake the phy back up */ - if (adapter->hw.phy.media_type == e1000_media_type_copper) { - /* - * According to the manual, the phy will retain its - * settings across a power-down/up cycle - */ - e1e_rphy(&adapter->hw, PHY_CONTROL, &mii_reg); - mii_reg &= ~MII_CR_POWER_DOWN; - e1e_wphy(&adapter->hw, PHY_CONTROL, mii_reg); - } + if (adapter->hw.phy.ops.power_up) + adapter->hw.phy.ops.power_up(&adapter->hw); adapter->hw.mac.ops.setup_link(&adapter->hw); } @@ -2660,35 +2650,17 @@ void e1000e_power_up_phy(struct e1000_adapter *adapter) /** * e1000_power_down_phy - Power down the PHY * - * Power down the PHY so no link is implied when interface is down - * The PHY cannot be powered down is management or WoL is active + * Power down the PHY so no link is implied when interface is down. + * The PHY cannot be powered down if management or WoL is active. */ static void e1000_power_down_phy(struct e1000_adapter *adapter) { - struct e1000_hw *hw = &adapter->hw; - u16 mii_reg; - /* WoL is enabled */ if (adapter->wol) return; - /* non-copper PHY? */ - if (adapter->hw.phy.media_type != e1000_media_type_copper) - return; - - /* reset is blocked because of a SoL/IDER session */ - if (e1000e_check_mng_mode(hw) || e1000_check_reset_block(hw)) - return; - - /* manageability (AMT) is enabled */ - if (er32(MANC) & E1000_MANC_SMBUS_EN) - return; - - /* power down the PHY */ - e1e_rphy(hw, PHY_CONTROL, &mii_reg); - mii_reg |= MII_CR_POWER_DOWN; - e1e_wphy(hw, PHY_CONTROL, mii_reg); - mdelay(1); + if (adapter->hw.phy.ops.power_down) + adapter->hw.phy.ops.power_down(&adapter->hw); } /** @@ -5294,17 +5266,17 @@ static void __devexit e1000_remove(struct pci_dev *pdev) cancel_work_sync(&adapter->print_hang_task); flush_scheduled_work(); + if (!(netdev->flags & IFF_UP)) + e1000_power_down_phy(adapter); + + unregister_netdev(netdev); + /* * Release control of h/w to f/w. If f/w is AMT enabled, this * would have already happened in close and is redundant. */ e1000_release_hw_control(adapter); - unregister_netdev(netdev); - - if (!e1000_check_reset_block(&adapter->hw)) - e1000_phy_hw_reset(&adapter->hw); - e1000e_reset_interrupt_capability(adapter); kfree(adapter->tx_ring); kfree(adapter->rx_ring); diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c index 9ce499734dc..140b23b320f 100644 --- a/drivers/net/e1000e/phy.c +++ b/drivers/net/e1000e/phy.c @@ -2534,6 +2534,43 @@ out: } /** + * e1000_power_up_phy_copper - Restore copper link in case of PHY power down + * @hw: pointer to the HW structure + * + * In the case of a PHY power down to save power, or to turn off link during a + * driver unload, or wake on lan is not enabled, restore the link to previous + * settings. + **/ +void e1000_power_up_phy_copper(struct e1000_hw *hw) +{ + u16 mii_reg = 0; + + /* The PHY will retain its settings across a power down/up cycle */ + e1e_rphy(hw, PHY_CONTROL, &mii_reg); + mii_reg &= ~MII_CR_POWER_DOWN; + e1e_wphy(hw, PHY_CONTROL, mii_reg); +} + +/** + * e1000_power_down_phy_copper - Restore copper link in case of PHY power down + * @hw: pointer to the HW structure + * + * In the case of a PHY power down to save power, or to turn off link during a + * driver unload, or wake on lan is not enabled, restore the link to previous + * settings. + **/ +void e1000_power_down_phy_copper(struct e1000_hw *hw) +{ + u16 mii_reg = 0; + + /* The PHY will retain its settings across a power down/up cycle */ + e1e_rphy(hw, PHY_CONTROL, &mii_reg); + mii_reg |= MII_CR_POWER_DOWN; + e1e_wphy(hw, PHY_CONTROL, mii_reg); + msleep(1); +} + +/** * e1000e_commit_phy - Soft PHY reset * @hw: pointer to the HW structure * |