1847 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright(c) 2013 - 2018 Intel Corporation. */3 4#include <linux/bitfield.h>5#include <linux/uaccess.h>6 7/* ethtool support for iavf */8#include "iavf.h"9 10/* ethtool statistics helpers */11 12/**13 * struct iavf_stats - definition for an ethtool statistic14 * @stat_string: statistic name to display in ethtool -S output15 * @sizeof_stat: the sizeof() the stat, must be no greater than sizeof(u64)16 * @stat_offset: offsetof() the stat from a base pointer17 *18 * This structure defines a statistic to be added to the ethtool stats buffer.19 * It defines a statistic as offset from a common base pointer. Stats should20 * be defined in constant arrays using the IAVF_STAT macro, with every element21 * of the array using the same _type for calculating the sizeof_stat and22 * stat_offset.23 *24 * The @sizeof_stat is expected to be sizeof(u8), sizeof(u16), sizeof(u32) or25 * sizeof(u64). Other sizes are not expected and will produce a WARN_ONCE from26 * the iavf_add_ethtool_stat() helper function.27 *28 * The @stat_string is interpreted as a format string, allowing formatted29 * values to be inserted while looping over multiple structures for a given30 * statistics array. Thus, every statistic string in an array should have the31 * same type and number of format specifiers, to be formatted by variadic32 * arguments to the iavf_add_stat_string() helper function.33 **/34struct iavf_stats {35 char stat_string[ETH_GSTRING_LEN];36 int sizeof_stat;37 int stat_offset;38};39 40/* Helper macro to define an iavf_stat structure with proper size and type.41 * Use this when defining constant statistics arrays. Note that @_type expects42 * only a type name and is used multiple times.43 */44#define IAVF_STAT(_type, _name, _stat) { \45 .stat_string = _name, \46 .sizeof_stat = sizeof_field(_type, _stat), \47 .stat_offset = offsetof(_type, _stat) \48}49 50/* Helper macro for defining some statistics related to queues */51#define IAVF_QUEUE_STAT(_name, _stat) \52 IAVF_STAT(struct iavf_ring, _name, _stat)53 54/* Stats associated with a Tx or Rx ring */55static const struct iavf_stats iavf_gstrings_queue_stats[] = {56 IAVF_QUEUE_STAT("%s-%u.packets", stats.packets),57 IAVF_QUEUE_STAT("%s-%u.bytes", stats.bytes),58};59 60/**61 * iavf_add_one_ethtool_stat - copy the stat into the supplied buffer62 * @data: location to store the stat value63 * @pointer: basis for where to copy from64 * @stat: the stat definition65 *66 * Copies the stat data defined by the pointer and stat structure pair into67 * the memory supplied as data. Used to implement iavf_add_ethtool_stats and68 * iavf_add_queue_stats. If the pointer is null, data will be zero'd.69 */70static void71iavf_add_one_ethtool_stat(u64 *data, void *pointer,72 const struct iavf_stats *stat)73{74 char *p;75 76 if (!pointer) {77 /* ensure that the ethtool data buffer is zero'd for any stats78 * which don't have a valid pointer.79 */80 *data = 0;81 return;82 }83 84 p = (char *)pointer + stat->stat_offset;85 switch (stat->sizeof_stat) {86 case sizeof(u64):87 *data = *((u64 *)p);88 break;89 case sizeof(u32):90 *data = *((u32 *)p);91 break;92 case sizeof(u16):93 *data = *((u16 *)p);94 break;95 case sizeof(u8):96 *data = *((u8 *)p);97 break;98 default:99 WARN_ONCE(1, "unexpected stat size for %s",100 stat->stat_string);101 *data = 0;102 }103}104 105/**106 * __iavf_add_ethtool_stats - copy stats into the ethtool supplied buffer107 * @data: ethtool stats buffer108 * @pointer: location to copy stats from109 * @stats: array of stats to copy110 * @size: the size of the stats definition111 *112 * Copy the stats defined by the stats array using the pointer as a base into113 * the data buffer supplied by ethtool. Updates the data pointer to point to114 * the next empty location for successive calls to __iavf_add_ethtool_stats.115 * If pointer is null, set the data values to zero and update the pointer to116 * skip these stats.117 **/118static void119__iavf_add_ethtool_stats(u64 **data, void *pointer,120 const struct iavf_stats stats[],121 const unsigned int size)122{123 unsigned int i;124 125 for (i = 0; i < size; i++)126 iavf_add_one_ethtool_stat((*data)++, pointer, &stats[i]);127}128 129/**130 * iavf_add_ethtool_stats - copy stats into ethtool supplied buffer131 * @data: ethtool stats buffer132 * @pointer: location where stats are stored133 * @stats: static const array of stat definitions134 *135 * Macro to ease the use of __iavf_add_ethtool_stats by taking a static136 * constant stats array and passing the ARRAY_SIZE(). This avoids typos by137 * ensuring that we pass the size associated with the given stats array.138 *139 * The parameter @stats is evaluated twice, so parameters with side effects140 * should be avoided.141 **/142#define iavf_add_ethtool_stats(data, pointer, stats) \143 __iavf_add_ethtool_stats(data, pointer, stats, ARRAY_SIZE(stats))144 145/**146 * iavf_add_queue_stats - copy queue statistics into supplied buffer147 * @data: ethtool stats buffer148 * @ring: the ring to copy149 *150 * Queue statistics must be copied while protected by151 * u64_stats_fetch_begin, so we can't directly use iavf_add_ethtool_stats.152 * Assumes that queue stats are defined in iavf_gstrings_queue_stats. If the153 * ring pointer is null, zero out the queue stat values and update the data154 * pointer. Otherwise safely copy the stats from the ring into the supplied155 * buffer and update the data pointer when finished.156 *157 * This function expects to be called while under rcu_read_lock().158 **/159static void160iavf_add_queue_stats(u64 **data, struct iavf_ring *ring)161{162 const unsigned int size = ARRAY_SIZE(iavf_gstrings_queue_stats);163 const struct iavf_stats *stats = iavf_gstrings_queue_stats;164 unsigned int start;165 unsigned int i;166 167 /* To avoid invalid statistics values, ensure that we keep retrying168 * the copy until we get a consistent value according to169 * u64_stats_fetch_retry. But first, make sure our ring is170 * non-null before attempting to access its syncp.171 */172 do {173 start = !ring ? 0 : u64_stats_fetch_begin(&ring->syncp);174 for (i = 0; i < size; i++)175 iavf_add_one_ethtool_stat(&(*data)[i], ring, &stats[i]);176 } while (ring && u64_stats_fetch_retry(&ring->syncp, start));177 178 /* Once we successfully copy the stats in, update the data pointer */179 *data += size;180}181 182/**183 * __iavf_add_stat_strings - copy stat strings into ethtool buffer184 * @p: ethtool supplied buffer185 * @stats: stat definitions array186 * @size: size of the stats array187 *188 * Format and copy the strings described by stats into the buffer pointed at189 * by p.190 **/191static void __iavf_add_stat_strings(u8 **p, const struct iavf_stats stats[],192 const unsigned int size, ...)193{194 unsigned int i;195 196 for (i = 0; i < size; i++) {197 va_list args;198 199 va_start(args, size);200 vsnprintf(*p, ETH_GSTRING_LEN, stats[i].stat_string, args);201 *p += ETH_GSTRING_LEN;202 va_end(args);203 }204}205 206/**207 * iavf_add_stat_strings - copy stat strings into ethtool buffer208 * @p: ethtool supplied buffer209 * @stats: stat definitions array210 *211 * Format and copy the strings described by the const static stats value into212 * the buffer pointed at by p.213 *214 * The parameter @stats is evaluated twice, so parameters with side effects215 * should be avoided. Additionally, stats must be an array such that216 * ARRAY_SIZE can be called on it.217 **/218#define iavf_add_stat_strings(p, stats, ...) \219 __iavf_add_stat_strings(p, stats, ARRAY_SIZE(stats), ## __VA_ARGS__)220 221#define VF_STAT(_name, _stat) \222 IAVF_STAT(struct iavf_adapter, _name, _stat)223 224static const struct iavf_stats iavf_gstrings_stats[] = {225 VF_STAT("rx_bytes", current_stats.rx_bytes),226 VF_STAT("rx_unicast", current_stats.rx_unicast),227 VF_STAT("rx_multicast", current_stats.rx_multicast),228 VF_STAT("rx_broadcast", current_stats.rx_broadcast),229 VF_STAT("rx_discards", current_stats.rx_discards),230 VF_STAT("rx_unknown_protocol", current_stats.rx_unknown_protocol),231 VF_STAT("tx_bytes", current_stats.tx_bytes),232 VF_STAT("tx_unicast", current_stats.tx_unicast),233 VF_STAT("tx_multicast", current_stats.tx_multicast),234 VF_STAT("tx_broadcast", current_stats.tx_broadcast),235 VF_STAT("tx_discards", current_stats.tx_discards),236 VF_STAT("tx_errors", current_stats.tx_errors),237};238 239#define IAVF_STATS_LEN ARRAY_SIZE(iavf_gstrings_stats)240 241#define IAVF_QUEUE_STATS_LEN ARRAY_SIZE(iavf_gstrings_queue_stats)242 243/**244 * iavf_get_link_ksettings - Get Link Speed and Duplex settings245 * @netdev: network interface device structure246 * @cmd: ethtool command247 *248 * Reports speed/duplex settings. Because this is a VF, we don't know what249 * kind of link we really have, so we fake it.250 **/251static int iavf_get_link_ksettings(struct net_device *netdev,252 struct ethtool_link_ksettings *cmd)253{254 struct iavf_adapter *adapter = netdev_priv(netdev);255 256 ethtool_link_ksettings_zero_link_mode(cmd, supported);257 cmd->base.autoneg = AUTONEG_DISABLE;258 cmd->base.port = PORT_NONE;259 cmd->base.duplex = DUPLEX_FULL;260 261 if (ADV_LINK_SUPPORT(adapter)) {262 if (adapter->link_speed_mbps &&263 adapter->link_speed_mbps < U32_MAX)264 cmd->base.speed = adapter->link_speed_mbps;265 else266 cmd->base.speed = SPEED_UNKNOWN;267 268 return 0;269 }270 271 switch (adapter->link_speed) {272 case VIRTCHNL_LINK_SPEED_40GB:273 cmd->base.speed = SPEED_40000;274 break;275 case VIRTCHNL_LINK_SPEED_25GB:276 cmd->base.speed = SPEED_25000;277 break;278 case VIRTCHNL_LINK_SPEED_20GB:279 cmd->base.speed = SPEED_20000;280 break;281 case VIRTCHNL_LINK_SPEED_10GB:282 cmd->base.speed = SPEED_10000;283 break;284 case VIRTCHNL_LINK_SPEED_5GB:285 cmd->base.speed = SPEED_5000;286 break;287 case VIRTCHNL_LINK_SPEED_2_5GB:288 cmd->base.speed = SPEED_2500;289 break;290 case VIRTCHNL_LINK_SPEED_1GB:291 cmd->base.speed = SPEED_1000;292 break;293 case VIRTCHNL_LINK_SPEED_100MB:294 cmd->base.speed = SPEED_100;295 break;296 default:297 break;298 }299 300 return 0;301}302 303/**304 * iavf_get_sset_count - Get length of string set305 * @netdev: network interface device structure306 * @sset: id of string set307 *308 * Reports size of various string tables.309 **/310static int iavf_get_sset_count(struct net_device *netdev, int sset)311{312 /* Report the maximum number queues, even if not every queue is313 * currently configured. Since allocation of queues is in pairs,314 * use netdev->real_num_tx_queues * 2. The real_num_tx_queues is set315 * at device creation and never changes.316 */317 318 if (sset == ETH_SS_STATS)319 return IAVF_STATS_LEN +320 (IAVF_QUEUE_STATS_LEN * 2 *321 netdev->real_num_tx_queues);322 else323 return -EINVAL;324}325 326/**327 * iavf_get_ethtool_stats - report device statistics328 * @netdev: network interface device structure329 * @stats: ethtool statistics structure330 * @data: pointer to data buffer331 *332 * All statistics are added to the data buffer as an array of u64.333 **/334static void iavf_get_ethtool_stats(struct net_device *netdev,335 struct ethtool_stats *stats, u64 *data)336{337 struct iavf_adapter *adapter = netdev_priv(netdev);338 unsigned int i;339 340 /* Explicitly request stats refresh */341 iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_REQUEST_STATS);342 343 iavf_add_ethtool_stats(&data, adapter, iavf_gstrings_stats);344 345 rcu_read_lock();346 /* As num_active_queues describe both tx and rx queues, we can use347 * it to iterate over rings' stats.348 */349 for (i = 0; i < adapter->num_active_queues; i++) {350 struct iavf_ring *ring;351 352 /* Tx rings stats */353 ring = &adapter->tx_rings[i];354 iavf_add_queue_stats(&data, ring);355 356 /* Rx rings stats */357 ring = &adapter->rx_rings[i];358 iavf_add_queue_stats(&data, ring);359 }360 rcu_read_unlock();361}362 363/**364 * iavf_get_stat_strings - Get stat strings365 * @netdev: network interface device structure366 * @data: buffer for string data367 *368 * Builds the statistics string table369 **/370static void iavf_get_stat_strings(struct net_device *netdev, u8 *data)371{372 unsigned int i;373 374 iavf_add_stat_strings(&data, iavf_gstrings_stats);375 376 /* Queues are always allocated in pairs, so we just use377 * real_num_tx_queues for both Tx and Rx queues.378 */379 for (i = 0; i < netdev->real_num_tx_queues; i++) {380 iavf_add_stat_strings(&data, iavf_gstrings_queue_stats,381 "tx", i);382 iavf_add_stat_strings(&data, iavf_gstrings_queue_stats,383 "rx", i);384 }385}386 387/**388 * iavf_get_strings - Get string set389 * @netdev: network interface device structure390 * @sset: id of string set391 * @data: buffer for string data392 *393 * Builds string tables for various string sets394 **/395static void iavf_get_strings(struct net_device *netdev, u32 sset, u8 *data)396{397 switch (sset) {398 case ETH_SS_STATS:399 iavf_get_stat_strings(netdev, data);400 break;401 default:402 break;403 }404}405 406/**407 * iavf_get_msglevel - Get debug message level408 * @netdev: network interface device structure409 *410 * Returns current debug message level.411 **/412static u32 iavf_get_msglevel(struct net_device *netdev)413{414 struct iavf_adapter *adapter = netdev_priv(netdev);415 416 return adapter->msg_enable;417}418 419/**420 * iavf_set_msglevel - Set debug message level421 * @netdev: network interface device structure422 * @data: message level423 *424 * Set current debug message level. Higher values cause the driver to425 * be noisier.426 **/427static void iavf_set_msglevel(struct net_device *netdev, u32 data)428{429 struct iavf_adapter *adapter = netdev_priv(netdev);430 431 if (IAVF_DEBUG_USER & data)432 adapter->hw.debug_mask = data;433 adapter->msg_enable = data;434}435 436/**437 * iavf_get_drvinfo - Get driver info438 * @netdev: network interface device structure439 * @drvinfo: ethool driver info structure440 *441 * Returns information about the driver and device for display to the user.442 **/443static void iavf_get_drvinfo(struct net_device *netdev,444 struct ethtool_drvinfo *drvinfo)445{446 struct iavf_adapter *adapter = netdev_priv(netdev);447 448 strscpy(drvinfo->driver, iavf_driver_name, 32);449 strscpy(drvinfo->fw_version, "N/A", 4);450 strscpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);451}452 453/**454 * iavf_get_ringparam - Get ring parameters455 * @netdev: network interface device structure456 * @ring: ethtool ringparam structure457 * @kernel_ring: ethtool extenal ringparam structure458 * @extack: netlink extended ACK report struct459 *460 * Returns current ring parameters. TX and RX rings are reported separately,461 * but the number of rings is not reported.462 **/463static void iavf_get_ringparam(struct net_device *netdev,464 struct ethtool_ringparam *ring,465 struct kernel_ethtool_ringparam *kernel_ring,466 struct netlink_ext_ack *extack)467{468 struct iavf_adapter *adapter = netdev_priv(netdev);469 470 ring->rx_max_pending = IAVF_MAX_RXD;471 ring->tx_max_pending = IAVF_MAX_TXD;472 ring->rx_pending = adapter->rx_desc_count;473 ring->tx_pending = adapter->tx_desc_count;474}475 476/**477 * iavf_set_ringparam - Set ring parameters478 * @netdev: network interface device structure479 * @ring: ethtool ringparam structure480 * @kernel_ring: ethtool external ringparam structure481 * @extack: netlink extended ACK report struct482 *483 * Sets ring parameters. TX and RX rings are controlled separately, but the484 * number of rings is not specified, so all rings get the same settings.485 **/486static int iavf_set_ringparam(struct net_device *netdev,487 struct ethtool_ringparam *ring,488 struct kernel_ethtool_ringparam *kernel_ring,489 struct netlink_ext_ack *extack)490{491 struct iavf_adapter *adapter = netdev_priv(netdev);492 u32 new_rx_count, new_tx_count;493 int ret = 0;494 495 if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))496 return -EINVAL;497 498 if (ring->tx_pending > IAVF_MAX_TXD ||499 ring->tx_pending < IAVF_MIN_TXD ||500 ring->rx_pending > IAVF_MAX_RXD ||501 ring->rx_pending < IAVF_MIN_RXD) {502 netdev_err(netdev, "Descriptors requested (Tx: %d / Rx: %d) out of range [%d-%d] (increment %d)\n",503 ring->tx_pending, ring->rx_pending, IAVF_MIN_TXD,504 IAVF_MAX_RXD, IAVF_REQ_DESCRIPTOR_MULTIPLE);505 return -EINVAL;506 }507 508 new_tx_count = ALIGN(ring->tx_pending, IAVF_REQ_DESCRIPTOR_MULTIPLE);509 if (new_tx_count != ring->tx_pending)510 netdev_info(netdev, "Requested Tx descriptor count rounded up to %d\n",511 new_tx_count);512 513 new_rx_count = ALIGN(ring->rx_pending, IAVF_REQ_DESCRIPTOR_MULTIPLE);514 if (new_rx_count != ring->rx_pending)515 netdev_info(netdev, "Requested Rx descriptor count rounded up to %d\n",516 new_rx_count);517 518 /* if nothing to do return success */519 if ((new_tx_count == adapter->tx_desc_count) &&520 (new_rx_count == adapter->rx_desc_count)) {521 netdev_dbg(netdev, "Nothing to change, descriptor count is same as requested\n");522 return 0;523 }524 525 if (new_tx_count != adapter->tx_desc_count) {526 netdev_dbg(netdev, "Changing Tx descriptor count from %d to %d\n",527 adapter->tx_desc_count, new_tx_count);528 adapter->tx_desc_count = new_tx_count;529 }530 531 if (new_rx_count != adapter->rx_desc_count) {532 netdev_dbg(netdev, "Changing Rx descriptor count from %d to %d\n",533 adapter->rx_desc_count, new_rx_count);534 adapter->rx_desc_count = new_rx_count;535 }536 537 if (netif_running(netdev)) {538 iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);539 ret = iavf_wait_for_reset(adapter);540 if (ret)541 netdev_warn(netdev, "Changing ring parameters timeout or interrupted waiting for reset");542 }543 544 return ret;545}546 547/**548 * __iavf_get_coalesce - get per-queue coalesce settings549 * @netdev: the netdev to check550 * @ec: ethtool coalesce data structure551 * @queue: which queue to pick552 *553 * Gets the per-queue settings for coalescence. Specifically Rx and Tx usecs554 * are per queue. If queue is <0 then we default to queue 0 as the555 * representative value.556 **/557static int __iavf_get_coalesce(struct net_device *netdev,558 struct ethtool_coalesce *ec, int queue)559{560 struct iavf_adapter *adapter = netdev_priv(netdev);561 struct iavf_ring *rx_ring, *tx_ring;562 563 /* Rx and Tx usecs per queue value. If user doesn't specify the564 * queue, return queue 0's value to represent.565 */566 if (queue < 0)567 queue = 0;568 else if (queue >= adapter->num_active_queues)569 return -EINVAL;570 571 rx_ring = &adapter->rx_rings[queue];572 tx_ring = &adapter->tx_rings[queue];573 574 if (ITR_IS_DYNAMIC(rx_ring->itr_setting))575 ec->use_adaptive_rx_coalesce = 1;576 577 if (ITR_IS_DYNAMIC(tx_ring->itr_setting))578 ec->use_adaptive_tx_coalesce = 1;579 580 ec->rx_coalesce_usecs = rx_ring->itr_setting & ~IAVF_ITR_DYNAMIC;581 ec->tx_coalesce_usecs = tx_ring->itr_setting & ~IAVF_ITR_DYNAMIC;582 583 return 0;584}585 586/**587 * iavf_get_coalesce - Get interrupt coalescing settings588 * @netdev: network interface device structure589 * @ec: ethtool coalesce structure590 * @kernel_coal: ethtool CQE mode setting structure591 * @extack: extack for reporting error messages592 *593 * Returns current coalescing settings. This is referred to elsewhere in the594 * driver as Interrupt Throttle Rate, as this is how the hardware describes595 * this functionality. Note that if per-queue settings have been modified this596 * only represents the settings of queue 0.597 **/598static int iavf_get_coalesce(struct net_device *netdev,599 struct ethtool_coalesce *ec,600 struct kernel_ethtool_coalesce *kernel_coal,601 struct netlink_ext_ack *extack)602{603 return __iavf_get_coalesce(netdev, ec, -1);604}605 606/**607 * iavf_get_per_queue_coalesce - get coalesce values for specific queue608 * @netdev: netdev to read609 * @ec: coalesce settings from ethtool610 * @queue: the queue to read611 *612 * Read specific queue's coalesce settings.613 **/614static int iavf_get_per_queue_coalesce(struct net_device *netdev, u32 queue,615 struct ethtool_coalesce *ec)616{617 return __iavf_get_coalesce(netdev, ec, queue);618}619 620/**621 * iavf_set_itr_per_queue - set ITR values for specific queue622 * @adapter: the VF adapter struct to set values for623 * @ec: coalesce settings from ethtool624 * @queue: the queue to modify625 *626 * Change the ITR settings for a specific queue.627 **/628static int iavf_set_itr_per_queue(struct iavf_adapter *adapter,629 struct ethtool_coalesce *ec, int queue)630{631 struct iavf_ring *rx_ring = &adapter->rx_rings[queue];632 struct iavf_ring *tx_ring = &adapter->tx_rings[queue];633 struct iavf_q_vector *q_vector;634 u16 itr_setting;635 636 itr_setting = rx_ring->itr_setting & ~IAVF_ITR_DYNAMIC;637 638 if (ec->rx_coalesce_usecs != itr_setting &&639 ec->use_adaptive_rx_coalesce) {640 netif_info(adapter, drv, adapter->netdev,641 "Rx interrupt throttling cannot be changed if adaptive-rx is enabled\n");642 return -EINVAL;643 }644 645 itr_setting = tx_ring->itr_setting & ~IAVF_ITR_DYNAMIC;646 647 if (ec->tx_coalesce_usecs != itr_setting &&648 ec->use_adaptive_tx_coalesce) {649 netif_info(adapter, drv, adapter->netdev,650 "Tx interrupt throttling cannot be changed if adaptive-tx is enabled\n");651 return -EINVAL;652 }653 654 rx_ring->itr_setting = ITR_REG_ALIGN(ec->rx_coalesce_usecs);655 tx_ring->itr_setting = ITR_REG_ALIGN(ec->tx_coalesce_usecs);656 657 rx_ring->itr_setting |= IAVF_ITR_DYNAMIC;658 if (!ec->use_adaptive_rx_coalesce)659 rx_ring->itr_setting ^= IAVF_ITR_DYNAMIC;660 661 tx_ring->itr_setting |= IAVF_ITR_DYNAMIC;662 if (!ec->use_adaptive_tx_coalesce)663 tx_ring->itr_setting ^= IAVF_ITR_DYNAMIC;664 665 q_vector = rx_ring->q_vector;666 q_vector->rx.target_itr = ITR_TO_REG(rx_ring->itr_setting);667 668 q_vector = tx_ring->q_vector;669 q_vector->tx.target_itr = ITR_TO_REG(tx_ring->itr_setting);670 671 /* The interrupt handler itself will take care of programming672 * the Tx and Rx ITR values based on the values we have entered673 * into the q_vector, no need to write the values now.674 */675 return 0;676}677 678/**679 * __iavf_set_coalesce - set coalesce settings for particular queue680 * @netdev: the netdev to change681 * @ec: ethtool coalesce settings682 * @queue: the queue to change683 *684 * Sets the coalesce settings for a particular queue.685 **/686static int __iavf_set_coalesce(struct net_device *netdev,687 struct ethtool_coalesce *ec, int queue)688{689 struct iavf_adapter *adapter = netdev_priv(netdev);690 int i;691 692 if (ec->rx_coalesce_usecs > IAVF_MAX_ITR) {693 netif_info(adapter, drv, netdev, "Invalid value, rx-usecs range is 0-8160\n");694 return -EINVAL;695 } else if (ec->tx_coalesce_usecs > IAVF_MAX_ITR) {696 netif_info(adapter, drv, netdev, "Invalid value, tx-usecs range is 0-8160\n");697 return -EINVAL;698 }699 700 /* Rx and Tx usecs has per queue value. If user doesn't specify the701 * queue, apply to all queues.702 */703 if (queue < 0) {704 for (i = 0; i < adapter->num_active_queues; i++)705 if (iavf_set_itr_per_queue(adapter, ec, i))706 return -EINVAL;707 } else if (queue < adapter->num_active_queues) {708 if (iavf_set_itr_per_queue(adapter, ec, queue))709 return -EINVAL;710 } else {711 netif_info(adapter, drv, netdev, "Invalid queue value, queue range is 0 - %d\n",712 adapter->num_active_queues - 1);713 return -EINVAL;714 }715 716 return 0;717}718 719/**720 * iavf_set_coalesce - Set interrupt coalescing settings721 * @netdev: network interface device structure722 * @ec: ethtool coalesce structure723 * @kernel_coal: ethtool CQE mode setting structure724 * @extack: extack for reporting error messages725 *726 * Change current coalescing settings for every queue.727 **/728static int iavf_set_coalesce(struct net_device *netdev,729 struct ethtool_coalesce *ec,730 struct kernel_ethtool_coalesce *kernel_coal,731 struct netlink_ext_ack *extack)732{733 return __iavf_set_coalesce(netdev, ec, -1);734}735 736/**737 * iavf_set_per_queue_coalesce - set specific queue's coalesce settings738 * @netdev: the netdev to change739 * @ec: ethtool's coalesce settings740 * @queue: the queue to modify741 *742 * Modifies a specific queue's coalesce settings.743 */744static int iavf_set_per_queue_coalesce(struct net_device *netdev, u32 queue,745 struct ethtool_coalesce *ec)746{747 return __iavf_set_coalesce(netdev, ec, queue);748}749 750/**751 * iavf_fltr_to_ethtool_flow - convert filter type values to ethtool752 * flow type values753 * @flow: filter type to be converted754 *755 * Returns the corresponding ethtool flow type.756 */757static int iavf_fltr_to_ethtool_flow(enum iavf_fdir_flow_type flow)758{759 switch (flow) {760 case IAVF_FDIR_FLOW_IPV4_TCP:761 return TCP_V4_FLOW;762 case IAVF_FDIR_FLOW_IPV4_UDP:763 return UDP_V4_FLOW;764 case IAVF_FDIR_FLOW_IPV4_SCTP:765 return SCTP_V4_FLOW;766 case IAVF_FDIR_FLOW_IPV4_AH:767 return AH_V4_FLOW;768 case IAVF_FDIR_FLOW_IPV4_ESP:769 return ESP_V4_FLOW;770 case IAVF_FDIR_FLOW_IPV4_OTHER:771 return IPV4_USER_FLOW;772 case IAVF_FDIR_FLOW_IPV6_TCP:773 return TCP_V6_FLOW;774 case IAVF_FDIR_FLOW_IPV6_UDP:775 return UDP_V6_FLOW;776 case IAVF_FDIR_FLOW_IPV6_SCTP:777 return SCTP_V6_FLOW;778 case IAVF_FDIR_FLOW_IPV6_AH:779 return AH_V6_FLOW;780 case IAVF_FDIR_FLOW_IPV6_ESP:781 return ESP_V6_FLOW;782 case IAVF_FDIR_FLOW_IPV6_OTHER:783 return IPV6_USER_FLOW;784 case IAVF_FDIR_FLOW_NON_IP_L2:785 return ETHER_FLOW;786 default:787 /* 0 is undefined ethtool flow */788 return 0;789 }790}791 792/**793 * iavf_ethtool_flow_to_fltr - convert ethtool flow type to filter enum794 * @eth: Ethtool flow type to be converted795 *796 * Returns flow enum797 */798static enum iavf_fdir_flow_type iavf_ethtool_flow_to_fltr(int eth)799{800 switch (eth) {801 case TCP_V4_FLOW:802 return IAVF_FDIR_FLOW_IPV4_TCP;803 case UDP_V4_FLOW:804 return IAVF_FDIR_FLOW_IPV4_UDP;805 case SCTP_V4_FLOW:806 return IAVF_FDIR_FLOW_IPV4_SCTP;807 case AH_V4_FLOW:808 return IAVF_FDIR_FLOW_IPV4_AH;809 case ESP_V4_FLOW:810 return IAVF_FDIR_FLOW_IPV4_ESP;811 case IPV4_USER_FLOW:812 return IAVF_FDIR_FLOW_IPV4_OTHER;813 case TCP_V6_FLOW:814 return IAVF_FDIR_FLOW_IPV6_TCP;815 case UDP_V6_FLOW:816 return IAVF_FDIR_FLOW_IPV6_UDP;817 case SCTP_V6_FLOW:818 return IAVF_FDIR_FLOW_IPV6_SCTP;819 case AH_V6_FLOW:820 return IAVF_FDIR_FLOW_IPV6_AH;821 case ESP_V6_FLOW:822 return IAVF_FDIR_FLOW_IPV6_ESP;823 case IPV6_USER_FLOW:824 return IAVF_FDIR_FLOW_IPV6_OTHER;825 case ETHER_FLOW:826 return IAVF_FDIR_FLOW_NON_IP_L2;827 default:828 return IAVF_FDIR_FLOW_NONE;829 }830}831 832/**833 * iavf_is_mask_valid - check mask field set834 * @mask: full mask to check835 * @field: field for which mask should be valid836 *837 * If the mask is fully set return true. If it is not valid for field return838 * false.839 */840static bool iavf_is_mask_valid(u64 mask, u64 field)841{842 return (mask & field) == field;843}844 845/**846 * iavf_parse_rx_flow_user_data - deconstruct user-defined data847 * @fsp: pointer to ethtool Rx flow specification848 * @fltr: pointer to Flow Director filter for userdef data storage849 *850 * Returns 0 on success, negative error value on failure851 */852static int853iavf_parse_rx_flow_user_data(struct ethtool_rx_flow_spec *fsp,854 struct iavf_fdir_fltr *fltr)855{856 struct iavf_flex_word *flex;857 int i, cnt = 0;858 859 if (!(fsp->flow_type & FLOW_EXT))860 return 0;861 862 for (i = 0; i < IAVF_FLEX_WORD_NUM; i++) {863#define IAVF_USERDEF_FLEX_WORD_M GENMASK(15, 0)864#define IAVF_USERDEF_FLEX_OFFS_S 16865#define IAVF_USERDEF_FLEX_OFFS_M GENMASK(31, IAVF_USERDEF_FLEX_OFFS_S)866#define IAVF_USERDEF_FLEX_FLTR_M GENMASK(31, 0)867 u32 value = be32_to_cpu(fsp->h_ext.data[i]);868 u32 mask = be32_to_cpu(fsp->m_ext.data[i]);869 870 if (!value || !mask)871 continue;872 873 if (!iavf_is_mask_valid(mask, IAVF_USERDEF_FLEX_FLTR_M))874 return -EINVAL;875 876 /* 504 is the maximum value for offsets, and offset is measured877 * from the start of the MAC address.878 */879#define IAVF_USERDEF_FLEX_MAX_OFFS_VAL 504880 flex = &fltr->flex_words[cnt++];881 flex->word = value & IAVF_USERDEF_FLEX_WORD_M;882 flex->offset = FIELD_GET(IAVF_USERDEF_FLEX_OFFS_M, value);883 if (flex->offset > IAVF_USERDEF_FLEX_MAX_OFFS_VAL)884 return -EINVAL;885 }886 887 fltr->flex_cnt = cnt;888 889 return 0;890}891 892/**893 * iavf_fill_rx_flow_ext_data - fill the additional data894 * @fsp: pointer to ethtool Rx flow specification895 * @fltr: pointer to Flow Director filter to get additional data896 */897static void898iavf_fill_rx_flow_ext_data(struct ethtool_rx_flow_spec *fsp,899 struct iavf_fdir_fltr *fltr)900{901 if (!fltr->ext_mask.usr_def[0] && !fltr->ext_mask.usr_def[1])902 return;903 904 fsp->flow_type |= FLOW_EXT;905 906 memcpy(fsp->h_ext.data, fltr->ext_data.usr_def, sizeof(fsp->h_ext.data));907 memcpy(fsp->m_ext.data, fltr->ext_mask.usr_def, sizeof(fsp->m_ext.data));908}909 910/**911 * iavf_get_ethtool_fdir_entry - fill ethtool structure with Flow Director filter data912 * @adapter: the VF adapter structure that contains filter list913 * @cmd: ethtool command data structure to receive the filter data914 *915 * Returns 0 as expected for success by ethtool916 */917static int918iavf_get_ethtool_fdir_entry(struct iavf_adapter *adapter,919 struct ethtool_rxnfc *cmd)920{921 struct ethtool_rx_flow_spec *fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;922 struct iavf_fdir_fltr *rule = NULL;923 int ret = 0;924 925 if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))926 return -EOPNOTSUPP;927 928 spin_lock_bh(&adapter->fdir_fltr_lock);929 930 rule = iavf_find_fdir_fltr(adapter, false, fsp->location);931 if (!rule) {932 ret = -EINVAL;933 goto release_lock;934 }935 936 fsp->flow_type = iavf_fltr_to_ethtool_flow(rule->flow_type);937 938 memset(&fsp->m_u, 0, sizeof(fsp->m_u));939 memset(&fsp->m_ext, 0, sizeof(fsp->m_ext));940 941 switch (fsp->flow_type) {942 case TCP_V4_FLOW:943 case UDP_V4_FLOW:944 case SCTP_V4_FLOW:945 fsp->h_u.tcp_ip4_spec.ip4src = rule->ip_data.v4_addrs.src_ip;946 fsp->h_u.tcp_ip4_spec.ip4dst = rule->ip_data.v4_addrs.dst_ip;947 fsp->h_u.tcp_ip4_spec.psrc = rule->ip_data.src_port;948 fsp->h_u.tcp_ip4_spec.pdst = rule->ip_data.dst_port;949 fsp->h_u.tcp_ip4_spec.tos = rule->ip_data.tos;950 fsp->m_u.tcp_ip4_spec.ip4src = rule->ip_mask.v4_addrs.src_ip;951 fsp->m_u.tcp_ip4_spec.ip4dst = rule->ip_mask.v4_addrs.dst_ip;952 fsp->m_u.tcp_ip4_spec.psrc = rule->ip_mask.src_port;953 fsp->m_u.tcp_ip4_spec.pdst = rule->ip_mask.dst_port;954 fsp->m_u.tcp_ip4_spec.tos = rule->ip_mask.tos;955 break;956 case AH_V4_FLOW:957 case ESP_V4_FLOW:958 fsp->h_u.ah_ip4_spec.ip4src = rule->ip_data.v4_addrs.src_ip;959 fsp->h_u.ah_ip4_spec.ip4dst = rule->ip_data.v4_addrs.dst_ip;960 fsp->h_u.ah_ip4_spec.spi = rule->ip_data.spi;961 fsp->h_u.ah_ip4_spec.tos = rule->ip_data.tos;962 fsp->m_u.ah_ip4_spec.ip4src = rule->ip_mask.v4_addrs.src_ip;963 fsp->m_u.ah_ip4_spec.ip4dst = rule->ip_mask.v4_addrs.dst_ip;964 fsp->m_u.ah_ip4_spec.spi = rule->ip_mask.spi;965 fsp->m_u.ah_ip4_spec.tos = rule->ip_mask.tos;966 break;967 case IPV4_USER_FLOW:968 fsp->h_u.usr_ip4_spec.ip4src = rule->ip_data.v4_addrs.src_ip;969 fsp->h_u.usr_ip4_spec.ip4dst = rule->ip_data.v4_addrs.dst_ip;970 fsp->h_u.usr_ip4_spec.l4_4_bytes = rule->ip_data.l4_header;971 fsp->h_u.usr_ip4_spec.tos = rule->ip_data.tos;972 fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;973 fsp->h_u.usr_ip4_spec.proto = rule->ip_data.proto;974 fsp->m_u.usr_ip4_spec.ip4src = rule->ip_mask.v4_addrs.src_ip;975 fsp->m_u.usr_ip4_spec.ip4dst = rule->ip_mask.v4_addrs.dst_ip;976 fsp->m_u.usr_ip4_spec.l4_4_bytes = rule->ip_mask.l4_header;977 fsp->m_u.usr_ip4_spec.tos = rule->ip_mask.tos;978 fsp->m_u.usr_ip4_spec.ip_ver = 0xFF;979 fsp->m_u.usr_ip4_spec.proto = rule->ip_mask.proto;980 break;981 case TCP_V6_FLOW:982 case UDP_V6_FLOW:983 case SCTP_V6_FLOW:984 memcpy(fsp->h_u.usr_ip6_spec.ip6src, &rule->ip_data.v6_addrs.src_ip,985 sizeof(struct in6_addr));986 memcpy(fsp->h_u.usr_ip6_spec.ip6dst, &rule->ip_data.v6_addrs.dst_ip,987 sizeof(struct in6_addr));988 fsp->h_u.tcp_ip6_spec.psrc = rule->ip_data.src_port;989 fsp->h_u.tcp_ip6_spec.pdst = rule->ip_data.dst_port;990 fsp->h_u.tcp_ip6_spec.tclass = rule->ip_data.tclass;991 memcpy(fsp->m_u.usr_ip6_spec.ip6src, &rule->ip_mask.v6_addrs.src_ip,992 sizeof(struct in6_addr));993 memcpy(fsp->m_u.usr_ip6_spec.ip6dst, &rule->ip_mask.v6_addrs.dst_ip,994 sizeof(struct in6_addr));995 fsp->m_u.tcp_ip6_spec.psrc = rule->ip_mask.src_port;996 fsp->m_u.tcp_ip6_spec.pdst = rule->ip_mask.dst_port;997 fsp->m_u.tcp_ip6_spec.tclass = rule->ip_mask.tclass;998 break;999 case AH_V6_FLOW:1000 case ESP_V6_FLOW:1001 memcpy(fsp->h_u.ah_ip6_spec.ip6src, &rule->ip_data.v6_addrs.src_ip,1002 sizeof(struct in6_addr));1003 memcpy(fsp->h_u.ah_ip6_spec.ip6dst, &rule->ip_data.v6_addrs.dst_ip,1004 sizeof(struct in6_addr));1005 fsp->h_u.ah_ip6_spec.spi = rule->ip_data.spi;1006 fsp->h_u.ah_ip6_spec.tclass = rule->ip_data.tclass;1007 memcpy(fsp->m_u.ah_ip6_spec.ip6src, &rule->ip_mask.v6_addrs.src_ip,1008 sizeof(struct in6_addr));1009 memcpy(fsp->m_u.ah_ip6_spec.ip6dst, &rule->ip_mask.v6_addrs.dst_ip,1010 sizeof(struct in6_addr));1011 fsp->m_u.ah_ip6_spec.spi = rule->ip_mask.spi;1012 fsp->m_u.ah_ip6_spec.tclass = rule->ip_mask.tclass;1013 break;1014 case IPV6_USER_FLOW:1015 memcpy(fsp->h_u.usr_ip6_spec.ip6src, &rule->ip_data.v6_addrs.src_ip,1016 sizeof(struct in6_addr));1017 memcpy(fsp->h_u.usr_ip6_spec.ip6dst, &rule->ip_data.v6_addrs.dst_ip,1018 sizeof(struct in6_addr));1019 fsp->h_u.usr_ip6_spec.l4_4_bytes = rule->ip_data.l4_header;1020 fsp->h_u.usr_ip6_spec.tclass = rule->ip_data.tclass;1021 fsp->h_u.usr_ip6_spec.l4_proto = rule->ip_data.proto;1022 memcpy(fsp->m_u.usr_ip6_spec.ip6src, &rule->ip_mask.v6_addrs.src_ip,1023 sizeof(struct in6_addr));1024 memcpy(fsp->m_u.usr_ip6_spec.ip6dst, &rule->ip_mask.v6_addrs.dst_ip,1025 sizeof(struct in6_addr));1026 fsp->m_u.usr_ip6_spec.l4_4_bytes = rule->ip_mask.l4_header;1027 fsp->m_u.usr_ip6_spec.tclass = rule->ip_mask.tclass;1028 fsp->m_u.usr_ip6_spec.l4_proto = rule->ip_mask.proto;1029 break;1030 case ETHER_FLOW:1031 fsp->h_u.ether_spec.h_proto = rule->eth_data.etype;1032 fsp->m_u.ether_spec.h_proto = rule->eth_mask.etype;1033 break;1034 default:1035 ret = -EINVAL;1036 break;1037 }1038 1039 iavf_fill_rx_flow_ext_data(fsp, rule);1040 1041 if (rule->action == VIRTCHNL_ACTION_DROP)1042 fsp->ring_cookie = RX_CLS_FLOW_DISC;1043 else1044 fsp->ring_cookie = rule->q_index;1045 1046release_lock:1047 spin_unlock_bh(&adapter->fdir_fltr_lock);1048 return ret;1049}1050 1051/**1052 * iavf_get_fdir_fltr_ids - fill buffer with filter IDs of active filters1053 * @adapter: the VF adapter structure containing the filter list1054 * @cmd: ethtool command data structure1055 * @rule_locs: ethtool array passed in from OS to receive filter IDs1056 *1057 * Returns 0 as expected for success by ethtool1058 */1059static int1060iavf_get_fdir_fltr_ids(struct iavf_adapter *adapter, struct ethtool_rxnfc *cmd,1061 u32 *rule_locs)1062{1063 struct iavf_fdir_fltr *fltr;1064 unsigned int cnt = 0;1065 int val = 0;1066 1067 if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))1068 return -EOPNOTSUPP;1069 1070 cmd->data = IAVF_MAX_FDIR_FILTERS;1071 1072 spin_lock_bh(&adapter->fdir_fltr_lock);1073 1074 list_for_each_entry(fltr, &adapter->fdir_list_head, list) {1075 if (iavf_is_raw_fdir(fltr))1076 continue;1077 1078 if (cnt == cmd->rule_cnt) {1079 val = -EMSGSIZE;1080 goto release_lock;1081 }1082 rule_locs[cnt] = fltr->loc;1083 cnt++;1084 }1085 1086release_lock:1087 spin_unlock_bh(&adapter->fdir_fltr_lock);1088 if (!val)1089 cmd->rule_cnt = cnt;1090 1091 return val;1092}1093 1094/**1095 * iavf_add_fdir_fltr_info - Set the input set for Flow Director filter1096 * @adapter: pointer to the VF adapter structure1097 * @fsp: pointer to ethtool Rx flow specification1098 * @fltr: filter structure1099 */1100static int1101iavf_add_fdir_fltr_info(struct iavf_adapter *adapter, struct ethtool_rx_flow_spec *fsp,1102 struct iavf_fdir_fltr *fltr)1103{1104 u32 flow_type, q_index = 0;1105 enum virtchnl_action act;1106 int err;1107 1108 if (fsp->ring_cookie == RX_CLS_FLOW_DISC) {1109 act = VIRTCHNL_ACTION_DROP;1110 } else {1111 q_index = fsp->ring_cookie;1112 if (q_index >= adapter->num_active_queues)1113 return -EINVAL;1114 1115 act = VIRTCHNL_ACTION_QUEUE;1116 }1117 1118 fltr->action = act;1119 fltr->loc = fsp->location;1120 fltr->q_index = q_index;1121 1122 if (fsp->flow_type & FLOW_EXT) {1123 memcpy(fltr->ext_data.usr_def, fsp->h_ext.data,1124 sizeof(fltr->ext_data.usr_def));1125 memcpy(fltr->ext_mask.usr_def, fsp->m_ext.data,1126 sizeof(fltr->ext_mask.usr_def));1127 }1128 1129 flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);1130 fltr->flow_type = iavf_ethtool_flow_to_fltr(flow_type);1131 1132 switch (flow_type) {1133 case TCP_V4_FLOW:1134 case UDP_V4_FLOW:1135 case SCTP_V4_FLOW:1136 fltr->ip_data.v4_addrs.src_ip = fsp->h_u.tcp_ip4_spec.ip4src;1137 fltr->ip_data.v4_addrs.dst_ip = fsp->h_u.tcp_ip4_spec.ip4dst;1138 fltr->ip_data.src_port = fsp->h_u.tcp_ip4_spec.psrc;1139 fltr->ip_data.dst_port = fsp->h_u.tcp_ip4_spec.pdst;1140 fltr->ip_data.tos = fsp->h_u.tcp_ip4_spec.tos;1141 fltr->ip_mask.v4_addrs.src_ip = fsp->m_u.tcp_ip4_spec.ip4src;1142 fltr->ip_mask.v4_addrs.dst_ip = fsp->m_u.tcp_ip4_spec.ip4dst;1143 fltr->ip_mask.src_port = fsp->m_u.tcp_ip4_spec.psrc;1144 fltr->ip_mask.dst_port = fsp->m_u.tcp_ip4_spec.pdst;1145 fltr->ip_mask.tos = fsp->m_u.tcp_ip4_spec.tos;1146 fltr->ip_ver = 4;1147 break;1148 case AH_V4_FLOW:1149 case ESP_V4_FLOW:1150 fltr->ip_data.v4_addrs.src_ip = fsp->h_u.ah_ip4_spec.ip4src;1151 fltr->ip_data.v4_addrs.dst_ip = fsp->h_u.ah_ip4_spec.ip4dst;1152 fltr->ip_data.spi = fsp->h_u.ah_ip4_spec.spi;1153 fltr->ip_data.tos = fsp->h_u.ah_ip4_spec.tos;1154 fltr->ip_mask.v4_addrs.src_ip = fsp->m_u.ah_ip4_spec.ip4src;1155 fltr->ip_mask.v4_addrs.dst_ip = fsp->m_u.ah_ip4_spec.ip4dst;1156 fltr->ip_mask.spi = fsp->m_u.ah_ip4_spec.spi;1157 fltr->ip_mask.tos = fsp->m_u.ah_ip4_spec.tos;1158 fltr->ip_ver = 4;1159 break;1160 case IPV4_USER_FLOW:1161 fltr->ip_data.v4_addrs.src_ip = fsp->h_u.usr_ip4_spec.ip4src;1162 fltr->ip_data.v4_addrs.dst_ip = fsp->h_u.usr_ip4_spec.ip4dst;1163 fltr->ip_data.l4_header = fsp->h_u.usr_ip4_spec.l4_4_bytes;1164 fltr->ip_data.tos = fsp->h_u.usr_ip4_spec.tos;1165 fltr->ip_data.proto = fsp->h_u.usr_ip4_spec.proto;1166 fltr->ip_mask.v4_addrs.src_ip = fsp->m_u.usr_ip4_spec.ip4src;1167 fltr->ip_mask.v4_addrs.dst_ip = fsp->m_u.usr_ip4_spec.ip4dst;1168 fltr->ip_mask.l4_header = fsp->m_u.usr_ip4_spec.l4_4_bytes;1169 fltr->ip_mask.tos = fsp->m_u.usr_ip4_spec.tos;1170 fltr->ip_mask.proto = fsp->m_u.usr_ip4_spec.proto;1171 fltr->ip_ver = 4;1172 break;1173 case TCP_V6_FLOW:1174 case UDP_V6_FLOW:1175 case SCTP_V6_FLOW:1176 memcpy(&fltr->ip_data.v6_addrs.src_ip, fsp->h_u.usr_ip6_spec.ip6src,1177 sizeof(struct in6_addr));1178 memcpy(&fltr->ip_data.v6_addrs.dst_ip, fsp->h_u.usr_ip6_spec.ip6dst,1179 sizeof(struct in6_addr));1180 fltr->ip_data.src_port = fsp->h_u.tcp_ip6_spec.psrc;1181 fltr->ip_data.dst_port = fsp->h_u.tcp_ip6_spec.pdst;1182 fltr->ip_data.tclass = fsp->h_u.tcp_ip6_spec.tclass;1183 memcpy(&fltr->ip_mask.v6_addrs.src_ip, fsp->m_u.usr_ip6_spec.ip6src,1184 sizeof(struct in6_addr));1185 memcpy(&fltr->ip_mask.v6_addrs.dst_ip, fsp->m_u.usr_ip6_spec.ip6dst,1186 sizeof(struct in6_addr));1187 fltr->ip_mask.src_port = fsp->m_u.tcp_ip6_spec.psrc;1188 fltr->ip_mask.dst_port = fsp->m_u.tcp_ip6_spec.pdst;1189 fltr->ip_mask.tclass = fsp->m_u.tcp_ip6_spec.tclass;1190 fltr->ip_ver = 6;1191 break;1192 case AH_V6_FLOW:1193 case ESP_V6_FLOW:1194 memcpy(&fltr->ip_data.v6_addrs.src_ip, fsp->h_u.ah_ip6_spec.ip6src,1195 sizeof(struct in6_addr));1196 memcpy(&fltr->ip_data.v6_addrs.dst_ip, fsp->h_u.ah_ip6_spec.ip6dst,1197 sizeof(struct in6_addr));1198 fltr->ip_data.spi = fsp->h_u.ah_ip6_spec.spi;1199 fltr->ip_data.tclass = fsp->h_u.ah_ip6_spec.tclass;1200 memcpy(&fltr->ip_mask.v6_addrs.src_ip, fsp->m_u.ah_ip6_spec.ip6src,1201 sizeof(struct in6_addr));1202 memcpy(&fltr->ip_mask.v6_addrs.dst_ip, fsp->m_u.ah_ip6_spec.ip6dst,1203 sizeof(struct in6_addr));1204 fltr->ip_mask.spi = fsp->m_u.ah_ip6_spec.spi;1205 fltr->ip_mask.tclass = fsp->m_u.ah_ip6_spec.tclass;1206 fltr->ip_ver = 6;1207 break;1208 case IPV6_USER_FLOW:1209 memcpy(&fltr->ip_data.v6_addrs.src_ip, fsp->h_u.usr_ip6_spec.ip6src,1210 sizeof(struct in6_addr));1211 memcpy(&fltr->ip_data.v6_addrs.dst_ip, fsp->h_u.usr_ip6_spec.ip6dst,1212 sizeof(struct in6_addr));1213 fltr->ip_data.l4_header = fsp->h_u.usr_ip6_spec.l4_4_bytes;1214 fltr->ip_data.tclass = fsp->h_u.usr_ip6_spec.tclass;1215 fltr->ip_data.proto = fsp->h_u.usr_ip6_spec.l4_proto;1216 memcpy(&fltr->ip_mask.v6_addrs.src_ip, fsp->m_u.usr_ip6_spec.ip6src,1217 sizeof(struct in6_addr));1218 memcpy(&fltr->ip_mask.v6_addrs.dst_ip, fsp->m_u.usr_ip6_spec.ip6dst,1219 sizeof(struct in6_addr));1220 fltr->ip_mask.l4_header = fsp->m_u.usr_ip6_spec.l4_4_bytes;1221 fltr->ip_mask.tclass = fsp->m_u.usr_ip6_spec.tclass;1222 fltr->ip_mask.proto = fsp->m_u.usr_ip6_spec.l4_proto;1223 fltr->ip_ver = 6;1224 break;1225 case ETHER_FLOW:1226 fltr->eth_data.etype = fsp->h_u.ether_spec.h_proto;1227 fltr->eth_mask.etype = fsp->m_u.ether_spec.h_proto;1228 break;1229 default:1230 /* not doing un-parsed flow types */1231 return -EINVAL;1232 }1233 1234 err = iavf_validate_fdir_fltr_masks(adapter, fltr);1235 if (err)1236 return err;1237 1238 if (iavf_fdir_is_dup_fltr(adapter, fltr))1239 return -EEXIST;1240 1241 err = iavf_parse_rx_flow_user_data(fsp, fltr);1242 if (err)1243 return err;1244 1245 return iavf_fill_fdir_add_msg(adapter, fltr);1246}1247 1248/**1249 * iavf_add_fdir_ethtool - add Flow Director filter1250 * @adapter: pointer to the VF adapter structure1251 * @cmd: command to add Flow Director filter1252 *1253 * Returns 0 on success and negative values for failure1254 */1255static int iavf_add_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rxnfc *cmd)1256{1257 struct ethtool_rx_flow_spec *fsp = &cmd->fs;1258 struct iavf_fdir_fltr *fltr;1259 int count = 50;1260 int err;1261 1262 if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))1263 return -EOPNOTSUPP;1264 1265 if (fsp->flow_type & FLOW_MAC_EXT)1266 return -EINVAL;1267 1268 spin_lock_bh(&adapter->fdir_fltr_lock);1269 if (iavf_find_fdir_fltr(adapter, false, fsp->location)) {1270 dev_err(&adapter->pdev->dev, "Failed to add Flow Director filter, it already exists\n");1271 spin_unlock_bh(&adapter->fdir_fltr_lock);1272 return -EEXIST;1273 }1274 spin_unlock_bh(&adapter->fdir_fltr_lock);1275 1276 fltr = kzalloc(sizeof(*fltr), GFP_KERNEL);1277 if (!fltr)1278 return -ENOMEM;1279 1280 while (!mutex_trylock(&adapter->crit_lock)) {1281 if (--count == 0) {1282 kfree(fltr);1283 return -EINVAL;1284 }1285 udelay(1);1286 }1287 1288 err = iavf_add_fdir_fltr_info(adapter, fsp, fltr);1289 if (!err)1290 err = iavf_fdir_add_fltr(adapter, fltr);1291 1292 if (err)1293 kfree(fltr);1294 1295 mutex_unlock(&adapter->crit_lock);1296 return err;1297}1298 1299/**1300 * iavf_del_fdir_ethtool - delete Flow Director filter1301 * @adapter: pointer to the VF adapter structure1302 * @cmd: command to delete Flow Director filter1303 *1304 * Returns 0 on success and negative values for failure1305 */1306static int iavf_del_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rxnfc *cmd)1307{1308 struct ethtool_rx_flow_spec *fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;1309 1310 if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))1311 return -EOPNOTSUPP;1312 1313 return iavf_fdir_del_fltr(adapter, false, fsp->location);1314}1315 1316/**1317 * iavf_adv_rss_parse_hdrs - parses headers from RSS hash input1318 * @cmd: ethtool rxnfc command1319 *1320 * This function parses the rxnfc command and returns intended1321 * header types for RSS configuration1322 */1323static u32 iavf_adv_rss_parse_hdrs(struct ethtool_rxnfc *cmd)1324{1325 u32 hdrs = IAVF_ADV_RSS_FLOW_SEG_HDR_NONE;1326 1327 switch (cmd->flow_type) {1328 case TCP_V4_FLOW:1329 hdrs |= IAVF_ADV_RSS_FLOW_SEG_HDR_TCP |1330 IAVF_ADV_RSS_FLOW_SEG_HDR_IPV4;1331 break;1332 case UDP_V4_FLOW:1333 hdrs |= IAVF_ADV_RSS_FLOW_SEG_HDR_UDP |1334 IAVF_ADV_RSS_FLOW_SEG_HDR_IPV4;1335 break;1336 case SCTP_V4_FLOW:1337 hdrs |= IAVF_ADV_RSS_FLOW_SEG_HDR_SCTP |1338 IAVF_ADV_RSS_FLOW_SEG_HDR_IPV4;1339 break;1340 case TCP_V6_FLOW:1341 hdrs |= IAVF_ADV_RSS_FLOW_SEG_HDR_TCP |1342 IAVF_ADV_RSS_FLOW_SEG_HDR_IPV6;1343 break;1344 case UDP_V6_FLOW:1345 hdrs |= IAVF_ADV_RSS_FLOW_SEG_HDR_UDP |1346 IAVF_ADV_RSS_FLOW_SEG_HDR_IPV6;1347 break;1348 case SCTP_V6_FLOW:1349 hdrs |= IAVF_ADV_RSS_FLOW_SEG_HDR_SCTP |1350 IAVF_ADV_RSS_FLOW_SEG_HDR_IPV6;1351 break;1352 default:1353 break;1354 }1355 1356 return hdrs;1357}1358 1359/**1360 * iavf_adv_rss_parse_hash_flds - parses hash fields from RSS hash input1361 * @cmd: ethtool rxnfc command1362 * @symm: true if Symmetric Topelitz is set1363 *1364 * This function parses the rxnfc command and returns intended hash fields for1365 * RSS configuration1366 */1367static u64 iavf_adv_rss_parse_hash_flds(struct ethtool_rxnfc *cmd, bool symm)1368{1369 u64 hfld = IAVF_ADV_RSS_HASH_INVALID;1370 1371 if (cmd->data & RXH_IP_SRC || cmd->data & RXH_IP_DST) {1372 switch (cmd->flow_type) {1373 case TCP_V4_FLOW:1374 case UDP_V4_FLOW:1375 case SCTP_V4_FLOW:1376 if (cmd->data & RXH_IP_SRC)1377 hfld |= IAVF_ADV_RSS_HASH_FLD_IPV4_SA;1378 if (cmd->data & RXH_IP_DST)1379 hfld |= IAVF_ADV_RSS_HASH_FLD_IPV4_DA;1380 break;1381 case TCP_V6_FLOW:1382 case UDP_V6_FLOW:1383 case SCTP_V6_FLOW:1384 if (cmd->data & RXH_IP_SRC)1385 hfld |= IAVF_ADV_RSS_HASH_FLD_IPV6_SA;1386 if (cmd->data & RXH_IP_DST)1387 hfld |= IAVF_ADV_RSS_HASH_FLD_IPV6_DA;1388 break;1389 default:1390 break;1391 }1392 }1393 1394 if (cmd->data & RXH_L4_B_0_1 || cmd->data & RXH_L4_B_2_3) {1395 switch (cmd->flow_type) {1396 case TCP_V4_FLOW:1397 case TCP_V6_FLOW:1398 if (cmd->data & RXH_L4_B_0_1)1399 hfld |= IAVF_ADV_RSS_HASH_FLD_TCP_SRC_PORT;1400 if (cmd->data & RXH_L4_B_2_3)1401 hfld |= IAVF_ADV_RSS_HASH_FLD_TCP_DST_PORT;1402 break;1403 case UDP_V4_FLOW:1404 case UDP_V6_FLOW:1405 if (cmd->data & RXH_L4_B_0_1)1406 hfld |= IAVF_ADV_RSS_HASH_FLD_UDP_SRC_PORT;1407 if (cmd->data & RXH_L4_B_2_3)1408 hfld |= IAVF_ADV_RSS_HASH_FLD_UDP_DST_PORT;1409 break;1410 case SCTP_V4_FLOW:1411 case SCTP_V6_FLOW:1412 if (cmd->data & RXH_L4_B_0_1)1413 hfld |= IAVF_ADV_RSS_HASH_FLD_SCTP_SRC_PORT;1414 if (cmd->data & RXH_L4_B_2_3)1415 hfld |= IAVF_ADV_RSS_HASH_FLD_SCTP_DST_PORT;1416 break;1417 default:1418 break;1419 }1420 }1421 1422 return hfld;1423}1424 1425/**1426 * iavf_set_adv_rss_hash_opt - Enable/Disable flow types for RSS hash1427 * @adapter: pointer to the VF adapter structure1428 * @cmd: ethtool rxnfc command1429 *1430 * Returns Success if the flow input set is supported.1431 */1432static int1433iavf_set_adv_rss_hash_opt(struct iavf_adapter *adapter,1434 struct ethtool_rxnfc *cmd)1435{1436 struct iavf_adv_rss *rss_old, *rss_new;1437 bool rss_new_add = false;1438 int count = 50, err = 0;1439 bool symm = false;1440 u64 hash_flds;1441 u32 hdrs;1442 1443 if (!ADV_RSS_SUPPORT(adapter))1444 return -EOPNOTSUPP;1445 1446 symm = !!(adapter->hfunc == VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC);1447 1448 hdrs = iavf_adv_rss_parse_hdrs(cmd);1449 if (hdrs == IAVF_ADV_RSS_FLOW_SEG_HDR_NONE)1450 return -EINVAL;1451 1452 hash_flds = iavf_adv_rss_parse_hash_flds(cmd, symm);1453 if (hash_flds == IAVF_ADV_RSS_HASH_INVALID)1454 return -EINVAL;1455 1456 rss_new = kzalloc(sizeof(*rss_new), GFP_KERNEL);1457 if (!rss_new)1458 return -ENOMEM;1459 1460 if (iavf_fill_adv_rss_cfg_msg(&rss_new->cfg_msg, hdrs, hash_flds,1461 symm)) {1462 kfree(rss_new);1463 return -EINVAL;1464 }1465 1466 while (!mutex_trylock(&adapter->crit_lock)) {1467 if (--count == 0) {1468 kfree(rss_new);1469 return -EINVAL;1470 }1471 1472 udelay(1);1473 }1474 1475 spin_lock_bh(&adapter->adv_rss_lock);1476 rss_old = iavf_find_adv_rss_cfg_by_hdrs(adapter, hdrs);1477 if (rss_old) {1478 if (rss_old->state != IAVF_ADV_RSS_ACTIVE) {1479 err = -EBUSY;1480 } else if (rss_old->hash_flds != hash_flds ||1481 rss_old->symm != symm) {1482 rss_old->state = IAVF_ADV_RSS_ADD_REQUEST;1483 rss_old->hash_flds = hash_flds;1484 rss_old->symm = symm;1485 memcpy(&rss_old->cfg_msg, &rss_new->cfg_msg,1486 sizeof(rss_new->cfg_msg));1487 } else {1488 err = -EEXIST;1489 }1490 } else {1491 rss_new_add = true;1492 rss_new->state = IAVF_ADV_RSS_ADD_REQUEST;1493 rss_new->packet_hdrs = hdrs;1494 rss_new->hash_flds = hash_flds;1495 rss_new->symm = symm;1496 list_add_tail(&rss_new->list, &adapter->adv_rss_list_head);1497 }1498 spin_unlock_bh(&adapter->adv_rss_lock);1499 1500 if (!err)1501 iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_ADV_RSS_CFG);1502 1503 mutex_unlock(&adapter->crit_lock);1504 1505 if (!rss_new_add)1506 kfree(rss_new);1507 1508 return err;1509}1510 1511/**1512 * iavf_get_adv_rss_hash_opt - Retrieve hash fields for a given flow-type1513 * @adapter: pointer to the VF adapter structure1514 * @cmd: ethtool rxnfc command1515 *1516 * Returns Success if the flow input set is supported.1517 */1518static int1519iavf_get_adv_rss_hash_opt(struct iavf_adapter *adapter,1520 struct ethtool_rxnfc *cmd)1521{1522 struct iavf_adv_rss *rss;1523 u64 hash_flds;1524 u32 hdrs;1525 1526 if (!ADV_RSS_SUPPORT(adapter))1527 return -EOPNOTSUPP;1528 1529 cmd->data = 0;1530 1531 hdrs = iavf_adv_rss_parse_hdrs(cmd);1532 if (hdrs == IAVF_ADV_RSS_FLOW_SEG_HDR_NONE)1533 return -EINVAL;1534 1535 spin_lock_bh(&adapter->adv_rss_lock);1536 rss = iavf_find_adv_rss_cfg_by_hdrs(adapter, hdrs);1537 if (rss)1538 hash_flds = rss->hash_flds;1539 else1540 hash_flds = IAVF_ADV_RSS_HASH_INVALID;1541 spin_unlock_bh(&adapter->adv_rss_lock);1542 1543 if (hash_flds == IAVF_ADV_RSS_HASH_INVALID)1544 return -EINVAL;1545 1546 if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_IPV4_SA |1547 IAVF_ADV_RSS_HASH_FLD_IPV6_SA))1548 cmd->data |= (u64)RXH_IP_SRC;1549 1550 if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_IPV4_DA |1551 IAVF_ADV_RSS_HASH_FLD_IPV6_DA))1552 cmd->data |= (u64)RXH_IP_DST;1553 1554 if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_TCP_SRC_PORT |1555 IAVF_ADV_RSS_HASH_FLD_UDP_SRC_PORT |1556 IAVF_ADV_RSS_HASH_FLD_SCTP_SRC_PORT))1557 cmd->data |= (u64)RXH_L4_B_0_1;1558 1559 if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_TCP_DST_PORT |1560 IAVF_ADV_RSS_HASH_FLD_UDP_DST_PORT |1561 IAVF_ADV_RSS_HASH_FLD_SCTP_DST_PORT))1562 cmd->data |= (u64)RXH_L4_B_2_3;1563 1564 return 0;1565}1566 1567/**1568 * iavf_set_rxnfc - command to set Rx flow rules.1569 * @netdev: network interface device structure1570 * @cmd: ethtool rxnfc command1571 *1572 * Returns 0 for success and negative values for errors1573 */1574static int iavf_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)1575{1576 struct iavf_adapter *adapter = netdev_priv(netdev);1577 int ret = -EOPNOTSUPP;1578 1579 switch (cmd->cmd) {1580 case ETHTOOL_SRXCLSRLINS:1581 ret = iavf_add_fdir_ethtool(adapter, cmd);1582 break;1583 case ETHTOOL_SRXCLSRLDEL:1584 ret = iavf_del_fdir_ethtool(adapter, cmd);1585 break;1586 case ETHTOOL_SRXFH:1587 ret = iavf_set_adv_rss_hash_opt(adapter, cmd);1588 break;1589 default:1590 break;1591 }1592 1593 return ret;1594}1595 1596/**1597 * iavf_get_rxnfc - command to get RX flow classification rules1598 * @netdev: network interface device structure1599 * @cmd: ethtool rxnfc command1600 * @rule_locs: pointer to store rule locations1601 *1602 * Returns Success if the command is supported.1603 **/1604static int iavf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,1605 u32 *rule_locs)1606{1607 struct iavf_adapter *adapter = netdev_priv(netdev);1608 int ret = -EOPNOTSUPP;1609 1610 switch (cmd->cmd) {1611 case ETHTOOL_GRXRINGS:1612 cmd->data = adapter->num_active_queues;1613 ret = 0;1614 break;1615 case ETHTOOL_GRXCLSRLCNT:1616 if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))1617 break;1618 spin_lock_bh(&adapter->fdir_fltr_lock);1619 cmd->rule_cnt = adapter->fdir_active_fltr;1620 spin_unlock_bh(&adapter->fdir_fltr_lock);1621 cmd->data = IAVF_MAX_FDIR_FILTERS;1622 ret = 0;1623 break;1624 case ETHTOOL_GRXCLSRULE:1625 ret = iavf_get_ethtool_fdir_entry(adapter, cmd);1626 break;1627 case ETHTOOL_GRXCLSRLALL:1628 ret = iavf_get_fdir_fltr_ids(adapter, cmd, (u32 *)rule_locs);1629 break;1630 case ETHTOOL_GRXFH:1631 ret = iavf_get_adv_rss_hash_opt(adapter, cmd);1632 break;1633 default:1634 break;1635 }1636 1637 return ret;1638}1639/**1640 * iavf_get_channels: get the number of channels supported by the device1641 * @netdev: network interface device structure1642 * @ch: channel information structure1643 *1644 * For the purposes of our device, we only use combined channels, i.e. a tx/rx1645 * queue pair. Report one extra channel to match our "other" MSI-X vector.1646 **/1647static void iavf_get_channels(struct net_device *netdev,1648 struct ethtool_channels *ch)1649{1650 struct iavf_adapter *adapter = netdev_priv(netdev);1651 1652 /* Report maximum channels */1653 ch->max_combined = adapter->vsi_res->num_queue_pairs;1654 1655 ch->max_other = NONQ_VECS;1656 ch->other_count = NONQ_VECS;1657 1658 ch->combined_count = adapter->num_active_queues;1659}1660 1661/**1662 * iavf_set_channels: set the new channel count1663 * @netdev: network interface device structure1664 * @ch: channel information structure1665 *1666 * Negotiate a new number of channels with the PF then do a reset. During1667 * reset we'll realloc queues and fix the RSS table. Returns 0 on success,1668 * negative on failure.1669 **/1670static int iavf_set_channels(struct net_device *netdev,1671 struct ethtool_channels *ch)1672{1673 struct iavf_adapter *adapter = netdev_priv(netdev);1674 u32 num_req = ch->combined_count;1675 int ret = 0;1676 1677 if ((adapter->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ) &&1678 adapter->num_tc) {1679 dev_info(&adapter->pdev->dev, "Cannot set channels since ADq is enabled.\n");1680 return -EINVAL;1681 }1682 1683 /* All of these should have already been checked by ethtool before this1684 * even gets to us, but just to be sure.1685 */1686 if (num_req == 0 || num_req > adapter->vsi_res->num_queue_pairs)1687 return -EINVAL;1688 1689 if (num_req == adapter->num_active_queues)1690 return 0;1691 1692 if (ch->rx_count || ch->tx_count || ch->other_count != NONQ_VECS)1693 return -EINVAL;1694 1695 adapter->num_req_queues = num_req;1696 adapter->flags |= IAVF_FLAG_REINIT_ITR_NEEDED;1697 iavf_schedule_reset(adapter, IAVF_FLAG_RESET_NEEDED);1698 1699 ret = iavf_wait_for_reset(adapter);1700 if (ret)1701 netdev_warn(netdev, "Changing channel count timeout or interrupted waiting for reset");1702 1703 return ret;1704}1705 1706/**1707 * iavf_get_rxfh_key_size - get the RSS hash key size1708 * @netdev: network interface device structure1709 *1710 * Returns the table size.1711 **/1712static u32 iavf_get_rxfh_key_size(struct net_device *netdev)1713{1714 struct iavf_adapter *adapter = netdev_priv(netdev);1715 1716 return adapter->rss_key_size;1717}1718 1719/**1720 * iavf_get_rxfh_indir_size - get the rx flow hash indirection table size1721 * @netdev: network interface device structure1722 *1723 * Returns the table size.1724 **/1725static u32 iavf_get_rxfh_indir_size(struct net_device *netdev)1726{1727 struct iavf_adapter *adapter = netdev_priv(netdev);1728 1729 return adapter->rss_lut_size;1730}1731 1732/**1733 * iavf_get_rxfh - get the rx flow hash indirection table1734 * @netdev: network interface device structure1735 * @rxfh: pointer to param struct (indir, key, hfunc)1736 *1737 * Reads the indirection table directly from the hardware. Always returns 0.1738 **/1739static int iavf_get_rxfh(struct net_device *netdev,1740 struct ethtool_rxfh_param *rxfh)1741{1742 struct iavf_adapter *adapter = netdev_priv(netdev);1743 u16 i;1744 1745 rxfh->hfunc = ETH_RSS_HASH_TOP;1746 if (adapter->hfunc == VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC)1747 rxfh->input_xfrm |= RXH_XFRM_SYM_XOR;1748 1749 if (rxfh->key)1750 memcpy(rxfh->key, adapter->rss_key, adapter->rss_key_size);1751 1752 if (rxfh->indir)1753 /* Each 32 bits pointed by 'indir' is stored with a lut entry */1754 for (i = 0; i < adapter->rss_lut_size; i++)1755 rxfh->indir[i] = (u32)adapter->rss_lut[i];1756 1757 return 0;1758}1759 1760/**1761 * iavf_set_rxfh - set the rx flow hash indirection table1762 * @netdev: network interface device structure1763 * @rxfh: pointer to param struct (indir, key, hfunc)1764 * @extack: extended ACK from the Netlink message1765 *1766 * Returns -EINVAL if the table specifies an invalid queue id, otherwise1767 * returns 0 after programming the table.1768 **/1769static int iavf_set_rxfh(struct net_device *netdev,1770 struct ethtool_rxfh_param *rxfh,1771 struct netlink_ext_ack *extack)1772{1773 struct iavf_adapter *adapter = netdev_priv(netdev);1774 u16 i;1775 1776 /* Only support toeplitz hash function */1777 if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&1778 rxfh->hfunc != ETH_RSS_HASH_TOP)1779 return -EOPNOTSUPP;1780 1781 if ((rxfh->input_xfrm & RXH_XFRM_SYM_XOR) &&1782 adapter->hfunc != VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC) {1783 if (!ADV_RSS_SUPPORT(adapter))1784 return -EOPNOTSUPP;1785 adapter->hfunc = VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC;1786 adapter->aq_required |= IAVF_FLAG_AQ_SET_RSS_HFUNC;1787 } else if (!(rxfh->input_xfrm & RXH_XFRM_SYM_XOR) &&1788 adapter->hfunc != VIRTCHNL_RSS_ALG_TOEPLITZ_ASYMMETRIC) {1789 adapter->hfunc = VIRTCHNL_RSS_ALG_TOEPLITZ_ASYMMETRIC;1790 adapter->aq_required |= IAVF_FLAG_AQ_SET_RSS_HFUNC;1791 }1792 1793 if (!rxfh->key && !rxfh->indir)1794 return 0;1795 1796 if (rxfh->key)1797 memcpy(adapter->rss_key, rxfh->key, adapter->rss_key_size);1798 1799 if (rxfh->indir) {1800 /* Each 32 bits pointed by 'indir' is stored with a lut entry */1801 for (i = 0; i < adapter->rss_lut_size; i++)1802 adapter->rss_lut[i] = (u8)(rxfh->indir[i]);1803 }1804 1805 return iavf_config_rss(adapter);1806}1807 1808static const struct ethtool_ops iavf_ethtool_ops = {1809 .supported_coalesce_params = ETHTOOL_COALESCE_USECS |1810 ETHTOOL_COALESCE_USE_ADAPTIVE,1811 .cap_rss_sym_xor_supported = true,1812 .get_drvinfo = iavf_get_drvinfo,1813 .get_link = ethtool_op_get_link,1814 .get_ringparam = iavf_get_ringparam,1815 .set_ringparam = iavf_set_ringparam,1816 .get_strings = iavf_get_strings,1817 .get_ethtool_stats = iavf_get_ethtool_stats,1818 .get_sset_count = iavf_get_sset_count,1819 .get_msglevel = iavf_get_msglevel,1820 .set_msglevel = iavf_set_msglevel,1821 .get_coalesce = iavf_get_coalesce,1822 .set_coalesce = iavf_set_coalesce,1823 .get_per_queue_coalesce = iavf_get_per_queue_coalesce,1824 .set_per_queue_coalesce = iavf_set_per_queue_coalesce,1825 .set_rxnfc = iavf_set_rxnfc,1826 .get_rxnfc = iavf_get_rxnfc,1827 .get_rxfh_indir_size = iavf_get_rxfh_indir_size,1828 .get_rxfh = iavf_get_rxfh,1829 .set_rxfh = iavf_set_rxfh,1830 .get_channels = iavf_get_channels,1831 .set_channels = iavf_set_channels,1832 .get_rxfh_key_size = iavf_get_rxfh_key_size,1833 .get_link_ksettings = iavf_get_link_ksettings,1834};1835 1836/**1837 * iavf_set_ethtool_ops - Initialize ethtool ops struct1838 * @netdev: network interface device structure1839 *1840 * Sets ethtool ops struct in our netdev so that ethtool can call1841 * our functions.1842 **/1843void iavf_set_ethtool_ops(struct net_device *netdev)1844{1845 netdev->ethtool_ops = &iavf_ethtool_ops;1846}1847