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 | |
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')
-rw-r--r-- | drivers/net/e1000e/e1000.h | 1 | ||||
-rw-r--r-- | drivers/net/e1000e/ethtool.c | 54 | ||||
-rw-r--r-- | drivers/net/e1000e/netdev.c | 2 |
3 files changed, 29 insertions, 28 deletions
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index 328b7f4a07bc..9ee133f5034e 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h | |||
@@ -461,7 +461,6 @@ extern int e1000e_setup_tx_resources(struct e1000_adapter *adapter); | |||
461 | extern void e1000e_free_rx_resources(struct e1000_adapter *adapter); | 461 | extern void e1000e_free_rx_resources(struct e1000_adapter *adapter); |
462 | extern void e1000e_free_tx_resources(struct e1000_adapter *adapter); | 462 | extern void e1000e_free_tx_resources(struct e1000_adapter *adapter); |
463 | extern void e1000e_update_stats(struct e1000_adapter *adapter); | 463 | extern void e1000e_update_stats(struct e1000_adapter *adapter); |
464 | extern bool e1000e_has_link(struct e1000_adapter *adapter); | ||
465 | extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter); | 464 | extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter); |
466 | extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter); | 465 | extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter); |
467 | extern void e1000e_disable_aspm(struct pci_dev *pdev, u16 state); | 466 | extern void e1000e_disable_aspm(struct pci_dev *pdev, u16 state); |
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) |
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 8faf2246d89c..2a71889112b6 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c | |||
@@ -3964,7 +3964,7 @@ static void e1000_print_link_info(struct e1000_adapter *adapter) | |||
3964 | ((ctrl & E1000_CTRL_TFCE) ? "TX" : "None" ))); | 3964 | ((ctrl & E1000_CTRL_TFCE) ? "TX" : "None" ))); |
3965 | } | 3965 | } |
3966 | 3966 | ||
3967 | bool e1000e_has_link(struct e1000_adapter *adapter) | 3967 | static bool e1000e_has_link(struct e1000_adapter *adapter) |
3968 | { | 3968 | { |
3969 | struct e1000_hw *hw = &adapter->hw; | 3969 | struct e1000_hw *hw = &adapter->hw; |
3970 | bool link_active = 0; | 3970 | bool link_active = 0; |