Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[platform/kernel/linux-starfive.git] / drivers / net / ethernet / sfc / ethtool.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /****************************************************************************
3  * Driver for Solarflare network controllers and boards
4  * 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 0xEFAB
24
25 /**************************************************************************
26  *
27  * Ethtool operations
28  *
29  **************************************************************************
30  */
31
32 /* Identify device by flashing LEDs */
33 static 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
56 static 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
61 static 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 any
72  * completion (or other event).  Unless the module parameter
73  * separate_tx_channels is set, IRQs and moderation are therefore
74  * shared between RX and TX completions.  In this case, when RX IRQ
75  * moderation is explicitly changed then TX IRQ moderation is
76  * automatically changed too, but otherwise we fail if the two values
77  * are requested to be different.
78  *
79  * The hardware does not support a limit on the number of completions
80  * before an IRQ, so we do not use the max_frames fields.  We should
81  * report and require that max_frames == (usecs != 0), but this would
82  * invalidate existing user documentation.
83  *
84  * The hardware does not have distinct settings for interrupt
85  * moderation while the previous IRQ is being handled, so we should
86  * not use the 'irq' fields.  However, an earlier developer
87  * misunderstood the meaning of the 'irq' fields and the driver did
88  * not support the standard fields.  To avoid invalidating existing
89  * user documentation, we report and accept changes through either the
90  * standard or 'irq' fields.  If both are changed at the same time, we
91  * prefer the standard field.
92  *
93  * We implement adaptive IRQ moderation, but use a different algorithm
94  * from that assumed in the definition of struct ethtool_coalesce.
95  * Therefore we do not use any of the adaptive moderation parameters
96  * in it.
97  */
98
99 static 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
119 static 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         else
135                 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 quietly
140          * 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         else
147                 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
160 static void
161 efx_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
174 static int
175 efx_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
204 static 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
212 static 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
219 static 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
228 static int efx_ethtool_get_ts_info(struct net_device *net_dev,
229                                    struct ethtool_ts_info *ts_info)
230 {
231         struct efx_nic *efx = efx_netdev_priv(net_dev);
232
233         /* Software capabilities */
234         ts_info->so_timestamping = (SOF_TIMESTAMPING_RX_SOFTWARE |
235                                     SOF_TIMESTAMPING_SOFTWARE);
236         ts_info->phc_index = -1;
237
238         efx_ptp_get_ts_info(efx, ts_info);
239         return 0;
240 }
241
242 const struct ethtool_ops efx_ethtool_ops = {
243         .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
244                                      ETHTOOL_COALESCE_USECS_IRQ |
245                                      ETHTOOL_COALESCE_USE_ADAPTIVE_RX,
246         .get_drvinfo            = efx_ethtool_get_drvinfo,
247         .get_regs_len           = efx_ethtool_get_regs_len,
248         .get_regs               = efx_ethtool_get_regs,
249         .get_msglevel           = efx_ethtool_get_msglevel,
250         .set_msglevel           = efx_ethtool_set_msglevel,
251         .get_link               = ethtool_op_get_link,
252         .get_coalesce           = efx_ethtool_get_coalesce,
253         .set_coalesce           = efx_ethtool_set_coalesce,
254         .get_ringparam          = efx_ethtool_get_ringparam,
255         .set_ringparam          = efx_ethtool_set_ringparam,
256         .get_pauseparam         = efx_ethtool_get_pauseparam,
257         .set_pauseparam         = efx_ethtool_set_pauseparam,
258         .get_sset_count         = efx_ethtool_get_sset_count,
259         .self_test              = efx_ethtool_self_test,
260         .get_strings            = efx_ethtool_get_strings,
261         .set_phys_id            = efx_ethtool_phys_id,
262         .get_ethtool_stats      = efx_ethtool_get_stats,
263         .get_wol                = efx_ethtool_get_wol,
264         .set_wol                = efx_ethtool_set_wol,
265         .reset                  = efx_ethtool_reset,
266         .get_rxnfc              = efx_ethtool_get_rxnfc,
267         .set_rxnfc              = efx_ethtool_set_rxnfc,
268         .get_rxfh_indir_size    = efx_ethtool_get_rxfh_indir_size,
269         .get_rxfh_key_size      = efx_ethtool_get_rxfh_key_size,
270         .get_rxfh               = efx_ethtool_get_rxfh,
271         .set_rxfh               = efx_ethtool_set_rxfh,
272         .get_rxfh_context       = efx_ethtool_get_rxfh_context,
273         .set_rxfh_context       = efx_ethtool_set_rxfh_context,
274         .get_ts_info            = efx_ethtool_get_ts_info,
275         .get_module_info        = efx_ethtool_get_module_info,
276         .get_module_eeprom      = efx_ethtool_get_module_eeprom,
277         .get_link_ksettings     = efx_ethtool_get_link_ksettings,
278         .set_link_ksettings     = efx_ethtool_set_link_ksettings,
279         .get_fec_stats          = efx_ethtool_get_fec_stats,
280         .get_fecparam           = efx_ethtool_get_fecparam,
281         .set_fecparam           = efx_ethtool_set_fecparam,
282 };