diff options
author | Bruce Allan <bruce.w.allan@intel.com> | 2010-06-17 14:58:43 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-06-23 15:58:38 -0400 |
commit | 0c6bdb3084d015221270b418190b630553a38cf8 (patch) | |
tree | 5362357877c998ecd88df96f45e03362a8db727d /drivers/net/e1000e/ethtool.c | |
parent | 69ad78208ecf4c392f3d323ed050423847c24104 (diff) |
e1000e: avoid polling h/w registers during link negotiation
Avoid touching hardware registers when possible, otherwise link negotiation
can get messed up when user-level scripts are rapidly polling the driver to
see if/when link is up. Use the saved link state information instead when
possible.
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>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/e1000e/ethtool.c')
-rw-r--r-- | drivers/net/e1000e/ethtool.c | 54 |
1 files changed, 28 insertions, 26 deletions
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index db86850b1636..77c5829ab945 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c | |||
@@ -118,7 +118,6 @@ static int e1000_get_settings(struct net_device *netdev, | |||
118 | { | 118 | { |
119 | struct e1000_adapter *adapter = netdev_priv(netdev); | 119 | struct e1000_adapter *adapter = netdev_priv(netdev); |
120 | struct e1000_hw *hw = &adapter->hw; | 120 | struct e1000_hw *hw = &adapter->hw; |
121 | u32 status; | ||
122 | 121 | ||
123 | if (hw->phy.media_type == e1000_media_type_copper) { | 122 | if (hw->phy.media_type == e1000_media_type_copper) { |
124 | 123 | ||
@@ -156,22 +155,29 @@ static int e1000_get_settings(struct net_device *netdev, | |||
156 | ecmd->transceiver = XCVR_EXTERNAL; | 155 | ecmd->transceiver = XCVR_EXTERNAL; |
157 | } | 156 | } |
158 | 157 | ||
159 | status = er32(STATUS); | 158 | ecmd->speed = -1; |
160 | if (status & E1000_STATUS_LU) { | 159 | ecmd->duplex = -1; |
161 | if (status & E1000_STATUS_SPEED_1000) | ||
162 | ecmd->speed = 1000; | ||
163 | else if (status & E1000_STATUS_SPEED_100) | ||
164 | ecmd->speed = 100; | ||
165 | else | ||
166 | ecmd->speed = 10; | ||
167 | 160 | ||
168 | if (status & E1000_STATUS_FD) | 161 | if (netif_running(netdev)) { |
169 | ecmd->duplex = DUPLEX_FULL; | 162 | if (netif_carrier_ok(netdev)) { |
170 | else | 163 | ecmd->speed = adapter->link_speed; |
171 | ecmd->duplex = DUPLEX_HALF; | 164 | ecmd->duplex = adapter->link_duplex - 1; |
165 | } | ||
172 | } else { | 166 | } else { |
173 | ecmd->speed = -1; | 167 | u32 status = er32(STATUS); |
174 | ecmd->duplex = -1; | 168 | if (status & E1000_STATUS_LU) { |
169 | if (status & E1000_STATUS_SPEED_1000) | ||
170 | ecmd->speed = 1000; | ||
171 | else if (status & E1000_STATUS_SPEED_100) | ||
172 | ecmd->speed = 100; | ||
173 | else | ||
174 | ecmd->speed = 10; | ||
175 | |||
176 | if (status & E1000_STATUS_FD) | ||
177 | ecmd->duplex = DUPLEX_FULL; | ||
178 | else | ||
179 | ecmd->duplex = DUPLEX_HALF; | ||
180 | } | ||
175 | } | 181 | } |
176 | 182 | ||
177 | ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) || | 183 | ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) || |
@@ -179,7 +185,7 @@ static int e1000_get_settings(struct net_device *netdev, | |||
179 | 185 | ||
180 | /* MDI-X => 2; MDI =>1; Invalid =>0 */ | 186 | /* MDI-X => 2; MDI =>1; Invalid =>0 */ |
181 | if ((hw->phy.media_type == e1000_media_type_copper) && | 187 | if ((hw->phy.media_type == e1000_media_type_copper) && |
182 | !hw->mac.get_link_status) | 188 | netif_carrier_ok(netdev)) |
183 | ecmd->eth_tp_mdix = hw->phy.is_mdix ? ETH_TP_MDI_X : | 189 | ecmd->eth_tp_mdix = hw->phy.is_mdix ? ETH_TP_MDI_X : |
184 | ETH_TP_MDI; | 190 | ETH_TP_MDI; |
185 | else | 191 | else |
@@ -191,19 +197,15 @@ static int e1000_get_settings(struct net_device *netdev, | |||
191 | static u32 e1000_get_link(struct net_device *netdev) | 197 | static u32 e1000_get_link(struct net_device *netdev) |
192 | { | 198 | { |
193 | struct e1000_adapter *adapter = netdev_priv(netdev); | 199 | struct e1000_adapter *adapter = netdev_priv(netdev); |
194 | struct e1000_mac_info *mac = &adapter->hw.mac; | 200 | struct e1000_hw *hw = &adapter->hw; |
195 | 201 | ||
196 | /* | 202 | /* |
197 | * If the link is not reported up to netdev, interrupts are disabled, | 203 | * Avoid touching hardware registers when possible, otherwise |
198 | * and so the physical link state may have changed since we last | 204 | * link negotiation can get messed up when user-level scripts |
199 | * looked. Set get_link_status to make sure that the true link | 205 | * are rapidly polling the driver to see if link is up. |
200 | * state is interrogated, rather than pulling a cached and possibly | ||
201 | * stale link state from the driver. | ||
202 | */ | 206 | */ |
203 | if (!netif_carrier_ok(netdev)) | 207 | return netif_running(netdev) ? netif_carrier_ok(netdev) : |
204 | mac->get_link_status = 1; | 208 | !!(er32(STATUS) & E1000_STATUS_LU); |
205 | |||
206 | return e1000e_has_link(adapter); | ||
207 | } | 209 | } |
208 | 210 | ||
209 | static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) | 211 | static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) |