diff options
author | David Decotigny <decot@google.com> | 2011-04-27 14:32:43 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-04-29 17:03:03 -0400 |
commit | 14ad2513ed5b709e566a853f4b515d91c5d83311 (patch) | |
tree | 19ce2e6deefaa0725533612df85c51b99d2513cb /drivers/net/e1000e | |
parent | fbef7139a8b89a7f49ba1410593ed894b4c8b017 (diff) |
net/igb/e1000/e1000e: more robust ethtool duplex/speed configuration
This makes sure that one cannot request a 99Mbps full-duplex and get a
100Mbps half-duplex configuration in return due to the way the
speed/duplex parameters are handled internally.
Tested: e1000 works
Signed-off-by: David Decotigny <decot@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/e1000e')
-rw-r--r-- | drivers/net/e1000e/ethtool.c | 24 |
1 files changed, 16 insertions, 8 deletions
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 12f1ee250522..859d0d3af6c9 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c | |||
@@ -200,20 +200,25 @@ static int e1000_get_settings(struct net_device *netdev, | |||
200 | return 0; | 200 | return 0; |
201 | } | 201 | } |
202 | 202 | ||
203 | static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) | 203 | static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u32 spd, u8 dplx) |
204 | { | 204 | { |
205 | struct e1000_mac_info *mac = &adapter->hw.mac; | 205 | struct e1000_mac_info *mac = &adapter->hw.mac; |
206 | 206 | ||
207 | mac->autoneg = 0; | 207 | mac->autoneg = 0; |
208 | 208 | ||
209 | /* Make sure dplx is at most 1 bit and lsb of speed is not set | ||
210 | * for the switch() below to work */ | ||
211 | if ((spd & 1) || (dplx & ~1)) | ||
212 | goto err_inval; | ||
213 | |||
209 | /* Fiber NICs only allow 1000 gbps Full duplex */ | 214 | /* Fiber NICs only allow 1000 gbps Full duplex */ |
210 | if ((adapter->hw.phy.media_type == e1000_media_type_fiber) && | 215 | if ((adapter->hw.phy.media_type == e1000_media_type_fiber) && |
211 | spddplx != (SPEED_1000 + DUPLEX_FULL)) { | 216 | spd != SPEED_1000 && |
212 | e_err("Unsupported Speed/Duplex configuration\n"); | 217 | dplx != DUPLEX_FULL) { |
213 | return -EINVAL; | 218 | goto err_inval; |
214 | } | 219 | } |
215 | 220 | ||
216 | switch (spddplx) { | 221 | switch (spd + dplx) { |
217 | case SPEED_10 + DUPLEX_HALF: | 222 | case SPEED_10 + DUPLEX_HALF: |
218 | mac->forced_speed_duplex = ADVERTISE_10_HALF; | 223 | mac->forced_speed_duplex = ADVERTISE_10_HALF; |
219 | break; | 224 | break; |
@@ -232,10 +237,13 @@ static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) | |||
232 | break; | 237 | break; |
233 | case SPEED_1000 + DUPLEX_HALF: /* not supported */ | 238 | case SPEED_1000 + DUPLEX_HALF: /* not supported */ |
234 | default: | 239 | default: |
235 | e_err("Unsupported Speed/Duplex configuration\n"); | 240 | goto err_inval; |
236 | return -EINVAL; | ||
237 | } | 241 | } |
238 | return 0; | 242 | return 0; |
243 | |||
244 | err_inval: | ||
245 | e_err("Unsupported Speed/Duplex configuration\n"); | ||
246 | return -EINVAL; | ||
239 | } | 247 | } |
240 | 248 | ||
241 | static int e1000_set_settings(struct net_device *netdev, | 249 | static int e1000_set_settings(struct net_device *netdev, |
@@ -272,7 +280,7 @@ static int e1000_set_settings(struct net_device *netdev, | |||
272 | hw->fc.requested_mode = e1000_fc_default; | 280 | hw->fc.requested_mode = e1000_fc_default; |
273 | } else { | 281 | } else { |
274 | u32 speed = ethtool_cmd_speed(ecmd); | 282 | u32 speed = ethtool_cmd_speed(ecmd); |
275 | if (e1000_set_spd_dplx(adapter, speed + ecmd->duplex)) { | 283 | if (e1000_set_spd_dplx(adapter, speed, ecmd->duplex)) { |
276 | clear_bit(__E1000_RESETTING, &adapter->state); | 284 | clear_bit(__E1000_RESETTING, &adapter->state); |
277 | return -EINVAL; | 285 | return -EINVAL; |
278 | } | 286 | } |