diff options
author | Nick Nunley <nicholasx.d.nunley@intel.com> | 2010-02-16 20:01:59 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-17 16:21:33 -0500 |
commit | 88a268c1a11a2e94b7c55a8cfe97892d845887c8 (patch) | |
tree | b748dcd6491b17376c984145c2dca02165d92547 /drivers/net | |
parent | 53c992fa8497286f24f279ebec5a8c7a58d4e68c (diff) |
igb: Power down link when interface is down
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>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/igb/e1000_82575.c | 44 | ||||
-rw-r--r-- | drivers/net/igb/e1000_82575.h | 2 | ||||
-rw-r--r-- | drivers/net/igb/e1000_defines.h | 1 | ||||
-rw-r--r-- | drivers/net/igb/e1000_phy.c | 35 | ||||
-rw-r--r-- | drivers/net/igb/e1000_phy.h | 2 | ||||
-rw-r--r-- | drivers/net/igb/igb.h | 1 | ||||
-rw-r--r-- | drivers/net/igb/igb_ethtool.c | 16 | ||||
-rw-r--r-- | drivers/net/igb/igb_main.c | 39 |
8 files changed, 129 insertions, 11 deletions
diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index 59817bcc7169..9d7fa2fb85ea 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c | |||
@@ -727,6 +727,34 @@ static s32 igb_check_for_link_82575(struct e1000_hw *hw) | |||
727 | } | 727 | } |
728 | 728 | ||
729 | /** | 729 | /** |
730 | * igb_power_up_serdes_link_82575 - Power up the serdes link after shutdown | ||
731 | * @hw: pointer to the HW structure | ||
732 | **/ | ||
733 | void igb_power_up_serdes_link_82575(struct e1000_hw *hw) | ||
734 | { | ||
735 | u32 reg; | ||
736 | |||
737 | |||
738 | if ((hw->phy.media_type != e1000_media_type_internal_serdes) && | ||
739 | !igb_sgmii_active_82575(hw)) | ||
740 | return; | ||
741 | |||
742 | /* Enable PCS to turn on link */ | ||
743 | reg = rd32(E1000_PCS_CFG0); | ||
744 | reg |= E1000_PCS_CFG_PCS_EN; | ||
745 | wr32(E1000_PCS_CFG0, reg); | ||
746 | |||
747 | /* Power up the laser */ | ||
748 | reg = rd32(E1000_CTRL_EXT); | ||
749 | reg &= ~E1000_CTRL_EXT_SDP3_DATA; | ||
750 | wr32(E1000_CTRL_EXT, reg); | ||
751 | |||
752 | /* flush the write to verify completion */ | ||
753 | wrfl(); | ||
754 | msleep(1); | ||
755 | } | ||
756 | |||
757 | /** | ||
730 | * igb_get_pcs_speed_and_duplex_82575 - Retrieve current speed/duplex | 758 | * igb_get_pcs_speed_and_duplex_82575 - Retrieve current speed/duplex |
731 | * @hw: pointer to the HW structure | 759 | * @hw: pointer to the HW structure |
732 | * @speed: stores the current speed | 760 | * @speed: stores the current speed |
@@ -1166,6 +1194,22 @@ out: | |||
1166 | } | 1194 | } |
1167 | 1195 | ||
1168 | /** | 1196 | /** |
1197 | * igb_power_down_phy_copper_82575 - Remove link during PHY power down | ||
1198 | * @hw: pointer to the HW structure | ||
1199 | * | ||
1200 | * In the case of a PHY power down to save power, or to turn off link during a | ||
1201 | * driver unload, or wake on lan is not enabled, remove the link. | ||
1202 | **/ | ||
1203 | void igb_power_down_phy_copper_82575(struct e1000_hw *hw) | ||
1204 | { | ||
1205 | /* If the management interface is not enabled, then power down */ | ||
1206 | if (!(igb_enable_mng_pass_thru(hw) || igb_check_reset_block(hw))) | ||
1207 | igb_power_down_phy_copper(hw); | ||
1208 | |||
1209 | return; | ||
1210 | } | ||
1211 | |||
1212 | /** | ||
1169 | * igb_clear_hw_cntrs_82575 - Clear device specific hardware counters | 1213 | * igb_clear_hw_cntrs_82575 - Clear device specific hardware counters |
1170 | * @hw: pointer to the HW structure | 1214 | * @hw: pointer to the HW structure |
1171 | * | 1215 | * |
diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h index bb53083ec61f..fbe1c99c193c 100644 --- a/drivers/net/igb/e1000_82575.h +++ b/drivers/net/igb/e1000_82575.h | |||
@@ -29,6 +29,8 @@ | |||
29 | #define _E1000_82575_H_ | 29 | #define _E1000_82575_H_ |
30 | 30 | ||
31 | extern void igb_shutdown_serdes_link_82575(struct e1000_hw *hw); | 31 | extern void igb_shutdown_serdes_link_82575(struct e1000_hw *hw); |
32 | extern void igb_power_up_serdes_link_82575(struct e1000_hw *hw); | ||
33 | extern void igb_power_down_phy_copper_82575(struct e1000_hw *hw); | ||
32 | extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw); | 34 | extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw); |
33 | 35 | ||
34 | #define ID_LED_DEFAULT_82575_SERDES ((ID_LED_DEF1_DEF2 << 12) | \ | 36 | #define ID_LED_DEFAULT_82575_SERDES ((ID_LED_DEF1_DEF2 << 12) | \ |
diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h index 6e036ae3138f..c01715070764 100644 --- a/drivers/net/igb/e1000_defines.h +++ b/drivers/net/igb/e1000_defines.h | |||
@@ -481,6 +481,7 @@ | |||
481 | /* PHY Control Register */ | 481 | /* PHY Control Register */ |
482 | #define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ | 482 | #define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ |
483 | #define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ | 483 | #define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ |
484 | #define MII_CR_POWER_DOWN 0x0800 /* Power down */ | ||
484 | #define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ | 485 | #define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ |
485 | #define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ | 486 | #define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ |
486 | #define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ | 487 | #define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ |
diff --git a/drivers/net/igb/e1000_phy.c b/drivers/net/igb/e1000_phy.c index 3670a66401b8..cf1f32300923 100644 --- a/drivers/net/igb/e1000_phy.c +++ b/drivers/net/igb/e1000_phy.c | |||
@@ -1931,6 +1931,41 @@ s32 igb_phy_init_script_igp3(struct e1000_hw *hw) | |||
1931 | } | 1931 | } |
1932 | 1932 | ||
1933 | /** | 1933 | /** |
1934 | * igb_power_up_phy_copper - Restore copper link in case of PHY power down | ||
1935 | * @hw: pointer to the HW structure | ||
1936 | * | ||
1937 | * In the case of a PHY power down to save power, or to turn off link during a | ||
1938 | * driver unload, restore the link to previous settings. | ||
1939 | **/ | ||
1940 | void igb_power_up_phy_copper(struct e1000_hw *hw) | ||
1941 | { | ||
1942 | u16 mii_reg = 0; | ||
1943 | |||
1944 | /* The PHY will retain its settings across a power down/up cycle */ | ||
1945 | hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg); | ||
1946 | mii_reg &= ~MII_CR_POWER_DOWN; | ||
1947 | hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg); | ||
1948 | } | ||
1949 | |||
1950 | /** | ||
1951 | * igb_power_down_phy_copper - Power down copper PHY | ||
1952 | * @hw: pointer to the HW structure | ||
1953 | * | ||
1954 | * Power down PHY to save power when interface is down and wake on lan | ||
1955 | * is not enabled. | ||
1956 | **/ | ||
1957 | void igb_power_down_phy_copper(struct e1000_hw *hw) | ||
1958 | { | ||
1959 | u16 mii_reg = 0; | ||
1960 | |||
1961 | /* The PHY will retain its settings across a power down/up cycle */ | ||
1962 | hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg); | ||
1963 | mii_reg |= MII_CR_POWER_DOWN; | ||
1964 | hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg); | ||
1965 | msleep(1); | ||
1966 | } | ||
1967 | |||
1968 | /** | ||
1934 | * igb_check_polarity_82580 - Checks the polarity. | 1969 | * igb_check_polarity_82580 - Checks the polarity. |
1935 | * @hw: pointer to the HW structure | 1970 | * @hw: pointer to the HW structure |
1936 | * | 1971 | * |
diff --git a/drivers/net/igb/e1000_phy.h b/drivers/net/igb/e1000_phy.h index 555eb54bb6ed..565a6dbb3714 100644 --- a/drivers/net/igb/e1000_phy.h +++ b/drivers/net/igb/e1000_phy.h | |||
@@ -60,6 +60,8 @@ s32 igb_setup_copper_link(struct e1000_hw *hw); | |||
60 | s32 igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data); | 60 | s32 igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data); |
61 | s32 igb_phy_has_link(struct e1000_hw *hw, u32 iterations, | 61 | s32 igb_phy_has_link(struct e1000_hw *hw, u32 iterations, |
62 | u32 usec_interval, bool *success); | 62 | u32 usec_interval, bool *success); |
63 | void igb_power_up_phy_copper(struct e1000_hw *hw); | ||
64 | void igb_power_down_phy_copper(struct e1000_hw *hw); | ||
63 | s32 igb_phy_init_script_igp3(struct e1000_hw *hw); | 65 | s32 igb_phy_init_script_igp3(struct e1000_hw *hw); |
64 | s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data); | 66 | s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data); |
65 | s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data); | 67 | s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data); |
diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index 452a4dee87f8..0e0800dc801d 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h | |||
@@ -358,6 +358,7 @@ extern void igb_alloc_rx_buffers_adv(struct igb_ring *, int); | |||
358 | extern void igb_update_stats(struct igb_adapter *); | 358 | extern void igb_update_stats(struct igb_adapter *); |
359 | extern bool igb_has_link(struct igb_adapter *adapter); | 359 | extern bool igb_has_link(struct igb_adapter *adapter); |
360 | extern void igb_set_ethtool_ops(struct net_device *); | 360 | extern void igb_set_ethtool_ops(struct net_device *); |
361 | extern void igb_power_up_link(struct igb_adapter *); | ||
361 | 362 | ||
362 | static inline s32 igb_reset_phy(struct e1000_hw *hw) | 363 | static inline s32 igb_reset_phy(struct e1000_hw *hw) |
363 | { | 364 | { |
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index 4eea03b428c4..485288303f32 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c | |||
@@ -1722,6 +1722,9 @@ static void igb_diag_test(struct net_device *netdev, | |||
1722 | 1722 | ||
1723 | dev_info(&adapter->pdev->dev, "offline testing starting\n"); | 1723 | dev_info(&adapter->pdev->dev, "offline testing starting\n"); |
1724 | 1724 | ||
1725 | /* power up link for link test */ | ||
1726 | igb_power_up_link(adapter); | ||
1727 | |||
1725 | /* Link test performed before hardware reset so autoneg doesn't | 1728 | /* Link test performed before hardware reset so autoneg doesn't |
1726 | * interfere with test result */ | 1729 | * interfere with test result */ |
1727 | if (igb_link_test(adapter, &data[4])) | 1730 | if (igb_link_test(adapter, &data[4])) |
@@ -1745,6 +1748,8 @@ static void igb_diag_test(struct net_device *netdev, | |||
1745 | eth_test->flags |= ETH_TEST_FL_FAILED; | 1748 | eth_test->flags |= ETH_TEST_FL_FAILED; |
1746 | 1749 | ||
1747 | igb_reset(adapter); | 1750 | igb_reset(adapter); |
1751 | /* power up link for loopback test */ | ||
1752 | igb_power_up_link(adapter); | ||
1748 | if (igb_loopback_test(adapter, &data[3])) | 1753 | if (igb_loopback_test(adapter, &data[3])) |
1749 | eth_test->flags |= ETH_TEST_FL_FAILED; | 1754 | eth_test->flags |= ETH_TEST_FL_FAILED; |
1750 | 1755 | ||
@@ -1763,9 +1768,14 @@ static void igb_diag_test(struct net_device *netdev, | |||
1763 | dev_open(netdev); | 1768 | dev_open(netdev); |
1764 | } else { | 1769 | } else { |
1765 | dev_info(&adapter->pdev->dev, "online testing starting\n"); | 1770 | dev_info(&adapter->pdev->dev, "online testing starting\n"); |
1766 | /* Online tests */ | 1771 | |
1767 | if (igb_link_test(adapter, &data[4])) | 1772 | /* PHY is powered down when interface is down */ |
1768 | eth_test->flags |= ETH_TEST_FL_FAILED; | 1773 | if (!netif_carrier_ok(netdev)) { |
1774 | data[4] = 0; | ||
1775 | } else { | ||
1776 | if (igb_link_test(adapter, &data[4])) | ||
1777 | eth_test->flags |= ETH_TEST_FL_FAILED; | ||
1778 | } | ||
1769 | 1779 | ||
1770 | /* Online tests aren't run; pass by default */ | 1780 | /* Online tests aren't run; pass by default */ |
1771 | data[0] = 0; | 1781 | data[0] = 0; |
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index e40319e2ec25..0427e7c10295 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c | |||
@@ -1114,6 +1114,29 @@ static void igb_configure(struct igb_adapter *adapter) | |||
1114 | adapter->tx_queue_len = netdev->tx_queue_len; | 1114 | adapter->tx_queue_len = netdev->tx_queue_len; |
1115 | } | 1115 | } |
1116 | 1116 | ||
1117 | /** | ||
1118 | * igb_power_up_link - Power up the phy/serdes link | ||
1119 | * @adapter: address of board private structure | ||
1120 | **/ | ||
1121 | void igb_power_up_link(struct igb_adapter *adapter) | ||
1122 | { | ||
1123 | if (adapter->hw.phy.media_type == e1000_media_type_copper) | ||
1124 | igb_power_up_phy_copper(&adapter->hw); | ||
1125 | else | ||
1126 | igb_power_up_serdes_link_82575(&adapter->hw); | ||
1127 | } | ||
1128 | |||
1129 | /** | ||
1130 | * igb_power_down_link - Power down the phy/serdes link | ||
1131 | * @adapter: address of board private structure | ||
1132 | */ | ||
1133 | static void igb_power_down_link(struct igb_adapter *adapter) | ||
1134 | { | ||
1135 | if (adapter->hw.phy.media_type == e1000_media_type_copper) | ||
1136 | igb_power_down_phy_copper_82575(&adapter->hw); | ||
1137 | else | ||
1138 | igb_shutdown_serdes_link_82575(&adapter->hw); | ||
1139 | } | ||
1117 | 1140 | ||
1118 | /** | 1141 | /** |
1119 | * igb_up - Open the interface and prepare it to handle traffic | 1142 | * igb_up - Open the interface and prepare it to handle traffic |
@@ -1335,6 +1358,9 @@ void igb_reset(struct igb_adapter *adapter) | |||
1335 | wr32(E1000_PCIEMISC, | 1358 | wr32(E1000_PCIEMISC, |
1336 | reg & ~E1000_PCIEMISC_LX_DECISION); | 1359 | reg & ~E1000_PCIEMISC_LX_DECISION); |
1337 | } | 1360 | } |
1361 | if (!netif_running(adapter->netdev)) | ||
1362 | igb_power_down_link(adapter); | ||
1363 | |||
1338 | igb_update_mng_vlan(adapter); | 1364 | igb_update_mng_vlan(adapter); |
1339 | 1365 | ||
1340 | /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */ | 1366 | /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */ |
@@ -1717,9 +1743,6 @@ static void __devexit igb_remove(struct pci_dev *pdev) | |||
1717 | 1743 | ||
1718 | unregister_netdev(netdev); | 1744 | unregister_netdev(netdev); |
1719 | 1745 | ||
1720 | if (!igb_check_reset_block(hw)) | ||
1721 | igb_reset_phy(hw); | ||
1722 | |||
1723 | igb_clear_interrupt_scheme(adapter); | 1746 | igb_clear_interrupt_scheme(adapter); |
1724 | 1747 | ||
1725 | #ifdef CONFIG_PCI_IOV | 1748 | #ifdef CONFIG_PCI_IOV |
@@ -1995,7 +2018,7 @@ static int igb_open(struct net_device *netdev) | |||
1995 | if (err) | 2018 | if (err) |
1996 | goto err_setup_rx; | 2019 | goto err_setup_rx; |
1997 | 2020 | ||
1998 | /* e1000_power_up_phy(adapter); */ | 2021 | igb_power_up_link(adapter); |
1999 | 2022 | ||
2000 | /* before we allocate an interrupt, we must be ready to handle it. | 2023 | /* before we allocate an interrupt, we must be ready to handle it. |
2001 | * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt | 2024 | * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt |
@@ -2037,7 +2060,7 @@ static int igb_open(struct net_device *netdev) | |||
2037 | 2060 | ||
2038 | err_req_irq: | 2061 | err_req_irq: |
2039 | igb_release_hw_control(adapter); | 2062 | igb_release_hw_control(adapter); |
2040 | /* e1000_power_down_phy(adapter); */ | 2063 | igb_power_down_link(adapter); |
2041 | igb_free_all_rx_resources(adapter); | 2064 | igb_free_all_rx_resources(adapter); |
2042 | err_setup_rx: | 2065 | err_setup_rx: |
2043 | igb_free_all_tx_resources(adapter); | 2066 | igb_free_all_tx_resources(adapter); |
@@ -5820,7 +5843,9 @@ static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake) | |||
5820 | 5843 | ||
5821 | *enable_wake = wufc || adapter->en_mng_pt; | 5844 | *enable_wake = wufc || adapter->en_mng_pt; |
5822 | if (!*enable_wake) | 5845 | if (!*enable_wake) |
5823 | igb_shutdown_serdes_link_82575(hw); | 5846 | igb_power_down_link(adapter); |
5847 | else | ||
5848 | igb_power_up_link(adapter); | ||
5824 | 5849 | ||
5825 | /* Release control of h/w to f/w. If f/w is AMT enabled, this | 5850 | /* Release control of h/w to f/w. If f/w is AMT enabled, this |
5826 | * would have already happened in close and is redundant. */ | 5851 | * would have already happened in close and is redundant. */ |
@@ -5877,8 +5902,6 @@ static int igb_resume(struct pci_dev *pdev) | |||
5877 | return -ENOMEM; | 5902 | return -ENOMEM; |
5878 | } | 5903 | } |
5879 | 5904 | ||
5880 | /* e1000_power_up_phy(adapter); */ | ||
5881 | |||
5882 | igb_reset(adapter); | 5905 | igb_reset(adapter); |
5883 | 5906 | ||
5884 | /* let the f/w know that the h/w is now under the control of the | 5907 | /* let the f/w know that the h/w is now under the control of the |