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", 37433e274bSKuo Zhao "rx_skb_alloc_fail", "rx_buf_alloc_fail", "rx_desc_err_dropped_pkt", 38433e274bSKuo Zhao "interface_up_cnt", "interface_down_cnt", "reset_cnt", 39433e274bSKuo Zhao "page_alloc_fail", "dma_mapping_error", 40433e274bSKuo Zhao }; 41433e274bSKuo Zhao 42433e274bSKuo Zhao static const char gve_gstrings_rx_stats[][ETH_GSTRING_LEN] = { 43433e274bSKuo Zhao "rx_posted_desc[%u]", "rx_completed_desc[%u]", "rx_bytes[%u]", 44433e274bSKuo Zhao "rx_dropped_pkt[%u]", "rx_copybreak_pkt[%u]", "rx_copied_pkt[%u]", 45433e274bSKuo Zhao }; 46433e274bSKuo Zhao 47433e274bSKuo Zhao static const char gve_gstrings_tx_stats[][ETH_GSTRING_LEN] = { 48433e274bSKuo Zhao "tx_posted_desc[%u]", "tx_completed_desc[%u]", "tx_bytes[%u]", 49433e274bSKuo Zhao "tx_wake[%u]", "tx_stop[%u]", "tx_event_counter[%u]", 50433e274bSKuo Zhao }; 51433e274bSKuo Zhao 52433e274bSKuo Zhao static const char gve_gstrings_adminq_stats[][ETH_GSTRING_LEN] = { 53433e274bSKuo Zhao "adminq_prod_cnt", "adminq_cmd_fail", "adminq_timeouts", 54433e274bSKuo Zhao "adminq_describe_device_cnt", "adminq_cfg_device_resources_cnt", 55433e274bSKuo Zhao "adminq_register_page_list_cnt", "adminq_unregister_page_list_cnt", 56433e274bSKuo Zhao "adminq_create_tx_queue_cnt", "adminq_create_rx_queue_cnt", 57433e274bSKuo Zhao "adminq_destroy_tx_queue_cnt", "adminq_destroy_rx_queue_cnt", 58433e274bSKuo Zhao "adminq_dcfg_device_resources_cnt", "adminq_set_driver_parameter_cnt", 59e5b845dcSCatherine Sullivan }; 60e5b845dcSCatherine Sullivan 61e5b845dcSCatherine Sullivan #define GVE_MAIN_STATS_LEN ARRAY_SIZE(gve_gstrings_main_stats) 62433e274bSKuo Zhao #define GVE_ADMINQ_STATS_LEN ARRAY_SIZE(gve_gstrings_adminq_stats) 63433e274bSKuo Zhao #define NUM_GVE_TX_CNTS ARRAY_SIZE(gve_gstrings_tx_stats) 64433e274bSKuo Zhao #define NUM_GVE_RX_CNTS ARRAY_SIZE(gve_gstrings_rx_stats) 65e5b845dcSCatherine Sullivan 66e5b845dcSCatherine Sullivan static void gve_get_strings(struct net_device *netdev, u32 stringset, u8 *data) 67e5b845dcSCatherine Sullivan { 68e5b845dcSCatherine Sullivan struct gve_priv *priv = netdev_priv(netdev); 69e5b845dcSCatherine Sullivan char *s = (char *)data; 70433e274bSKuo Zhao int i, j; 71e5b845dcSCatherine Sullivan 72e5b845dcSCatherine Sullivan if (stringset != ETH_SS_STATS) 73e5b845dcSCatherine Sullivan return; 74e5b845dcSCatherine Sullivan 75e5b845dcSCatherine Sullivan memcpy(s, *gve_gstrings_main_stats, 76e5b845dcSCatherine Sullivan sizeof(gve_gstrings_main_stats)); 77e5b845dcSCatherine Sullivan s += sizeof(gve_gstrings_main_stats); 78e5b845dcSCatherine Sullivan for (i = 0; i < priv->rx_cfg.num_queues; i++) { 79433e274bSKuo Zhao for (j = 0; j < NUM_GVE_RX_CNTS; j++) { 80433e274bSKuo Zhao snprintf(s, ETH_GSTRING_LEN, gve_gstrings_rx_stats[j], i); 81e5b845dcSCatherine Sullivan s += ETH_GSTRING_LEN; 82433e274bSKuo Zhao } 83e5b845dcSCatherine Sullivan } 84e5b845dcSCatherine Sullivan for (i = 0; i < priv->tx_cfg.num_queues; i++) { 85433e274bSKuo Zhao for (j = 0; j < NUM_GVE_TX_CNTS; j++) { 86433e274bSKuo Zhao snprintf(s, ETH_GSTRING_LEN, gve_gstrings_tx_stats[j], i); 87e5b845dcSCatherine Sullivan s += ETH_GSTRING_LEN; 88e5b845dcSCatherine Sullivan } 89e5b845dcSCatherine Sullivan } 90e5b845dcSCatherine Sullivan 91433e274bSKuo Zhao memcpy(s, *gve_gstrings_adminq_stats, 92433e274bSKuo Zhao sizeof(gve_gstrings_adminq_stats)); 93433e274bSKuo Zhao s += sizeof(gve_gstrings_adminq_stats); 94433e274bSKuo Zhao } 95433e274bSKuo Zhao 96e5b845dcSCatherine Sullivan static int gve_get_sset_count(struct net_device *netdev, int sset) 97e5b845dcSCatherine Sullivan { 98e5b845dcSCatherine Sullivan struct gve_priv *priv = netdev_priv(netdev); 99e5b845dcSCatherine Sullivan 100e5b845dcSCatherine Sullivan switch (sset) { 101e5b845dcSCatherine Sullivan case ETH_SS_STATS: 102433e274bSKuo Zhao return GVE_MAIN_STATS_LEN + GVE_ADMINQ_STATS_LEN + 103e5b845dcSCatherine Sullivan (priv->rx_cfg.num_queues * NUM_GVE_RX_CNTS) + 104e5b845dcSCatherine Sullivan (priv->tx_cfg.num_queues * NUM_GVE_TX_CNTS); 105e5b845dcSCatherine Sullivan default: 106e5b845dcSCatherine Sullivan return -EOPNOTSUPP; 107e5b845dcSCatherine Sullivan } 108e5b845dcSCatherine Sullivan } 109e5b845dcSCatherine Sullivan 110e5b845dcSCatherine Sullivan static void 111e5b845dcSCatherine Sullivan gve_get_ethtool_stats(struct net_device *netdev, 112e5b845dcSCatherine Sullivan struct ethtool_stats *stats, u64 *data) 113e5b845dcSCatherine Sullivan { 114433e274bSKuo Zhao u64 tmp_rx_pkts, tmp_rx_bytes, tmp_rx_skb_alloc_fail, tmp_rx_buf_alloc_fail, 115433e274bSKuo Zhao tmp_rx_desc_err_dropped_pkt, tmp_tx_pkts, tmp_tx_bytes; 116433e274bSKuo Zhao u64 rx_buf_alloc_fail, rx_desc_err_dropped_pkt, rx_pkts, 117433e274bSKuo Zhao rx_skb_alloc_fail, rx_bytes, tx_pkts, tx_bytes; 118433e274bSKuo Zhao struct gve_priv *priv; 119e5b845dcSCatherine Sullivan unsigned int start; 120e5b845dcSCatherine Sullivan int ring; 121e5b845dcSCatherine Sullivan int i; 122e5b845dcSCatherine Sullivan 123e5b845dcSCatherine Sullivan ASSERT_RTNL(); 124e5b845dcSCatherine Sullivan 125433e274bSKuo Zhao priv = netdev_priv(netdev); 126433e274bSKuo Zhao for (rx_pkts = 0, rx_bytes = 0, rx_skb_alloc_fail = 0, 127433e274bSKuo Zhao rx_buf_alloc_fail = 0, rx_desc_err_dropped_pkt = 0, ring = 0; 128e5b845dcSCatherine Sullivan ring < priv->rx_cfg.num_queues; ring++) { 129e5b845dcSCatherine Sullivan if (priv->rx) { 130e5b845dcSCatherine Sullivan do { 131433e274bSKuo Zhao struct gve_rx_ring *rx = &priv->rx[ring]; 132433e274bSKuo Zhao 1333c13ce74SCatherine Sullivan start = 134e5b845dcSCatherine Sullivan u64_stats_fetch_begin(&priv->rx[ring].statss); 135433e274bSKuo Zhao tmp_rx_pkts = rx->rpackets; 136433e274bSKuo Zhao tmp_rx_bytes = rx->rbytes; 137433e274bSKuo Zhao tmp_rx_skb_alloc_fail = rx->rx_skb_alloc_fail; 138433e274bSKuo Zhao tmp_rx_buf_alloc_fail = rx->rx_buf_alloc_fail; 139433e274bSKuo Zhao tmp_rx_desc_err_dropped_pkt = 140433e274bSKuo Zhao rx->rx_desc_err_dropped_pkt; 141e5b845dcSCatherine Sullivan } while (u64_stats_fetch_retry(&priv->rx[ring].statss, 142e5b845dcSCatherine Sullivan start)); 143433e274bSKuo Zhao rx_pkts += tmp_rx_pkts; 144433e274bSKuo Zhao rx_bytes += tmp_rx_bytes; 145433e274bSKuo Zhao rx_skb_alloc_fail += tmp_rx_skb_alloc_fail; 146433e274bSKuo Zhao rx_buf_alloc_fail += tmp_rx_buf_alloc_fail; 147433e274bSKuo Zhao rx_desc_err_dropped_pkt += tmp_rx_desc_err_dropped_pkt; 148e5b845dcSCatherine Sullivan } 149e5b845dcSCatherine Sullivan } 150e5b845dcSCatherine Sullivan for (tx_pkts = 0, tx_bytes = 0, ring = 0; 151e5b845dcSCatherine Sullivan ring < priv->tx_cfg.num_queues; ring++) { 152e5b845dcSCatherine Sullivan if (priv->tx) { 153e5b845dcSCatherine Sullivan do { 1543c13ce74SCatherine Sullivan start = 155e5b845dcSCatherine Sullivan u64_stats_fetch_begin(&priv->tx[ring].statss); 156433e274bSKuo Zhao tmp_tx_pkts = priv->tx[ring].pkt_done; 157433e274bSKuo Zhao tmp_tx_bytes = priv->tx[ring].bytes_done; 158e5b845dcSCatherine Sullivan } while (u64_stats_fetch_retry(&priv->tx[ring].statss, 159e5b845dcSCatherine Sullivan start)); 160433e274bSKuo Zhao tx_pkts += tmp_tx_pkts; 161433e274bSKuo Zhao tx_bytes += tmp_tx_bytes; 162e5b845dcSCatherine Sullivan } 163e5b845dcSCatherine Sullivan } 164e5b845dcSCatherine Sullivan 165e5b845dcSCatherine Sullivan i = 0; 166e5b845dcSCatherine Sullivan data[i++] = rx_pkts; 167e5b845dcSCatherine Sullivan data[i++] = tx_pkts; 168e5b845dcSCatherine Sullivan data[i++] = rx_bytes; 169e5b845dcSCatherine Sullivan data[i++] = tx_bytes; 170433e274bSKuo Zhao /* total rx dropped packets */ 171433e274bSKuo Zhao data[i++] = rx_skb_alloc_fail + rx_buf_alloc_fail + 172433e274bSKuo Zhao rx_desc_err_dropped_pkt; 173433e274bSKuo Zhao /* Skip tx_dropped */ 174433e274bSKuo Zhao i++; 175433e274bSKuo Zhao 176e5b845dcSCatherine Sullivan data[i++] = priv->tx_timeo_cnt; 177433e274bSKuo Zhao data[i++] = rx_skb_alloc_fail; 178433e274bSKuo Zhao data[i++] = rx_buf_alloc_fail; 179433e274bSKuo Zhao data[i++] = rx_desc_err_dropped_pkt; 180433e274bSKuo Zhao data[i++] = priv->interface_up_cnt; 181433e274bSKuo Zhao data[i++] = priv->interface_down_cnt; 182433e274bSKuo Zhao data[i++] = priv->reset_cnt; 183433e274bSKuo Zhao data[i++] = priv->page_alloc_fail; 184433e274bSKuo Zhao data[i++] = priv->dma_mapping_error; 185e5b845dcSCatherine Sullivan i = GVE_MAIN_STATS_LEN; 186e5b845dcSCatherine Sullivan 187e5b845dcSCatherine Sullivan /* walk RX rings */ 188e5b845dcSCatherine Sullivan if (priv->rx) { 189e5b845dcSCatherine Sullivan for (ring = 0; ring < priv->rx_cfg.num_queues; ring++) { 190e5b845dcSCatherine Sullivan struct gve_rx_ring *rx = &priv->rx[ring]; 191e5b845dcSCatherine Sullivan 192438b43bdSCatherine Sullivan data[i++] = rx->fill_cnt; 193433e274bSKuo Zhao data[i++] = rx->cnt; 194433e274bSKuo Zhao do { 195433e274bSKuo Zhao start = 196433e274bSKuo Zhao u64_stats_fetch_begin(&priv->rx[ring].statss); 197433e274bSKuo Zhao tmp_rx_bytes = rx->rbytes; 198433e274bSKuo Zhao tmp_rx_skb_alloc_fail = rx->rx_skb_alloc_fail; 199433e274bSKuo Zhao tmp_rx_buf_alloc_fail = rx->rx_buf_alloc_fail; 200433e274bSKuo Zhao tmp_rx_desc_err_dropped_pkt = 201433e274bSKuo Zhao rx->rx_desc_err_dropped_pkt; 202433e274bSKuo Zhao } while (u64_stats_fetch_retry(&priv->rx[ring].statss, 203433e274bSKuo Zhao start)); 204433e274bSKuo Zhao data[i++] = tmp_rx_bytes; 205433e274bSKuo Zhao /* rx dropped packets */ 206433e274bSKuo Zhao data[i++] = tmp_rx_skb_alloc_fail + 207433e274bSKuo Zhao tmp_rx_buf_alloc_fail + 208433e274bSKuo Zhao tmp_rx_desc_err_dropped_pkt; 209433e274bSKuo Zhao data[i++] = rx->rx_copybreak_pkt; 210433e274bSKuo Zhao data[i++] = rx->rx_copied_pkt; 211e5b845dcSCatherine Sullivan } 212e5b845dcSCatherine Sullivan } else { 213e5b845dcSCatherine Sullivan i += priv->rx_cfg.num_queues * NUM_GVE_RX_CNTS; 214e5b845dcSCatherine Sullivan } 215e5b845dcSCatherine Sullivan /* walk TX rings */ 216e5b845dcSCatherine Sullivan if (priv->tx) { 217e5b845dcSCatherine Sullivan for (ring = 0; ring < priv->tx_cfg.num_queues; ring++) { 218e5b845dcSCatherine Sullivan struct gve_tx_ring *tx = &priv->tx[ring]; 219e5b845dcSCatherine Sullivan 220e5b845dcSCatherine Sullivan data[i++] = tx->req; 221e5b845dcSCatherine Sullivan data[i++] = tx->done; 222433e274bSKuo Zhao do { 223433e274bSKuo Zhao start = 224433e274bSKuo Zhao u64_stats_fetch_begin(&priv->tx[ring].statss); 225433e274bSKuo Zhao tmp_tx_bytes = tx->bytes_done; 226433e274bSKuo Zhao } while (u64_stats_fetch_retry(&priv->tx[ring].statss, 227433e274bSKuo Zhao start)); 228433e274bSKuo Zhao data[i++] = tmp_tx_bytes; 229e5b845dcSCatherine Sullivan data[i++] = tx->wake_queue; 230e5b845dcSCatherine Sullivan data[i++] = tx->stop_queue; 231e5b845dcSCatherine Sullivan data[i++] = be32_to_cpu(gve_tx_load_event_counter(priv, 232e5b845dcSCatherine Sullivan tx)); 233e5b845dcSCatherine Sullivan } 234e5b845dcSCatherine Sullivan } else { 235e5b845dcSCatherine Sullivan i += priv->tx_cfg.num_queues * NUM_GVE_TX_CNTS; 236e5b845dcSCatherine Sullivan } 237433e274bSKuo Zhao /* AQ Stats */ 238433e274bSKuo Zhao data[i++] = priv->adminq_prod_cnt; 239433e274bSKuo Zhao data[i++] = priv->adminq_cmd_fail; 240433e274bSKuo Zhao data[i++] = priv->adminq_timeouts; 241433e274bSKuo Zhao data[i++] = priv->adminq_describe_device_cnt; 242433e274bSKuo Zhao data[i++] = priv->adminq_cfg_device_resources_cnt; 243433e274bSKuo Zhao data[i++] = priv->adminq_register_page_list_cnt; 244433e274bSKuo Zhao data[i++] = priv->adminq_unregister_page_list_cnt; 245433e274bSKuo Zhao data[i++] = priv->adminq_create_tx_queue_cnt; 246433e274bSKuo Zhao data[i++] = priv->adminq_create_rx_queue_cnt; 247433e274bSKuo Zhao data[i++] = priv->adminq_destroy_tx_queue_cnt; 248433e274bSKuo Zhao data[i++] = priv->adminq_destroy_rx_queue_cnt; 249433e274bSKuo Zhao data[i++] = priv->adminq_dcfg_device_resources_cnt; 250433e274bSKuo Zhao data[i++] = priv->adminq_set_driver_parameter_cnt; 251e5b845dcSCatherine Sullivan } 252e5b845dcSCatherine Sullivan 253e5b845dcSCatherine Sullivan static void gve_get_channels(struct net_device *netdev, 254e5b845dcSCatherine Sullivan struct ethtool_channels *cmd) 255e5b845dcSCatherine Sullivan { 256e5b845dcSCatherine Sullivan struct gve_priv *priv = netdev_priv(netdev); 257e5b845dcSCatherine Sullivan 258e5b845dcSCatherine Sullivan cmd->max_rx = priv->rx_cfg.max_queues; 259e5b845dcSCatherine Sullivan cmd->max_tx = priv->tx_cfg.max_queues; 260e5b845dcSCatherine Sullivan cmd->max_other = 0; 261e5b845dcSCatherine Sullivan cmd->max_combined = 0; 262e5b845dcSCatherine Sullivan cmd->rx_count = priv->rx_cfg.num_queues; 263e5b845dcSCatherine Sullivan cmd->tx_count = priv->tx_cfg.num_queues; 264e5b845dcSCatherine Sullivan cmd->other_count = 0; 265e5b845dcSCatherine Sullivan cmd->combined_count = 0; 266e5b845dcSCatherine Sullivan } 267e5b845dcSCatherine Sullivan 268e5b845dcSCatherine Sullivan static int gve_set_channels(struct net_device *netdev, 269e5b845dcSCatherine Sullivan struct ethtool_channels *cmd) 270e5b845dcSCatherine Sullivan { 271e5b845dcSCatherine Sullivan struct gve_priv *priv = netdev_priv(netdev); 272e5b845dcSCatherine Sullivan struct gve_queue_config new_tx_cfg = priv->tx_cfg; 273e5b845dcSCatherine Sullivan struct gve_queue_config new_rx_cfg = priv->rx_cfg; 274e5b845dcSCatherine Sullivan struct ethtool_channels old_settings; 275e5b845dcSCatherine Sullivan int new_tx = cmd->tx_count; 276e5b845dcSCatherine Sullivan int new_rx = cmd->rx_count; 277e5b845dcSCatherine Sullivan 278e5b845dcSCatherine Sullivan gve_get_channels(netdev, &old_settings); 279e5b845dcSCatherine Sullivan 280e5b845dcSCatherine Sullivan /* Changing combined is not allowed allowed */ 281e5b845dcSCatherine Sullivan if (cmd->combined_count != old_settings.combined_count) 282e5b845dcSCatherine Sullivan return -EINVAL; 283e5b845dcSCatherine Sullivan 284e5b845dcSCatherine Sullivan if (!new_rx || !new_tx) 285e5b845dcSCatherine Sullivan return -EINVAL; 286e5b845dcSCatherine Sullivan 287e5b845dcSCatherine Sullivan if (!netif_carrier_ok(netdev)) { 288e5b845dcSCatherine Sullivan priv->tx_cfg.num_queues = new_tx; 289e5b845dcSCatherine Sullivan priv->rx_cfg.num_queues = new_rx; 290e5b845dcSCatherine Sullivan return 0; 291e5b845dcSCatherine Sullivan } 292e5b845dcSCatherine Sullivan 293e5b845dcSCatherine Sullivan new_tx_cfg.num_queues = new_tx; 294e5b845dcSCatherine Sullivan new_rx_cfg.num_queues = new_rx; 295e5b845dcSCatherine Sullivan 296e5b845dcSCatherine Sullivan return gve_adjust_queues(priv, new_rx_cfg, new_tx_cfg); 297e5b845dcSCatherine Sullivan } 298e5b845dcSCatherine Sullivan 299e5b845dcSCatherine Sullivan static void gve_get_ringparam(struct net_device *netdev, 300e5b845dcSCatherine Sullivan struct ethtool_ringparam *cmd) 301e5b845dcSCatherine Sullivan { 302e5b845dcSCatherine Sullivan struct gve_priv *priv = netdev_priv(netdev); 303e5b845dcSCatherine Sullivan 304e5b845dcSCatherine Sullivan cmd->rx_max_pending = priv->rx_desc_cnt; 305e5b845dcSCatherine Sullivan cmd->tx_max_pending = priv->tx_desc_cnt; 306e5b845dcSCatherine Sullivan cmd->rx_pending = priv->rx_desc_cnt; 307e5b845dcSCatherine Sullivan cmd->tx_pending = priv->tx_desc_cnt; 308e5b845dcSCatherine Sullivan } 309e5b845dcSCatherine Sullivan 310e5b845dcSCatherine Sullivan static int gve_user_reset(struct net_device *netdev, u32 *flags) 311e5b845dcSCatherine Sullivan { 312e5b845dcSCatherine Sullivan struct gve_priv *priv = netdev_priv(netdev); 313e5b845dcSCatherine Sullivan 314e5b845dcSCatherine Sullivan if (*flags == ETH_RESET_ALL) { 315e5b845dcSCatherine Sullivan *flags = 0; 316e5b845dcSCatherine Sullivan return gve_reset(priv, true); 317e5b845dcSCatherine Sullivan } 318e5b845dcSCatherine Sullivan 319e5b845dcSCatherine Sullivan return -EOPNOTSUPP; 320e5b845dcSCatherine Sullivan } 321e5b845dcSCatherine Sullivan 322d5f7543cSKuo Zhao static int gve_get_tunable(struct net_device *netdev, 323d5f7543cSKuo Zhao const struct ethtool_tunable *etuna, void *value) 324d5f7543cSKuo Zhao { 325d5f7543cSKuo Zhao struct gve_priv *priv = netdev_priv(netdev); 326d5f7543cSKuo Zhao 327d5f7543cSKuo Zhao switch (etuna->id) { 328d5f7543cSKuo Zhao case ETHTOOL_RX_COPYBREAK: 329d5f7543cSKuo Zhao *(u32 *)value = priv->rx_copybreak; 330d5f7543cSKuo Zhao return 0; 331d5f7543cSKuo Zhao default: 332d5f7543cSKuo Zhao return -EOPNOTSUPP; 333d5f7543cSKuo Zhao } 334d5f7543cSKuo Zhao } 335d5f7543cSKuo Zhao 336d5f7543cSKuo Zhao static int gve_set_tunable(struct net_device *netdev, 337433e274bSKuo Zhao const struct ethtool_tunable *etuna, 338433e274bSKuo Zhao const void *value) 339d5f7543cSKuo Zhao { 340d5f7543cSKuo Zhao struct gve_priv *priv = netdev_priv(netdev); 341d5f7543cSKuo Zhao u32 len; 342d5f7543cSKuo Zhao 343d5f7543cSKuo Zhao switch (etuna->id) { 344d5f7543cSKuo Zhao case ETHTOOL_RX_COPYBREAK: 345d5f7543cSKuo Zhao len = *(u32 *)value; 346d5f7543cSKuo Zhao if (len > PAGE_SIZE / 2) 347d5f7543cSKuo Zhao return -EINVAL; 348d5f7543cSKuo Zhao priv->rx_copybreak = len; 349d5f7543cSKuo Zhao return 0; 350d5f7543cSKuo Zhao default: 351d5f7543cSKuo Zhao return -EOPNOTSUPP; 352d5f7543cSKuo Zhao } 353d5f7543cSKuo Zhao } 354d5f7543cSKuo Zhao 355e5b845dcSCatherine Sullivan const struct ethtool_ops gve_ethtool_ops = { 356e5b845dcSCatherine Sullivan .get_drvinfo = gve_get_drvinfo, 357e5b845dcSCatherine Sullivan .get_strings = gve_get_strings, 358e5b845dcSCatherine Sullivan .get_sset_count = gve_get_sset_count, 359e5b845dcSCatherine Sullivan .get_ethtool_stats = gve_get_ethtool_stats, 360e5b845dcSCatherine Sullivan .set_msglevel = gve_set_msglevel, 361e5b845dcSCatherine Sullivan .get_msglevel = gve_get_msglevel, 362e5b845dcSCatherine Sullivan .set_channels = gve_set_channels, 363e5b845dcSCatherine Sullivan .get_channels = gve_get_channels, 364e5b845dcSCatherine Sullivan .get_link = ethtool_op_get_link, 365e5b845dcSCatherine Sullivan .get_ringparam = gve_get_ringparam, 366e5b845dcSCatherine Sullivan .reset = gve_user_reset, 367d5f7543cSKuo Zhao .get_tunable = gve_get_tunable, 368d5f7543cSKuo Zhao .set_tunable = gve_set_tunable, 369e5b845dcSCatherine Sullivan }; 370