e1000e: provide family-specific PHY power up/down operations
authorBruce Allan <bruce.w.allan@intel.com>
Tue, 1 Dec 2009 15:47:22 +0000 (15:47 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 2 Dec 2009 08:35:52 +0000 (00:35 -0800)
The different families (80003es2lan, 8257x, ICHx/PCH) supported by the
driver each have their own conditions when the PHY can be powered down.
This patch rewrites the PHY power up/down code to fit with the family-
specific style used in the driver.  All pre-existing calls to power up or
down the PHY remain untouched.  A new call to power down the PHY when
removing the driver when the interface is down replaces the current call
to reset the PHY in order to reduce power consumption.

Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/e1000e/82571.c
drivers/net/e1000e/e1000.h
drivers/net/e1000e/es2lan.c
drivers/net/e1000e/hw.h
drivers/net/e1000e/ich8lan.c
drivers/net/e1000e/netdev.c
drivers/net/e1000e/phy.c

index 8ea3ed7e5364ff1f68b8164c691573daf4496314..26ea5d57a3545d85bdeca9ff3ff65d43ece47f2d 100644 (file)
@@ -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:
@@ -1600,6 +1604,28 @@ static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw)
        return 0;
 }
 
+/**
+ * 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
index 4c08752b824d8bd7356fe1a6e0ee319a1bd05555..c4e861fb3862002058d036d2ebb754cd91ec0ee9 100644 (file)
@@ -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);
index 3f435c16608dd3ddcf05f0b589b4a529a4efe1b4..c7bc657b5da21d04bb7c2f80042bf7f943432f3b 100644 (file)
@@ -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;
@@ -1302,6 +1306,23 @@ static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
        return ret_val;
 }
 
+/**
+ * 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
index 6c3d55fc77531126a9611f449dd70d4b0d16f0fb..e0addf3eea8af35f735582895ad8360454f1b50c 100644 (file)
@@ -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. */
index 7530fc5d81c3d334a6ff5ca5772ad25bb324081d..9c3895598923e7a64b8d5ddcdfc913f9e0f1de53 100644 (file)
@@ -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
@@ -3391,6 +3397,23 @@ static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
        return 0;
 }
 
+/**
+ * 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
index 2381cb76f17c63fe03d419122299561174c838d8..ab4db5266f14afa85a72177b77304f3b9f301d33 100644 (file)
@@ -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);
index 9ce499734dca31ad44cddbbab19e3975d0f6c1ed..140b23b320fdec061a4b84bd26b74887a10a3853 100644 (file)
@@ -2533,6 +2533,43 @@ out:
        return ret_val;
 }
 
+/**
+ * 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