igb: Power down link when interface is down
authorNick Nunley <nicholasx.d.nunley@intel.com>
Wed, 17 Feb 2010 01:01:59 +0000 (01:01 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 17 Feb 2010 21:21:33 +0000 (13:21 -0800)
This changes the behavior of the driver to power down the link
when the associated interface is down, unless management is enabled.

Signed-off-by: Nicholas Nunley <nicholasx.d.nunley@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/igb/e1000_82575.c
drivers/net/igb/e1000_82575.h
drivers/net/igb/e1000_defines.h
drivers/net/igb/e1000_phy.c
drivers/net/igb/e1000_phy.h
drivers/net/igb/igb.h
drivers/net/igb/igb_ethtool.c
drivers/net/igb/igb_main.c

index 59817bcc7169d3b277fc779d037eb7713520d821..9d7fa2fb85ea0cb9de0b7582da337d03d7b9c917 100644 (file)
@@ -726,6 +726,34 @@ static s32 igb_check_for_link_82575(struct e1000_hw *hw)
        return ret_val;
 }
 
+/**
+ *  igb_power_up_serdes_link_82575 - Power up the serdes link after shutdown
+ *  @hw: pointer to the HW structure
+ **/
+void igb_power_up_serdes_link_82575(struct e1000_hw *hw)
+{
+       u32 reg;
+
+
+       if ((hw->phy.media_type != e1000_media_type_internal_serdes) &&
+           !igb_sgmii_active_82575(hw))
+               return;
+
+       /* Enable PCS to turn on link */
+       reg = rd32(E1000_PCS_CFG0);
+       reg |= E1000_PCS_CFG_PCS_EN;
+       wr32(E1000_PCS_CFG0, reg);
+
+       /* Power up the laser */
+       reg = rd32(E1000_CTRL_EXT);
+       reg &= ~E1000_CTRL_EXT_SDP3_DATA;
+       wr32(E1000_CTRL_EXT, reg);
+
+       /* flush the write to verify completion */
+       wrfl();
+       msleep(1);
+}
+
 /**
  *  igb_get_pcs_speed_and_duplex_82575 - Retrieve current speed/duplex
  *  @hw: pointer to the HW structure
@@ -1165,6 +1193,22 @@ out:
        return ret_val;
 }
 
+/**
+ * igb_power_down_phy_copper_82575 - 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.
+ **/
+void igb_power_down_phy_copper_82575(struct e1000_hw *hw)
+{
+       /* If the management interface is not enabled, then power down */
+       if (!(igb_enable_mng_pass_thru(hw) || igb_check_reset_block(hw)))
+               igb_power_down_phy_copper(hw);
+
+       return;
+}
+
 /**
  *  igb_clear_hw_cntrs_82575 - Clear device specific hardware counters
  *  @hw: pointer to the HW structure
index bb53083ec61f7929072f0be6c08837d8b9e70d62..fbe1c99c193c09434a72ee35a84d10f09731bd24 100644 (file)
@@ -29,6 +29,8 @@
 #define _E1000_82575_H_
 
 extern void igb_shutdown_serdes_link_82575(struct e1000_hw *hw);
+extern void igb_power_up_serdes_link_82575(struct e1000_hw *hw);
+extern void igb_power_down_phy_copper_82575(struct e1000_hw *hw);
 extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw);
 
 #define ID_LED_DEFAULT_82575_SERDES ((ID_LED_DEF1_DEF2 << 12) | \
index 6e036ae3138ff25b96b23c54494bc4154efd04fc..c0171507076410c57e082cbe48dab3409006fbc8 100644 (file)
 /* PHY Control Register */
 #define MII_CR_FULL_DUPLEX      0x0100  /* FDX =1, half duplex =0 */
 #define MII_CR_RESTART_AUTO_NEG 0x0200  /* Restart auto negotiation */
+#define MII_CR_POWER_DOWN       0x0800  /* Power down */
 #define MII_CR_AUTO_NEG_EN      0x1000  /* Auto Neg Enable */
 #define MII_CR_LOOPBACK         0x4000  /* 0 = normal, 1 = loopback */
 #define MII_CR_RESET            0x8000  /* 0 = normal, 1 = PHY reset */
index 3670a66401b87923d5ff3dc82cc67f1701cc4986..cf1f323009233aed82c601b0d73454bdfe7200e1 100644 (file)
@@ -1930,6 +1930,41 @@ s32 igb_phy_init_script_igp3(struct e1000_hw *hw)
        return 0;
 }
 
+/**
+ * igb_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, restore the link to previous settings.
+ **/
+void igb_power_up_phy_copper(struct e1000_hw *hw)
+{
+       u16 mii_reg = 0;
+
+       /* The PHY will retain its settings across a power down/up cycle */
+       hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
+       mii_reg &= ~MII_CR_POWER_DOWN;
+       hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
+}
+
+/**
+ * igb_power_down_phy_copper - Power down copper PHY
+ * @hw: pointer to the HW structure
+ *
+ * Power down PHY to save power when interface is down and wake on lan
+ * is not enabled.
+ **/
+void igb_power_down_phy_copper(struct e1000_hw *hw)
+{
+       u16 mii_reg = 0;
+
+       /* The PHY will retain its settings across a power down/up cycle */
+       hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
+       mii_reg |= MII_CR_POWER_DOWN;
+       hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
+       msleep(1);
+}
+
 /**
  *  igb_check_polarity_82580 - Checks the polarity.
  *  @hw: pointer to the HW structure
index 555eb54bb6edefdb0cf99cc068d0298bc0bf410e..565a6dbb3714418d7776c8a4ceb2095f27e793db 100644 (file)
@@ -60,6 +60,8 @@ s32  igb_setup_copper_link(struct e1000_hw *hw);
 s32  igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
 s32  igb_phy_has_link(struct e1000_hw *hw, u32 iterations,
                                u32 usec_interval, bool *success);
+void igb_power_up_phy_copper(struct e1000_hw *hw);
+void igb_power_down_phy_copper(struct e1000_hw *hw);
 s32  igb_phy_init_script_igp3(struct e1000_hw *hw);
 s32  igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
 s32  igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
index 452a4dee87f8d40e0fbb0ce68947d438d1e91418..0e0800dc801d8553e3b6a159b3b2dc2d84155246 100644 (file)
@@ -358,6 +358,7 @@ extern void igb_alloc_rx_buffers_adv(struct igb_ring *, int);
 extern void igb_update_stats(struct igb_adapter *);
 extern bool igb_has_link(struct igb_adapter *adapter);
 extern void igb_set_ethtool_ops(struct net_device *);
+extern void igb_power_up_link(struct igb_adapter *);
 
 static inline s32 igb_reset_phy(struct e1000_hw *hw)
 {
index 4eea03b428c486534415216aab16675e3b2d3a48..485288303f327e3202f4e7f7934beacb2e4d507a 100644 (file)
@@ -1722,6 +1722,9 @@ static void igb_diag_test(struct net_device *netdev,
 
                dev_info(&adapter->pdev->dev, "offline testing starting\n");
 
+               /* power up link for link test */
+               igb_power_up_link(adapter);
+
                /* Link test performed before hardware reset so autoneg doesn't
                 * interfere with test result */
                if (igb_link_test(adapter, &data[4]))
@@ -1745,6 +1748,8 @@ static void igb_diag_test(struct net_device *netdev,
                        eth_test->flags |= ETH_TEST_FL_FAILED;
 
                igb_reset(adapter);
+               /* power up link for loopback test */
+               igb_power_up_link(adapter);
                if (igb_loopback_test(adapter, &data[3]))
                        eth_test->flags |= ETH_TEST_FL_FAILED;
 
@@ -1763,9 +1768,14 @@ static void igb_diag_test(struct net_device *netdev,
                        dev_open(netdev);
        } else {
                dev_info(&adapter->pdev->dev, "online testing starting\n");
-               /* Online tests */
-               if (igb_link_test(adapter, &data[4]))
-                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+               /* PHY is powered down when interface is down */
+               if (!netif_carrier_ok(netdev)) {
+                       data[4] = 0;
+               } else {
+                       if (igb_link_test(adapter, &data[4]))
+                               eth_test->flags |= ETH_TEST_FL_FAILED;
+               }
 
                /* Online tests aren't run; pass by default */
                data[0] = 0;
index e40319e2ec251ed5e494f02e8beac32b6b32bea2..0427e7c10295221bcdc4f827f569cc77a6ea56a9 100644 (file)
@@ -1114,6 +1114,29 @@ static void igb_configure(struct igb_adapter *adapter)
        adapter->tx_queue_len = netdev->tx_queue_len;
 }
 
+/**
+ * igb_power_up_link - Power up the phy/serdes link
+ * @adapter: address of board private structure
+ **/
+void igb_power_up_link(struct igb_adapter *adapter)
+{
+       if (adapter->hw.phy.media_type == e1000_media_type_copper)
+               igb_power_up_phy_copper(&adapter->hw);
+       else
+               igb_power_up_serdes_link_82575(&adapter->hw);
+}
+
+/**
+ * igb_power_down_link - Power down the phy/serdes link
+ * @adapter: address of board private structure
+ */
+static void igb_power_down_link(struct igb_adapter *adapter)
+{
+       if (adapter->hw.phy.media_type == e1000_media_type_copper)
+               igb_power_down_phy_copper_82575(&adapter->hw);
+       else
+               igb_shutdown_serdes_link_82575(&adapter->hw);
+}
 
 /**
  * igb_up - Open the interface and prepare it to handle traffic
@@ -1335,6 +1358,9 @@ void igb_reset(struct igb_adapter *adapter)
                wr32(E1000_PCIEMISC,
                                reg & ~E1000_PCIEMISC_LX_DECISION);
        }
+       if (!netif_running(adapter->netdev))
+               igb_power_down_link(adapter);
+
        igb_update_mng_vlan(adapter);
 
        /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */
@@ -1717,9 +1743,6 @@ static void __devexit igb_remove(struct pci_dev *pdev)
 
        unregister_netdev(netdev);
 
-       if (!igb_check_reset_block(hw))
-               igb_reset_phy(hw);
-
        igb_clear_interrupt_scheme(adapter);
 
 #ifdef CONFIG_PCI_IOV
@@ -1995,7 +2018,7 @@ static int igb_open(struct net_device *netdev)
        if (err)
                goto err_setup_rx;
 
-       /* e1000_power_up_phy(adapter); */
+       igb_power_up_link(adapter);
 
        /* before we allocate an interrupt, we must be ready to handle it.
         * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt
@@ -2037,7 +2060,7 @@ static int igb_open(struct net_device *netdev)
 
 err_req_irq:
        igb_release_hw_control(adapter);
-       /* e1000_power_down_phy(adapter); */
+       igb_power_down_link(adapter);
        igb_free_all_rx_resources(adapter);
 err_setup_rx:
        igb_free_all_tx_resources(adapter);
@@ -5820,7 +5843,9 @@ static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake)
 
        *enable_wake = wufc || adapter->en_mng_pt;
        if (!*enable_wake)
-               igb_shutdown_serdes_link_82575(hw);
+               igb_power_down_link(adapter);
+       else
+               igb_power_up_link(adapter);
 
        /* Release control of h/w to f/w.  If f/w is AMT enabled, this
         * would have already happened in close and is redundant. */
@@ -5877,8 +5902,6 @@ static int igb_resume(struct pci_dev *pdev)
                return -ENOMEM;
        }
 
-       /* e1000_power_up_phy(adapter); */
-
        igb_reset(adapter);
 
        /* let the f/w know that the h/w is now under the control of the