diff options
author | Bruce Allan <bruce.w.allan@intel.com> | 2012-12-05 03:40:59 -0500 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2013-01-18 07:54:49 -0500 |
commit | 203e41514a557b71c4c42b4bb2912b56fa0c2fdc (patch) | |
tree | 956d6ab42a9eee23a0e0f9ec391b836ba7aa2b4c | |
parent | 887c95cc1da53f66a5890fdeab13414613010097 (diff) |
e1000e: add ethtool .get_eee/.set_eee
Add the ability to query and set Energy Efficient Ethernet parameters via
ethtool for applicable devices.
Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
-rw-r--r-- | drivers/net/ethernet/intel/e1000e/defines.h | 30 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/e1000e/e1000.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/e1000e/ethtool.c | 134 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/e1000e/hw.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/e1000e/ich8lan.c | 24 |
5 files changed, 167 insertions, 23 deletions
diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h index 7326ea2fef8f..3041a54e3a61 100644 --- a/drivers/net/ethernet/intel/e1000e/defines.h +++ b/drivers/net/ethernet/intel/e1000e/defines.h | |||
@@ -383,6 +383,9 @@ | |||
383 | 383 | ||
384 | #define E1000_KABGTXD_BGSQLBIAS 0x00050000 | 384 | #define E1000_KABGTXD_BGSQLBIAS 0x00050000 |
385 | 385 | ||
386 | /* Low Power IDLE Control */ | ||
387 | #define E1000_LPIC_LPIET_SHIFT 24 /* Low Power Idle Entry Time */ | ||
388 | |||
386 | /* PBA constants */ | 389 | /* PBA constants */ |
387 | #define E1000_PBA_8K 0x0008 /* 8KB */ | 390 | #define E1000_PBA_8K 0x0008 /* 8KB */ |
388 | #define E1000_PBA_16K 0x0010 /* 16KB */ | 391 | #define E1000_PBA_16K 0x0010 /* 16KB */ |
@@ -799,6 +802,33 @@ | |||
799 | /* BME1000 PHY Specific Control Register */ | 802 | /* BME1000 PHY Specific Control Register */ |
800 | #define BME1000_PSCR_ENABLE_DOWNSHIFT 0x0800 /* 1 = enable downshift */ | 803 | #define BME1000_PSCR_ENABLE_DOWNSHIFT 0x0800 /* 1 = enable downshift */ |
801 | 804 | ||
805 | /* PHY Low Power Idle Control */ | ||
806 | #define I82579_LPI_CTRL PHY_REG(772, 20) | ||
807 | #define I82579_LPI_CTRL_100_ENABLE 0x2000 | ||
808 | #define I82579_LPI_CTRL_1000_ENABLE 0x4000 | ||
809 | #define I82579_LPI_CTRL_ENABLE_MASK 0x6000 | ||
810 | #define I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT 0x80 | ||
811 | |||
812 | /* Extended Management Interface (EMI) Registers */ | ||
813 | #define I82579_EMI_ADDR 0x10 | ||
814 | #define I82579_EMI_DATA 0x11 | ||
815 | #define I82579_LPI_UPDATE_TIMER 0x4805 /* in 40ns units + 40 ns base value */ | ||
816 | #define I82579_MSE_THRESHOLD 0x084F /* 82579 Mean Square Error Threshold */ | ||
817 | #define I82577_MSE_THRESHOLD 0x0887 /* 82577 Mean Square Error Threshold */ | ||
818 | #define I82579_MSE_LINK_DOWN 0x2411 /* MSE count before dropping link */ | ||
819 | #define I82579_EEE_PCS_STATUS 0x182D /* IEEE MMD Register 3.1 >> 8 */ | ||
820 | #define I82579_EEE_CAPABILITY 0x0410 /* IEEE MMD Register 3.20 */ | ||
821 | #define I82579_EEE_ADVERTISEMENT 0x040E /* IEEE MMD Register 7.60 */ | ||
822 | #define I82579_EEE_LP_ABILITY 0x040F /* IEEE MMD Register 7.61 */ | ||
823 | #define I82579_EEE_100_SUPPORTED (1 << 1) /* 100BaseTx EEE supported */ | ||
824 | #define I82579_EEE_1000_SUPPORTED (1 << 2) /* 1000BaseTx EEE supported */ | ||
825 | #define I217_EEE_PCS_STATUS 0x9401 /* IEEE MMD Register 3.1 */ | ||
826 | #define I217_EEE_CAPABILITY 0x8000 /* IEEE MMD Register 3.20 */ | ||
827 | #define I217_EEE_ADVERTISEMENT 0x8001 /* IEEE MMD Register 7.60 */ | ||
828 | #define I217_EEE_LP_ABILITY 0x8002 /* IEEE MMD Register 7.61 */ | ||
829 | |||
830 | #define E1000_EEE_RX_LPI_RCVD 0x0400 /* Tx LP idle received */ | ||
831 | #define E1000_EEE_TX_LPI_RCVD 0x0800 /* Rx LP idle received */ | ||
802 | 832 | ||
803 | #define PHY_PAGE_SHIFT 5 | 833 | #define PHY_PAGE_SHIFT 5 |
804 | #define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \ | 834 | #define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \ |
diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index 3f8bbc31795c..b89b181da7b1 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h | |||
@@ -659,6 +659,7 @@ extern s32 e1000_check_polarity_ife(struct e1000_hw *hw); | |||
659 | extern s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw); | 659 | extern s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw); |
660 | extern s32 e1000_check_polarity_igp(struct e1000_hw *hw); | 660 | extern s32 e1000_check_polarity_igp(struct e1000_hw *hw); |
661 | extern bool e1000_check_phy_82574(struct e1000_hw *hw); | 661 | extern bool e1000_check_phy_82574(struct e1000_hw *hw); |
662 | extern s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data); | ||
662 | 663 | ||
663 | static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw) | 664 | static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw) |
664 | { | 665 | { |
diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index 2225603a8a28..636ba09ca6fb 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
36 | #include <linux/delay.h> | 36 | #include <linux/delay.h> |
37 | #include <linux/vmalloc.h> | 37 | #include <linux/vmalloc.h> |
38 | #include <linux/mdio.h> | ||
38 | 39 | ||
39 | #include "e1000.h" | 40 | #include "e1000.h" |
40 | 41 | ||
@@ -2050,6 +2051,137 @@ static int e1000_get_rxnfc(struct net_device *netdev, | |||
2050 | } | 2051 | } |
2051 | } | 2052 | } |
2052 | 2053 | ||
2054 | static int e1000e_get_eee(struct net_device *netdev, struct ethtool_eee *edata) | ||
2055 | { | ||
2056 | struct e1000_adapter *adapter = netdev_priv(netdev); | ||
2057 | struct e1000_hw *hw = &adapter->hw; | ||
2058 | u16 cap_addr, adv_addr, lpa_addr, pcs_stat_addr, phy_data, lpi_ctrl; | ||
2059 | u32 status, ret_val; | ||
2060 | |||
2061 | if (!(adapter->flags & FLAG_IS_ICH) || | ||
2062 | !(adapter->flags2 & FLAG2_HAS_EEE)) | ||
2063 | return -EOPNOTSUPP; | ||
2064 | |||
2065 | switch (hw->phy.type) { | ||
2066 | case e1000_phy_82579: | ||
2067 | cap_addr = I82579_EEE_CAPABILITY; | ||
2068 | adv_addr = I82579_EEE_ADVERTISEMENT; | ||
2069 | lpa_addr = I82579_EEE_LP_ABILITY; | ||
2070 | pcs_stat_addr = I82579_EEE_PCS_STATUS; | ||
2071 | break; | ||
2072 | case e1000_phy_i217: | ||
2073 | cap_addr = I217_EEE_CAPABILITY; | ||
2074 | adv_addr = I217_EEE_ADVERTISEMENT; | ||
2075 | lpa_addr = I217_EEE_LP_ABILITY; | ||
2076 | pcs_stat_addr = I217_EEE_PCS_STATUS; | ||
2077 | break; | ||
2078 | default: | ||
2079 | return -EOPNOTSUPP; | ||
2080 | } | ||
2081 | |||
2082 | ret_val = hw->phy.ops.acquire(hw); | ||
2083 | if (ret_val) | ||
2084 | return -EBUSY; | ||
2085 | |||
2086 | /* EEE Capability */ | ||
2087 | ret_val = e1000_read_emi_reg_locked(hw, cap_addr, &phy_data); | ||
2088 | if (ret_val) | ||
2089 | goto release; | ||
2090 | edata->supported = mmd_eee_cap_to_ethtool_sup_t(phy_data); | ||
2091 | |||
2092 | /* EEE Advertised */ | ||
2093 | ret_val = e1000_read_emi_reg_locked(hw, adv_addr, &phy_data); | ||
2094 | if (ret_val) | ||
2095 | goto release; | ||
2096 | edata->advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data); | ||
2097 | |||
2098 | /* EEE Link Partner Advertised */ | ||
2099 | ret_val = e1000_read_emi_reg_locked(hw, lpa_addr, &phy_data); | ||
2100 | if (ret_val) | ||
2101 | goto release; | ||
2102 | edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data); | ||
2103 | |||
2104 | /* EEE PCS Status */ | ||
2105 | ret_val = e1000_read_emi_reg_locked(hw, pcs_stat_addr, &phy_data); | ||
2106 | if (hw->phy.type == e1000_phy_82579) | ||
2107 | phy_data <<= 8; | ||
2108 | |||
2109 | release: | ||
2110 | hw->phy.ops.release(hw); | ||
2111 | if (ret_val) | ||
2112 | return -ENODATA; | ||
2113 | |||
2114 | e1e_rphy(hw, I82579_LPI_CTRL, &lpi_ctrl); | ||
2115 | status = er32(STATUS); | ||
2116 | |||
2117 | /* Result of the EEE auto negotiation - there is no register that | ||
2118 | * has the status of the EEE negotiation so do a best-guess based | ||
2119 | * on whether both Tx and Rx LPI indications have been received or | ||
2120 | * base it on the link speed, the EEE advertised speeds on both ends | ||
2121 | * and the speeds on which EEE is enabled locally. | ||
2122 | */ | ||
2123 | if (((phy_data & E1000_EEE_TX_LPI_RCVD) && | ||
2124 | (phy_data & E1000_EEE_RX_LPI_RCVD)) || | ||
2125 | ((status & E1000_STATUS_SPEED_100) && | ||
2126 | (edata->advertised & ADVERTISED_100baseT_Full) && | ||
2127 | (edata->lp_advertised & ADVERTISED_100baseT_Full) && | ||
2128 | (lpi_ctrl & I82579_LPI_CTRL_100_ENABLE)) || | ||
2129 | ((status & E1000_STATUS_SPEED_1000) && | ||
2130 | (edata->advertised & ADVERTISED_1000baseT_Full) && | ||
2131 | (edata->lp_advertised & ADVERTISED_1000baseT_Full) && | ||
2132 | (lpi_ctrl & I82579_LPI_CTRL_1000_ENABLE))) | ||
2133 | edata->eee_active = true; | ||
2134 | |||
2135 | edata->eee_enabled = !hw->dev_spec.ich8lan.eee_disable; | ||
2136 | edata->tx_lpi_enabled = true; | ||
2137 | edata->tx_lpi_timer = er32(LPIC) >> E1000_LPIC_LPIET_SHIFT; | ||
2138 | |||
2139 | return 0; | ||
2140 | } | ||
2141 | |||
2142 | static int e1000e_set_eee(struct net_device *netdev, struct ethtool_eee *edata) | ||
2143 | { | ||
2144 | struct e1000_adapter *adapter = netdev_priv(netdev); | ||
2145 | struct e1000_hw *hw = &adapter->hw; | ||
2146 | struct ethtool_eee eee_curr; | ||
2147 | s32 ret_val; | ||
2148 | |||
2149 | if (!(adapter->flags & FLAG_IS_ICH) || | ||
2150 | !(adapter->flags2 & FLAG2_HAS_EEE)) | ||
2151 | return -EOPNOTSUPP; | ||
2152 | |||
2153 | ret_val = e1000e_get_eee(netdev, &eee_curr); | ||
2154 | if (ret_val) | ||
2155 | return ret_val; | ||
2156 | |||
2157 | if (eee_curr.advertised != edata->advertised) { | ||
2158 | e_err("Setting EEE advertisement is not supported\n"); | ||
2159 | return -EINVAL; | ||
2160 | } | ||
2161 | |||
2162 | if (eee_curr.tx_lpi_enabled != edata->tx_lpi_enabled) { | ||
2163 | e_err("Setting EEE tx-lpi is not supported\n"); | ||
2164 | return -EINVAL; | ||
2165 | } | ||
2166 | |||
2167 | if (eee_curr.tx_lpi_timer != edata->tx_lpi_timer) { | ||
2168 | e_err("Setting EEE Tx LPI timer is not supported\n"); | ||
2169 | return -EINVAL; | ||
2170 | } | ||
2171 | |||
2172 | if (hw->dev_spec.ich8lan.eee_disable != !edata->eee_enabled) { | ||
2173 | hw->dev_spec.ich8lan.eee_disable = !edata->eee_enabled; | ||
2174 | |||
2175 | /* reset the link */ | ||
2176 | if (netif_running(netdev)) | ||
2177 | e1000e_reinit_locked(adapter); | ||
2178 | else | ||
2179 | e1000e_reset(adapter); | ||
2180 | } | ||
2181 | |||
2182 | return 0; | ||
2183 | } | ||
2184 | |||
2053 | static const struct ethtool_ops e1000_ethtool_ops = { | 2185 | static const struct ethtool_ops e1000_ethtool_ops = { |
2054 | .get_settings = e1000_get_settings, | 2186 | .get_settings = e1000_get_settings, |
2055 | .set_settings = e1000_set_settings, | 2187 | .set_settings = e1000_set_settings, |
@@ -2078,6 +2210,8 @@ static const struct ethtool_ops e1000_ethtool_ops = { | |||
2078 | .set_coalesce = e1000_set_coalesce, | 2210 | .set_coalesce = e1000_set_coalesce, |
2079 | .get_rxnfc = e1000_get_rxnfc, | 2211 | .get_rxnfc = e1000_get_rxnfc, |
2080 | .get_ts_info = ethtool_op_get_ts_info, | 2212 | .get_ts_info = ethtool_op_get_ts_info, |
2213 | .get_eee = e1000e_get_eee, | ||
2214 | .set_eee = e1000e_set_eee, | ||
2081 | }; | 2215 | }; |
2082 | 2216 | ||
2083 | void e1000e_set_ethtool_ops(struct net_device *netdev) | 2217 | void e1000e_set_ethtool_ops(struct net_device *netdev) |
diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h index 06239fe47db1..81afad5b80f2 100644 --- a/drivers/net/ethernet/intel/e1000e/hw.h +++ b/drivers/net/ethernet/intel/e1000e/hw.h | |||
@@ -62,6 +62,7 @@ enum e1e_registers { | |||
62 | E1000_IVAR = 0x000E4, /* Interrupt Vector Allocation - RW */ | 62 | E1000_IVAR = 0x000E4, /* Interrupt Vector Allocation - RW */ |
63 | E1000_EITR_82574_BASE = 0x000E8, /* Interrupt Throttling - RW */ | 63 | E1000_EITR_82574_BASE = 0x000E8, /* Interrupt Throttling - RW */ |
64 | #define E1000_EITR_82574(_n) (E1000_EITR_82574_BASE + (_n << 2)) | 64 | #define E1000_EITR_82574(_n) (E1000_EITR_82574_BASE + (_n << 2)) |
65 | E1000_LPIC = 0x000FC, /* Low Power Idle Control - RW */ | ||
65 | E1000_RCTL = 0x00100, /* Rx Control - RW */ | 66 | E1000_RCTL = 0x00100, /* Rx Control - RW */ |
66 | E1000_FCTTV = 0x00170, /* Flow Control Transmit Timer Value - RW */ | 67 | E1000_FCTTV = 0x00170, /* Flow Control Transmit Timer Value - RW */ |
67 | E1000_TXCW = 0x00178, /* Tx Configuration Word - RW */ | 68 | E1000_TXCW = 0x00178, /* Tx Configuration Word - RW */ |
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index 051dfda75fc0..3829f7fd1d97 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c | |||
@@ -148,28 +148,6 @@ | |||
148 | #define HV_PM_CTRL PHY_REG(770, 17) | 148 | #define HV_PM_CTRL PHY_REG(770, 17) |
149 | #define HV_PM_CTRL_PLL_STOP_IN_K1_GIGA 0x100 | 149 | #define HV_PM_CTRL_PLL_STOP_IN_K1_GIGA 0x100 |
150 | 150 | ||
151 | /* PHY Low Power Idle Control */ | ||
152 | #define I82579_LPI_CTRL PHY_REG(772, 20) | ||
153 | #define I82579_LPI_CTRL_100_ENABLE 0x2000 | ||
154 | #define I82579_LPI_CTRL_1000_ENABLE 0x4000 | ||
155 | #define I82579_LPI_CTRL_ENABLE_MASK 0x6000 | ||
156 | #define I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT 0x80 | ||
157 | |||
158 | /* Extended Management Interface (EMI) Registers */ | ||
159 | #define I82579_EMI_ADDR 0x10 | ||
160 | #define I82579_EMI_DATA 0x11 | ||
161 | #define I82579_LPI_UPDATE_TIMER 0x4805 /* in 40ns units + 40 ns base value */ | ||
162 | #define I82579_MSE_THRESHOLD 0x084F /* 82579 Mean Square Error Threshold */ | ||
163 | #define I82577_MSE_THRESHOLD 0x0887 /* 82577 Mean Square Error Threshold */ | ||
164 | #define I82579_MSE_LINK_DOWN 0x2411 /* MSE count before dropping link */ | ||
165 | #define I82579_EEE_PCS_STATUS 0x182D /* IEEE MMD Register 3.1 >> 8 */ | ||
166 | #define I82579_EEE_LP_ABILITY 0x040F /* IEEE MMD Register 7.61 */ | ||
167 | #define I82579_EEE_100_SUPPORTED (1 << 1) /* 100BaseTx EEE supported */ | ||
168 | #define I82579_EEE_1000_SUPPORTED (1 << 2) /* 1000BaseTx EEE supported */ | ||
169 | #define I217_EEE_PCS_STATUS 0x9401 /* IEEE MMD Register 3.1 */ | ||
170 | #define I217_EEE_ADVERTISEMENT 0x8001 /* IEEE MMD Register 7.60 */ | ||
171 | #define I217_EEE_LP_ABILITY 0x8002 /* IEEE MMD Register 7.61 */ | ||
172 | |||
173 | /* Intel Rapid Start Technology Support */ | 151 | /* Intel Rapid Start Technology Support */ |
174 | #define I217_PROXY_CTRL BM_PHY_REG(BM_WUC_PAGE, 70) | 152 | #define I217_PROXY_CTRL BM_PHY_REG(BM_WUC_PAGE, 70) |
175 | #define I217_PROXY_CTRL_AUTO_DISABLE 0x0080 | 153 | #define I217_PROXY_CTRL_AUTO_DISABLE 0x0080 |
@@ -829,7 +807,7 @@ static s32 __e1000_access_emi_reg_locked(struct e1000_hw *hw, u16 address, | |||
829 | * | 807 | * |
830 | * Assumes the SW/FW/HW Semaphore is already acquired. | 808 | * Assumes the SW/FW/HW Semaphore is already acquired. |
831 | **/ | 809 | **/ |
832 | static s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data) | 810 | s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data) |
833 | { | 811 | { |
834 | return __e1000_access_emi_reg_locked(hw, addr, data, true); | 812 | return __e1000_access_emi_reg_locked(hw, addr, data, true); |
835 | } | 813 | } |