diff options
Diffstat (limited to 'drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c')
| -rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c | 262 |
1 files changed, 113 insertions, 149 deletions
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c b/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c index c7234f35f8ff..76e42abca965 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c @@ -1,39 +1,33 @@ -/* Intel(R) Ethernet Switch Host Interface Driver - * Copyright(c) 2013 - 2017 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * The full GNU General Public License is included in this distribution in - * the file called "COPYING". - * - * Contact Information: - * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - */ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2013 - 2019 Intel Corporation. */ +#include <linux/ethtool.h> #include <linux/vmalloc.h> #include "fm10k.h" struct fm10k_stats { + /* The stat_string is expected to be a format string formatted using + * vsnprintf by fm10k_add_stat_strings. Every member of a stats array + * should use the same format specifiers as they will be formatted + * using the same variadic arguments. + */ char stat_string[ETH_GSTRING_LEN]; int sizeof_stat; int stat_offset; }; -#define FM10K_NETDEV_STAT(_net_stat) { \ - .stat_string = #_net_stat, \ - .sizeof_stat = FIELD_SIZEOF(struct net_device_stats, _net_stat), \ - .stat_offset = offsetof(struct net_device_stats, _net_stat) \ +#define FM10K_STAT_FIELDS(_type, _name, _stat) { \ + .stat_string = _name, \ + .sizeof_stat = sizeof_field(_type, _stat), \ + .stat_offset = offsetof(_type, _stat) \ } +/* netdevice statistics */ +#define FM10K_NETDEV_STAT(_net_stat) \ + FM10K_STAT_FIELDS(struct net_device_stats, __stringify(_net_stat), \ + _net_stat) + static const struct fm10k_stats fm10k_gstrings_net_stats[] = { FM10K_NETDEV_STAT(tx_packets), FM10K_NETDEV_STAT(tx_bytes), @@ -51,11 +45,9 @@ static const struct fm10k_stats fm10k_gstrings_net_stats[] = { #define FM10K_NETDEV_STATS_LEN ARRAY_SIZE(fm10k_gstrings_net_stats) -#define FM10K_STAT(_name, _stat) { \ - .stat_string = _name, \ - .sizeof_stat = FIELD_SIZEOF(struct fm10k_intfc, _stat), \ - .stat_offset = offsetof(struct fm10k_intfc, _stat) \ -} +/* General interface statistics */ +#define FM10K_STAT(_name, _stat) \ + FM10K_STAT_FIELDS(struct fm10k_intfc, _name, _stat) static const struct fm10k_stats fm10k_gstrings_global_stats[] = { FM10K_STAT("tx_restart_queue", restart_queue), @@ -92,11 +84,9 @@ static const struct fm10k_stats fm10k_gstrings_pf_stats[] = { FM10K_STAT("nodesc_drop", stats.nodesc_drop.count), }; -#define FM10K_MBX_STAT(_name, _stat) { \ - .stat_string = _name, \ - .sizeof_stat = FIELD_SIZEOF(struct fm10k_mbx_info, _stat), \ - .stat_offset = offsetof(struct fm10k_mbx_info, _stat) \ -} +/* mailbox statistics */ +#define FM10K_MBX_STAT(_name, _stat) \ + FM10K_STAT_FIELDS(struct fm10k_mbx_info, _name, _stat) static const struct fm10k_stats fm10k_gstrings_mbx_stats[] = { FM10K_MBX_STAT("mbx_tx_busy", tx_busy), @@ -110,15 +100,13 @@ static const struct fm10k_stats fm10k_gstrings_mbx_stats[] = { FM10K_MBX_STAT("mbx_rx_mbmem_pushed", rx_mbmem_pushed), }; -#define FM10K_QUEUE_STAT(_name, _stat) { \ - .stat_string = _name, \ - .sizeof_stat = FIELD_SIZEOF(struct fm10k_ring, _stat), \ - .stat_offset = offsetof(struct fm10k_ring, _stat) \ -} +/* per-queue ring statistics */ +#define FM10K_QUEUE_STAT(_name, _stat) \ + FM10K_STAT_FIELDS(struct fm10k_ring, _name, _stat) static const struct fm10k_stats fm10k_gstrings_queue_stats[] = { - FM10K_QUEUE_STAT("packets", stats.packets), - FM10K_QUEUE_STAT("bytes", stats.bytes), + FM10K_QUEUE_STAT("%s_queue_%u_packets", stats.packets), + FM10K_QUEUE_STAT("%s_queue_%u_bytes", stats.bytes), }; #define FM10K_GLOBAL_STATS_LEN ARRAY_SIZE(fm10k_gstrings_global_stats) @@ -148,49 +136,44 @@ enum { static const char fm10k_prv_flags[FM10K_PRV_FLAG_LEN][ETH_GSTRING_LEN] = { }; -static void fm10k_add_stat_strings(u8 **p, const char *prefix, - const struct fm10k_stats stats[], - const unsigned int size) +static void __fm10k_add_stat_strings(u8 **p, const struct fm10k_stats stats[], + const unsigned int size, ...) { unsigned int i; for (i = 0; i < size; i++) { - snprintf(*p, ETH_GSTRING_LEN, "%s%s", - prefix, stats[i].stat_string); + va_list args; + + va_start(args, size); + vsnprintf(*p, ETH_GSTRING_LEN, stats[i].stat_string, args); *p += ETH_GSTRING_LEN; + va_end(args); } } +#define fm10k_add_stat_strings(p, stats, ...) \ + __fm10k_add_stat_strings(p, stats, ARRAY_SIZE(stats), ## __VA_ARGS__) + static void fm10k_get_stat_strings(struct net_device *dev, u8 *data) { struct fm10k_intfc *interface = netdev_priv(dev); unsigned int i; - fm10k_add_stat_strings(&data, "", fm10k_gstrings_net_stats, - FM10K_NETDEV_STATS_LEN); + fm10k_add_stat_strings(&data, fm10k_gstrings_net_stats); - fm10k_add_stat_strings(&data, "", fm10k_gstrings_global_stats, - FM10K_GLOBAL_STATS_LEN); + fm10k_add_stat_strings(&data, fm10k_gstrings_global_stats); - fm10k_add_stat_strings(&data, "", fm10k_gstrings_mbx_stats, - FM10K_MBX_STATS_LEN); + fm10k_add_stat_strings(&data, fm10k_gstrings_mbx_stats); if (interface->hw.mac.type != fm10k_mac_vf) - fm10k_add_stat_strings(&data, "", fm10k_gstrings_pf_stats, - FM10K_PF_STATS_LEN); + fm10k_add_stat_strings(&data, fm10k_gstrings_pf_stats); for (i = 0; i < interface->hw.mac.max_queues; i++) { - char prefix[ETH_GSTRING_LEN]; - - snprintf(prefix, ETH_GSTRING_LEN, "tx_queue_%u_", i); - fm10k_add_stat_strings(&data, prefix, - fm10k_gstrings_queue_stats, - FM10K_QUEUE_STATS_LEN); + fm10k_add_stat_strings(&data, fm10k_gstrings_queue_stats, + "tx", i); - snprintf(prefix, ETH_GSTRING_LEN, "rx_queue_%u_", i); - fm10k_add_stat_strings(&data, prefix, - fm10k_gstrings_queue_stats, - FM10K_QUEUE_STATS_LEN); + fm10k_add_stat_strings(&data, fm10k_gstrings_queue_stats, + "rx", i); } } @@ -235,12 +218,11 @@ static int fm10k_get_sset_count(struct net_device *dev, int sset) } } -static void fm10k_add_ethtool_stats(u64 **data, void *pointer, - const struct fm10k_stats stats[], - const unsigned int size) +static void __fm10k_add_ethtool_stats(u64 **data, void *pointer, + const struct fm10k_stats stats[], + const unsigned int size) { unsigned int i; - char *p; if (!pointer) { /* memory is not zero allocated so we have to clear it */ @@ -250,7 +232,7 @@ static void fm10k_add_ethtool_stats(u64 **data, void *pointer, } for (i = 0; i < size; i++) { - p = (char *)pointer + stats[i].stat_offset; + char *p = (char *)pointer + stats[i].stat_offset; switch (stats[i].sizeof_stat) { case sizeof(u64): @@ -266,11 +248,16 @@ static void fm10k_add_ethtool_stats(u64 **data, void *pointer, *((*data)++) = *(u8 *)p; break; default: + WARN_ONCE(1, "unexpected stat size for %s", + stats[i].stat_string); *((*data)++) = 0; } } } +#define fm10k_add_ethtool_stats(data, pointer, stats) \ + __fm10k_add_ethtool_stats(data, pointer, stats, ARRAY_SIZE(stats)) + static void fm10k_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats __always_unused *stats, u64 *data) @@ -281,20 +268,16 @@ static void fm10k_get_ethtool_stats(struct net_device *netdev, fm10k_update_stats(interface); - fm10k_add_ethtool_stats(&data, net_stats, fm10k_gstrings_net_stats, - FM10K_NETDEV_STATS_LEN); + fm10k_add_ethtool_stats(&data, net_stats, fm10k_gstrings_net_stats); - fm10k_add_ethtool_stats(&data, interface, fm10k_gstrings_global_stats, - FM10K_GLOBAL_STATS_LEN); + fm10k_add_ethtool_stats(&data, interface, fm10k_gstrings_global_stats); fm10k_add_ethtool_stats(&data, &interface->hw.mbx, - fm10k_gstrings_mbx_stats, - FM10K_MBX_STATS_LEN); + fm10k_gstrings_mbx_stats); if (interface->hw.mac.type != fm10k_mac_vf) { fm10k_add_ethtool_stats(&data, interface, - fm10k_gstrings_pf_stats, - FM10K_PF_STATS_LEN); + fm10k_gstrings_pf_stats); } for (i = 0; i < interface->hw.mac.max_queues; i++) { @@ -302,13 +285,11 @@ static void fm10k_get_ethtool_stats(struct net_device *netdev, ring = interface->tx_ring[i]; fm10k_add_ethtool_stats(&data, ring, - fm10k_gstrings_queue_stats, - FM10K_QUEUE_STATS_LEN); + fm10k_gstrings_queue_stats); ring = interface->rx_ring[i]; fm10k_add_ethtool_stats(&data, ring, - fm10k_gstrings_queue_stats, - FM10K_QUEUE_STATS_LEN); + fm10k_gstrings_queue_stats); } } @@ -467,12 +448,10 @@ static void fm10k_get_drvinfo(struct net_device *dev, { struct fm10k_intfc *interface = netdev_priv(dev); - strncpy(info->driver, fm10k_driver_name, - sizeof(info->driver) - 1); - strncpy(info->version, fm10k_driver_version, - sizeof(info->version) - 1); - strncpy(info->bus_info, pci_name(interface->pdev), - sizeof(info->bus_info) - 1); + strscpy(info->driver, fm10k_driver_name, + sizeof(info->driver)); + strscpy(info->bus_info, pci_name(interface->pdev), + sizeof(info->bus_info)); } static void fm10k_get_pauseparam(struct net_device *dev, @@ -523,7 +502,9 @@ static void fm10k_set_msglevel(struct net_device *netdev, u32 data) } static void fm10k_get_ringparam(struct net_device *netdev, - struct ethtool_ringparam *ring) + struct ethtool_ringparam *ring, + struct kernel_ethtool_ringparam *kernel_ring, + struct netlink_ext_ack *extack) { struct fm10k_intfc *interface = netdev_priv(netdev); @@ -538,7 +519,9 @@ static void fm10k_get_ringparam(struct net_device *netdev, } static int fm10k_set_ringparam(struct net_device *netdev, - struct ethtool_ringparam *ring) + struct ethtool_ringparam *ring, + struct kernel_ethtool_ringparam *kernel_ring, + struct netlink_ext_ack *extack) { struct fm10k_intfc *interface = netdev_priv(netdev); struct fm10k_ring *temp_ring; @@ -577,7 +560,7 @@ static int fm10k_set_ringparam(struct net_device *netdev, /* allocate temporary buffer to store rings in */ i = max_t(int, interface->num_tx_queues, interface->num_rx_queues); - temp_ring = vmalloc(i * sizeof(struct fm10k_ring)); + temp_ring = vmalloc_array(i, sizeof(struct fm10k_ring)); if (!temp_ring) { err = -ENOMEM; @@ -653,7 +636,9 @@ clear_reset: } static int fm10k_get_coalesce(struct net_device *dev, - struct ethtool_coalesce *ec) + struct ethtool_coalesce *ec, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) { struct fm10k_intfc *interface = netdev_priv(dev); @@ -667,10 +652,11 @@ static int fm10k_get_coalesce(struct net_device *dev, } static int fm10k_set_coalesce(struct net_device *dev, - struct ethtool_coalesce *ec) + struct ethtool_coalesce *ec, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) { struct fm10k_intfc *interface = netdev_priv(dev); - struct fm10k_q_vector *qv; u16 tx_itr, rx_itr; int i; @@ -696,7 +682,8 @@ static int fm10k_set_coalesce(struct net_device *dev, /* update q_vectors */ for (i = 0; i < interface->num_q_vectors; i++) { - qv = interface->q_vector[i]; + struct fm10k_q_vector *qv = interface->q_vector[i]; + qv->tx.itr = tx_itr; qv->rx.itr = rx_itr; } @@ -704,9 +691,11 @@ static int fm10k_set_coalesce(struct net_device *dev, return 0; } -static int fm10k_get_rss_hash_opts(struct fm10k_intfc *interface, - struct ethtool_rxnfc *cmd) +static int fm10k_get_rssh_fields(struct net_device *dev, + struct ethtool_rxfh_fields *cmd) { + struct fm10k_intfc *interface = netdev_priv(dev); + cmd->data = 0; /* Report default options for RSS on fm10k */ @@ -714,12 +703,12 @@ static int fm10k_get_rss_hash_opts(struct fm10k_intfc *interface, case TCP_V4_FLOW: case TCP_V6_FLOW: cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; - /* fall through */ + fallthrough; case UDP_V4_FLOW: if (test_bit(FM10K_FLAG_RSS_FIELD_IPV4_UDP, interface->flags)) cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; - /* fall through */ + fallthrough; case SCTP_V4_FLOW: case SCTP_V6_FLOW: case AH_ESP_V4_FLOW: @@ -745,30 +734,18 @@ static int fm10k_get_rss_hash_opts(struct fm10k_intfc *interface, return 0; } -static int fm10k_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, - u32 __always_unused *rule_locs) +static u32 fm10k_get_rx_ring_count(struct net_device *dev) { struct fm10k_intfc *interface = netdev_priv(dev); - int ret = -EOPNOTSUPP; - - switch (cmd->cmd) { - case ETHTOOL_GRXRINGS: - cmd->data = interface->num_rx_queues; - ret = 0; - break; - case ETHTOOL_GRXFH: - ret = fm10k_get_rss_hash_opts(interface, cmd); - break; - default: - break; - } - return ret; + return interface->num_rx_queues; } -static int fm10k_set_rss_hash_opt(struct fm10k_intfc *interface, - struct ethtool_rxnfc *nfc) +static int fm10k_set_rssh_fields(struct net_device *dev, + const struct ethtool_rxfh_fields *nfc, + struct netlink_ext_ack *extack) { + struct fm10k_intfc *interface = netdev_priv(dev); int rss_ipv4_udp = test_bit(FM10K_FLAG_RSS_FIELD_IPV4_UDP, interface->flags); int rss_ipv6_udp = test_bit(FM10K_FLAG_RSS_FIELD_IPV6_UDP, @@ -884,22 +861,6 @@ static int fm10k_set_rss_hash_opt(struct fm10k_intfc *interface, return 0; } -static int fm10k_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) -{ - struct fm10k_intfc *interface = netdev_priv(dev); - int ret = -EOPNOTSUPP; - - switch (cmd->cmd) { - case ETHTOOL_SRXFH: - ret = fm10k_set_rss_hash_opt(interface, cmd); - break; - default: - break; - } - - return ret; -} - static int fm10k_mbx_test(struct fm10k_intfc *interface, u64 *data) { struct fm10k_hw *hw = &interface->hw; @@ -1070,16 +1031,16 @@ static u32 fm10k_get_rssrk_size(struct net_device __always_unused *netdev) return FM10K_RSSRK_SIZE * FM10K_RSSRK_ENTRIES_PER_REG; } -static int fm10k_get_rssh(struct net_device *netdev, u32 *indir, u8 *key, - u8 *hfunc) +static int fm10k_get_rssh(struct net_device *netdev, + struct ethtool_rxfh_param *rxfh) { struct fm10k_intfc *interface = netdev_priv(netdev); + u8 *key = rxfh->key; int i, err; - if (hfunc) - *hfunc = ETH_RSS_HASH_TOP; + rxfh->hfunc = ETH_RSS_HASH_TOP; - err = fm10k_get_reta(netdev, indir); + err = fm10k_get_reta(netdev, rxfh->indir); if (err || !key) return err; @@ -1089,23 +1050,25 @@ static int fm10k_get_rssh(struct net_device *netdev, u32 *indir, u8 *key, return 0; } -static int fm10k_set_rssh(struct net_device *netdev, const u32 *indir, - const u8 *key, const u8 hfunc) +static int fm10k_set_rssh(struct net_device *netdev, + struct ethtool_rxfh_param *rxfh, + struct netlink_ext_ack *extack) { struct fm10k_intfc *interface = netdev_priv(netdev); struct fm10k_hw *hw = &interface->hw; int i, err; /* We do not allow change in unsupported parameters */ - if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) + if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE && + rxfh->hfunc != ETH_RSS_HASH_TOP) return -EOPNOTSUPP; - err = fm10k_set_reta(netdev, indir); - if (err || !key) + err = fm10k_set_reta(netdev, rxfh->indir); + if (err || !rxfh->key) return err; - for (i = 0; i < FM10K_RSSRK_SIZE; i++, key += 4) { - u32 rssrk = le32_to_cpu(*(__le32 *)key); + for (i = 0; i < FM10K_RSSRK_SIZE; i++, rxfh->key += 4) { + u32 rssrk = le32_to_cpu(*(__le32 *)rxfh->key); if (interface->rssrk[i] == rssrk) continue; @@ -1134,13 +1097,12 @@ static void fm10k_get_channels(struct net_device *dev, struct ethtool_channels *ch) { struct fm10k_intfc *interface = netdev_priv(dev); - struct fm10k_hw *hw = &interface->hw; /* report maximum channels */ ch->max_combined = fm10k_max_channels(dev); /* report info for other vector */ - ch->max_other = NON_Q_VECTORS(hw); + ch->max_other = NON_Q_VECTORS; ch->other_count = ch->max_other; /* record RSS queues */ @@ -1152,14 +1114,13 @@ static int fm10k_set_channels(struct net_device *dev, { struct fm10k_intfc *interface = netdev_priv(dev); unsigned int count = ch->combined_count; - struct fm10k_hw *hw = &interface->hw; /* verify they are not requesting separate vectors */ if (!count || ch->rx_count || ch->tx_count) return -EINVAL; /* verify other_count has not changed */ - if (ch->other_count != NON_Q_VECTORS(hw)) + if (ch->other_count != NON_Q_VECTORS) return -EINVAL; /* verify the number of channels does not exceed hardware limits */ @@ -1173,6 +1134,8 @@ static int fm10k_set_channels(struct net_device *dev, } static const struct ethtool_ops fm10k_ethtool_ops = { + .supported_coalesce_params = ETHTOOL_COALESCE_USECS | + ETHTOOL_COALESCE_USE_ADAPTIVE, .get_strings = fm10k_get_strings, .get_sset_count = fm10k_get_sset_count, .get_ethtool_stats = fm10k_get_ethtool_stats, @@ -1186,8 +1149,7 @@ static const struct ethtool_ops fm10k_ethtool_ops = { .set_ringparam = fm10k_set_ringparam, .get_coalesce = fm10k_get_coalesce, .set_coalesce = fm10k_set_coalesce, - .get_rxnfc = fm10k_get_rxnfc, - .set_rxnfc = fm10k_set_rxnfc, + .get_rx_ring_count = fm10k_get_rx_ring_count, .get_regs = fm10k_get_regs, .get_regs_len = fm10k_get_regs_len, .self_test = fm10k_self_test, @@ -1197,6 +1159,8 @@ static const struct ethtool_ops fm10k_ethtool_ops = { .get_rxfh_key_size = fm10k_get_rssrk_size, .get_rxfh = fm10k_get_rssh, .set_rxfh = fm10k_set_rssh, + .get_rxfh_fields = fm10k_get_rssh_fields, + .set_rxfh_fields = fm10k_set_rssh_fields, .get_channels = fm10k_get_channels, .set_channels = fm10k_set_channels, .get_ts_info = ethtool_op_get_ts_info, |
