Merge drm/drm-next into drm-intel-next-queued
[linux-2.6-microblaze.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 = 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(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 = 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 {
102         struct efx_nic *efx = netdev_priv(net_dev);
103         unsigned int tx_usecs, rx_usecs;
104         bool rx_adaptive;
105
106         efx_get_irq_moderation(efx, &tx_usecs, &rx_usecs, &rx_adaptive);
107
108         coalesce->tx_coalesce_usecs = tx_usecs;
109         coalesce->tx_coalesce_usecs_irq = tx_usecs;
110         coalesce->rx_coalesce_usecs = rx_usecs;
111         coalesce->rx_coalesce_usecs_irq = rx_usecs;
112         coalesce->use_adaptive_rx_coalesce = rx_adaptive;
113
114         return 0;
115 }
116
117 static int efx_ethtool_set_coalesce(struct net_device *net_dev,
118                                     struct ethtool_coalesce *coalesce)
119 {
120         struct efx_nic *efx = netdev_priv(net_dev);
121         struct efx_channel *channel;
122         unsigned int tx_usecs, rx_usecs;
123         bool adaptive, rx_may_override_tx;
124         int rc;
125
126         efx_get_irq_moderation(efx, &tx_usecs, &rx_usecs, &adaptive);
127
128         if (coalesce->rx_coalesce_usecs != rx_usecs)
129                 rx_usecs = coalesce->rx_coalesce_usecs;
130         else
131                 rx_usecs = coalesce->rx_coalesce_usecs_irq;
132
133         adaptive = coalesce->use_adaptive_rx_coalesce;
134
135         /* If channels are shared, TX IRQ moderation can be quietly
136          * overridden unless it is changed from its old value.
137          */
138         rx_may_override_tx = (coalesce->tx_coalesce_usecs == tx_usecs &&
139                               coalesce->tx_coalesce_usecs_irq == tx_usecs);
140         if (coalesce->tx_coalesce_usecs != tx_usecs)
141                 tx_usecs = coalesce->tx_coalesce_usecs;
142         else
143                 tx_usecs = coalesce->tx_coalesce_usecs_irq;
144
145         rc = efx_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive,
146                                      rx_may_override_tx);
147         if (rc != 0)
148                 return rc;
149
150         efx_for_each_channel(channel, efx)
151                 efx->type->push_irq_moderation(channel);
152
153         return 0;
154 }
155
156 static void efx_ethtool_get_ringparam(struct net_device *net_dev,
157                                       struct ethtool_ringparam *ring)
158 {
159         struct efx_nic *efx = netdev_priv(net_dev);
160
161         ring->rx_max_pending = EFX_MAX_DMAQ_SIZE;
162         ring->tx_max_pending = EFX_TXQ_MAX_ENT(efx);
163         ring->rx_pending = efx->rxq_entries;
164         ring->tx_pending = efx->txq_entries;
165 }
166
167 static int efx_ethtool_set_ringparam(struct net_device *net_dev,
168                                      struct ethtool_ringparam *ring)
169 {
170         struct efx_nic *efx = netdev_priv(net_dev);
171         u32 txq_entries;
172
173         if (ring->rx_mini_pending || ring->rx_jumbo_pending ||
174             ring->rx_pending > EFX_MAX_DMAQ_SIZE ||
175             ring->tx_pending > EFX_TXQ_MAX_ENT(efx))
176                 return -EINVAL;
177
178         if (ring->rx_pending < EFX_RXQ_MIN_ENT) {
179                 netif_err(efx, drv, efx->net_dev,
180                           "RX queues cannot be smaller than %u\n",
181                           EFX_RXQ_MIN_ENT);
182                 return -EINVAL;
183         }
184
185         txq_entries = max(ring->tx_pending, EFX_TXQ_MIN_ENT(efx));
186         if (txq_entries != ring->tx_pending)
187                 netif_warn(efx, drv, efx->net_dev,
188                            "increasing TX queue size to minimum of %u\n",
189                            txq_entries);
190
191         return efx_realloc_channels(efx, ring->rx_pending, txq_entries);
192 }
193
194 static void efx_ethtool_get_wol(struct net_device *net_dev,
195                                 struct ethtool_wolinfo *wol)
196 {
197         struct efx_nic *efx = netdev_priv(net_dev);
198         return efx->type->get_wol(efx, wol);
199 }
200
201
202 static int efx_ethtool_set_wol(struct net_device *net_dev,
203                                struct ethtool_wolinfo *wol)
204 {
205         struct efx_nic *efx = netdev_priv(net_dev);
206         return efx->type->set_wol(efx, wol->wolopts);
207 }
208
209 static int efx_ethtool_get_ts_info(struct net_device *net_dev,
210                                    struct ethtool_ts_info *ts_info)
211 {
212         struct efx_nic *efx = netdev_priv(net_dev);
213
214         /* Software capabilities */
215         ts_info->so_timestamping = (SOF_TIMESTAMPING_RX_SOFTWARE |
216                                     SOF_TIMESTAMPING_SOFTWARE);
217         ts_info->phc_index = -1;
218
219         efx_ptp_get_ts_info(efx, ts_info);
220         return 0;
221 }
222
223 const struct ethtool_ops efx_ethtool_ops = {
224         .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
225                                      ETHTOOL_COALESCE_USECS_IRQ |
226                                      ETHTOOL_COALESCE_USE_ADAPTIVE_RX,
227         .get_drvinfo            = efx_ethtool_get_drvinfo,
228         .get_regs_len           = efx_ethtool_get_regs_len,
229         .get_regs               = efx_ethtool_get_regs,
230         .get_msglevel           = efx_ethtool_get_msglevel,
231         .set_msglevel           = efx_ethtool_set_msglevel,
232         .get_link               = ethtool_op_get_link,
233         .get_coalesce           = efx_ethtool_get_coalesce,
234         .set_coalesce           = efx_ethtool_set_coalesce,
235         .get_ringparam          = efx_ethtool_get_ringparam,
236         .set_ringparam          = efx_ethtool_set_ringparam,
237         .get_pauseparam         = efx_ethtool_get_pauseparam,
238         .set_pauseparam         = efx_ethtool_set_pauseparam,
239         .get_sset_count         = efx_ethtool_get_sset_count,
240         .self_test              = efx_ethtool_self_test,
241         .get_strings            = efx_ethtool_get_strings,
242         .set_phys_id            = efx_ethtool_phys_id,
243         .get_ethtool_stats      = efx_ethtool_get_stats,
244         .get_wol                = efx_ethtool_get_wol,
245         .set_wol                = efx_ethtool_set_wol,
246         .reset                  = efx_ethtool_reset,
247         .get_rxnfc              = efx_ethtool_get_rxnfc,
248         .set_rxnfc              = efx_ethtool_set_rxnfc,
249         .get_rxfh_indir_size    = efx_ethtool_get_rxfh_indir_size,
250         .get_rxfh_key_size      = efx_ethtool_get_rxfh_key_size,
251         .get_rxfh               = efx_ethtool_get_rxfh,
252         .set_rxfh               = efx_ethtool_set_rxfh,
253         .get_rxfh_context       = efx_ethtool_get_rxfh_context,
254         .set_rxfh_context       = efx_ethtool_set_rxfh_context,
255         .get_ts_info            = efx_ethtool_get_ts_info,
256         .get_module_info        = efx_ethtool_get_module_info,
257         .get_module_eeprom      = efx_ethtool_get_module_eeprom,
258         .get_link_ksettings     = efx_ethtool_get_link_ksettings,
259         .set_link_ksettings     = efx_ethtool_set_link_ksettings,
260         .get_fecparam           = efx_ethtool_get_fecparam,
261         .set_fecparam           = efx_ethtool_set_fecparam,
262 };