aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/e1000
diff options
context:
space:
mode:
authorDavid Decotigny <decot@google.com>2011-04-27 14:32:43 -0400
committerDavid S. Miller <davem@davemloft.net>2011-04-29 17:03:03 -0400
commit14ad2513ed5b709e566a853f4b515d91c5d83311 (patch)
tree19ce2e6deefaa0725533612df85c51b99d2513cb /drivers/net/e1000
parentfbef7139a8b89a7f49ba1410593ed894b4c8b017 (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.h2
-rw-r--r--drivers/net/e1000/e1000_ethtool.c2
-rw-r--r--drivers/net/e1000/e1000_main.c42
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);
349extern void e1000_down(struct e1000_adapter *adapter); 349extern void e1000_down(struct e1000_adapter *adapter);
350extern void e1000_reinit_locked(struct e1000_adapter *adapter); 350extern void e1000_reinit_locked(struct e1000_adapter *adapter);
351extern void e1000_reset(struct e1000_adapter *adapter); 351extern void e1000_reset(struct e1000_adapter *adapter);
352extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx); 352extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, u32 spd, u8 dplx);
353extern int e1000_setup_all_rx_resources(struct e1000_adapter *adapter); 353extern int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);
354extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter); 354extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
355extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter); 355extern 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);
96void e1000_down(struct e1000_adapter *adapter); 96void e1000_down(struct e1000_adapter *adapter);
97void e1000_reinit_locked(struct e1000_adapter *adapter); 97void e1000_reinit_locked(struct e1000_adapter *adapter);
98void e1000_reset(struct e1000_adapter *adapter); 98void e1000_reset(struct e1000_adapter *adapter);
99int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx);
100int e1000_setup_all_tx_resources(struct e1000_adapter *adapter); 99int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
101int e1000_setup_all_rx_resources(struct e1000_adapter *adapter); 100int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);
102void e1000_free_all_tx_resources(struct e1000_adapter *adapter); 101void 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
4599int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) 4598int 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
4638err_inval:
4639 e_err(probe, "Unsupported Speed/Duplex configuration\n");
4640 return -EINVAL;
4635} 4641}
4636 4642
4637static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) 4643static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake)