| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | /*******************************************************************************
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver | 
					
						
							| 
									
										
										
										
											2014-02-20 19:29:12 -08:00
										 |  |  |  * Copyright(c) 2013 - 2014 Intel Corporation. | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * 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. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2014-04-05 07:46:11 +00:00
										 |  |  |  * You should have received a copy of the GNU General Public License along | 
					
						
							|  |  |  |  * with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  |  * 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 i40evf */ | 
					
						
							|  |  |  | #include "i40evf.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/uaccess.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct i40evf_stats { | 
					
						
							|  |  |  | 	char stat_string[ETH_GSTRING_LEN]; | 
					
						
							|  |  |  | 	int stat_offset; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define I40EVF_STAT(_name, _stat) { \
 | 
					
						
							|  |  |  | 	.stat_string = _name, \ | 
					
						
							|  |  |  | 	.stat_offset = offsetof(struct i40evf_adapter, _stat) \ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* All stats are u64, so we don't need to track the size of the field. */ | 
					
						
							|  |  |  | static const struct i40evf_stats i40evf_gstrings_stats[] = { | 
					
						
							|  |  |  | 	I40EVF_STAT("rx_bytes", current_stats.rx_bytes), | 
					
						
							|  |  |  | 	I40EVF_STAT("rx_unicast", current_stats.rx_unicast), | 
					
						
							|  |  |  | 	I40EVF_STAT("rx_multicast", current_stats.rx_multicast), | 
					
						
							|  |  |  | 	I40EVF_STAT("rx_broadcast", current_stats.rx_broadcast), | 
					
						
							|  |  |  | 	I40EVF_STAT("rx_discards", current_stats.rx_discards), | 
					
						
							|  |  |  | 	I40EVF_STAT("rx_unknown_protocol", current_stats.rx_unknown_protocol), | 
					
						
							|  |  |  | 	I40EVF_STAT("tx_bytes", current_stats.tx_bytes), | 
					
						
							|  |  |  | 	I40EVF_STAT("tx_unicast", current_stats.tx_unicast), | 
					
						
							|  |  |  | 	I40EVF_STAT("tx_multicast", current_stats.tx_multicast), | 
					
						
							|  |  |  | 	I40EVF_STAT("tx_broadcast", current_stats.tx_broadcast), | 
					
						
							|  |  |  | 	I40EVF_STAT("tx_discards", current_stats.tx_discards), | 
					
						
							|  |  |  | 	I40EVF_STAT("tx_errors", current_stats.tx_errors), | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define I40EVF_GLOBAL_STATS_LEN ARRAY_SIZE(i40evf_gstrings_stats)
 | 
					
						
							| 
									
										
										
										
											2014-04-04 04:43:08 +00:00
										 |  |  | #define I40EVF_QUEUE_STATS_LEN(_dev) \
 | 
					
						
							| 
									
										
										
										
											2014-11-11 20:02:42 +00:00
										 |  |  | 	(((struct i40evf_adapter *)\ | 
					
						
							| 
									
										
										
										
											2014-10-25 03:24:34 +00:00
										 |  |  | 		netdev_priv(_dev))->num_active_queues \ | 
					
						
							| 
									
										
										
										
											2014-04-04 04:43:08 +00:00
										 |  |  | 		  * 2 * (sizeof(struct i40e_queue_stats) / sizeof(u64))) | 
					
						
							|  |  |  | #define I40EVF_STATS_LEN(_dev) \
 | 
					
						
							|  |  |  | 	(I40EVF_GLOBAL_STATS_LEN + I40EVF_QUEUE_STATS_LEN(_dev)) | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * i40evf_get_settings - Get Link Speed and Duplex settings | 
					
						
							|  |  |  |  * @netdev: network interface device structure | 
					
						
							|  |  |  |  * @ecmd: ethtool command | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Reports speed/duplex settings. Because this is a VF, we don't know what | 
					
						
							|  |  |  |  * kind of link we really have, so we fake it. | 
					
						
							|  |  |  |  **/ | 
					
						
							|  |  |  | static int i40evf_get_settings(struct net_device *netdev, | 
					
						
							|  |  |  | 			       struct ethtool_cmd *ecmd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* In the future the VF will be able to query the PF for
 | 
					
						
							|  |  |  | 	 * some information - for now use a dummy value | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2014-04-04 04:43:09 +00:00
										 |  |  | 	ecmd->supported = 0; | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | 	ecmd->autoneg = AUTONEG_DISABLE; | 
					
						
							|  |  |  | 	ecmd->transceiver = XCVR_DUMMY1; | 
					
						
							|  |  |  | 	ecmd->port = PORT_NONE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * i40evf_get_sset_count - Get length of string set | 
					
						
							|  |  |  |  * @netdev: network interface device structure | 
					
						
							|  |  |  |  * @sset: id of string set | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Reports size of string table. This driver only supports | 
					
						
							|  |  |  |  * strings for statistics. | 
					
						
							|  |  |  |  **/ | 
					
						
							|  |  |  | static int i40evf_get_sset_count(struct net_device *netdev, int sset) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (sset == ETH_SS_STATS) | 
					
						
							| 
									
										
										
										
											2014-04-04 04:43:08 +00:00
										 |  |  | 		return I40EVF_STATS_LEN(netdev); | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2014-04-04 04:43:08 +00:00
										 |  |  | 		return -EINVAL; | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * i40evf_get_ethtool_stats - report device statistics | 
					
						
							|  |  |  |  * @netdev: network interface device structure | 
					
						
							|  |  |  |  * @stats: ethtool statistics structure | 
					
						
							|  |  |  |  * @data: pointer to data buffer | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * All statistics are added to the data buffer as an array of u64. | 
					
						
							|  |  |  |  **/ | 
					
						
							|  |  |  | static void i40evf_get_ethtool_stats(struct net_device *netdev, | 
					
						
							|  |  |  | 				     struct ethtool_stats *stats, u64 *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct i40evf_adapter *adapter = netdev_priv(netdev); | 
					
						
							|  |  |  | 	int i, j; | 
					
						
							|  |  |  | 	char *p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < I40EVF_GLOBAL_STATS_LEN; i++) { | 
					
						
							|  |  |  | 		p = (char *)adapter + i40evf_gstrings_stats[i].stat_offset; | 
					
						
							|  |  |  | 		data[i] =  *(u64 *)p; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-10-25 03:24:34 +00:00
										 |  |  | 	for (j = 0; j < adapter->num_active_queues; j++) { | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | 		data[i++] = adapter->tx_rings[j]->stats.packets; | 
					
						
							|  |  |  | 		data[i++] = adapter->tx_rings[j]->stats.bytes; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-10-25 03:24:34 +00:00
										 |  |  | 	for (j = 0; j < adapter->num_active_queues; j++) { | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | 		data[i++] = adapter->rx_rings[j]->stats.packets; | 
					
						
							|  |  |  | 		data[i++] = adapter->rx_rings[j]->stats.bytes; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * i40evf_get_strings - Get string set | 
					
						
							|  |  |  |  * @netdev: network interface device structure | 
					
						
							|  |  |  |  * @sset: id of string set | 
					
						
							|  |  |  |  * @data: buffer for string data | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Builds stats string table. | 
					
						
							|  |  |  |  **/ | 
					
						
							|  |  |  | static void i40evf_get_strings(struct net_device *netdev, u32 sset, u8 *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct i40evf_adapter *adapter = netdev_priv(netdev); | 
					
						
							|  |  |  | 	u8 *p = data; | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (sset == ETH_SS_STATS) { | 
					
						
							|  |  |  | 		for (i = 0; i < I40EVF_GLOBAL_STATS_LEN; i++) { | 
					
						
							|  |  |  | 			memcpy(p, i40evf_gstrings_stats[i].stat_string, | 
					
						
							|  |  |  | 			       ETH_GSTRING_LEN); | 
					
						
							|  |  |  | 			p += ETH_GSTRING_LEN; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-10-25 03:24:34 +00:00
										 |  |  | 		for (i = 0; i < adapter->num_active_queues; i++) { | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | 			snprintf(p, ETH_GSTRING_LEN, "tx-%u.packets", i); | 
					
						
							|  |  |  | 			p += ETH_GSTRING_LEN; | 
					
						
							|  |  |  | 			snprintf(p, ETH_GSTRING_LEN, "tx-%u.bytes", i); | 
					
						
							|  |  |  | 			p += ETH_GSTRING_LEN; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-10-25 03:24:34 +00:00
										 |  |  | 		for (i = 0; i < adapter->num_active_queues; i++) { | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | 			snprintf(p, ETH_GSTRING_LEN, "rx-%u.packets", i); | 
					
						
							|  |  |  | 			p += ETH_GSTRING_LEN; | 
					
						
							|  |  |  | 			snprintf(p, ETH_GSTRING_LEN, "rx-%u.bytes", i); | 
					
						
							|  |  |  | 			p += ETH_GSTRING_LEN; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * i40evf_get_msglevel - Get debug message level | 
					
						
							|  |  |  |  * @netdev: network interface device structure | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Returns current debug message level. | 
					
						
							|  |  |  |  **/ | 
					
						
							|  |  |  | static u32 i40evf_get_msglevel(struct net_device *netdev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct i40evf_adapter *adapter = netdev_priv(netdev); | 
					
						
							| 
									
										
										
										
											2014-11-11 20:02:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | 	return adapter->msg_enable; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * i40evf_get_msglevel - Set debug message level | 
					
						
							|  |  |  |  * @netdev: network interface device structure | 
					
						
							|  |  |  |  * @data: message level | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Set current debug message level. Higher values cause the driver to | 
					
						
							|  |  |  |  * be noisier. | 
					
						
							|  |  |  |  **/ | 
					
						
							|  |  |  | static void i40evf_set_msglevel(struct net_device *netdev, u32 data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct i40evf_adapter *adapter = netdev_priv(netdev); | 
					
						
							| 
									
										
										
										
											2014-11-11 20:02:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | 	adapter->msg_enable = data; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2014-08-01 13:27:08 -07:00
										 |  |  |  * i40evf_get_drvinfo - Get driver info | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  |  * @netdev: network interface device structure | 
					
						
							|  |  |  |  * @drvinfo: ethool driver info structure | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Returns information about the driver and device for display to the user. | 
					
						
							|  |  |  |  **/ | 
					
						
							|  |  |  | static void i40evf_get_drvinfo(struct net_device *netdev, | 
					
						
							|  |  |  | 			       struct ethtool_drvinfo *drvinfo) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct i40evf_adapter *adapter = netdev_priv(netdev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	strlcpy(drvinfo->driver, i40evf_driver_name, 32); | 
					
						
							|  |  |  | 	strlcpy(drvinfo->version, i40evf_driver_version, 32); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * i40evf_get_ringparam - Get ring parameters | 
					
						
							|  |  |  |  * @netdev: network interface device structure | 
					
						
							|  |  |  |  * @ring: ethtool ringparam structure | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Returns current ring parameters. TX and RX rings are reported separately, | 
					
						
							|  |  |  |  * but the number of rings is not reported. | 
					
						
							|  |  |  |  **/ | 
					
						
							|  |  |  | static void i40evf_get_ringparam(struct net_device *netdev, | 
					
						
							| 
									
										
										
										
											2014-11-11 20:02:42 +00:00
										 |  |  | 				 struct ethtool_ringparam *ring) | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct i40evf_adapter *adapter = netdev_priv(netdev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ring->rx_max_pending = I40EVF_MAX_RXD; | 
					
						
							|  |  |  | 	ring->tx_max_pending = I40EVF_MAX_TXD; | 
					
						
							| 
									
										
										
										
											2014-04-24 06:41:37 +00:00
										 |  |  | 	ring->rx_pending = adapter->rx_desc_count; | 
					
						
							|  |  |  | 	ring->tx_pending = adapter->tx_desc_count; | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * i40evf_set_ringparam - Set ring parameters | 
					
						
							|  |  |  |  * @netdev: network interface device structure | 
					
						
							|  |  |  |  * @ring: ethtool ringparam structure | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Sets ring parameters. TX and RX rings are controlled separately, but the | 
					
						
							|  |  |  |  * number of rings is not specified, so all rings get the same settings. | 
					
						
							|  |  |  |  **/ | 
					
						
							|  |  |  | static int i40evf_set_ringparam(struct net_device *netdev, | 
					
						
							|  |  |  | 				struct ethtool_ringparam *ring) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct i40evf_adapter *adapter = netdev_priv(netdev); | 
					
						
							|  |  |  | 	u32 new_rx_count, new_tx_count; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	new_tx_count = clamp_t(u32, ring->tx_pending, | 
					
						
							|  |  |  | 			       I40EVF_MIN_TXD, | 
					
						
							|  |  |  | 			       I40EVF_MAX_TXD); | 
					
						
							|  |  |  | 	new_tx_count = ALIGN(new_tx_count, I40EVF_REQ_DESCRIPTOR_MULTIPLE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	new_rx_count = clamp_t(u32, ring->rx_pending, | 
					
						
							|  |  |  | 			       I40EVF_MIN_RXD, | 
					
						
							|  |  |  | 			       I40EVF_MAX_RXD); | 
					
						
							|  |  |  | 	new_rx_count = ALIGN(new_rx_count, I40EVF_REQ_DESCRIPTOR_MULTIPLE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* if nothing to do return success */ | 
					
						
							| 
									
										
										
										
											2014-04-24 06:41:37 +00:00
										 |  |  | 	if ((new_tx_count == adapter->tx_desc_count) && | 
					
						
							|  |  |  | 	    (new_rx_count == adapter->rx_desc_count)) | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-24 06:41:37 +00:00
										 |  |  | 	adapter->tx_desc_count = new_tx_count; | 
					
						
							|  |  |  | 	adapter->rx_desc_count = new_rx_count; | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (netif_running(netdev)) | 
					
						
							|  |  |  | 		i40evf_reinit_locked(adapter); | 
					
						
							| 
									
										
										
										
											2014-04-24 06:41:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * i40evf_get_coalesce - Get interrupt coalescing settings | 
					
						
							|  |  |  |  * @netdev: network interface device structure | 
					
						
							|  |  |  |  * @ec: ethtool coalesce structure | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Returns current coalescing settings. This is referred to elsewhere in the | 
					
						
							|  |  |  |  * driver as Interrupt Throttle Rate, as this is how the hardware describes | 
					
						
							|  |  |  |  * this functionality. | 
					
						
							|  |  |  |  **/ | 
					
						
							|  |  |  | static int i40evf_get_coalesce(struct net_device *netdev, | 
					
						
							| 
									
										
										
										
											2014-11-11 20:02:42 +00:00
										 |  |  | 			       struct ethtool_coalesce *ec) | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct i40evf_adapter *adapter = netdev_priv(netdev); | 
					
						
							|  |  |  | 	struct i40e_vsi *vsi = &adapter->vsi; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ec->tx_max_coalesced_frames = vsi->work_limit; | 
					
						
							|  |  |  | 	ec->rx_max_coalesced_frames = vsi->work_limit; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ITR_IS_DYNAMIC(vsi->rx_itr_setting)) | 
					
						
							| 
									
										
										
										
											2014-04-04 04:43:10 +00:00
										 |  |  | 		ec->use_adaptive_rx_coalesce = 1; | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (ITR_IS_DYNAMIC(vsi->tx_itr_setting)) | 
					
						
							| 
									
										
										
										
											2014-04-04 04:43:10 +00:00
										 |  |  | 		ec->use_adaptive_tx_coalesce = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ec->rx_coalesce_usecs = vsi->rx_itr_setting & ~I40E_ITR_DYNAMIC; | 
					
						
							|  |  |  | 	ec->tx_coalesce_usecs = vsi->tx_itr_setting & ~I40E_ITR_DYNAMIC; | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * i40evf_set_coalesce - Set interrupt coalescing settings | 
					
						
							|  |  |  |  * @netdev: network interface device structure | 
					
						
							|  |  |  |  * @ec: ethtool coalesce structure | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Change current coalescing settings. | 
					
						
							|  |  |  |  **/ | 
					
						
							|  |  |  | static int i40evf_set_coalesce(struct net_device *netdev, | 
					
						
							| 
									
										
										
										
											2014-11-11 20:02:42 +00:00
										 |  |  | 			       struct ethtool_coalesce *ec) | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct i40evf_adapter *adapter = netdev_priv(netdev); | 
					
						
							|  |  |  | 	struct i40e_hw *hw = &adapter->hw; | 
					
						
							|  |  |  | 	struct i40e_vsi *vsi = &adapter->vsi; | 
					
						
							|  |  |  | 	struct i40e_q_vector *q_vector; | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-04 04:43:10 +00:00
										 |  |  | 	if (ec->tx_max_coalesced_frames_irq || ec->rx_max_coalesced_frames_irq) | 
					
						
							|  |  |  | 		vsi->work_limit = ec->tx_max_coalesced_frames_irq; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((ec->rx_coalesce_usecs >= (I40E_MIN_ITR << 1)) && | 
					
						
							|  |  |  | 	    (ec->rx_coalesce_usecs <= (I40E_MAX_ITR << 1))) | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | 		vsi->rx_itr_setting = ec->rx_coalesce_usecs; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-04 04:43:10 +00:00
										 |  |  | 	else | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((ec->tx_coalesce_usecs >= (I40E_MIN_ITR << 1)) && | 
					
						
							|  |  |  | 	    (ec->tx_coalesce_usecs <= (I40E_MAX_ITR << 1))) | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | 		vsi->tx_itr_setting = ec->tx_coalesce_usecs; | 
					
						
							| 
									
										
										
										
											2014-04-04 04:43:10 +00:00
										 |  |  | 	else if (ec->use_adaptive_tx_coalesce) | 
					
						
							|  |  |  | 		vsi->tx_itr_setting = (I40E_ITR_DYNAMIC | | 
					
						
							|  |  |  | 				       ITR_REG_TO_USEC(I40E_ITR_RX_DEF)); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ec->use_adaptive_rx_coalesce) | 
					
						
							|  |  |  | 		vsi->rx_itr_setting |= I40E_ITR_DYNAMIC; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		vsi->rx_itr_setting &= ~I40E_ITR_DYNAMIC; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ec->use_adaptive_tx_coalesce) | 
					
						
							|  |  |  | 		vsi->tx_itr_setting |= I40E_ITR_DYNAMIC; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		vsi->tx_itr_setting &= ~I40E_ITR_DYNAMIC; | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < adapter->num_msix_vectors - NONQ_VECS; i++) { | 
					
						
							|  |  |  | 		q_vector = adapter->q_vector[i]; | 
					
						
							|  |  |  | 		q_vector->rx.itr = ITR_TO_REG(vsi->rx_itr_setting); | 
					
						
							|  |  |  | 		wr32(hw, I40E_VFINT_ITRN1(0, i), q_vector->rx.itr); | 
					
						
							|  |  |  | 		q_vector->tx.itr = ITR_TO_REG(vsi->tx_itr_setting); | 
					
						
							|  |  |  | 		wr32(hw, I40E_VFINT_ITRN1(1, i), q_vector->tx.itr); | 
					
						
							|  |  |  | 		i40e_flush(hw); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-01 04:43:49 +00:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * i40e_get_rss_hash_opts - Get RSS hash Input Set for each flow type | 
					
						
							|  |  |  |  * @adapter: board private structure | 
					
						
							|  |  |  |  * @cmd: ethtool rxnfc command | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Returns Success if the flow is supported, else Invalid Input. | 
					
						
							|  |  |  |  **/ | 
					
						
							|  |  |  | static int i40evf_get_rss_hash_opts(struct i40evf_adapter *adapter, | 
					
						
							|  |  |  | 				    struct ethtool_rxnfc *cmd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct i40e_hw *hw = &adapter->hw; | 
					
						
							|  |  |  | 	u64 hena = (u64)rd32(hw, I40E_VFQF_HENA(0)) | | 
					
						
							|  |  |  | 		   ((u64)rd32(hw, I40E_VFQF_HENA(1)) << 32); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* We always hash on IP src and dest addresses */ | 
					
						
							|  |  |  | 	cmd->data = RXH_IP_SRC | RXH_IP_DST; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (cmd->flow_type) { | 
					
						
							|  |  |  | 	case TCP_V4_FLOW: | 
					
						
							|  |  |  | 		if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP)) | 
					
						
							|  |  |  | 			cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case UDP_V4_FLOW: | 
					
						
							|  |  |  | 		if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP)) | 
					
						
							|  |  |  | 			cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case SCTP_V4_FLOW: | 
					
						
							|  |  |  | 	case AH_ESP_V4_FLOW: | 
					
						
							|  |  |  | 	case AH_V4_FLOW: | 
					
						
							|  |  |  | 	case ESP_V4_FLOW: | 
					
						
							|  |  |  | 	case IPV4_FLOW: | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case TCP_V6_FLOW: | 
					
						
							|  |  |  | 		if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP)) | 
					
						
							|  |  |  | 			cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case UDP_V6_FLOW: | 
					
						
							|  |  |  | 		if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP)) | 
					
						
							|  |  |  | 			cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case SCTP_V6_FLOW: | 
					
						
							|  |  |  | 	case AH_ESP_V6_FLOW: | 
					
						
							|  |  |  | 	case AH_V6_FLOW: | 
					
						
							|  |  |  | 	case ESP_V6_FLOW: | 
					
						
							|  |  |  | 	case IPV6_FLOW: | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		cmd->data = 0; | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * i40evf_get_rxnfc - command to get RX flow classification rules | 
					
						
							|  |  |  |  * @netdev: network interface device structure | 
					
						
							|  |  |  |  * @cmd: ethtool rxnfc command | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Returns Success if the command is supported. | 
					
						
							|  |  |  |  **/ | 
					
						
							|  |  |  | static int i40evf_get_rxnfc(struct net_device *netdev, | 
					
						
							|  |  |  | 			    struct ethtool_rxnfc *cmd, | 
					
						
							|  |  |  | 			    u32 *rule_locs) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct i40evf_adapter *adapter = netdev_priv(netdev); | 
					
						
							|  |  |  | 	int ret = -EOPNOTSUPP; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (cmd->cmd) { | 
					
						
							|  |  |  | 	case ETHTOOL_GRXRINGS: | 
					
						
							| 
									
										
										
										
											2014-10-25 03:24:34 +00:00
										 |  |  | 		cmd->data = adapter->num_active_queues; | 
					
						
							| 
									
										
										
										
											2014-04-01 04:43:49 +00:00
										 |  |  | 		ret = 0; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case ETHTOOL_GRXFH: | 
					
						
							|  |  |  | 		ret = i40evf_get_rss_hash_opts(adapter, cmd); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * i40evf_set_rss_hash_opt - Enable/Disable flow types for RSS hash | 
					
						
							|  |  |  |  * @adapter: board private structure | 
					
						
							|  |  |  |  * @cmd: ethtool rxnfc command | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Returns Success if the flow input set is supported. | 
					
						
							|  |  |  |  **/ | 
					
						
							|  |  |  | static int i40evf_set_rss_hash_opt(struct i40evf_adapter *adapter, | 
					
						
							|  |  |  | 				   struct ethtool_rxnfc *nfc) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct i40e_hw *hw = &adapter->hw; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	u64 hena = (u64)rd32(hw, I40E_VFQF_HENA(0)) | | 
					
						
							|  |  |  | 		   ((u64)rd32(hw, I40E_VFQF_HENA(1)) << 32); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* RSS does not support anything other than hashing
 | 
					
						
							|  |  |  | 	 * to queues on src and dst IPs and ports | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST | | 
					
						
							|  |  |  | 			  RXH_L4_B_0_1 | RXH_L4_B_2_3)) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* We need at least the IP SRC and DEST fields for hashing */ | 
					
						
							|  |  |  | 	if (!(nfc->data & RXH_IP_SRC) || | 
					
						
							|  |  |  | 	    !(nfc->data & RXH_IP_DST)) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (nfc->flow_type) { | 
					
						
							|  |  |  | 	case TCP_V4_FLOW: | 
					
						
							|  |  |  | 		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { | 
					
						
							|  |  |  | 		case 0: | 
					
						
							|  |  |  | 			hena &= ~((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case (RXH_L4_B_0_1 | RXH_L4_B_2_3): | 
					
						
							|  |  |  | 			hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			return -EINVAL; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case TCP_V6_FLOW: | 
					
						
							|  |  |  | 		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { | 
					
						
							|  |  |  | 		case 0: | 
					
						
							|  |  |  | 			hena &= ~((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case (RXH_L4_B_0_1 | RXH_L4_B_2_3): | 
					
						
							|  |  |  | 			hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			return -EINVAL; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case UDP_V4_FLOW: | 
					
						
							|  |  |  | 		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { | 
					
						
							|  |  |  | 		case 0: | 
					
						
							|  |  |  | 			hena &= ~(((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | | 
					
						
							|  |  |  | 				  ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4)); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case (RXH_L4_B_0_1 | RXH_L4_B_2_3): | 
					
						
							|  |  |  | 			hena |= (((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | | 
					
						
							|  |  |  | 				 ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4)); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			return -EINVAL; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case UDP_V6_FLOW: | 
					
						
							|  |  |  | 		switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { | 
					
						
							|  |  |  | 		case 0: | 
					
						
							|  |  |  | 			hena &= ~(((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | | 
					
						
							|  |  |  | 				  ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6)); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case (RXH_L4_B_0_1 | RXH_L4_B_2_3): | 
					
						
							|  |  |  | 			hena |= (((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | | 
					
						
							|  |  |  | 				 ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6)); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			return -EINVAL; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case AH_ESP_V4_FLOW: | 
					
						
							|  |  |  | 	case AH_V4_FLOW: | 
					
						
							|  |  |  | 	case ESP_V4_FLOW: | 
					
						
							|  |  |  | 	case SCTP_V4_FLOW: | 
					
						
							|  |  |  | 		if ((nfc->data & RXH_L4_B_0_1) || | 
					
						
							|  |  |  | 		    (nfc->data & RXH_L4_B_2_3)) | 
					
						
							|  |  |  | 			return -EINVAL; | 
					
						
							|  |  |  | 		hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case AH_ESP_V6_FLOW: | 
					
						
							|  |  |  | 	case AH_V6_FLOW: | 
					
						
							|  |  |  | 	case ESP_V6_FLOW: | 
					
						
							|  |  |  | 	case SCTP_V6_FLOW: | 
					
						
							|  |  |  | 		if ((nfc->data & RXH_L4_B_0_1) || | 
					
						
							|  |  |  | 		    (nfc->data & RXH_L4_B_2_3)) | 
					
						
							|  |  |  | 			return -EINVAL; | 
					
						
							|  |  |  | 		hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case IPV4_FLOW: | 
					
						
							|  |  |  | 		hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | | 
					
						
							|  |  |  | 			((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case IPV6_FLOW: | 
					
						
							|  |  |  | 		hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | | 
					
						
							|  |  |  | 			((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	wr32(hw, I40E_VFQF_HENA(0), (u32)hena); | 
					
						
							|  |  |  | 	wr32(hw, I40E_VFQF_HENA(1), (u32)(hena >> 32)); | 
					
						
							|  |  |  | 	i40e_flush(hw); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * i40evf_set_rxnfc - command to set RX flow classification rules | 
					
						
							|  |  |  |  * @netdev: network interface device structure | 
					
						
							|  |  |  |  * @cmd: ethtool rxnfc command | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Returns Success if the command is supported. | 
					
						
							|  |  |  |  **/ | 
					
						
							|  |  |  | static int i40evf_set_rxnfc(struct net_device *netdev, | 
					
						
							|  |  |  | 			    struct ethtool_rxnfc *cmd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct i40evf_adapter *adapter = netdev_priv(netdev); | 
					
						
							|  |  |  | 	int ret = -EOPNOTSUPP; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (cmd->cmd) { | 
					
						
							|  |  |  | 	case ETHTOOL_SRXFH: | 
					
						
							|  |  |  | 		ret = i40evf_set_rss_hash_opt(adapter, cmd); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * i40evf_get_channels: get the number of channels supported by the device | 
					
						
							|  |  |  |  * @netdev: network interface device structure | 
					
						
							|  |  |  |  * @ch: channel information structure | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * For the purposes of our device, we only use combined channels, i.e. a tx/rx | 
					
						
							|  |  |  |  * queue pair. Report one extra channel to match our "other" MSI-X vector. | 
					
						
							|  |  |  |  **/ | 
					
						
							|  |  |  | static void i40evf_get_channels(struct net_device *netdev, | 
					
						
							|  |  |  | 				struct ethtool_channels *ch) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct i40evf_adapter *adapter = netdev_priv(netdev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Report maximum channels */ | 
					
						
							| 
									
										
										
										
											2014-10-25 03:24:34 +00:00
										 |  |  | 	ch->max_combined = adapter->num_active_queues; | 
					
						
							| 
									
										
										
										
											2014-04-01 04:43:49 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ch->max_other = NONQ_VECS; | 
					
						
							|  |  |  | 	ch->other_count = NONQ_VECS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-25 03:24:34 +00:00
										 |  |  | 	ch->combined_count = adapter->num_active_queues; | 
					
						
							| 
									
										
										
										
											2014-04-01 04:43:49 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * i40evf_get_rxfh_indir_size - get the rx flow hash indirection table size | 
					
						
							|  |  |  |  * @netdev: network interface device structure | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Returns the table size. | 
					
						
							|  |  |  |  **/ | 
					
						
							|  |  |  | static u32 i40evf_get_rxfh_indir_size(struct net_device *netdev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return (I40E_VFQF_HLUT_MAX_INDEX + 1) * 4; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2014-05-15 01:25:27 +01:00
										 |  |  |  * i40evf_get_rxfh - get the rx flow hash indirection table | 
					
						
							| 
									
										
										
										
											2014-04-01 04:43:49 +00:00
										 |  |  |  * @netdev: network interface device structure | 
					
						
							|  |  |  |  * @indir: indirection table | 
					
						
							| 
									
										
										
										
											2014-11-11 20:02:31 +00:00
										 |  |  |  * @key: hash key | 
					
						
							| 
									
										
										
										
											2014-04-01 04:43:49 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Reads the indirection table directly from the hardware. Always returns 0. | 
					
						
							|  |  |  |  **/ | 
					
						
							| 
									
										
										
										
											2014-12-02 18:12:10 +02:00
										 |  |  | static int i40evf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, | 
					
						
							|  |  |  | 			   u8 *hfunc) | 
					
						
							| 
									
										
										
										
											2014-04-01 04:43:49 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct i40evf_adapter *adapter = netdev_priv(netdev); | 
					
						
							|  |  |  | 	struct i40e_hw *hw = &adapter->hw; | 
					
						
							|  |  |  | 	u32 hlut_val; | 
					
						
							|  |  |  | 	int i, j; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-02 18:12:10 +02:00
										 |  |  | 	if (hfunc) | 
					
						
							|  |  |  | 		*hfunc = ETH_RSS_HASH_TOP; | 
					
						
							|  |  |  | 	if (!indir) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-03 23:50:20 +00:00
										 |  |  | 	for (i = 0, j = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) { | 
					
						
							| 
									
										
										
										
											2014-04-01 04:43:49 +00:00
										 |  |  | 		hlut_val = rd32(hw, I40E_VFQF_HLUT(i)); | 
					
						
							|  |  |  | 		indir[j++] = hlut_val & 0xff; | 
					
						
							|  |  |  | 		indir[j++] = (hlut_val >> 8) & 0xff; | 
					
						
							|  |  |  | 		indir[j++] = (hlut_val >> 16) & 0xff; | 
					
						
							|  |  |  | 		indir[j++] = (hlut_val >> 24) & 0xff; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2014-05-15 01:25:27 +01:00
										 |  |  |  * i40evf_set_rxfh - set the rx flow hash indirection table | 
					
						
							| 
									
										
										
										
											2014-04-01 04:43:49 +00:00
										 |  |  |  * @netdev: network interface device structure | 
					
						
							|  |  |  |  * @indir: indirection table | 
					
						
							| 
									
										
										
										
											2014-11-11 20:02:31 +00:00
										 |  |  |  * @key: hash key | 
					
						
							| 
									
										
										
										
											2014-04-01 04:43:49 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Returns -EINVAL if the table specifies an inavlid queue id, otherwise | 
					
						
							|  |  |  |  * returns 0 after programming the table. | 
					
						
							|  |  |  |  **/ | 
					
						
							| 
									
										
										
										
											2014-05-15 01:25:27 +01:00
										 |  |  | static int i40evf_set_rxfh(struct net_device *netdev, const u32 *indir, | 
					
						
							| 
									
										
										
										
											2014-12-02 18:12:10 +02:00
										 |  |  | 			   const u8 *key, const u8 hfunc) | 
					
						
							| 
									
										
										
										
											2014-04-01 04:43:49 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct i40evf_adapter *adapter = netdev_priv(netdev); | 
					
						
							|  |  |  | 	struct i40e_hw *hw = &adapter->hw; | 
					
						
							|  |  |  | 	u32 hlut_val; | 
					
						
							|  |  |  | 	int i, j; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-02 18:12:10 +02:00
										 |  |  | 	/* We do not allow change in unsupported parameters */ | 
					
						
							|  |  |  | 	if (key || | 
					
						
							|  |  |  | 	    (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)) | 
					
						
							|  |  |  | 		return -EOPNOTSUPP; | 
					
						
							|  |  |  | 	if (!indir) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-03 23:50:20 +00:00
										 |  |  | 	for (i = 0, j = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) { | 
					
						
							| 
									
										
										
										
											2014-04-01 04:43:49 +00:00
										 |  |  | 		hlut_val = indir[j++]; | 
					
						
							|  |  |  | 		hlut_val |= indir[j++] << 8; | 
					
						
							|  |  |  | 		hlut_val |= indir[j++] << 16; | 
					
						
							|  |  |  | 		hlut_val |= indir[j++] << 24; | 
					
						
							|  |  |  | 		wr32(hw, I40E_VFQF_HLUT(i), hlut_val); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-04 04:43:11 +00:00
										 |  |  | static const struct ethtool_ops i40evf_ethtool_ops = { | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | 	.get_settings		= i40evf_get_settings, | 
					
						
							|  |  |  | 	.get_drvinfo		= i40evf_get_drvinfo, | 
					
						
							|  |  |  | 	.get_link		= ethtool_op_get_link, | 
					
						
							|  |  |  | 	.get_ringparam		= i40evf_get_ringparam, | 
					
						
							|  |  |  | 	.set_ringparam		= i40evf_set_ringparam, | 
					
						
							|  |  |  | 	.get_strings		= i40evf_get_strings, | 
					
						
							|  |  |  | 	.get_ethtool_stats	= i40evf_get_ethtool_stats, | 
					
						
							|  |  |  | 	.get_sset_count		= i40evf_get_sset_count, | 
					
						
							|  |  |  | 	.get_msglevel		= i40evf_get_msglevel, | 
					
						
							|  |  |  | 	.set_msglevel		= i40evf_set_msglevel, | 
					
						
							|  |  |  | 	.get_coalesce		= i40evf_get_coalesce, | 
					
						
							|  |  |  | 	.set_coalesce		= i40evf_set_coalesce, | 
					
						
							| 
									
										
										
										
											2014-04-01 04:43:49 +00:00
										 |  |  | 	.get_rxnfc		= i40evf_get_rxnfc, | 
					
						
							|  |  |  | 	.set_rxnfc		= i40evf_set_rxnfc, | 
					
						
							|  |  |  | 	.get_rxfh_indir_size	= i40evf_get_rxfh_indir_size, | 
					
						
							| 
									
										
										
										
											2014-05-15 01:25:27 +01:00
										 |  |  | 	.get_rxfh		= i40evf_get_rxfh, | 
					
						
							|  |  |  | 	.set_rxfh		= i40evf_set_rxfh, | 
					
						
							| 
									
										
										
										
											2014-04-01 04:43:49 +00:00
										 |  |  | 	.get_channels		= i40evf_get_channels, | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * i40evf_set_ethtool_ops - Initialize ethtool ops struct | 
					
						
							|  |  |  |  * @netdev: network interface device structure | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Sets ethtool ops struct in our netdev so that ethtool can call | 
					
						
							|  |  |  |  * our functions. | 
					
						
							|  |  |  |  **/ | 
					
						
							|  |  |  | void i40evf_set_ethtool_ops(struct net_device *netdev) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-05-11 00:12:32 +00:00
										 |  |  | 	netdev->ethtool_ops = &i40evf_ethtool_ops; | 
					
						
							| 
									
										
										
										
											2013-12-21 06:12:56 +00:00
										 |  |  | } |