Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gve: Add ethtool support

Add support for the following ethtool commands:

ethtool -s|--change devname [msglvl N] [msglevel type on|off]
ethtool -S|--statistics devname
ethtool -i|--driver devname
ethtool -l|--show-channels devname
ethtool -L|--set-channels devname
ethtool -g|--show-ring devname
ethtool --reset devname

Signed-off-by: Catherine Sullivan <csully@google.com>
Signed-off-by: Sagi Shahar <sagis@google.com>
Signed-off-by: Jon Olson <jonolson@google.com>
Acked-by: Willem de Bruijn <willemb@google.com>
Reviewed-by: Luigi Rizzo <lrizzo@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Catherine Sullivan and committed by
David S. Miller
e5b845dc 9e5f7d26

+288 -2
+1 -1
drivers/net/ethernet/google/gve/Makefile
··· 1 1 # Makefile for the Google virtual Ethernet (gve) driver 2 2 3 3 obj-$(CONFIG_GVE) += gve.o 4 - gve-objs := gve_main.o gve_tx.o gve_rx.o gve_adminq.o 4 + gve-objs := gve_main.o gve_tx.o gve_rx.o gve_ethtool.o gve_adminq.o
+4
drivers/net/ethernet/google/gve/gve.h
··· 452 452 int gve_adjust_queues(struct gve_priv *priv, 453 453 struct gve_queue_config new_rx_config, 454 454 struct gve_queue_config new_tx_config); 455 + /* exported by ethtool.c */ 456 + extern const struct ethtool_ops gve_ethtool_ops; 457 + /* needed by ethtool */ 458 + extern const char gve_version_str[]; 455 459 #endif /* _GVE_H_ */
+243
drivers/net/ethernet/google/gve/gve_ethtool.c
··· 1 + // SPDX-License-Identifier: (GPL-2.0 OR MIT) 2 + /* Google virtual Ethernet (gve) driver 3 + * 4 + * Copyright (C) 2015-2019 Google, Inc. 5 + */ 6 + 7 + #include <linux/rtnetlink.h> 8 + #include "gve.h" 9 + 10 + static void gve_get_drvinfo(struct net_device *netdev, 11 + struct ethtool_drvinfo *info) 12 + { 13 + struct gve_priv *priv = netdev_priv(netdev); 14 + 15 + strlcpy(info->driver, "gve", sizeof(info->driver)); 16 + strlcpy(info->version, gve_version_str, sizeof(info->version)); 17 + strlcpy(info->bus_info, pci_name(priv->pdev), sizeof(info->bus_info)); 18 + } 19 + 20 + static void gve_set_msglevel(struct net_device *netdev, u32 value) 21 + { 22 + struct gve_priv *priv = netdev_priv(netdev); 23 + 24 + priv->msg_enable = value; 25 + } 26 + 27 + static u32 gve_get_msglevel(struct net_device *netdev) 28 + { 29 + struct gve_priv *priv = netdev_priv(netdev); 30 + 31 + return priv->msg_enable; 32 + } 33 + 34 + static const char gve_gstrings_main_stats[][ETH_GSTRING_LEN] = { 35 + "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", 36 + "rx_dropped", "tx_dropped", "tx_timeouts", 37 + }; 38 + 39 + #define GVE_MAIN_STATS_LEN ARRAY_SIZE(gve_gstrings_main_stats) 40 + #define NUM_GVE_TX_CNTS 5 41 + #define NUM_GVE_RX_CNTS 2 42 + 43 + static void gve_get_strings(struct net_device *netdev, u32 stringset, u8 *data) 44 + { 45 + struct gve_priv *priv = netdev_priv(netdev); 46 + char *s = (char *)data; 47 + int i; 48 + 49 + if (stringset != ETH_SS_STATS) 50 + return; 51 + 52 + memcpy(s, *gve_gstrings_main_stats, 53 + sizeof(gve_gstrings_main_stats)); 54 + s += sizeof(gve_gstrings_main_stats); 55 + for (i = 0; i < priv->rx_cfg.num_queues; i++) { 56 + snprintf(s, ETH_GSTRING_LEN, "rx_desc_cnt[%u]", i); 57 + s += ETH_GSTRING_LEN; 58 + snprintf(s, ETH_GSTRING_LEN, "rx_desc_fill_cnt[%u]", i); 59 + s += ETH_GSTRING_LEN; 60 + } 61 + for (i = 0; i < priv->tx_cfg.num_queues; i++) { 62 + snprintf(s, ETH_GSTRING_LEN, "tx_req[%u]", i); 63 + s += ETH_GSTRING_LEN; 64 + snprintf(s, ETH_GSTRING_LEN, "tx_done[%u]", i); 65 + s += ETH_GSTRING_LEN; 66 + snprintf(s, ETH_GSTRING_LEN, "tx_wake[%u]", i); 67 + s += ETH_GSTRING_LEN; 68 + snprintf(s, ETH_GSTRING_LEN, "tx_stop[%u]", i); 69 + s += ETH_GSTRING_LEN; 70 + snprintf(s, ETH_GSTRING_LEN, "tx_event_counter[%u]", i); 71 + s += ETH_GSTRING_LEN; 72 + } 73 + } 74 + 75 + static int gve_get_sset_count(struct net_device *netdev, int sset) 76 + { 77 + struct gve_priv *priv = netdev_priv(netdev); 78 + 79 + switch (sset) { 80 + case ETH_SS_STATS: 81 + return GVE_MAIN_STATS_LEN + 82 + (priv->rx_cfg.num_queues * NUM_GVE_RX_CNTS) + 83 + (priv->tx_cfg.num_queues * NUM_GVE_TX_CNTS); 84 + default: 85 + return -EOPNOTSUPP; 86 + } 87 + } 88 + 89 + static void 90 + gve_get_ethtool_stats(struct net_device *netdev, 91 + struct ethtool_stats *stats, u64 *data) 92 + { 93 + struct gve_priv *priv = netdev_priv(netdev); 94 + u64 rx_pkts, rx_bytes, tx_pkts, tx_bytes; 95 + unsigned int start; 96 + int ring; 97 + int i; 98 + 99 + ASSERT_RTNL(); 100 + 101 + for (rx_pkts = 0, rx_bytes = 0, ring = 0; 102 + ring < priv->rx_cfg.num_queues; ring++) { 103 + if (priv->rx) { 104 + do { 105 + u64_stats_fetch_begin(&priv->rx[ring].statss); 106 + rx_pkts += priv->rx[ring].rpackets; 107 + rx_bytes += priv->rx[ring].rbytes; 108 + } while (u64_stats_fetch_retry(&priv->rx[ring].statss, 109 + start)); 110 + } 111 + } 112 + for (tx_pkts = 0, tx_bytes = 0, ring = 0; 113 + ring < priv->tx_cfg.num_queues; ring++) { 114 + if (priv->tx) { 115 + do { 116 + u64_stats_fetch_begin(&priv->tx[ring].statss); 117 + tx_pkts += priv->tx[ring].pkt_done; 118 + tx_bytes += priv->tx[ring].bytes_done; 119 + } while (u64_stats_fetch_retry(&priv->tx[ring].statss, 120 + start)); 121 + } 122 + } 123 + 124 + i = 0; 125 + data[i++] = rx_pkts; 126 + data[i++] = tx_pkts; 127 + data[i++] = rx_bytes; 128 + data[i++] = tx_bytes; 129 + /* Skip rx_dropped and tx_dropped */ 130 + i += 2; 131 + data[i++] = priv->tx_timeo_cnt; 132 + i = GVE_MAIN_STATS_LEN; 133 + 134 + /* walk RX rings */ 135 + if (priv->rx) { 136 + for (ring = 0; ring < priv->rx_cfg.num_queues; ring++) { 137 + struct gve_rx_ring *rx = &priv->rx[ring]; 138 + 139 + data[i++] = rx->desc.cnt; 140 + data[i++] = rx->desc.fill_cnt; 141 + } 142 + } else { 143 + i += priv->rx_cfg.num_queues * NUM_GVE_RX_CNTS; 144 + } 145 + /* walk TX rings */ 146 + if (priv->tx) { 147 + for (ring = 0; ring < priv->tx_cfg.num_queues; ring++) { 148 + struct gve_tx_ring *tx = &priv->tx[ring]; 149 + 150 + data[i++] = tx->req; 151 + data[i++] = tx->done; 152 + data[i++] = tx->wake_queue; 153 + data[i++] = tx->stop_queue; 154 + data[i++] = be32_to_cpu(gve_tx_load_event_counter(priv, 155 + tx)); 156 + } 157 + } else { 158 + i += priv->tx_cfg.num_queues * NUM_GVE_TX_CNTS; 159 + } 160 + } 161 + 162 + static void gve_get_channels(struct net_device *netdev, 163 + struct ethtool_channels *cmd) 164 + { 165 + struct gve_priv *priv = netdev_priv(netdev); 166 + 167 + cmd->max_rx = priv->rx_cfg.max_queues; 168 + cmd->max_tx = priv->tx_cfg.max_queues; 169 + cmd->max_other = 0; 170 + cmd->max_combined = 0; 171 + cmd->rx_count = priv->rx_cfg.num_queues; 172 + cmd->tx_count = priv->tx_cfg.num_queues; 173 + cmd->other_count = 0; 174 + cmd->combined_count = 0; 175 + } 176 + 177 + static int gve_set_channels(struct net_device *netdev, 178 + struct ethtool_channels *cmd) 179 + { 180 + struct gve_priv *priv = netdev_priv(netdev); 181 + struct gve_queue_config new_tx_cfg = priv->tx_cfg; 182 + struct gve_queue_config new_rx_cfg = priv->rx_cfg; 183 + struct ethtool_channels old_settings; 184 + int new_tx = cmd->tx_count; 185 + int new_rx = cmd->rx_count; 186 + 187 + gve_get_channels(netdev, &old_settings); 188 + 189 + /* Changing combined is not allowed allowed */ 190 + if (cmd->combined_count != old_settings.combined_count) 191 + return -EINVAL; 192 + 193 + if (!new_rx || !new_tx) 194 + return -EINVAL; 195 + 196 + if (!netif_carrier_ok(netdev)) { 197 + priv->tx_cfg.num_queues = new_tx; 198 + priv->rx_cfg.num_queues = new_rx; 199 + return 0; 200 + } 201 + 202 + new_tx_cfg.num_queues = new_tx; 203 + new_rx_cfg.num_queues = new_rx; 204 + 205 + return gve_adjust_queues(priv, new_rx_cfg, new_tx_cfg); 206 + } 207 + 208 + static void gve_get_ringparam(struct net_device *netdev, 209 + struct ethtool_ringparam *cmd) 210 + { 211 + struct gve_priv *priv = netdev_priv(netdev); 212 + 213 + cmd->rx_max_pending = priv->rx_desc_cnt; 214 + cmd->tx_max_pending = priv->tx_desc_cnt; 215 + cmd->rx_pending = priv->rx_desc_cnt; 216 + cmd->tx_pending = priv->tx_desc_cnt; 217 + } 218 + 219 + static int gve_user_reset(struct net_device *netdev, u32 *flags) 220 + { 221 + struct gve_priv *priv = netdev_priv(netdev); 222 + 223 + if (*flags == ETH_RESET_ALL) { 224 + *flags = 0; 225 + return gve_reset(priv, true); 226 + } 227 + 228 + return -EOPNOTSUPP; 229 + } 230 + 231 + const struct ethtool_ops gve_ethtool_ops = { 232 + .get_drvinfo = gve_get_drvinfo, 233 + .get_strings = gve_get_strings, 234 + .get_sset_count = gve_get_sset_count, 235 + .get_ethtool_stats = gve_get_ethtool_stats, 236 + .set_msglevel = gve_set_msglevel, 237 + .get_msglevel = gve_get_msglevel, 238 + .set_channels = gve_set_channels, 239 + .get_channels = gve_get_channels, 240 + .get_link = ethtool_op_get_link, 241 + .get_ringparam = gve_get_ringparam, 242 + .reset = gve_user_reset, 243 + };
+40 -1
drivers/net/ethernet/google/gve/gve_main.c
··· 23 23 #define GVE_VERSION "1.0.0" 24 24 #define GVE_VERSION_PREFIX "GVE-" 25 25 26 - static const char gve_version_str[] = GVE_VERSION; 26 + const char gve_version_str[] = GVE_VERSION; 27 27 static const char gve_version_prefix[] = GVE_VERSION_PREFIX; 28 28 29 29 static void gve_get_stats(struct net_device *dev, struct rtnl_link_stats64 *s) ··· 746 746 return gve_reset_recovery(priv, false); 747 747 } 748 748 749 + int gve_adjust_queues(struct gve_priv *priv, 750 + struct gve_queue_config new_rx_config, 751 + struct gve_queue_config new_tx_config) 752 + { 753 + int err; 754 + 755 + if (netif_carrier_ok(priv->dev)) { 756 + /* To make this process as simple as possible we teardown the 757 + * device, set the new configuration, and then bring the device 758 + * up again. 759 + */ 760 + err = gve_close(priv->dev); 761 + /* we have already tried to reset in close, 762 + * just fail at this point 763 + */ 764 + if (err) 765 + return err; 766 + priv->tx_cfg = new_tx_config; 767 + priv->rx_cfg = new_rx_config; 768 + 769 + err = gve_open(priv->dev); 770 + if (err) 771 + goto err; 772 + 773 + return 0; 774 + } 775 + /* Set the config for the next up. */ 776 + priv->tx_cfg = new_tx_config; 777 + priv->rx_cfg = new_rx_config; 778 + 779 + return 0; 780 + err: 781 + netif_err(priv, drv, priv->dev, 782 + "Adjust queues failed! !!! DISABLING ALL QUEUES !!!\n"); 783 + gve_turndown(priv); 784 + return err; 785 + } 786 + 749 787 static void gve_turndown(struct gve_priv *priv) 750 788 { 751 789 int idx; ··· 1120 1082 } 1121 1083 SET_NETDEV_DEV(dev, &pdev->dev); 1122 1084 pci_set_drvdata(pdev, dev); 1085 + dev->ethtool_ops = &gve_ethtool_ops; 1123 1086 dev->netdev_ops = &gve_netdev_ops; 1124 1087 /* advertise features */ 1125 1088 dev->hw_features = NETIF_F_HIGHDMA;