diff options
Diffstat (limited to 'drivers/net/ethernet/intel/igb/igb_ethtool.c')
| -rw-r--r-- | drivers/net/ethernet/intel/igb/igb_ethtool.c | 382 | 
1 files changed, 253 insertions, 129 deletions
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index 48cbc833b05..c737d1f4083 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -1,29 +1,25 @@ -/******************************************************************************* - -  Intel(R) Gigabit Ethernet Linux driver -  Copyright(c) 2007-2013 Intel Corporation. - -  This program is free software; you can redistribute it and/or modify it -  under the terms and conditions of the GNU General Public License, -  version 2, as published by the Free Software Foundation. - -  This program is distributed in the hope it will be useful, but WITHOUT -  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for -  more details. - -  You should have received a copy of the GNU General Public License along with -  this program; if not, write to the Free Software Foundation, Inc., -  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - -  The full GNU General Public License is included in this distribution in -  the file called "COPYING". - -  Contact Information: -  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> -  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel(R) Gigabit Ethernet Linux driver + * Copyright(c) 2007-2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, see <http://www.gnu.org/licenses/>. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */  /* ethtool support for igb */ @@ -145,7 +141,9 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)  	struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;  	struct e1000_sfp_flags *eth_flags = &dev_spec->eth_flags;  	u32 status; +	u32 speed; +	status = rd32(E1000_STATUS);  	if (hw->phy.media_type == e1000_media_type_copper) {  		ecmd->supported = (SUPPORTED_10baseT_Half | @@ -169,13 +167,22 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)  		ecmd->transceiver = XCVR_INTERNAL;  	} else {  		ecmd->supported = (SUPPORTED_FIBRE | +				   SUPPORTED_1000baseKX_Full |  				   SUPPORTED_Autoneg |  				   SUPPORTED_Pause); -		ecmd->advertising = ADVERTISED_FIBRE; - -		if ((eth_flags->e1000_base_lx) || (eth_flags->e1000_base_sx)) { -			ecmd->supported |= SUPPORTED_1000baseT_Full; -			ecmd->advertising |= ADVERTISED_1000baseT_Full; +		ecmd->advertising = (ADVERTISED_FIBRE | +				     ADVERTISED_1000baseKX_Full); +		if (hw->mac.type == e1000_i354) { +			if ((hw->device_id == +			     E1000_DEV_ID_I354_BACKPLANE_2_5GBPS) && +			    !(status & E1000_STATUS_2P5_SKU_OVER)) { +				ecmd->supported |= SUPPORTED_2500baseX_Full; +				ecmd->supported &= +					~SUPPORTED_1000baseKX_Full; +				ecmd->advertising |= ADVERTISED_2500baseX_Full; +				ecmd->advertising &= +					~ADVERTISED_1000baseKX_Full; +			}  		}  		if (eth_flags->e100_base_fx) {  			ecmd->supported |= SUPPORTED_100baseT_Full; @@ -187,41 +194,35 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)  		ecmd->port = PORT_FIBRE;  		ecmd->transceiver = XCVR_EXTERNAL;  	} -  	if (hw->mac.autoneg != 1)  		ecmd->advertising &= ~(ADVERTISED_Pause |  				       ADVERTISED_Asym_Pause); -	if (hw->fc.requested_mode == e1000_fc_full) +	switch (hw->fc.requested_mode) { +	case e1000_fc_full:  		ecmd->advertising |= ADVERTISED_Pause; -	else if (hw->fc.requested_mode == e1000_fc_rx_pause) +		break; +	case e1000_fc_rx_pause:  		ecmd->advertising |= (ADVERTISED_Pause |  				      ADVERTISED_Asym_Pause); -	else if (hw->fc.requested_mode == e1000_fc_tx_pause) +		break; +	case e1000_fc_tx_pause:  		ecmd->advertising |=  ADVERTISED_Asym_Pause; -	else +		break; +	default:  		ecmd->advertising &= ~(ADVERTISED_Pause |  				       ADVERTISED_Asym_Pause); - -	status = rd32(E1000_STATUS); - +	}  	if (status & E1000_STATUS_LU) { -		if (hw->mac.type == e1000_i354) { -			if ((status & E1000_STATUS_2P5_SKU) && -			    !(status & E1000_STATUS_2P5_SKU_OVER)) { -				ecmd->supported = SUPPORTED_2500baseX_Full; -				ecmd->advertising = ADVERTISED_2500baseX_Full; -				ecmd->speed = SPEED_2500; -			} else { -				ecmd->supported = SUPPORTED_1000baseT_Full; -				ecmd->advertising = ADVERTISED_1000baseT_Full; -			} +		if ((status & E1000_STATUS_2P5_SKU) && +		    !(status & E1000_STATUS_2P5_SKU_OVER)) { +			speed = SPEED_2500;  		} else if (status & E1000_STATUS_SPEED_1000) { -			ecmd->speed = SPEED_1000; +			speed = SPEED_1000;  		} else if (status & E1000_STATUS_SPEED_100) { -			ecmd->speed = SPEED_100; +			speed = SPEED_100;  		} else { -			ecmd->speed = SPEED_10; +			speed = SPEED_10;  		}  		if ((status & E1000_STATUS_FD) ||  		    hw->phy.media_type != e1000_media_type_copper) @@ -229,10 +230,10 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)  		else  			ecmd->duplex = DUPLEX_HALF;  	} else { -		ecmd->speed = -1; -		ecmd->duplex = -1; +		speed = SPEED_UNKNOWN; +		ecmd->duplex = DUPLEX_UNKNOWN;  	} - +	ethtool_cmd_speed_set(ecmd, speed);  	if ((hw->phy.media_type == e1000_media_type_fiber) ||  	    hw->mac.autoneg)  		ecmd->autoneg = AUTONEG_ENABLE; @@ -284,7 +285,7 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)  	}  	while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) -		msleep(1); +		usleep_range(1000, 2000);  	if (ecmd->autoneg == AUTONEG_ENABLE) {  		hw->mac.autoneg = 1; @@ -397,7 +398,7 @@ static int igb_set_pauseparam(struct net_device *netdev,  	adapter->fc_autoneg = pause->autoneg;  	while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) -		msleep(1); +		usleep_range(1000, 2000);  	if (adapter->fc_autoneg == AUTONEG_ENABLE) {  		hw->fc.requested_mode = e1000_fc_default; @@ -771,8 +772,10 @@ static int igb_set_eeprom(struct net_device *netdev,  	if (eeprom->len == 0)  		return -EOPNOTSUPP; -	if (hw->mac.type == e1000_i211) +	if ((hw->mac.type >= e1000_i210) && +	    !igb_get_flash_presence_i210(hw)) {  		return -EOPNOTSUPP; +	}  	if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))  		return -EFAULT; @@ -882,7 +885,7 @@ static int igb_set_ringparam(struct net_device *netdev,  	}  	while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) -		msleep(1); +		usleep_range(1000, 2000);  	if (!netif_running(adapter->netdev)) {  		for (i = 0; i < adapter->num_tx_queues; i++) @@ -1056,8 +1059,8 @@ static struct igb_reg_test reg_test_i350[] = {  	{ E1000_TDT(0),	   0x100, 4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },  	{ E1000_TDT(4),	   0x40,  4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },  	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, -	{ E1000_RCTL, 	   0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB }, -	{ E1000_RCTL, 	   0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF }, +	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB }, +	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF },  	{ E1000_TCTL,	   0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },  	{ E1000_RA,	   0, 16, TABLE64_TEST_LO,  						0xFFFFFFFF, 0xFFFFFFFF }, @@ -1099,8 +1102,8 @@ static struct igb_reg_test reg_test_82580[] = {  	{ E1000_TDT(0),	   0x100, 4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },  	{ E1000_TDT(4),	   0x40,  4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },  	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, -	{ E1000_RCTL, 	   0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB }, -	{ E1000_RCTL, 	   0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF }, +	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB }, +	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF },  	{ E1000_TCTL,	   0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },  	{ E1000_RA,	   0, 16, TABLE64_TEST_LO,  						0xFFFFFFFF, 0xFFFFFFFF }, @@ -1128,8 +1131,10 @@ static struct igb_reg_test reg_test_82576[] = {  	{ E1000_RDBAH(4),  0x40, 12, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },  	{ E1000_RDLEN(4),  0x40, 12, PATTERN_TEST, 0x000FFFF0, 0x000FFFFF },  	/* Enable all RX queues before testing. */ -	{ E1000_RXDCTL(0), 0x100, 4,  WRITE_NO_TEST, 0, E1000_RXDCTL_QUEUE_ENABLE }, -	{ E1000_RXDCTL(4), 0x40, 12,  WRITE_NO_TEST, 0, E1000_RXDCTL_QUEUE_ENABLE }, +	{ E1000_RXDCTL(0), 0x100, 4, WRITE_NO_TEST, 0, +	  E1000_RXDCTL_QUEUE_ENABLE }, +	{ E1000_RXDCTL(4), 0x40, 12, WRITE_NO_TEST, 0, +	  E1000_RXDCTL_QUEUE_ENABLE },  	/* RDH is read-only for 82576, only test RDT. */  	{ E1000_RDT(0),	   0x100, 4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },  	{ E1000_RDT(4),	   0x40, 12,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, @@ -1145,14 +1150,14 @@ static struct igb_reg_test reg_test_82576[] = {  	{ E1000_TDBAH(4),  0x40, 12,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },  	{ E1000_TDLEN(4),  0x40, 12,  PATTERN_TEST, 0x000FFFF0, 0x000FFFFF },  	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, -	{ E1000_RCTL, 	   0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB }, -	{ E1000_RCTL, 	   0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF }, +	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB }, +	{ E1000_RCTL,	   0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF },  	{ E1000_TCTL,	   0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },  	{ E1000_RA,	   0, 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF },  	{ E1000_RA,	   0, 16, TABLE64_TEST_HI, 0x83FFFFFF, 0xFFFFFFFF },  	{ E1000_RA2,	   0, 8, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF },  	{ E1000_RA2,	   0, 8, TABLE64_TEST_HI, 0x83FFFFFF, 0xFFFFFFFF }, -	{ E1000_MTA,	   0, 128,TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, +	{ E1000_MTA,	   0, 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF },  	{ 0, 0, 0, 0 }  }; @@ -1166,7 +1171,8 @@ static struct igb_reg_test reg_test_82575[] = {  	{ E1000_RDBAH(0),  0x100, 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },  	{ E1000_RDLEN(0),  0x100, 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },  	/* Enable all four RX queues before testing. */ -	{ E1000_RXDCTL(0), 0x100, 4, WRITE_NO_TEST, 0, E1000_RXDCTL_QUEUE_ENABLE }, +	{ E1000_RXDCTL(0), 0x100, 4, WRITE_NO_TEST, 0, +	  E1000_RXDCTL_QUEUE_ENABLE },  	/* RDH is read-only for 82575, only test RDT. */  	{ E1000_RDT(0),    0x100, 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },  	{ E1000_RXDCTL(0), 0x100, 4, WRITE_NO_TEST, 0, 0 }, @@ -1192,8 +1198,8 @@ static bool reg_pattern_test(struct igb_adapter *adapter, u64 *data,  {  	struct e1000_hw *hw = &adapter->hw;  	u32 pat, val; -	static const u32 _test[] = -		{0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; +	static const u32 _test[] = { +		0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};  	for (pat = 0; pat < ARRAY_SIZE(_test); pat++) {  		wr32(reg, (_test[pat] & write));  		val = rd32(reg) & mask; @@ -1202,11 +1208,11 @@ static bool reg_pattern_test(struct igb_adapter *adapter, u64 *data,  				"pattern test reg %04X failed: got 0x%08X expected 0x%08X\n",  				reg, val, (_test[pat] & write & mask));  			*data = reg; -			return 1; +			return true;  		}  	} -	return 0; +	return false;  }  static bool reg_set_and_check(struct igb_adapter *adapter, u64 *data, @@ -1214,17 +1220,18 @@ static bool reg_set_and_check(struct igb_adapter *adapter, u64 *data,  {  	struct e1000_hw *hw = &adapter->hw;  	u32 val; +  	wr32(reg, write & mask);  	val = rd32(reg);  	if ((write & mask) != (val & mask)) {  		dev_err(&adapter->pdev->dev, -			"set/check reg %04X test failed: got 0x%08X expected 0x%08X\n", reg, -			(val & mask), (write & mask)); +			"set/check reg %04X test failed: got 0x%08X expected 0x%08X\n", +			reg, (val & mask), (write & mask));  		*data = reg; -		return 1; +		return true;  	} -	return 0; +	return false;  }  #define REG_PATTERN_TEST(reg, mask, write) \ @@ -1381,16 +1388,16 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)  	*data = 0;  	/* Hook up test interrupt handler just for this test */ -	if (adapter->msix_entries) { +	if (adapter->flags & IGB_FLAG_HAS_MSIX) {  		if (request_irq(adapter->msix_entries[0].vector, -		                igb_test_intr, 0, netdev->name, adapter)) { +				igb_test_intr, 0, netdev->name, adapter)) {  			*data = 1;  			return -1;  		}  	} else if (adapter->flags & IGB_FLAG_HAS_MSI) {  		shared_int = false;  		if (request_irq(irq, -		                igb_test_intr, 0, netdev->name, adapter)) { +				igb_test_intr, 0, netdev->name, adapter)) {  			*data = 1;  			return -1;  		} @@ -1408,7 +1415,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)  	/* Disable all the interrupts */  	wr32(E1000_IMC, ~0);  	wrfl(); -	msleep(10); +	usleep_range(10000, 11000);  	/* Define all writable bits for ICS */  	switch (hw->mac.type) { @@ -1455,7 +1462,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)  			wr32(E1000_IMC, mask);  			wr32(E1000_ICS, mask);  			wrfl(); -			msleep(10); +			usleep_range(10000, 11000);  			if (adapter->test_icr & mask) {  				*data = 3; @@ -1477,7 +1484,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)  		wr32(E1000_IMS, mask);  		wr32(E1000_ICS, mask);  		wrfl(); -		msleep(10); +		usleep_range(10000, 11000);  		if (!(adapter->test_icr & mask)) {  			*data = 4; @@ -1499,7 +1506,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)  			wr32(E1000_IMC, ~mask);  			wr32(E1000_ICS, ~mask);  			wrfl(); -			msleep(10); +			usleep_range(10000, 11000);  			if (adapter->test_icr & mask) {  				*data = 5; @@ -1511,10 +1518,10 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)  	/* Disable all the interrupts */  	wr32(E1000_IMC, ~0);  	wrfl(); -	msleep(10); +	usleep_range(10000, 11000);  	/* Unhook test interrupt handler */ -	if (adapter->msix_entries) +	if (adapter->flags & IGB_FLAG_HAS_MSIX)  		free_irq(adapter->msix_entries[0].vector, adapter);  	else  		free_irq(irq, adapter); @@ -1607,6 +1614,9 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter)  			igb_write_phy_reg(hw, I347AT4_PAGE_SELECT, 0);  			igb_write_phy_reg(hw, PHY_CONTROL, 0x4140);  		} +	} else if (hw->phy.type == e1000_phy_82580) { +		/* enable MII loopback */ +		igb_write_phy_reg(hw, I82580_PHY_LBK_CTRL, 0x8041);  	}  	/* add small delay to avoid loopback test failure */ @@ -1656,8 +1666,9 @@ static int igb_setup_loopback_test(struct igb_adapter *adapter)  		if ((hw->device_id == E1000_DEV_ID_DH89XXCC_SGMII) ||  		(hw->device_id == E1000_DEV_ID_DH89XXCC_SERDES) ||  		(hw->device_id == E1000_DEV_ID_DH89XXCC_BACKPLANE) || -		(hw->device_id == E1000_DEV_ID_DH89XXCC_SFP)) { - +		(hw->device_id == E1000_DEV_ID_DH89XXCC_SFP) || +		(hw->device_id == E1000_DEV_ID_I354_SGMII) || +		(hw->device_id == E1000_DEV_ID_I354_BACKPLANE_2_5GBPS)) {  			/* Enable DH89xxCC MPHY for near end loopback */  			reg = rd32(E1000_MPHY_ADDR_CTL);  			reg = (reg & E1000_MPHY_ADDR_CTL_OFFSET_MASK) | @@ -1722,7 +1733,8 @@ static void igb_loopback_cleanup(struct igb_adapter *adapter)  	if ((hw->device_id == E1000_DEV_ID_DH89XXCC_SGMII) ||  	(hw->device_id == E1000_DEV_ID_DH89XXCC_SERDES) ||  	(hw->device_id == E1000_DEV_ID_DH89XXCC_BACKPLANE) || -	(hw->device_id == E1000_DEV_ID_DH89XXCC_SFP)) { +	(hw->device_id == E1000_DEV_ID_DH89XXCC_SFP) || +	(hw->device_id == E1000_DEV_ID_I354_SGMII)) {  		u32 reg;  		/* Disable near end loopback on DH89xxCC */ @@ -1940,6 +1952,7 @@ static int igb_link_test(struct igb_adapter *adapter, u64 *data)  	*data = 0;  	if (hw->phy.media_type == e1000_media_type_internal_serdes) {  		int i = 0; +  		hw->mac.serdes_has_link = false;  		/* On some blade server designs, link establishment @@ -1973,6 +1986,10 @@ static void igb_diag_test(struct net_device *netdev,  	bool if_running = netif_running(netdev);  	set_bit(__IGB_TESTING, &adapter->state); + +	/* can't do offline tests on media switching devices */ +	if (adapter->hw.dev_spec._82575.mas_capable) +		eth_test->flags &= ~ETH_TEST_FL_OFFLINE;  	if (eth_test->flags == ETH_TEST_FL_OFFLINE) {  		/* Offline tests */ @@ -2052,14 +2069,15 @@ static void igb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)  {  	struct igb_adapter *adapter = netdev_priv(netdev); -	wol->supported = WAKE_UCAST | WAKE_MCAST | -			 WAKE_BCAST | WAKE_MAGIC | -			 WAKE_PHY;  	wol->wolopts = 0;  	if (!(adapter->flags & IGB_FLAG_WOL_SUPPORTED))  		return; +	wol->supported = WAKE_UCAST | WAKE_MCAST | +			 WAKE_BCAST | WAKE_MAGIC | +			 WAKE_PHY; +  	/* apply any specific unsupported masks here */  	switch (adapter->hw.device_id) {  	default: @@ -2259,15 +2277,15 @@ static void igb_get_ethtool_stats(struct net_device *netdev,  		ring = adapter->tx_ring[j];  		do { -			start = u64_stats_fetch_begin_bh(&ring->tx_syncp); +			start = u64_stats_fetch_begin_irq(&ring->tx_syncp);  			data[i]   = ring->tx_stats.packets;  			data[i+1] = ring->tx_stats.bytes;  			data[i+2] = ring->tx_stats.restart_queue; -		} while (u64_stats_fetch_retry_bh(&ring->tx_syncp, start)); +		} while (u64_stats_fetch_retry_irq(&ring->tx_syncp, start));  		do { -			start = u64_stats_fetch_begin_bh(&ring->tx_syncp2); +			start = u64_stats_fetch_begin_irq(&ring->tx_syncp2);  			restart2  = ring->tx_stats.restart_queue2; -		} while (u64_stats_fetch_retry_bh(&ring->tx_syncp2, start)); +		} while (u64_stats_fetch_retry_irq(&ring->tx_syncp2, start));  		data[i+2] += restart2;  		i += IGB_TX_QUEUE_STATS_LEN; @@ -2275,13 +2293,13 @@ static void igb_get_ethtool_stats(struct net_device *netdev,  	for (j = 0; j < adapter->num_rx_queues; j++) {  		ring = adapter->rx_ring[j];  		do { -			start = u64_stats_fetch_begin_bh(&ring->rx_syncp); +			start = u64_stats_fetch_begin_irq(&ring->rx_syncp);  			data[i]   = ring->rx_stats.packets;  			data[i+1] = ring->rx_stats.bytes;  			data[i+2] = ring->rx_stats.drops;  			data[i+3] = ring->rx_stats.csum_err;  			data[i+4] = ring->rx_stats.alloc_failed; -		} while (u64_stats_fetch_retry_bh(&ring->rx_syncp, start)); +		} while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start));  		i += IGB_RX_QUEUE_STATS_LEN;  	}  	spin_unlock(&adapter->stats64_lock); @@ -2339,6 +2357,11 @@ static int igb_get_ts_info(struct net_device *dev,  {  	struct igb_adapter *adapter = netdev_priv(dev); +	if (adapter->ptp_clock) +		info->phc_index = ptp_clock_index(adapter->ptp_clock); +	else +		info->phc_index = -1; +  	switch (adapter->hw.mac.type) {  	case e1000_82575:  		info->so_timestamping = @@ -2360,11 +2383,6 @@ static int igb_get_ts_info(struct net_device *dev,  			SOF_TIMESTAMPING_RX_HARDWARE |  			SOF_TIMESTAMPING_RAW_HARDWARE; -		if (adapter->ptp_clock) -			info->phc_index = ptp_clock_index(adapter->ptp_clock); -		else -			info->phc_index = -1; -  		info->tx_types =  			(1 << HWTSTAMP_TX_OFF) |  			(1 << HWTSTAMP_TX_ON); @@ -2399,9 +2417,11 @@ static int igb_get_rss_hash_opts(struct igb_adapter *adapter,  	switch (cmd->flow_type) {  	case TCP_V4_FLOW:  		cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; +		/* Fall through */  	case UDP_V4_FLOW:  		if (adapter->flags & IGB_FLAG_RSS_FIELD_IPV4_UDP)  			cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; +		/* Fall through */  	case SCTP_V4_FLOW:  	case AH_ESP_V4_FLOW:  	case AH_V4_FLOW: @@ -2411,9 +2431,11 @@ static int igb_get_rss_hash_opts(struct igb_adapter *adapter,  		break;  	case TCP_V6_FLOW:  		cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; +		/* Fall through */  	case UDP_V6_FLOW:  		if (adapter->flags & IGB_FLAG_RSS_FIELD_IPV6_UDP)  			cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; +		/* Fall through */  	case SCTP_V6_FLOW:  	case AH_ESP_V6_FLOW:  	case AH_V6_FLOW: @@ -2573,7 +2595,7 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata)  {  	struct igb_adapter *adapter = netdev_priv(netdev);  	struct e1000_hw *hw = &adapter->hw; -	u32 ipcnfg, eeer, ret_val; +	u32 ret_val;  	u16 phy_data;  	if ((hw->mac.type < e1000_i350) || @@ -2582,16 +2604,25 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata)  	edata->supported = (SUPPORTED_1000baseT_Full |  			    SUPPORTED_100baseT_Full); +	if (!hw->dev_spec._82575.eee_disable) +		edata->advertised = +			mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert); -	ipcnfg = rd32(E1000_IPCNFG); -	eeer = rd32(E1000_EEER); +	/* The IPCNFG and EEER registers are not supported on I354. */ +	if (hw->mac.type == e1000_i354) { +		igb_get_eee_status_i354(hw, (bool *)&edata->eee_active); +	} else { +		u32 eeer; + +		eeer = rd32(E1000_EEER); -	/* EEE status on negotiated link */ -	if (ipcnfg & E1000_IPCNFG_EEE_1G_AN) -		edata->advertised = ADVERTISED_1000baseT_Full; +		/* EEE status on negotiated link */ +		if (eeer & E1000_EEER_EEE_NEG) +			edata->eee_active = true; -	if (ipcnfg & E1000_IPCNFG_EEE_100M_AN) -		edata->advertised |= ADVERTISED_100baseT_Full; +		if (eeer & E1000_EEER_TX_LPI_EN) +			edata->tx_lpi_enabled = true; +	}  	/* EEE Link Partner Advertised */  	switch (hw->mac.type) { @@ -2602,8 +2633,8 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata)  			return -ENODATA;  		edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data); -  		break; +	case e1000_i354:  	case e1000_i210:  	case e1000_i211:  		ret_val = igb_read_xmdio_reg(hw, E1000_EEE_LP_ADV_ADDR_I210, @@ -2619,12 +2650,10 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata)  		break;  	} -	if (eeer & E1000_EEER_EEE_NEG) -		edata->eee_active = true; -  	edata->eee_enabled = !hw->dev_spec._82575.eee_disable; -	if (eeer & E1000_EEER_TX_LPI_EN) +	if ((hw->mac.type == e1000_i354) && +	    (edata->eee_enabled))  		edata->tx_lpi_enabled = true;  	/* Report correct negotiated EEE status for devices that @@ -2652,6 +2681,8 @@ static int igb_set_eee(struct net_device *netdev,  	    (hw->phy.media_type != e1000_media_type_copper))  		return -EOPNOTSUPP; +	memset(&eee_curr, 0, sizeof(struct ethtool_eee)); +  	ret_val = igb_get_eee(netdev, &eee_curr);  	if (ret_val)  		return ret_val; @@ -2670,9 +2701,10 @@ static int igb_set_eee(struct net_device *netdev,  			return -EINVAL;  		} -		if (eee_curr.advertised != edata->advertised) { +		if (edata->advertised & +		    ~(ADVERTISE_100_FULL | ADVERTISE_1000_FULL)) {  			dev_err(&adapter->pdev->dev, -				"Setting EEE Advertisement is not supported\n"); +				"EEE Advertisement supports only 100Tx and or 100T full duplex\n");  			return -EINVAL;  		} @@ -2682,9 +2714,14 @@ static int igb_set_eee(struct net_device *netdev,  			return -EINVAL;  		} +	adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised);  	if (hw->dev_spec._82575.eee_disable != !edata->eee_enabled) {  		hw->dev_spec._82575.eee_disable = !edata->eee_enabled; -		igb_set_eee_i350(hw); +		adapter->flags |= IGB_FLAG_EEE; +		if (hw->mac.type == e1000_i350) +			igb_set_eee_i350(hw); +		else +			igb_set_eee_i354(hw);  		/* reset link */  		if (netif_running(netdev)) @@ -2701,7 +2738,7 @@ static int igb_get_module_info(struct net_device *netdev,  {  	struct igb_adapter *adapter = netdev_priv(netdev);  	struct e1000_hw *hw = &adapter->hw; -	u32 status = E1000_SUCCESS; +	u32 status = 0;  	u16 sff8472_rev, addr_mode;  	bool page_swap = false; @@ -2711,12 +2748,12 @@ static int igb_get_module_info(struct net_device *netdev,  	/* Check whether we support SFF-8472 or not */  	status = igb_read_phy_reg_i2c(hw, IGB_SFF_8472_COMP, &sff8472_rev); -	if (status != E1000_SUCCESS) +	if (status)  		return -EIO;  	/* addressing mode is not supported */  	status = igb_read_phy_reg_i2c(hw, IGB_SFF_8472_SWAP, &addr_mode); -	if (status != E1000_SUCCESS) +	if (status)  		return -EIO;  	/* addressing mode is not supported */ @@ -2743,7 +2780,7 @@ static int igb_get_module_eeprom(struct net_device *netdev,  {  	struct igb_adapter *adapter = netdev_priv(netdev);  	struct e1000_hw *hw = &adapter->hw; -	u32 status = E1000_SUCCESS; +	u32 status = 0;  	u16 *dataword;  	u16 first_word, last_word;  	int i = 0; @@ -2762,9 +2799,11 @@ static int igb_get_module_eeprom(struct net_device *netdev,  	/* Read EEPROM block, SFF-8079/SFF-8472, word at a time */  	for (i = 0; i < last_word - first_word + 1; i++) {  		status = igb_read_phy_reg_i2c(hw, first_word + i, &dataword[i]); -		if (status != E1000_SUCCESS) +		if (status) {  			/* Error occurred while reading module */ +			kfree(dataword);  			return -EIO; +		}  		be16_to_cpus(&dataword[i]);  	} @@ -2793,7 +2832,7 @@ static u32 igb_get_rxfh_indir_size(struct net_device *netdev)  	return IGB_RETA_SIZE;  } -static int igb_get_rxfh_indir(struct net_device *netdev, u32 *indir) +static int igb_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key)  {  	struct igb_adapter *adapter = netdev_priv(netdev);  	int i; @@ -2839,7 +2878,8 @@ void igb_write_rss_indir_tbl(struct igb_adapter *adapter)  	}  } -static int igb_set_rxfh_indir(struct net_device *netdev, const u32 *indir) +static int igb_set_rxfh(struct net_device *netdev, const u32 *indir, +			const u8 *key)  {  	struct igb_adapter *adapter = netdev_priv(netdev);  	struct e1000_hw *hw = &adapter->hw; @@ -2872,6 +2912,88 @@ static int igb_set_rxfh_indir(struct net_device *netdev, const u32 *indir)  	return 0;  } +static unsigned int igb_max_channels(struct igb_adapter *adapter) +{ +	struct e1000_hw *hw = &adapter->hw; +	unsigned int max_combined = 0; + +	switch (hw->mac.type) { +	case e1000_i211: +		max_combined = IGB_MAX_RX_QUEUES_I211; +		break; +	case e1000_82575: +	case e1000_i210: +		max_combined = IGB_MAX_RX_QUEUES_82575; +		break; +	case e1000_i350: +		if (!!adapter->vfs_allocated_count) { +			max_combined = 1; +			break; +		} +		/* fall through */ +	case e1000_82576: +		if (!!adapter->vfs_allocated_count) { +			max_combined = 2; +			break; +		} +		/* fall through */ +	case e1000_82580: +	case e1000_i354: +	default: +		max_combined = IGB_MAX_RX_QUEUES; +		break; +	} + +	return max_combined; +} + +static void igb_get_channels(struct net_device *netdev, +			     struct ethtool_channels *ch) +{ +	struct igb_adapter *adapter = netdev_priv(netdev); + +	/* Report maximum channels */ +	ch->max_combined = igb_max_channels(adapter); + +	/* Report info for other vector */ +	if (adapter->flags & IGB_FLAG_HAS_MSIX) { +		ch->max_other = NON_Q_VECTORS; +		ch->other_count = NON_Q_VECTORS; +	} + +	ch->combined_count = adapter->rss_queues; +} + +static int igb_set_channels(struct net_device *netdev, +			    struct ethtool_channels *ch) +{ +	struct igb_adapter *adapter = netdev_priv(netdev); +	unsigned int count = ch->combined_count; + +	/* Verify they are not requesting separate vectors */ +	if (!count || ch->rx_count || ch->tx_count) +		return -EINVAL; + +	/* Verify other_count is valid and has not been changed */ +	if (ch->other_count != NON_Q_VECTORS) +		return -EINVAL; + +	/* Verify the number of channels doesn't exceed hw limits */ +	if (count > igb_max_channels(adapter)) +		return -EINVAL; + +	if (count != adapter->rss_queues) { +		adapter->rss_queues = count; + +		/* Hardware has to reinitialize queues and interrupts to +		 * match the new configuration. +		 */ +		return igb_reinit_queues(adapter); +	} + +	return 0; +} +  static const struct ethtool_ops igb_ethtool_ops = {  	.get_settings		= igb_get_settings,  	.set_settings		= igb_set_settings, @@ -2906,13 +3028,15 @@ static const struct ethtool_ops igb_ethtool_ops = {  	.get_module_info	= igb_get_module_info,  	.get_module_eeprom	= igb_get_module_eeprom,  	.get_rxfh_indir_size	= igb_get_rxfh_indir_size, -	.get_rxfh_indir		= igb_get_rxfh_indir, -	.set_rxfh_indir		= igb_set_rxfh_indir, +	.get_rxfh		= igb_get_rxfh, +	.set_rxfh		= igb_set_rxfh, +	.get_channels		= igb_get_channels, +	.set_channels		= igb_set_channels,  	.begin			= igb_ethtool_begin,  	.complete		= igb_ethtool_complete,  };  void igb_set_ethtool_ops(struct net_device *netdev)  { -	SET_ETHTOOL_OPS(netdev, &igb_ethtool_ops); +	netdev->ethtool_ops = &igb_ethtool_ops;  }  | 
