162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright(c) 2013 - 2018 Intel Corporation. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci/* ethtool support for iavf */
562306a36Sopenharmony_ci#include "iavf.h"
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/uaccess.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci/* ethtool statistics helpers */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/**
1262306a36Sopenharmony_ci * struct iavf_stats - definition for an ethtool statistic
1362306a36Sopenharmony_ci * @stat_string: statistic name to display in ethtool -S output
1462306a36Sopenharmony_ci * @sizeof_stat: the sizeof() the stat, must be no greater than sizeof(u64)
1562306a36Sopenharmony_ci * @stat_offset: offsetof() the stat from a base pointer
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * This structure defines a statistic to be added to the ethtool stats buffer.
1862306a36Sopenharmony_ci * It defines a statistic as offset from a common base pointer. Stats should
1962306a36Sopenharmony_ci * be defined in constant arrays using the IAVF_STAT macro, with every element
2062306a36Sopenharmony_ci * of the array using the same _type for calculating the sizeof_stat and
2162306a36Sopenharmony_ci * stat_offset.
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * The @sizeof_stat is expected to be sizeof(u8), sizeof(u16), sizeof(u32) or
2462306a36Sopenharmony_ci * sizeof(u64). Other sizes are not expected and will produce a WARN_ONCE from
2562306a36Sopenharmony_ci * the iavf_add_ethtool_stat() helper function.
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci * The @stat_string is interpreted as a format string, allowing formatted
2862306a36Sopenharmony_ci * values to be inserted while looping over multiple structures for a given
2962306a36Sopenharmony_ci * statistics array. Thus, every statistic string in an array should have the
3062306a36Sopenharmony_ci * same type and number of format specifiers, to be formatted by variadic
3162306a36Sopenharmony_ci * arguments to the iavf_add_stat_string() helper function.
3262306a36Sopenharmony_ci **/
3362306a36Sopenharmony_cistruct iavf_stats {
3462306a36Sopenharmony_ci	char stat_string[ETH_GSTRING_LEN];
3562306a36Sopenharmony_ci	int sizeof_stat;
3662306a36Sopenharmony_ci	int stat_offset;
3762306a36Sopenharmony_ci};
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/* Helper macro to define an iavf_stat structure with proper size and type.
4062306a36Sopenharmony_ci * Use this when defining constant statistics arrays. Note that @_type expects
4162306a36Sopenharmony_ci * only a type name and is used multiple times.
4262306a36Sopenharmony_ci */
4362306a36Sopenharmony_ci#define IAVF_STAT(_type, _name, _stat) { \
4462306a36Sopenharmony_ci	.stat_string = _name, \
4562306a36Sopenharmony_ci	.sizeof_stat = sizeof_field(_type, _stat), \
4662306a36Sopenharmony_ci	.stat_offset = offsetof(_type, _stat) \
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/* Helper macro for defining some statistics related to queues */
5062306a36Sopenharmony_ci#define IAVF_QUEUE_STAT(_name, _stat) \
5162306a36Sopenharmony_ci	IAVF_STAT(struct iavf_ring, _name, _stat)
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/* Stats associated with a Tx or Rx ring */
5462306a36Sopenharmony_cistatic const struct iavf_stats iavf_gstrings_queue_stats[] = {
5562306a36Sopenharmony_ci	IAVF_QUEUE_STAT("%s-%u.packets", stats.packets),
5662306a36Sopenharmony_ci	IAVF_QUEUE_STAT("%s-%u.bytes", stats.bytes),
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/**
6062306a36Sopenharmony_ci * iavf_add_one_ethtool_stat - copy the stat into the supplied buffer
6162306a36Sopenharmony_ci * @data: location to store the stat value
6262306a36Sopenharmony_ci * @pointer: basis for where to copy from
6362306a36Sopenharmony_ci * @stat: the stat definition
6462306a36Sopenharmony_ci *
6562306a36Sopenharmony_ci * Copies the stat data defined by the pointer and stat structure pair into
6662306a36Sopenharmony_ci * the memory supplied as data. Used to implement iavf_add_ethtool_stats and
6762306a36Sopenharmony_ci * iavf_add_queue_stats. If the pointer is null, data will be zero'd.
6862306a36Sopenharmony_ci */
6962306a36Sopenharmony_cistatic void
7062306a36Sopenharmony_ciiavf_add_one_ethtool_stat(u64 *data, void *pointer,
7162306a36Sopenharmony_ci			  const struct iavf_stats *stat)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	char *p;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	if (!pointer) {
7662306a36Sopenharmony_ci		/* ensure that the ethtool data buffer is zero'd for any stats
7762306a36Sopenharmony_ci		 * which don't have a valid pointer.
7862306a36Sopenharmony_ci		 */
7962306a36Sopenharmony_ci		*data = 0;
8062306a36Sopenharmony_ci		return;
8162306a36Sopenharmony_ci	}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	p = (char *)pointer + stat->stat_offset;
8462306a36Sopenharmony_ci	switch (stat->sizeof_stat) {
8562306a36Sopenharmony_ci	case sizeof(u64):
8662306a36Sopenharmony_ci		*data = *((u64 *)p);
8762306a36Sopenharmony_ci		break;
8862306a36Sopenharmony_ci	case sizeof(u32):
8962306a36Sopenharmony_ci		*data = *((u32 *)p);
9062306a36Sopenharmony_ci		break;
9162306a36Sopenharmony_ci	case sizeof(u16):
9262306a36Sopenharmony_ci		*data = *((u16 *)p);
9362306a36Sopenharmony_ci		break;
9462306a36Sopenharmony_ci	case sizeof(u8):
9562306a36Sopenharmony_ci		*data = *((u8 *)p);
9662306a36Sopenharmony_ci		break;
9762306a36Sopenharmony_ci	default:
9862306a36Sopenharmony_ci		WARN_ONCE(1, "unexpected stat size for %s",
9962306a36Sopenharmony_ci			  stat->stat_string);
10062306a36Sopenharmony_ci		*data = 0;
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/**
10562306a36Sopenharmony_ci * __iavf_add_ethtool_stats - copy stats into the ethtool supplied buffer
10662306a36Sopenharmony_ci * @data: ethtool stats buffer
10762306a36Sopenharmony_ci * @pointer: location to copy stats from
10862306a36Sopenharmony_ci * @stats: array of stats to copy
10962306a36Sopenharmony_ci * @size: the size of the stats definition
11062306a36Sopenharmony_ci *
11162306a36Sopenharmony_ci * Copy the stats defined by the stats array using the pointer as a base into
11262306a36Sopenharmony_ci * the data buffer supplied by ethtool. Updates the data pointer to point to
11362306a36Sopenharmony_ci * the next empty location for successive calls to __iavf_add_ethtool_stats.
11462306a36Sopenharmony_ci * If pointer is null, set the data values to zero and update the pointer to
11562306a36Sopenharmony_ci * skip these stats.
11662306a36Sopenharmony_ci **/
11762306a36Sopenharmony_cistatic void
11862306a36Sopenharmony_ci__iavf_add_ethtool_stats(u64 **data, void *pointer,
11962306a36Sopenharmony_ci			 const struct iavf_stats stats[],
12062306a36Sopenharmony_ci			 const unsigned int size)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	unsigned int i;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	for (i = 0; i < size; i++)
12562306a36Sopenharmony_ci		iavf_add_one_ethtool_stat((*data)++, pointer, &stats[i]);
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci/**
12962306a36Sopenharmony_ci * iavf_add_ethtool_stats - copy stats into ethtool supplied buffer
13062306a36Sopenharmony_ci * @data: ethtool stats buffer
13162306a36Sopenharmony_ci * @pointer: location where stats are stored
13262306a36Sopenharmony_ci * @stats: static const array of stat definitions
13362306a36Sopenharmony_ci *
13462306a36Sopenharmony_ci * Macro to ease the use of __iavf_add_ethtool_stats by taking a static
13562306a36Sopenharmony_ci * constant stats array and passing the ARRAY_SIZE(). This avoids typos by
13662306a36Sopenharmony_ci * ensuring that we pass the size associated with the given stats array.
13762306a36Sopenharmony_ci *
13862306a36Sopenharmony_ci * The parameter @stats is evaluated twice, so parameters with side effects
13962306a36Sopenharmony_ci * should be avoided.
14062306a36Sopenharmony_ci **/
14162306a36Sopenharmony_ci#define iavf_add_ethtool_stats(data, pointer, stats) \
14262306a36Sopenharmony_ci	__iavf_add_ethtool_stats(data, pointer, stats, ARRAY_SIZE(stats))
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci/**
14562306a36Sopenharmony_ci * iavf_add_queue_stats - copy queue statistics into supplied buffer
14662306a36Sopenharmony_ci * @data: ethtool stats buffer
14762306a36Sopenharmony_ci * @ring: the ring to copy
14862306a36Sopenharmony_ci *
14962306a36Sopenharmony_ci * Queue statistics must be copied while protected by
15062306a36Sopenharmony_ci * u64_stats_fetch_begin, so we can't directly use iavf_add_ethtool_stats.
15162306a36Sopenharmony_ci * Assumes that queue stats are defined in iavf_gstrings_queue_stats. If the
15262306a36Sopenharmony_ci * ring pointer is null, zero out the queue stat values and update the data
15362306a36Sopenharmony_ci * pointer. Otherwise safely copy the stats from the ring into the supplied
15462306a36Sopenharmony_ci * buffer and update the data pointer when finished.
15562306a36Sopenharmony_ci *
15662306a36Sopenharmony_ci * This function expects to be called while under rcu_read_lock().
15762306a36Sopenharmony_ci **/
15862306a36Sopenharmony_cistatic void
15962306a36Sopenharmony_ciiavf_add_queue_stats(u64 **data, struct iavf_ring *ring)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	const unsigned int size = ARRAY_SIZE(iavf_gstrings_queue_stats);
16262306a36Sopenharmony_ci	const struct iavf_stats *stats = iavf_gstrings_queue_stats;
16362306a36Sopenharmony_ci	unsigned int start;
16462306a36Sopenharmony_ci	unsigned int i;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	/* To avoid invalid statistics values, ensure that we keep retrying
16762306a36Sopenharmony_ci	 * the copy until we get a consistent value according to
16862306a36Sopenharmony_ci	 * u64_stats_fetch_retry. But first, make sure our ring is
16962306a36Sopenharmony_ci	 * non-null before attempting to access its syncp.
17062306a36Sopenharmony_ci	 */
17162306a36Sopenharmony_ci	do {
17262306a36Sopenharmony_ci		start = !ring ? 0 : u64_stats_fetch_begin(&ring->syncp);
17362306a36Sopenharmony_ci		for (i = 0; i < size; i++)
17462306a36Sopenharmony_ci			iavf_add_one_ethtool_stat(&(*data)[i], ring, &stats[i]);
17562306a36Sopenharmony_ci	} while (ring && u64_stats_fetch_retry(&ring->syncp, start));
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	/* Once we successfully copy the stats in, update the data pointer */
17862306a36Sopenharmony_ci	*data += size;
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci/**
18262306a36Sopenharmony_ci * __iavf_add_stat_strings - copy stat strings into ethtool buffer
18362306a36Sopenharmony_ci * @p: ethtool supplied buffer
18462306a36Sopenharmony_ci * @stats: stat definitions array
18562306a36Sopenharmony_ci * @size: size of the stats array
18662306a36Sopenharmony_ci *
18762306a36Sopenharmony_ci * Format and copy the strings described by stats into the buffer pointed at
18862306a36Sopenharmony_ci * by p.
18962306a36Sopenharmony_ci **/
19062306a36Sopenharmony_cistatic void __iavf_add_stat_strings(u8 **p, const struct iavf_stats stats[],
19162306a36Sopenharmony_ci				    const unsigned int size, ...)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	unsigned int i;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	for (i = 0; i < size; i++) {
19662306a36Sopenharmony_ci		va_list args;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci		va_start(args, size);
19962306a36Sopenharmony_ci		vsnprintf(*p, ETH_GSTRING_LEN, stats[i].stat_string, args);
20062306a36Sopenharmony_ci		*p += ETH_GSTRING_LEN;
20162306a36Sopenharmony_ci		va_end(args);
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci/**
20662306a36Sopenharmony_ci * iavf_add_stat_strings - copy stat strings into ethtool buffer
20762306a36Sopenharmony_ci * @p: ethtool supplied buffer
20862306a36Sopenharmony_ci * @stats: stat definitions array
20962306a36Sopenharmony_ci *
21062306a36Sopenharmony_ci * Format and copy the strings described by the const static stats value into
21162306a36Sopenharmony_ci * the buffer pointed at by p.
21262306a36Sopenharmony_ci *
21362306a36Sopenharmony_ci * The parameter @stats is evaluated twice, so parameters with side effects
21462306a36Sopenharmony_ci * should be avoided. Additionally, stats must be an array such that
21562306a36Sopenharmony_ci * ARRAY_SIZE can be called on it.
21662306a36Sopenharmony_ci **/
21762306a36Sopenharmony_ci#define iavf_add_stat_strings(p, stats, ...) \
21862306a36Sopenharmony_ci	__iavf_add_stat_strings(p, stats, ARRAY_SIZE(stats), ## __VA_ARGS__)
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci#define VF_STAT(_name, _stat) \
22162306a36Sopenharmony_ci	IAVF_STAT(struct iavf_adapter, _name, _stat)
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic const struct iavf_stats iavf_gstrings_stats[] = {
22462306a36Sopenharmony_ci	VF_STAT("rx_bytes", current_stats.rx_bytes),
22562306a36Sopenharmony_ci	VF_STAT("rx_unicast", current_stats.rx_unicast),
22662306a36Sopenharmony_ci	VF_STAT("rx_multicast", current_stats.rx_multicast),
22762306a36Sopenharmony_ci	VF_STAT("rx_broadcast", current_stats.rx_broadcast),
22862306a36Sopenharmony_ci	VF_STAT("rx_discards", current_stats.rx_discards),
22962306a36Sopenharmony_ci	VF_STAT("rx_unknown_protocol", current_stats.rx_unknown_protocol),
23062306a36Sopenharmony_ci	VF_STAT("tx_bytes", current_stats.tx_bytes),
23162306a36Sopenharmony_ci	VF_STAT("tx_unicast", current_stats.tx_unicast),
23262306a36Sopenharmony_ci	VF_STAT("tx_multicast", current_stats.tx_multicast),
23362306a36Sopenharmony_ci	VF_STAT("tx_broadcast", current_stats.tx_broadcast),
23462306a36Sopenharmony_ci	VF_STAT("tx_discards", current_stats.tx_discards),
23562306a36Sopenharmony_ci	VF_STAT("tx_errors", current_stats.tx_errors),
23662306a36Sopenharmony_ci};
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci#define IAVF_STATS_LEN	ARRAY_SIZE(iavf_gstrings_stats)
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci#define IAVF_QUEUE_STATS_LEN	ARRAY_SIZE(iavf_gstrings_queue_stats)
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci/* For now we have one and only one private flag and it is only defined
24362306a36Sopenharmony_ci * when we have support for the SKIP_CPU_SYNC DMA attribute.  Instead
24462306a36Sopenharmony_ci * of leaving all this code sitting around empty we will strip it unless
24562306a36Sopenharmony_ci * our one private flag is actually available.
24662306a36Sopenharmony_ci */
24762306a36Sopenharmony_cistruct iavf_priv_flags {
24862306a36Sopenharmony_ci	char flag_string[ETH_GSTRING_LEN];
24962306a36Sopenharmony_ci	u32 flag;
25062306a36Sopenharmony_ci	bool read_only;
25162306a36Sopenharmony_ci};
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci#define IAVF_PRIV_FLAG(_name, _flag, _read_only) { \
25462306a36Sopenharmony_ci	.flag_string = _name, \
25562306a36Sopenharmony_ci	.flag = _flag, \
25662306a36Sopenharmony_ci	.read_only = _read_only, \
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic const struct iavf_priv_flags iavf_gstrings_priv_flags[] = {
26062306a36Sopenharmony_ci	IAVF_PRIV_FLAG("legacy-rx", IAVF_FLAG_LEGACY_RX, 0),
26162306a36Sopenharmony_ci};
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci#define IAVF_PRIV_FLAGS_STR_LEN ARRAY_SIZE(iavf_gstrings_priv_flags)
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci/**
26662306a36Sopenharmony_ci * iavf_get_link_ksettings - Get Link Speed and Duplex settings
26762306a36Sopenharmony_ci * @netdev: network interface device structure
26862306a36Sopenharmony_ci * @cmd: ethtool command
26962306a36Sopenharmony_ci *
27062306a36Sopenharmony_ci * Reports speed/duplex settings. Because this is a VF, we don't know what
27162306a36Sopenharmony_ci * kind of link we really have, so we fake it.
27262306a36Sopenharmony_ci **/
27362306a36Sopenharmony_cistatic int iavf_get_link_ksettings(struct net_device *netdev,
27462306a36Sopenharmony_ci				   struct ethtool_link_ksettings *cmd)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	struct iavf_adapter *adapter = netdev_priv(netdev);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	ethtool_link_ksettings_zero_link_mode(cmd, supported);
27962306a36Sopenharmony_ci	cmd->base.autoneg = AUTONEG_DISABLE;
28062306a36Sopenharmony_ci	cmd->base.port = PORT_NONE;
28162306a36Sopenharmony_ci	cmd->base.duplex = DUPLEX_FULL;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	if (ADV_LINK_SUPPORT(adapter)) {
28462306a36Sopenharmony_ci		if (adapter->link_speed_mbps &&
28562306a36Sopenharmony_ci		    adapter->link_speed_mbps < U32_MAX)
28662306a36Sopenharmony_ci			cmd->base.speed = adapter->link_speed_mbps;
28762306a36Sopenharmony_ci		else
28862306a36Sopenharmony_ci			cmd->base.speed = SPEED_UNKNOWN;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci		return 0;
29162306a36Sopenharmony_ci	}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	switch (adapter->link_speed) {
29462306a36Sopenharmony_ci	case VIRTCHNL_LINK_SPEED_40GB:
29562306a36Sopenharmony_ci		cmd->base.speed = SPEED_40000;
29662306a36Sopenharmony_ci		break;
29762306a36Sopenharmony_ci	case VIRTCHNL_LINK_SPEED_25GB:
29862306a36Sopenharmony_ci		cmd->base.speed = SPEED_25000;
29962306a36Sopenharmony_ci		break;
30062306a36Sopenharmony_ci	case VIRTCHNL_LINK_SPEED_20GB:
30162306a36Sopenharmony_ci		cmd->base.speed = SPEED_20000;
30262306a36Sopenharmony_ci		break;
30362306a36Sopenharmony_ci	case VIRTCHNL_LINK_SPEED_10GB:
30462306a36Sopenharmony_ci		cmd->base.speed = SPEED_10000;
30562306a36Sopenharmony_ci		break;
30662306a36Sopenharmony_ci	case VIRTCHNL_LINK_SPEED_5GB:
30762306a36Sopenharmony_ci		cmd->base.speed = SPEED_5000;
30862306a36Sopenharmony_ci		break;
30962306a36Sopenharmony_ci	case VIRTCHNL_LINK_SPEED_2_5GB:
31062306a36Sopenharmony_ci		cmd->base.speed = SPEED_2500;
31162306a36Sopenharmony_ci		break;
31262306a36Sopenharmony_ci	case VIRTCHNL_LINK_SPEED_1GB:
31362306a36Sopenharmony_ci		cmd->base.speed = SPEED_1000;
31462306a36Sopenharmony_ci		break;
31562306a36Sopenharmony_ci	case VIRTCHNL_LINK_SPEED_100MB:
31662306a36Sopenharmony_ci		cmd->base.speed = SPEED_100;
31762306a36Sopenharmony_ci		break;
31862306a36Sopenharmony_ci	default:
31962306a36Sopenharmony_ci		break;
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	return 0;
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci/**
32662306a36Sopenharmony_ci * iavf_get_sset_count - Get length of string set
32762306a36Sopenharmony_ci * @netdev: network interface device structure
32862306a36Sopenharmony_ci * @sset: id of string set
32962306a36Sopenharmony_ci *
33062306a36Sopenharmony_ci * Reports size of various string tables.
33162306a36Sopenharmony_ci **/
33262306a36Sopenharmony_cistatic int iavf_get_sset_count(struct net_device *netdev, int sset)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	/* Report the maximum number queues, even if not every queue is
33562306a36Sopenharmony_ci	 * currently configured. Since allocation of queues is in pairs,
33662306a36Sopenharmony_ci	 * use netdev->real_num_tx_queues * 2. The real_num_tx_queues is set
33762306a36Sopenharmony_ci	 * at device creation and never changes.
33862306a36Sopenharmony_ci	 */
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	if (sset == ETH_SS_STATS)
34162306a36Sopenharmony_ci		return IAVF_STATS_LEN +
34262306a36Sopenharmony_ci			(IAVF_QUEUE_STATS_LEN * 2 *
34362306a36Sopenharmony_ci			 netdev->real_num_tx_queues);
34462306a36Sopenharmony_ci	else if (sset == ETH_SS_PRIV_FLAGS)
34562306a36Sopenharmony_ci		return IAVF_PRIV_FLAGS_STR_LEN;
34662306a36Sopenharmony_ci	else
34762306a36Sopenharmony_ci		return -EINVAL;
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci/**
35162306a36Sopenharmony_ci * iavf_get_ethtool_stats - report device statistics
35262306a36Sopenharmony_ci * @netdev: network interface device structure
35362306a36Sopenharmony_ci * @stats: ethtool statistics structure
35462306a36Sopenharmony_ci * @data: pointer to data buffer
35562306a36Sopenharmony_ci *
35662306a36Sopenharmony_ci * All statistics are added to the data buffer as an array of u64.
35762306a36Sopenharmony_ci **/
35862306a36Sopenharmony_cistatic void iavf_get_ethtool_stats(struct net_device *netdev,
35962306a36Sopenharmony_ci				   struct ethtool_stats *stats, u64 *data)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	struct iavf_adapter *adapter = netdev_priv(netdev);
36262306a36Sopenharmony_ci	unsigned int i;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	/* Explicitly request stats refresh */
36562306a36Sopenharmony_ci	iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_REQUEST_STATS);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	iavf_add_ethtool_stats(&data, adapter, iavf_gstrings_stats);
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	rcu_read_lock();
37062306a36Sopenharmony_ci	/* As num_active_queues describe both tx and rx queues, we can use
37162306a36Sopenharmony_ci	 * it to iterate over rings' stats.
37262306a36Sopenharmony_ci	 */
37362306a36Sopenharmony_ci	for (i = 0; i < adapter->num_active_queues; i++) {
37462306a36Sopenharmony_ci		struct iavf_ring *ring;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci		/* Tx rings stats */
37762306a36Sopenharmony_ci		ring = &adapter->tx_rings[i];
37862306a36Sopenharmony_ci		iavf_add_queue_stats(&data, ring);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci		/* Rx rings stats */
38162306a36Sopenharmony_ci		ring = &adapter->rx_rings[i];
38262306a36Sopenharmony_ci		iavf_add_queue_stats(&data, ring);
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci	rcu_read_unlock();
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci/**
38862306a36Sopenharmony_ci * iavf_get_priv_flag_strings - Get private flag strings
38962306a36Sopenharmony_ci * @netdev: network interface device structure
39062306a36Sopenharmony_ci * @data: buffer for string data
39162306a36Sopenharmony_ci *
39262306a36Sopenharmony_ci * Builds the private flags string table
39362306a36Sopenharmony_ci **/
39462306a36Sopenharmony_cistatic void iavf_get_priv_flag_strings(struct net_device *netdev, u8 *data)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	unsigned int i;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	for (i = 0; i < IAVF_PRIV_FLAGS_STR_LEN; i++) {
39962306a36Sopenharmony_ci		snprintf(data, ETH_GSTRING_LEN, "%s",
40062306a36Sopenharmony_ci			 iavf_gstrings_priv_flags[i].flag_string);
40162306a36Sopenharmony_ci		data += ETH_GSTRING_LEN;
40262306a36Sopenharmony_ci	}
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci/**
40662306a36Sopenharmony_ci * iavf_get_stat_strings - Get stat strings
40762306a36Sopenharmony_ci * @netdev: network interface device structure
40862306a36Sopenharmony_ci * @data: buffer for string data
40962306a36Sopenharmony_ci *
41062306a36Sopenharmony_ci * Builds the statistics string table
41162306a36Sopenharmony_ci **/
41262306a36Sopenharmony_cistatic void iavf_get_stat_strings(struct net_device *netdev, u8 *data)
41362306a36Sopenharmony_ci{
41462306a36Sopenharmony_ci	unsigned int i;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	iavf_add_stat_strings(&data, iavf_gstrings_stats);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	/* Queues are always allocated in pairs, so we just use
41962306a36Sopenharmony_ci	 * real_num_tx_queues for both Tx and Rx queues.
42062306a36Sopenharmony_ci	 */
42162306a36Sopenharmony_ci	for (i = 0; i < netdev->real_num_tx_queues; i++) {
42262306a36Sopenharmony_ci		iavf_add_stat_strings(&data, iavf_gstrings_queue_stats,
42362306a36Sopenharmony_ci				      "tx", i);
42462306a36Sopenharmony_ci		iavf_add_stat_strings(&data, iavf_gstrings_queue_stats,
42562306a36Sopenharmony_ci				      "rx", i);
42662306a36Sopenharmony_ci	}
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci/**
43062306a36Sopenharmony_ci * iavf_get_strings - Get string set
43162306a36Sopenharmony_ci * @netdev: network interface device structure
43262306a36Sopenharmony_ci * @sset: id of string set
43362306a36Sopenharmony_ci * @data: buffer for string data
43462306a36Sopenharmony_ci *
43562306a36Sopenharmony_ci * Builds string tables for various string sets
43662306a36Sopenharmony_ci **/
43762306a36Sopenharmony_cistatic void iavf_get_strings(struct net_device *netdev, u32 sset, u8 *data)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	switch (sset) {
44062306a36Sopenharmony_ci	case ETH_SS_STATS:
44162306a36Sopenharmony_ci		iavf_get_stat_strings(netdev, data);
44262306a36Sopenharmony_ci		break;
44362306a36Sopenharmony_ci	case ETH_SS_PRIV_FLAGS:
44462306a36Sopenharmony_ci		iavf_get_priv_flag_strings(netdev, data);
44562306a36Sopenharmony_ci		break;
44662306a36Sopenharmony_ci	default:
44762306a36Sopenharmony_ci		break;
44862306a36Sopenharmony_ci	}
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci/**
45262306a36Sopenharmony_ci * iavf_get_priv_flags - report device private flags
45362306a36Sopenharmony_ci * @netdev: network interface device structure
45462306a36Sopenharmony_ci *
45562306a36Sopenharmony_ci * The get string set count and the string set should be matched for each
45662306a36Sopenharmony_ci * flag returned.  Add new strings for each flag to the iavf_gstrings_priv_flags
45762306a36Sopenharmony_ci * array.
45862306a36Sopenharmony_ci *
45962306a36Sopenharmony_ci * Returns a u32 bitmap of flags.
46062306a36Sopenharmony_ci **/
46162306a36Sopenharmony_cistatic u32 iavf_get_priv_flags(struct net_device *netdev)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	struct iavf_adapter *adapter = netdev_priv(netdev);
46462306a36Sopenharmony_ci	u32 i, ret_flags = 0;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	for (i = 0; i < IAVF_PRIV_FLAGS_STR_LEN; i++) {
46762306a36Sopenharmony_ci		const struct iavf_priv_flags *priv_flags;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci		priv_flags = &iavf_gstrings_priv_flags[i];
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci		if (priv_flags->flag & adapter->flags)
47262306a36Sopenharmony_ci			ret_flags |= BIT(i);
47362306a36Sopenharmony_ci	}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	return ret_flags;
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci/**
47962306a36Sopenharmony_ci * iavf_set_priv_flags - set private flags
48062306a36Sopenharmony_ci * @netdev: network interface device structure
48162306a36Sopenharmony_ci * @flags: bit flags to be set
48262306a36Sopenharmony_ci **/
48362306a36Sopenharmony_cistatic int iavf_set_priv_flags(struct net_device *netdev, u32 flags)
48462306a36Sopenharmony_ci{
48562306a36Sopenharmony_ci	struct iavf_adapter *adapter = netdev_priv(netdev);
48662306a36Sopenharmony_ci	u32 orig_flags, new_flags, changed_flags;
48762306a36Sopenharmony_ci	int ret = 0;
48862306a36Sopenharmony_ci	u32 i;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	orig_flags = READ_ONCE(adapter->flags);
49162306a36Sopenharmony_ci	new_flags = orig_flags;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	for (i = 0; i < IAVF_PRIV_FLAGS_STR_LEN; i++) {
49462306a36Sopenharmony_ci		const struct iavf_priv_flags *priv_flags;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci		priv_flags = &iavf_gstrings_priv_flags[i];
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci		if (flags & BIT(i))
49962306a36Sopenharmony_ci			new_flags |= priv_flags->flag;
50062306a36Sopenharmony_ci		else
50162306a36Sopenharmony_ci			new_flags &= ~(priv_flags->flag);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci		if (priv_flags->read_only &&
50462306a36Sopenharmony_ci		    ((orig_flags ^ new_flags) & ~BIT(i)))
50562306a36Sopenharmony_ci			return -EOPNOTSUPP;
50662306a36Sopenharmony_ci	}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	/* Before we finalize any flag changes, any checks which we need to
50962306a36Sopenharmony_ci	 * perform to determine if the new flags will be supported should go
51062306a36Sopenharmony_ci	 * here...
51162306a36Sopenharmony_ci	 */
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	/* Compare and exchange the new flags into place. If we failed, that
51462306a36Sopenharmony_ci	 * is if cmpxchg returns anything but the old value, this means
51562306a36Sopenharmony_ci	 * something else must have modified the flags variable since we
51662306a36Sopenharmony_ci	 * copied it. We'll just punt with an error and log something in the
51762306a36Sopenharmony_ci	 * message buffer.
51862306a36Sopenharmony_ci	 */
51962306a36Sopenharmony_ci	if (cmpxchg(&adapter->flags, orig_flags, new_flags) != orig_flags) {
52062306a36Sopenharmony_ci		dev_warn(&adapter->pdev->dev,
52162306a36Sopenharmony_ci			 "Unable to update adapter->flags as it was modified by another thread...\n");
52262306a36Sopenharmony_ci		return -EAGAIN;
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	changed_flags = orig_flags ^ new_flags;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	/* Process any additional changes needed as a result of flag changes.
52862306a36Sopenharmony_ci	 * The changed_flags value reflects the list of bits that were changed
52962306a36Sopenharmony_ci	 * in the code above.
53062306a36Sopenharmony_ci	 */
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	/* issue a reset to force legacy-rx change to take effect */
53362306a36Sopenharmony_ci	if (changed_flags & IAVF_FLAG_LEGACY_RX) {
53462306a36Sopenharmony_ci		if (netif_running(netdev)) {
53562306a36Sopenharmony_ci			iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
53662306a36Sopenharmony_ci			ret = iavf_wait_for_reset(adapter);
53762306a36Sopenharmony_ci			if (ret)
53862306a36Sopenharmony_ci				netdev_warn(netdev, "Changing private flags timeout or interrupted waiting for reset");
53962306a36Sopenharmony_ci		}
54062306a36Sopenharmony_ci	}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	return ret;
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci/**
54662306a36Sopenharmony_ci * iavf_get_msglevel - Get debug message level
54762306a36Sopenharmony_ci * @netdev: network interface device structure
54862306a36Sopenharmony_ci *
54962306a36Sopenharmony_ci * Returns current debug message level.
55062306a36Sopenharmony_ci **/
55162306a36Sopenharmony_cistatic u32 iavf_get_msglevel(struct net_device *netdev)
55262306a36Sopenharmony_ci{
55362306a36Sopenharmony_ci	struct iavf_adapter *adapter = netdev_priv(netdev);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	return adapter->msg_enable;
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci/**
55962306a36Sopenharmony_ci * iavf_set_msglevel - Set debug message level
56062306a36Sopenharmony_ci * @netdev: network interface device structure
56162306a36Sopenharmony_ci * @data: message level
56262306a36Sopenharmony_ci *
56362306a36Sopenharmony_ci * Set current debug message level. Higher values cause the driver to
56462306a36Sopenharmony_ci * be noisier.
56562306a36Sopenharmony_ci **/
56662306a36Sopenharmony_cistatic void iavf_set_msglevel(struct net_device *netdev, u32 data)
56762306a36Sopenharmony_ci{
56862306a36Sopenharmony_ci	struct iavf_adapter *adapter = netdev_priv(netdev);
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	if (IAVF_DEBUG_USER & data)
57162306a36Sopenharmony_ci		adapter->hw.debug_mask = data;
57262306a36Sopenharmony_ci	adapter->msg_enable = data;
57362306a36Sopenharmony_ci}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci/**
57662306a36Sopenharmony_ci * iavf_get_drvinfo - Get driver info
57762306a36Sopenharmony_ci * @netdev: network interface device structure
57862306a36Sopenharmony_ci * @drvinfo: ethool driver info structure
57962306a36Sopenharmony_ci *
58062306a36Sopenharmony_ci * Returns information about the driver and device for display to the user.
58162306a36Sopenharmony_ci **/
58262306a36Sopenharmony_cistatic void iavf_get_drvinfo(struct net_device *netdev,
58362306a36Sopenharmony_ci			     struct ethtool_drvinfo *drvinfo)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	struct iavf_adapter *adapter = netdev_priv(netdev);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	strscpy(drvinfo->driver, iavf_driver_name, 32);
58862306a36Sopenharmony_ci	strscpy(drvinfo->fw_version, "N/A", 4);
58962306a36Sopenharmony_ci	strscpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
59062306a36Sopenharmony_ci	drvinfo->n_priv_flags = IAVF_PRIV_FLAGS_STR_LEN;
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci/**
59462306a36Sopenharmony_ci * iavf_get_ringparam - Get ring parameters
59562306a36Sopenharmony_ci * @netdev: network interface device structure
59662306a36Sopenharmony_ci * @ring: ethtool ringparam structure
59762306a36Sopenharmony_ci * @kernel_ring: ethtool extenal ringparam structure
59862306a36Sopenharmony_ci * @extack: netlink extended ACK report struct
59962306a36Sopenharmony_ci *
60062306a36Sopenharmony_ci * Returns current ring parameters. TX and RX rings are reported separately,
60162306a36Sopenharmony_ci * but the number of rings is not reported.
60262306a36Sopenharmony_ci **/
60362306a36Sopenharmony_cistatic void iavf_get_ringparam(struct net_device *netdev,
60462306a36Sopenharmony_ci			       struct ethtool_ringparam *ring,
60562306a36Sopenharmony_ci			       struct kernel_ethtool_ringparam *kernel_ring,
60662306a36Sopenharmony_ci			       struct netlink_ext_ack *extack)
60762306a36Sopenharmony_ci{
60862306a36Sopenharmony_ci	struct iavf_adapter *adapter = netdev_priv(netdev);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	ring->rx_max_pending = IAVF_MAX_RXD;
61162306a36Sopenharmony_ci	ring->tx_max_pending = IAVF_MAX_TXD;
61262306a36Sopenharmony_ci	ring->rx_pending = adapter->rx_desc_count;
61362306a36Sopenharmony_ci	ring->tx_pending = adapter->tx_desc_count;
61462306a36Sopenharmony_ci}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci/**
61762306a36Sopenharmony_ci * iavf_set_ringparam - Set ring parameters
61862306a36Sopenharmony_ci * @netdev: network interface device structure
61962306a36Sopenharmony_ci * @ring: ethtool ringparam structure
62062306a36Sopenharmony_ci * @kernel_ring: ethtool external ringparam structure
62162306a36Sopenharmony_ci * @extack: netlink extended ACK report struct
62262306a36Sopenharmony_ci *
62362306a36Sopenharmony_ci * Sets ring parameters. TX and RX rings are controlled separately, but the
62462306a36Sopenharmony_ci * number of rings is not specified, so all rings get the same settings.
62562306a36Sopenharmony_ci **/
62662306a36Sopenharmony_cistatic int iavf_set_ringparam(struct net_device *netdev,
62762306a36Sopenharmony_ci			      struct ethtool_ringparam *ring,
62862306a36Sopenharmony_ci			      struct kernel_ethtool_ringparam *kernel_ring,
62962306a36Sopenharmony_ci			      struct netlink_ext_ack *extack)
63062306a36Sopenharmony_ci{
63162306a36Sopenharmony_ci	struct iavf_adapter *adapter = netdev_priv(netdev);
63262306a36Sopenharmony_ci	u32 new_rx_count, new_tx_count;
63362306a36Sopenharmony_ci	int ret = 0;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
63662306a36Sopenharmony_ci		return -EINVAL;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	if (ring->tx_pending > IAVF_MAX_TXD ||
63962306a36Sopenharmony_ci	    ring->tx_pending < IAVF_MIN_TXD ||
64062306a36Sopenharmony_ci	    ring->rx_pending > IAVF_MAX_RXD ||
64162306a36Sopenharmony_ci	    ring->rx_pending < IAVF_MIN_RXD) {
64262306a36Sopenharmony_ci		netdev_err(netdev, "Descriptors requested (Tx: %d / Rx: %d) out of range [%d-%d] (increment %d)\n",
64362306a36Sopenharmony_ci			   ring->tx_pending, ring->rx_pending, IAVF_MIN_TXD,
64462306a36Sopenharmony_ci			   IAVF_MAX_RXD, IAVF_REQ_DESCRIPTOR_MULTIPLE);
64562306a36Sopenharmony_ci		return -EINVAL;
64662306a36Sopenharmony_ci	}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	new_tx_count = ALIGN(ring->tx_pending, IAVF_REQ_DESCRIPTOR_MULTIPLE);
64962306a36Sopenharmony_ci	if (new_tx_count != ring->tx_pending)
65062306a36Sopenharmony_ci		netdev_info(netdev, "Requested Tx descriptor count rounded up to %d\n",
65162306a36Sopenharmony_ci			    new_tx_count);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	new_rx_count = ALIGN(ring->rx_pending, IAVF_REQ_DESCRIPTOR_MULTIPLE);
65462306a36Sopenharmony_ci	if (new_rx_count != ring->rx_pending)
65562306a36Sopenharmony_ci		netdev_info(netdev, "Requested Rx descriptor count rounded up to %d\n",
65662306a36Sopenharmony_ci			    new_rx_count);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	/* if nothing to do return success */
65962306a36Sopenharmony_ci	if ((new_tx_count == adapter->tx_desc_count) &&
66062306a36Sopenharmony_ci	    (new_rx_count == adapter->rx_desc_count)) {
66162306a36Sopenharmony_ci		netdev_dbg(netdev, "Nothing to change, descriptor count is same as requested\n");
66262306a36Sopenharmony_ci		return 0;
66362306a36Sopenharmony_ci	}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	if (new_tx_count != adapter->tx_desc_count) {
66662306a36Sopenharmony_ci		netdev_dbg(netdev, "Changing Tx descriptor count from %d to %d\n",
66762306a36Sopenharmony_ci			   adapter->tx_desc_count, new_tx_count);
66862306a36Sopenharmony_ci		adapter->tx_desc_count = new_tx_count;
66962306a36Sopenharmony_ci	}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	if (new_rx_count != adapter->rx_desc_count) {
67262306a36Sopenharmony_ci		netdev_dbg(netdev, "Changing Rx descriptor count from %d to %d\n",
67362306a36Sopenharmony_ci			   adapter->rx_desc_count, new_rx_count);
67462306a36Sopenharmony_ci		adapter->rx_desc_count = new_rx_count;
67562306a36Sopenharmony_ci	}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	if (netif_running(netdev)) {
67862306a36Sopenharmony_ci		iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
67962306a36Sopenharmony_ci		ret = iavf_wait_for_reset(adapter);
68062306a36Sopenharmony_ci		if (ret)
68162306a36Sopenharmony_ci			netdev_warn(netdev, "Changing ring parameters timeout or interrupted waiting for reset");
68262306a36Sopenharmony_ci	}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	return ret;
68562306a36Sopenharmony_ci}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci/**
68862306a36Sopenharmony_ci * __iavf_get_coalesce - get per-queue coalesce settings
68962306a36Sopenharmony_ci * @netdev: the netdev to check
69062306a36Sopenharmony_ci * @ec: ethtool coalesce data structure
69162306a36Sopenharmony_ci * @queue: which queue to pick
69262306a36Sopenharmony_ci *
69362306a36Sopenharmony_ci * Gets the per-queue settings for coalescence. Specifically Rx and Tx usecs
69462306a36Sopenharmony_ci * are per queue. If queue is <0 then we default to queue 0 as the
69562306a36Sopenharmony_ci * representative value.
69662306a36Sopenharmony_ci **/
69762306a36Sopenharmony_cistatic int __iavf_get_coalesce(struct net_device *netdev,
69862306a36Sopenharmony_ci			       struct ethtool_coalesce *ec, int queue)
69962306a36Sopenharmony_ci{
70062306a36Sopenharmony_ci	struct iavf_adapter *adapter = netdev_priv(netdev);
70162306a36Sopenharmony_ci	struct iavf_ring *rx_ring, *tx_ring;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	/* Rx and Tx usecs per queue value. If user doesn't specify the
70462306a36Sopenharmony_ci	 * queue, return queue 0's value to represent.
70562306a36Sopenharmony_ci	 */
70662306a36Sopenharmony_ci	if (queue < 0)
70762306a36Sopenharmony_ci		queue = 0;
70862306a36Sopenharmony_ci	else if (queue >= adapter->num_active_queues)
70962306a36Sopenharmony_ci		return -EINVAL;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	rx_ring = &adapter->rx_rings[queue];
71262306a36Sopenharmony_ci	tx_ring = &adapter->tx_rings[queue];
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	if (ITR_IS_DYNAMIC(rx_ring->itr_setting))
71562306a36Sopenharmony_ci		ec->use_adaptive_rx_coalesce = 1;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	if (ITR_IS_DYNAMIC(tx_ring->itr_setting))
71862306a36Sopenharmony_ci		ec->use_adaptive_tx_coalesce = 1;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	ec->rx_coalesce_usecs = rx_ring->itr_setting & ~IAVF_ITR_DYNAMIC;
72162306a36Sopenharmony_ci	ec->tx_coalesce_usecs = tx_ring->itr_setting & ~IAVF_ITR_DYNAMIC;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	return 0;
72462306a36Sopenharmony_ci}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci/**
72762306a36Sopenharmony_ci * iavf_get_coalesce - Get interrupt coalescing settings
72862306a36Sopenharmony_ci * @netdev: network interface device structure
72962306a36Sopenharmony_ci * @ec: ethtool coalesce structure
73062306a36Sopenharmony_ci * @kernel_coal: ethtool CQE mode setting structure
73162306a36Sopenharmony_ci * @extack: extack for reporting error messages
73262306a36Sopenharmony_ci *
73362306a36Sopenharmony_ci * Returns current coalescing settings. This is referred to elsewhere in the
73462306a36Sopenharmony_ci * driver as Interrupt Throttle Rate, as this is how the hardware describes
73562306a36Sopenharmony_ci * this functionality. Note that if per-queue settings have been modified this
73662306a36Sopenharmony_ci * only represents the settings of queue 0.
73762306a36Sopenharmony_ci **/
73862306a36Sopenharmony_cistatic int iavf_get_coalesce(struct net_device *netdev,
73962306a36Sopenharmony_ci			     struct ethtool_coalesce *ec,
74062306a36Sopenharmony_ci			     struct kernel_ethtool_coalesce *kernel_coal,
74162306a36Sopenharmony_ci			     struct netlink_ext_ack *extack)
74262306a36Sopenharmony_ci{
74362306a36Sopenharmony_ci	return __iavf_get_coalesce(netdev, ec, -1);
74462306a36Sopenharmony_ci}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci/**
74762306a36Sopenharmony_ci * iavf_get_per_queue_coalesce - get coalesce values for specific queue
74862306a36Sopenharmony_ci * @netdev: netdev to read
74962306a36Sopenharmony_ci * @ec: coalesce settings from ethtool
75062306a36Sopenharmony_ci * @queue: the queue to read
75162306a36Sopenharmony_ci *
75262306a36Sopenharmony_ci * Read specific queue's coalesce settings.
75362306a36Sopenharmony_ci **/
75462306a36Sopenharmony_cistatic int iavf_get_per_queue_coalesce(struct net_device *netdev, u32 queue,
75562306a36Sopenharmony_ci				       struct ethtool_coalesce *ec)
75662306a36Sopenharmony_ci{
75762306a36Sopenharmony_ci	return __iavf_get_coalesce(netdev, ec, queue);
75862306a36Sopenharmony_ci}
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci/**
76162306a36Sopenharmony_ci * iavf_set_itr_per_queue - set ITR values for specific queue
76262306a36Sopenharmony_ci * @adapter: the VF adapter struct to set values for
76362306a36Sopenharmony_ci * @ec: coalesce settings from ethtool
76462306a36Sopenharmony_ci * @queue: the queue to modify
76562306a36Sopenharmony_ci *
76662306a36Sopenharmony_ci * Change the ITR settings for a specific queue.
76762306a36Sopenharmony_ci **/
76862306a36Sopenharmony_cistatic int iavf_set_itr_per_queue(struct iavf_adapter *adapter,
76962306a36Sopenharmony_ci				  struct ethtool_coalesce *ec, int queue)
77062306a36Sopenharmony_ci{
77162306a36Sopenharmony_ci	struct iavf_ring *rx_ring = &adapter->rx_rings[queue];
77262306a36Sopenharmony_ci	struct iavf_ring *tx_ring = &adapter->tx_rings[queue];
77362306a36Sopenharmony_ci	struct iavf_q_vector *q_vector;
77462306a36Sopenharmony_ci	u16 itr_setting;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	itr_setting = rx_ring->itr_setting & ~IAVF_ITR_DYNAMIC;
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	if (ec->rx_coalesce_usecs != itr_setting &&
77962306a36Sopenharmony_ci	    ec->use_adaptive_rx_coalesce) {
78062306a36Sopenharmony_ci		netif_info(adapter, drv, adapter->netdev,
78162306a36Sopenharmony_ci			   "Rx interrupt throttling cannot be changed if adaptive-rx is enabled\n");
78262306a36Sopenharmony_ci		return -EINVAL;
78362306a36Sopenharmony_ci	}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	itr_setting = tx_ring->itr_setting & ~IAVF_ITR_DYNAMIC;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	if (ec->tx_coalesce_usecs != itr_setting &&
78862306a36Sopenharmony_ci	    ec->use_adaptive_tx_coalesce) {
78962306a36Sopenharmony_ci		netif_info(adapter, drv, adapter->netdev,
79062306a36Sopenharmony_ci			   "Tx interrupt throttling cannot be changed if adaptive-tx is enabled\n");
79162306a36Sopenharmony_ci		return -EINVAL;
79262306a36Sopenharmony_ci	}
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	rx_ring->itr_setting = ITR_REG_ALIGN(ec->rx_coalesce_usecs);
79562306a36Sopenharmony_ci	tx_ring->itr_setting = ITR_REG_ALIGN(ec->tx_coalesce_usecs);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	rx_ring->itr_setting |= IAVF_ITR_DYNAMIC;
79862306a36Sopenharmony_ci	if (!ec->use_adaptive_rx_coalesce)
79962306a36Sopenharmony_ci		rx_ring->itr_setting ^= IAVF_ITR_DYNAMIC;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	tx_ring->itr_setting |= IAVF_ITR_DYNAMIC;
80262306a36Sopenharmony_ci	if (!ec->use_adaptive_tx_coalesce)
80362306a36Sopenharmony_ci		tx_ring->itr_setting ^= IAVF_ITR_DYNAMIC;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	q_vector = rx_ring->q_vector;
80662306a36Sopenharmony_ci	q_vector->rx.target_itr = ITR_TO_REG(rx_ring->itr_setting);
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	q_vector = tx_ring->q_vector;
80962306a36Sopenharmony_ci	q_vector->tx.target_itr = ITR_TO_REG(tx_ring->itr_setting);
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	/* The interrupt handler itself will take care of programming
81262306a36Sopenharmony_ci	 * the Tx and Rx ITR values based on the values we have entered
81362306a36Sopenharmony_ci	 * into the q_vector, no need to write the values now.
81462306a36Sopenharmony_ci	 */
81562306a36Sopenharmony_ci	return 0;
81662306a36Sopenharmony_ci}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci/**
81962306a36Sopenharmony_ci * __iavf_set_coalesce - set coalesce settings for particular queue
82062306a36Sopenharmony_ci * @netdev: the netdev to change
82162306a36Sopenharmony_ci * @ec: ethtool coalesce settings
82262306a36Sopenharmony_ci * @queue: the queue to change
82362306a36Sopenharmony_ci *
82462306a36Sopenharmony_ci * Sets the coalesce settings for a particular queue.
82562306a36Sopenharmony_ci **/
82662306a36Sopenharmony_cistatic int __iavf_set_coalesce(struct net_device *netdev,
82762306a36Sopenharmony_ci			       struct ethtool_coalesce *ec, int queue)
82862306a36Sopenharmony_ci{
82962306a36Sopenharmony_ci	struct iavf_adapter *adapter = netdev_priv(netdev);
83062306a36Sopenharmony_ci	int i;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	if (ec->rx_coalesce_usecs > IAVF_MAX_ITR) {
83362306a36Sopenharmony_ci		netif_info(adapter, drv, netdev, "Invalid value, rx-usecs range is 0-8160\n");
83462306a36Sopenharmony_ci		return -EINVAL;
83562306a36Sopenharmony_ci	} else if (ec->tx_coalesce_usecs > IAVF_MAX_ITR) {
83662306a36Sopenharmony_ci		netif_info(adapter, drv, netdev, "Invalid value, tx-usecs range is 0-8160\n");
83762306a36Sopenharmony_ci		return -EINVAL;
83862306a36Sopenharmony_ci	}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	/* Rx and Tx usecs has per queue value. If user doesn't specify the
84162306a36Sopenharmony_ci	 * queue, apply to all queues.
84262306a36Sopenharmony_ci	 */
84362306a36Sopenharmony_ci	if (queue < 0) {
84462306a36Sopenharmony_ci		for (i = 0; i < adapter->num_active_queues; i++)
84562306a36Sopenharmony_ci			if (iavf_set_itr_per_queue(adapter, ec, i))
84662306a36Sopenharmony_ci				return -EINVAL;
84762306a36Sopenharmony_ci	} else if (queue < adapter->num_active_queues) {
84862306a36Sopenharmony_ci		if (iavf_set_itr_per_queue(adapter, ec, queue))
84962306a36Sopenharmony_ci			return -EINVAL;
85062306a36Sopenharmony_ci	} else {
85162306a36Sopenharmony_ci		netif_info(adapter, drv, netdev, "Invalid queue value, queue range is 0 - %d\n",
85262306a36Sopenharmony_ci			   adapter->num_active_queues - 1);
85362306a36Sopenharmony_ci		return -EINVAL;
85462306a36Sopenharmony_ci	}
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	return 0;
85762306a36Sopenharmony_ci}
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci/**
86062306a36Sopenharmony_ci * iavf_set_coalesce - Set interrupt coalescing settings
86162306a36Sopenharmony_ci * @netdev: network interface device structure
86262306a36Sopenharmony_ci * @ec: ethtool coalesce structure
86362306a36Sopenharmony_ci * @kernel_coal: ethtool CQE mode setting structure
86462306a36Sopenharmony_ci * @extack: extack for reporting error messages
86562306a36Sopenharmony_ci *
86662306a36Sopenharmony_ci * Change current coalescing settings for every queue.
86762306a36Sopenharmony_ci **/
86862306a36Sopenharmony_cistatic int iavf_set_coalesce(struct net_device *netdev,
86962306a36Sopenharmony_ci			     struct ethtool_coalesce *ec,
87062306a36Sopenharmony_ci			     struct kernel_ethtool_coalesce *kernel_coal,
87162306a36Sopenharmony_ci			     struct netlink_ext_ack *extack)
87262306a36Sopenharmony_ci{
87362306a36Sopenharmony_ci	return __iavf_set_coalesce(netdev, ec, -1);
87462306a36Sopenharmony_ci}
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci/**
87762306a36Sopenharmony_ci * iavf_set_per_queue_coalesce - set specific queue's coalesce settings
87862306a36Sopenharmony_ci * @netdev: the netdev to change
87962306a36Sopenharmony_ci * @ec: ethtool's coalesce settings
88062306a36Sopenharmony_ci * @queue: the queue to modify
88162306a36Sopenharmony_ci *
88262306a36Sopenharmony_ci * Modifies a specific queue's coalesce settings.
88362306a36Sopenharmony_ci */
88462306a36Sopenharmony_cistatic int iavf_set_per_queue_coalesce(struct net_device *netdev, u32 queue,
88562306a36Sopenharmony_ci				       struct ethtool_coalesce *ec)
88662306a36Sopenharmony_ci{
88762306a36Sopenharmony_ci	return __iavf_set_coalesce(netdev, ec, queue);
88862306a36Sopenharmony_ci}
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci/**
89162306a36Sopenharmony_ci * iavf_fltr_to_ethtool_flow - convert filter type values to ethtool
89262306a36Sopenharmony_ci * flow type values
89362306a36Sopenharmony_ci * @flow: filter type to be converted
89462306a36Sopenharmony_ci *
89562306a36Sopenharmony_ci * Returns the corresponding ethtool flow type.
89662306a36Sopenharmony_ci */
89762306a36Sopenharmony_cistatic int iavf_fltr_to_ethtool_flow(enum iavf_fdir_flow_type flow)
89862306a36Sopenharmony_ci{
89962306a36Sopenharmony_ci	switch (flow) {
90062306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_TCP:
90162306a36Sopenharmony_ci		return TCP_V4_FLOW;
90262306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_UDP:
90362306a36Sopenharmony_ci		return UDP_V4_FLOW;
90462306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_SCTP:
90562306a36Sopenharmony_ci		return SCTP_V4_FLOW;
90662306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_AH:
90762306a36Sopenharmony_ci		return AH_V4_FLOW;
90862306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_ESP:
90962306a36Sopenharmony_ci		return ESP_V4_FLOW;
91062306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV4_OTHER:
91162306a36Sopenharmony_ci		return IPV4_USER_FLOW;
91262306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_TCP:
91362306a36Sopenharmony_ci		return TCP_V6_FLOW;
91462306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_UDP:
91562306a36Sopenharmony_ci		return UDP_V6_FLOW;
91662306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_SCTP:
91762306a36Sopenharmony_ci		return SCTP_V6_FLOW;
91862306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_AH:
91962306a36Sopenharmony_ci		return AH_V6_FLOW;
92062306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_ESP:
92162306a36Sopenharmony_ci		return ESP_V6_FLOW;
92262306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_IPV6_OTHER:
92362306a36Sopenharmony_ci		return IPV6_USER_FLOW;
92462306a36Sopenharmony_ci	case IAVF_FDIR_FLOW_NON_IP_L2:
92562306a36Sopenharmony_ci		return ETHER_FLOW;
92662306a36Sopenharmony_ci	default:
92762306a36Sopenharmony_ci		/* 0 is undefined ethtool flow */
92862306a36Sopenharmony_ci		return 0;
92962306a36Sopenharmony_ci	}
93062306a36Sopenharmony_ci}
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci/**
93362306a36Sopenharmony_ci * iavf_ethtool_flow_to_fltr - convert ethtool flow type to filter enum
93462306a36Sopenharmony_ci * @eth: Ethtool flow type to be converted
93562306a36Sopenharmony_ci *
93662306a36Sopenharmony_ci * Returns flow enum
93762306a36Sopenharmony_ci */
93862306a36Sopenharmony_cistatic enum iavf_fdir_flow_type iavf_ethtool_flow_to_fltr(int eth)
93962306a36Sopenharmony_ci{
94062306a36Sopenharmony_ci	switch (eth) {
94162306a36Sopenharmony_ci	case TCP_V4_FLOW:
94262306a36Sopenharmony_ci		return IAVF_FDIR_FLOW_IPV4_TCP;
94362306a36Sopenharmony_ci	case UDP_V4_FLOW:
94462306a36Sopenharmony_ci		return IAVF_FDIR_FLOW_IPV4_UDP;
94562306a36Sopenharmony_ci	case SCTP_V4_FLOW:
94662306a36Sopenharmony_ci		return IAVF_FDIR_FLOW_IPV4_SCTP;
94762306a36Sopenharmony_ci	case AH_V4_FLOW:
94862306a36Sopenharmony_ci		return IAVF_FDIR_FLOW_IPV4_AH;
94962306a36Sopenharmony_ci	case ESP_V4_FLOW:
95062306a36Sopenharmony_ci		return IAVF_FDIR_FLOW_IPV4_ESP;
95162306a36Sopenharmony_ci	case IPV4_USER_FLOW:
95262306a36Sopenharmony_ci		return IAVF_FDIR_FLOW_IPV4_OTHER;
95362306a36Sopenharmony_ci	case TCP_V6_FLOW:
95462306a36Sopenharmony_ci		return IAVF_FDIR_FLOW_IPV6_TCP;
95562306a36Sopenharmony_ci	case UDP_V6_FLOW:
95662306a36Sopenharmony_ci		return IAVF_FDIR_FLOW_IPV6_UDP;
95762306a36Sopenharmony_ci	case SCTP_V6_FLOW:
95862306a36Sopenharmony_ci		return IAVF_FDIR_FLOW_IPV6_SCTP;
95962306a36Sopenharmony_ci	case AH_V6_FLOW:
96062306a36Sopenharmony_ci		return IAVF_FDIR_FLOW_IPV6_AH;
96162306a36Sopenharmony_ci	case ESP_V6_FLOW:
96262306a36Sopenharmony_ci		return IAVF_FDIR_FLOW_IPV6_ESP;
96362306a36Sopenharmony_ci	case IPV6_USER_FLOW:
96462306a36Sopenharmony_ci		return IAVF_FDIR_FLOW_IPV6_OTHER;
96562306a36Sopenharmony_ci	case ETHER_FLOW:
96662306a36Sopenharmony_ci		return IAVF_FDIR_FLOW_NON_IP_L2;
96762306a36Sopenharmony_ci	default:
96862306a36Sopenharmony_ci		return IAVF_FDIR_FLOW_NONE;
96962306a36Sopenharmony_ci	}
97062306a36Sopenharmony_ci}
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci/**
97362306a36Sopenharmony_ci * iavf_is_mask_valid - check mask field set
97462306a36Sopenharmony_ci * @mask: full mask to check
97562306a36Sopenharmony_ci * @field: field for which mask should be valid
97662306a36Sopenharmony_ci *
97762306a36Sopenharmony_ci * If the mask is fully set return true. If it is not valid for field return
97862306a36Sopenharmony_ci * false.
97962306a36Sopenharmony_ci */
98062306a36Sopenharmony_cistatic bool iavf_is_mask_valid(u64 mask, u64 field)
98162306a36Sopenharmony_ci{
98262306a36Sopenharmony_ci	return (mask & field) == field;
98362306a36Sopenharmony_ci}
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci/**
98662306a36Sopenharmony_ci * iavf_parse_rx_flow_user_data - deconstruct user-defined data
98762306a36Sopenharmony_ci * @fsp: pointer to ethtool Rx flow specification
98862306a36Sopenharmony_ci * @fltr: pointer to Flow Director filter for userdef data storage
98962306a36Sopenharmony_ci *
99062306a36Sopenharmony_ci * Returns 0 on success, negative error value on failure
99162306a36Sopenharmony_ci */
99262306a36Sopenharmony_cistatic int
99362306a36Sopenharmony_ciiavf_parse_rx_flow_user_data(struct ethtool_rx_flow_spec *fsp,
99462306a36Sopenharmony_ci			     struct iavf_fdir_fltr *fltr)
99562306a36Sopenharmony_ci{
99662306a36Sopenharmony_ci	struct iavf_flex_word *flex;
99762306a36Sopenharmony_ci	int i, cnt = 0;
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	if (!(fsp->flow_type & FLOW_EXT))
100062306a36Sopenharmony_ci		return 0;
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	for (i = 0; i < IAVF_FLEX_WORD_NUM; i++) {
100362306a36Sopenharmony_ci#define IAVF_USERDEF_FLEX_WORD_M	GENMASK(15, 0)
100462306a36Sopenharmony_ci#define IAVF_USERDEF_FLEX_OFFS_S	16
100562306a36Sopenharmony_ci#define IAVF_USERDEF_FLEX_OFFS_M	GENMASK(31, IAVF_USERDEF_FLEX_OFFS_S)
100662306a36Sopenharmony_ci#define IAVF_USERDEF_FLEX_FLTR_M	GENMASK(31, 0)
100762306a36Sopenharmony_ci		u32 value = be32_to_cpu(fsp->h_ext.data[i]);
100862306a36Sopenharmony_ci		u32 mask = be32_to_cpu(fsp->m_ext.data[i]);
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci		if (!value || !mask)
101162306a36Sopenharmony_ci			continue;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci		if (!iavf_is_mask_valid(mask, IAVF_USERDEF_FLEX_FLTR_M))
101462306a36Sopenharmony_ci			return -EINVAL;
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci		/* 504 is the maximum value for offsets, and offset is measured
101762306a36Sopenharmony_ci		 * from the start of the MAC address.
101862306a36Sopenharmony_ci		 */
101962306a36Sopenharmony_ci#define IAVF_USERDEF_FLEX_MAX_OFFS_VAL 504
102062306a36Sopenharmony_ci		flex = &fltr->flex_words[cnt++];
102162306a36Sopenharmony_ci		flex->word = value & IAVF_USERDEF_FLEX_WORD_M;
102262306a36Sopenharmony_ci		flex->offset = (value & IAVF_USERDEF_FLEX_OFFS_M) >>
102362306a36Sopenharmony_ci			     IAVF_USERDEF_FLEX_OFFS_S;
102462306a36Sopenharmony_ci		if (flex->offset > IAVF_USERDEF_FLEX_MAX_OFFS_VAL)
102562306a36Sopenharmony_ci			return -EINVAL;
102662306a36Sopenharmony_ci	}
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	fltr->flex_cnt = cnt;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	return 0;
103162306a36Sopenharmony_ci}
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci/**
103462306a36Sopenharmony_ci * iavf_fill_rx_flow_ext_data - fill the additional data
103562306a36Sopenharmony_ci * @fsp: pointer to ethtool Rx flow specification
103662306a36Sopenharmony_ci * @fltr: pointer to Flow Director filter to get additional data
103762306a36Sopenharmony_ci */
103862306a36Sopenharmony_cistatic void
103962306a36Sopenharmony_ciiavf_fill_rx_flow_ext_data(struct ethtool_rx_flow_spec *fsp,
104062306a36Sopenharmony_ci			   struct iavf_fdir_fltr *fltr)
104162306a36Sopenharmony_ci{
104262306a36Sopenharmony_ci	if (!fltr->ext_mask.usr_def[0] && !fltr->ext_mask.usr_def[1])
104362306a36Sopenharmony_ci		return;
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	fsp->flow_type |= FLOW_EXT;
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	memcpy(fsp->h_ext.data, fltr->ext_data.usr_def, sizeof(fsp->h_ext.data));
104862306a36Sopenharmony_ci	memcpy(fsp->m_ext.data, fltr->ext_mask.usr_def, sizeof(fsp->m_ext.data));
104962306a36Sopenharmony_ci}
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci/**
105262306a36Sopenharmony_ci * iavf_get_ethtool_fdir_entry - fill ethtool structure with Flow Director filter data
105362306a36Sopenharmony_ci * @adapter: the VF adapter structure that contains filter list
105462306a36Sopenharmony_ci * @cmd: ethtool command data structure to receive the filter data
105562306a36Sopenharmony_ci *
105662306a36Sopenharmony_ci * Returns 0 as expected for success by ethtool
105762306a36Sopenharmony_ci */
105862306a36Sopenharmony_cistatic int
105962306a36Sopenharmony_ciiavf_get_ethtool_fdir_entry(struct iavf_adapter *adapter,
106062306a36Sopenharmony_ci			    struct ethtool_rxnfc *cmd)
106162306a36Sopenharmony_ci{
106262306a36Sopenharmony_ci	struct ethtool_rx_flow_spec *fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
106362306a36Sopenharmony_ci	struct iavf_fdir_fltr *rule = NULL;
106462306a36Sopenharmony_ci	int ret = 0;
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))
106762306a36Sopenharmony_ci		return -EOPNOTSUPP;
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	spin_lock_bh(&adapter->fdir_fltr_lock);
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	rule = iavf_find_fdir_fltr_by_loc(adapter, fsp->location);
107262306a36Sopenharmony_ci	if (!rule) {
107362306a36Sopenharmony_ci		ret = -EINVAL;
107462306a36Sopenharmony_ci		goto release_lock;
107562306a36Sopenharmony_ci	}
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	fsp->flow_type = iavf_fltr_to_ethtool_flow(rule->flow_type);
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	memset(&fsp->m_u, 0, sizeof(fsp->m_u));
108062306a36Sopenharmony_ci	memset(&fsp->m_ext, 0, sizeof(fsp->m_ext));
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	switch (fsp->flow_type) {
108362306a36Sopenharmony_ci	case TCP_V4_FLOW:
108462306a36Sopenharmony_ci	case UDP_V4_FLOW:
108562306a36Sopenharmony_ci	case SCTP_V4_FLOW:
108662306a36Sopenharmony_ci		fsp->h_u.tcp_ip4_spec.ip4src = rule->ip_data.v4_addrs.src_ip;
108762306a36Sopenharmony_ci		fsp->h_u.tcp_ip4_spec.ip4dst = rule->ip_data.v4_addrs.dst_ip;
108862306a36Sopenharmony_ci		fsp->h_u.tcp_ip4_spec.psrc = rule->ip_data.src_port;
108962306a36Sopenharmony_ci		fsp->h_u.tcp_ip4_spec.pdst = rule->ip_data.dst_port;
109062306a36Sopenharmony_ci		fsp->h_u.tcp_ip4_spec.tos = rule->ip_data.tos;
109162306a36Sopenharmony_ci		fsp->m_u.tcp_ip4_spec.ip4src = rule->ip_mask.v4_addrs.src_ip;
109262306a36Sopenharmony_ci		fsp->m_u.tcp_ip4_spec.ip4dst = rule->ip_mask.v4_addrs.dst_ip;
109362306a36Sopenharmony_ci		fsp->m_u.tcp_ip4_spec.psrc = rule->ip_mask.src_port;
109462306a36Sopenharmony_ci		fsp->m_u.tcp_ip4_spec.pdst = rule->ip_mask.dst_port;
109562306a36Sopenharmony_ci		fsp->m_u.tcp_ip4_spec.tos = rule->ip_mask.tos;
109662306a36Sopenharmony_ci		break;
109762306a36Sopenharmony_ci	case AH_V4_FLOW:
109862306a36Sopenharmony_ci	case ESP_V4_FLOW:
109962306a36Sopenharmony_ci		fsp->h_u.ah_ip4_spec.ip4src = rule->ip_data.v4_addrs.src_ip;
110062306a36Sopenharmony_ci		fsp->h_u.ah_ip4_spec.ip4dst = rule->ip_data.v4_addrs.dst_ip;
110162306a36Sopenharmony_ci		fsp->h_u.ah_ip4_spec.spi = rule->ip_data.spi;
110262306a36Sopenharmony_ci		fsp->h_u.ah_ip4_spec.tos = rule->ip_data.tos;
110362306a36Sopenharmony_ci		fsp->m_u.ah_ip4_spec.ip4src = rule->ip_mask.v4_addrs.src_ip;
110462306a36Sopenharmony_ci		fsp->m_u.ah_ip4_spec.ip4dst = rule->ip_mask.v4_addrs.dst_ip;
110562306a36Sopenharmony_ci		fsp->m_u.ah_ip4_spec.spi = rule->ip_mask.spi;
110662306a36Sopenharmony_ci		fsp->m_u.ah_ip4_spec.tos = rule->ip_mask.tos;
110762306a36Sopenharmony_ci		break;
110862306a36Sopenharmony_ci	case IPV4_USER_FLOW:
110962306a36Sopenharmony_ci		fsp->h_u.usr_ip4_spec.ip4src = rule->ip_data.v4_addrs.src_ip;
111062306a36Sopenharmony_ci		fsp->h_u.usr_ip4_spec.ip4dst = rule->ip_data.v4_addrs.dst_ip;
111162306a36Sopenharmony_ci		fsp->h_u.usr_ip4_spec.l4_4_bytes = rule->ip_data.l4_header;
111262306a36Sopenharmony_ci		fsp->h_u.usr_ip4_spec.tos = rule->ip_data.tos;
111362306a36Sopenharmony_ci		fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;
111462306a36Sopenharmony_ci		fsp->h_u.usr_ip4_spec.proto = rule->ip_data.proto;
111562306a36Sopenharmony_ci		fsp->m_u.usr_ip4_spec.ip4src = rule->ip_mask.v4_addrs.src_ip;
111662306a36Sopenharmony_ci		fsp->m_u.usr_ip4_spec.ip4dst = rule->ip_mask.v4_addrs.dst_ip;
111762306a36Sopenharmony_ci		fsp->m_u.usr_ip4_spec.l4_4_bytes = rule->ip_mask.l4_header;
111862306a36Sopenharmony_ci		fsp->m_u.usr_ip4_spec.tos = rule->ip_mask.tos;
111962306a36Sopenharmony_ci		fsp->m_u.usr_ip4_spec.ip_ver = 0xFF;
112062306a36Sopenharmony_ci		fsp->m_u.usr_ip4_spec.proto = rule->ip_mask.proto;
112162306a36Sopenharmony_ci		break;
112262306a36Sopenharmony_ci	case TCP_V6_FLOW:
112362306a36Sopenharmony_ci	case UDP_V6_FLOW:
112462306a36Sopenharmony_ci	case SCTP_V6_FLOW:
112562306a36Sopenharmony_ci		memcpy(fsp->h_u.usr_ip6_spec.ip6src, &rule->ip_data.v6_addrs.src_ip,
112662306a36Sopenharmony_ci		       sizeof(struct in6_addr));
112762306a36Sopenharmony_ci		memcpy(fsp->h_u.usr_ip6_spec.ip6dst, &rule->ip_data.v6_addrs.dst_ip,
112862306a36Sopenharmony_ci		       sizeof(struct in6_addr));
112962306a36Sopenharmony_ci		fsp->h_u.tcp_ip6_spec.psrc = rule->ip_data.src_port;
113062306a36Sopenharmony_ci		fsp->h_u.tcp_ip6_spec.pdst = rule->ip_data.dst_port;
113162306a36Sopenharmony_ci		fsp->h_u.tcp_ip6_spec.tclass = rule->ip_data.tclass;
113262306a36Sopenharmony_ci		memcpy(fsp->m_u.usr_ip6_spec.ip6src, &rule->ip_mask.v6_addrs.src_ip,
113362306a36Sopenharmony_ci		       sizeof(struct in6_addr));
113462306a36Sopenharmony_ci		memcpy(fsp->m_u.usr_ip6_spec.ip6dst, &rule->ip_mask.v6_addrs.dst_ip,
113562306a36Sopenharmony_ci		       sizeof(struct in6_addr));
113662306a36Sopenharmony_ci		fsp->m_u.tcp_ip6_spec.psrc = rule->ip_mask.src_port;
113762306a36Sopenharmony_ci		fsp->m_u.tcp_ip6_spec.pdst = rule->ip_mask.dst_port;
113862306a36Sopenharmony_ci		fsp->m_u.tcp_ip6_spec.tclass = rule->ip_mask.tclass;
113962306a36Sopenharmony_ci		break;
114062306a36Sopenharmony_ci	case AH_V6_FLOW:
114162306a36Sopenharmony_ci	case ESP_V6_FLOW:
114262306a36Sopenharmony_ci		memcpy(fsp->h_u.ah_ip6_spec.ip6src, &rule->ip_data.v6_addrs.src_ip,
114362306a36Sopenharmony_ci		       sizeof(struct in6_addr));
114462306a36Sopenharmony_ci		memcpy(fsp->h_u.ah_ip6_spec.ip6dst, &rule->ip_data.v6_addrs.dst_ip,
114562306a36Sopenharmony_ci		       sizeof(struct in6_addr));
114662306a36Sopenharmony_ci		fsp->h_u.ah_ip6_spec.spi = rule->ip_data.spi;
114762306a36Sopenharmony_ci		fsp->h_u.ah_ip6_spec.tclass = rule->ip_data.tclass;
114862306a36Sopenharmony_ci		memcpy(fsp->m_u.ah_ip6_spec.ip6src, &rule->ip_mask.v6_addrs.src_ip,
114962306a36Sopenharmony_ci		       sizeof(struct in6_addr));
115062306a36Sopenharmony_ci		memcpy(fsp->m_u.ah_ip6_spec.ip6dst, &rule->ip_mask.v6_addrs.dst_ip,
115162306a36Sopenharmony_ci		       sizeof(struct in6_addr));
115262306a36Sopenharmony_ci		fsp->m_u.ah_ip6_spec.spi = rule->ip_mask.spi;
115362306a36Sopenharmony_ci		fsp->m_u.ah_ip6_spec.tclass = rule->ip_mask.tclass;
115462306a36Sopenharmony_ci		break;
115562306a36Sopenharmony_ci	case IPV6_USER_FLOW:
115662306a36Sopenharmony_ci		memcpy(fsp->h_u.usr_ip6_spec.ip6src, &rule->ip_data.v6_addrs.src_ip,
115762306a36Sopenharmony_ci		       sizeof(struct in6_addr));
115862306a36Sopenharmony_ci		memcpy(fsp->h_u.usr_ip6_spec.ip6dst, &rule->ip_data.v6_addrs.dst_ip,
115962306a36Sopenharmony_ci		       sizeof(struct in6_addr));
116062306a36Sopenharmony_ci		fsp->h_u.usr_ip6_spec.l4_4_bytes = rule->ip_data.l4_header;
116162306a36Sopenharmony_ci		fsp->h_u.usr_ip6_spec.tclass = rule->ip_data.tclass;
116262306a36Sopenharmony_ci		fsp->h_u.usr_ip6_spec.l4_proto = rule->ip_data.proto;
116362306a36Sopenharmony_ci		memcpy(fsp->m_u.usr_ip6_spec.ip6src, &rule->ip_mask.v6_addrs.src_ip,
116462306a36Sopenharmony_ci		       sizeof(struct in6_addr));
116562306a36Sopenharmony_ci		memcpy(fsp->m_u.usr_ip6_spec.ip6dst, &rule->ip_mask.v6_addrs.dst_ip,
116662306a36Sopenharmony_ci		       sizeof(struct in6_addr));
116762306a36Sopenharmony_ci		fsp->m_u.usr_ip6_spec.l4_4_bytes = rule->ip_mask.l4_header;
116862306a36Sopenharmony_ci		fsp->m_u.usr_ip6_spec.tclass = rule->ip_mask.tclass;
116962306a36Sopenharmony_ci		fsp->m_u.usr_ip6_spec.l4_proto = rule->ip_mask.proto;
117062306a36Sopenharmony_ci		break;
117162306a36Sopenharmony_ci	case ETHER_FLOW:
117262306a36Sopenharmony_ci		fsp->h_u.ether_spec.h_proto = rule->eth_data.etype;
117362306a36Sopenharmony_ci		fsp->m_u.ether_spec.h_proto = rule->eth_mask.etype;
117462306a36Sopenharmony_ci		break;
117562306a36Sopenharmony_ci	default:
117662306a36Sopenharmony_ci		ret = -EINVAL;
117762306a36Sopenharmony_ci		break;
117862306a36Sopenharmony_ci	}
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	iavf_fill_rx_flow_ext_data(fsp, rule);
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	if (rule->action == VIRTCHNL_ACTION_DROP)
118362306a36Sopenharmony_ci		fsp->ring_cookie = RX_CLS_FLOW_DISC;
118462306a36Sopenharmony_ci	else
118562306a36Sopenharmony_ci		fsp->ring_cookie = rule->q_index;
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_cirelease_lock:
118862306a36Sopenharmony_ci	spin_unlock_bh(&adapter->fdir_fltr_lock);
118962306a36Sopenharmony_ci	return ret;
119062306a36Sopenharmony_ci}
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci/**
119362306a36Sopenharmony_ci * iavf_get_fdir_fltr_ids - fill buffer with filter IDs of active filters
119462306a36Sopenharmony_ci * @adapter: the VF adapter structure containing the filter list
119562306a36Sopenharmony_ci * @cmd: ethtool command data structure
119662306a36Sopenharmony_ci * @rule_locs: ethtool array passed in from OS to receive filter IDs
119762306a36Sopenharmony_ci *
119862306a36Sopenharmony_ci * Returns 0 as expected for success by ethtool
119962306a36Sopenharmony_ci */
120062306a36Sopenharmony_cistatic int
120162306a36Sopenharmony_ciiavf_get_fdir_fltr_ids(struct iavf_adapter *adapter, struct ethtool_rxnfc *cmd,
120262306a36Sopenharmony_ci		       u32 *rule_locs)
120362306a36Sopenharmony_ci{
120462306a36Sopenharmony_ci	struct iavf_fdir_fltr *fltr;
120562306a36Sopenharmony_ci	unsigned int cnt = 0;
120662306a36Sopenharmony_ci	int val = 0;
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))
120962306a36Sopenharmony_ci		return -EOPNOTSUPP;
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	cmd->data = IAVF_MAX_FDIR_FILTERS;
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	spin_lock_bh(&adapter->fdir_fltr_lock);
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	list_for_each_entry(fltr, &adapter->fdir_list_head, list) {
121662306a36Sopenharmony_ci		if (cnt == cmd->rule_cnt) {
121762306a36Sopenharmony_ci			val = -EMSGSIZE;
121862306a36Sopenharmony_ci			goto release_lock;
121962306a36Sopenharmony_ci		}
122062306a36Sopenharmony_ci		rule_locs[cnt] = fltr->loc;
122162306a36Sopenharmony_ci		cnt++;
122262306a36Sopenharmony_ci	}
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_cirelease_lock:
122562306a36Sopenharmony_ci	spin_unlock_bh(&adapter->fdir_fltr_lock);
122662306a36Sopenharmony_ci	if (!val)
122762306a36Sopenharmony_ci		cmd->rule_cnt = cnt;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	return val;
123062306a36Sopenharmony_ci}
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci/**
123362306a36Sopenharmony_ci * iavf_add_fdir_fltr_info - Set the input set for Flow Director filter
123462306a36Sopenharmony_ci * @adapter: pointer to the VF adapter structure
123562306a36Sopenharmony_ci * @fsp: pointer to ethtool Rx flow specification
123662306a36Sopenharmony_ci * @fltr: filter structure
123762306a36Sopenharmony_ci */
123862306a36Sopenharmony_cistatic int
123962306a36Sopenharmony_ciiavf_add_fdir_fltr_info(struct iavf_adapter *adapter, struct ethtool_rx_flow_spec *fsp,
124062306a36Sopenharmony_ci			struct iavf_fdir_fltr *fltr)
124162306a36Sopenharmony_ci{
124262306a36Sopenharmony_ci	u32 flow_type, q_index = 0;
124362306a36Sopenharmony_ci	enum virtchnl_action act;
124462306a36Sopenharmony_ci	int err;
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	if (fsp->ring_cookie == RX_CLS_FLOW_DISC) {
124762306a36Sopenharmony_ci		act = VIRTCHNL_ACTION_DROP;
124862306a36Sopenharmony_ci	} else {
124962306a36Sopenharmony_ci		q_index = fsp->ring_cookie;
125062306a36Sopenharmony_ci		if (q_index >= adapter->num_active_queues)
125162306a36Sopenharmony_ci			return -EINVAL;
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci		act = VIRTCHNL_ACTION_QUEUE;
125462306a36Sopenharmony_ci	}
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	fltr->action = act;
125762306a36Sopenharmony_ci	fltr->loc = fsp->location;
125862306a36Sopenharmony_ci	fltr->q_index = q_index;
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	if (fsp->flow_type & FLOW_EXT) {
126162306a36Sopenharmony_ci		memcpy(fltr->ext_data.usr_def, fsp->h_ext.data,
126262306a36Sopenharmony_ci		       sizeof(fltr->ext_data.usr_def));
126362306a36Sopenharmony_ci		memcpy(fltr->ext_mask.usr_def, fsp->m_ext.data,
126462306a36Sopenharmony_ci		       sizeof(fltr->ext_mask.usr_def));
126562306a36Sopenharmony_ci	}
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
126862306a36Sopenharmony_ci	fltr->flow_type = iavf_ethtool_flow_to_fltr(flow_type);
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	switch (flow_type) {
127162306a36Sopenharmony_ci	case TCP_V4_FLOW:
127262306a36Sopenharmony_ci	case UDP_V4_FLOW:
127362306a36Sopenharmony_ci	case SCTP_V4_FLOW:
127462306a36Sopenharmony_ci		fltr->ip_data.v4_addrs.src_ip = fsp->h_u.tcp_ip4_spec.ip4src;
127562306a36Sopenharmony_ci		fltr->ip_data.v4_addrs.dst_ip = fsp->h_u.tcp_ip4_spec.ip4dst;
127662306a36Sopenharmony_ci		fltr->ip_data.src_port = fsp->h_u.tcp_ip4_spec.psrc;
127762306a36Sopenharmony_ci		fltr->ip_data.dst_port = fsp->h_u.tcp_ip4_spec.pdst;
127862306a36Sopenharmony_ci		fltr->ip_data.tos = fsp->h_u.tcp_ip4_spec.tos;
127962306a36Sopenharmony_ci		fltr->ip_mask.v4_addrs.src_ip = fsp->m_u.tcp_ip4_spec.ip4src;
128062306a36Sopenharmony_ci		fltr->ip_mask.v4_addrs.dst_ip = fsp->m_u.tcp_ip4_spec.ip4dst;
128162306a36Sopenharmony_ci		fltr->ip_mask.src_port = fsp->m_u.tcp_ip4_spec.psrc;
128262306a36Sopenharmony_ci		fltr->ip_mask.dst_port = fsp->m_u.tcp_ip4_spec.pdst;
128362306a36Sopenharmony_ci		fltr->ip_mask.tos = fsp->m_u.tcp_ip4_spec.tos;
128462306a36Sopenharmony_ci		fltr->ip_ver = 4;
128562306a36Sopenharmony_ci		break;
128662306a36Sopenharmony_ci	case AH_V4_FLOW:
128762306a36Sopenharmony_ci	case ESP_V4_FLOW:
128862306a36Sopenharmony_ci		fltr->ip_data.v4_addrs.src_ip = fsp->h_u.ah_ip4_spec.ip4src;
128962306a36Sopenharmony_ci		fltr->ip_data.v4_addrs.dst_ip = fsp->h_u.ah_ip4_spec.ip4dst;
129062306a36Sopenharmony_ci		fltr->ip_data.spi = fsp->h_u.ah_ip4_spec.spi;
129162306a36Sopenharmony_ci		fltr->ip_data.tos = fsp->h_u.ah_ip4_spec.tos;
129262306a36Sopenharmony_ci		fltr->ip_mask.v4_addrs.src_ip = fsp->m_u.ah_ip4_spec.ip4src;
129362306a36Sopenharmony_ci		fltr->ip_mask.v4_addrs.dst_ip = fsp->m_u.ah_ip4_spec.ip4dst;
129462306a36Sopenharmony_ci		fltr->ip_mask.spi = fsp->m_u.ah_ip4_spec.spi;
129562306a36Sopenharmony_ci		fltr->ip_mask.tos = fsp->m_u.ah_ip4_spec.tos;
129662306a36Sopenharmony_ci		fltr->ip_ver = 4;
129762306a36Sopenharmony_ci		break;
129862306a36Sopenharmony_ci	case IPV4_USER_FLOW:
129962306a36Sopenharmony_ci		fltr->ip_data.v4_addrs.src_ip = fsp->h_u.usr_ip4_spec.ip4src;
130062306a36Sopenharmony_ci		fltr->ip_data.v4_addrs.dst_ip = fsp->h_u.usr_ip4_spec.ip4dst;
130162306a36Sopenharmony_ci		fltr->ip_data.l4_header = fsp->h_u.usr_ip4_spec.l4_4_bytes;
130262306a36Sopenharmony_ci		fltr->ip_data.tos = fsp->h_u.usr_ip4_spec.tos;
130362306a36Sopenharmony_ci		fltr->ip_data.proto = fsp->h_u.usr_ip4_spec.proto;
130462306a36Sopenharmony_ci		fltr->ip_mask.v4_addrs.src_ip = fsp->m_u.usr_ip4_spec.ip4src;
130562306a36Sopenharmony_ci		fltr->ip_mask.v4_addrs.dst_ip = fsp->m_u.usr_ip4_spec.ip4dst;
130662306a36Sopenharmony_ci		fltr->ip_mask.l4_header = fsp->m_u.usr_ip4_spec.l4_4_bytes;
130762306a36Sopenharmony_ci		fltr->ip_mask.tos = fsp->m_u.usr_ip4_spec.tos;
130862306a36Sopenharmony_ci		fltr->ip_mask.proto = fsp->m_u.usr_ip4_spec.proto;
130962306a36Sopenharmony_ci		fltr->ip_ver = 4;
131062306a36Sopenharmony_ci		break;
131162306a36Sopenharmony_ci	case TCP_V6_FLOW:
131262306a36Sopenharmony_ci	case UDP_V6_FLOW:
131362306a36Sopenharmony_ci	case SCTP_V6_FLOW:
131462306a36Sopenharmony_ci		memcpy(&fltr->ip_data.v6_addrs.src_ip, fsp->h_u.usr_ip6_spec.ip6src,
131562306a36Sopenharmony_ci		       sizeof(struct in6_addr));
131662306a36Sopenharmony_ci		memcpy(&fltr->ip_data.v6_addrs.dst_ip, fsp->h_u.usr_ip6_spec.ip6dst,
131762306a36Sopenharmony_ci		       sizeof(struct in6_addr));
131862306a36Sopenharmony_ci		fltr->ip_data.src_port = fsp->h_u.tcp_ip6_spec.psrc;
131962306a36Sopenharmony_ci		fltr->ip_data.dst_port = fsp->h_u.tcp_ip6_spec.pdst;
132062306a36Sopenharmony_ci		fltr->ip_data.tclass = fsp->h_u.tcp_ip6_spec.tclass;
132162306a36Sopenharmony_ci		memcpy(&fltr->ip_mask.v6_addrs.src_ip, fsp->m_u.usr_ip6_spec.ip6src,
132262306a36Sopenharmony_ci		       sizeof(struct in6_addr));
132362306a36Sopenharmony_ci		memcpy(&fltr->ip_mask.v6_addrs.dst_ip, fsp->m_u.usr_ip6_spec.ip6dst,
132462306a36Sopenharmony_ci		       sizeof(struct in6_addr));
132562306a36Sopenharmony_ci		fltr->ip_mask.src_port = fsp->m_u.tcp_ip6_spec.psrc;
132662306a36Sopenharmony_ci		fltr->ip_mask.dst_port = fsp->m_u.tcp_ip6_spec.pdst;
132762306a36Sopenharmony_ci		fltr->ip_mask.tclass = fsp->m_u.tcp_ip6_spec.tclass;
132862306a36Sopenharmony_ci		fltr->ip_ver = 6;
132962306a36Sopenharmony_ci		break;
133062306a36Sopenharmony_ci	case AH_V6_FLOW:
133162306a36Sopenharmony_ci	case ESP_V6_FLOW:
133262306a36Sopenharmony_ci		memcpy(&fltr->ip_data.v6_addrs.src_ip, fsp->h_u.ah_ip6_spec.ip6src,
133362306a36Sopenharmony_ci		       sizeof(struct in6_addr));
133462306a36Sopenharmony_ci		memcpy(&fltr->ip_data.v6_addrs.dst_ip, fsp->h_u.ah_ip6_spec.ip6dst,
133562306a36Sopenharmony_ci		       sizeof(struct in6_addr));
133662306a36Sopenharmony_ci		fltr->ip_data.spi = fsp->h_u.ah_ip6_spec.spi;
133762306a36Sopenharmony_ci		fltr->ip_data.tclass = fsp->h_u.ah_ip6_spec.tclass;
133862306a36Sopenharmony_ci		memcpy(&fltr->ip_mask.v6_addrs.src_ip, fsp->m_u.ah_ip6_spec.ip6src,
133962306a36Sopenharmony_ci		       sizeof(struct in6_addr));
134062306a36Sopenharmony_ci		memcpy(&fltr->ip_mask.v6_addrs.dst_ip, fsp->m_u.ah_ip6_spec.ip6dst,
134162306a36Sopenharmony_ci		       sizeof(struct in6_addr));
134262306a36Sopenharmony_ci		fltr->ip_mask.spi = fsp->m_u.ah_ip6_spec.spi;
134362306a36Sopenharmony_ci		fltr->ip_mask.tclass = fsp->m_u.ah_ip6_spec.tclass;
134462306a36Sopenharmony_ci		fltr->ip_ver = 6;
134562306a36Sopenharmony_ci		break;
134662306a36Sopenharmony_ci	case IPV6_USER_FLOW:
134762306a36Sopenharmony_ci		memcpy(&fltr->ip_data.v6_addrs.src_ip, fsp->h_u.usr_ip6_spec.ip6src,
134862306a36Sopenharmony_ci		       sizeof(struct in6_addr));
134962306a36Sopenharmony_ci		memcpy(&fltr->ip_data.v6_addrs.dst_ip, fsp->h_u.usr_ip6_spec.ip6dst,
135062306a36Sopenharmony_ci		       sizeof(struct in6_addr));
135162306a36Sopenharmony_ci		fltr->ip_data.l4_header = fsp->h_u.usr_ip6_spec.l4_4_bytes;
135262306a36Sopenharmony_ci		fltr->ip_data.tclass = fsp->h_u.usr_ip6_spec.tclass;
135362306a36Sopenharmony_ci		fltr->ip_data.proto = fsp->h_u.usr_ip6_spec.l4_proto;
135462306a36Sopenharmony_ci		memcpy(&fltr->ip_mask.v6_addrs.src_ip, fsp->m_u.usr_ip6_spec.ip6src,
135562306a36Sopenharmony_ci		       sizeof(struct in6_addr));
135662306a36Sopenharmony_ci		memcpy(&fltr->ip_mask.v6_addrs.dst_ip, fsp->m_u.usr_ip6_spec.ip6dst,
135762306a36Sopenharmony_ci		       sizeof(struct in6_addr));
135862306a36Sopenharmony_ci		fltr->ip_mask.l4_header = fsp->m_u.usr_ip6_spec.l4_4_bytes;
135962306a36Sopenharmony_ci		fltr->ip_mask.tclass = fsp->m_u.usr_ip6_spec.tclass;
136062306a36Sopenharmony_ci		fltr->ip_mask.proto = fsp->m_u.usr_ip6_spec.l4_proto;
136162306a36Sopenharmony_ci		fltr->ip_ver = 6;
136262306a36Sopenharmony_ci		break;
136362306a36Sopenharmony_ci	case ETHER_FLOW:
136462306a36Sopenharmony_ci		fltr->eth_data.etype = fsp->h_u.ether_spec.h_proto;
136562306a36Sopenharmony_ci		fltr->eth_mask.etype = fsp->m_u.ether_spec.h_proto;
136662306a36Sopenharmony_ci		break;
136762306a36Sopenharmony_ci	default:
136862306a36Sopenharmony_ci		/* not doing un-parsed flow types */
136962306a36Sopenharmony_ci		return -EINVAL;
137062306a36Sopenharmony_ci	}
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	err = iavf_validate_fdir_fltr_masks(adapter, fltr);
137362306a36Sopenharmony_ci	if (err)
137462306a36Sopenharmony_ci		return err;
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	if (iavf_fdir_is_dup_fltr(adapter, fltr))
137762306a36Sopenharmony_ci		return -EEXIST;
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	err = iavf_parse_rx_flow_user_data(fsp, fltr);
138062306a36Sopenharmony_ci	if (err)
138162306a36Sopenharmony_ci		return err;
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	return iavf_fill_fdir_add_msg(adapter, fltr);
138462306a36Sopenharmony_ci}
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci/**
138762306a36Sopenharmony_ci * iavf_add_fdir_ethtool - add Flow Director filter
138862306a36Sopenharmony_ci * @adapter: pointer to the VF adapter structure
138962306a36Sopenharmony_ci * @cmd: command to add Flow Director filter
139062306a36Sopenharmony_ci *
139162306a36Sopenharmony_ci * Returns 0 on success and negative values for failure
139262306a36Sopenharmony_ci */
139362306a36Sopenharmony_cistatic int iavf_add_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rxnfc *cmd)
139462306a36Sopenharmony_ci{
139562306a36Sopenharmony_ci	struct ethtool_rx_flow_spec *fsp = &cmd->fs;
139662306a36Sopenharmony_ci	struct iavf_fdir_fltr *fltr;
139762306a36Sopenharmony_ci	int count = 50;
139862306a36Sopenharmony_ci	int err;
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))
140162306a36Sopenharmony_ci		return -EOPNOTSUPP;
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	if (fsp->flow_type & FLOW_MAC_EXT)
140462306a36Sopenharmony_ci		return -EINVAL;
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	spin_lock_bh(&adapter->fdir_fltr_lock);
140762306a36Sopenharmony_ci	if (adapter->fdir_active_fltr >= IAVF_MAX_FDIR_FILTERS) {
140862306a36Sopenharmony_ci		spin_unlock_bh(&adapter->fdir_fltr_lock);
140962306a36Sopenharmony_ci		dev_err(&adapter->pdev->dev,
141062306a36Sopenharmony_ci			"Unable to add Flow Director filter because VF reached the limit of max allowed filters (%u)\n",
141162306a36Sopenharmony_ci			IAVF_MAX_FDIR_FILTERS);
141262306a36Sopenharmony_ci		return -ENOSPC;
141362306a36Sopenharmony_ci	}
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	if (iavf_find_fdir_fltr_by_loc(adapter, fsp->location)) {
141662306a36Sopenharmony_ci		dev_err(&adapter->pdev->dev, "Failed to add Flow Director filter, it already exists\n");
141762306a36Sopenharmony_ci		spin_unlock_bh(&adapter->fdir_fltr_lock);
141862306a36Sopenharmony_ci		return -EEXIST;
141962306a36Sopenharmony_ci	}
142062306a36Sopenharmony_ci	spin_unlock_bh(&adapter->fdir_fltr_lock);
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	fltr = kzalloc(sizeof(*fltr), GFP_KERNEL);
142362306a36Sopenharmony_ci	if (!fltr)
142462306a36Sopenharmony_ci		return -ENOMEM;
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	while (!mutex_trylock(&adapter->crit_lock)) {
142762306a36Sopenharmony_ci		if (--count == 0) {
142862306a36Sopenharmony_ci			kfree(fltr);
142962306a36Sopenharmony_ci			return -EINVAL;
143062306a36Sopenharmony_ci		}
143162306a36Sopenharmony_ci		udelay(1);
143262306a36Sopenharmony_ci	}
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	err = iavf_add_fdir_fltr_info(adapter, fsp, fltr);
143562306a36Sopenharmony_ci	if (err)
143662306a36Sopenharmony_ci		goto ret;
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci	spin_lock_bh(&adapter->fdir_fltr_lock);
143962306a36Sopenharmony_ci	iavf_fdir_list_add_fltr(adapter, fltr);
144062306a36Sopenharmony_ci	adapter->fdir_active_fltr++;
144162306a36Sopenharmony_ci	if (adapter->link_up) {
144262306a36Sopenharmony_ci		fltr->state = IAVF_FDIR_FLTR_ADD_REQUEST;
144362306a36Sopenharmony_ci		adapter->aq_required |= IAVF_FLAG_AQ_ADD_FDIR_FILTER;
144462306a36Sopenharmony_ci	} else {
144562306a36Sopenharmony_ci		fltr->state = IAVF_FDIR_FLTR_INACTIVE;
144662306a36Sopenharmony_ci	}
144762306a36Sopenharmony_ci	spin_unlock_bh(&adapter->fdir_fltr_lock);
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	if (adapter->link_up)
145062306a36Sopenharmony_ci		mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
145162306a36Sopenharmony_ciret:
145262306a36Sopenharmony_ci	if (err && fltr)
145362306a36Sopenharmony_ci		kfree(fltr);
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	mutex_unlock(&adapter->crit_lock);
145662306a36Sopenharmony_ci	return err;
145762306a36Sopenharmony_ci}
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci/**
146062306a36Sopenharmony_ci * iavf_del_fdir_ethtool - delete Flow Director filter
146162306a36Sopenharmony_ci * @adapter: pointer to the VF adapter structure
146262306a36Sopenharmony_ci * @cmd: command to delete Flow Director filter
146362306a36Sopenharmony_ci *
146462306a36Sopenharmony_ci * Returns 0 on success and negative values for failure
146562306a36Sopenharmony_ci */
146662306a36Sopenharmony_cistatic int iavf_del_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rxnfc *cmd)
146762306a36Sopenharmony_ci{
146862306a36Sopenharmony_ci	struct ethtool_rx_flow_spec *fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
146962306a36Sopenharmony_ci	struct iavf_fdir_fltr *fltr = NULL;
147062306a36Sopenharmony_ci	int err = 0;
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))
147362306a36Sopenharmony_ci		return -EOPNOTSUPP;
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	spin_lock_bh(&adapter->fdir_fltr_lock);
147662306a36Sopenharmony_ci	fltr = iavf_find_fdir_fltr_by_loc(adapter, fsp->location);
147762306a36Sopenharmony_ci	if (fltr) {
147862306a36Sopenharmony_ci		if (fltr->state == IAVF_FDIR_FLTR_ACTIVE) {
147962306a36Sopenharmony_ci			fltr->state = IAVF_FDIR_FLTR_DEL_REQUEST;
148062306a36Sopenharmony_ci			adapter->aq_required |= IAVF_FLAG_AQ_DEL_FDIR_FILTER;
148162306a36Sopenharmony_ci		} else if (fltr->state == IAVF_FDIR_FLTR_INACTIVE) {
148262306a36Sopenharmony_ci			list_del(&fltr->list);
148362306a36Sopenharmony_ci			kfree(fltr);
148462306a36Sopenharmony_ci			adapter->fdir_active_fltr--;
148562306a36Sopenharmony_ci			fltr = NULL;
148662306a36Sopenharmony_ci		} else {
148762306a36Sopenharmony_ci			err = -EBUSY;
148862306a36Sopenharmony_ci		}
148962306a36Sopenharmony_ci	} else if (adapter->fdir_active_fltr) {
149062306a36Sopenharmony_ci		err = -EINVAL;
149162306a36Sopenharmony_ci	}
149262306a36Sopenharmony_ci	spin_unlock_bh(&adapter->fdir_fltr_lock);
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	if (fltr && fltr->state == IAVF_FDIR_FLTR_DEL_REQUEST)
149562306a36Sopenharmony_ci		mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	return err;
149862306a36Sopenharmony_ci}
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci/**
150162306a36Sopenharmony_ci * iavf_adv_rss_parse_hdrs - parses headers from RSS hash input
150262306a36Sopenharmony_ci * @cmd: ethtool rxnfc command
150362306a36Sopenharmony_ci *
150462306a36Sopenharmony_ci * This function parses the rxnfc command and returns intended
150562306a36Sopenharmony_ci * header types for RSS configuration
150662306a36Sopenharmony_ci */
150762306a36Sopenharmony_cistatic u32 iavf_adv_rss_parse_hdrs(struct ethtool_rxnfc *cmd)
150862306a36Sopenharmony_ci{
150962306a36Sopenharmony_ci	u32 hdrs = IAVF_ADV_RSS_FLOW_SEG_HDR_NONE;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	switch (cmd->flow_type) {
151262306a36Sopenharmony_ci	case TCP_V4_FLOW:
151362306a36Sopenharmony_ci		hdrs |= IAVF_ADV_RSS_FLOW_SEG_HDR_TCP |
151462306a36Sopenharmony_ci			IAVF_ADV_RSS_FLOW_SEG_HDR_IPV4;
151562306a36Sopenharmony_ci		break;
151662306a36Sopenharmony_ci	case UDP_V4_FLOW:
151762306a36Sopenharmony_ci		hdrs |= IAVF_ADV_RSS_FLOW_SEG_HDR_UDP |
151862306a36Sopenharmony_ci			IAVF_ADV_RSS_FLOW_SEG_HDR_IPV4;
151962306a36Sopenharmony_ci		break;
152062306a36Sopenharmony_ci	case SCTP_V4_FLOW:
152162306a36Sopenharmony_ci		hdrs |= IAVF_ADV_RSS_FLOW_SEG_HDR_SCTP |
152262306a36Sopenharmony_ci			IAVF_ADV_RSS_FLOW_SEG_HDR_IPV4;
152362306a36Sopenharmony_ci		break;
152462306a36Sopenharmony_ci	case TCP_V6_FLOW:
152562306a36Sopenharmony_ci		hdrs |= IAVF_ADV_RSS_FLOW_SEG_HDR_TCP |
152662306a36Sopenharmony_ci			IAVF_ADV_RSS_FLOW_SEG_HDR_IPV6;
152762306a36Sopenharmony_ci		break;
152862306a36Sopenharmony_ci	case UDP_V6_FLOW:
152962306a36Sopenharmony_ci		hdrs |= IAVF_ADV_RSS_FLOW_SEG_HDR_UDP |
153062306a36Sopenharmony_ci			IAVF_ADV_RSS_FLOW_SEG_HDR_IPV6;
153162306a36Sopenharmony_ci		break;
153262306a36Sopenharmony_ci	case SCTP_V6_FLOW:
153362306a36Sopenharmony_ci		hdrs |= IAVF_ADV_RSS_FLOW_SEG_HDR_SCTP |
153462306a36Sopenharmony_ci			IAVF_ADV_RSS_FLOW_SEG_HDR_IPV6;
153562306a36Sopenharmony_ci		break;
153662306a36Sopenharmony_ci	default:
153762306a36Sopenharmony_ci		break;
153862306a36Sopenharmony_ci	}
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci	return hdrs;
154162306a36Sopenharmony_ci}
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci/**
154462306a36Sopenharmony_ci * iavf_adv_rss_parse_hash_flds - parses hash fields from RSS hash input
154562306a36Sopenharmony_ci * @cmd: ethtool rxnfc command
154662306a36Sopenharmony_ci *
154762306a36Sopenharmony_ci * This function parses the rxnfc command and returns intended hash fields for
154862306a36Sopenharmony_ci * RSS configuration
154962306a36Sopenharmony_ci */
155062306a36Sopenharmony_cistatic u64 iavf_adv_rss_parse_hash_flds(struct ethtool_rxnfc *cmd)
155162306a36Sopenharmony_ci{
155262306a36Sopenharmony_ci	u64 hfld = IAVF_ADV_RSS_HASH_INVALID;
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	if (cmd->data & RXH_IP_SRC || cmd->data & RXH_IP_DST) {
155562306a36Sopenharmony_ci		switch (cmd->flow_type) {
155662306a36Sopenharmony_ci		case TCP_V4_FLOW:
155762306a36Sopenharmony_ci		case UDP_V4_FLOW:
155862306a36Sopenharmony_ci		case SCTP_V4_FLOW:
155962306a36Sopenharmony_ci			if (cmd->data & RXH_IP_SRC)
156062306a36Sopenharmony_ci				hfld |= IAVF_ADV_RSS_HASH_FLD_IPV4_SA;
156162306a36Sopenharmony_ci			if (cmd->data & RXH_IP_DST)
156262306a36Sopenharmony_ci				hfld |= IAVF_ADV_RSS_HASH_FLD_IPV4_DA;
156362306a36Sopenharmony_ci			break;
156462306a36Sopenharmony_ci		case TCP_V6_FLOW:
156562306a36Sopenharmony_ci		case UDP_V6_FLOW:
156662306a36Sopenharmony_ci		case SCTP_V6_FLOW:
156762306a36Sopenharmony_ci			if (cmd->data & RXH_IP_SRC)
156862306a36Sopenharmony_ci				hfld |= IAVF_ADV_RSS_HASH_FLD_IPV6_SA;
156962306a36Sopenharmony_ci			if (cmd->data & RXH_IP_DST)
157062306a36Sopenharmony_ci				hfld |= IAVF_ADV_RSS_HASH_FLD_IPV6_DA;
157162306a36Sopenharmony_ci			break;
157262306a36Sopenharmony_ci		default:
157362306a36Sopenharmony_ci			break;
157462306a36Sopenharmony_ci		}
157562306a36Sopenharmony_ci	}
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	if (cmd->data & RXH_L4_B_0_1 || cmd->data & RXH_L4_B_2_3) {
157862306a36Sopenharmony_ci		switch (cmd->flow_type) {
157962306a36Sopenharmony_ci		case TCP_V4_FLOW:
158062306a36Sopenharmony_ci		case TCP_V6_FLOW:
158162306a36Sopenharmony_ci			if (cmd->data & RXH_L4_B_0_1)
158262306a36Sopenharmony_ci				hfld |= IAVF_ADV_RSS_HASH_FLD_TCP_SRC_PORT;
158362306a36Sopenharmony_ci			if (cmd->data & RXH_L4_B_2_3)
158462306a36Sopenharmony_ci				hfld |= IAVF_ADV_RSS_HASH_FLD_TCP_DST_PORT;
158562306a36Sopenharmony_ci			break;
158662306a36Sopenharmony_ci		case UDP_V4_FLOW:
158762306a36Sopenharmony_ci		case UDP_V6_FLOW:
158862306a36Sopenharmony_ci			if (cmd->data & RXH_L4_B_0_1)
158962306a36Sopenharmony_ci				hfld |= IAVF_ADV_RSS_HASH_FLD_UDP_SRC_PORT;
159062306a36Sopenharmony_ci			if (cmd->data & RXH_L4_B_2_3)
159162306a36Sopenharmony_ci				hfld |= IAVF_ADV_RSS_HASH_FLD_UDP_DST_PORT;
159262306a36Sopenharmony_ci			break;
159362306a36Sopenharmony_ci		case SCTP_V4_FLOW:
159462306a36Sopenharmony_ci		case SCTP_V6_FLOW:
159562306a36Sopenharmony_ci			if (cmd->data & RXH_L4_B_0_1)
159662306a36Sopenharmony_ci				hfld |= IAVF_ADV_RSS_HASH_FLD_SCTP_SRC_PORT;
159762306a36Sopenharmony_ci			if (cmd->data & RXH_L4_B_2_3)
159862306a36Sopenharmony_ci				hfld |= IAVF_ADV_RSS_HASH_FLD_SCTP_DST_PORT;
159962306a36Sopenharmony_ci			break;
160062306a36Sopenharmony_ci		default:
160162306a36Sopenharmony_ci			break;
160262306a36Sopenharmony_ci		}
160362306a36Sopenharmony_ci	}
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	return hfld;
160662306a36Sopenharmony_ci}
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci/**
160962306a36Sopenharmony_ci * iavf_set_adv_rss_hash_opt - Enable/Disable flow types for RSS hash
161062306a36Sopenharmony_ci * @adapter: pointer to the VF adapter structure
161162306a36Sopenharmony_ci * @cmd: ethtool rxnfc command
161262306a36Sopenharmony_ci *
161362306a36Sopenharmony_ci * Returns Success if the flow input set is supported.
161462306a36Sopenharmony_ci */
161562306a36Sopenharmony_cistatic int
161662306a36Sopenharmony_ciiavf_set_adv_rss_hash_opt(struct iavf_adapter *adapter,
161762306a36Sopenharmony_ci			  struct ethtool_rxnfc *cmd)
161862306a36Sopenharmony_ci{
161962306a36Sopenharmony_ci	struct iavf_adv_rss *rss_old, *rss_new;
162062306a36Sopenharmony_ci	bool rss_new_add = false;
162162306a36Sopenharmony_ci	int count = 50, err = 0;
162262306a36Sopenharmony_ci	u64 hash_flds;
162362306a36Sopenharmony_ci	u32 hdrs;
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	if (!ADV_RSS_SUPPORT(adapter))
162662306a36Sopenharmony_ci		return -EOPNOTSUPP;
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	hdrs = iavf_adv_rss_parse_hdrs(cmd);
162962306a36Sopenharmony_ci	if (hdrs == IAVF_ADV_RSS_FLOW_SEG_HDR_NONE)
163062306a36Sopenharmony_ci		return -EINVAL;
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	hash_flds = iavf_adv_rss_parse_hash_flds(cmd);
163362306a36Sopenharmony_ci	if (hash_flds == IAVF_ADV_RSS_HASH_INVALID)
163462306a36Sopenharmony_ci		return -EINVAL;
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	rss_new = kzalloc(sizeof(*rss_new), GFP_KERNEL);
163762306a36Sopenharmony_ci	if (!rss_new)
163862306a36Sopenharmony_ci		return -ENOMEM;
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci	if (iavf_fill_adv_rss_cfg_msg(&rss_new->cfg_msg, hdrs, hash_flds)) {
164162306a36Sopenharmony_ci		kfree(rss_new);
164262306a36Sopenharmony_ci		return -EINVAL;
164362306a36Sopenharmony_ci	}
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci	while (!mutex_trylock(&adapter->crit_lock)) {
164662306a36Sopenharmony_ci		if (--count == 0) {
164762306a36Sopenharmony_ci			kfree(rss_new);
164862306a36Sopenharmony_ci			return -EINVAL;
164962306a36Sopenharmony_ci		}
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci		udelay(1);
165262306a36Sopenharmony_ci	}
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	spin_lock_bh(&adapter->adv_rss_lock);
165562306a36Sopenharmony_ci	rss_old = iavf_find_adv_rss_cfg_by_hdrs(adapter, hdrs);
165662306a36Sopenharmony_ci	if (rss_old) {
165762306a36Sopenharmony_ci		if (rss_old->state != IAVF_ADV_RSS_ACTIVE) {
165862306a36Sopenharmony_ci			err = -EBUSY;
165962306a36Sopenharmony_ci		} else if (rss_old->hash_flds != hash_flds) {
166062306a36Sopenharmony_ci			rss_old->state = IAVF_ADV_RSS_ADD_REQUEST;
166162306a36Sopenharmony_ci			rss_old->hash_flds = hash_flds;
166262306a36Sopenharmony_ci			memcpy(&rss_old->cfg_msg, &rss_new->cfg_msg,
166362306a36Sopenharmony_ci			       sizeof(rss_new->cfg_msg));
166462306a36Sopenharmony_ci			adapter->aq_required |= IAVF_FLAG_AQ_ADD_ADV_RSS_CFG;
166562306a36Sopenharmony_ci		} else {
166662306a36Sopenharmony_ci			err = -EEXIST;
166762306a36Sopenharmony_ci		}
166862306a36Sopenharmony_ci	} else {
166962306a36Sopenharmony_ci		rss_new_add = true;
167062306a36Sopenharmony_ci		rss_new->state = IAVF_ADV_RSS_ADD_REQUEST;
167162306a36Sopenharmony_ci		rss_new->packet_hdrs = hdrs;
167262306a36Sopenharmony_ci		rss_new->hash_flds = hash_flds;
167362306a36Sopenharmony_ci		list_add_tail(&rss_new->list, &adapter->adv_rss_list_head);
167462306a36Sopenharmony_ci		adapter->aq_required |= IAVF_FLAG_AQ_ADD_ADV_RSS_CFG;
167562306a36Sopenharmony_ci	}
167662306a36Sopenharmony_ci	spin_unlock_bh(&adapter->adv_rss_lock);
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	if (!err)
167962306a36Sopenharmony_ci		mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	mutex_unlock(&adapter->crit_lock);
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	if (!rss_new_add)
168462306a36Sopenharmony_ci		kfree(rss_new);
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	return err;
168762306a36Sopenharmony_ci}
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci/**
169062306a36Sopenharmony_ci * iavf_get_adv_rss_hash_opt - Retrieve hash fields for a given flow-type
169162306a36Sopenharmony_ci * @adapter: pointer to the VF adapter structure
169262306a36Sopenharmony_ci * @cmd: ethtool rxnfc command
169362306a36Sopenharmony_ci *
169462306a36Sopenharmony_ci * Returns Success if the flow input set is supported.
169562306a36Sopenharmony_ci */
169662306a36Sopenharmony_cistatic int
169762306a36Sopenharmony_ciiavf_get_adv_rss_hash_opt(struct iavf_adapter *adapter,
169862306a36Sopenharmony_ci			  struct ethtool_rxnfc *cmd)
169962306a36Sopenharmony_ci{
170062306a36Sopenharmony_ci	struct iavf_adv_rss *rss;
170162306a36Sopenharmony_ci	u64 hash_flds;
170262306a36Sopenharmony_ci	u32 hdrs;
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	if (!ADV_RSS_SUPPORT(adapter))
170562306a36Sopenharmony_ci		return -EOPNOTSUPP;
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_ci	cmd->data = 0;
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci	hdrs = iavf_adv_rss_parse_hdrs(cmd);
171062306a36Sopenharmony_ci	if (hdrs == IAVF_ADV_RSS_FLOW_SEG_HDR_NONE)
171162306a36Sopenharmony_ci		return -EINVAL;
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	spin_lock_bh(&adapter->adv_rss_lock);
171462306a36Sopenharmony_ci	rss = iavf_find_adv_rss_cfg_by_hdrs(adapter, hdrs);
171562306a36Sopenharmony_ci	if (rss)
171662306a36Sopenharmony_ci		hash_flds = rss->hash_flds;
171762306a36Sopenharmony_ci	else
171862306a36Sopenharmony_ci		hash_flds = IAVF_ADV_RSS_HASH_INVALID;
171962306a36Sopenharmony_ci	spin_unlock_bh(&adapter->adv_rss_lock);
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci	if (hash_flds == IAVF_ADV_RSS_HASH_INVALID)
172262306a36Sopenharmony_ci		return -EINVAL;
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_IPV4_SA |
172562306a36Sopenharmony_ci			 IAVF_ADV_RSS_HASH_FLD_IPV6_SA))
172662306a36Sopenharmony_ci		cmd->data |= (u64)RXH_IP_SRC;
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci	if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_IPV4_DA |
172962306a36Sopenharmony_ci			 IAVF_ADV_RSS_HASH_FLD_IPV6_DA))
173062306a36Sopenharmony_ci		cmd->data |= (u64)RXH_IP_DST;
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_TCP_SRC_PORT |
173362306a36Sopenharmony_ci			 IAVF_ADV_RSS_HASH_FLD_UDP_SRC_PORT |
173462306a36Sopenharmony_ci			 IAVF_ADV_RSS_HASH_FLD_SCTP_SRC_PORT))
173562306a36Sopenharmony_ci		cmd->data |= (u64)RXH_L4_B_0_1;
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci	if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_TCP_DST_PORT |
173862306a36Sopenharmony_ci			 IAVF_ADV_RSS_HASH_FLD_UDP_DST_PORT |
173962306a36Sopenharmony_ci			 IAVF_ADV_RSS_HASH_FLD_SCTP_DST_PORT))
174062306a36Sopenharmony_ci		cmd->data |= (u64)RXH_L4_B_2_3;
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci	return 0;
174362306a36Sopenharmony_ci}
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci/**
174662306a36Sopenharmony_ci * iavf_set_rxnfc - command to set Rx flow rules.
174762306a36Sopenharmony_ci * @netdev: network interface device structure
174862306a36Sopenharmony_ci * @cmd: ethtool rxnfc command
174962306a36Sopenharmony_ci *
175062306a36Sopenharmony_ci * Returns 0 for success and negative values for errors
175162306a36Sopenharmony_ci */
175262306a36Sopenharmony_cistatic int iavf_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
175362306a36Sopenharmony_ci{
175462306a36Sopenharmony_ci	struct iavf_adapter *adapter = netdev_priv(netdev);
175562306a36Sopenharmony_ci	int ret = -EOPNOTSUPP;
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	switch (cmd->cmd) {
175862306a36Sopenharmony_ci	case ETHTOOL_SRXCLSRLINS:
175962306a36Sopenharmony_ci		ret = iavf_add_fdir_ethtool(adapter, cmd);
176062306a36Sopenharmony_ci		break;
176162306a36Sopenharmony_ci	case ETHTOOL_SRXCLSRLDEL:
176262306a36Sopenharmony_ci		ret = iavf_del_fdir_ethtool(adapter, cmd);
176362306a36Sopenharmony_ci		break;
176462306a36Sopenharmony_ci	case ETHTOOL_SRXFH:
176562306a36Sopenharmony_ci		ret = iavf_set_adv_rss_hash_opt(adapter, cmd);
176662306a36Sopenharmony_ci		break;
176762306a36Sopenharmony_ci	default:
176862306a36Sopenharmony_ci		break;
176962306a36Sopenharmony_ci	}
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	return ret;
177262306a36Sopenharmony_ci}
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci/**
177562306a36Sopenharmony_ci * iavf_get_rxnfc - command to get RX flow classification rules
177662306a36Sopenharmony_ci * @netdev: network interface device structure
177762306a36Sopenharmony_ci * @cmd: ethtool rxnfc command
177862306a36Sopenharmony_ci * @rule_locs: pointer to store rule locations
177962306a36Sopenharmony_ci *
178062306a36Sopenharmony_ci * Returns Success if the command is supported.
178162306a36Sopenharmony_ci **/
178262306a36Sopenharmony_cistatic int iavf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
178362306a36Sopenharmony_ci			  u32 *rule_locs)
178462306a36Sopenharmony_ci{
178562306a36Sopenharmony_ci	struct iavf_adapter *adapter = netdev_priv(netdev);
178662306a36Sopenharmony_ci	int ret = -EOPNOTSUPP;
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	switch (cmd->cmd) {
178962306a36Sopenharmony_ci	case ETHTOOL_GRXRINGS:
179062306a36Sopenharmony_ci		cmd->data = adapter->num_active_queues;
179162306a36Sopenharmony_ci		ret = 0;
179262306a36Sopenharmony_ci		break;
179362306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRLCNT:
179462306a36Sopenharmony_ci		if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))
179562306a36Sopenharmony_ci			break;
179662306a36Sopenharmony_ci		spin_lock_bh(&adapter->fdir_fltr_lock);
179762306a36Sopenharmony_ci		cmd->rule_cnt = adapter->fdir_active_fltr;
179862306a36Sopenharmony_ci		spin_unlock_bh(&adapter->fdir_fltr_lock);
179962306a36Sopenharmony_ci		cmd->data = IAVF_MAX_FDIR_FILTERS;
180062306a36Sopenharmony_ci		ret = 0;
180162306a36Sopenharmony_ci		break;
180262306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRULE:
180362306a36Sopenharmony_ci		ret = iavf_get_ethtool_fdir_entry(adapter, cmd);
180462306a36Sopenharmony_ci		break;
180562306a36Sopenharmony_ci	case ETHTOOL_GRXCLSRLALL:
180662306a36Sopenharmony_ci		ret = iavf_get_fdir_fltr_ids(adapter, cmd, (u32 *)rule_locs);
180762306a36Sopenharmony_ci		break;
180862306a36Sopenharmony_ci	case ETHTOOL_GRXFH:
180962306a36Sopenharmony_ci		ret = iavf_get_adv_rss_hash_opt(adapter, cmd);
181062306a36Sopenharmony_ci		break;
181162306a36Sopenharmony_ci	default:
181262306a36Sopenharmony_ci		break;
181362306a36Sopenharmony_ci	}
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci	return ret;
181662306a36Sopenharmony_ci}
181762306a36Sopenharmony_ci/**
181862306a36Sopenharmony_ci * iavf_get_channels: get the number of channels supported by the device
181962306a36Sopenharmony_ci * @netdev: network interface device structure
182062306a36Sopenharmony_ci * @ch: channel information structure
182162306a36Sopenharmony_ci *
182262306a36Sopenharmony_ci * For the purposes of our device, we only use combined channels, i.e. a tx/rx
182362306a36Sopenharmony_ci * queue pair. Report one extra channel to match our "other" MSI-X vector.
182462306a36Sopenharmony_ci **/
182562306a36Sopenharmony_cistatic void iavf_get_channels(struct net_device *netdev,
182662306a36Sopenharmony_ci			      struct ethtool_channels *ch)
182762306a36Sopenharmony_ci{
182862306a36Sopenharmony_ci	struct iavf_adapter *adapter = netdev_priv(netdev);
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	/* Report maximum channels */
183162306a36Sopenharmony_ci	ch->max_combined = adapter->vsi_res->num_queue_pairs;
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci	ch->max_other = NONQ_VECS;
183462306a36Sopenharmony_ci	ch->other_count = NONQ_VECS;
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	ch->combined_count = adapter->num_active_queues;
183762306a36Sopenharmony_ci}
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci/**
184062306a36Sopenharmony_ci * iavf_set_channels: set the new channel count
184162306a36Sopenharmony_ci * @netdev: network interface device structure
184262306a36Sopenharmony_ci * @ch: channel information structure
184362306a36Sopenharmony_ci *
184462306a36Sopenharmony_ci * Negotiate a new number of channels with the PF then do a reset.  During
184562306a36Sopenharmony_ci * reset we'll realloc queues and fix the RSS table.  Returns 0 on success,
184662306a36Sopenharmony_ci * negative on failure.
184762306a36Sopenharmony_ci **/
184862306a36Sopenharmony_cistatic int iavf_set_channels(struct net_device *netdev,
184962306a36Sopenharmony_ci			     struct ethtool_channels *ch)
185062306a36Sopenharmony_ci{
185162306a36Sopenharmony_ci	struct iavf_adapter *adapter = netdev_priv(netdev);
185262306a36Sopenharmony_ci	u32 num_req = ch->combined_count;
185362306a36Sopenharmony_ci	int ret = 0;
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	if ((adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ) &&
185662306a36Sopenharmony_ci	    adapter->num_tc) {
185762306a36Sopenharmony_ci		dev_info(&adapter->pdev->dev, "Cannot set channels since ADq is enabled.\n");
185862306a36Sopenharmony_ci		return -EINVAL;
185962306a36Sopenharmony_ci	}
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	/* All of these should have already been checked by ethtool before this
186262306a36Sopenharmony_ci	 * even gets to us, but just to be sure.
186362306a36Sopenharmony_ci	 */
186462306a36Sopenharmony_ci	if (num_req == 0 || num_req > adapter->vsi_res->num_queue_pairs)
186562306a36Sopenharmony_ci		return -EINVAL;
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	if (num_req == adapter->num_active_queues)
186862306a36Sopenharmony_ci		return 0;
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	if (ch->rx_count || ch->tx_count || ch->other_count != NONQ_VECS)
187162306a36Sopenharmony_ci		return -EINVAL;
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	adapter->num_req_queues = num_req;
187462306a36Sopenharmony_ci	adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED;
187562306a36Sopenharmony_ci	iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci	ret = iavf_wait_for_reset(adapter);
187862306a36Sopenharmony_ci	if (ret)
187962306a36Sopenharmony_ci		netdev_warn(netdev, "Changing channel count timeout or interrupted waiting for reset");
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	return ret;
188262306a36Sopenharmony_ci}
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci/**
188562306a36Sopenharmony_ci * iavf_get_rxfh_key_size - get the RSS hash key size
188662306a36Sopenharmony_ci * @netdev: network interface device structure
188762306a36Sopenharmony_ci *
188862306a36Sopenharmony_ci * Returns the table size.
188962306a36Sopenharmony_ci **/
189062306a36Sopenharmony_cistatic u32 iavf_get_rxfh_key_size(struct net_device *netdev)
189162306a36Sopenharmony_ci{
189262306a36Sopenharmony_ci	struct iavf_adapter *adapter = netdev_priv(netdev);
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	return adapter->rss_key_size;
189562306a36Sopenharmony_ci}
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ci/**
189862306a36Sopenharmony_ci * iavf_get_rxfh_indir_size - get the rx flow hash indirection table size
189962306a36Sopenharmony_ci * @netdev: network interface device structure
190062306a36Sopenharmony_ci *
190162306a36Sopenharmony_ci * Returns the table size.
190262306a36Sopenharmony_ci **/
190362306a36Sopenharmony_cistatic u32 iavf_get_rxfh_indir_size(struct net_device *netdev)
190462306a36Sopenharmony_ci{
190562306a36Sopenharmony_ci	struct iavf_adapter *adapter = netdev_priv(netdev);
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci	return adapter->rss_lut_size;
190862306a36Sopenharmony_ci}
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci/**
191162306a36Sopenharmony_ci * iavf_get_rxfh - get the rx flow hash indirection table
191262306a36Sopenharmony_ci * @netdev: network interface device structure
191362306a36Sopenharmony_ci * @indir: indirection table
191462306a36Sopenharmony_ci * @key: hash key
191562306a36Sopenharmony_ci * @hfunc: hash function in use
191662306a36Sopenharmony_ci *
191762306a36Sopenharmony_ci * Reads the indirection table directly from the hardware. Always returns 0.
191862306a36Sopenharmony_ci **/
191962306a36Sopenharmony_cistatic int iavf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
192062306a36Sopenharmony_ci			 u8 *hfunc)
192162306a36Sopenharmony_ci{
192262306a36Sopenharmony_ci	struct iavf_adapter *adapter = netdev_priv(netdev);
192362306a36Sopenharmony_ci	u16 i;
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_ci	if (hfunc)
192662306a36Sopenharmony_ci		*hfunc = ETH_RSS_HASH_TOP;
192762306a36Sopenharmony_ci	if (key)
192862306a36Sopenharmony_ci		memcpy(key, adapter->rss_key, adapter->rss_key_size);
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	if (indir)
193162306a36Sopenharmony_ci		/* Each 32 bits pointed by 'indir' is stored with a lut entry */
193262306a36Sopenharmony_ci		for (i = 0; i < adapter->rss_lut_size; i++)
193362306a36Sopenharmony_ci			indir[i] = (u32)adapter->rss_lut[i];
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	return 0;
193662306a36Sopenharmony_ci}
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci/**
193962306a36Sopenharmony_ci * iavf_set_rxfh - set the rx flow hash indirection table
194062306a36Sopenharmony_ci * @netdev: network interface device structure
194162306a36Sopenharmony_ci * @indir: indirection table
194262306a36Sopenharmony_ci * @key: hash key
194362306a36Sopenharmony_ci * @hfunc: hash function to use
194462306a36Sopenharmony_ci *
194562306a36Sopenharmony_ci * Returns -EINVAL if the table specifies an invalid queue id, otherwise
194662306a36Sopenharmony_ci * returns 0 after programming the table.
194762306a36Sopenharmony_ci **/
194862306a36Sopenharmony_cistatic int iavf_set_rxfh(struct net_device *netdev, const u32 *indir,
194962306a36Sopenharmony_ci			 const u8 *key, const u8 hfunc)
195062306a36Sopenharmony_ci{
195162306a36Sopenharmony_ci	struct iavf_adapter *adapter = netdev_priv(netdev);
195262306a36Sopenharmony_ci	u16 i;
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci	/* Only support toeplitz hash function */
195562306a36Sopenharmony_ci	if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
195662306a36Sopenharmony_ci		return -EOPNOTSUPP;
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	if (!key && !indir)
195962306a36Sopenharmony_ci		return 0;
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci	if (key)
196262306a36Sopenharmony_ci		memcpy(adapter->rss_key, key, adapter->rss_key_size);
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci	if (indir) {
196562306a36Sopenharmony_ci		/* Each 32 bits pointed by 'indir' is stored with a lut entry */
196662306a36Sopenharmony_ci		for (i = 0; i < adapter->rss_lut_size; i++)
196762306a36Sopenharmony_ci			adapter->rss_lut[i] = (u8)(indir[i]);
196862306a36Sopenharmony_ci	}
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	return iavf_config_rss(adapter);
197162306a36Sopenharmony_ci}
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_cistatic const struct ethtool_ops iavf_ethtool_ops = {
197462306a36Sopenharmony_ci	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
197562306a36Sopenharmony_ci				     ETHTOOL_COALESCE_USE_ADAPTIVE,
197662306a36Sopenharmony_ci	.get_drvinfo		= iavf_get_drvinfo,
197762306a36Sopenharmony_ci	.get_link		= ethtool_op_get_link,
197862306a36Sopenharmony_ci	.get_ringparam		= iavf_get_ringparam,
197962306a36Sopenharmony_ci	.set_ringparam		= iavf_set_ringparam,
198062306a36Sopenharmony_ci	.get_strings		= iavf_get_strings,
198162306a36Sopenharmony_ci	.get_ethtool_stats	= iavf_get_ethtool_stats,
198262306a36Sopenharmony_ci	.get_sset_count		= iavf_get_sset_count,
198362306a36Sopenharmony_ci	.get_priv_flags		= iavf_get_priv_flags,
198462306a36Sopenharmony_ci	.set_priv_flags		= iavf_set_priv_flags,
198562306a36Sopenharmony_ci	.get_msglevel		= iavf_get_msglevel,
198662306a36Sopenharmony_ci	.set_msglevel		= iavf_set_msglevel,
198762306a36Sopenharmony_ci	.get_coalesce		= iavf_get_coalesce,
198862306a36Sopenharmony_ci	.set_coalesce		= iavf_set_coalesce,
198962306a36Sopenharmony_ci	.get_per_queue_coalesce = iavf_get_per_queue_coalesce,
199062306a36Sopenharmony_ci	.set_per_queue_coalesce = iavf_set_per_queue_coalesce,
199162306a36Sopenharmony_ci	.set_rxnfc		= iavf_set_rxnfc,
199262306a36Sopenharmony_ci	.get_rxnfc		= iavf_get_rxnfc,
199362306a36Sopenharmony_ci	.get_rxfh_indir_size	= iavf_get_rxfh_indir_size,
199462306a36Sopenharmony_ci	.get_rxfh		= iavf_get_rxfh,
199562306a36Sopenharmony_ci	.set_rxfh		= iavf_set_rxfh,
199662306a36Sopenharmony_ci	.get_channels		= iavf_get_channels,
199762306a36Sopenharmony_ci	.set_channels		= iavf_set_channels,
199862306a36Sopenharmony_ci	.get_rxfh_key_size	= iavf_get_rxfh_key_size,
199962306a36Sopenharmony_ci	.get_link_ksettings	= iavf_get_link_ksettings,
200062306a36Sopenharmony_ci};
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci/**
200362306a36Sopenharmony_ci * iavf_set_ethtool_ops - Initialize ethtool ops struct
200462306a36Sopenharmony_ci * @netdev: network interface device structure
200562306a36Sopenharmony_ci *
200662306a36Sopenharmony_ci * Sets ethtool ops struct in our netdev so that ethtool can call
200762306a36Sopenharmony_ci * our functions.
200862306a36Sopenharmony_ci **/
200962306a36Sopenharmony_civoid iavf_set_ethtool_ops(struct net_device *netdev)
201062306a36Sopenharmony_ci{
201162306a36Sopenharmony_ci	netdev->ethtool_ops = &iavf_ethtool_ops;
201262306a36Sopenharmony_ci}
2013