281 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/****************************************************************************3 * Driver for Solarflare network controllers and boards4 * Copyright 2005-2006 Fen Systems Ltd.5 * Copyright 2006-2013 Solarflare Communications Inc.6 */7 8#include <linux/netdevice.h>9#include <linux/ethtool.h>10#include <linux/rtnetlink.h>11#include <linux/in.h>12#include "net_driver.h"13#include "workarounds.h"14#include "selftest.h"15#include "efx.h"16#include "efx_channels.h"17#include "rx_common.h"18#include "tx_common.h"19#include "ethtool_common.h"20#include "filter.h"21#include "nic.h"22 23#define EFX_ETHTOOL_EEPROM_MAGIC 0xEFAB24 25/**************************************************************************26 *27 * Ethtool operations28 *29 **************************************************************************30 */31 32/* Identify device by flashing LEDs */33static int efx_ethtool_phys_id(struct net_device *net_dev,34 enum ethtool_phys_id_state state)35{36 struct efx_nic *efx = efx_netdev_priv(net_dev);37 enum efx_led_mode mode = EFX_LED_DEFAULT;38 39 switch (state) {40 case ETHTOOL_ID_ON:41 mode = EFX_LED_ON;42 break;43 case ETHTOOL_ID_OFF:44 mode = EFX_LED_OFF;45 break;46 case ETHTOOL_ID_INACTIVE:47 mode = EFX_LED_DEFAULT;48 break;49 case ETHTOOL_ID_ACTIVE:50 return 1; /* cycle on/off once per second */51 }52 53 return efx_mcdi_set_id_led(efx, mode);54}55 56static int efx_ethtool_get_regs_len(struct net_device *net_dev)57{58 return efx_nic_get_regs_len(efx_netdev_priv(net_dev));59}60 61static void efx_ethtool_get_regs(struct net_device *net_dev,62 struct ethtool_regs *regs, void *buf)63{64 struct efx_nic *efx = efx_netdev_priv(net_dev);65 66 regs->version = efx->type->revision;67 efx_nic_get_regs(efx, buf);68}69 70/*71 * Each channel has a single IRQ and moderation timer, started by any72 * completion (or other event). Unless the module parameter73 * separate_tx_channels is set, IRQs and moderation are therefore74 * shared between RX and TX completions. In this case, when RX IRQ75 * moderation is explicitly changed then TX IRQ moderation is76 * automatically changed too, but otherwise we fail if the two values77 * are requested to be different.78 *79 * The hardware does not support a limit on the number of completions80 * before an IRQ, so we do not use the max_frames fields. We should81 * report and require that max_frames == (usecs != 0), but this would82 * invalidate existing user documentation.83 *84 * The hardware does not have distinct settings for interrupt85 * moderation while the previous IRQ is being handled, so we should86 * not use the 'irq' fields. However, an earlier developer87 * misunderstood the meaning of the 'irq' fields and the driver did88 * not support the standard fields. To avoid invalidating existing89 * user documentation, we report and accept changes through either the90 * standard or 'irq' fields. If both are changed at the same time, we91 * prefer the standard field.92 *93 * We implement adaptive IRQ moderation, but use a different algorithm94 * from that assumed in the definition of struct ethtool_coalesce.95 * Therefore we do not use any of the adaptive moderation parameters96 * in it.97 */98 99static int efx_ethtool_get_coalesce(struct net_device *net_dev,100 struct ethtool_coalesce *coalesce,101 struct kernel_ethtool_coalesce *kernel_coal,102 struct netlink_ext_ack *extack)103{104 struct efx_nic *efx = efx_netdev_priv(net_dev);105 unsigned int tx_usecs, rx_usecs;106 bool rx_adaptive;107 108 efx_get_irq_moderation(efx, &tx_usecs, &rx_usecs, &rx_adaptive);109 110 coalesce->tx_coalesce_usecs = tx_usecs;111 coalesce->tx_coalesce_usecs_irq = tx_usecs;112 coalesce->rx_coalesce_usecs = rx_usecs;113 coalesce->rx_coalesce_usecs_irq = rx_usecs;114 coalesce->use_adaptive_rx_coalesce = rx_adaptive;115 116 return 0;117}118 119static int efx_ethtool_set_coalesce(struct net_device *net_dev,120 struct ethtool_coalesce *coalesce,121 struct kernel_ethtool_coalesce *kernel_coal,122 struct netlink_ext_ack *extack)123{124 struct efx_nic *efx = efx_netdev_priv(net_dev);125 struct efx_channel *channel;126 unsigned int tx_usecs, rx_usecs;127 bool adaptive, rx_may_override_tx;128 int rc;129 130 efx_get_irq_moderation(efx, &tx_usecs, &rx_usecs, &adaptive);131 132 if (coalesce->rx_coalesce_usecs != rx_usecs)133 rx_usecs = coalesce->rx_coalesce_usecs;134 else135 rx_usecs = coalesce->rx_coalesce_usecs_irq;136 137 adaptive = coalesce->use_adaptive_rx_coalesce;138 139 /* If channels are shared, TX IRQ moderation can be quietly140 * overridden unless it is changed from its old value.141 */142 rx_may_override_tx = (coalesce->tx_coalesce_usecs == tx_usecs &&143 coalesce->tx_coalesce_usecs_irq == tx_usecs);144 if (coalesce->tx_coalesce_usecs != tx_usecs)145 tx_usecs = coalesce->tx_coalesce_usecs;146 else147 tx_usecs = coalesce->tx_coalesce_usecs_irq;148 149 rc = efx_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive,150 rx_may_override_tx);151 if (rc != 0)152 return rc;153 154 efx_for_each_channel(channel, efx)155 efx->type->push_irq_moderation(channel);156 157 return 0;158}159 160static void161efx_ethtool_get_ringparam(struct net_device *net_dev,162 struct ethtool_ringparam *ring,163 struct kernel_ethtool_ringparam *kernel_ring,164 struct netlink_ext_ack *extack)165{166 struct efx_nic *efx = efx_netdev_priv(net_dev);167 168 ring->rx_max_pending = EFX_MAX_DMAQ_SIZE;169 ring->tx_max_pending = EFX_TXQ_MAX_ENT(efx);170 ring->rx_pending = efx->rxq_entries;171 ring->tx_pending = efx->txq_entries;172}173 174static int175efx_ethtool_set_ringparam(struct net_device *net_dev,176 struct ethtool_ringparam *ring,177 struct kernel_ethtool_ringparam *kernel_ring,178 struct netlink_ext_ack *extack)179{180 struct efx_nic *efx = efx_netdev_priv(net_dev);181 u32 txq_entries;182 183 if (ring->rx_mini_pending || ring->rx_jumbo_pending ||184 ring->rx_pending > EFX_MAX_DMAQ_SIZE ||185 ring->tx_pending > EFX_TXQ_MAX_ENT(efx))186 return -EINVAL;187 188 if (ring->rx_pending < EFX_RXQ_MIN_ENT) {189 netif_err(efx, drv, efx->net_dev,190 "RX queues cannot be smaller than %u\n",191 EFX_RXQ_MIN_ENT);192 return -EINVAL;193 }194 195 txq_entries = max(ring->tx_pending, EFX_TXQ_MIN_ENT(efx));196 if (txq_entries != ring->tx_pending)197 netif_warn(efx, drv, efx->net_dev,198 "increasing TX queue size to minimum of %u\n",199 txq_entries);200 201 return efx_realloc_channels(efx, ring->rx_pending, txq_entries);202}203 204static void efx_ethtool_get_wol(struct net_device *net_dev,205 struct ethtool_wolinfo *wol)206{207 struct efx_nic *efx = efx_netdev_priv(net_dev);208 return efx->type->get_wol(efx, wol);209}210 211 212static int efx_ethtool_set_wol(struct net_device *net_dev,213 struct ethtool_wolinfo *wol)214{215 struct efx_nic *efx = efx_netdev_priv(net_dev);216 return efx->type->set_wol(efx, wol->wolopts);217}218 219static void efx_ethtool_get_fec_stats(struct net_device *net_dev,220 struct ethtool_fec_stats *fec_stats)221{222 struct efx_nic *efx = efx_netdev_priv(net_dev);223 224 if (efx->type->get_fec_stats)225 efx->type->get_fec_stats(efx, fec_stats);226}227 228static int efx_ethtool_get_ts_info(struct net_device *net_dev,229 struct kernel_ethtool_ts_info *ts_info)230{231 struct efx_nic *efx = efx_netdev_priv(net_dev);232 233 efx_ptp_get_ts_info(efx, ts_info);234 return 0;235}236 237const struct ethtool_ops efx_ethtool_ops = {238 .supported_coalesce_params = ETHTOOL_COALESCE_USECS |239 ETHTOOL_COALESCE_USECS_IRQ |240 ETHTOOL_COALESCE_USE_ADAPTIVE_RX,241 .get_drvinfo = efx_ethtool_get_drvinfo,242 .get_regs_len = efx_ethtool_get_regs_len,243 .get_regs = efx_ethtool_get_regs,244 .get_msglevel = efx_ethtool_get_msglevel,245 .set_msglevel = efx_ethtool_set_msglevel,246 .get_link = ethtool_op_get_link,247 .get_coalesce = efx_ethtool_get_coalesce,248 .set_coalesce = efx_ethtool_set_coalesce,249 .get_ringparam = efx_ethtool_get_ringparam,250 .set_ringparam = efx_ethtool_set_ringparam,251 .get_pauseparam = efx_ethtool_get_pauseparam,252 .set_pauseparam = efx_ethtool_set_pauseparam,253 .get_sset_count = efx_ethtool_get_sset_count,254 .self_test = efx_ethtool_self_test,255 .get_strings = efx_ethtool_get_strings,256 .set_phys_id = efx_ethtool_phys_id,257 .get_ethtool_stats = efx_ethtool_get_stats,258 .get_wol = efx_ethtool_get_wol,259 .set_wol = efx_ethtool_set_wol,260 .reset = efx_ethtool_reset,261 .get_rxnfc = efx_ethtool_get_rxnfc,262 .set_rxnfc = efx_ethtool_set_rxnfc,263 .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size,264 .get_rxfh_key_size = efx_ethtool_get_rxfh_key_size,265 .rxfh_per_ctx_key = true,266 .rxfh_priv_size = sizeof(struct efx_rss_context_priv),267 .get_rxfh = efx_ethtool_get_rxfh,268 .set_rxfh = efx_ethtool_set_rxfh,269 .create_rxfh_context = efx_ethtool_create_rxfh_context,270 .modify_rxfh_context = efx_ethtool_modify_rxfh_context,271 .remove_rxfh_context = efx_ethtool_remove_rxfh_context,272 .get_ts_info = efx_ethtool_get_ts_info,273 .get_module_info = efx_ethtool_get_module_info,274 .get_module_eeprom = efx_ethtool_get_module_eeprom,275 .get_link_ksettings = efx_ethtool_get_link_ksettings,276 .set_link_ksettings = efx_ethtool_set_link_ksettings,277 .get_fec_stats = efx_ethtool_get_fec_stats,278 .get_fecparam = efx_ethtool_get_fecparam,279 .set_fecparam = efx_ethtool_set_fecparam,280};281