mlx5_en_ethtool.c revision 331569
1/*-
2 * Copyright (c) 2015 Mellanox Technologies. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 *
25 * $FreeBSD: stable/11/sys/dev/mlx5/mlx5_en/mlx5_en_ethtool.c 331569 2018-03-26 20:00:30Z hselasky $
26 */
27
28#include "en.h"
29#include <net/sff8472.h>
30
31void
32mlx5e_create_stats(struct sysctl_ctx_list *ctx,
33    struct sysctl_oid_list *parent, const char *buffer,
34    const char **desc, unsigned num, u64 * arg)
35{
36	struct sysctl_oid *node;
37	unsigned x;
38
39	sysctl_ctx_init(ctx);
40
41	node = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO,
42	    buffer, CTLFLAG_RD, NULL, "Statistics");
43	if (node == NULL)
44		return;
45	for (x = 0; x != num; x++) {
46		SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
47		    desc[2 * x], CTLFLAG_RD, arg + x, desc[2 * x + 1]);
48	}
49}
50
51static void
52mlx5e_ethtool_sync_tx_completion_fact(struct mlx5e_priv *priv)
53{
54	/*
55	 * Limit the maximum distance between completion events to
56	 * half of the currently set TX queue size.
57	 *
58	 * The maximum number of queue entries a single IP packet can
59	 * consume is given by MLX5_SEND_WQE_MAX_WQEBBS.
60	 *
61	 * The worst case max value is then given as below:
62	 */
63	uint64_t max = priv->params_ethtool.tx_queue_size /
64	    (2 * MLX5_SEND_WQE_MAX_WQEBBS);
65
66	/*
67	 * Update the maximum completion factor value in case the
68	 * tx_queue_size field changed. Ensure we don't overflow
69	 * 16-bits.
70	 */
71	if (max < 1)
72		max = 1;
73	else if (max > 65535)
74		max = 65535;
75	priv->params_ethtool.tx_completion_fact_max = max;
76
77	/*
78	 * Verify that the current TX completion factor is within the
79	 * given limits:
80	 */
81	if (priv->params_ethtool.tx_completion_fact < 1)
82		priv->params_ethtool.tx_completion_fact = 1;
83	else if (priv->params_ethtool.tx_completion_fact > max)
84		priv->params_ethtool.tx_completion_fact = max;
85}
86
87#define	MLX5_PARAM_OFFSET(n)				\
88    __offsetof(struct mlx5e_priv, params_ethtool.n)
89
90static int
91mlx5e_ethtool_handler(SYSCTL_HANDLER_ARGS)
92{
93	struct mlx5e_priv *priv = arg1;
94	uint64_t value;
95	int mode_modify;
96	int was_opened;
97	int error;
98
99	PRIV_LOCK(priv);
100	value = priv->params_ethtool.arg[arg2];
101	if (req != NULL) {
102		error = sysctl_handle_64(oidp, &value, 0, req);
103		if (error || req->newptr == NULL ||
104		    value == priv->params_ethtool.arg[arg2])
105			goto done;
106
107		/* assign new value */
108		priv->params_ethtool.arg[arg2] = value;
109	} else {
110		error = 0;
111	}
112	/* check if device is gone */
113	if (priv->gone) {
114		error = ENXIO;
115		goto done;
116	}
117	was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
118	mode_modify = MLX5_CAP_GEN(priv->mdev, cq_period_mode_modify);
119
120	switch (MLX5_PARAM_OFFSET(arg[arg2])) {
121	case MLX5_PARAM_OFFSET(rx_coalesce_usecs):
122		/* import RX coal time */
123		if (priv->params_ethtool.rx_coalesce_usecs < 1)
124			priv->params_ethtool.rx_coalesce_usecs = 0;
125		else if (priv->params_ethtool.rx_coalesce_usecs >
126		    MLX5E_FLD_MAX(cqc, cq_period)) {
127			priv->params_ethtool.rx_coalesce_usecs =
128			    MLX5E_FLD_MAX(cqc, cq_period);
129		}
130		priv->params.rx_cq_moderation_usec =
131		    priv->params_ethtool.rx_coalesce_usecs;
132
133		/* check to avoid down and up the network interface */
134		if (was_opened)
135			error = mlx5e_refresh_channel_params(priv);
136		break;
137
138	case MLX5_PARAM_OFFSET(rx_coalesce_pkts):
139		/* import RX coal pkts */
140		if (priv->params_ethtool.rx_coalesce_pkts < 1)
141			priv->params_ethtool.rx_coalesce_pkts = 0;
142		else if (priv->params_ethtool.rx_coalesce_pkts >
143		    MLX5E_FLD_MAX(cqc, cq_max_count)) {
144			priv->params_ethtool.rx_coalesce_pkts =
145			    MLX5E_FLD_MAX(cqc, cq_max_count);
146		}
147		priv->params.rx_cq_moderation_pkts =
148		    priv->params_ethtool.rx_coalesce_pkts;
149
150		/* check to avoid down and up the network interface */
151		if (was_opened)
152			error = mlx5e_refresh_channel_params(priv);
153		break;
154
155	case MLX5_PARAM_OFFSET(tx_coalesce_usecs):
156		/* import TX coal time */
157		if (priv->params_ethtool.tx_coalesce_usecs < 1)
158			priv->params_ethtool.tx_coalesce_usecs = 0;
159		else if (priv->params_ethtool.tx_coalesce_usecs >
160		    MLX5E_FLD_MAX(cqc, cq_period)) {
161			priv->params_ethtool.tx_coalesce_usecs =
162			    MLX5E_FLD_MAX(cqc, cq_period);
163		}
164		priv->params.tx_cq_moderation_usec =
165		    priv->params_ethtool.tx_coalesce_usecs;
166
167		/* check to avoid down and up the network interface */
168		if (was_opened)
169			error = mlx5e_refresh_channel_params(priv);
170		break;
171
172	case MLX5_PARAM_OFFSET(tx_coalesce_pkts):
173		/* import TX coal pkts */
174		if (priv->params_ethtool.tx_coalesce_pkts < 1)
175			priv->params_ethtool.tx_coalesce_pkts = 0;
176		else if (priv->params_ethtool.tx_coalesce_pkts >
177		    MLX5E_FLD_MAX(cqc, cq_max_count)) {
178			priv->params_ethtool.tx_coalesce_pkts =
179			    MLX5E_FLD_MAX(cqc, cq_max_count);
180		}
181		priv->params.tx_cq_moderation_pkts =
182		    priv->params_ethtool.tx_coalesce_pkts;
183
184		/* check to avoid down and up the network interface */
185		if (was_opened)
186			error = mlx5e_refresh_channel_params(priv);
187		break;
188
189	case MLX5_PARAM_OFFSET(tx_queue_size):
190		/* network interface must be down */
191		if (was_opened)
192			mlx5e_close_locked(priv->ifp);
193
194		/* import TX queue size */
195		if (priv->params_ethtool.tx_queue_size <
196		    (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)) {
197			priv->params_ethtool.tx_queue_size =
198			    (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE);
199		} else if (priv->params_ethtool.tx_queue_size >
200		    priv->params_ethtool.tx_queue_size_max) {
201			priv->params_ethtool.tx_queue_size =
202			    priv->params_ethtool.tx_queue_size_max;
203		}
204		/* store actual TX queue size */
205		priv->params.log_sq_size =
206		    order_base_2(priv->params_ethtool.tx_queue_size);
207		priv->params_ethtool.tx_queue_size =
208		    1 << priv->params.log_sq_size;
209
210		/* verify TX completion factor */
211		mlx5e_ethtool_sync_tx_completion_fact(priv);
212
213		/* restart network interface, if any */
214		if (was_opened)
215			mlx5e_open_locked(priv->ifp);
216		break;
217
218	case MLX5_PARAM_OFFSET(rx_queue_size):
219		/* network interface must be down */
220		if (was_opened)
221			mlx5e_close_locked(priv->ifp);
222
223		/* import RX queue size */
224		if (priv->params_ethtool.rx_queue_size <
225		    (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE)) {
226			priv->params_ethtool.rx_queue_size =
227			    (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE);
228		} else if (priv->params_ethtool.rx_queue_size >
229		    priv->params_ethtool.rx_queue_size_max) {
230			priv->params_ethtool.rx_queue_size =
231			    priv->params_ethtool.rx_queue_size_max;
232		}
233		/* store actual RX queue size */
234		priv->params.log_rq_size =
235		    order_base_2(priv->params_ethtool.rx_queue_size);
236		priv->params_ethtool.rx_queue_size =
237		    1 << priv->params.log_rq_size;
238
239		/* update least number of RX WQEs */
240		priv->params.min_rx_wqes = min(
241		    priv->params_ethtool.rx_queue_size - 1,
242		    MLX5E_PARAMS_DEFAULT_MIN_RX_WQES);
243
244		/* restart network interface, if any */
245		if (was_opened)
246			mlx5e_open_locked(priv->ifp);
247		break;
248
249	case MLX5_PARAM_OFFSET(channels):
250		/* network interface must be down */
251		if (was_opened)
252			mlx5e_close_locked(priv->ifp);
253
254		/* import number of channels */
255		if (priv->params_ethtool.channels < 1)
256			priv->params_ethtool.channels = 1;
257		else if (priv->params_ethtool.channels >
258		    (u64) priv->mdev->priv.eq_table.num_comp_vectors) {
259			priv->params_ethtool.channels =
260			    (u64) priv->mdev->priv.eq_table.num_comp_vectors;
261		}
262		priv->params.num_channels = priv->params_ethtool.channels;
263
264		/* restart network interface, if any */
265		if (was_opened)
266			mlx5e_open_locked(priv->ifp);
267		break;
268
269	case MLX5_PARAM_OFFSET(rx_coalesce_mode):
270		/* network interface must be down */
271		if (was_opened != 0 && mode_modify == 0)
272			mlx5e_close_locked(priv->ifp);
273
274		/* import RX coalesce mode */
275		if (priv->params_ethtool.rx_coalesce_mode != 0)
276			priv->params_ethtool.rx_coalesce_mode = 1;
277		priv->params.rx_cq_moderation_mode =
278		    priv->params_ethtool.rx_coalesce_mode;
279
280		/* restart network interface, if any */
281		if (was_opened != 0) {
282			if (mode_modify == 0)
283				mlx5e_open_locked(priv->ifp);
284			else
285				error = mlx5e_refresh_channel_params(priv);
286		}
287		break;
288
289	case MLX5_PARAM_OFFSET(tx_coalesce_mode):
290		/* network interface must be down */
291		if (was_opened != 0 && mode_modify == 0)
292			mlx5e_close_locked(priv->ifp);
293
294		/* import TX coalesce mode */
295		if (priv->params_ethtool.tx_coalesce_mode != 0)
296			priv->params_ethtool.tx_coalesce_mode = 1;
297		priv->params.tx_cq_moderation_mode =
298		    priv->params_ethtool.tx_coalesce_mode;
299
300		/* restart network interface, if any */
301		if (was_opened != 0) {
302			if (mode_modify == 0)
303				mlx5e_open_locked(priv->ifp);
304			else
305				error = mlx5e_refresh_channel_params(priv);
306		}
307		break;
308
309	case MLX5_PARAM_OFFSET(hw_lro):
310		/* network interface must be down */
311		if (was_opened)
312			mlx5e_close_locked(priv->ifp);
313
314		/* import HW LRO mode */
315		if (priv->params_ethtool.hw_lro != 0) {
316			if ((priv->ifp->if_capenable & IFCAP_LRO) &&
317			    MLX5_CAP_ETH(priv->mdev, lro_cap)) {
318				priv->params.hw_lro_en = 1;
319				priv->params_ethtool.hw_lro = 1;
320			} else {
321				priv->params.hw_lro_en = 0;
322				priv->params_ethtool.hw_lro = 0;
323				error = EINVAL;
324
325				if_printf(priv->ifp, "Can't enable HW LRO: "
326				    "The HW or SW LRO feature is disabled\n");
327			}
328		} else {
329			priv->params.hw_lro_en = 0;
330		}
331		/* restart network interface, if any */
332		if (was_opened)
333			mlx5e_open_locked(priv->ifp);
334		break;
335
336	case MLX5_PARAM_OFFSET(cqe_zipping):
337		/* network interface must be down */
338		if (was_opened)
339			mlx5e_close_locked(priv->ifp);
340
341		/* import CQE zipping mode */
342		if (priv->params_ethtool.cqe_zipping &&
343		    MLX5_CAP_GEN(priv->mdev, cqe_compression)) {
344			priv->params.cqe_zipping_en = true;
345			priv->params_ethtool.cqe_zipping = 1;
346		} else {
347			priv->params.cqe_zipping_en = false;
348			priv->params_ethtool.cqe_zipping = 0;
349		}
350		/* restart network interface, if any */
351		if (was_opened)
352			mlx5e_open_locked(priv->ifp);
353		break;
354
355	case MLX5_PARAM_OFFSET(tx_bufring_disable):
356		/* rangecheck input value */
357		priv->params_ethtool.tx_bufring_disable =
358		    priv->params_ethtool.tx_bufring_disable ? 1 : 0;
359
360		/* reconfigure the sendqueues, if any */
361		if (was_opened) {
362			mlx5e_close_locked(priv->ifp);
363			mlx5e_open_locked(priv->ifp);
364		}
365		break;
366
367	case MLX5_PARAM_OFFSET(tx_completion_fact):
368		/* network interface must be down */
369		if (was_opened)
370			mlx5e_close_locked(priv->ifp);
371
372		/* verify parameter */
373		mlx5e_ethtool_sync_tx_completion_fact(priv);
374
375		/* restart network interface, if any */
376		if (was_opened)
377			mlx5e_open_locked(priv->ifp);
378		break;
379
380	case MLX5_PARAM_OFFSET(modify_tx_dma):
381		/* check if network interface is opened */
382		if (was_opened) {
383			priv->params_ethtool.modify_tx_dma =
384			    priv->params_ethtool.modify_tx_dma ? 1 : 0;
385			/* modify tx according to value */
386			mlx5e_modify_tx_dma(priv, value != 0);
387		} else {
388			/* if closed force enable tx */
389			priv->params_ethtool.modify_tx_dma = 0;
390		}
391		break;
392
393	case MLX5_PARAM_OFFSET(modify_rx_dma):
394		/* check if network interface is opened */
395		if (was_opened) {
396			priv->params_ethtool.modify_rx_dma =
397			    priv->params_ethtool.modify_rx_dma ? 1 : 0;
398			/* modify rx according to value */
399			mlx5e_modify_rx_dma(priv, value != 0);
400		} else {
401			/* if closed force enable rx */
402			priv->params_ethtool.modify_rx_dma = 0;
403		}
404		break;
405
406	case MLX5_PARAM_OFFSET(diag_pci_enable):
407		priv->params_ethtool.diag_pci_enable =
408		    priv->params_ethtool.diag_pci_enable ? 1 : 0;
409
410		error = -mlx5_core_set_diagnostics_full(priv->mdev,
411		    priv->params_ethtool.diag_pci_enable,
412		    priv->params_ethtool.diag_general_enable);
413		break;
414
415	case MLX5_PARAM_OFFSET(diag_general_enable):
416		priv->params_ethtool.diag_general_enable =
417		    priv->params_ethtool.diag_general_enable ? 1 : 0;
418
419		error = -mlx5_core_set_diagnostics_full(priv->mdev,
420		    priv->params_ethtool.diag_pci_enable,
421		    priv->params_ethtool.diag_general_enable);
422		break;
423
424	case MLX5_PARAM_OFFSET(mc_local_lb):
425		priv->params_ethtool.mc_local_lb =
426		    priv->params_ethtool.mc_local_lb ? 1 : 0;
427
428		if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
429			error = mlx5_nic_vport_modify_local_lb(priv->mdev,
430			    MLX5_LOCAL_MC_LB, priv->params_ethtool.mc_local_lb);
431		} else {
432			error = EOPNOTSUPP;
433		}
434		break;
435
436	case MLX5_PARAM_OFFSET(uc_local_lb):
437		priv->params_ethtool.uc_local_lb =
438		    priv->params_ethtool.uc_local_lb ? 1 : 0;
439
440		if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
441			error = mlx5_nic_vport_modify_local_lb(priv->mdev,
442			    MLX5_LOCAL_UC_LB, priv->params_ethtool.uc_local_lb);
443		} else {
444			error = EOPNOTSUPP;
445		}
446		break;
447
448	default:
449		break;
450	}
451done:
452	PRIV_UNLOCK(priv);
453	return (error);
454}
455
456/*
457 * Read the first three bytes of the eeprom in order to get the needed info
458 * for the whole reading.
459 * Byte 0 - Identifier byte
460 * Byte 1 - Revision byte
461 * Byte 2 - Status byte
462 */
463static int
464mlx5e_get_eeprom_info(struct mlx5e_priv *priv, struct mlx5e_eeprom *eeprom)
465{
466	struct mlx5_core_dev *dev = priv->mdev;
467	u32 data = 0;
468	int size_read = 0;
469	int ret;
470
471	ret = mlx5_query_module_num(dev, &eeprom->module_num);
472	if (ret) {
473		if_printf(priv->ifp, "%s:%d: Failed query module error=%d\n",
474		    __func__, __LINE__, ret);
475		return (ret);
476	}
477
478	/* Read the first three bytes to get Identifier, Revision and Status */
479	ret = mlx5_query_eeprom(dev, eeprom->i2c_addr, eeprom->page_num,
480	    eeprom->device_addr, MLX5E_EEPROM_INFO_BYTES, eeprom->module_num, &data,
481	    &size_read);
482	if (ret) {
483		if_printf(priv->ifp, "%s:%d: Failed query eeprom module error=0x%x\n",
484		    __func__, __LINE__, ret);
485		return (ret);
486	}
487
488	switch (data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) {
489	case SFF_8024_ID_QSFP:
490		eeprom->type = MLX5E_ETH_MODULE_SFF_8436;
491		eeprom->len = MLX5E_ETH_MODULE_SFF_8436_LEN;
492		break;
493	case SFF_8024_ID_QSFPPLUS:
494	case SFF_8024_ID_QSFP28:
495		if ((data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) == SFF_8024_ID_QSFP28 ||
496		    ((data & MLX5_EEPROM_REVISION_ID_BYTE_MASK) >> 8) >= 0x3) {
497			eeprom->type = MLX5E_ETH_MODULE_SFF_8636;
498			eeprom->len = MLX5E_ETH_MODULE_SFF_8636_LEN;
499		} else {
500			eeprom->type = MLX5E_ETH_MODULE_SFF_8436;
501			eeprom->len = MLX5E_ETH_MODULE_SFF_8436_LEN;
502		}
503		if ((data & MLX5_EEPROM_PAGE_3_VALID_BIT_MASK) == 0)
504			eeprom->page_valid = 1;
505		break;
506	case SFF_8024_ID_SFP:
507		eeprom->type = MLX5E_ETH_MODULE_SFF_8472;
508		eeprom->len = MLX5E_ETH_MODULE_SFF_8472_LEN;
509		break;
510	default:
511		if_printf(priv->ifp, "%s:%d: Not recognized cable type = 0x%x(%s)\n",
512		    __func__, __LINE__, data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK,
513		    sff_8024_id[data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK]);
514		return (EINVAL);
515	}
516	return (0);
517}
518
519/* Read both low and high pages of the eeprom */
520static int
521mlx5e_get_eeprom(struct mlx5e_priv *priv, struct mlx5e_eeprom *ee)
522{
523	struct mlx5_core_dev *dev = priv->mdev;
524	int size_read = 0;
525	int ret;
526
527	if (ee->len == 0)
528		return (EINVAL);
529
530	/* Read low page of the eeprom */
531	while (ee->device_addr < ee->len) {
532		ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num, ee->device_addr,
533		    ee->len - ee->device_addr, ee->module_num,
534		    ee->data + (ee->device_addr / 4), &size_read);
535		if (ret) {
536			if_printf(priv->ifp, "%s:%d: Failed reading eeprom, "
537			    "error = 0x%02x\n", __func__, __LINE__, ret);
538			return (ret);
539		}
540		ee->device_addr += size_read;
541	}
542
543	/* Read high page of the eeprom */
544	if (ee->page_valid) {
545		ee->device_addr = MLX5E_EEPROM_HIGH_PAGE_OFFSET;
546		ee->page_num = MLX5E_EEPROM_HIGH_PAGE;
547		size_read = 0;
548		while (ee->device_addr < MLX5E_EEPROM_PAGE_LENGTH) {
549			ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num,
550			    ee->device_addr, MLX5E_EEPROM_PAGE_LENGTH - ee->device_addr,
551			    ee->module_num, ee->data + (ee->len / 4) +
552			    ((ee->device_addr - MLX5E_EEPROM_HIGH_PAGE_OFFSET) / 4),
553			    &size_read);
554			if (ret) {
555				if_printf(priv->ifp, "%s:%d: Failed reading eeprom, "
556				    "error = 0x%02x\n", __func__, __LINE__, ret);
557				return (ret);
558			}
559			ee->device_addr += size_read;
560		}
561	}
562	return (0);
563}
564
565static void
566mlx5e_print_eeprom(struct mlx5e_eeprom *eeprom)
567{
568	int row;
569	int index_in_row;
570	int byte_to_write = 0;
571	int line_length = 16;
572
573	printf("\nOffset\t\tValues\n");
574	printf("------\t\t------");
575	while (byte_to_write < eeprom->len) {
576		printf("\n0x%04X\t\t", byte_to_write);
577		for (index_in_row = 0; index_in_row < line_length; index_in_row++) {
578			printf("%02X ", ((u8 *)eeprom->data)[byte_to_write]);
579			byte_to_write++;
580		}
581	}
582
583	if (eeprom->page_valid) {
584		row = MLX5E_EEPROM_HIGH_PAGE_OFFSET;
585		printf("\n\nUpper Page 0x03\n");
586		printf("\nOffset\t\tValues\n");
587		printf("------\t\t------");
588		while (row < MLX5E_EEPROM_PAGE_LENGTH) {
589			printf("\n0x%04X\t\t", row);
590			for (index_in_row = 0; index_in_row < line_length; index_in_row++) {
591				printf("%02X ", ((u8 *)eeprom->data)[byte_to_write]);
592				byte_to_write++;
593				row++;
594			}
595		}
596	}
597}
598
599/*
600 * Read cable EEPROM module information by first inspecting the first
601 * three bytes to get the initial information for a whole reading.
602 * Information will be printed to dmesg.
603 */
604static int
605mlx5e_read_eeprom(SYSCTL_HANDLER_ARGS)
606{
607	struct mlx5e_priv *priv = arg1;
608	struct mlx5e_eeprom eeprom;
609	int error;
610	int result = 0;
611
612	PRIV_LOCK(priv);
613	error = sysctl_handle_int(oidp, &result, 0, req);
614	if (error || !req->newptr)
615		goto done;
616
617	/* Check if device is gone */
618	if (priv->gone) {
619		error = ENXIO;
620		goto done;
621	}
622
623	if (result == 1) {
624		eeprom.i2c_addr = MLX5E_I2C_ADDR_LOW;
625		eeprom.device_addr = 0;
626		eeprom.page_num = MLX5E_EEPROM_LOW_PAGE;
627		eeprom.page_valid = 0;
628
629		/* Read three first bytes to get important info */
630		error = mlx5e_get_eeprom_info(priv, &eeprom);
631		if (error) {
632			if_printf(priv->ifp, "%s:%d: Failed reading eeprom's "
633			    "initial information\n", __func__, __LINE__);
634			error = 0;
635			goto done;
636		}
637		/*
638		 * Allocate needed length buffer and additional space for
639		 * page 0x03
640		 */
641		eeprom.data = malloc(eeprom.len + MLX5E_EEPROM_PAGE_LENGTH,
642		    M_MLX5EN, M_WAITOK | M_ZERO);
643
644		/* Read the whole eeprom information */
645		error = mlx5e_get_eeprom(priv, &eeprom);
646		if (error) {
647			if_printf(priv->ifp, "%s:%d: Failed reading eeprom\n",
648			    __func__, __LINE__);
649			error = 0;
650			/*
651			 * Continue printing partial information in case of
652			 * an error
653			 */
654		}
655		mlx5e_print_eeprom(&eeprom);
656		free(eeprom.data, M_MLX5EN);
657	}
658done:
659	PRIV_UNLOCK(priv);
660	return (error);
661}
662
663static const char *mlx5e_params_desc[] = {
664	MLX5E_PARAMS(MLX5E_STATS_DESC)
665};
666
667static const char *mlx5e_port_stats_debug_desc[] = {
668	MLX5E_PORT_STATS_DEBUG(MLX5E_STATS_DESC)
669};
670
671static int
672mlx5e_ethtool_debug_stats(SYSCTL_HANDLER_ARGS)
673{
674	struct mlx5e_priv *priv = arg1;
675	int error;
676	int sys_debug;
677
678	sys_debug = priv->sysctl_debug;
679	error = sysctl_handle_int(oidp, &priv->sysctl_debug, 0, req);
680	if (error || !req->newptr)
681		return (error);
682	priv->sysctl_debug = !!priv->sysctl_debug;
683	if (sys_debug == priv->sysctl_debug)
684		return (error);
685	if (priv->sysctl_debug)
686		mlx5e_create_stats(&priv->stats.port_stats_debug.ctx,
687		    SYSCTL_CHILDREN(priv->sysctl_ifnet), "debug_stats",
688		    mlx5e_port_stats_debug_desc, MLX5E_PORT_STATS_DEBUG_NUM,
689		    priv->stats.port_stats_debug.arg);
690	else
691		sysctl_ctx_free(&priv->stats.port_stats_debug.ctx);
692	return (error);
693}
694
695static void
696mlx5e_create_diagnostics(struct mlx5e_priv *priv)
697{
698	struct mlx5_core_diagnostics_entry entry;
699	struct sysctl_ctx_list *ctx;
700	struct sysctl_oid *node;
701	int x;
702
703	/* sysctl context we are using */
704	ctx = &priv->sysctl_ctx;
705
706	/* create root node */
707	node = SYSCTL_ADD_NODE(ctx,
708	    SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
709	    "diagnostics", CTLFLAG_RD, NULL, "Diagnostics");
710	if (node == NULL)
711		return;
712
713	/* create PCI diagnostics */
714	for (x = 0; x != MLX5_CORE_PCI_DIAGNOSTICS_NUM; x++) {
715		entry = mlx5_core_pci_diagnostics_table[x];
716		if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0)
717			continue;
718		SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
719		    entry.desc, CTLFLAG_RD, priv->params_pci.array + x,
720		    "PCI diagnostics counter");
721	}
722
723	/* create general diagnostics */
724	for (x = 0; x != MLX5_CORE_GENERAL_DIAGNOSTICS_NUM; x++) {
725		entry = mlx5_core_general_diagnostics_table[x];
726		if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0)
727			continue;
728		SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
729		    entry.desc, CTLFLAG_RD, priv->params_general.array + x,
730		    "General diagnostics counter");
731	}
732}
733
734void
735mlx5e_create_ethtool(struct mlx5e_priv *priv)
736{
737	struct sysctl_oid *node;
738	const char *pnameunit;
739	unsigned x;
740
741	/* set some defaults */
742	priv->params_ethtool.tx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE;
743	priv->params_ethtool.rx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE;
744	priv->params_ethtool.tx_queue_size = 1 << priv->params.log_sq_size;
745	priv->params_ethtool.rx_queue_size = 1 << priv->params.log_rq_size;
746	priv->params_ethtool.channels = priv->params.num_channels;
747	priv->params_ethtool.coalesce_pkts_max = MLX5E_FLD_MAX(cqc, cq_max_count);
748	priv->params_ethtool.coalesce_usecs_max = MLX5E_FLD_MAX(cqc, cq_period);
749	priv->params_ethtool.rx_coalesce_mode = priv->params.rx_cq_moderation_mode;
750	priv->params_ethtool.rx_coalesce_usecs = priv->params.rx_cq_moderation_usec;
751	priv->params_ethtool.rx_coalesce_pkts = priv->params.rx_cq_moderation_pkts;
752	priv->params_ethtool.tx_coalesce_mode = priv->params.tx_cq_moderation_mode;
753	priv->params_ethtool.tx_coalesce_usecs = priv->params.tx_cq_moderation_usec;
754	priv->params_ethtool.tx_coalesce_pkts = priv->params.tx_cq_moderation_pkts;
755	priv->params_ethtool.hw_lro = priv->params.hw_lro_en;
756	priv->params_ethtool.cqe_zipping = priv->params.cqe_zipping_en;
757	mlx5e_ethtool_sync_tx_completion_fact(priv);
758
759	/* get default values for local loopback, if any */
760	if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
761		int err;
762		u8 val;
763
764		err = mlx5_nic_vport_query_local_lb(priv->mdev, MLX5_LOCAL_MC_LB, &val);
765		if (err == 0)
766			priv->params_ethtool.mc_local_lb = val;
767
768		err = mlx5_nic_vport_query_local_lb(priv->mdev, MLX5_LOCAL_UC_LB, &val);
769		if (err == 0)
770			priv->params_ethtool.uc_local_lb = val;
771	}
772
773	/* create root node */
774	node = SYSCTL_ADD_NODE(&priv->sysctl_ctx,
775	    SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
776	    "conf", CTLFLAG_RW, NULL, "Configuration");
777	if (node == NULL)
778		return;
779	for (x = 0; x != MLX5E_PARAMS_NUM; x++) {
780		/* check for read-only parameter */
781		if (strstr(mlx5e_params_desc[2 * x], "_max") != NULL) {
782			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
783			    mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RD |
784			    CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU",
785			    mlx5e_params_desc[2 * x + 1]);
786		} else {
787#if (__FreeBSD_version < 1100000)
788			char path[64];
789#endif
790			/*
791			 * NOTE: In FreeBSD-11 and newer the
792			 * CTLFLAG_RWTUN flag will take care of
793			 * loading default sysctl value from the
794			 * kernel environment, if any:
795			 */
796			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
797			    mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RWTUN |
798			    CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU",
799			    mlx5e_params_desc[2 * x + 1]);
800
801#if (__FreeBSD_version < 1100000)
802			/* compute path for sysctl */
803			snprintf(path, sizeof(path), "dev.mce.%d.conf.%s",
804			    device_get_unit(priv->mdev->pdev->dev.bsddev),
805			    mlx5e_params_desc[2 * x]);
806
807			/* try to fetch tunable, if any */
808			if (TUNABLE_QUAD_FETCH(path, &priv->params_ethtool.arg[x]))
809				mlx5e_ethtool_handler(NULL, priv, x, NULL);
810#endif
811		}
812	}
813
814	SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
815	    "debug_stats", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv,
816	    0, &mlx5e_ethtool_debug_stats, "I", "Extended debug statistics");
817
818	pnameunit = device_get_nameunit(priv->mdev->pdev->dev.bsddev);
819
820	SYSCTL_ADD_STRING(&priv->sysctl_ctx, SYSCTL_CHILDREN(node),
821	    OID_AUTO, "device_name", CTLFLAG_RD,
822	    __DECONST(void *, pnameunit), 0,
823	    "PCI device name");
824
825	/* EEPROM support */
826	SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO, "eeprom_info",
827	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0,
828	    mlx5e_read_eeprom, "I", "EEPROM information");
829
830	/* Diagnostics support */
831	mlx5e_create_diagnostics(priv);
832}
833