diff options
Diffstat (limited to 'drivers/net/e1000e/ethtool.c')
| -rw-r--r-- | drivers/net/e1000e/ethtool.c | 154 | 
1 files changed, 81 insertions, 73 deletions
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 07f09e96e45..859d0d3af6c 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -122,6 +122,7 @@ static int e1000_get_settings(struct net_device *netdev,  {  	struct e1000_adapter *adapter = netdev_priv(netdev);  	struct e1000_hw *hw = &adapter->hw; +	u32 speed;  	if (hw->phy.media_type == e1000_media_type_copper) { @@ -159,23 +160,23 @@ static int e1000_get_settings(struct net_device *netdev,  		ecmd->transceiver = XCVR_EXTERNAL;  	} -	ecmd->speed = -1; +	speed = -1;  	ecmd->duplex = -1;  	if (netif_running(netdev)) {  		if (netif_carrier_ok(netdev)) { -			ecmd->speed = adapter->link_speed; +			speed = adapter->link_speed;  			ecmd->duplex = adapter->link_duplex - 1;  		}  	} else {  		u32 status = er32(STATUS);  		if (status & E1000_STATUS_LU) {  			if (status & E1000_STATUS_SPEED_1000) -				ecmd->speed = 1000; +				speed = SPEED_1000;  			else if (status & E1000_STATUS_SPEED_100) -				ecmd->speed = 100; +				speed = SPEED_100;  			else -				ecmd->speed = 10; +				speed = SPEED_10;  			if (status & E1000_STATUS_FD)  				ecmd->duplex = DUPLEX_FULL; @@ -184,6 +185,7 @@ static int e1000_get_settings(struct net_device *netdev,  		}  	} +	ethtool_cmd_speed_set(ecmd, speed);  	ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) ||  			 hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE; @@ -198,20 +200,25 @@ static int e1000_get_settings(struct net_device *netdev,  	return 0;  } -static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) +static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u32 spd, u8 dplx)  {  	struct e1000_mac_info *mac = &adapter->hw.mac;  	mac->autoneg = 0; +	/* Make sure dplx is at most 1 bit and lsb of speed is not set +	 * for the switch() below to work */ +	if ((spd & 1) || (dplx & ~1)) +		goto err_inval; +  	/* Fiber NICs only allow 1000 gbps Full duplex */  	if ((adapter->hw.phy.media_type == e1000_media_type_fiber) && -		spddplx != (SPEED_1000 + DUPLEX_FULL)) { -		e_err("Unsupported Speed/Duplex configuration\n"); -		return -EINVAL; +	    spd != SPEED_1000 && +	    dplx != DUPLEX_FULL) { +		goto err_inval;  	} -	switch (spddplx) { +	switch (spd + dplx) {  	case SPEED_10 + DUPLEX_HALF:  		mac->forced_speed_duplex = ADVERTISE_10_HALF;  		break; @@ -230,10 +237,13 @@ static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx)  		break;  	case SPEED_1000 + DUPLEX_HALF: /* not supported */  	default: -		e_err("Unsupported Speed/Duplex configuration\n"); -		return -EINVAL; +		goto err_inval;  	}  	return 0; + +err_inval: +	e_err("Unsupported Speed/Duplex configuration\n"); +	return -EINVAL;  }  static int e1000_set_settings(struct net_device *netdev, @@ -253,7 +263,7 @@ static int e1000_set_settings(struct net_device *netdev,  	}  	while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) -		msleep(1); +		usleep_range(1000, 2000);  	if (ecmd->autoneg == AUTONEG_ENABLE) {  		hw->mac.autoneg = 1; @@ -269,7 +279,8 @@ static int e1000_set_settings(struct net_device *netdev,  		if (adapter->fc_autoneg)  			hw->fc.requested_mode = e1000_fc_default;  	} else { -		if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) { +		u32 speed = ethtool_cmd_speed(ecmd); +		if (e1000_set_spd_dplx(adapter, speed, ecmd->duplex)) {  			clear_bit(__E1000_RESETTING, &adapter->state);  			return -EINVAL;  		} @@ -317,7 +328,7 @@ static int e1000_set_pauseparam(struct net_device *netdev,  	adapter->fc_autoneg = pause->autoneg;  	while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) -		msleep(1); +		usleep_range(1000, 2000);  	if (adapter->fc_autoneg == AUTONEG_ENABLE) {  		hw->fc.requested_mode = e1000_fc_default; @@ -673,7 +684,7 @@ static int e1000_set_ringparam(struct net_device *netdev,  		return -EINVAL;  	while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) -		msleep(1); +		usleep_range(1000, 2000);  	if (netif_running(adapter->netdev))  		e1000e_down(adapter); @@ -952,7 +963,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)  	/* Disable all the interrupts */  	ew32(IMC, 0xFFFFFFFF); -	msleep(10); +	usleep_range(10000, 20000);  	/* Test each interrupt */  	for (i = 0; i < 10; i++) { @@ -984,7 +995,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)  			adapter->test_icr = 0;  			ew32(IMC, mask);  			ew32(ICS, mask); -			msleep(10); +			usleep_range(10000, 20000);  			if (adapter->test_icr & mask) {  				*data = 3; @@ -1002,7 +1013,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)  		adapter->test_icr = 0;  		ew32(IMS, mask);  		ew32(ICS, mask); -		msleep(10); +		usleep_range(10000, 20000);  		if (!(adapter->test_icr & mask)) {  			*data = 4; @@ -1020,7 +1031,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)  			adapter->test_icr = 0;  			ew32(IMC, ~mask & 0x00007FFF);  			ew32(ICS, ~mask & 0x00007FFF); -			msleep(10); +			usleep_range(10000, 20000);  			if (adapter->test_icr) {  				*data = 5; @@ -1031,7 +1042,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)  	/* Disable all the interrupts */  	ew32(IMC, 0xFFFFFFFF); -	msleep(10); +	usleep_range(10000, 20000);  	/* Unhook test interrupt handler */  	free_irq(irq, netdev); @@ -1406,7 +1417,7 @@ static int e1000_set_82571_fiber_loopback(struct e1000_adapter *adapter)  	 */  #define E1000_SERDES_LB_ON 0x410  	ew32(SCTL, E1000_SERDES_LB_ON); -	msleep(10); +	usleep_range(10000, 20000);  	return 0;  } @@ -1501,7 +1512,7 @@ static void e1000_loopback_cleanup(struct e1000_adapter *adapter)  		    hw->phy.media_type == e1000_media_type_internal_serdes) {  #define E1000_SERDES_LB_OFF 0x400  			ew32(SCTL, E1000_SERDES_LB_OFF); -			msleep(10); +			usleep_range(10000, 20000);  			break;  		}  		/* Fall Through */ @@ -1851,64 +1862,35 @@ static int e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)  	return 0;  } -/* toggle LED 4 times per second = 2 "blinks" per second */ -#define E1000_ID_INTERVAL	(HZ/4) - -/* bit defines for adapter->led_status */ -#define E1000_LED_ON		0 - -void e1000e_led_blink_task(struct work_struct *work) -{ -	struct e1000_adapter *adapter = container_of(work, -	                                struct e1000_adapter, led_blink_task); - -	if (test_and_change_bit(E1000_LED_ON, &adapter->led_status)) -		adapter->hw.mac.ops.led_off(&adapter->hw); -	else -		adapter->hw.mac.ops.led_on(&adapter->hw); -} - -static void e1000_led_blink_callback(unsigned long data) -{ -	struct e1000_adapter *adapter = (struct e1000_adapter *) data; - -	schedule_work(&adapter->led_blink_task); -	mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL); -} - -static int e1000_phys_id(struct net_device *netdev, u32 data) +static int e1000_set_phys_id(struct net_device *netdev, +			     enum ethtool_phys_id_state state)  {  	struct e1000_adapter *adapter = netdev_priv(netdev);  	struct e1000_hw *hw = &adapter->hw; -	if (!data) -		data = INT_MAX; +	switch (state) { +	case ETHTOOL_ID_ACTIVE: +		if (!hw->mac.ops.blink_led) +			return 2;	/* cycle on/off twice per second */ -	if ((hw->phy.type == e1000_phy_ife) || -	    (hw->mac.type == e1000_pchlan) || -	    (hw->mac.type == e1000_pch2lan) || -	    (hw->mac.type == e1000_82583) || -	    (hw->mac.type == e1000_82574)) { -		if (!adapter->blink_timer.function) { -			init_timer(&adapter->blink_timer); -			adapter->blink_timer.function = -				e1000_led_blink_callback; -			adapter->blink_timer.data = (unsigned long) adapter; -		} -		mod_timer(&adapter->blink_timer, jiffies); -		msleep_interruptible(data * 1000); -		del_timer_sync(&adapter->blink_timer); +		hw->mac.ops.blink_led(hw); +		break; + +	case ETHTOOL_ID_INACTIVE:  		if (hw->phy.type == e1000_phy_ife)  			e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0); -	} else { -		e1000e_blink_led(hw); -		msleep_interruptible(data * 1000); -	} +		hw->mac.ops.led_off(hw); +		hw->mac.ops.cleanup_led(hw); +		break; -	hw->mac.ops.led_off(hw); -	clear_bit(E1000_LED_ON, &adapter->led_status); -	hw->mac.ops.cleanup_led(hw); +	case ETHTOOL_ID_ON: +		adapter->hw.mac.ops.led_on(&adapter->hw); +		break; +	case ETHTOOL_ID_OFF: +		adapter->hw.mac.ops.led_off(&adapter->hw); +		break; +	}  	return 0;  } @@ -2020,6 +2002,31 @@ static void e1000_get_strings(struct net_device *netdev, u32 stringset,  	}  } +static int e1000e_set_flags(struct net_device *netdev, u32 data) +{ +	struct e1000_adapter *adapter = netdev_priv(netdev); +	bool need_reset = false; +	int rc; + +	need_reset = (data & ETH_FLAG_RXVLAN) != +		     (netdev->features & NETIF_F_HW_VLAN_RX); + +	rc = ethtool_op_set_flags(netdev, data, ETH_FLAG_RXVLAN | +				  ETH_FLAG_TXVLAN); + +	if (rc) +		return rc; + +	if (need_reset) { +		if (netif_running(netdev)) +			e1000e_reinit_locked(adapter); +		else +			e1000e_reset(adapter); +	} + +	return 0; +} +  static const struct ethtool_ops e1000_ethtool_ops = {  	.get_settings		= e1000_get_settings,  	.set_settings		= e1000_set_settings, @@ -2049,12 +2056,13 @@ static const struct ethtool_ops e1000_ethtool_ops = {  	.set_tso		= e1000_set_tso,  	.self_test		= e1000_diag_test,  	.get_strings		= e1000_get_strings, -	.phys_id		= e1000_phys_id, +	.set_phys_id		= e1000_set_phys_id,  	.get_ethtool_stats	= e1000_get_ethtool_stats,  	.get_sset_count		= e1000e_get_sset_count,  	.get_coalesce		= e1000_get_coalesce,  	.set_coalesce		= e1000_set_coalesce,  	.get_flags		= ethtool_op_get_flags, +	.set_flags		= e1000e_set_flags,  };  void e1000e_set_ethtool_ops(struct net_device *netdev)  |