Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
8ceee660 | 2 | /**************************************************************************** |
f7a6d2c4 | 3 | * Driver for Solarflare network controllers and boards |
8ceee660 | 4 | * Copyright 2005-2006 Fen Systems Ltd. |
f7a6d2c4 | 5 | * Copyright 2006-2013 Solarflare Communications Inc. |
8ceee660 BH |
6 | */ |
7 | ||
8 | #include <linux/netdevice.h> | |
9 | #include <linux/ethtool.h> | |
10 | #include <linux/rtnetlink.h> | |
c39d35eb | 11 | #include <linux/in.h> |
8ceee660 | 12 | #include "net_driver.h" |
04cc8cac | 13 | #include "workarounds.h" |
3273c2e8 | 14 | #include "selftest.h" |
8ceee660 | 15 | #include "efx.h" |
e1253f39 AM |
16 | #include "efx_channels.h" |
17 | #include "rx_common.h" | |
18 | #include "tx_common.h" | |
3653954d | 19 | #include "ethtool_common.h" |
b4187e42 | 20 | #include "filter.h" |
744093c9 | 21 | #include "nic.h" |
8ceee660 | 22 | |
4a5b504d | 23 | #define EFX_ETHTOOL_EEPROM_MAGIC 0xEFAB |
4a5b504d | 24 | |
8ceee660 BH |
25 | /************************************************************************** |
26 | * | |
27 | * Ethtool operations | |
28 | * | |
29 | ************************************************************************** | |
30 | */ | |
31 | ||
32 | /* Identify device by flashing LEDs */ | |
c5e129ac BH |
33 | static int efx_ethtool_phys_id(struct net_device *net_dev, |
34 | enum ethtool_phys_id_state state) | |
8ceee660 | 35 | { |
8cb03f4e | 36 | struct efx_nic *efx = efx_netdev_priv(net_dev); |
fce55922 | 37 | enum efx_led_mode mode = EFX_LED_DEFAULT; |
8ceee660 | 38 | |
c5e129ac BH |
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; | |
fce55922 AB |
49 | case ETHTOOL_ID_ACTIVE: |
50 | return 1; /* cycle on/off once per second */ | |
c5e129ac | 51 | } |
398468ed | 52 | |
f2ed621f | 53 | return efx_mcdi_set_id_led(efx, mode); |
8ceee660 BH |
54 | } |
55 | ||
5b98c1bf BH |
56 | static int efx_ethtool_get_regs_len(struct net_device *net_dev) |
57 | { | |
8cb03f4e | 58 | return efx_nic_get_regs_len(efx_netdev_priv(net_dev)); |
5b98c1bf BH |
59 | } |
60 | ||
61 | static void efx_ethtool_get_regs(struct net_device *net_dev, | |
62 | struct ethtool_regs *regs, void *buf) | |
63 | { | |
8cb03f4e | 64 | struct efx_nic *efx = efx_netdev_priv(net_dev); |
5b98c1bf BH |
65 | |
66 | regs->version = efx->type->revision; | |
67 | efx_nic_get_regs(efx, buf); | |
68 | } | |
69 | ||
a0c4faf5 BH |
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 | * | |
13225977 BH |
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 | * | |
a0c4faf5 BH |
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 | ||
8ceee660 | 99 | static int efx_ethtool_get_coalesce(struct net_device *net_dev, |
f3ccfda1 YM |
100 | struct ethtool_coalesce *coalesce, |
101 | struct kernel_ethtool_coalesce *kernel_coal, | |
102 | struct netlink_ext_ack *extack) | |
8ceee660 | 103 | { |
8cb03f4e | 104 | struct efx_nic *efx = efx_netdev_priv(net_dev); |
a0c4faf5 BH |
105 | unsigned int tx_usecs, rx_usecs; |
106 | bool rx_adaptive; | |
8ceee660 | 107 | |
a0c4faf5 | 108 | efx_get_irq_moderation(efx, &tx_usecs, &rx_usecs, &rx_adaptive); |
8ceee660 | 109 | |
13225977 | 110 | coalesce->tx_coalesce_usecs = tx_usecs; |
a0c4faf5 | 111 | coalesce->tx_coalesce_usecs_irq = tx_usecs; |
13225977 | 112 | coalesce->rx_coalesce_usecs = rx_usecs; |
a0c4faf5 BH |
113 | coalesce->rx_coalesce_usecs_irq = rx_usecs; |
114 | coalesce->use_adaptive_rx_coalesce = rx_adaptive; | |
0d86ebd8 | 115 | |
8ceee660 BH |
116 | return 0; |
117 | } | |
118 | ||
8ceee660 | 119 | static int efx_ethtool_set_coalesce(struct net_device *net_dev, |
f3ccfda1 YM |
120 | struct ethtool_coalesce *coalesce, |
121 | struct kernel_ethtool_coalesce *kernel_coal, | |
122 | struct netlink_ext_ack *extack) | |
8ceee660 | 123 | { |
8cb03f4e | 124 | struct efx_nic *efx = efx_netdev_priv(net_dev); |
8ceee660 | 125 | struct efx_channel *channel; |
b548f976 | 126 | unsigned int tx_usecs, rx_usecs; |
9e393b30 BH |
127 | bool adaptive, rx_may_override_tx; |
128 | int rc; | |
8ceee660 | 129 | |
a0c4faf5 BH |
130 | efx_get_irq_moderation(efx, &tx_usecs, &rx_usecs, &adaptive); |
131 | ||
13225977 BH |
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 | ||
6fb70fd1 | 137 | adaptive = coalesce->use_adaptive_rx_coalesce; |
8ceee660 | 138 | |
a0c4faf5 BH |
139 | /* If channels are shared, TX IRQ moderation can be quietly |
140 | * overridden unless it is changed from its old value. | |
141 | */ | |
13225977 BH |
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; | |
8ceee660 | 148 | |
9e393b30 BH |
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 | ||
8ceee660 | 154 | efx_for_each_channel(channel, efx) |
ef2b90ee | 155 | efx->type->push_irq_moderation(channel); |
8ceee660 BH |
156 | |
157 | return 0; | |
158 | } | |
159 | ||
74624944 HC |
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) | |
4642610c | 165 | { |
8cb03f4e | 166 | struct efx_nic *efx = efx_netdev_priv(net_dev); |
4642610c BH |
167 | |
168 | ring->rx_max_pending = EFX_MAX_DMAQ_SIZE; | |
d9317aea | 169 | ring->tx_max_pending = EFX_TXQ_MAX_ENT(efx); |
4642610c BH |
170 | ring->rx_pending = efx->rxq_entries; |
171 | ring->tx_pending = efx->txq_entries; | |
4642610c BH |
172 | } |
173 | ||
74624944 HC |
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) | |
4642610c | 179 | { |
8cb03f4e | 180 | struct efx_nic *efx = efx_netdev_priv(net_dev); |
7e6d06f0 | 181 | u32 txq_entries; |
4642610c BH |
182 | |
183 | if (ring->rx_mini_pending || ring->rx_jumbo_pending || | |
184 | ring->rx_pending > EFX_MAX_DMAQ_SIZE || | |
d9317aea | 185 | ring->tx_pending > EFX_TXQ_MAX_ENT(efx)) |
4642610c BH |
186 | return -EINVAL; |
187 | ||
7e6d06f0 | 188 | if (ring->rx_pending < EFX_RXQ_MIN_ENT) { |
4642610c | 189 | netif_err(efx, drv, efx->net_dev, |
7e6d06f0 BH |
190 | "RX queues cannot be smaller than %u\n", |
191 | EFX_RXQ_MIN_ENT); | |
4642610c BH |
192 | return -EINVAL; |
193 | } | |
194 | ||
7e6d06f0 BH |
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); | |
4642610c BH |
202 | } |
203 | ||
89c758fa BH |
204 | static void efx_ethtool_get_wol(struct net_device *net_dev, |
205 | struct ethtool_wolinfo *wol) | |
206 | { | |
8cb03f4e | 207 | struct efx_nic *efx = efx_netdev_priv(net_dev); |
89c758fa BH |
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 | { | |
8cb03f4e | 215 | struct efx_nic *efx = efx_netdev_priv(net_dev); |
89c758fa BH |
216 | return efx->type->set_wol(efx, wol->wolopts); |
217 | } | |
218 | ||
cab351be JK |
219 | static void efx_ethtool_get_fec_stats(struct net_device *net_dev, |
220 | struct ethtool_fec_stats *fec_stats) | |
221 | { | |
8cb03f4e | 222 | struct efx_nic *efx = efx_netdev_priv(net_dev); |
cab351be JK |
223 | |
224 | if (efx->type->get_fec_stats) | |
225 | efx->type->get_fec_stats(efx, fec_stats); | |
226 | } | |
227 | ||
b51ca34a FW |
228 | static int efx_ethtool_get_ts_info(struct net_device *net_dev, |
229 | struct ethtool_ts_info *ts_info) | |
62ebac92 | 230 | { |
8cb03f4e | 231 | struct efx_nic *efx = efx_netdev_priv(net_dev); |
62ebac92 BH |
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 | ||
0fc0b732 | 242 | const struct ethtool_ops efx_ethtool_ops = { |
eff87b4f JK |
243 | .supported_coalesce_params = ETHTOOL_COALESCE_USECS | |
244 | ETHTOOL_COALESCE_USECS_IRQ | | |
245 | ETHTOOL_COALESCE_USE_ADAPTIVE_RX, | |
8ceee660 | 246 | .get_drvinfo = efx_ethtool_get_drvinfo, |
5b98c1bf BH |
247 | .get_regs_len = efx_ethtool_get_regs_len, |
248 | .get_regs = efx_ethtool_get_regs, | |
62776d03 BH |
249 | .get_msglevel = efx_ethtool_get_msglevel, |
250 | .set_msglevel = efx_ethtool_set_msglevel, | |
ed4ba4b5 | 251 | .get_link = ethtool_op_get_link, |
8ceee660 BH |
252 | .get_coalesce = efx_ethtool_get_coalesce, |
253 | .set_coalesce = efx_ethtool_set_coalesce, | |
4642610c BH |
254 | .get_ringparam = efx_ethtool_get_ringparam, |
255 | .set_ringparam = efx_ethtool_set_ringparam, | |
8ceee660 BH |
256 | .get_pauseparam = efx_ethtool_get_pauseparam, |
257 | .set_pauseparam = efx_ethtool_set_pauseparam, | |
3594e131 | 258 | .get_sset_count = efx_ethtool_get_sset_count, |
3273c2e8 | 259 | .self_test = efx_ethtool_self_test, |
8ceee660 | 260 | .get_strings = efx_ethtool_get_strings, |
c5e129ac | 261 | .set_phys_id = efx_ethtool_phys_id, |
8ceee660 | 262 | .get_ethtool_stats = efx_ethtool_get_stats, |
89c758fa BH |
263 | .get_wol = efx_ethtool_get_wol, |
264 | .set_wol = efx_ethtool_set_wol, | |
eb9f6744 | 265 | .reset = efx_ethtool_reset, |
765c9f46 | 266 | .get_rxnfc = efx_ethtool_get_rxnfc, |
b2bb7b77 | 267 | .set_rxnfc = efx_ethtool_set_rxnfc, |
7850f63f | 268 | .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size, |
f74d1995 | 269 | .get_rxfh_key_size = efx_ethtool_get_rxfh_key_size, |
fe62d001 BH |
270 | .get_rxfh = efx_ethtool_get_rxfh, |
271 | .set_rxfh = efx_ethtool_set_rxfh, | |
42356d9a EC |
272 | .get_rxfh_context = efx_ethtool_get_rxfh_context, |
273 | .set_rxfh_context = efx_ethtool_set_rxfh_context, | |
62ebac92 | 274 | .get_ts_info = efx_ethtool_get_ts_info, |
c087bd2c SH |
275 | .get_module_info = efx_ethtool_get_module_info, |
276 | .get_module_eeprom = efx_ethtool_get_module_eeprom, | |
7cafe8f8 PR |
277 | .get_link_ksettings = efx_ethtool_get_link_ksettings, |
278 | .set_link_ksettings = efx_ethtool_set_link_ksettings, | |
cab351be | 279 | .get_fec_stats = efx_ethtool_get_fec_stats, |
7f61e6c6 EC |
280 | .get_fecparam = efx_ethtool_get_fecparam, |
281 | .set_fecparam = efx_ethtool_set_fecparam, | |
8ceee660 | 282 | }; |