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/10/sys/dev/mlx5/mlx5_en/mlx5_en_ethtool.c 341984 2018-12-12 13:14:41Z 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_rsss):
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_rsss < 1)
256			priv->params_ethtool.channels_rsss = 1;
257		else if (priv->params_ethtool.channels_rsss > 128)
258			priv->params_ethtool.channels_rsss = 128;
259
260		priv->params.channels_rsss = priv->params_ethtool.channels_rsss;
261
262		/* restart network interface, if any */
263		if (was_opened)
264			mlx5e_open_locked(priv->ifp);
265		break;
266
267	case MLX5_PARAM_OFFSET(channels):
268		/* network interface must be down */
269		if (was_opened)
270			mlx5e_close_locked(priv->ifp);
271
272		/* import number of channels */
273		if (priv->params_ethtool.channels < 1)
274			priv->params_ethtool.channels = 1;
275		else if (priv->params_ethtool.channels >
276		    (u64) priv->mdev->priv.eq_table.num_comp_vectors) {
277			priv->params_ethtool.channels =
278			    (u64) priv->mdev->priv.eq_table.num_comp_vectors;
279		}
280		priv->params.num_channels = priv->params_ethtool.channels;
281
282		/* restart network interface, if any */
283		if (was_opened)
284			mlx5e_open_locked(priv->ifp);
285		break;
286
287	case MLX5_PARAM_OFFSET(rx_coalesce_mode):
288		/* network interface must be down */
289		if (was_opened != 0 && mode_modify == 0)
290			mlx5e_close_locked(priv->ifp);
291
292		/* import RX coalesce mode */
293		if (priv->params_ethtool.rx_coalesce_mode != 0)
294			priv->params_ethtool.rx_coalesce_mode = 1;
295		priv->params.rx_cq_moderation_mode =
296		    priv->params_ethtool.rx_coalesce_mode;
297
298		/* restart network interface, if any */
299		if (was_opened != 0) {
300			if (mode_modify == 0)
301				mlx5e_open_locked(priv->ifp);
302			else
303				error = mlx5e_refresh_channel_params(priv);
304		}
305		break;
306
307	case MLX5_PARAM_OFFSET(tx_coalesce_mode):
308		/* network interface must be down */
309		if (was_opened != 0 && mode_modify == 0)
310			mlx5e_close_locked(priv->ifp);
311
312		/* import TX coalesce mode */
313		if (priv->params_ethtool.tx_coalesce_mode != 0)
314			priv->params_ethtool.tx_coalesce_mode = 1;
315		priv->params.tx_cq_moderation_mode =
316		    priv->params_ethtool.tx_coalesce_mode;
317
318		/* restart network interface, if any */
319		if (was_opened != 0) {
320			if (mode_modify == 0)
321				mlx5e_open_locked(priv->ifp);
322			else
323				error = mlx5e_refresh_channel_params(priv);
324		}
325		break;
326
327	case MLX5_PARAM_OFFSET(hw_lro):
328		/* network interface must be down */
329		if (was_opened)
330			mlx5e_close_locked(priv->ifp);
331
332		/* import HW LRO mode */
333		if (priv->params_ethtool.hw_lro != 0 &&
334		    MLX5_CAP_ETH(priv->mdev, lro_cap)) {
335			priv->params_ethtool.hw_lro = 1;
336			/* check if feature should actually be enabled */
337			if (priv->ifp->if_capenable & IFCAP_LRO) {
338				priv->params.hw_lro_en = true;
339			} else {
340				priv->params.hw_lro_en = false;
341
342				if_printf(priv->ifp, "To enable HW LRO "
343				    "please also enable LRO via ifconfig(8).\n");
344			}
345		} else {
346			/* return an error if HW does not support this feature */
347			if (priv->params_ethtool.hw_lro != 0)
348				error = EINVAL;
349			priv->params.hw_lro_en = false;
350			priv->params_ethtool.hw_lro = 0;
351		}
352		/* restart network interface, if any */
353		if (was_opened)
354			mlx5e_open_locked(priv->ifp);
355		break;
356
357	case MLX5_PARAM_OFFSET(cqe_zipping):
358		/* network interface must be down */
359		if (was_opened)
360			mlx5e_close_locked(priv->ifp);
361
362		/* import CQE zipping mode */
363		if (priv->params_ethtool.cqe_zipping &&
364		    MLX5_CAP_GEN(priv->mdev, cqe_compression)) {
365			priv->params.cqe_zipping_en = true;
366			priv->params_ethtool.cqe_zipping = 1;
367		} else {
368			priv->params.cqe_zipping_en = false;
369			priv->params_ethtool.cqe_zipping = 0;
370		}
371		/* restart network interface, if any */
372		if (was_opened)
373			mlx5e_open_locked(priv->ifp);
374		break;
375
376	case MLX5_PARAM_OFFSET(tx_bufring_disable):
377		/* rangecheck input value */
378		priv->params_ethtool.tx_bufring_disable =
379		    priv->params_ethtool.tx_bufring_disable ? 1 : 0;
380
381		/* reconfigure the sendqueues, if any */
382		if (was_opened) {
383			mlx5e_close_locked(priv->ifp);
384			mlx5e_open_locked(priv->ifp);
385		}
386		break;
387
388	case MLX5_PARAM_OFFSET(tx_completion_fact):
389		/* network interface must be down */
390		if (was_opened)
391			mlx5e_close_locked(priv->ifp);
392
393		/* verify parameter */
394		mlx5e_ethtool_sync_tx_completion_fact(priv);
395
396		/* restart network interface, if any */
397		if (was_opened)
398			mlx5e_open_locked(priv->ifp);
399		break;
400
401	case MLX5_PARAM_OFFSET(diag_pci_enable):
402		priv->params_ethtool.diag_pci_enable =
403		    priv->params_ethtool.diag_pci_enable ? 1 : 0;
404
405		error = -mlx5_core_set_diagnostics_full(priv->mdev,
406		    priv->params_ethtool.diag_pci_enable,
407		    priv->params_ethtool.diag_general_enable);
408		break;
409
410	case MLX5_PARAM_OFFSET(diag_general_enable):
411		priv->params_ethtool.diag_general_enable =
412		    priv->params_ethtool.diag_general_enable ? 1 : 0;
413
414		error = -mlx5_core_set_diagnostics_full(priv->mdev,
415		    priv->params_ethtool.diag_pci_enable,
416		    priv->params_ethtool.diag_general_enable);
417		break;
418
419	default:
420		break;
421	}
422done:
423	PRIV_UNLOCK(priv);
424	return (error);
425}
426
427/*
428 * Read the first three bytes of the eeprom in order to get the needed info
429 * for the whole reading.
430 * Byte 0 - Identifier byte
431 * Byte 1 - Revision byte
432 * Byte 2 - Status byte
433 */
434static int
435mlx5e_get_eeprom_info(struct mlx5e_priv *priv, struct mlx5e_eeprom *eeprom)
436{
437	struct mlx5_core_dev *dev = priv->mdev;
438	u32 data = 0;
439	int size_read = 0;
440	int ret;
441
442	ret = mlx5_query_module_num(dev, &eeprom->module_num);
443	if (ret) {
444		if_printf(priv->ifp, "%s:%d: Failed query module error=%d\n",
445		    __func__, __LINE__, ret);
446		return (ret);
447	}
448
449	/* Read the first three bytes to get Identifier, Revision and Status */
450	ret = mlx5_query_eeprom(dev, eeprom->i2c_addr, eeprom->page_num,
451	    eeprom->device_addr, MLX5E_EEPROM_INFO_BYTES, eeprom->module_num, &data,
452	    &size_read);
453	if (ret) {
454		if_printf(priv->ifp, "%s:%d: Failed query eeprom module error=0x%x\n",
455		    __func__, __LINE__, ret);
456		return (ret);
457	}
458
459	switch (data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) {
460	case SFF_8024_ID_QSFP:
461		eeprom->type = MLX5E_ETH_MODULE_SFF_8436;
462		eeprom->len = MLX5E_ETH_MODULE_SFF_8436_LEN;
463		break;
464	case SFF_8024_ID_QSFPPLUS:
465	case SFF_8024_ID_QSFP28:
466		if ((data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) == SFF_8024_ID_QSFP28 ||
467		    ((data & MLX5_EEPROM_REVISION_ID_BYTE_MASK) >> 8) >= 0x3) {
468			eeprom->type = MLX5E_ETH_MODULE_SFF_8636;
469			eeprom->len = MLX5E_ETH_MODULE_SFF_8636_LEN;
470		} else {
471			eeprom->type = MLX5E_ETH_MODULE_SFF_8436;
472			eeprom->len = MLX5E_ETH_MODULE_SFF_8436_LEN;
473		}
474		if ((data & MLX5_EEPROM_PAGE_3_VALID_BIT_MASK) == 0)
475			eeprom->page_valid = 1;
476		break;
477	case SFF_8024_ID_SFP:
478		eeprom->type = MLX5E_ETH_MODULE_SFF_8472;
479		eeprom->len = MLX5E_ETH_MODULE_SFF_8472_LEN;
480		break;
481	default:
482		if_printf(priv->ifp, "%s:%d: Not recognized cable type = 0x%x(%s)\n",
483		    __func__, __LINE__, data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK,
484		    sff_8024_id[data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK]);
485		return (EINVAL);
486	}
487	return (0);
488}
489
490/* Read both low and high pages of the eeprom */
491static int
492mlx5e_get_eeprom(struct mlx5e_priv *priv, struct mlx5e_eeprom *ee)
493{
494	struct mlx5_core_dev *dev = priv->mdev;
495	int size_read = 0;
496	int ret;
497
498	if (ee->len == 0)
499		return (EINVAL);
500
501	/* Read low page of the eeprom */
502	while (ee->device_addr < ee->len) {
503		ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num, ee->device_addr,
504		    ee->len - ee->device_addr, ee->module_num,
505		    ee->data + (ee->device_addr / 4), &size_read);
506		if (ret) {
507			if_printf(priv->ifp, "%s:%d: Failed reading eeprom, "
508			    "error = 0x%02x\n", __func__, __LINE__, ret);
509			return (ret);
510		}
511		ee->device_addr += size_read;
512	}
513
514	/* Read high page of the eeprom */
515	if (ee->page_valid) {
516		ee->device_addr = MLX5E_EEPROM_HIGH_PAGE_OFFSET;
517		ee->page_num = MLX5E_EEPROM_HIGH_PAGE;
518		size_read = 0;
519		while (ee->device_addr < MLX5E_EEPROM_PAGE_LENGTH) {
520			ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num,
521			    ee->device_addr, MLX5E_EEPROM_PAGE_LENGTH - ee->device_addr,
522			    ee->module_num, ee->data + (ee->len / 4) +
523			    ((ee->device_addr - MLX5E_EEPROM_HIGH_PAGE_OFFSET) / 4),
524			    &size_read);
525			if (ret) {
526				if_printf(priv->ifp, "%s:%d: Failed reading eeprom, "
527				    "error = 0x%02x\n", __func__, __LINE__, ret);
528				return (ret);
529			}
530			ee->device_addr += size_read;
531		}
532	}
533	return (0);
534}
535
536static void
537mlx5e_print_eeprom(struct mlx5e_eeprom *eeprom)
538{
539	int row;
540	int index_in_row;
541	int byte_to_write = 0;
542	int line_length = 16;
543
544	printf("\nOffset\t\tValues\n");
545	printf("------\t\t------");
546	while (byte_to_write < eeprom->len) {
547		printf("\n0x%04X\t\t", byte_to_write);
548		for (index_in_row = 0; index_in_row < line_length; index_in_row++) {
549			printf("%02X ", ((u8 *)eeprom->data)[byte_to_write]);
550			byte_to_write++;
551		}
552	}
553
554	if (eeprom->page_valid) {
555		row = MLX5E_EEPROM_HIGH_PAGE_OFFSET;
556		printf("\n\nUpper Page 0x03\n");
557		printf("\nOffset\t\tValues\n");
558		printf("------\t\t------");
559		while (row < MLX5E_EEPROM_PAGE_LENGTH) {
560			printf("\n0x%04X\t\t", row);
561			for (index_in_row = 0; index_in_row < line_length; index_in_row++) {
562				printf("%02X ", ((u8 *)eeprom->data)[byte_to_write]);
563				byte_to_write++;
564				row++;
565			}
566		}
567	}
568}
569
570/*
571 * Read cable EEPROM module information by first inspecting the first
572 * three bytes to get the initial information for a whole reading.
573 * Information will be printed to dmesg.
574 */
575static int
576mlx5e_read_eeprom(SYSCTL_HANDLER_ARGS)
577{
578	struct mlx5e_priv *priv = arg1;
579	struct mlx5e_eeprom eeprom;
580	int error;
581	int result = 0;
582
583	PRIV_LOCK(priv);
584	error = sysctl_handle_int(oidp, &result, 0, req);
585	if (error || !req->newptr)
586		goto done;
587
588	/* Check if device is gone */
589	if (priv->gone) {
590		error = ENXIO;
591		goto done;
592	}
593
594	if (result == 1) {
595		eeprom.i2c_addr = MLX5E_I2C_ADDR_LOW;
596		eeprom.device_addr = 0;
597		eeprom.page_num = MLX5E_EEPROM_LOW_PAGE;
598		eeprom.page_valid = 0;
599
600		/* Read three first bytes to get important info */
601		error = mlx5e_get_eeprom_info(priv, &eeprom);
602		if (error) {
603			if_printf(priv->ifp, "%s:%d: Failed reading eeprom's "
604			    "initial information\n", __func__, __LINE__);
605			error = 0;
606			goto done;
607		}
608		/*
609		 * Allocate needed length buffer and additional space for
610		 * page 0x03
611		 */
612		eeprom.data = malloc(eeprom.len + MLX5E_EEPROM_PAGE_LENGTH,
613		    M_MLX5EN, M_WAITOK | M_ZERO);
614
615		/* Read the whole eeprom information */
616		error = mlx5e_get_eeprom(priv, &eeprom);
617		if (error) {
618			if_printf(priv->ifp, "%s:%d: Failed reading eeprom\n",
619			    __func__, __LINE__);
620			error = 0;
621			/*
622			 * Continue printing partial information in case of
623			 * an error
624			 */
625		}
626		mlx5e_print_eeprom(&eeprom);
627		free(eeprom.data, M_MLX5EN);
628	}
629done:
630	PRIV_UNLOCK(priv);
631	return (error);
632}
633
634static const char *mlx5e_params_desc[] = {
635	MLX5E_PARAMS(MLX5E_STATS_DESC)
636};
637
638static const char *mlx5e_port_stats_debug_desc[] = {
639	MLX5E_PORT_STATS_DEBUG(MLX5E_STATS_DESC)
640};
641
642static int
643mlx5e_ethtool_debug_stats(SYSCTL_HANDLER_ARGS)
644{
645	struct mlx5e_priv *priv = arg1;
646	int error;
647	int sys_debug;
648
649	sys_debug = priv->sysctl_debug;
650	error = sysctl_handle_int(oidp, &priv->sysctl_debug, 0, req);
651	if (error || !req->newptr)
652		return (error);
653	priv->sysctl_debug = !!priv->sysctl_debug;
654	if (sys_debug == priv->sysctl_debug)
655		return (error);
656	if (priv->sysctl_debug)
657		mlx5e_create_stats(&priv->stats.port_stats_debug.ctx,
658		    SYSCTL_CHILDREN(priv->sysctl_ifnet), "debug_stats",
659		    mlx5e_port_stats_debug_desc, MLX5E_PORT_STATS_DEBUG_NUM,
660		    priv->stats.port_stats_debug.arg);
661	else
662		sysctl_ctx_free(&priv->stats.port_stats_debug.ctx);
663	return (error);
664}
665
666static void
667mlx5e_create_diagnostics(struct mlx5e_priv *priv)
668{
669	struct mlx5_core_diagnostics_entry entry;
670	struct sysctl_ctx_list *ctx;
671	struct sysctl_oid *node;
672	int x;
673
674	/* sysctl context we are using */
675	ctx = &priv->sysctl_ctx;
676
677	/* create root node */
678	node = SYSCTL_ADD_NODE(ctx,
679	    SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
680	    "diagnostics", CTLFLAG_RD, NULL, "Diagnostics");
681	if (node == NULL)
682		return;
683
684	/* create PCI diagnostics */
685	for (x = 0; x != MLX5_CORE_PCI_DIAGNOSTICS_NUM; x++) {
686		entry = mlx5_core_pci_diagnostics_table[x];
687		if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0)
688			continue;
689		SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
690		    entry.desc, CTLFLAG_RD, priv->params_pci.array + x,
691		    "PCI diagnostics counter");
692	}
693
694	/* create general diagnostics */
695	for (x = 0; x != MLX5_CORE_GENERAL_DIAGNOSTICS_NUM; x++) {
696		entry = mlx5_core_general_diagnostics_table[x];
697		if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0)
698			continue;
699		SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
700		    entry.desc, CTLFLAG_RD, priv->params_general.array + x,
701		    "General diagnostics counter");
702	}
703}
704
705void
706mlx5e_create_ethtool(struct mlx5e_priv *priv)
707{
708	struct sysctl_oid *node;
709	const char *pnameunit;
710	unsigned x;
711
712	/* set some defaults */
713	priv->params_ethtool.tx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE;
714	priv->params_ethtool.rx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE;
715	priv->params_ethtool.tx_queue_size = 1 << priv->params.log_sq_size;
716	priv->params_ethtool.rx_queue_size = 1 << priv->params.log_rq_size;
717	priv->params_ethtool.channels = priv->params.num_channels;
718	priv->params_ethtool.channels_rsss = priv->params.channels_rsss;
719	priv->params_ethtool.coalesce_pkts_max = MLX5E_FLD_MAX(cqc, cq_max_count);
720	priv->params_ethtool.coalesce_usecs_max = MLX5E_FLD_MAX(cqc, cq_period);
721	priv->params_ethtool.rx_coalesce_mode = priv->params.rx_cq_moderation_mode;
722	priv->params_ethtool.rx_coalesce_usecs = priv->params.rx_cq_moderation_usec;
723	priv->params_ethtool.rx_coalesce_pkts = priv->params.rx_cq_moderation_pkts;
724	priv->params_ethtool.tx_coalesce_mode = priv->params.tx_cq_moderation_mode;
725	priv->params_ethtool.tx_coalesce_usecs = priv->params.tx_cq_moderation_usec;
726	priv->params_ethtool.tx_coalesce_pkts = priv->params.tx_cq_moderation_pkts;
727	priv->params_ethtool.hw_lro = priv->params.hw_lro_en;
728	priv->params_ethtool.cqe_zipping = priv->params.cqe_zipping_en;
729	mlx5e_ethtool_sync_tx_completion_fact(priv);
730
731	/* create root node */
732	node = SYSCTL_ADD_NODE(&priv->sysctl_ctx,
733	    SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
734	    "conf", CTLFLAG_RW, NULL, "Configuration");
735	if (node == NULL)
736		return;
737	for (x = 0; x != MLX5E_PARAMS_NUM; x++) {
738		/* check for read-only parameter */
739		if (strstr(mlx5e_params_desc[2 * x], "_max") != NULL ||
740		    strstr(mlx5e_params_desc[2 * x], "_mtu") != NULL) {
741			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
742			    mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RD |
743			    CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU",
744			    mlx5e_params_desc[2 * x + 1]);
745		} else {
746#if (__FreeBSD_version < 1100000)
747			char path[64];
748#endif
749			/*
750			 * NOTE: In FreeBSD-11 and newer the
751			 * CTLFLAG_RWTUN flag will take care of
752			 * loading default sysctl value from the
753			 * kernel environment, if any:
754			 */
755			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
756			    mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RWTUN |
757			    CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU",
758			    mlx5e_params_desc[2 * x + 1]);
759
760#if (__FreeBSD_version < 1100000)
761			/* compute path for sysctl */
762			snprintf(path, sizeof(path), "dev.mce.%d.conf.%s",
763			    device_get_unit(priv->mdev->pdev->dev.bsddev),
764			    mlx5e_params_desc[2 * x]);
765
766			/* try to fetch tunable, if any */
767			if (TUNABLE_QUAD_FETCH(path, &priv->params_ethtool.arg[x]))
768				mlx5e_ethtool_handler(NULL, priv, x, NULL);
769#endif
770		}
771	}
772
773	SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
774	    "debug_stats", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv,
775	    0, &mlx5e_ethtool_debug_stats, "I", "Extended debug statistics");
776
777	pnameunit = device_get_nameunit(priv->mdev->pdev->dev.bsddev);
778
779	SYSCTL_ADD_STRING(&priv->sysctl_ctx, SYSCTL_CHILDREN(node),
780	    OID_AUTO, "device_name", CTLFLAG_RD,
781	    __DECONST(void *, pnameunit), 0,
782	    "PCI device name");
783
784	/* EEPROM support */
785	SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO, "eeprom_info",
786	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0,
787	    mlx5e_read_eeprom, "I", "EEPROM information");
788
789	/* Diagnostics support */
790	mlx5e_create_diagnostics(priv);
791}
792