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