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/igb | |
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/igb')
-rw-r--r-- | drivers/net/igb/igb.h | 2 | ||||
-rw-r--r-- | drivers/net/igb/igb_ethtool.c | 2 | ||||
-rw-r--r-- | drivers/net/igb/igb_main.c | 23 |
3 files changed, 17 insertions, 10 deletions
diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index 1c687e298d5e..f4fa4b1751cf 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h | |||
@@ -360,7 +360,7 @@ extern int igb_up(struct igb_adapter *); | |||
360 | extern void igb_down(struct igb_adapter *); | 360 | extern void igb_down(struct igb_adapter *); |
361 | extern void igb_reinit_locked(struct igb_adapter *); | 361 | extern void igb_reinit_locked(struct igb_adapter *); |
362 | extern void igb_reset(struct igb_adapter *); | 362 | extern void igb_reset(struct igb_adapter *); |
363 | extern int igb_set_spd_dplx(struct igb_adapter *, u16); | 363 | extern int igb_set_spd_dplx(struct igb_adapter *, u32, u8); |
364 | extern int igb_setup_tx_resources(struct igb_ring *); | 364 | extern int igb_setup_tx_resources(struct igb_ring *); |
365 | extern int igb_setup_rx_resources(struct igb_ring *); | 365 | extern int igb_setup_rx_resources(struct igb_ring *); |
366 | extern void igb_free_tx_resources(struct igb_ring *); | 366 | extern void igb_free_tx_resources(struct igb_ring *); |
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index 023aa9b10654..6e29634b1fb5 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c | |||
@@ -224,7 +224,7 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) | |||
224 | hw->fc.requested_mode = e1000_fc_default; | 224 | hw->fc.requested_mode = e1000_fc_default; |
225 | } else { | 225 | } else { |
226 | u32 speed = ethtool_cmd_speed(ecmd); | 226 | u32 speed = ethtool_cmd_speed(ecmd); |
227 | if (igb_set_spd_dplx(adapter, speed + ecmd->duplex)) { | 227 | if (igb_set_spd_dplx(adapter, speed, ecmd->duplex)) { |
228 | clear_bit(__IGB_RESETTING, &adapter->state); | 228 | clear_bit(__IGB_RESETTING, &adapter->state); |
229 | return -EINVAL; | 229 | return -EINVAL; |
230 | } | 230 | } |
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index cdfd57271051..ce7838e55827 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c | |||
@@ -6349,21 +6349,25 @@ static void igb_restore_vlan(struct igb_adapter *adapter) | |||
6349 | } | 6349 | } |
6350 | } | 6350 | } |
6351 | 6351 | ||
6352 | int igb_set_spd_dplx(struct igb_adapter *adapter, u16 spddplx) | 6352 | int igb_set_spd_dplx(struct igb_adapter *adapter, u32 spd, u8 dplx) |
6353 | { | 6353 | { |
6354 | struct pci_dev *pdev = adapter->pdev; | 6354 | struct pci_dev *pdev = adapter->pdev; |
6355 | struct e1000_mac_info *mac = &adapter->hw.mac; | 6355 | struct e1000_mac_info *mac = &adapter->hw.mac; |
6356 | 6356 | ||
6357 | mac->autoneg = 0; | 6357 | mac->autoneg = 0; |
6358 | 6358 | ||
6359 | /* Make sure dplx is at most 1 bit and lsb of speed is not set | ||
6360 | * for the switch() below to work */ | ||
6361 | if ((spd & 1) || (dplx & ~1)) | ||
6362 | goto err_inval; | ||
6363 | |||
6359 | /* Fiber NIC's only allow 1000 Gbps Full duplex */ | 6364 | /* Fiber NIC's only allow 1000 Gbps Full duplex */ |
6360 | if ((adapter->hw.phy.media_type == e1000_media_type_internal_serdes) && | 6365 | if ((adapter->hw.phy.media_type == e1000_media_type_internal_serdes) && |
6361 | spddplx != (SPEED_1000 + DUPLEX_FULL)) { | 6366 | spd != SPEED_1000 && |
6362 | dev_err(&pdev->dev, "Unsupported Speed/Duplex configuration\n"); | 6367 | dplx != DUPLEX_FULL) |
6363 | return -EINVAL; | 6368 | goto err_inval; |
6364 | } | ||
6365 | 6369 | ||
6366 | switch (spddplx) { | 6370 | switch (spd + dplx) { |
6367 | case SPEED_10 + DUPLEX_HALF: | 6371 | case SPEED_10 + DUPLEX_HALF: |
6368 | mac->forced_speed_duplex = ADVERTISE_10_HALF; | 6372 | mac->forced_speed_duplex = ADVERTISE_10_HALF; |
6369 | break; | 6373 | break; |
@@ -6382,10 +6386,13 @@ int igb_set_spd_dplx(struct igb_adapter *adapter, u16 spddplx) | |||
6382 | break; | 6386 | break; |
6383 | case SPEED_1000 + DUPLEX_HALF: /* not supported */ | 6387 | case SPEED_1000 + DUPLEX_HALF: /* not supported */ |
6384 | default: | 6388 | default: |
6385 | dev_err(&pdev->dev, "Unsupported Speed/Duplex configuration\n"); | 6389 | goto err_inval; |
6386 | return -EINVAL; | ||
6387 | } | 6390 | } |
6388 | return 0; | 6391 | return 0; |
6392 | |||
6393 | err_inval: | ||
6394 | dev_err(&pdev->dev, "Unsupported Speed/Duplex configuration\n"); | ||
6395 | return -EINVAL; | ||
6389 | } | 6396 | } |
6390 | 6397 | ||
6391 | static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake) | 6398 | static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake) |