1e5b845dcSCatherine Sullivan // SPDX-License-Identifier: (GPL-2.0 OR MIT) 2e5b845dcSCatherine Sullivan /* Google virtual Ethernet (gve) driver 3e5b845dcSCatherine Sullivan * 4e5b845dcSCatherine Sullivan * Copyright (C) 2015-2019 Google, Inc. 5e5b845dcSCatherine Sullivan */ 6e5b845dcSCatherine Sullivan 7e5b845dcSCatherine Sullivan #include <linux/rtnetlink.h> 8e5b845dcSCatherine Sullivan #include "gve.h" 9e5b845dcSCatherine Sullivan 10e5b845dcSCatherine Sullivan static void gve_get_drvinfo(struct net_device *netdev, 11e5b845dcSCatherine Sullivan struct ethtool_drvinfo *info) 12e5b845dcSCatherine Sullivan { 13e5b845dcSCatherine Sullivan struct gve_priv *priv = netdev_priv(netdev); 14e5b845dcSCatherine Sullivan 15e5b845dcSCatherine Sullivan strlcpy(info->driver, "gve", sizeof(info->driver)); 16e5b845dcSCatherine Sullivan strlcpy(info->version, gve_version_str, sizeof(info->version)); 17e5b845dcSCatherine Sullivan strlcpy(info->bus_info, pci_name(priv->pdev), sizeof(info->bus_info)); 18e5b845dcSCatherine Sullivan } 19e5b845dcSCatherine Sullivan 20e5b845dcSCatherine Sullivan static void gve_set_msglevel(struct net_device *netdev, u32 value) 21e5b845dcSCatherine Sullivan { 22e5b845dcSCatherine Sullivan struct gve_priv *priv = netdev_priv(netdev); 23e5b845dcSCatherine Sullivan 24e5b845dcSCatherine Sullivan priv->msg_enable = value; 25e5b845dcSCatherine Sullivan } 26e5b845dcSCatherine Sullivan 27e5b845dcSCatherine Sullivan static u32 gve_get_msglevel(struct net_device *netdev) 28e5b845dcSCatherine Sullivan { 29e5b845dcSCatherine Sullivan struct gve_priv *priv = netdev_priv(netdev); 30e5b845dcSCatherine Sullivan 31e5b845dcSCatherine Sullivan return priv->msg_enable; 32e5b845dcSCatherine Sullivan } 33e5b845dcSCatherine Sullivan 34e5b845dcSCatherine Sullivan static const char gve_gstrings_main_stats[][ETH_GSTRING_LEN] = { 35e5b845dcSCatherine Sullivan "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", 36e5b845dcSCatherine Sullivan "rx_dropped", "tx_dropped", "tx_timeouts", 37e5b845dcSCatherine Sullivan }; 38e5b845dcSCatherine Sullivan 39e5b845dcSCatherine Sullivan #define GVE_MAIN_STATS_LEN ARRAY_SIZE(gve_gstrings_main_stats) 40e5b845dcSCatherine Sullivan #define NUM_GVE_TX_CNTS 5 41e5b845dcSCatherine Sullivan #define NUM_GVE_RX_CNTS 2 42e5b845dcSCatherine Sullivan 43e5b845dcSCatherine Sullivan static void gve_get_strings(struct net_device *netdev, u32 stringset, u8 *data) 44e5b845dcSCatherine Sullivan { 45e5b845dcSCatherine Sullivan struct gve_priv *priv = netdev_priv(netdev); 46e5b845dcSCatherine Sullivan char *s = (char *)data; 47e5b845dcSCatherine Sullivan int i; 48e5b845dcSCatherine Sullivan 49e5b845dcSCatherine Sullivan if (stringset != ETH_SS_STATS) 50e5b845dcSCatherine Sullivan return; 51e5b845dcSCatherine Sullivan 52e5b845dcSCatherine Sullivan memcpy(s, *gve_gstrings_main_stats, 53e5b845dcSCatherine Sullivan sizeof(gve_gstrings_main_stats)); 54e5b845dcSCatherine Sullivan s += sizeof(gve_gstrings_main_stats); 55e5b845dcSCatherine Sullivan for (i = 0; i < priv->rx_cfg.num_queues; i++) { 56e5b845dcSCatherine Sullivan snprintf(s, ETH_GSTRING_LEN, "rx_desc_cnt[%u]", i); 57e5b845dcSCatherine Sullivan s += ETH_GSTRING_LEN; 58e5b845dcSCatherine Sullivan snprintf(s, ETH_GSTRING_LEN, "rx_desc_fill_cnt[%u]", i); 59e5b845dcSCatherine Sullivan s += ETH_GSTRING_LEN; 60e5b845dcSCatherine Sullivan } 61e5b845dcSCatherine Sullivan for (i = 0; i < priv->tx_cfg.num_queues; i++) { 62e5b845dcSCatherine Sullivan snprintf(s, ETH_GSTRING_LEN, "tx_req[%u]", i); 63e5b845dcSCatherine Sullivan s += ETH_GSTRING_LEN; 64e5b845dcSCatherine Sullivan snprintf(s, ETH_GSTRING_LEN, "tx_done[%u]", i); 65e5b845dcSCatherine Sullivan s += ETH_GSTRING_LEN; 66e5b845dcSCatherine Sullivan snprintf(s, ETH_GSTRING_LEN, "tx_wake[%u]", i); 67e5b845dcSCatherine Sullivan s += ETH_GSTRING_LEN; 68e5b845dcSCatherine Sullivan snprintf(s, ETH_GSTRING_LEN, "tx_stop[%u]", i); 69e5b845dcSCatherine Sullivan s += ETH_GSTRING_LEN; 70e5b845dcSCatherine Sullivan snprintf(s, ETH_GSTRING_LEN, "tx_event_counter[%u]", i); 71e5b845dcSCatherine Sullivan s += ETH_GSTRING_LEN; 72e5b845dcSCatherine Sullivan } 73e5b845dcSCatherine Sullivan } 74e5b845dcSCatherine Sullivan 75e5b845dcSCatherine Sullivan static int gve_get_sset_count(struct net_device *netdev, int sset) 76e5b845dcSCatherine Sullivan { 77e5b845dcSCatherine Sullivan struct gve_priv *priv = netdev_priv(netdev); 78e5b845dcSCatherine Sullivan 79e5b845dcSCatherine Sullivan switch (sset) { 80e5b845dcSCatherine Sullivan case ETH_SS_STATS: 81e5b845dcSCatherine Sullivan return GVE_MAIN_STATS_LEN + 82e5b845dcSCatherine Sullivan (priv->rx_cfg.num_queues * NUM_GVE_RX_CNTS) + 83e5b845dcSCatherine Sullivan (priv->tx_cfg.num_queues * NUM_GVE_TX_CNTS); 84e5b845dcSCatherine Sullivan default: 85e5b845dcSCatherine Sullivan return -EOPNOTSUPP; 86e5b845dcSCatherine Sullivan } 87e5b845dcSCatherine Sullivan } 88e5b845dcSCatherine Sullivan 89e5b845dcSCatherine Sullivan static void 90e5b845dcSCatherine Sullivan gve_get_ethtool_stats(struct net_device *netdev, 91e5b845dcSCatherine Sullivan struct ethtool_stats *stats, u64 *data) 92e5b845dcSCatherine Sullivan { 93e5b845dcSCatherine Sullivan struct gve_priv *priv = netdev_priv(netdev); 94e5b845dcSCatherine Sullivan u64 rx_pkts, rx_bytes, tx_pkts, tx_bytes; 95e5b845dcSCatherine Sullivan unsigned int start; 96e5b845dcSCatherine Sullivan int ring; 97e5b845dcSCatherine Sullivan int i; 98e5b845dcSCatherine Sullivan 99e5b845dcSCatherine Sullivan ASSERT_RTNL(); 100e5b845dcSCatherine Sullivan 101e5b845dcSCatherine Sullivan for (rx_pkts = 0, rx_bytes = 0, ring = 0; 102e5b845dcSCatherine Sullivan ring < priv->rx_cfg.num_queues; ring++) { 103e5b845dcSCatherine Sullivan if (priv->rx) { 104e5b845dcSCatherine Sullivan do { 1053c13ce74SCatherine Sullivan start = 106e5b845dcSCatherine Sullivan u64_stats_fetch_begin(&priv->rx[ring].statss); 107e5b845dcSCatherine Sullivan rx_pkts += priv->rx[ring].rpackets; 108e5b845dcSCatherine Sullivan rx_bytes += priv->rx[ring].rbytes; 109e5b845dcSCatherine Sullivan } while (u64_stats_fetch_retry(&priv->rx[ring].statss, 110e5b845dcSCatherine Sullivan start)); 111e5b845dcSCatherine Sullivan } 112e5b845dcSCatherine Sullivan } 113e5b845dcSCatherine Sullivan for (tx_pkts = 0, tx_bytes = 0, ring = 0; 114e5b845dcSCatherine Sullivan ring < priv->tx_cfg.num_queues; ring++) { 115e5b845dcSCatherine Sullivan if (priv->tx) { 116e5b845dcSCatherine Sullivan do { 1173c13ce74SCatherine Sullivan start = 118e5b845dcSCatherine Sullivan u64_stats_fetch_begin(&priv->tx[ring].statss); 119e5b845dcSCatherine Sullivan tx_pkts += priv->tx[ring].pkt_done; 120e5b845dcSCatherine Sullivan tx_bytes += priv->tx[ring].bytes_done; 121e5b845dcSCatherine Sullivan } while (u64_stats_fetch_retry(&priv->tx[ring].statss, 122e5b845dcSCatherine Sullivan start)); 123e5b845dcSCatherine Sullivan } 124e5b845dcSCatherine Sullivan } 125e5b845dcSCatherine Sullivan 126e5b845dcSCatherine Sullivan i = 0; 127e5b845dcSCatherine Sullivan data[i++] = rx_pkts; 128e5b845dcSCatherine Sullivan data[i++] = tx_pkts; 129e5b845dcSCatherine Sullivan data[i++] = rx_bytes; 130e5b845dcSCatherine Sullivan data[i++] = tx_bytes; 131e5b845dcSCatherine Sullivan /* Skip rx_dropped and tx_dropped */ 132e5b845dcSCatherine Sullivan i += 2; 133e5b845dcSCatherine Sullivan data[i++] = priv->tx_timeo_cnt; 134e5b845dcSCatherine Sullivan i = GVE_MAIN_STATS_LEN; 135e5b845dcSCatherine Sullivan 136e5b845dcSCatherine Sullivan /* walk RX rings */ 137e5b845dcSCatherine Sullivan if (priv->rx) { 138e5b845dcSCatherine Sullivan for (ring = 0; ring < priv->rx_cfg.num_queues; ring++) { 139e5b845dcSCatherine Sullivan struct gve_rx_ring *rx = &priv->rx[ring]; 140e5b845dcSCatherine Sullivan 141e5b845dcSCatherine Sullivan data[i++] = rx->desc.cnt; 142e5b845dcSCatherine Sullivan data[i++] = rx->desc.fill_cnt; 143e5b845dcSCatherine Sullivan } 144e5b845dcSCatherine Sullivan } else { 145e5b845dcSCatherine Sullivan i += priv->rx_cfg.num_queues * NUM_GVE_RX_CNTS; 146e5b845dcSCatherine Sullivan } 147e5b845dcSCatherine Sullivan /* walk TX rings */ 148e5b845dcSCatherine Sullivan if (priv->tx) { 149e5b845dcSCatherine Sullivan for (ring = 0; ring < priv->tx_cfg.num_queues; ring++) { 150e5b845dcSCatherine Sullivan struct gve_tx_ring *tx = &priv->tx[ring]; 151e5b845dcSCatherine Sullivan 152e5b845dcSCatherine Sullivan data[i++] = tx->req; 153e5b845dcSCatherine Sullivan data[i++] = tx->done; 154e5b845dcSCatherine Sullivan data[i++] = tx->wake_queue; 155e5b845dcSCatherine Sullivan data[i++] = tx->stop_queue; 156e5b845dcSCatherine Sullivan data[i++] = be32_to_cpu(gve_tx_load_event_counter(priv, 157e5b845dcSCatherine Sullivan tx)); 158e5b845dcSCatherine Sullivan } 159e5b845dcSCatherine Sullivan } else { 160e5b845dcSCatherine Sullivan i += priv->tx_cfg.num_queues * NUM_GVE_TX_CNTS; 161e5b845dcSCatherine Sullivan } 162e5b845dcSCatherine Sullivan } 163e5b845dcSCatherine Sullivan 164e5b845dcSCatherine Sullivan static void gve_get_channels(struct net_device *netdev, 165e5b845dcSCatherine Sullivan struct ethtool_channels *cmd) 166e5b845dcSCatherine Sullivan { 167e5b845dcSCatherine Sullivan struct gve_priv *priv = netdev_priv(netdev); 168e5b845dcSCatherine Sullivan 169e5b845dcSCatherine Sullivan cmd->max_rx = priv->rx_cfg.max_queues; 170e5b845dcSCatherine Sullivan cmd->max_tx = priv->tx_cfg.max_queues; 171e5b845dcSCatherine Sullivan cmd->max_other = 0; 172e5b845dcSCatherine Sullivan cmd->max_combined = 0; 173e5b845dcSCatherine Sullivan cmd->rx_count = priv->rx_cfg.num_queues; 174e5b845dcSCatherine Sullivan cmd->tx_count = priv->tx_cfg.num_queues; 175e5b845dcSCatherine Sullivan cmd->other_count = 0; 176e5b845dcSCatherine Sullivan cmd->combined_count = 0; 177e5b845dcSCatherine Sullivan } 178e5b845dcSCatherine Sullivan 179e5b845dcSCatherine Sullivan static int gve_set_channels(struct net_device *netdev, 180e5b845dcSCatherine Sullivan struct ethtool_channels *cmd) 181e5b845dcSCatherine Sullivan { 182e5b845dcSCatherine Sullivan struct gve_priv *priv = netdev_priv(netdev); 183e5b845dcSCatherine Sullivan struct gve_queue_config new_tx_cfg = priv->tx_cfg; 184e5b845dcSCatherine Sullivan struct gve_queue_config new_rx_cfg = priv->rx_cfg; 185e5b845dcSCatherine Sullivan struct ethtool_channels old_settings; 186e5b845dcSCatherine Sullivan int new_tx = cmd->tx_count; 187e5b845dcSCatherine Sullivan int new_rx = cmd->rx_count; 188e5b845dcSCatherine Sullivan 189e5b845dcSCatherine Sullivan gve_get_channels(netdev, &old_settings); 190e5b845dcSCatherine Sullivan 191e5b845dcSCatherine Sullivan /* Changing combined is not allowed allowed */ 192e5b845dcSCatherine Sullivan if (cmd->combined_count != old_settings.combined_count) 193e5b845dcSCatherine Sullivan return -EINVAL; 194e5b845dcSCatherine Sullivan 195e5b845dcSCatherine Sullivan if (!new_rx || !new_tx) 196e5b845dcSCatherine Sullivan return -EINVAL; 197e5b845dcSCatherine Sullivan 198e5b845dcSCatherine Sullivan if (!netif_carrier_ok(netdev)) { 199e5b845dcSCatherine Sullivan priv->tx_cfg.num_queues = new_tx; 200e5b845dcSCatherine Sullivan priv->rx_cfg.num_queues = new_rx; 201e5b845dcSCatherine Sullivan return 0; 202e5b845dcSCatherine Sullivan } 203e5b845dcSCatherine Sullivan 204e5b845dcSCatherine Sullivan new_tx_cfg.num_queues = new_tx; 205e5b845dcSCatherine Sullivan new_rx_cfg.num_queues = new_rx; 206e5b845dcSCatherine Sullivan 207e5b845dcSCatherine Sullivan return gve_adjust_queues(priv, new_rx_cfg, new_tx_cfg); 208e5b845dcSCatherine Sullivan } 209e5b845dcSCatherine Sullivan 210e5b845dcSCatherine Sullivan static void gve_get_ringparam(struct net_device *netdev, 211e5b845dcSCatherine Sullivan struct ethtool_ringparam *cmd) 212e5b845dcSCatherine Sullivan { 213e5b845dcSCatherine Sullivan struct gve_priv *priv = netdev_priv(netdev); 214e5b845dcSCatherine Sullivan 215e5b845dcSCatherine Sullivan cmd->rx_max_pending = priv->rx_desc_cnt; 216e5b845dcSCatherine Sullivan cmd->tx_max_pending = priv->tx_desc_cnt; 217e5b845dcSCatherine Sullivan cmd->rx_pending = priv->rx_desc_cnt; 218e5b845dcSCatherine Sullivan cmd->tx_pending = priv->tx_desc_cnt; 219e5b845dcSCatherine Sullivan } 220e5b845dcSCatherine Sullivan 221e5b845dcSCatherine Sullivan static int gve_user_reset(struct net_device *netdev, u32 *flags) 222e5b845dcSCatherine Sullivan { 223e5b845dcSCatherine Sullivan struct gve_priv *priv = netdev_priv(netdev); 224e5b845dcSCatherine Sullivan 225e5b845dcSCatherine Sullivan if (*flags == ETH_RESET_ALL) { 226e5b845dcSCatherine Sullivan *flags = 0; 227e5b845dcSCatherine Sullivan return gve_reset(priv, true); 228e5b845dcSCatherine Sullivan } 229e5b845dcSCatherine Sullivan 230e5b845dcSCatherine Sullivan return -EOPNOTSUPP; 231e5b845dcSCatherine Sullivan } 232e5b845dcSCatherine Sullivan 233e5b845dcSCatherine Sullivan const struct ethtool_ops gve_ethtool_ops = { 234e5b845dcSCatherine Sullivan .get_drvinfo = gve_get_drvinfo, 235e5b845dcSCatherine Sullivan .get_strings = gve_get_strings, 236e5b845dcSCatherine Sullivan .get_sset_count = gve_get_sset_count, 237e5b845dcSCatherine Sullivan .get_ethtool_stats = gve_get_ethtool_stats, 238e5b845dcSCatherine Sullivan .set_msglevel = gve_set_msglevel, 239e5b845dcSCatherine Sullivan .get_msglevel = gve_get_msglevel, 240e5b845dcSCatherine Sullivan .set_channels = gve_set_channels, 241e5b845dcSCatherine Sullivan .get_channels = gve_get_channels, 242e5b845dcSCatherine Sullivan .get_link = ethtool_op_get_link, 243e5b845dcSCatherine Sullivan .get_ringparam = gve_get_ringparam, 244e5b845dcSCatherine Sullivan .reset = gve_user_reset, 245e5b845dcSCatherine Sullivan }; 246