1 | /* |
2 | * Copyright (c) 2015, Mellanox Technologies. All rights reserved. |
3 | * |
4 | * This software is available to you under a choice of one of two |
5 | * licenses. You may choose to be licensed under the terms of the GNU |
6 | * General Public License (GPL) Version 2, available from the file |
7 | * COPYING in the main directory of this source tree, or the |
8 | * OpenIB.org BSD license below: |
9 | * |
10 | * Redistribution and use in source and binary forms, with or |
11 | * without modification, are permitted provided that the following |
12 | * conditions are met: |
13 | * |
14 | * - Redistributions of source code must retain the above |
15 | * copyright notice, this list of conditions and the following |
16 | * disclaimer. |
17 | * |
18 | * - Redistributions in binary form must reproduce the above |
19 | * copyright notice, this list of conditions and the following |
20 | * disclaimer in the documentation and/or other materials |
21 | * provided with the distribution. |
22 | * |
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
30 | * SOFTWARE. |
31 | */ |
32 | |
33 | #include <linux/ethtool_netlink.h> |
34 | |
35 | #include "en.h" |
36 | #include "en/port.h" |
37 | #include "en/params.h" |
38 | #include "en/ptp.h" |
39 | #include "lib/clock.h" |
40 | #include "en/fs_ethtool.h" |
41 | |
42 | void mlx5e_ethtool_get_drvinfo(struct mlx5e_priv *priv, |
43 | struct ethtool_drvinfo *drvinfo) |
44 | { |
45 | struct mlx5_core_dev *mdev = priv->mdev; |
46 | int count; |
47 | |
48 | strscpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver)); |
49 | count = snprintf(buf: drvinfo->fw_version, size: sizeof(drvinfo->fw_version), |
50 | fmt: "%d.%d.%04d (%.16s)" , fw_rev_maj(dev: mdev), |
51 | fw_rev_min(dev: mdev), fw_rev_sub(dev: mdev), mdev->board_id); |
52 | if (count >= sizeof(drvinfo->fw_version)) |
53 | snprintf(buf: drvinfo->fw_version, size: sizeof(drvinfo->fw_version), |
54 | fmt: "%d.%d.%04d" , fw_rev_maj(dev: mdev), |
55 | fw_rev_min(dev: mdev), fw_rev_sub(dev: mdev)); |
56 | |
57 | strscpy(drvinfo->bus_info, dev_name(mdev->device), |
58 | sizeof(drvinfo->bus_info)); |
59 | } |
60 | |
61 | static void mlx5e_get_drvinfo(struct net_device *dev, |
62 | struct ethtool_drvinfo *drvinfo) |
63 | { |
64 | struct mlx5e_priv *priv = netdev_priv(dev); |
65 | |
66 | mlx5e_ethtool_get_drvinfo(priv, drvinfo); |
67 | } |
68 | |
69 | struct ptys2ethtool_config { |
70 | __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); |
71 | __ETHTOOL_DECLARE_LINK_MODE_MASK(advertised); |
72 | }; |
73 | |
74 | static |
75 | struct ptys2ethtool_config ptys2legacy_ethtool_table[MLX5E_LINK_MODES_NUMBER]; |
76 | static |
77 | struct ptys2ethtool_config ptys2ext_ethtool_table[MLX5E_EXT_LINK_MODES_NUMBER]; |
78 | |
79 | #define MLX5_BUILD_PTYS2ETHTOOL_CONFIG(reg_, table, ...) \ |
80 | ({ \ |
81 | struct ptys2ethtool_config *cfg; \ |
82 | const unsigned int modes[] = { __VA_ARGS__ }; \ |
83 | unsigned int i, bit, idx; \ |
84 | cfg = &ptys2##table##_ethtool_table[reg_]; \ |
85 | bitmap_zero(cfg->supported, \ |
86 | __ETHTOOL_LINK_MODE_MASK_NBITS); \ |
87 | bitmap_zero(cfg->advertised, \ |
88 | __ETHTOOL_LINK_MODE_MASK_NBITS); \ |
89 | for (i = 0 ; i < ARRAY_SIZE(modes) ; ++i) { \ |
90 | bit = modes[i] % 64; \ |
91 | idx = modes[i] / 64; \ |
92 | __set_bit(bit, &cfg->supported[idx]); \ |
93 | __set_bit(bit, &cfg->advertised[idx]); \ |
94 | } \ |
95 | }) |
96 | |
97 | void mlx5e_build_ptys2ethtool_map(void) |
98 | { |
99 | memset(ptys2legacy_ethtool_table, 0, sizeof(ptys2legacy_ethtool_table)); |
100 | memset(ptys2ext_ethtool_table, 0, sizeof(ptys2ext_ethtool_table)); |
101 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_1000BASE_CX_SGMII, legacy, |
102 | ETHTOOL_LINK_MODE_1000baseKX_Full_BIT); |
103 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_1000BASE_KX, legacy, |
104 | ETHTOOL_LINK_MODE_1000baseKX_Full_BIT); |
105 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_CX4, legacy, |
106 | ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT); |
107 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_KX4, legacy, |
108 | ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT); |
109 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_KR, legacy, |
110 | ETHTOOL_LINK_MODE_10000baseKR_Full_BIT); |
111 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_20GBASE_KR2, legacy, |
112 | ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT); |
113 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_40GBASE_CR4, legacy, |
114 | ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT); |
115 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_40GBASE_KR4, legacy, |
116 | ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT); |
117 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_56GBASE_R4, legacy, |
118 | ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT); |
119 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_CR, legacy, |
120 | ETHTOOL_LINK_MODE_10000baseKR_Full_BIT); |
121 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_SR, legacy, |
122 | ETHTOOL_LINK_MODE_10000baseKR_Full_BIT); |
123 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_ER, legacy, |
124 | ETHTOOL_LINK_MODE_10000baseKR_Full_BIT); |
125 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_40GBASE_SR4, legacy, |
126 | ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT); |
127 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_40GBASE_LR4, legacy, |
128 | ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT); |
129 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_50GBASE_SR2, legacy, |
130 | ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT); |
131 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_100GBASE_CR4, legacy, |
132 | ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT); |
133 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_100GBASE_SR4, legacy, |
134 | ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT); |
135 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_100GBASE_KR4, legacy, |
136 | ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT); |
137 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_100GBASE_LR4, legacy, |
138 | ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT); |
139 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_T, legacy, |
140 | ETHTOOL_LINK_MODE_10000baseT_Full_BIT); |
141 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_25GBASE_CR, legacy, |
142 | ETHTOOL_LINK_MODE_25000baseCR_Full_BIT); |
143 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_25GBASE_KR, legacy, |
144 | ETHTOOL_LINK_MODE_25000baseKR_Full_BIT); |
145 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_25GBASE_SR, legacy, |
146 | ETHTOOL_LINK_MODE_25000baseSR_Full_BIT); |
147 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_50GBASE_CR2, legacy, |
148 | ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT); |
149 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_50GBASE_KR2, legacy, |
150 | ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT); |
151 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_SGMII_100M, ext, |
152 | ETHTOOL_LINK_MODE_100baseT_Full_BIT); |
153 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_1000BASE_X_SGMII, ext, |
154 | ETHTOOL_LINK_MODE_1000baseT_Full_BIT, |
155 | ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, |
156 | ETHTOOL_LINK_MODE_1000baseX_Full_BIT); |
157 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_5GBASE_R, ext, |
158 | ETHTOOL_LINK_MODE_5000baseT_Full_BIT); |
159 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_XFI_XAUI_1, ext, |
160 | ETHTOOL_LINK_MODE_10000baseT_Full_BIT, |
161 | ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, |
162 | ETHTOOL_LINK_MODE_10000baseR_FEC_BIT, |
163 | ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, |
164 | ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, |
165 | ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, |
166 | ETHTOOL_LINK_MODE_10000baseER_Full_BIT); |
167 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_40GBASE_XLAUI_4_XLPPI_4, ext, |
168 | ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, |
169 | ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, |
170 | ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, |
171 | ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT); |
172 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_25GAUI_1_25GBASE_CR_KR, ext, |
173 | ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, |
174 | ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, |
175 | ETHTOOL_LINK_MODE_25000baseSR_Full_BIT); |
176 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_50GAUI_2_LAUI_2_50GBASE_CR2_KR2, |
177 | ext, |
178 | ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, |
179 | ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, |
180 | ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT); |
181 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_50GAUI_1_LAUI_1_50GBASE_CR_KR, ext, |
182 | ETHTOOL_LINK_MODE_50000baseKR_Full_BIT, |
183 | ETHTOOL_LINK_MODE_50000baseSR_Full_BIT, |
184 | ETHTOOL_LINK_MODE_50000baseCR_Full_BIT, |
185 | ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, |
186 | ETHTOOL_LINK_MODE_50000baseDR_Full_BIT); |
187 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_CAUI_4_100GBASE_CR4_KR4, ext, |
188 | ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, |
189 | ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, |
190 | ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, |
191 | ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT); |
192 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_100GAUI_2_100GBASE_CR2_KR2, ext, |
193 | ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT, |
194 | ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT, |
195 | ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT, |
196 | ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT, |
197 | ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT); |
198 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_200GAUI_4_200GBASE_CR4_KR4, ext, |
199 | ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT, |
200 | ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT, |
201 | ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT, |
202 | ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT, |
203 | ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT); |
204 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_100GAUI_1_100GBASE_CR_KR, ext, |
205 | ETHTOOL_LINK_MODE_100000baseKR_Full_BIT, |
206 | ETHTOOL_LINK_MODE_100000baseSR_Full_BIT, |
207 | ETHTOOL_LINK_MODE_100000baseLR_ER_FR_Full_BIT, |
208 | ETHTOOL_LINK_MODE_100000baseDR_Full_BIT, |
209 | ETHTOOL_LINK_MODE_100000baseCR_Full_BIT); |
210 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_200GAUI_2_200GBASE_CR2_KR2, ext, |
211 | ETHTOOL_LINK_MODE_200000baseKR2_Full_BIT, |
212 | ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT, |
213 | ETHTOOL_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT, |
214 | ETHTOOL_LINK_MODE_200000baseDR2_Full_BIT, |
215 | ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT); |
216 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_400GAUI_4_400GBASE_CR4_KR4, ext, |
217 | ETHTOOL_LINK_MODE_400000baseKR4_Full_BIT, |
218 | ETHTOOL_LINK_MODE_400000baseSR4_Full_BIT, |
219 | ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT, |
220 | ETHTOOL_LINK_MODE_400000baseDR4_Full_BIT, |
221 | ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT); |
222 | } |
223 | |
224 | static void mlx5e_ethtool_get_speed_arr(struct mlx5_core_dev *mdev, |
225 | struct ptys2ethtool_config **arr, |
226 | u32 *size) |
227 | { |
228 | bool ext = mlx5_ptys_ext_supported(mdev); |
229 | |
230 | *arr = ext ? ptys2ext_ethtool_table : ptys2legacy_ethtool_table; |
231 | *size = ext ? ARRAY_SIZE(ptys2ext_ethtool_table) : |
232 | ARRAY_SIZE(ptys2legacy_ethtool_table); |
233 | } |
234 | |
235 | typedef int (*mlx5e_pflag_handler)(struct net_device *netdev, bool enable); |
236 | |
237 | struct pflag_desc { |
238 | char name[ETH_GSTRING_LEN]; |
239 | mlx5e_pflag_handler handler; |
240 | }; |
241 | |
242 | static const struct pflag_desc mlx5e_priv_flags[MLX5E_NUM_PFLAGS]; |
243 | |
244 | int mlx5e_ethtool_get_sset_count(struct mlx5e_priv *priv, int sset) |
245 | { |
246 | switch (sset) { |
247 | case ETH_SS_STATS: |
248 | return mlx5e_stats_total_num(priv); |
249 | case ETH_SS_PRIV_FLAGS: |
250 | return MLX5E_NUM_PFLAGS; |
251 | case ETH_SS_TEST: |
252 | return mlx5e_self_test_num(priv); |
253 | default: |
254 | return -EOPNOTSUPP; |
255 | } |
256 | } |
257 | |
258 | static int mlx5e_get_sset_count(struct net_device *dev, int sset) |
259 | { |
260 | struct mlx5e_priv *priv = netdev_priv(dev); |
261 | |
262 | return mlx5e_ethtool_get_sset_count(priv, sset); |
263 | } |
264 | |
265 | void mlx5e_ethtool_get_strings(struct mlx5e_priv *priv, u32 stringset, u8 *data) |
266 | { |
267 | int i; |
268 | |
269 | switch (stringset) { |
270 | case ETH_SS_PRIV_FLAGS: |
271 | for (i = 0; i < MLX5E_NUM_PFLAGS; i++) |
272 | strcpy(p: data + i * ETH_GSTRING_LEN, |
273 | q: mlx5e_priv_flags[i].name); |
274 | break; |
275 | |
276 | case ETH_SS_TEST: |
277 | mlx5e_self_test_fill_strings(priv, data); |
278 | break; |
279 | |
280 | case ETH_SS_STATS: |
281 | mlx5e_stats_fill_strings(priv, data); |
282 | break; |
283 | } |
284 | } |
285 | |
286 | static void mlx5e_get_strings(struct net_device *dev, u32 stringset, u8 *data) |
287 | { |
288 | struct mlx5e_priv *priv = netdev_priv(dev); |
289 | |
290 | mlx5e_ethtool_get_strings(priv, stringset, data); |
291 | } |
292 | |
293 | void mlx5e_ethtool_get_ethtool_stats(struct mlx5e_priv *priv, |
294 | struct ethtool_stats *stats, u64 *data) |
295 | { |
296 | int idx = 0; |
297 | |
298 | mutex_lock(&priv->state_lock); |
299 | mlx5e_stats_update(priv); |
300 | mutex_unlock(lock: &priv->state_lock); |
301 | |
302 | mlx5e_stats_fill(priv, data, idx); |
303 | } |
304 | |
305 | static void mlx5e_get_ethtool_stats(struct net_device *dev, |
306 | struct ethtool_stats *stats, |
307 | u64 *data) |
308 | { |
309 | struct mlx5e_priv *priv = netdev_priv(dev); |
310 | |
311 | mlx5e_ethtool_get_ethtool_stats(priv, stats, data); |
312 | } |
313 | |
314 | void mlx5e_ethtool_get_ringparam(struct mlx5e_priv *priv, |
315 | struct ethtool_ringparam *param, |
316 | struct kernel_ethtool_ringparam *kernel_param) |
317 | { |
318 | /* Limitation for regular RQ. XSK RQ may clamp the queue length in |
319 | * mlx5e_mpwqe_get_log_rq_size. |
320 | */ |
321 | u8 max_log_mpwrq_pkts = mlx5e_mpwrq_max_log_rq_pkts(mdev: priv->mdev, |
322 | PAGE_SHIFT, |
323 | umr_mode: MLX5E_MPWRQ_UMR_MODE_ALIGNED); |
324 | |
325 | param->rx_max_pending = 1 << min_t(u8, MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE, |
326 | max_log_mpwrq_pkts); |
327 | param->tx_max_pending = 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE; |
328 | param->rx_pending = 1 << priv->channels.params.log_rq_mtu_frames; |
329 | param->tx_pending = 1 << priv->channels.params.log_sq_size; |
330 | |
331 | kernel_param->tcp_data_split = |
332 | (priv->channels.params.packet_merge.type == MLX5E_PACKET_MERGE_SHAMPO) ? |
333 | ETHTOOL_TCP_DATA_SPLIT_ENABLED : |
334 | ETHTOOL_TCP_DATA_SPLIT_DISABLED; |
335 | } |
336 | |
337 | static void mlx5e_get_ringparam(struct net_device *dev, |
338 | struct ethtool_ringparam *param, |
339 | struct kernel_ethtool_ringparam *kernel_param, |
340 | struct netlink_ext_ack *extack) |
341 | { |
342 | struct mlx5e_priv *priv = netdev_priv(dev); |
343 | |
344 | mlx5e_ethtool_get_ringparam(priv, param, kernel_param); |
345 | } |
346 | |
347 | int mlx5e_ethtool_set_ringparam(struct mlx5e_priv *priv, |
348 | struct ethtool_ringparam *param) |
349 | { |
350 | struct mlx5e_params new_params; |
351 | u8 log_rq_size; |
352 | u8 log_sq_size; |
353 | int err = 0; |
354 | |
355 | if (param->rx_jumbo_pending) { |
356 | netdev_info(dev: priv->netdev, format: "%s: rx_jumbo_pending not supported\n" , |
357 | __func__); |
358 | return -EINVAL; |
359 | } |
360 | if (param->rx_mini_pending) { |
361 | netdev_info(dev: priv->netdev, format: "%s: rx_mini_pending not supported\n" , |
362 | __func__); |
363 | return -EINVAL; |
364 | } |
365 | |
366 | if (param->rx_pending < (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE)) { |
367 | netdev_info(dev: priv->netdev, format: "%s: rx_pending (%d) < min (%d)\n" , |
368 | __func__, param->rx_pending, |
369 | 1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE); |
370 | return -EINVAL; |
371 | } |
372 | |
373 | if (param->tx_pending < (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)) { |
374 | netdev_info(dev: priv->netdev, format: "%s: tx_pending (%d) < min (%d)\n" , |
375 | __func__, param->tx_pending, |
376 | 1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE); |
377 | return -EINVAL; |
378 | } |
379 | |
380 | log_rq_size = order_base_2(param->rx_pending); |
381 | log_sq_size = order_base_2(param->tx_pending); |
382 | |
383 | if (log_rq_size == priv->channels.params.log_rq_mtu_frames && |
384 | log_sq_size == priv->channels.params.log_sq_size) |
385 | return 0; |
386 | |
387 | mutex_lock(&priv->state_lock); |
388 | |
389 | new_params = priv->channels.params; |
390 | new_params.log_rq_mtu_frames = log_rq_size; |
391 | new_params.log_sq_size = log_sq_size; |
392 | |
393 | err = mlx5e_validate_params(mdev: priv->mdev, params: &new_params); |
394 | if (err) |
395 | goto unlock; |
396 | |
397 | err = mlx5e_safe_switch_params(priv, new_params: &new_params, NULL, NULL, reset: true); |
398 | |
399 | unlock: |
400 | mutex_unlock(lock: &priv->state_lock); |
401 | |
402 | return err; |
403 | } |
404 | |
405 | static int mlx5e_set_ringparam(struct net_device *dev, |
406 | struct ethtool_ringparam *param, |
407 | struct kernel_ethtool_ringparam *kernel_param, |
408 | struct netlink_ext_ack *extack) |
409 | { |
410 | struct mlx5e_priv *priv = netdev_priv(dev); |
411 | |
412 | return mlx5e_ethtool_set_ringparam(priv, param); |
413 | } |
414 | |
415 | void mlx5e_ethtool_get_channels(struct mlx5e_priv *priv, |
416 | struct ethtool_channels *ch) |
417 | { |
418 | mutex_lock(&priv->state_lock); |
419 | ch->max_combined = priv->max_nch; |
420 | ch->combined_count = priv->channels.params.num_channels; |
421 | mutex_unlock(lock: &priv->state_lock); |
422 | } |
423 | |
424 | static void mlx5e_get_channels(struct net_device *dev, |
425 | struct ethtool_channels *ch) |
426 | { |
427 | struct mlx5e_priv *priv = netdev_priv(dev); |
428 | |
429 | mlx5e_ethtool_get_channels(priv, ch); |
430 | } |
431 | |
432 | int mlx5e_ethtool_set_channels(struct mlx5e_priv *priv, |
433 | struct ethtool_channels *ch) |
434 | { |
435 | struct mlx5e_params *cur_params = &priv->channels.params; |
436 | unsigned int count = ch->combined_count; |
437 | struct mlx5e_params new_params; |
438 | bool arfs_enabled; |
439 | int ; |
440 | bool opened; |
441 | int err = 0; |
442 | |
443 | if (!count) { |
444 | netdev_info(dev: priv->netdev, format: "%s: combined_count=0 not supported\n" , |
445 | __func__); |
446 | return -EINVAL; |
447 | } |
448 | |
449 | if (cur_params->num_channels == count) |
450 | return 0; |
451 | |
452 | mutex_lock(&priv->state_lock); |
453 | |
454 | if (mlx5e_rx_res_get_current_hash(res: priv->rx_res).hfunc == ETH_RSS_HASH_XOR) { |
455 | unsigned int xor8_max_channels = mlx5e_rqt_max_num_channels_allowed_for_xor8(); |
456 | |
457 | if (count > xor8_max_channels) { |
458 | err = -EINVAL; |
459 | netdev_err(dev: priv->netdev, format: "%s: Requested number of channels (%d) exceeds the maximum allowed by the XOR8 RSS hfunc (%d)\n" , |
460 | __func__, count, xor8_max_channels); |
461 | goto out; |
462 | } |
463 | } |
464 | |
465 | /* If RXFH is configured, changing the channels number is allowed only if |
466 | * it does not require resizing the RSS table. This is because the previous |
467 | * configuration may no longer be compatible with the new RSS table. |
468 | */ |
469 | if (netif_is_rxfh_configured(dev: priv->netdev)) { |
470 | int cur_rqt_size = mlx5e_rqt_size(mdev: priv->mdev, num_channels: cur_params->num_channels); |
471 | int new_rqt_size = mlx5e_rqt_size(mdev: priv->mdev, num_channels: count); |
472 | |
473 | if (new_rqt_size != cur_rqt_size) { |
474 | err = -EINVAL; |
475 | netdev_err(dev: priv->netdev, |
476 | format: "%s: RXFH is configured, block changing channels number that affects RSS table size (new: %d, current: %d)\n" , |
477 | __func__, new_rqt_size, cur_rqt_size); |
478 | goto out; |
479 | } |
480 | } |
481 | |
482 | /* Don't allow changing the number of channels if HTB offload is active, |
483 | * because the numeration of the QoS SQs will change, while per-queue |
484 | * qdiscs are attached. |
485 | */ |
486 | if (mlx5e_selq_is_htb_enabled(selq: &priv->selq)) { |
487 | err = -EINVAL; |
488 | netdev_err(dev: priv->netdev, format: "%s: HTB offload is active, cannot change the number of channels\n" , |
489 | __func__); |
490 | goto out; |
491 | } |
492 | |
493 | /* Don't allow changing the number of channels if non-default RSS contexts exist, |
494 | * the kernel doesn't protect against set_channels operations that break them. |
495 | */ |
496 | rss_cnt = mlx5e_rx_res_rss_cnt(res: priv->rx_res) - 1; |
497 | if (rss_cnt) { |
498 | err = -EINVAL; |
499 | netdev_err(dev: priv->netdev, format: "%s: Non-default RSS contexts exist (%d), cannot change the number of channels\n" , |
500 | __func__, rss_cnt); |
501 | goto out; |
502 | } |
503 | |
504 | /* Don't allow changing the number of channels if MQPRIO mode channel offload is active, |
505 | * because it defines a partition over the channels queues. |
506 | */ |
507 | if (cur_params->mqprio.mode == TC_MQPRIO_MODE_CHANNEL) { |
508 | err = -EINVAL; |
509 | netdev_err(dev: priv->netdev, format: "%s: MQPRIO mode channel offload is active, cannot change the number of channels\n" , |
510 | __func__); |
511 | goto out; |
512 | } |
513 | |
514 | new_params = *cur_params; |
515 | new_params.num_channels = count; |
516 | |
517 | opened = test_bit(MLX5E_STATE_OPENED, &priv->state); |
518 | |
519 | arfs_enabled = opened && (priv->netdev->features & NETIF_F_NTUPLE); |
520 | if (arfs_enabled) |
521 | mlx5e_arfs_disable(fs: priv->fs); |
522 | |
523 | /* Switch to new channels, set new parameters and close old ones */ |
524 | err = mlx5e_safe_switch_params(priv, new_params: &new_params, |
525 | preactivate: mlx5e_num_channels_changed_ctx, NULL, reset: true); |
526 | |
527 | if (arfs_enabled) { |
528 | int err2 = mlx5e_arfs_enable(fs: priv->fs); |
529 | |
530 | if (err2) |
531 | netdev_err(dev: priv->netdev, format: "%s: mlx5e_arfs_enable failed: %d\n" , |
532 | __func__, err2); |
533 | } |
534 | |
535 | out: |
536 | mutex_unlock(lock: &priv->state_lock); |
537 | |
538 | return err; |
539 | } |
540 | |
541 | static int mlx5e_set_channels(struct net_device *dev, |
542 | struct ethtool_channels *ch) |
543 | { |
544 | struct mlx5e_priv *priv = netdev_priv(dev); |
545 | |
546 | return mlx5e_ethtool_set_channels(priv, ch); |
547 | } |
548 | |
549 | int mlx5e_ethtool_get_coalesce(struct mlx5e_priv *priv, |
550 | struct ethtool_coalesce *coal, |
551 | struct kernel_ethtool_coalesce *kernel_coal) |
552 | { |
553 | struct dim_cq_moder *rx_moder, *tx_moder; |
554 | |
555 | if (!MLX5_CAP_GEN(priv->mdev, cq_moderation)) |
556 | return -EOPNOTSUPP; |
557 | |
558 | rx_moder = &priv->channels.params.rx_cq_moderation; |
559 | coal->rx_coalesce_usecs = rx_moder->usec; |
560 | coal->rx_max_coalesced_frames = rx_moder->pkts; |
561 | coal->use_adaptive_rx_coalesce = priv->channels.params.rx_dim_enabled; |
562 | |
563 | tx_moder = &priv->channels.params.tx_cq_moderation; |
564 | coal->tx_coalesce_usecs = tx_moder->usec; |
565 | coal->tx_max_coalesced_frames = tx_moder->pkts; |
566 | coal->use_adaptive_tx_coalesce = priv->channels.params.tx_dim_enabled; |
567 | |
568 | kernel_coal->use_cqe_mode_rx = |
569 | MLX5E_GET_PFLAG(&priv->channels.params, MLX5E_PFLAG_RX_CQE_BASED_MODER); |
570 | kernel_coal->use_cqe_mode_tx = |
571 | MLX5E_GET_PFLAG(&priv->channels.params, MLX5E_PFLAG_TX_CQE_BASED_MODER); |
572 | |
573 | return 0; |
574 | } |
575 | |
576 | static int mlx5e_get_coalesce(struct net_device *netdev, |
577 | struct ethtool_coalesce *coal, |
578 | struct kernel_ethtool_coalesce *kernel_coal, |
579 | struct netlink_ext_ack *extack) |
580 | { |
581 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
582 | |
583 | return mlx5e_ethtool_get_coalesce(priv, coal, kernel_coal); |
584 | } |
585 | |
586 | #define MLX5E_MAX_COAL_TIME MLX5_MAX_CQ_PERIOD |
587 | #define MLX5E_MAX_COAL_FRAMES MLX5_MAX_CQ_COUNT |
588 | |
589 | static void |
590 | mlx5e_set_priv_channels_tx_coalesce(struct mlx5e_priv *priv, struct ethtool_coalesce *coal) |
591 | { |
592 | int tc; |
593 | int i; |
594 | |
595 | for (i = 0; i < priv->channels.num; ++i) { |
596 | struct mlx5e_channel *c = priv->channels.c[i]; |
597 | struct mlx5_core_dev *mdev = c->mdev; |
598 | |
599 | for (tc = 0; tc < c->num_tc; tc++) { |
600 | mlx5_core_modify_cq_moderation(dev: mdev, |
601 | cq: &c->sq[tc].cq.mcq, |
602 | cq_period: coal->tx_coalesce_usecs, |
603 | cq_max_count: coal->tx_max_coalesced_frames); |
604 | } |
605 | } |
606 | } |
607 | |
608 | static void |
609 | mlx5e_set_priv_channels_rx_coalesce(struct mlx5e_priv *priv, struct ethtool_coalesce *coal) |
610 | { |
611 | int i; |
612 | |
613 | for (i = 0; i < priv->channels.num; ++i) { |
614 | struct mlx5e_channel *c = priv->channels.c[i]; |
615 | struct mlx5_core_dev *mdev = c->mdev; |
616 | |
617 | mlx5_core_modify_cq_moderation(dev: mdev, cq: &c->rq.cq.mcq, |
618 | cq_period: coal->rx_coalesce_usecs, |
619 | cq_max_count: coal->rx_max_coalesced_frames); |
620 | } |
621 | } |
622 | |
623 | /* convert a boolean value of cq_mode to mlx5 period mode |
624 | * true : MLX5_CQ_PERIOD_MODE_START_FROM_CQE |
625 | * false : MLX5_CQ_PERIOD_MODE_START_FROM_EQE |
626 | */ |
627 | static int cqe_mode_to_period_mode(bool val) |
628 | { |
629 | return val ? MLX5_CQ_PERIOD_MODE_START_FROM_CQE : MLX5_CQ_PERIOD_MODE_START_FROM_EQE; |
630 | } |
631 | |
632 | int mlx5e_ethtool_set_coalesce(struct mlx5e_priv *priv, |
633 | struct ethtool_coalesce *coal, |
634 | struct kernel_ethtool_coalesce *kernel_coal, |
635 | struct netlink_ext_ack *extack) |
636 | { |
637 | struct dim_cq_moder *rx_moder, *tx_moder; |
638 | struct mlx5_core_dev *mdev = priv->mdev; |
639 | struct mlx5e_params new_params; |
640 | bool reset_rx, reset_tx; |
641 | bool reset = true; |
642 | u8 cq_period_mode; |
643 | int err = 0; |
644 | |
645 | if (!MLX5_CAP_GEN(mdev, cq_moderation)) |
646 | return -EOPNOTSUPP; |
647 | |
648 | if (coal->tx_coalesce_usecs > MLX5E_MAX_COAL_TIME || |
649 | coal->rx_coalesce_usecs > MLX5E_MAX_COAL_TIME) { |
650 | netdev_info(dev: priv->netdev, format: "%s: maximum coalesce time supported is %lu usecs\n" , |
651 | __func__, MLX5E_MAX_COAL_TIME); |
652 | return -ERANGE; |
653 | } |
654 | |
655 | if (coal->tx_max_coalesced_frames > MLX5E_MAX_COAL_FRAMES || |
656 | coal->rx_max_coalesced_frames > MLX5E_MAX_COAL_FRAMES) { |
657 | netdev_info(dev: priv->netdev, format: "%s: maximum coalesced frames supported is %lu\n" , |
658 | __func__, MLX5E_MAX_COAL_FRAMES); |
659 | return -ERANGE; |
660 | } |
661 | |
662 | if ((kernel_coal->use_cqe_mode_rx || kernel_coal->use_cqe_mode_tx) && |
663 | !MLX5_CAP_GEN(priv->mdev, cq_period_start_from_cqe)) { |
664 | NL_SET_ERR_MSG_MOD(extack, "cqe_mode_rx/tx is not supported on this device" ); |
665 | return -EOPNOTSUPP; |
666 | } |
667 | |
668 | mutex_lock(&priv->state_lock); |
669 | new_params = priv->channels.params; |
670 | |
671 | rx_moder = &new_params.rx_cq_moderation; |
672 | rx_moder->usec = coal->rx_coalesce_usecs; |
673 | rx_moder->pkts = coal->rx_max_coalesced_frames; |
674 | new_params.rx_dim_enabled = !!coal->use_adaptive_rx_coalesce; |
675 | |
676 | tx_moder = &new_params.tx_cq_moderation; |
677 | tx_moder->usec = coal->tx_coalesce_usecs; |
678 | tx_moder->pkts = coal->tx_max_coalesced_frames; |
679 | new_params.tx_dim_enabled = !!coal->use_adaptive_tx_coalesce; |
680 | |
681 | reset_rx = !!coal->use_adaptive_rx_coalesce != priv->channels.params.rx_dim_enabled; |
682 | reset_tx = !!coal->use_adaptive_tx_coalesce != priv->channels.params.tx_dim_enabled; |
683 | |
684 | cq_period_mode = cqe_mode_to_period_mode(val: kernel_coal->use_cqe_mode_rx); |
685 | if (cq_period_mode != rx_moder->cq_period_mode) { |
686 | mlx5e_set_rx_cq_mode_params(params: &new_params, cq_period_mode); |
687 | reset_rx = true; |
688 | } |
689 | |
690 | cq_period_mode = cqe_mode_to_period_mode(val: kernel_coal->use_cqe_mode_tx); |
691 | if (cq_period_mode != tx_moder->cq_period_mode) { |
692 | mlx5e_set_tx_cq_mode_params(params: &new_params, cq_period_mode); |
693 | reset_tx = true; |
694 | } |
695 | |
696 | if (reset_rx) { |
697 | u8 mode = MLX5E_GET_PFLAG(&new_params, |
698 | MLX5E_PFLAG_RX_CQE_BASED_MODER); |
699 | |
700 | mlx5e_reset_rx_moderation(params: &new_params, cq_period_mode: mode); |
701 | } |
702 | if (reset_tx) { |
703 | u8 mode = MLX5E_GET_PFLAG(&new_params, |
704 | MLX5E_PFLAG_TX_CQE_BASED_MODER); |
705 | |
706 | mlx5e_reset_tx_moderation(params: &new_params, cq_period_mode: mode); |
707 | } |
708 | |
709 | /* If DIM state hasn't changed, it's possible to modify interrupt |
710 | * moderation parameters on the fly, even if the channels are open. |
711 | */ |
712 | if (!reset_rx && !reset_tx && test_bit(MLX5E_STATE_OPENED, &priv->state)) { |
713 | if (!coal->use_adaptive_rx_coalesce) |
714 | mlx5e_set_priv_channels_rx_coalesce(priv, coal); |
715 | if (!coal->use_adaptive_tx_coalesce) |
716 | mlx5e_set_priv_channels_tx_coalesce(priv, coal); |
717 | reset = false; |
718 | } |
719 | |
720 | err = mlx5e_safe_switch_params(priv, new_params: &new_params, NULL, NULL, reset); |
721 | |
722 | mutex_unlock(lock: &priv->state_lock); |
723 | return err; |
724 | } |
725 | |
726 | static int mlx5e_set_coalesce(struct net_device *netdev, |
727 | struct ethtool_coalesce *coal, |
728 | struct kernel_ethtool_coalesce *kernel_coal, |
729 | struct netlink_ext_ack *extack) |
730 | { |
731 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
732 | |
733 | return mlx5e_ethtool_set_coalesce(priv, coal, kernel_coal, extack); |
734 | } |
735 | |
736 | static void ptys2ethtool_supported_link(struct mlx5_core_dev *mdev, |
737 | unsigned long *supported_modes, |
738 | u32 eth_proto_cap) |
739 | { |
740 | unsigned long proto_cap = eth_proto_cap; |
741 | struct ptys2ethtool_config *table; |
742 | u32 max_size; |
743 | int proto; |
744 | |
745 | mlx5e_ethtool_get_speed_arr(mdev, arr: &table, size: &max_size); |
746 | for_each_set_bit(proto, &proto_cap, max_size) |
747 | bitmap_or(dst: supported_modes, src1: supported_modes, |
748 | src2: table[proto].supported, |
749 | nbits: __ETHTOOL_LINK_MODE_MASK_NBITS); |
750 | } |
751 | |
752 | static void ptys2ethtool_adver_link(unsigned long *advertising_modes, |
753 | u32 eth_proto_cap, bool ext) |
754 | { |
755 | unsigned long proto_cap = eth_proto_cap; |
756 | struct ptys2ethtool_config *table; |
757 | u32 max_size; |
758 | int proto; |
759 | |
760 | table = ext ? ptys2ext_ethtool_table : ptys2legacy_ethtool_table; |
761 | max_size = ext ? ARRAY_SIZE(ptys2ext_ethtool_table) : |
762 | ARRAY_SIZE(ptys2legacy_ethtool_table); |
763 | |
764 | for_each_set_bit(proto, &proto_cap, max_size) |
765 | bitmap_or(dst: advertising_modes, src1: advertising_modes, |
766 | src2: table[proto].advertised, |
767 | nbits: __ETHTOOL_LINK_MODE_MASK_NBITS); |
768 | } |
769 | |
770 | static const u32 pplm_fec_2_ethtool[] = { |
771 | [MLX5E_FEC_NOFEC] = ETHTOOL_FEC_OFF, |
772 | [MLX5E_FEC_FIRECODE] = ETHTOOL_FEC_BASER, |
773 | [MLX5E_FEC_RS_528_514] = ETHTOOL_FEC_RS, |
774 | [MLX5E_FEC_RS_544_514] = ETHTOOL_FEC_RS, |
775 | [MLX5E_FEC_LLRS_272_257_1] = ETHTOOL_FEC_LLRS, |
776 | }; |
777 | |
778 | static u32 pplm2ethtool_fec(u_long fec_mode, unsigned long size) |
779 | { |
780 | int mode = 0; |
781 | |
782 | if (!fec_mode) |
783 | return ETHTOOL_FEC_AUTO; |
784 | |
785 | mode = find_first_bit(addr: &fec_mode, size); |
786 | |
787 | if (mode < ARRAY_SIZE(pplm_fec_2_ethtool)) |
788 | return pplm_fec_2_ethtool[mode]; |
789 | |
790 | return 0; |
791 | } |
792 | |
793 | #define MLX5E_ADVERTISE_SUPPORTED_FEC(mlx5_fec, ethtool_fec) \ |
794 | do { \ |
795 | if (mlx5e_fec_in_caps(dev, 1 << (mlx5_fec))) \ |
796 | __set_bit(ethtool_fec, \ |
797 | link_ksettings->link_modes.supported);\ |
798 | } while (0) |
799 | |
800 | static const u32 pplm_fec_2_ethtool_linkmodes[] = { |
801 | [MLX5E_FEC_NOFEC] = ETHTOOL_LINK_MODE_FEC_NONE_BIT, |
802 | [MLX5E_FEC_FIRECODE] = ETHTOOL_LINK_MODE_FEC_BASER_BIT, |
803 | [MLX5E_FEC_RS_528_514] = ETHTOOL_LINK_MODE_FEC_RS_BIT, |
804 | [MLX5E_FEC_RS_544_514] = ETHTOOL_LINK_MODE_FEC_RS_BIT, |
805 | [MLX5E_FEC_LLRS_272_257_1] = ETHTOOL_LINK_MODE_FEC_LLRS_BIT, |
806 | }; |
807 | |
808 | static int get_fec_supported_advertised(struct mlx5_core_dev *dev, |
809 | struct ethtool_link_ksettings *link_ksettings) |
810 | { |
811 | unsigned long active_fec_long; |
812 | u32 active_fec; |
813 | u32 bitn; |
814 | int err; |
815 | |
816 | err = mlx5e_get_fec_mode(dev, fec_mode_active: &active_fec, NULL); |
817 | if (err) |
818 | return (err == -EOPNOTSUPP) ? 0 : err; |
819 | |
820 | MLX5E_ADVERTISE_SUPPORTED_FEC(MLX5E_FEC_NOFEC, |
821 | ETHTOOL_LINK_MODE_FEC_NONE_BIT); |
822 | MLX5E_ADVERTISE_SUPPORTED_FEC(MLX5E_FEC_FIRECODE, |
823 | ETHTOOL_LINK_MODE_FEC_BASER_BIT); |
824 | MLX5E_ADVERTISE_SUPPORTED_FEC(MLX5E_FEC_RS_528_514, |
825 | ETHTOOL_LINK_MODE_FEC_RS_BIT); |
826 | MLX5E_ADVERTISE_SUPPORTED_FEC(MLX5E_FEC_LLRS_272_257_1, |
827 | ETHTOOL_LINK_MODE_FEC_LLRS_BIT); |
828 | |
829 | active_fec_long = active_fec; |
830 | /* active fec is a bit set, find out which bit is set and |
831 | * advertise the corresponding ethtool bit |
832 | */ |
833 | bitn = find_first_bit(addr: &active_fec_long, size: sizeof(active_fec_long) * BITS_PER_BYTE); |
834 | if (bitn < ARRAY_SIZE(pplm_fec_2_ethtool_linkmodes)) |
835 | __set_bit(pplm_fec_2_ethtool_linkmodes[bitn], |
836 | link_ksettings->link_modes.advertising); |
837 | |
838 | return 0; |
839 | } |
840 | |
841 | static void ptys2ethtool_supported_advertised_port(struct mlx5_core_dev *mdev, |
842 | struct ethtool_link_ksettings *link_ksettings, |
843 | u32 eth_proto_cap, u8 connector_type) |
844 | { |
845 | if (!MLX5_CAP_PCAM_FEATURE(mdev, ptys_connector_type)) { |
846 | if (eth_proto_cap & (MLX5E_PROT_MASK(MLX5E_10GBASE_CR) |
847 | | MLX5E_PROT_MASK(MLX5E_10GBASE_SR) |
848 | | MLX5E_PROT_MASK(MLX5E_40GBASE_CR4) |
849 | | MLX5E_PROT_MASK(MLX5E_40GBASE_SR4) |
850 | | MLX5E_PROT_MASK(MLX5E_100GBASE_SR4) |
851 | | MLX5E_PROT_MASK(MLX5E_1000BASE_CX_SGMII))) { |
852 | ethtool_link_ksettings_add_link_mode(link_ksettings, |
853 | supported, |
854 | FIBRE); |
855 | ethtool_link_ksettings_add_link_mode(link_ksettings, |
856 | advertising, |
857 | FIBRE); |
858 | } |
859 | |
860 | if (eth_proto_cap & (MLX5E_PROT_MASK(MLX5E_100GBASE_KR4) |
861 | | MLX5E_PROT_MASK(MLX5E_40GBASE_KR4) |
862 | | MLX5E_PROT_MASK(MLX5E_10GBASE_KR) |
863 | | MLX5E_PROT_MASK(MLX5E_10GBASE_KX4) |
864 | | MLX5E_PROT_MASK(MLX5E_1000BASE_KX))) { |
865 | ethtool_link_ksettings_add_link_mode(link_ksettings, |
866 | supported, |
867 | Backplane); |
868 | ethtool_link_ksettings_add_link_mode(link_ksettings, |
869 | advertising, |
870 | Backplane); |
871 | } |
872 | return; |
873 | } |
874 | |
875 | switch (connector_type) { |
876 | case MLX5E_PORT_TP: |
877 | ethtool_link_ksettings_add_link_mode(link_ksettings, |
878 | supported, TP); |
879 | ethtool_link_ksettings_add_link_mode(link_ksettings, |
880 | advertising, TP); |
881 | break; |
882 | case MLX5E_PORT_AUI: |
883 | ethtool_link_ksettings_add_link_mode(link_ksettings, |
884 | supported, AUI); |
885 | ethtool_link_ksettings_add_link_mode(link_ksettings, |
886 | advertising, AUI); |
887 | break; |
888 | case MLX5E_PORT_BNC: |
889 | ethtool_link_ksettings_add_link_mode(link_ksettings, |
890 | supported, BNC); |
891 | ethtool_link_ksettings_add_link_mode(link_ksettings, |
892 | advertising, BNC); |
893 | break; |
894 | case MLX5E_PORT_MII: |
895 | ethtool_link_ksettings_add_link_mode(link_ksettings, |
896 | supported, MII); |
897 | ethtool_link_ksettings_add_link_mode(link_ksettings, |
898 | advertising, MII); |
899 | break; |
900 | case MLX5E_PORT_FIBRE: |
901 | ethtool_link_ksettings_add_link_mode(link_ksettings, |
902 | supported, FIBRE); |
903 | ethtool_link_ksettings_add_link_mode(link_ksettings, |
904 | advertising, FIBRE); |
905 | break; |
906 | case MLX5E_PORT_DA: |
907 | ethtool_link_ksettings_add_link_mode(link_ksettings, |
908 | supported, Backplane); |
909 | ethtool_link_ksettings_add_link_mode(link_ksettings, |
910 | advertising, Backplane); |
911 | break; |
912 | case MLX5E_PORT_NONE: |
913 | case MLX5E_PORT_OTHER: |
914 | default: |
915 | break; |
916 | } |
917 | } |
918 | |
919 | static void get_speed_duplex(struct net_device *netdev, |
920 | u32 eth_proto_oper, bool force_legacy, |
921 | u16 data_rate_oper, |
922 | struct ethtool_link_ksettings *link_ksettings) |
923 | { |
924 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
925 | u32 speed = SPEED_UNKNOWN; |
926 | u8 duplex = DUPLEX_UNKNOWN; |
927 | |
928 | if (!netif_carrier_ok(dev: netdev)) |
929 | goto out; |
930 | |
931 | speed = mlx5_port_ptys2speed(mdev: priv->mdev, eth_proto_oper, force_legacy); |
932 | if (!speed) { |
933 | if (data_rate_oper) |
934 | speed = 100 * data_rate_oper; |
935 | else |
936 | speed = SPEED_UNKNOWN; |
937 | goto out; |
938 | } |
939 | |
940 | duplex = DUPLEX_FULL; |
941 | |
942 | out: |
943 | link_ksettings->base.speed = speed; |
944 | link_ksettings->base.duplex = duplex; |
945 | } |
946 | |
947 | static void get_supported(struct mlx5_core_dev *mdev, u32 eth_proto_cap, |
948 | struct ethtool_link_ksettings *link_ksettings) |
949 | { |
950 | unsigned long *supported = link_ksettings->link_modes.supported; |
951 | ptys2ethtool_supported_link(mdev, supported_modes: supported, eth_proto_cap); |
952 | |
953 | ethtool_link_ksettings_add_link_mode(link_ksettings, supported, Pause); |
954 | } |
955 | |
956 | static void get_advertising(u32 eth_proto_cap, u8 tx_pause, u8 rx_pause, |
957 | struct ethtool_link_ksettings *link_ksettings, |
958 | bool ext) |
959 | { |
960 | unsigned long *advertising = link_ksettings->link_modes.advertising; |
961 | ptys2ethtool_adver_link(advertising_modes: advertising, eth_proto_cap, ext); |
962 | |
963 | if (rx_pause) |
964 | ethtool_link_ksettings_add_link_mode(link_ksettings, advertising, Pause); |
965 | if (tx_pause ^ rx_pause) |
966 | ethtool_link_ksettings_add_link_mode(link_ksettings, advertising, Asym_Pause); |
967 | } |
968 | |
969 | static int ptys2connector_type[MLX5E_CONNECTOR_TYPE_NUMBER] = { |
970 | [MLX5E_PORT_UNKNOWN] = PORT_OTHER, |
971 | [MLX5E_PORT_NONE] = PORT_NONE, |
972 | [MLX5E_PORT_TP] = PORT_TP, |
973 | [MLX5E_PORT_AUI] = PORT_AUI, |
974 | [MLX5E_PORT_BNC] = PORT_BNC, |
975 | [MLX5E_PORT_MII] = PORT_MII, |
976 | [MLX5E_PORT_FIBRE] = PORT_FIBRE, |
977 | [MLX5E_PORT_DA] = PORT_DA, |
978 | [MLX5E_PORT_OTHER] = PORT_OTHER, |
979 | }; |
980 | |
981 | static u8 get_connector_port(struct mlx5_core_dev *mdev, u32 eth_proto, u8 connector_type) |
982 | { |
983 | if (MLX5_CAP_PCAM_FEATURE(mdev, ptys_connector_type)) |
984 | return ptys2connector_type[connector_type]; |
985 | |
986 | if (eth_proto & |
987 | (MLX5E_PROT_MASK(MLX5E_10GBASE_SR) | |
988 | MLX5E_PROT_MASK(MLX5E_40GBASE_SR4) | |
989 | MLX5E_PROT_MASK(MLX5E_100GBASE_SR4) | |
990 | MLX5E_PROT_MASK(MLX5E_1000BASE_CX_SGMII))) { |
991 | return PORT_FIBRE; |
992 | } |
993 | |
994 | if (eth_proto & |
995 | (MLX5E_PROT_MASK(MLX5E_40GBASE_CR4) | |
996 | MLX5E_PROT_MASK(MLX5E_10GBASE_CR) | |
997 | MLX5E_PROT_MASK(MLX5E_100GBASE_CR4))) { |
998 | return PORT_DA; |
999 | } |
1000 | |
1001 | if (eth_proto & |
1002 | (MLX5E_PROT_MASK(MLX5E_10GBASE_KX4) | |
1003 | MLX5E_PROT_MASK(MLX5E_10GBASE_KR) | |
1004 | MLX5E_PROT_MASK(MLX5E_40GBASE_KR4) | |
1005 | MLX5E_PROT_MASK(MLX5E_100GBASE_KR4))) { |
1006 | return PORT_NONE; |
1007 | } |
1008 | |
1009 | return PORT_OTHER; |
1010 | } |
1011 | |
1012 | static void get_lp_advertising(struct mlx5_core_dev *mdev, u32 eth_proto_lp, |
1013 | struct ethtool_link_ksettings *link_ksettings) |
1014 | { |
1015 | unsigned long *lp_advertising = link_ksettings->link_modes.lp_advertising; |
1016 | bool ext = mlx5_ptys_ext_supported(mdev); |
1017 | |
1018 | ptys2ethtool_adver_link(advertising_modes: lp_advertising, eth_proto_cap: eth_proto_lp, ext); |
1019 | } |
1020 | |
1021 | int mlx5e_ethtool_get_link_ksettings(struct mlx5e_priv *priv, |
1022 | struct ethtool_link_ksettings *link_ksettings) |
1023 | { |
1024 | struct mlx5_core_dev *mdev = priv->mdev; |
1025 | u32 out[MLX5_ST_SZ_DW(ptys_reg)] = {}; |
1026 | u32 eth_proto_admin; |
1027 | u8 an_disable_admin; |
1028 | u16 data_rate_oper; |
1029 | u32 eth_proto_oper; |
1030 | u32 eth_proto_cap; |
1031 | u8 connector_type; |
1032 | u32 rx_pause = 0; |
1033 | u32 tx_pause = 0; |
1034 | u32 eth_proto_lp; |
1035 | bool admin_ext; |
1036 | u8 an_status; |
1037 | bool ext; |
1038 | int err; |
1039 | |
1040 | err = mlx5_query_port_ptys(dev: mdev, ptys: out, ptys_size: sizeof(out), proto_mask: MLX5_PTYS_EN, local_port: 1); |
1041 | if (err) { |
1042 | netdev_err(dev: priv->netdev, format: "%s: query port ptys failed: %d\n" , |
1043 | __func__, err); |
1044 | goto err_query_regs; |
1045 | } |
1046 | ext = !!MLX5_GET_ETH_PROTO(ptys_reg, out, true, eth_proto_capability); |
1047 | eth_proto_cap = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, |
1048 | eth_proto_capability); |
1049 | eth_proto_admin = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, |
1050 | eth_proto_admin); |
1051 | /* Fields: eth_proto_admin and ext_eth_proto_admin are |
1052 | * mutually exclusive. Hence try reading legacy advertising |
1053 | * when extended advertising is zero. |
1054 | * admin_ext indicates which proto_admin (ext vs. legacy) |
1055 | * should be read and interpreted |
1056 | */ |
1057 | admin_ext = ext; |
1058 | if (ext && !eth_proto_admin) { |
1059 | eth_proto_admin = MLX5_GET_ETH_PROTO(ptys_reg, out, false, |
1060 | eth_proto_admin); |
1061 | admin_ext = false; |
1062 | } |
1063 | |
1064 | eth_proto_oper = MLX5_GET_ETH_PROTO(ptys_reg, out, admin_ext, |
1065 | eth_proto_oper); |
1066 | eth_proto_lp = MLX5_GET(ptys_reg, out, eth_proto_lp_advertise); |
1067 | an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin); |
1068 | an_status = MLX5_GET(ptys_reg, out, an_status); |
1069 | connector_type = MLX5_GET(ptys_reg, out, connector_type); |
1070 | data_rate_oper = MLX5_GET(ptys_reg, out, data_rate_oper); |
1071 | |
1072 | mlx5_query_port_pause(dev: mdev, rx_pause: &rx_pause, tx_pause: &tx_pause); |
1073 | |
1074 | ethtool_link_ksettings_zero_link_mode(link_ksettings, supported); |
1075 | ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising); |
1076 | |
1077 | get_supported(mdev, eth_proto_cap, link_ksettings); |
1078 | get_advertising(eth_proto_cap: eth_proto_admin, tx_pause, rx_pause, link_ksettings, |
1079 | ext: admin_ext); |
1080 | get_speed_duplex(netdev: priv->netdev, eth_proto_oper, force_legacy: !admin_ext, |
1081 | data_rate_oper, link_ksettings); |
1082 | |
1083 | eth_proto_oper = eth_proto_oper ? eth_proto_oper : eth_proto_cap; |
1084 | connector_type = connector_type < MLX5E_CONNECTOR_TYPE_NUMBER ? |
1085 | connector_type : MLX5E_PORT_UNKNOWN; |
1086 | link_ksettings->base.port = get_connector_port(mdev, eth_proto: eth_proto_oper, connector_type); |
1087 | ptys2ethtool_supported_advertised_port(mdev, link_ksettings, eth_proto_cap: eth_proto_admin, |
1088 | connector_type); |
1089 | get_lp_advertising(mdev, eth_proto_lp, link_ksettings); |
1090 | |
1091 | if (an_status == MLX5_AN_COMPLETE) |
1092 | ethtool_link_ksettings_add_link_mode(link_ksettings, |
1093 | lp_advertising, Autoneg); |
1094 | |
1095 | link_ksettings->base.autoneg = an_disable_admin ? AUTONEG_DISABLE : |
1096 | AUTONEG_ENABLE; |
1097 | ethtool_link_ksettings_add_link_mode(link_ksettings, supported, |
1098 | Autoneg); |
1099 | |
1100 | err = get_fec_supported_advertised(dev: mdev, link_ksettings); |
1101 | if (err) { |
1102 | netdev_dbg(priv->netdev, "%s: FEC caps query failed: %d\n" , |
1103 | __func__, err); |
1104 | err = 0; /* don't fail caps query because of FEC error */ |
1105 | } |
1106 | |
1107 | if (!an_disable_admin) |
1108 | ethtool_link_ksettings_add_link_mode(link_ksettings, |
1109 | advertising, Autoneg); |
1110 | |
1111 | err_query_regs: |
1112 | return err; |
1113 | } |
1114 | |
1115 | static int mlx5e_get_link_ksettings(struct net_device *netdev, |
1116 | struct ethtool_link_ksettings *link_ksettings) |
1117 | { |
1118 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
1119 | |
1120 | return mlx5e_ethtool_get_link_ksettings(priv, link_ksettings); |
1121 | } |
1122 | |
1123 | static int mlx5e_speed_validate(struct net_device *netdev, bool ext, |
1124 | const unsigned long link_modes, u8 autoneg) |
1125 | { |
1126 | /* Extended link-mode has no speed limitations. */ |
1127 | if (ext) |
1128 | return 0; |
1129 | |
1130 | if ((link_modes & MLX5E_PROT_MASK(MLX5E_56GBASE_R4)) && |
1131 | autoneg != AUTONEG_ENABLE) { |
1132 | netdev_err(dev: netdev, format: "%s: 56G link speed requires autoneg enabled\n" , |
1133 | __func__); |
1134 | return -EINVAL; |
1135 | } |
1136 | return 0; |
1137 | } |
1138 | |
1139 | static u32 mlx5e_ethtool2ptys_adver_link(const unsigned long *link_modes) |
1140 | { |
1141 | u32 i, ptys_modes = 0; |
1142 | |
1143 | for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) { |
1144 | if (*ptys2legacy_ethtool_table[i].advertised == 0) |
1145 | continue; |
1146 | if (bitmap_intersects(src1: ptys2legacy_ethtool_table[i].advertised, |
1147 | src2: link_modes, |
1148 | nbits: __ETHTOOL_LINK_MODE_MASK_NBITS)) |
1149 | ptys_modes |= MLX5E_PROT_MASK(i); |
1150 | } |
1151 | |
1152 | return ptys_modes; |
1153 | } |
1154 | |
1155 | static u32 mlx5e_ethtool2ptys_ext_adver_link(const unsigned long *link_modes) |
1156 | { |
1157 | u32 i, ptys_modes = 0; |
1158 | unsigned long modes[2]; |
1159 | |
1160 | for (i = 0; i < MLX5E_EXT_LINK_MODES_NUMBER; ++i) { |
1161 | if (ptys2ext_ethtool_table[i].advertised[0] == 0 && |
1162 | ptys2ext_ethtool_table[i].advertised[1] == 0) |
1163 | continue; |
1164 | memset(modes, 0, sizeof(modes)); |
1165 | bitmap_and(dst: modes, src1: ptys2ext_ethtool_table[i].advertised, |
1166 | src2: link_modes, nbits: __ETHTOOL_LINK_MODE_MASK_NBITS); |
1167 | |
1168 | if (modes[0] == ptys2ext_ethtool_table[i].advertised[0] && |
1169 | modes[1] == ptys2ext_ethtool_table[i].advertised[1]) |
1170 | ptys_modes |= MLX5E_PROT_MASK(i); |
1171 | } |
1172 | return ptys_modes; |
1173 | } |
1174 | |
1175 | static bool ext_link_mode_requested(const unsigned long *adver) |
1176 | { |
1177 | #define MLX5E_MIN_PTYS_EXT_LINK_MODE_BIT ETHTOOL_LINK_MODE_50000baseKR_Full_BIT |
1178 | int size = __ETHTOOL_LINK_MODE_MASK_NBITS - MLX5E_MIN_PTYS_EXT_LINK_MODE_BIT; |
1179 | __ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = {0,}; |
1180 | |
1181 | bitmap_set(map: modes, MLX5E_MIN_PTYS_EXT_LINK_MODE_BIT, nbits: size); |
1182 | return bitmap_intersects(src1: modes, src2: adver, nbits: __ETHTOOL_LINK_MODE_MASK_NBITS); |
1183 | } |
1184 | |
1185 | static bool ext_requested(u8 autoneg, const unsigned long *adver, bool ext_supported) |
1186 | { |
1187 | bool ext_link_mode = ext_link_mode_requested(adver); |
1188 | |
1189 | return autoneg == AUTONEG_ENABLE ? ext_link_mode : ext_supported; |
1190 | } |
1191 | |
1192 | int mlx5e_ethtool_set_link_ksettings(struct mlx5e_priv *priv, |
1193 | const struct ethtool_link_ksettings *link_ksettings) |
1194 | { |
1195 | struct mlx5_core_dev *mdev = priv->mdev; |
1196 | struct mlx5_port_eth_proto eproto; |
1197 | const unsigned long *adver; |
1198 | bool an_changes = false; |
1199 | u8 an_disable_admin; |
1200 | bool ext_supported; |
1201 | u8 an_disable_cap; |
1202 | bool an_disable; |
1203 | u32 link_modes; |
1204 | u8 an_status; |
1205 | u8 autoneg; |
1206 | u32 speed; |
1207 | bool ext; |
1208 | int err; |
1209 | |
1210 | u32 (*ethtool2ptys_adver_func)(const unsigned long *adver); |
1211 | |
1212 | adver = link_ksettings->link_modes.advertising; |
1213 | autoneg = link_ksettings->base.autoneg; |
1214 | speed = link_ksettings->base.speed; |
1215 | |
1216 | ext_supported = mlx5_ptys_ext_supported(mdev); |
1217 | ext = ext_requested(autoneg, adver, ext_supported); |
1218 | if (!ext_supported && ext) |
1219 | return -EOPNOTSUPP; |
1220 | |
1221 | ethtool2ptys_adver_func = ext ? mlx5e_ethtool2ptys_ext_adver_link : |
1222 | mlx5e_ethtool2ptys_adver_link; |
1223 | err = mlx5_port_query_eth_proto(dev: mdev, port: 1, ext, eproto: &eproto); |
1224 | if (err) { |
1225 | netdev_err(dev: priv->netdev, format: "%s: query port eth proto failed: %d\n" , |
1226 | __func__, err); |
1227 | goto out; |
1228 | } |
1229 | link_modes = autoneg == AUTONEG_ENABLE ? ethtool2ptys_adver_func(adver) : |
1230 | mlx5_port_speed2linkmodes(mdev, speed, force_legacy: !ext); |
1231 | |
1232 | err = mlx5e_speed_validate(netdev: priv->netdev, ext, link_modes, autoneg); |
1233 | if (err) |
1234 | goto out; |
1235 | |
1236 | link_modes = link_modes & eproto.cap; |
1237 | if (!link_modes) { |
1238 | netdev_err(dev: priv->netdev, format: "%s: Not supported link mode(s) requested" , |
1239 | __func__); |
1240 | err = -EINVAL; |
1241 | goto out; |
1242 | } |
1243 | |
1244 | mlx5_port_query_eth_autoneg(dev: mdev, an_status: &an_status, an_disable_cap: &an_disable_cap, |
1245 | an_disable_admin: &an_disable_admin); |
1246 | |
1247 | an_disable = autoneg == AUTONEG_DISABLE; |
1248 | an_changes = ((!an_disable && an_disable_admin) || |
1249 | (an_disable && !an_disable_admin)); |
1250 | |
1251 | if (!an_changes && link_modes == eproto.admin) |
1252 | goto out; |
1253 | |
1254 | mlx5_port_set_eth_ptys(dev: mdev, an_disable, proto_admin: link_modes, ext); |
1255 | mlx5_toggle_port_link(dev: mdev); |
1256 | |
1257 | out: |
1258 | return err; |
1259 | } |
1260 | |
1261 | static int mlx5e_set_link_ksettings(struct net_device *netdev, |
1262 | const struct ethtool_link_ksettings *link_ksettings) |
1263 | { |
1264 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
1265 | |
1266 | return mlx5e_ethtool_set_link_ksettings(priv, link_ksettings); |
1267 | } |
1268 | |
1269 | u32 mlx5e_ethtool_get_rxfh_key_size(struct mlx5e_priv *priv) |
1270 | { |
1271 | return sizeof_field(struct mlx5e_rss_params_hash, toeplitz_hash_key); |
1272 | } |
1273 | |
1274 | static u32 mlx5e_get_rxfh_key_size(struct net_device *netdev) |
1275 | { |
1276 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
1277 | |
1278 | return mlx5e_ethtool_get_rxfh_key_size(priv); |
1279 | } |
1280 | |
1281 | u32 mlx5e_ethtool_get_rxfh_indir_size(struct mlx5e_priv *priv) |
1282 | { |
1283 | return mlx5e_rqt_size(mdev: priv->mdev, num_channels: priv->channels.params.num_channels); |
1284 | } |
1285 | |
1286 | static u32 mlx5e_get_rxfh_indir_size(struct net_device *netdev) |
1287 | { |
1288 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
1289 | |
1290 | return mlx5e_ethtool_get_rxfh_indir_size(priv); |
1291 | } |
1292 | |
1293 | int mlx5e_get_rxfh(struct net_device *netdev, struct ethtool_rxfh_param *rxfh) |
1294 | { |
1295 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
1296 | u32 = rxfh->rss_context; |
1297 | int err; |
1298 | |
1299 | mutex_lock(&priv->state_lock); |
1300 | err = mlx5e_rx_res_rss_get_rxfh(res: priv->rx_res, rss_idx: rss_context, |
1301 | indir: rxfh->indir, key: rxfh->key, hfunc: &rxfh->hfunc); |
1302 | mutex_unlock(lock: &priv->state_lock); |
1303 | return err; |
1304 | } |
1305 | |
1306 | int mlx5e_set_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh, |
1307 | struct netlink_ext_ack *extack) |
1308 | { |
1309 | struct mlx5e_priv *priv = netdev_priv(dev); |
1310 | u32 * = &rxfh->rss_context; |
1311 | u8 hfunc = rxfh->hfunc; |
1312 | unsigned int count; |
1313 | int err; |
1314 | |
1315 | mutex_lock(&priv->state_lock); |
1316 | |
1317 | count = priv->channels.params.num_channels; |
1318 | |
1319 | if (hfunc == ETH_RSS_HASH_XOR) { |
1320 | unsigned int xor8_max_channels = mlx5e_rqt_max_num_channels_allowed_for_xor8(); |
1321 | |
1322 | if (count > xor8_max_channels) { |
1323 | err = -EINVAL; |
1324 | netdev_err(dev: priv->netdev, format: "%s: Cannot set RSS hash function to XOR, current number of channels (%d) exceeds the maximum allowed for XOR8 RSS hfunc (%d)\n" , |
1325 | __func__, count, xor8_max_channels); |
1326 | goto unlock; |
1327 | } |
1328 | } |
1329 | |
1330 | if (*rss_context && rxfh->rss_delete) { |
1331 | err = mlx5e_rx_res_rss_destroy(res: priv->rx_res, rss_idx: *rss_context); |
1332 | goto unlock; |
1333 | } |
1334 | |
1335 | if (*rss_context == ETH_RXFH_CONTEXT_ALLOC) { |
1336 | err = mlx5e_rx_res_rss_init(res: priv->rx_res, rss_idx: rss_context, init_nch: count); |
1337 | if (err) |
1338 | goto unlock; |
1339 | } |
1340 | |
1341 | err = mlx5e_rx_res_rss_set_rxfh(res: priv->rx_res, rss_idx: *rss_context, |
1342 | indir: rxfh->indir, key: rxfh->key, |
1343 | hfunc: hfunc == ETH_RSS_HASH_NO_CHANGE ? NULL : &hfunc); |
1344 | |
1345 | unlock: |
1346 | mutex_unlock(lock: &priv->state_lock); |
1347 | return err; |
1348 | } |
1349 | |
1350 | #define MLX5E_PFC_PREVEN_AUTO_TOUT_MSEC 100 |
1351 | #define MLX5E_PFC_PREVEN_TOUT_MAX_MSEC 8000 |
1352 | #define MLX5E_PFC_PREVEN_MINOR_PRECENT 85 |
1353 | #define MLX5E_PFC_PREVEN_TOUT_MIN_MSEC 80 |
1354 | #define MLX5E_DEVICE_STALL_MINOR_WATERMARK(critical_tout) \ |
1355 | max_t(u16, MLX5E_PFC_PREVEN_TOUT_MIN_MSEC, \ |
1356 | (critical_tout * MLX5E_PFC_PREVEN_MINOR_PRECENT) / 100) |
1357 | |
1358 | static int mlx5e_get_pfc_prevention_tout(struct net_device *netdev, |
1359 | u16 *pfc_prevention_tout) |
1360 | { |
1361 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
1362 | struct mlx5_core_dev *mdev = priv->mdev; |
1363 | |
1364 | if (!MLX5_CAP_PCAM_FEATURE((priv)->mdev, pfcc_mask) || |
1365 | !MLX5_CAP_DEBUG((priv)->mdev, stall_detect)) |
1366 | return -EOPNOTSUPP; |
1367 | |
1368 | return mlx5_query_port_stall_watermark(dev: mdev, stall_critical_watermark: pfc_prevention_tout, NULL); |
1369 | } |
1370 | |
1371 | static int mlx5e_set_pfc_prevention_tout(struct net_device *netdev, |
1372 | u16 pfc_preven) |
1373 | { |
1374 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
1375 | struct mlx5_core_dev *mdev = priv->mdev; |
1376 | u16 critical_tout; |
1377 | u16 minor; |
1378 | |
1379 | if (!MLX5_CAP_PCAM_FEATURE((priv)->mdev, pfcc_mask) || |
1380 | !MLX5_CAP_DEBUG((priv)->mdev, stall_detect)) |
1381 | return -EOPNOTSUPP; |
1382 | |
1383 | critical_tout = (pfc_preven == PFC_STORM_PREVENTION_AUTO) ? |
1384 | MLX5E_PFC_PREVEN_AUTO_TOUT_MSEC : |
1385 | pfc_preven; |
1386 | |
1387 | if (critical_tout != PFC_STORM_PREVENTION_DISABLE && |
1388 | (critical_tout > MLX5E_PFC_PREVEN_TOUT_MAX_MSEC || |
1389 | critical_tout < MLX5E_PFC_PREVEN_TOUT_MIN_MSEC)) { |
1390 | netdev_info(dev: netdev, format: "%s: pfc prevention tout not in range (%d-%d)\n" , |
1391 | __func__, MLX5E_PFC_PREVEN_TOUT_MIN_MSEC, |
1392 | MLX5E_PFC_PREVEN_TOUT_MAX_MSEC); |
1393 | return -EINVAL; |
1394 | } |
1395 | |
1396 | minor = MLX5E_DEVICE_STALL_MINOR_WATERMARK(critical_tout); |
1397 | return mlx5_set_port_stall_watermark(dev: mdev, stall_critical_watermark: critical_tout, |
1398 | stall_minor_watermark: minor); |
1399 | } |
1400 | |
1401 | static int mlx5e_get_tunable(struct net_device *dev, |
1402 | const struct ethtool_tunable *tuna, |
1403 | void *data) |
1404 | { |
1405 | int err; |
1406 | |
1407 | switch (tuna->id) { |
1408 | case ETHTOOL_PFC_PREVENTION_TOUT: |
1409 | err = mlx5e_get_pfc_prevention_tout(netdev: dev, pfc_prevention_tout: data); |
1410 | break; |
1411 | default: |
1412 | err = -EINVAL; |
1413 | break; |
1414 | } |
1415 | |
1416 | return err; |
1417 | } |
1418 | |
1419 | static int mlx5e_set_tunable(struct net_device *dev, |
1420 | const struct ethtool_tunable *tuna, |
1421 | const void *data) |
1422 | { |
1423 | struct mlx5e_priv *priv = netdev_priv(dev); |
1424 | int err; |
1425 | |
1426 | mutex_lock(&priv->state_lock); |
1427 | |
1428 | switch (tuna->id) { |
1429 | case ETHTOOL_PFC_PREVENTION_TOUT: |
1430 | err = mlx5e_set_pfc_prevention_tout(netdev: dev, pfc_preven: *(u16 *)data); |
1431 | break; |
1432 | default: |
1433 | err = -EINVAL; |
1434 | break; |
1435 | } |
1436 | |
1437 | mutex_unlock(lock: &priv->state_lock); |
1438 | return err; |
1439 | } |
1440 | |
1441 | static void mlx5e_get_pause_stats(struct net_device *netdev, |
1442 | struct ethtool_pause_stats *pause_stats) |
1443 | { |
1444 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
1445 | |
1446 | mlx5e_stats_pause_get(priv, pause_stats); |
1447 | } |
1448 | |
1449 | void mlx5e_ethtool_get_pauseparam(struct mlx5e_priv *priv, |
1450 | struct ethtool_pauseparam *pauseparam) |
1451 | { |
1452 | struct mlx5_core_dev *mdev = priv->mdev; |
1453 | int err; |
1454 | |
1455 | err = mlx5_query_port_pause(dev: mdev, rx_pause: &pauseparam->rx_pause, |
1456 | tx_pause: &pauseparam->tx_pause); |
1457 | if (err) { |
1458 | netdev_err(dev: priv->netdev, format: "%s: mlx5_query_port_pause failed:0x%x\n" , |
1459 | __func__, err); |
1460 | } |
1461 | } |
1462 | |
1463 | static void mlx5e_get_pauseparam(struct net_device *netdev, |
1464 | struct ethtool_pauseparam *pauseparam) |
1465 | { |
1466 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
1467 | |
1468 | mlx5e_ethtool_get_pauseparam(priv, pauseparam); |
1469 | } |
1470 | |
1471 | int mlx5e_ethtool_set_pauseparam(struct mlx5e_priv *priv, |
1472 | struct ethtool_pauseparam *pauseparam) |
1473 | { |
1474 | struct mlx5_core_dev *mdev = priv->mdev; |
1475 | int err; |
1476 | |
1477 | if (!MLX5_CAP_GEN(mdev, vport_group_manager)) |
1478 | return -EOPNOTSUPP; |
1479 | |
1480 | if (pauseparam->autoneg) |
1481 | return -EINVAL; |
1482 | |
1483 | err = mlx5_set_port_pause(dev: mdev, |
1484 | rx_pause: pauseparam->rx_pause ? 1 : 0, |
1485 | tx_pause: pauseparam->tx_pause ? 1 : 0); |
1486 | if (err) { |
1487 | netdev_err(dev: priv->netdev, format: "%s: mlx5_set_port_pause failed:0x%x\n" , |
1488 | __func__, err); |
1489 | } |
1490 | |
1491 | return err; |
1492 | } |
1493 | |
1494 | static int mlx5e_set_pauseparam(struct net_device *netdev, |
1495 | struct ethtool_pauseparam *pauseparam) |
1496 | { |
1497 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
1498 | |
1499 | return mlx5e_ethtool_set_pauseparam(priv, pauseparam); |
1500 | } |
1501 | |
1502 | int mlx5e_ethtool_get_ts_info(struct mlx5e_priv *priv, |
1503 | struct ethtool_ts_info *info) |
1504 | { |
1505 | struct mlx5_core_dev *mdev = priv->mdev; |
1506 | |
1507 | info->phc_index = mlx5_clock_get_ptp_index(mdev); |
1508 | |
1509 | if (!MLX5_CAP_GEN(priv->mdev, device_frequency_khz) || |
1510 | info->phc_index == -1) |
1511 | return 0; |
1512 | |
1513 | info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | |
1514 | SOF_TIMESTAMPING_RX_HARDWARE | |
1515 | SOF_TIMESTAMPING_RAW_HARDWARE; |
1516 | |
1517 | info->tx_types = BIT(HWTSTAMP_TX_OFF) | |
1518 | BIT(HWTSTAMP_TX_ON); |
1519 | |
1520 | info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | |
1521 | BIT(HWTSTAMP_FILTER_ALL); |
1522 | |
1523 | return 0; |
1524 | } |
1525 | |
1526 | static int mlx5e_get_ts_info(struct net_device *dev, |
1527 | struct ethtool_ts_info *info) |
1528 | { |
1529 | struct mlx5e_priv *priv = netdev_priv(dev); |
1530 | |
1531 | return mlx5e_ethtool_get_ts_info(priv, info); |
1532 | } |
1533 | |
1534 | static __u32 mlx5e_get_wol_supported(struct mlx5_core_dev *mdev) |
1535 | { |
1536 | __u32 ret = 0; |
1537 | |
1538 | if (MLX5_CAP_GEN(mdev, wol_g)) |
1539 | ret |= WAKE_MAGIC; |
1540 | |
1541 | if (MLX5_CAP_GEN(mdev, wol_s)) |
1542 | ret |= WAKE_MAGICSECURE; |
1543 | |
1544 | if (MLX5_CAP_GEN(mdev, wol_a)) |
1545 | ret |= WAKE_ARP; |
1546 | |
1547 | if (MLX5_CAP_GEN(mdev, wol_b)) |
1548 | ret |= WAKE_BCAST; |
1549 | |
1550 | if (MLX5_CAP_GEN(mdev, wol_m)) |
1551 | ret |= WAKE_MCAST; |
1552 | |
1553 | if (MLX5_CAP_GEN(mdev, wol_u)) |
1554 | ret |= WAKE_UCAST; |
1555 | |
1556 | if (MLX5_CAP_GEN(mdev, wol_p)) |
1557 | ret |= WAKE_PHY; |
1558 | |
1559 | return ret; |
1560 | } |
1561 | |
1562 | static __u32 mlx5e_reformat_wol_mode_mlx5_to_linux(u8 mode) |
1563 | { |
1564 | __u32 ret = 0; |
1565 | |
1566 | if (mode & MLX5_WOL_MAGIC) |
1567 | ret |= WAKE_MAGIC; |
1568 | |
1569 | if (mode & MLX5_WOL_SECURED_MAGIC) |
1570 | ret |= WAKE_MAGICSECURE; |
1571 | |
1572 | if (mode & MLX5_WOL_ARP) |
1573 | ret |= WAKE_ARP; |
1574 | |
1575 | if (mode & MLX5_WOL_BROADCAST) |
1576 | ret |= WAKE_BCAST; |
1577 | |
1578 | if (mode & MLX5_WOL_MULTICAST) |
1579 | ret |= WAKE_MCAST; |
1580 | |
1581 | if (mode & MLX5_WOL_UNICAST) |
1582 | ret |= WAKE_UCAST; |
1583 | |
1584 | if (mode & MLX5_WOL_PHY_ACTIVITY) |
1585 | ret |= WAKE_PHY; |
1586 | |
1587 | return ret; |
1588 | } |
1589 | |
1590 | static u8 mlx5e_reformat_wol_mode_linux_to_mlx5(__u32 mode) |
1591 | { |
1592 | u8 ret = 0; |
1593 | |
1594 | if (mode & WAKE_MAGIC) |
1595 | ret |= MLX5_WOL_MAGIC; |
1596 | |
1597 | if (mode & WAKE_MAGICSECURE) |
1598 | ret |= MLX5_WOL_SECURED_MAGIC; |
1599 | |
1600 | if (mode & WAKE_ARP) |
1601 | ret |= MLX5_WOL_ARP; |
1602 | |
1603 | if (mode & WAKE_BCAST) |
1604 | ret |= MLX5_WOL_BROADCAST; |
1605 | |
1606 | if (mode & WAKE_MCAST) |
1607 | ret |= MLX5_WOL_MULTICAST; |
1608 | |
1609 | if (mode & WAKE_UCAST) |
1610 | ret |= MLX5_WOL_UNICAST; |
1611 | |
1612 | if (mode & WAKE_PHY) |
1613 | ret |= MLX5_WOL_PHY_ACTIVITY; |
1614 | |
1615 | return ret; |
1616 | } |
1617 | |
1618 | static void mlx5e_get_wol(struct net_device *netdev, |
1619 | struct ethtool_wolinfo *wol) |
1620 | { |
1621 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
1622 | struct mlx5_core_dev *mdev = priv->mdev; |
1623 | u8 mlx5_wol_mode; |
1624 | int err; |
1625 | |
1626 | memset(wol, 0, sizeof(*wol)); |
1627 | |
1628 | wol->supported = mlx5e_get_wol_supported(mdev); |
1629 | if (!wol->supported) |
1630 | return; |
1631 | |
1632 | err = mlx5_query_port_wol(mdev, wol_mode: &mlx5_wol_mode); |
1633 | if (err) |
1634 | return; |
1635 | |
1636 | wol->wolopts = mlx5e_reformat_wol_mode_mlx5_to_linux(mode: mlx5_wol_mode); |
1637 | } |
1638 | |
1639 | static int mlx5e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) |
1640 | { |
1641 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
1642 | struct mlx5_core_dev *mdev = priv->mdev; |
1643 | __u32 wol_supported = mlx5e_get_wol_supported(mdev); |
1644 | u32 mlx5_wol_mode; |
1645 | |
1646 | if (!wol_supported) |
1647 | return -EOPNOTSUPP; |
1648 | |
1649 | if (wol->wolopts & ~wol_supported) |
1650 | return -EINVAL; |
1651 | |
1652 | mlx5_wol_mode = mlx5e_reformat_wol_mode_linux_to_mlx5(mode: wol->wolopts); |
1653 | |
1654 | return mlx5_set_port_wol(mdev, wol_mode: mlx5_wol_mode); |
1655 | } |
1656 | |
1657 | static void mlx5e_get_fec_stats(struct net_device *netdev, |
1658 | struct ethtool_fec_stats *fec_stats) |
1659 | { |
1660 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
1661 | |
1662 | mlx5e_stats_fec_get(priv, fec_stats); |
1663 | } |
1664 | |
1665 | static int mlx5e_get_fecparam(struct net_device *netdev, |
1666 | struct ethtool_fecparam *fecparam) |
1667 | { |
1668 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
1669 | struct mlx5_core_dev *mdev = priv->mdev; |
1670 | u16 fec_configured; |
1671 | u32 fec_active; |
1672 | int err; |
1673 | |
1674 | err = mlx5e_get_fec_mode(dev: mdev, fec_mode_active: &fec_active, fec_configured_mode: &fec_configured); |
1675 | |
1676 | if (err) |
1677 | return err; |
1678 | |
1679 | fecparam->active_fec = pplm2ethtool_fec(fec_mode: (unsigned long)fec_active, |
1680 | size: sizeof(unsigned long) * BITS_PER_BYTE); |
1681 | |
1682 | if (!fecparam->active_fec) |
1683 | return -EOPNOTSUPP; |
1684 | |
1685 | fecparam->fec = pplm2ethtool_fec(fec_mode: (unsigned long)fec_configured, |
1686 | size: sizeof(unsigned long) * BITS_PER_BYTE); |
1687 | |
1688 | return 0; |
1689 | } |
1690 | |
1691 | static int mlx5e_set_fecparam(struct net_device *netdev, |
1692 | struct ethtool_fecparam *fecparam) |
1693 | { |
1694 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
1695 | struct mlx5_core_dev *mdev = priv->mdev; |
1696 | unsigned long fec_bitmap; |
1697 | u16 fec_policy = 0; |
1698 | int mode; |
1699 | int err; |
1700 | |
1701 | bitmap_from_arr32(bitmap: &fec_bitmap, buf: &fecparam->fec, nbits: sizeof(fecparam->fec) * BITS_PER_BYTE); |
1702 | if (bitmap_weight(src: &fec_bitmap, nbits: ETHTOOL_FEC_LLRS_BIT + 1) > 1) |
1703 | return -EOPNOTSUPP; |
1704 | |
1705 | for (mode = 0; mode < ARRAY_SIZE(pplm_fec_2_ethtool); mode++) { |
1706 | if (!(pplm_fec_2_ethtool[mode] & fecparam->fec)) |
1707 | continue; |
1708 | fec_policy |= (1 << mode); |
1709 | break; |
1710 | } |
1711 | |
1712 | err = mlx5e_set_fec_mode(dev: mdev, fec_policy); |
1713 | |
1714 | if (err) |
1715 | return err; |
1716 | |
1717 | mlx5_toggle_port_link(dev: mdev); |
1718 | |
1719 | return 0; |
1720 | } |
1721 | |
1722 | static int mlx5e_set_phys_id(struct net_device *dev, |
1723 | enum ethtool_phys_id_state state) |
1724 | { |
1725 | struct mlx5e_priv *priv = netdev_priv(dev); |
1726 | struct mlx5_core_dev *mdev = priv->mdev; |
1727 | u16 beacon_duration; |
1728 | |
1729 | if (!MLX5_CAP_GEN(mdev, beacon_led)) |
1730 | return -EOPNOTSUPP; |
1731 | |
1732 | switch (state) { |
1733 | case ETHTOOL_ID_ACTIVE: |
1734 | beacon_duration = MLX5_BEACON_DURATION_INF; |
1735 | break; |
1736 | case ETHTOOL_ID_INACTIVE: |
1737 | beacon_duration = MLX5_BEACON_DURATION_OFF; |
1738 | break; |
1739 | default: |
1740 | return -EOPNOTSUPP; |
1741 | } |
1742 | |
1743 | return mlx5_set_port_beacon(dev: mdev, beacon_duration); |
1744 | } |
1745 | |
1746 | static int mlx5e_get_module_info(struct net_device *netdev, |
1747 | struct ethtool_modinfo *modinfo) |
1748 | { |
1749 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
1750 | struct mlx5_core_dev *dev = priv->mdev; |
1751 | int size_read = 0; |
1752 | u8 data[4] = {0}; |
1753 | |
1754 | size_read = mlx5_query_module_eeprom(dev, offset: 0, size: 2, data); |
1755 | if (size_read < 2) |
1756 | return -EIO; |
1757 | |
1758 | /* data[0] = identifier byte */ |
1759 | switch (data[0]) { |
1760 | case MLX5_MODULE_ID_QSFP: |
1761 | modinfo->type = ETH_MODULE_SFF_8436; |
1762 | modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; |
1763 | break; |
1764 | case MLX5_MODULE_ID_QSFP_PLUS: |
1765 | case MLX5_MODULE_ID_QSFP28: |
1766 | /* data[1] = revision id */ |
1767 | if (data[0] == MLX5_MODULE_ID_QSFP28 || data[1] >= 0x3) { |
1768 | modinfo->type = ETH_MODULE_SFF_8636; |
1769 | modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN; |
1770 | } else { |
1771 | modinfo->type = ETH_MODULE_SFF_8436; |
1772 | modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; |
1773 | } |
1774 | break; |
1775 | case MLX5_MODULE_ID_SFP: |
1776 | modinfo->type = ETH_MODULE_SFF_8472; |
1777 | modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; |
1778 | break; |
1779 | default: |
1780 | netdev_err(dev: priv->netdev, format: "%s: cable type not recognized:0x%x\n" , |
1781 | __func__, data[0]); |
1782 | return -EINVAL; |
1783 | } |
1784 | |
1785 | return 0; |
1786 | } |
1787 | |
1788 | static int mlx5e_get_module_eeprom(struct net_device *netdev, |
1789 | struct ethtool_eeprom *ee, |
1790 | u8 *data) |
1791 | { |
1792 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
1793 | struct mlx5_core_dev *mdev = priv->mdev; |
1794 | int offset = ee->offset; |
1795 | int size_read; |
1796 | int i = 0; |
1797 | |
1798 | if (!ee->len) |
1799 | return -EINVAL; |
1800 | |
1801 | memset(data, 0, ee->len); |
1802 | |
1803 | while (i < ee->len) { |
1804 | size_read = mlx5_query_module_eeprom(dev: mdev, offset, size: ee->len - i, |
1805 | data: data + i); |
1806 | |
1807 | if (!size_read) |
1808 | /* Done reading */ |
1809 | return 0; |
1810 | |
1811 | if (size_read < 0) { |
1812 | netdev_err(dev: priv->netdev, format: "%s: mlx5_query_eeprom failed:0x%x\n" , |
1813 | __func__, size_read); |
1814 | return size_read; |
1815 | } |
1816 | |
1817 | i += size_read; |
1818 | offset += size_read; |
1819 | } |
1820 | |
1821 | return 0; |
1822 | } |
1823 | |
1824 | static int mlx5e_get_module_eeprom_by_page(struct net_device *netdev, |
1825 | const struct ethtool_module_eeprom *page_data, |
1826 | struct netlink_ext_ack *extack) |
1827 | { |
1828 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
1829 | struct mlx5_module_eeprom_query_params query; |
1830 | struct mlx5_core_dev *mdev = priv->mdev; |
1831 | u8 *data = page_data->data; |
1832 | int size_read; |
1833 | int i = 0; |
1834 | |
1835 | if (!page_data->length) |
1836 | return -EINVAL; |
1837 | |
1838 | memset(data, 0, page_data->length); |
1839 | |
1840 | query.offset = page_data->offset; |
1841 | query.i2c_address = page_data->i2c_address; |
1842 | query.bank = page_data->bank; |
1843 | query.page = page_data->page; |
1844 | while (i < page_data->length) { |
1845 | query.size = page_data->length - i; |
1846 | size_read = mlx5_query_module_eeprom_by_page(dev: mdev, params: &query, data: data + i); |
1847 | |
1848 | /* Done reading, return how many bytes was read */ |
1849 | if (!size_read) |
1850 | return i; |
1851 | |
1852 | if (size_read == -EINVAL) |
1853 | return -EINVAL; |
1854 | if (size_read < 0) { |
1855 | netdev_err(dev: priv->netdev, format: "%s: mlx5_query_module_eeprom_by_page failed:0x%x\n" , |
1856 | __func__, size_read); |
1857 | return i; |
1858 | } |
1859 | |
1860 | i += size_read; |
1861 | query.offset += size_read; |
1862 | } |
1863 | |
1864 | return i; |
1865 | } |
1866 | |
1867 | int mlx5e_ethtool_flash_device(struct mlx5e_priv *priv, |
1868 | struct ethtool_flash *flash) |
1869 | { |
1870 | struct mlx5_core_dev *mdev = priv->mdev; |
1871 | struct net_device *dev = priv->netdev; |
1872 | const struct firmware *fw; |
1873 | int err; |
1874 | |
1875 | if (flash->region != ETHTOOL_FLASH_ALL_REGIONS) |
1876 | return -EOPNOTSUPP; |
1877 | |
1878 | err = request_firmware_direct(fw: &fw, name: flash->data, device: &dev->dev); |
1879 | if (err) |
1880 | return err; |
1881 | |
1882 | dev_hold(dev); |
1883 | rtnl_unlock(); |
1884 | |
1885 | err = mlx5_firmware_flash(dev: mdev, fw, NULL); |
1886 | release_firmware(fw); |
1887 | |
1888 | rtnl_lock(); |
1889 | dev_put(dev); |
1890 | return err; |
1891 | } |
1892 | |
1893 | static int mlx5e_flash_device(struct net_device *dev, |
1894 | struct ethtool_flash *flash) |
1895 | { |
1896 | struct mlx5e_priv *priv = netdev_priv(dev); |
1897 | |
1898 | return mlx5e_ethtool_flash_device(priv, flash); |
1899 | } |
1900 | |
1901 | static int set_pflag_cqe_based_moder(struct net_device *netdev, bool enable, |
1902 | bool is_rx_cq) |
1903 | { |
1904 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
1905 | u8 cq_period_mode, current_cq_period_mode; |
1906 | struct mlx5e_params new_params; |
1907 | |
1908 | if (enable && !MLX5_CAP_GEN(priv->mdev, cq_period_start_from_cqe)) |
1909 | return -EOPNOTSUPP; |
1910 | |
1911 | cq_period_mode = cqe_mode_to_period_mode(val: enable); |
1912 | |
1913 | current_cq_period_mode = is_rx_cq ? |
1914 | priv->channels.params.rx_cq_moderation.cq_period_mode : |
1915 | priv->channels.params.tx_cq_moderation.cq_period_mode; |
1916 | |
1917 | if (cq_period_mode == current_cq_period_mode) |
1918 | return 0; |
1919 | |
1920 | new_params = priv->channels.params; |
1921 | if (is_rx_cq) |
1922 | mlx5e_set_rx_cq_mode_params(params: &new_params, cq_period_mode); |
1923 | else |
1924 | mlx5e_set_tx_cq_mode_params(params: &new_params, cq_period_mode); |
1925 | |
1926 | return mlx5e_safe_switch_params(priv, new_params: &new_params, NULL, NULL, reset: true); |
1927 | } |
1928 | |
1929 | static int set_pflag_tx_cqe_based_moder(struct net_device *netdev, bool enable) |
1930 | { |
1931 | return set_pflag_cqe_based_moder(netdev, enable, is_rx_cq: false); |
1932 | } |
1933 | |
1934 | static int set_pflag_rx_cqe_based_moder(struct net_device *netdev, bool enable) |
1935 | { |
1936 | return set_pflag_cqe_based_moder(netdev, enable, is_rx_cq: true); |
1937 | } |
1938 | |
1939 | int mlx5e_modify_rx_cqe_compression_locked(struct mlx5e_priv *priv, bool new_val, bool rx_filter) |
1940 | { |
1941 | bool curr_val = MLX5E_GET_PFLAG(&priv->channels.params, MLX5E_PFLAG_RX_CQE_COMPRESS); |
1942 | struct mlx5e_params new_params; |
1943 | int err = 0; |
1944 | |
1945 | if (!MLX5_CAP_GEN(priv->mdev, cqe_compression)) |
1946 | return new_val ? -EOPNOTSUPP : 0; |
1947 | |
1948 | if (curr_val == new_val) |
1949 | return 0; |
1950 | |
1951 | if (new_val && !mlx5e_profile_feature_cap(priv->profile, PTP_RX) && rx_filter) { |
1952 | netdev_err(dev: priv->netdev, |
1953 | format: "Profile doesn't support enabling of CQE compression while hardware time-stamping is enabled.\n" ); |
1954 | return -EINVAL; |
1955 | } |
1956 | |
1957 | if (priv->channels.params.packet_merge.type == MLX5E_PACKET_MERGE_SHAMPO) { |
1958 | netdev_warn(dev: priv->netdev, format: "Can't set CQE compression with HW-GRO, disable it first.\n" ); |
1959 | return -EINVAL; |
1960 | } |
1961 | |
1962 | new_params = priv->channels.params; |
1963 | MLX5E_SET_PFLAG(&new_params, MLX5E_PFLAG_RX_CQE_COMPRESS, new_val); |
1964 | if (rx_filter) |
1965 | new_params.ptp_rx = new_val; |
1966 | |
1967 | if (new_params.ptp_rx == priv->channels.params.ptp_rx) |
1968 | err = mlx5e_safe_switch_params(priv, new_params: &new_params, NULL, NULL, reset: true); |
1969 | else |
1970 | err = mlx5e_safe_switch_params(priv, new_params: &new_params, preactivate: mlx5e_ptp_rx_manage_fs_ctx, |
1971 | context: &new_params.ptp_rx, reset: true); |
1972 | if (err) |
1973 | return err; |
1974 | |
1975 | netdev_dbg(priv->netdev, "MLX5E: RxCqeCmprss was turned %s\n" , |
1976 | MLX5E_GET_PFLAG(&priv->channels.params, |
1977 | MLX5E_PFLAG_RX_CQE_COMPRESS) ? "ON" : "OFF" ); |
1978 | |
1979 | return 0; |
1980 | } |
1981 | |
1982 | static int set_pflag_rx_cqe_compress(struct net_device *netdev, |
1983 | bool enable) |
1984 | { |
1985 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
1986 | struct mlx5_core_dev *mdev = priv->mdev; |
1987 | bool rx_filter; |
1988 | int err; |
1989 | |
1990 | if (!MLX5_CAP_GEN(mdev, cqe_compression)) |
1991 | return -EOPNOTSUPP; |
1992 | |
1993 | rx_filter = priv->tstamp.rx_filter != HWTSTAMP_FILTER_NONE; |
1994 | err = mlx5e_modify_rx_cqe_compression_locked(priv, new_val: enable, rx_filter); |
1995 | if (err) |
1996 | return err; |
1997 | |
1998 | priv->channels.params.rx_cqe_compress_def = enable; |
1999 | |
2000 | return 0; |
2001 | } |
2002 | |
2003 | static int set_pflag_rx_striding_rq(struct net_device *netdev, bool enable) |
2004 | { |
2005 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
2006 | struct mlx5_core_dev *mdev = priv->mdev; |
2007 | struct mlx5e_params new_params; |
2008 | int err; |
2009 | |
2010 | if (enable) { |
2011 | /* Checking the regular RQ here; mlx5e_validate_xsk_param called |
2012 | * from mlx5e_open_xsk will check for each XSK queue, and |
2013 | * mlx5e_safe_switch_params will be reverted if any check fails. |
2014 | */ |
2015 | int err = mlx5e_mpwrq_validate_regular(mdev, params: &priv->channels.params); |
2016 | |
2017 | if (err) |
2018 | return err; |
2019 | } else if (priv->channels.params.packet_merge.type != MLX5E_PACKET_MERGE_NONE) { |
2020 | netdev_warn(dev: netdev, format: "Can't set legacy RQ with HW-GRO/LRO, disable them first\n" ); |
2021 | return -EINVAL; |
2022 | } |
2023 | |
2024 | new_params = priv->channels.params; |
2025 | |
2026 | MLX5E_SET_PFLAG(&new_params, MLX5E_PFLAG_RX_STRIDING_RQ, enable); |
2027 | mlx5e_set_rq_type(mdev, params: &new_params); |
2028 | |
2029 | err = mlx5e_safe_switch_params(priv, new_params: &new_params, NULL, NULL, reset: true); |
2030 | if (err) |
2031 | return err; |
2032 | |
2033 | /* update XDP supported features */ |
2034 | mlx5e_set_xdp_feature(netdev); |
2035 | |
2036 | return 0; |
2037 | } |
2038 | |
2039 | static int set_pflag_rx_no_csum_complete(struct net_device *netdev, bool enable) |
2040 | { |
2041 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
2042 | struct mlx5e_channels *channels = &priv->channels; |
2043 | struct mlx5e_channel *c; |
2044 | int i; |
2045 | |
2046 | if (!test_bit(MLX5E_STATE_OPENED, &priv->state) || |
2047 | priv->channels.params.xdp_prog) |
2048 | return 0; |
2049 | |
2050 | for (i = 0; i < channels->num; i++) { |
2051 | c = channels->c[i]; |
2052 | if (enable) |
2053 | __set_bit(MLX5E_RQ_STATE_NO_CSUM_COMPLETE, &c->rq.state); |
2054 | else |
2055 | __clear_bit(MLX5E_RQ_STATE_NO_CSUM_COMPLETE, &c->rq.state); |
2056 | } |
2057 | |
2058 | return 0; |
2059 | } |
2060 | |
2061 | static int set_pflag_tx_mpwqe_common(struct net_device *netdev, u32 flag, bool enable) |
2062 | { |
2063 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
2064 | struct mlx5_core_dev *mdev = priv->mdev; |
2065 | struct mlx5e_params new_params; |
2066 | |
2067 | if (enable && !mlx5e_tx_mpwqe_supported(mdev)) |
2068 | return -EOPNOTSUPP; |
2069 | |
2070 | new_params = priv->channels.params; |
2071 | |
2072 | MLX5E_SET_PFLAG(&new_params, flag, enable); |
2073 | |
2074 | return mlx5e_safe_switch_params(priv, new_params: &new_params, NULL, NULL, reset: true); |
2075 | } |
2076 | |
2077 | static int set_pflag_xdp_tx_mpwqe(struct net_device *netdev, bool enable) |
2078 | { |
2079 | return set_pflag_tx_mpwqe_common(netdev, flag: MLX5E_PFLAG_XDP_TX_MPWQE, enable); |
2080 | } |
2081 | |
2082 | static int set_pflag_skb_tx_mpwqe(struct net_device *netdev, bool enable) |
2083 | { |
2084 | return set_pflag_tx_mpwqe_common(netdev, flag: MLX5E_PFLAG_SKB_TX_MPWQE, enable); |
2085 | } |
2086 | |
2087 | static int set_pflag_tx_port_ts(struct net_device *netdev, bool enable) |
2088 | { |
2089 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
2090 | struct mlx5_core_dev *mdev = priv->mdev; |
2091 | struct mlx5e_params new_params; |
2092 | int err; |
2093 | |
2094 | if (!MLX5_CAP_GEN(mdev, ts_cqe_to_dest_cqn) || |
2095 | !MLX5_CAP_GEN_2(mdev, ts_cqe_metadata_size2wqe_counter)) |
2096 | return -EOPNOTSUPP; |
2097 | |
2098 | /* Don't allow changing the PTP state if HTB offload is active, because |
2099 | * the numeration of the QoS SQs will change, while per-queue qdiscs are |
2100 | * attached. |
2101 | */ |
2102 | if (mlx5e_selq_is_htb_enabled(selq: &priv->selq)) { |
2103 | netdev_err(dev: priv->netdev, format: "%s: HTB offload is active, cannot change the PTP state\n" , |
2104 | __func__); |
2105 | return -EINVAL; |
2106 | } |
2107 | |
2108 | new_params = priv->channels.params; |
2109 | /* Don't allow enabling TX-port-TS if MQPRIO mode channel offload is |
2110 | * active, since it defines explicitly which TC accepts the packet. |
2111 | * This conflicts with TX-port-TS hijacking the PTP traffic to a specific |
2112 | * HW TX-queue. |
2113 | */ |
2114 | if (enable && new_params.mqprio.mode == TC_MQPRIO_MODE_CHANNEL) { |
2115 | netdev_err(dev: priv->netdev, |
2116 | format: "%s: MQPRIO mode channel offload is active, cannot set the TX-port-TS\n" , |
2117 | __func__); |
2118 | return -EINVAL; |
2119 | } |
2120 | MLX5E_SET_PFLAG(&new_params, MLX5E_PFLAG_TX_PORT_TS, enable); |
2121 | /* No need to verify SQ stop room as |
2122 | * ptpsq.txqsq.stop_room <= generic_sq->stop_room, and both |
2123 | * has the same log_sq_size. |
2124 | */ |
2125 | |
2126 | err = mlx5e_safe_switch_params(priv, new_params: &new_params, |
2127 | preactivate: mlx5e_num_channels_changed_ctx, NULL, reset: true); |
2128 | if (!err) |
2129 | priv->tx_ptp_opened = true; |
2130 | |
2131 | return err; |
2132 | } |
2133 | |
2134 | static const struct pflag_desc mlx5e_priv_flags[MLX5E_NUM_PFLAGS] = { |
2135 | { "rx_cqe_moder" , set_pflag_rx_cqe_based_moder }, |
2136 | { "tx_cqe_moder" , set_pflag_tx_cqe_based_moder }, |
2137 | { "rx_cqe_compress" , set_pflag_rx_cqe_compress }, |
2138 | { "rx_striding_rq" , set_pflag_rx_striding_rq }, |
2139 | { "rx_no_csum_complete" , set_pflag_rx_no_csum_complete }, |
2140 | { "xdp_tx_mpwqe" , set_pflag_xdp_tx_mpwqe }, |
2141 | { "skb_tx_mpwqe" , set_pflag_skb_tx_mpwqe }, |
2142 | { "tx_port_ts" , set_pflag_tx_port_ts }, |
2143 | }; |
2144 | |
2145 | static int mlx5e_handle_pflag(struct net_device *netdev, |
2146 | u32 wanted_flags, |
2147 | enum mlx5e_priv_flag flag) |
2148 | { |
2149 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
2150 | bool enable = !!(wanted_flags & BIT(flag)); |
2151 | u32 changes = wanted_flags ^ priv->channels.params.pflags; |
2152 | int err; |
2153 | |
2154 | if (!(changes & BIT(flag))) |
2155 | return 0; |
2156 | |
2157 | err = mlx5e_priv_flags[flag].handler(netdev, enable); |
2158 | if (err) { |
2159 | netdev_err(dev: netdev, format: "%s private flag '%s' failed err %d\n" , |
2160 | enable ? "Enable" : "Disable" , mlx5e_priv_flags[flag].name, err); |
2161 | return err; |
2162 | } |
2163 | |
2164 | MLX5E_SET_PFLAG(&priv->channels.params, flag, enable); |
2165 | return 0; |
2166 | } |
2167 | |
2168 | static int mlx5e_set_priv_flags(struct net_device *netdev, u32 pflags) |
2169 | { |
2170 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
2171 | enum mlx5e_priv_flag pflag; |
2172 | int err; |
2173 | |
2174 | mutex_lock(&priv->state_lock); |
2175 | |
2176 | for (pflag = 0; pflag < MLX5E_NUM_PFLAGS; pflag++) { |
2177 | err = mlx5e_handle_pflag(netdev, wanted_flags: pflags, flag: pflag); |
2178 | if (err) |
2179 | break; |
2180 | } |
2181 | |
2182 | mutex_unlock(lock: &priv->state_lock); |
2183 | |
2184 | /* Need to fix some features.. */ |
2185 | netdev_update_features(dev: netdev); |
2186 | |
2187 | return err; |
2188 | } |
2189 | |
2190 | static u32 mlx5e_get_priv_flags(struct net_device *netdev) |
2191 | { |
2192 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
2193 | |
2194 | return priv->channels.params.pflags; |
2195 | } |
2196 | |
2197 | static int mlx5e_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, |
2198 | u32 *rule_locs) |
2199 | { |
2200 | struct mlx5e_priv *priv = netdev_priv(dev); |
2201 | |
2202 | /* ETHTOOL_GRXRINGS is needed by ethtool -x which is not part |
2203 | * of rxnfc. We keep this logic out of mlx5e_ethtool_get_rxnfc, |
2204 | * to avoid breaking "ethtool -x" when mlx5e_ethtool_get_rxnfc |
2205 | * is compiled out via CONFIG_MLX5_EN_RXNFC=n. |
2206 | */ |
2207 | if (info->cmd == ETHTOOL_GRXRINGS) { |
2208 | info->data = priv->channels.params.num_channels; |
2209 | return 0; |
2210 | } |
2211 | |
2212 | return mlx5e_ethtool_get_rxnfc(priv, info, rule_locs); |
2213 | } |
2214 | |
2215 | static int mlx5e_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) |
2216 | { |
2217 | struct mlx5e_priv *priv = netdev_priv(dev); |
2218 | |
2219 | return mlx5e_ethtool_set_rxnfc(priv, cmd); |
2220 | } |
2221 | |
2222 | static int query_port_status_opcode(struct mlx5_core_dev *mdev, u32 *status_opcode) |
2223 | { |
2224 | struct mlx5_ifc_pddr_troubleshooting_page_bits *pddr_troubleshooting_page; |
2225 | u32 in[MLX5_ST_SZ_DW(pddr_reg)] = {}; |
2226 | u32 out[MLX5_ST_SZ_DW(pddr_reg)]; |
2227 | int err; |
2228 | |
2229 | MLX5_SET(pddr_reg, in, local_port, 1); |
2230 | MLX5_SET(pddr_reg, in, page_select, |
2231 | MLX5_PDDR_REG_PAGE_SELECT_TROUBLESHOOTING_INFO_PAGE); |
2232 | |
2233 | pddr_troubleshooting_page = MLX5_ADDR_OF(pddr_reg, in, page_data); |
2234 | MLX5_SET(pddr_troubleshooting_page, pddr_troubleshooting_page, |
2235 | group_opcode, MLX5_PDDR_REG_TRBLSH_GROUP_OPCODE_MONITOR); |
2236 | err = mlx5_core_access_reg(dev: mdev, data_in: in, size_in: sizeof(in), data_out: out, |
2237 | size_out: sizeof(out), reg_num: MLX5_REG_PDDR, arg: 0, write: 0); |
2238 | if (err) |
2239 | return err; |
2240 | |
2241 | pddr_troubleshooting_page = MLX5_ADDR_OF(pddr_reg, out, page_data); |
2242 | *status_opcode = MLX5_GET(pddr_troubleshooting_page, pddr_troubleshooting_page, |
2243 | status_opcode); |
2244 | return 0; |
2245 | } |
2246 | |
2247 | struct mlx5e_ethtool_link_ext_state_opcode_mapping { |
2248 | u32 status_opcode; |
2249 | enum ethtool_link_ext_state link_ext_state; |
2250 | u8 link_ext_substate; |
2251 | }; |
2252 | |
2253 | static const struct mlx5e_ethtool_link_ext_state_opcode_mapping |
2254 | mlx5e_link_ext_state_opcode_map[] = { |
2255 | /* States relating to the autonegotiation or issues therein */ |
2256 | {2, ETHTOOL_LINK_EXT_STATE_AUTONEG, |
2257 | ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED}, |
2258 | {3, ETHTOOL_LINK_EXT_STATE_AUTONEG, |
2259 | ETHTOOL_LINK_EXT_SUBSTATE_AN_ACK_NOT_RECEIVED}, |
2260 | {4, ETHTOOL_LINK_EXT_STATE_AUTONEG, |
2261 | ETHTOOL_LINK_EXT_SUBSTATE_AN_NEXT_PAGE_EXCHANGE_FAILED}, |
2262 | {36, ETHTOOL_LINK_EXT_STATE_AUTONEG, |
2263 | ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED_FORCE_MODE}, |
2264 | {38, ETHTOOL_LINK_EXT_STATE_AUTONEG, |
2265 | ETHTOOL_LINK_EXT_SUBSTATE_AN_FEC_MISMATCH_DURING_OVERRIDE}, |
2266 | {39, ETHTOOL_LINK_EXT_STATE_AUTONEG, |
2267 | ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_HCD}, |
2268 | |
2269 | /* Failure during link training */ |
2270 | {5, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE, |
2271 | ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_FRAME_LOCK_NOT_ACQUIRED}, |
2272 | {6, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE, |
2273 | ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_INHIBIT_TIMEOUT}, |
2274 | {7, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE, |
2275 | ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_PARTNER_DID_NOT_SET_RECEIVER_READY}, |
2276 | {8, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE, 0}, |
2277 | {14, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE, |
2278 | ETHTOOL_LINK_EXT_SUBSTATE_LT_REMOTE_FAULT}, |
2279 | |
2280 | /* Logical mismatch in physical coding sublayer or forward error correction sublayer */ |
2281 | {9, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH, |
2282 | ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_BLOCK_LOCK}, |
2283 | {10, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH, |
2284 | ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_AM_LOCK}, |
2285 | {11, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH, |
2286 | ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_GET_ALIGN_STATUS}, |
2287 | {12, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH, |
2288 | ETHTOOL_LINK_EXT_SUBSTATE_LLM_FC_FEC_IS_NOT_LOCKED}, |
2289 | {13, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH, |
2290 | ETHTOOL_LINK_EXT_SUBSTATE_LLM_RS_FEC_IS_NOT_LOCKED}, |
2291 | |
2292 | /* Signal integrity issues */ |
2293 | {15, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY, 0}, |
2294 | {17, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY, |
2295 | ETHTOOL_LINK_EXT_SUBSTATE_BSI_LARGE_NUMBER_OF_PHYSICAL_ERRORS}, |
2296 | {42, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY, |
2297 | ETHTOOL_LINK_EXT_SUBSTATE_BSI_UNSUPPORTED_RATE}, |
2298 | |
2299 | /* No cable connected */ |
2300 | {1024, ETHTOOL_LINK_EXT_STATE_NO_CABLE, 0}, |
2301 | |
2302 | /* Failure is related to cable, e.g., unsupported cable */ |
2303 | {16, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE, |
2304 | ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE}, |
2305 | {20, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE, |
2306 | ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE}, |
2307 | {29, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE, |
2308 | ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE}, |
2309 | {1025, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE, |
2310 | ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE}, |
2311 | {1029, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE, |
2312 | ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE}, |
2313 | {1031, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE, 0}, |
2314 | |
2315 | /* Failure is related to EEPROM, e.g., failure during reading or parsing the data */ |
2316 | {1027, ETHTOOL_LINK_EXT_STATE_EEPROM_ISSUE, 0}, |
2317 | |
2318 | /* Failure during calibration algorithm */ |
2319 | {23, ETHTOOL_LINK_EXT_STATE_CALIBRATION_FAILURE, 0}, |
2320 | |
2321 | /* The hardware is not able to provide the power required from cable or module */ |
2322 | {1032, ETHTOOL_LINK_EXT_STATE_POWER_BUDGET_EXCEEDED, 0}, |
2323 | |
2324 | /* The module is overheated */ |
2325 | {1030, ETHTOOL_LINK_EXT_STATE_OVERHEAT, 0}, |
2326 | }; |
2327 | |
2328 | static void |
2329 | mlx5e_set_link_ext_state(struct mlx5e_ethtool_link_ext_state_opcode_mapping |
2330 | link_ext_state_mapping, |
2331 | struct ethtool_link_ext_state_info *link_ext_state_info) |
2332 | { |
2333 | switch (link_ext_state_mapping.link_ext_state) { |
2334 | case ETHTOOL_LINK_EXT_STATE_AUTONEG: |
2335 | link_ext_state_info->autoneg = |
2336 | link_ext_state_mapping.link_ext_substate; |
2337 | break; |
2338 | case ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE: |
2339 | link_ext_state_info->link_training = |
2340 | link_ext_state_mapping.link_ext_substate; |
2341 | break; |
2342 | case ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH: |
2343 | link_ext_state_info->link_logical_mismatch = |
2344 | link_ext_state_mapping.link_ext_substate; |
2345 | break; |
2346 | case ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY: |
2347 | link_ext_state_info->bad_signal_integrity = |
2348 | link_ext_state_mapping.link_ext_substate; |
2349 | break; |
2350 | case ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE: |
2351 | link_ext_state_info->cable_issue = |
2352 | link_ext_state_mapping.link_ext_substate; |
2353 | break; |
2354 | default: |
2355 | break; |
2356 | } |
2357 | |
2358 | link_ext_state_info->link_ext_state = link_ext_state_mapping.link_ext_state; |
2359 | } |
2360 | |
2361 | static int |
2362 | mlx5e_get_link_ext_state(struct net_device *dev, |
2363 | struct ethtool_link_ext_state_info *link_ext_state_info) |
2364 | { |
2365 | struct mlx5e_ethtool_link_ext_state_opcode_mapping link_ext_state_mapping; |
2366 | struct mlx5e_priv *priv = netdev_priv(dev); |
2367 | u32 status_opcode = 0; |
2368 | int i; |
2369 | |
2370 | /* Exit without data if the interface state is OK, since no extended data is |
2371 | * available in such case |
2372 | */ |
2373 | if (netif_carrier_ok(dev)) |
2374 | return -ENODATA; |
2375 | |
2376 | if (query_port_status_opcode(mdev: priv->mdev, status_opcode: &status_opcode) || |
2377 | !status_opcode) |
2378 | return -ENODATA; |
2379 | |
2380 | for (i = 0; i < ARRAY_SIZE(mlx5e_link_ext_state_opcode_map); i++) { |
2381 | link_ext_state_mapping = mlx5e_link_ext_state_opcode_map[i]; |
2382 | if (link_ext_state_mapping.status_opcode == status_opcode) { |
2383 | mlx5e_set_link_ext_state(link_ext_state_mapping, |
2384 | link_ext_state_info); |
2385 | return 0; |
2386 | } |
2387 | } |
2388 | |
2389 | return -ENODATA; |
2390 | } |
2391 | |
2392 | static void mlx5e_get_eth_phy_stats(struct net_device *netdev, |
2393 | struct ethtool_eth_phy_stats *phy_stats) |
2394 | { |
2395 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
2396 | |
2397 | mlx5e_stats_eth_phy_get(priv, phy_stats); |
2398 | } |
2399 | |
2400 | static void mlx5e_get_eth_mac_stats(struct net_device *netdev, |
2401 | struct ethtool_eth_mac_stats *mac_stats) |
2402 | { |
2403 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
2404 | |
2405 | mlx5e_stats_eth_mac_get(priv, mac_stats); |
2406 | } |
2407 | |
2408 | static void mlx5e_get_eth_ctrl_stats(struct net_device *netdev, |
2409 | struct ethtool_eth_ctrl_stats *ctrl_stats) |
2410 | { |
2411 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
2412 | |
2413 | mlx5e_stats_eth_ctrl_get(priv, ctrl_stats); |
2414 | } |
2415 | |
2416 | static void mlx5e_get_rmon_stats(struct net_device *netdev, |
2417 | struct ethtool_rmon_stats *rmon_stats, |
2418 | const struct ethtool_rmon_hist_range **ranges) |
2419 | { |
2420 | struct mlx5e_priv *priv = netdev_priv(dev: netdev); |
2421 | |
2422 | mlx5e_stats_rmon_get(priv, rmon: rmon_stats, ranges); |
2423 | } |
2424 | |
2425 | const struct ethtool_ops mlx5e_ethtool_ops = { |
2426 | .cap_rss_ctx_supported = true, |
2427 | .supported_coalesce_params = ETHTOOL_COALESCE_USECS | |
2428 | ETHTOOL_COALESCE_MAX_FRAMES | |
2429 | ETHTOOL_COALESCE_USE_ADAPTIVE | |
2430 | ETHTOOL_COALESCE_USE_CQE, |
2431 | .get_drvinfo = mlx5e_get_drvinfo, |
2432 | .get_link = ethtool_op_get_link, |
2433 | .get_link_ext_state = mlx5e_get_link_ext_state, |
2434 | .get_strings = mlx5e_get_strings, |
2435 | .get_sset_count = mlx5e_get_sset_count, |
2436 | .get_ethtool_stats = mlx5e_get_ethtool_stats, |
2437 | .get_ringparam = mlx5e_get_ringparam, |
2438 | .set_ringparam = mlx5e_set_ringparam, |
2439 | .get_channels = mlx5e_get_channels, |
2440 | .set_channels = mlx5e_set_channels, |
2441 | .get_coalesce = mlx5e_get_coalesce, |
2442 | .set_coalesce = mlx5e_set_coalesce, |
2443 | .get_link_ksettings = mlx5e_get_link_ksettings, |
2444 | .set_link_ksettings = mlx5e_set_link_ksettings, |
2445 | .get_rxfh_key_size = mlx5e_get_rxfh_key_size, |
2446 | .get_rxfh_indir_size = mlx5e_get_rxfh_indir_size, |
2447 | .get_rxfh = mlx5e_get_rxfh, |
2448 | .set_rxfh = mlx5e_set_rxfh, |
2449 | .get_rxnfc = mlx5e_get_rxnfc, |
2450 | .set_rxnfc = mlx5e_set_rxnfc, |
2451 | .get_tunable = mlx5e_get_tunable, |
2452 | .set_tunable = mlx5e_set_tunable, |
2453 | .get_pause_stats = mlx5e_get_pause_stats, |
2454 | .get_pauseparam = mlx5e_get_pauseparam, |
2455 | .set_pauseparam = mlx5e_set_pauseparam, |
2456 | .get_ts_info = mlx5e_get_ts_info, |
2457 | .set_phys_id = mlx5e_set_phys_id, |
2458 | .get_wol = mlx5e_get_wol, |
2459 | .set_wol = mlx5e_set_wol, |
2460 | .get_module_info = mlx5e_get_module_info, |
2461 | .get_module_eeprom = mlx5e_get_module_eeprom, |
2462 | .get_module_eeprom_by_page = mlx5e_get_module_eeprom_by_page, |
2463 | .flash_device = mlx5e_flash_device, |
2464 | .get_priv_flags = mlx5e_get_priv_flags, |
2465 | .set_priv_flags = mlx5e_set_priv_flags, |
2466 | .self_test = mlx5e_self_test, |
2467 | .get_fec_stats = mlx5e_get_fec_stats, |
2468 | .get_fecparam = mlx5e_get_fecparam, |
2469 | .set_fecparam = mlx5e_set_fecparam, |
2470 | .get_eth_phy_stats = mlx5e_get_eth_phy_stats, |
2471 | .get_eth_mac_stats = mlx5e_get_eth_mac_stats, |
2472 | .get_eth_ctrl_stats = mlx5e_get_eth_ctrl_stats, |
2473 | .get_rmon_stats = mlx5e_get_rmon_stats, |
2474 | .get_link_ext_stats = mlx5e_get_link_ext_stats |
2475 | }; |
2476 | |