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/e1000 | |
| 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/e1000')
| -rw-r--r-- | drivers/net/e1000/e1000.h | 2 | ||||
| -rw-r--r-- | drivers/net/e1000/e1000_ethtool.c | 2 | ||||
| -rw-r--r-- | drivers/net/e1000/e1000_main.c | 42 |
3 files changed, 26 insertions, 20 deletions
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index a881dd0093bd..b1b23ddd4eed 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h | |||
| @@ -349,7 +349,7 @@ extern int e1000_up(struct e1000_adapter *adapter); | |||
| 349 | extern void e1000_down(struct e1000_adapter *adapter); | 349 | extern void e1000_down(struct e1000_adapter *adapter); |
| 350 | extern void e1000_reinit_locked(struct e1000_adapter *adapter); | 350 | extern void e1000_reinit_locked(struct e1000_adapter *adapter); |
| 351 | extern void e1000_reset(struct e1000_adapter *adapter); | 351 | extern void e1000_reset(struct e1000_adapter *adapter); |
| 352 | extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx); | 352 | extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, u32 spd, u8 dplx); |
| 353 | extern int e1000_setup_all_rx_resources(struct e1000_adapter *adapter); | 353 | extern int e1000_setup_all_rx_resources(struct e1000_adapter *adapter); |
| 354 | extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter); | 354 | extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter); |
| 355 | extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter); | 355 | extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter); |
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 127fef4fce49..4fa727ce8374 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c | |||
| @@ -199,7 +199,7 @@ static int e1000_set_settings(struct net_device *netdev, | |||
| 199 | ecmd->advertising = hw->autoneg_advertised; | 199 | ecmd->advertising = hw->autoneg_advertised; |
| 200 | } else { | 200 | } else { |
| 201 | u32 speed = ethtool_cmd_speed(ecmd); | 201 | u32 speed = ethtool_cmd_speed(ecmd); |
| 202 | if (e1000_set_spd_dplx(adapter, speed + ecmd->duplex)) { | 202 | if (e1000_set_spd_dplx(adapter, speed, ecmd->duplex)) { |
| 203 | clear_bit(__E1000_RESETTING, &adapter->flags); | 203 | clear_bit(__E1000_RESETTING, &adapter->flags); |
| 204 | return -EINVAL; | 204 | return -EINVAL; |
| 205 | } | 205 | } |
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 477e066a1cf0..c18cb8e883dd 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c | |||
| @@ -96,7 +96,6 @@ int e1000_up(struct e1000_adapter *adapter); | |||
| 96 | void e1000_down(struct e1000_adapter *adapter); | 96 | void e1000_down(struct e1000_adapter *adapter); |
| 97 | void e1000_reinit_locked(struct e1000_adapter *adapter); | 97 | void e1000_reinit_locked(struct e1000_adapter *adapter); |
| 98 | void e1000_reset(struct e1000_adapter *adapter); | 98 | void e1000_reset(struct e1000_adapter *adapter); |
| 99 | int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx); | ||
| 100 | int e1000_setup_all_tx_resources(struct e1000_adapter *adapter); | 99 | int e1000_setup_all_tx_resources(struct e1000_adapter *adapter); |
| 101 | int e1000_setup_all_rx_resources(struct e1000_adapter *adapter); | 100 | int e1000_setup_all_rx_resources(struct e1000_adapter *adapter); |
| 102 | void e1000_free_all_tx_resources(struct e1000_adapter *adapter); | 101 | void e1000_free_all_tx_resources(struct e1000_adapter *adapter); |
| @@ -4385,7 +4384,6 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, | |||
| 4385 | struct mii_ioctl_data *data = if_mii(ifr); | 4384 | struct mii_ioctl_data *data = if_mii(ifr); |
| 4386 | int retval; | 4385 | int retval; |
| 4387 | u16 mii_reg; | 4386 | u16 mii_reg; |
| 4388 | u16 spddplx; | ||
| 4389 | unsigned long flags; | 4387 | unsigned long flags; |
| 4390 | 4388 | ||
| 4391 | if (hw->media_type != e1000_media_type_copper) | 4389 | if (hw->media_type != e1000_media_type_copper) |
| @@ -4424,17 +4422,18 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, | |||
| 4424 | hw->autoneg = 1; | 4422 | hw->autoneg = 1; |
| 4425 | hw->autoneg_advertised = 0x2F; | 4423 | hw->autoneg_advertised = 0x2F; |
| 4426 | } else { | 4424 | } else { |
| 4425 | u32 speed; | ||
| 4427 | if (mii_reg & 0x40) | 4426 | if (mii_reg & 0x40) |
| 4428 | spddplx = SPEED_1000; | 4427 | speed = SPEED_1000; |
| 4429 | else if (mii_reg & 0x2000) | 4428 | else if (mii_reg & 0x2000) |
| 4430 | spddplx = SPEED_100; | 4429 | speed = SPEED_100; |
| 4431 | else | 4430 | else |
| 4432 | spddplx = SPEED_10; | 4431 | speed = SPEED_10; |
| 4433 | spddplx += (mii_reg & 0x100) | 4432 | retval = e1000_set_spd_dplx( |
| 4434 | ? DUPLEX_FULL : | 4433 | adapter, speed, |
| 4435 | DUPLEX_HALF; | 4434 | ((mii_reg & 0x100) |
| 4436 | retval = e1000_set_spd_dplx(adapter, | 4435 | ? DUPLEX_FULL : |
| 4437 | spddplx); | 4436 | DUPLEX_HALF)); |
| 4438 | if (retval) | 4437 | if (retval) |
| 4439 | return retval; | 4438 | return retval; |
| 4440 | } | 4439 | } |
| @@ -4596,20 +4595,24 @@ static void e1000_restore_vlan(struct e1000_adapter *adapter) | |||
| 4596 | } | 4595 | } |
| 4597 | } | 4596 | } |
| 4598 | 4597 | ||
| 4599 | int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) | 4598 | int e1000_set_spd_dplx(struct e1000_adapter *adapter, u32 spd, u8 dplx) |
| 4600 | { | 4599 | { |
| 4601 | struct e1000_hw *hw = &adapter->hw; | 4600 | struct e1000_hw *hw = &adapter->hw; |
| 4602 | 4601 | ||
| 4603 | hw->autoneg = 0; | 4602 | hw->autoneg = 0; |
| 4604 | 4603 | ||
| 4604 | /* Make sure dplx is at most 1 bit and lsb of speed is not set | ||
| 4605 | * for the switch() below to work */ | ||
| 4606 | if ((spd & 1) || (dplx & ~1)) | ||
| 4607 | goto err_inval; | ||
| 4608 | |||
| 4605 | /* Fiber NICs only allow 1000 gbps Full duplex */ | 4609 | /* Fiber NICs only allow 1000 gbps Full duplex */ |
| 4606 | if ((hw->media_type == e1000_media_type_fiber) && | 4610 | if ((hw->media_type == e1000_media_type_fiber) && |
| 4607 | spddplx != (SPEED_1000 + DUPLEX_FULL)) { | 4611 | spd != SPEED_1000 && |
| 4608 | e_err(probe, "Unsupported Speed/Duplex configuration\n"); | 4612 | dplx != DUPLEX_FULL) |
| 4609 | return -EINVAL; | 4613 | goto err_inval; |
| 4610 | } | ||
| 4611 | 4614 | ||
| 4612 | switch (spddplx) { | 4615 | switch (spd + dplx) { |
| 4613 | case SPEED_10 + DUPLEX_HALF: | 4616 | case SPEED_10 + DUPLEX_HALF: |
| 4614 | hw->forced_speed_duplex = e1000_10_half; | 4617 | hw->forced_speed_duplex = e1000_10_half; |
| 4615 | break; | 4618 | break; |
| @@ -4628,10 +4631,13 @@ int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) | |||
| 4628 | break; | 4631 | break; |
| 4629 | case SPEED_1000 + DUPLEX_HALF: /* not supported */ | 4632 | case SPEED_1000 + DUPLEX_HALF: /* not supported */ |
| 4630 | default: | 4633 | default: |
| 4631 | e_err(probe, "Unsupported Speed/Duplex configuration\n"); | 4634 | goto err_inval; |
| 4632 | return -EINVAL; | ||
| 4633 | } | 4635 | } |
| 4634 | return 0; | 4636 | return 0; |
| 4637 | |||
| 4638 | err_inval: | ||
| 4639 | e_err(probe, "Unsupported Speed/Duplex configuration\n"); | ||
| 4640 | return -EINVAL; | ||
| 4635 | } | 4641 | } |
| 4636 | 4642 | ||
| 4637 | static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) | 4643 | static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) |
