xref: /freebsd/sys/dev/mlx5/mlx5_en/mlx5_en_ethtool.c (revision f03f517b)
1dc7e38acSHans Petter Selasky /*-
2dc7e38acSHans Petter Selasky  * Copyright (c) 2015 Mellanox Technologies. All rights reserved.
3dc7e38acSHans Petter Selasky  *
4dc7e38acSHans Petter Selasky  * Redistribution and use in source and binary forms, with or without
5dc7e38acSHans Petter Selasky  * modification, are permitted provided that the following conditions
6dc7e38acSHans Petter Selasky  * are met:
7dc7e38acSHans Petter Selasky  * 1. Redistributions of source code must retain the above copyright
8dc7e38acSHans Petter Selasky  *    notice, this list of conditions and the following disclaimer.
9dc7e38acSHans Petter Selasky  * 2. Redistributions in binary form must reproduce the above copyright
10dc7e38acSHans Petter Selasky  *    notice, this list of conditions and the following disclaimer in the
11dc7e38acSHans Petter Selasky  *    documentation and/or other materials provided with the distribution.
12dc7e38acSHans Petter Selasky  *
13dc7e38acSHans Petter Selasky  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14dc7e38acSHans Petter Selasky  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15dc7e38acSHans Petter Selasky  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16dc7e38acSHans Petter Selasky  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17dc7e38acSHans Petter Selasky  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18dc7e38acSHans Petter Selasky  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19dc7e38acSHans Petter Selasky  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20dc7e38acSHans Petter Selasky  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21dc7e38acSHans Petter Selasky  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22dc7e38acSHans Petter Selasky  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23dc7e38acSHans Petter Selasky  * SUCH DAMAGE.
24dc7e38acSHans Petter Selasky  *
25dc7e38acSHans Petter Selasky  * $FreeBSD$
26dc7e38acSHans Petter Selasky  */
27dc7e38acSHans Petter Selasky 
28dc7e38acSHans Petter Selasky #include "en.h"
29dc7e38acSHans Petter Selasky #include <net/sff8472.h>
30dc7e38acSHans Petter Selasky 
31dc7e38acSHans Petter Selasky void
32dc7e38acSHans Petter Selasky mlx5e_create_stats(struct sysctl_ctx_list *ctx,
33dc7e38acSHans Petter Selasky     struct sysctl_oid_list *parent, const char *buffer,
34dc7e38acSHans Petter Selasky     const char **desc, unsigned num, u64 * arg)
35dc7e38acSHans Petter Selasky {
36dc7e38acSHans Petter Selasky 	struct sysctl_oid *node;
37dc7e38acSHans Petter Selasky 	unsigned x;
38dc7e38acSHans Petter Selasky 
39dc7e38acSHans Petter Selasky 	sysctl_ctx_init(ctx);
40dc7e38acSHans Petter Selasky 
41dc7e38acSHans Petter Selasky 	node = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO,
42dc7e38acSHans Petter Selasky 	    buffer, CTLFLAG_RD, NULL, "Statistics");
43dc7e38acSHans Petter Selasky 	if (node == NULL)
44dc7e38acSHans Petter Selasky 		return;
45dc7e38acSHans Petter Selasky 	for (x = 0; x != num; x++) {
46dc7e38acSHans Petter Selasky 		SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
47dc7e38acSHans Petter Selasky 		    desc[2 * x], CTLFLAG_RD, arg + x, desc[2 * x + 1]);
48dc7e38acSHans Petter Selasky 	}
49dc7e38acSHans Petter Selasky }
50dc7e38acSHans Petter Selasky 
51dc7e38acSHans Petter Selasky static int
52dc7e38acSHans Petter Selasky mlx5e_ethtool_handler(SYSCTL_HANDLER_ARGS)
53dc7e38acSHans Petter Selasky {
54dc7e38acSHans Petter Selasky 	struct mlx5e_priv *priv = arg1;
55dc7e38acSHans Petter Selasky 	uint64_t value;
56dc7e38acSHans Petter Selasky 	int was_opened;
57dc7e38acSHans Petter Selasky 	int error;
58dc7e38acSHans Petter Selasky 
59dc7e38acSHans Petter Selasky 	PRIV_LOCK(priv);
60dc7e38acSHans Petter Selasky 	value = priv->params_ethtool.arg[arg2];
61ec0143b2SHans Petter Selasky 	if (req != NULL) {
62dc7e38acSHans Petter Selasky 		error = sysctl_handle_64(oidp, &value, 0, req);
63dc7e38acSHans Petter Selasky 		if (error || req->newptr == NULL ||
64dc7e38acSHans Petter Selasky 		    value == priv->params_ethtool.arg[arg2])
65dc7e38acSHans Petter Selasky 			goto done;
66dc7e38acSHans Petter Selasky 
67dc7e38acSHans Petter Selasky 		/* assign new value */
68dc7e38acSHans Petter Selasky 		priv->params_ethtool.arg[arg2] = value;
69ec0143b2SHans Petter Selasky 	} else {
70ec0143b2SHans Petter Selasky 		error = 0;
71ec0143b2SHans Petter Selasky 	}
72dc7e38acSHans Petter Selasky 	/* check if device is gone */
73dc7e38acSHans Petter Selasky 	if (priv->gone) {
74dc7e38acSHans Petter Selasky 		error = ENXIO;
75dc7e38acSHans Petter Selasky 		goto done;
76dc7e38acSHans Petter Selasky 	}
77f03f517bSHans Petter Selasky 	/* import RX coal time */
78f03f517bSHans Petter Selasky 	if (priv->params_ethtool.rx_coalesce_usecs < 1)
79f03f517bSHans Petter Selasky 		priv->params_ethtool.rx_coalesce_usecs = 0;
80f03f517bSHans Petter Selasky 	else if (priv->params_ethtool.rx_coalesce_usecs >
81f03f517bSHans Petter Selasky 	    MLX5E_FLD_MAX(cqc, cq_period)) {
82f03f517bSHans Petter Selasky 		priv->params_ethtool.rx_coalesce_usecs =
83f03f517bSHans Petter Selasky 		    MLX5E_FLD_MAX(cqc, cq_period);
84f03f517bSHans Petter Selasky 	}
85f03f517bSHans Petter Selasky 	priv->params.rx_cq_moderation_usec = priv->params_ethtool.rx_coalesce_usecs;
86f03f517bSHans Petter Selasky 
87f03f517bSHans Petter Selasky 	/* import RX coal pkts */
88f03f517bSHans Petter Selasky 	if (priv->params_ethtool.rx_coalesce_pkts < 1)
89f03f517bSHans Petter Selasky 		priv->params_ethtool.rx_coalesce_pkts = 0;
90f03f517bSHans Petter Selasky 	else if (priv->params_ethtool.rx_coalesce_pkts >
91f03f517bSHans Petter Selasky 	    MLX5E_FLD_MAX(cqc, cq_max_count)) {
92f03f517bSHans Petter Selasky 		priv->params_ethtool.rx_coalesce_pkts =
93f03f517bSHans Petter Selasky 		    MLX5E_FLD_MAX(cqc, cq_max_count);
94f03f517bSHans Petter Selasky 	}
95f03f517bSHans Petter Selasky 	priv->params.rx_cq_moderation_pkts = priv->params_ethtool.rx_coalesce_pkts;
96f03f517bSHans Petter Selasky 
97f03f517bSHans Petter Selasky 	/* import TX coal time */
98f03f517bSHans Petter Selasky 	if (priv->params_ethtool.tx_coalesce_usecs < 1)
99f03f517bSHans Petter Selasky 		priv->params_ethtool.tx_coalesce_usecs = 0;
100f03f517bSHans Petter Selasky 	else if (priv->params_ethtool.tx_coalesce_usecs >
101f03f517bSHans Petter Selasky 	    MLX5E_FLD_MAX(cqc, cq_period)) {
102f03f517bSHans Petter Selasky 		priv->params_ethtool.tx_coalesce_usecs =
103f03f517bSHans Petter Selasky 		    MLX5E_FLD_MAX(cqc, cq_period);
104f03f517bSHans Petter Selasky 	}
105f03f517bSHans Petter Selasky 	priv->params.tx_cq_moderation_usec = priv->params_ethtool.tx_coalesce_usecs;
106f03f517bSHans Petter Selasky 
107f03f517bSHans Petter Selasky 	/* import TX coal pkts */
108f03f517bSHans Petter Selasky 	if (priv->params_ethtool.tx_coalesce_pkts < 1)
109f03f517bSHans Petter Selasky 		priv->params_ethtool.tx_coalesce_pkts = 0;
110f03f517bSHans Petter Selasky 	else if (priv->params_ethtool.tx_coalesce_pkts >
111f03f517bSHans Petter Selasky 	    MLX5E_FLD_MAX(cqc, cq_max_count)) {
112f03f517bSHans Petter Selasky 		priv->params_ethtool.tx_coalesce_pkts = MLX5E_FLD_MAX(cqc, cq_max_count);
113f03f517bSHans Petter Selasky 	}
114f03f517bSHans Petter Selasky 	priv->params.tx_cq_moderation_pkts = priv->params_ethtool.tx_coalesce_pkts;
115dc7e38acSHans Petter Selasky 
116dc7e38acSHans Petter Selasky 	if (&priv->params_ethtool.arg[arg2] == &priv->params_ethtool.rx_pauseframe_control ||
117dc7e38acSHans Petter Selasky 	    &priv->params_ethtool.arg[arg2] == &priv->params_ethtool.tx_pauseframe_control) {
118dc7e38acSHans Petter Selasky 		/* range check parameters */
119dc7e38acSHans Petter Selasky 		priv->params_ethtool.rx_pauseframe_control =
120dc7e38acSHans Petter Selasky 		    priv->params_ethtool.rx_pauseframe_control ? 1 : 0;
121dc7e38acSHans Petter Selasky 		priv->params_ethtool.tx_pauseframe_control =
122dc7e38acSHans Petter Selasky 		    priv->params_ethtool.tx_pauseframe_control ? 1 : 0;
123dc7e38acSHans Petter Selasky 
124dc7e38acSHans Petter Selasky 		/* update firmware */
125dc7e38acSHans Petter Selasky 		error = -mlx5_set_port_pause(priv->mdev, 1,
126dc7e38acSHans Petter Selasky 		    priv->params_ethtool.rx_pauseframe_control,
127dc7e38acSHans Petter Selasky 		    priv->params_ethtool.tx_pauseframe_control);
128dc7e38acSHans Petter Selasky 		goto done;
129dc7e38acSHans Petter Selasky 	}
130dc7e38acSHans Petter Selasky 
131dc7e38acSHans Petter Selasky 	was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
132f03f517bSHans Petter Selasky 	if (was_opened) {
133f03f517bSHans Petter Selasky 		u64 *xarg = priv->params_ethtool.arg + arg2;
134dc7e38acSHans Petter Selasky 
135f03f517bSHans Petter Selasky 		if (xarg == &priv->params_ethtool.tx_coalesce_pkts ||
136f03f517bSHans Petter Selasky 		    xarg == &priv->params_ethtool.rx_coalesce_pkts ||
137f03f517bSHans Petter Selasky 		    xarg == &priv->params_ethtool.tx_coalesce_usecs ||
138f03f517bSHans Petter Selasky 		    xarg == &priv->params_ethtool.rx_coalesce_usecs) {
139f03f517bSHans Petter Selasky 			/* avoid downing and upping the network interface */
140f03f517bSHans Petter Selasky 			error = mlx5e_refresh_channel_params(priv);
141f03f517bSHans Petter Selasky 			goto done;
142f03f517bSHans Petter Selasky 		}
143f03f517bSHans Petter Selasky 		mlx5e_close_locked(priv->ifp);
144f03f517bSHans Petter Selasky 	}
145dc7e38acSHans Petter Selasky 	/* import TX queue size */
146dc7e38acSHans Petter Selasky 	if (priv->params_ethtool.tx_queue_size <
147dc7e38acSHans Petter Selasky 	    (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)) {
148dc7e38acSHans Petter Selasky 		priv->params_ethtool.tx_queue_size =
149dc7e38acSHans Petter Selasky 		    (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE);
150dc7e38acSHans Petter Selasky 	} else if (priv->params_ethtool.tx_queue_size >
151dc7e38acSHans Petter Selasky 	    priv->params_ethtool.tx_queue_size_max) {
152dc7e38acSHans Petter Selasky 		priv->params_ethtool.tx_queue_size =
153dc7e38acSHans Petter Selasky 		    priv->params_ethtool.tx_queue_size_max;
154dc7e38acSHans Petter Selasky 	}
155dc7e38acSHans Petter Selasky 	priv->params.log_sq_size =
156dc7e38acSHans Petter Selasky 	    order_base_2(priv->params_ethtool.tx_queue_size);
157dc7e38acSHans Petter Selasky 
158dc7e38acSHans Petter Selasky 	/* import RX queue size */
159dc7e38acSHans Petter Selasky 	if (priv->params_ethtool.rx_queue_size <
160dc7e38acSHans Petter Selasky 	    (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE)) {
161dc7e38acSHans Petter Selasky 		priv->params_ethtool.rx_queue_size =
162dc7e38acSHans Petter Selasky 		    (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE);
163dc7e38acSHans Petter Selasky 	} else if (priv->params_ethtool.rx_queue_size >
164dc7e38acSHans Petter Selasky 	    priv->params_ethtool.rx_queue_size_max) {
165dc7e38acSHans Petter Selasky 		priv->params_ethtool.rx_queue_size =
166dc7e38acSHans Petter Selasky 		    priv->params_ethtool.rx_queue_size_max;
167dc7e38acSHans Petter Selasky 	}
168dc7e38acSHans Petter Selasky 	priv->params.log_rq_size =
169dc7e38acSHans Petter Selasky 	    order_base_2(priv->params_ethtool.rx_queue_size);
170dc7e38acSHans Petter Selasky 
171dc7e38acSHans Petter Selasky 	priv->params.min_rx_wqes = min_t (u16,
172dc7e38acSHans Petter Selasky 	          priv->params_ethtool.rx_queue_size - 1,
173dc7e38acSHans Petter Selasky 	          MLX5E_PARAMS_DEFAULT_MIN_RX_WQES);
174dc7e38acSHans Petter Selasky 
175dc7e38acSHans Petter Selasky 	/* import number of channels */
176dc7e38acSHans Petter Selasky 	if (priv->params_ethtool.channels < 1)
177dc7e38acSHans Petter Selasky 		priv->params_ethtool.channels = 1;
178dc7e38acSHans Petter Selasky 	else if (priv->params_ethtool.channels >
179dc7e38acSHans Petter Selasky 	    (u64) priv->mdev->priv.eq_table.num_comp_vectors) {
180dc7e38acSHans Petter Selasky 		priv->params_ethtool.channels =
181dc7e38acSHans Petter Selasky 		    (u64) priv->mdev->priv.eq_table.num_comp_vectors;
182dc7e38acSHans Petter Selasky 	}
183dc7e38acSHans Petter Selasky 	priv->params.num_channels = priv->params_ethtool.channels;
184dc7e38acSHans Petter Selasky 
185dc7e38acSHans Petter Selasky 	/* import RX mode */
186dc7e38acSHans Petter Selasky 	if (priv->params_ethtool.rx_coalesce_mode != 0)
187dc7e38acSHans Petter Selasky 		priv->params_ethtool.rx_coalesce_mode = 1;
188dc7e38acSHans Petter Selasky 	priv->params.rx_cq_moderation_mode = priv->params_ethtool.rx_coalesce_mode;
189dc7e38acSHans Petter Selasky 
19074540a31SHans Petter Selasky 	/* import TX mode */
19174540a31SHans Petter Selasky 	if (priv->params_ethtool.tx_coalesce_mode != 0)
19274540a31SHans Petter Selasky 		priv->params_ethtool.tx_coalesce_mode = 1;
19374540a31SHans Petter Selasky 	priv->params.tx_cq_moderation_mode = priv->params_ethtool.tx_coalesce_mode;
19474540a31SHans Petter Selasky 
195dc7e38acSHans Petter Selasky 	/* we always agree to turn off HW LRO - but not always to turn on */
196dc7e38acSHans Petter Selasky 	if (priv->params_ethtool.hw_lro) {
197dc7e38acSHans Petter Selasky 		if (priv->params_ethtool.hw_lro != 1) {
198dc7e38acSHans Petter Selasky 			priv->params_ethtool.hw_lro = priv->params.hw_lro_en;
199dc7e38acSHans Petter Selasky 			error = EINVAL;
200dc7e38acSHans Petter Selasky 			goto done;
201dc7e38acSHans Petter Selasky 		}
202dc7e38acSHans Petter Selasky 		if (priv->ifp->if_capenable & IFCAP_LRO)
203dc7e38acSHans Petter Selasky 			priv->params.hw_lro_en = !!MLX5_CAP_ETH(priv->mdev, lro_cap);
20436c1007dSHans Petter Selasky 		else {
20536c1007dSHans Petter Selasky 			/* set the correct (0) value to params_ethtool.hw_lro, issue a warning and return error */
20636c1007dSHans Petter Selasky 			priv->params_ethtool.hw_lro = 0;
20736c1007dSHans Petter Selasky 			error = EINVAL;
20836c1007dSHans Petter Selasky 			if_printf(priv->ifp, "Can't set HW_LRO to a device with LRO turned off");
20936c1007dSHans Petter Selasky 			goto done;
21036c1007dSHans Petter Selasky 		}
211bb3853c6SHans Petter Selasky 	} else {
212dc7e38acSHans Petter Selasky 		priv->params.hw_lro_en = false;
213dc7e38acSHans Petter Selasky 	}
214dc7e38acSHans Petter Selasky 
21590cc1c77SHans Petter Selasky 	if (&priv->params_ethtool.arg[arg2] ==
21690cc1c77SHans Petter Selasky 	    &priv->params_ethtool.cqe_zipping) {
21790cc1c77SHans Petter Selasky 		if (priv->params_ethtool.cqe_zipping &&
21890cc1c77SHans Petter Selasky 		    MLX5_CAP_GEN(priv->mdev, cqe_compression)) {
21990cc1c77SHans Petter Selasky 			priv->params.cqe_zipping_en = true;
22090cc1c77SHans Petter Selasky 			priv->params_ethtool.cqe_zipping = 1;
22190cc1c77SHans Petter Selasky 		} else {
22290cc1c77SHans Petter Selasky 			priv->params.cqe_zipping_en = false;
22390cc1c77SHans Petter Selasky 			priv->params_ethtool.cqe_zipping = 0;
22490cc1c77SHans Petter Selasky 		}
22590cc1c77SHans Petter Selasky 	}
22690cc1c77SHans Petter Selasky 
227dc7e38acSHans Petter Selasky 	if (was_opened)
228dc7e38acSHans Petter Selasky 		mlx5e_open_locked(priv->ifp);
229dc7e38acSHans Petter Selasky done:
230dc7e38acSHans Petter Selasky 	PRIV_UNLOCK(priv);
231dc7e38acSHans Petter Selasky 	return (error);
232dc7e38acSHans Petter Selasky }
233dc7e38acSHans Petter Selasky 
234dc7e38acSHans Petter Selasky /*
235dc7e38acSHans Petter Selasky  * Read the first three bytes of the eeprom in order to get the needed info
236dc7e38acSHans Petter Selasky  * for the whole reading.
237dc7e38acSHans Petter Selasky  * Byte 0 - Identifier byte
238dc7e38acSHans Petter Selasky  * Byte 1 - Revision byte
239dc7e38acSHans Petter Selasky  * Byte 2 - Status byte
240dc7e38acSHans Petter Selasky  */
241dc7e38acSHans Petter Selasky static int
242dc7e38acSHans Petter Selasky mlx5e_get_eeprom_info(struct mlx5e_priv *priv, struct mlx5e_eeprom *eeprom)
243dc7e38acSHans Petter Selasky {
244dc7e38acSHans Petter Selasky 	struct mlx5_core_dev *dev = priv->mdev;
245dc7e38acSHans Petter Selasky 	u32 data = 0;
246dc7e38acSHans Petter Selasky 	int size_read = 0;
247dc7e38acSHans Petter Selasky 	int ret;
248dc7e38acSHans Petter Selasky 
249dc7e38acSHans Petter Selasky 	ret = mlx5_query_module_num(dev, &eeprom->module_num);
250dc7e38acSHans Petter Selasky 	if (ret) {
251dc7e38acSHans Petter Selasky 		if_printf(priv->ifp, "%s:%d: Failed query module error=%d\n",
252dc7e38acSHans Petter Selasky 		    __func__, __LINE__, ret);
253dc7e38acSHans Petter Selasky 		return (ret);
254dc7e38acSHans Petter Selasky 	}
255dc7e38acSHans Petter Selasky 
256dc7e38acSHans Petter Selasky 	/* Read the first three bytes to get Identifier, Revision and Status */
257dc7e38acSHans Petter Selasky 	ret = mlx5_query_eeprom(dev, eeprom->i2c_addr, eeprom->page_num,
258dc7e38acSHans Petter Selasky 	    eeprom->device_addr, MLX5E_EEPROM_INFO_BYTES, eeprom->module_num, &data,
259dc7e38acSHans Petter Selasky 	    &size_read);
260dc7e38acSHans Petter Selasky 	if (ret) {
261dc7e38acSHans Petter Selasky 		if_printf(priv->ifp, "%s:%d: Failed query eeprom module error=0x%x\n",
262dc7e38acSHans Petter Selasky 		    __func__, __LINE__, ret);
263dc7e38acSHans Petter Selasky 		return (ret);
264dc7e38acSHans Petter Selasky 	}
265dc7e38acSHans Petter Selasky 
266dc7e38acSHans Petter Selasky 	switch (data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) {
267dc7e38acSHans Petter Selasky 	case SFF_8024_ID_QSFP:
268dc7e38acSHans Petter Selasky 		eeprom->type = MLX5E_ETH_MODULE_SFF_8436;
269dc7e38acSHans Petter Selasky 		eeprom->len = MLX5E_ETH_MODULE_SFF_8436_LEN;
270dc7e38acSHans Petter Selasky 		break;
271dc7e38acSHans Petter Selasky 	case SFF_8024_ID_QSFPPLUS:
272dc7e38acSHans Petter Selasky 	case SFF_8024_ID_QSFP28:
273dc7e38acSHans Petter Selasky 		if ((data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) == SFF_8024_ID_QSFP28 ||
274dc7e38acSHans Petter Selasky 		    ((data & MLX5_EEPROM_REVISION_ID_BYTE_MASK) >> 8) >= 0x3) {
275dc7e38acSHans Petter Selasky 			eeprom->type = MLX5E_ETH_MODULE_SFF_8636;
276dc7e38acSHans Petter Selasky 			eeprom->len = MLX5E_ETH_MODULE_SFF_8636_LEN;
277dc7e38acSHans Petter Selasky 		} else {
278dc7e38acSHans Petter Selasky 			eeprom->type = MLX5E_ETH_MODULE_SFF_8436;
279dc7e38acSHans Petter Selasky 			eeprom->len = MLX5E_ETH_MODULE_SFF_8436_LEN;
280dc7e38acSHans Petter Selasky 		}
281dc7e38acSHans Petter Selasky 		if ((data & MLX5_EEPROM_PAGE_3_VALID_BIT_MASK) == 0)
282dc7e38acSHans Petter Selasky 			eeprom->page_valid = 1;
283dc7e38acSHans Petter Selasky 		break;
284dc7e38acSHans Petter Selasky 	case SFF_8024_ID_SFP:
285dc7e38acSHans Petter Selasky 		eeprom->type = MLX5E_ETH_MODULE_SFF_8472;
286dc7e38acSHans Petter Selasky 		eeprom->len = MLX5E_ETH_MODULE_SFF_8472_LEN;
287dc7e38acSHans Petter Selasky 		break;
288dc7e38acSHans Petter Selasky 	default:
2897e1b8bc0SHans Petter Selasky 		if_printf(priv->ifp, "%s:%d: Not recognized cable type = 0x%x(%s)\n",
2907e1b8bc0SHans Petter Selasky 		    __func__, __LINE__, data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK,
2917e1b8bc0SHans Petter Selasky 		    sff_8024_id[data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK]);
292dc7e38acSHans Petter Selasky 		return (EINVAL);
293dc7e38acSHans Petter Selasky 	}
294dc7e38acSHans Petter Selasky 	return (0);
295dc7e38acSHans Petter Selasky }
296dc7e38acSHans Petter Selasky 
297dc7e38acSHans Petter Selasky /* Read both low and high pages of the eeprom */
298dc7e38acSHans Petter Selasky static int
299dc7e38acSHans Petter Selasky mlx5e_get_eeprom(struct mlx5e_priv *priv, struct mlx5e_eeprom *ee)
300dc7e38acSHans Petter Selasky {
301dc7e38acSHans Petter Selasky 	struct mlx5_core_dev *dev = priv->mdev;
302dc7e38acSHans Petter Selasky 	int size_read = 0;
303dc7e38acSHans Petter Selasky 	int ret;
304dc7e38acSHans Petter Selasky 
305dc7e38acSHans Petter Selasky 	if (ee->len == 0)
306dc7e38acSHans Petter Selasky 		return (EINVAL);
307dc7e38acSHans Petter Selasky 
308dc7e38acSHans Petter Selasky 	/* Read low page of the eeprom */
309dc7e38acSHans Petter Selasky 	while (ee->device_addr < ee->len) {
310dc7e38acSHans Petter Selasky 		ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num, ee->device_addr,
311dc7e38acSHans Petter Selasky 		    ee->len - ee->device_addr, ee->module_num,
312dc7e38acSHans Petter Selasky 		    ee->data + (ee->device_addr / 4), &size_read);
313dc7e38acSHans Petter Selasky 		if (ret) {
314dc7e38acSHans Petter Selasky 			if_printf(priv->ifp, "%s:%d: Failed reading eeprom, "
315dc7e38acSHans Petter Selasky 			    "error = 0x%02x\n", __func__, __LINE__, ret);
316dc7e38acSHans Petter Selasky 			return (ret);
317dc7e38acSHans Petter Selasky 		}
318dc7e38acSHans Petter Selasky 		ee->device_addr += size_read;
319dc7e38acSHans Petter Selasky 	}
320dc7e38acSHans Petter Selasky 
321dc7e38acSHans Petter Selasky 	/* Read high page of the eeprom */
322dc7e38acSHans Petter Selasky 	if (ee->page_valid) {
323dc7e38acSHans Petter Selasky 		ee->device_addr = MLX5E_EEPROM_HIGH_PAGE_OFFSET;
324dc7e38acSHans Petter Selasky 		ee->page_num = MLX5E_EEPROM_HIGH_PAGE;
325dc7e38acSHans Petter Selasky 		size_read = 0;
326dc7e38acSHans Petter Selasky 		while (ee->device_addr < MLX5E_EEPROM_PAGE_LENGTH) {
327dc7e38acSHans Petter Selasky 			ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num,
328dc7e38acSHans Petter Selasky 			    ee->device_addr, MLX5E_EEPROM_PAGE_LENGTH - ee->device_addr,
329dc7e38acSHans Petter Selasky 			    ee->module_num, ee->data + (ee->len / 4) +
330dc7e38acSHans Petter Selasky 			    ((ee->device_addr - MLX5E_EEPROM_HIGH_PAGE_OFFSET) / 4),
331dc7e38acSHans Petter Selasky 			    &size_read);
332dc7e38acSHans Petter Selasky 			if (ret) {
333dc7e38acSHans Petter Selasky 				if_printf(priv->ifp, "%s:%d: Failed reading eeprom, "
334dc7e38acSHans Petter Selasky 				    "error = 0x%02x\n", __func__, __LINE__, ret);
335dc7e38acSHans Petter Selasky 				return (ret);
336dc7e38acSHans Petter Selasky 			}
337dc7e38acSHans Petter Selasky 			ee->device_addr += size_read;
338dc7e38acSHans Petter Selasky 		}
339dc7e38acSHans Petter Selasky 	}
340dc7e38acSHans Petter Selasky 	return (0);
341dc7e38acSHans Petter Selasky }
342dc7e38acSHans Petter Selasky 
343dc7e38acSHans Petter Selasky static void
344dc7e38acSHans Petter Selasky mlx5e_print_eeprom(struct mlx5e_eeprom *eeprom)
345dc7e38acSHans Petter Selasky {
346ee41fc8fSHans Petter Selasky 	int row;
347ee41fc8fSHans Petter Selasky 	int index_in_row;
348ee41fc8fSHans Petter Selasky 	int byte_to_write = 0;
349ee41fc8fSHans Petter Selasky 	int line_length = 16;
350dc7e38acSHans Petter Selasky 
351dc7e38acSHans Petter Selasky 	printf("\nOffset\t\tValues\n");
352ee41fc8fSHans Petter Selasky 	printf("------\t\t------");
353ee41fc8fSHans Petter Selasky 	while (byte_to_write < eeprom->len) {
354ee41fc8fSHans Petter Selasky 		printf("\n0x%04X\t\t", byte_to_write);
355ee41fc8fSHans Petter Selasky 		for (index_in_row = 0; index_in_row < line_length; index_in_row++) {
356ee41fc8fSHans Petter Selasky 			printf("%02X ", ((u8 *)eeprom->data)[byte_to_write]);
357ee41fc8fSHans Petter Selasky 			byte_to_write++;
358dc7e38acSHans Petter Selasky 		}
359dc7e38acSHans Petter Selasky 	}
360dc7e38acSHans Petter Selasky 
361dc7e38acSHans Petter Selasky 	if (eeprom->page_valid) {
362dc7e38acSHans Petter Selasky 		row = MLX5E_EEPROM_HIGH_PAGE_OFFSET;
363ee41fc8fSHans Petter Selasky 		printf("\n\nUpper Page 0x03\n");
364dc7e38acSHans Petter Selasky 		printf("\nOffset\t\tValues\n");
365ee41fc8fSHans Petter Selasky 		printf("------\t\t------");
366dc7e38acSHans Petter Selasky 		while (row < MLX5E_EEPROM_PAGE_LENGTH) {
367ee41fc8fSHans Petter Selasky 			printf("\n0x%04X\t\t", row);
368ee41fc8fSHans Petter Selasky 			for (index_in_row = 0; index_in_row < line_length; index_in_row++) {
369ee41fc8fSHans Petter Selasky 				printf("%02X ", ((u8 *)eeprom->data)[byte_to_write]);
370ee41fc8fSHans Petter Selasky 				byte_to_write++;
371dc7e38acSHans Petter Selasky 				row++;
372dc7e38acSHans Petter Selasky 			}
373dc7e38acSHans Petter Selasky 		}
374dc7e38acSHans Petter Selasky 	}
375dc7e38acSHans Petter Selasky }
376dc7e38acSHans Petter Selasky 
377dc7e38acSHans Petter Selasky /*
378dc7e38acSHans Petter Selasky  * Read cable EEPROM module information by first inspecting the first
379dc7e38acSHans Petter Selasky  * three bytes to get the initial information for a whole reading.
380dc7e38acSHans Petter Selasky  * Information will be printed to dmesg.
381dc7e38acSHans Petter Selasky  */
382dc7e38acSHans Petter Selasky static int
383dc7e38acSHans Petter Selasky mlx5e_read_eeprom(SYSCTL_HANDLER_ARGS)
384dc7e38acSHans Petter Selasky {
385dc7e38acSHans Petter Selasky 	struct mlx5e_priv *priv = arg1;
386dc7e38acSHans Petter Selasky 	struct mlx5e_eeprom eeprom;
387dc7e38acSHans Petter Selasky 	int error;
388dc7e38acSHans Petter Selasky 	int result = 0;
389dc7e38acSHans Petter Selasky 
390dc7e38acSHans Petter Selasky 	PRIV_LOCK(priv);
391dc7e38acSHans Petter Selasky 	error = sysctl_handle_int(oidp, &result, 0, req);
392dc7e38acSHans Petter Selasky 	if (error || !req->newptr)
393dc7e38acSHans Petter Selasky 		goto done;
394dc7e38acSHans Petter Selasky 
395dc7e38acSHans Petter Selasky 	/* Check if device is gone */
396dc7e38acSHans Petter Selasky 	if (priv->gone) {
397dc7e38acSHans Petter Selasky 		error = ENXIO;
398dc7e38acSHans Petter Selasky 		goto done;
399dc7e38acSHans Petter Selasky 	}
400dc7e38acSHans Petter Selasky 
401dc7e38acSHans Petter Selasky 	if (result == 1) {
402dc7e38acSHans Petter Selasky 		eeprom.i2c_addr = MLX5E_I2C_ADDR_LOW;
403dc7e38acSHans Petter Selasky 		eeprom.device_addr = 0;
404dc7e38acSHans Petter Selasky 		eeprom.page_num = MLX5E_EEPROM_LOW_PAGE;
405dc7e38acSHans Petter Selasky 		eeprom.page_valid = 0;
406dc7e38acSHans Petter Selasky 
407dc7e38acSHans Petter Selasky 		/* Read three first bytes to get important info */
408dc7e38acSHans Petter Selasky 		error = mlx5e_get_eeprom_info(priv, &eeprom);
409dc7e38acSHans Petter Selasky 		if (error) {
410dc7e38acSHans Petter Selasky 			if_printf(priv->ifp, "%s:%d: Failed reading eeprom's "
411dc7e38acSHans Petter Selasky 			    "initial information\n", __func__, __LINE__);
412dc7e38acSHans Petter Selasky 			error = 0;
413dc7e38acSHans Petter Selasky 			goto done;
414dc7e38acSHans Petter Selasky 		}
415bb3853c6SHans Petter Selasky 		/*
416bb3853c6SHans Petter Selasky 		 * Allocate needed length buffer and additional space for
417bb3853c6SHans Petter Selasky 		 * page 0x03
418bb3853c6SHans Petter Selasky 		 */
419dc7e38acSHans Petter Selasky 		eeprom.data = malloc(eeprom.len + MLX5E_EEPROM_PAGE_LENGTH,
420dc7e38acSHans Petter Selasky 		    M_MLX5EN, M_WAITOK | M_ZERO);
421dc7e38acSHans Petter Selasky 
422dc7e38acSHans Petter Selasky 		/* Read the whole eeprom information */
423dc7e38acSHans Petter Selasky 		error = mlx5e_get_eeprom(priv, &eeprom);
424dc7e38acSHans Petter Selasky 		if (error) {
425dc7e38acSHans Petter Selasky 			if_printf(priv->ifp, "%s:%d: Failed reading eeprom\n",
426dc7e38acSHans Petter Selasky 			    __func__, __LINE__);
427dc7e38acSHans Petter Selasky 			error = 0;
428bb3853c6SHans Petter Selasky 			/*
429bb3853c6SHans Petter Selasky 			 * Continue printing partial information in case of
430bb3853c6SHans Petter Selasky 			 * an error
431bb3853c6SHans Petter Selasky 			 */
432dc7e38acSHans Petter Selasky 		}
433dc7e38acSHans Petter Selasky 		mlx5e_print_eeprom(&eeprom);
434dc7e38acSHans Petter Selasky 		free(eeprom.data, M_MLX5EN);
435dc7e38acSHans Petter Selasky 	}
436dc7e38acSHans Petter Selasky done:
437dc7e38acSHans Petter Selasky 	PRIV_UNLOCK(priv);
438dc7e38acSHans Petter Selasky 	return (error);
439dc7e38acSHans Petter Selasky }
440dc7e38acSHans Petter Selasky 
441dc7e38acSHans Petter Selasky static const char *mlx5e_params_desc[] = {
442dc7e38acSHans Petter Selasky 	MLX5E_PARAMS(MLX5E_STATS_DESC)
443dc7e38acSHans Petter Selasky };
444dc7e38acSHans Petter Selasky 
445dc7e38acSHans Petter Selasky static const char *mlx5e_port_stats_debug_desc[] = {
446dc7e38acSHans Petter Selasky 	MLX5E_PORT_STATS_DEBUG(MLX5E_STATS_DESC)
447dc7e38acSHans Petter Selasky };
448dc7e38acSHans Petter Selasky 
449dc7e38acSHans Petter Selasky static int
450dc7e38acSHans Petter Selasky mlx5e_ethtool_debug_stats(SYSCTL_HANDLER_ARGS)
451dc7e38acSHans Petter Selasky {
452dc7e38acSHans Petter Selasky 	struct mlx5e_priv *priv = arg1;
453dc7e38acSHans Petter Selasky 	int error;
454dc7e38acSHans Petter Selasky 	int sys_debug;
455dc7e38acSHans Petter Selasky 
456dc7e38acSHans Petter Selasky 	sys_debug = priv->sysctl_debug;
457dc7e38acSHans Petter Selasky 	error = sysctl_handle_int(oidp, &priv->sysctl_debug, 0, req);
458dc7e38acSHans Petter Selasky 	if (error || !req->newptr)
459dc7e38acSHans Petter Selasky 		return (error);
460dc7e38acSHans Petter Selasky 	priv->sysctl_debug = !!priv->sysctl_debug;
461dc7e38acSHans Petter Selasky 	if (sys_debug == priv->sysctl_debug)
462dc7e38acSHans Petter Selasky 		return (error);
463dc7e38acSHans Petter Selasky 	if (priv->sysctl_debug)
464dc7e38acSHans Petter Selasky 		mlx5e_create_stats(&priv->stats.port_stats_debug.ctx,
465dc7e38acSHans Petter Selasky 		    SYSCTL_CHILDREN(priv->sysctl_ifnet), "debug_stats",
466dc7e38acSHans Petter Selasky 		    mlx5e_port_stats_debug_desc, MLX5E_PORT_STATS_DEBUG_NUM,
467dc7e38acSHans Petter Selasky 		    priv->stats.port_stats_debug.arg);
468dc7e38acSHans Petter Selasky 	else
469dc7e38acSHans Petter Selasky 		sysctl_ctx_free(&priv->stats.port_stats_debug.ctx);
470dc7e38acSHans Petter Selasky 	return (error);
471dc7e38acSHans Petter Selasky }
472dc7e38acSHans Petter Selasky 
473dc7e38acSHans Petter Selasky void
474dc7e38acSHans Petter Selasky mlx5e_create_ethtool(struct mlx5e_priv *priv)
475dc7e38acSHans Petter Selasky {
476dc7e38acSHans Petter Selasky 	struct sysctl_oid *node;
477dc7e38acSHans Petter Selasky 	const char *pnameunit;
478dc7e38acSHans Petter Selasky 	unsigned x;
479dc7e38acSHans Petter Selasky 
480dc7e38acSHans Petter Selasky 	/* set some defaults */
481dc7e38acSHans Petter Selasky 	priv->params_ethtool.tx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE;
482dc7e38acSHans Petter Selasky 	priv->params_ethtool.rx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE;
483dc7e38acSHans Petter Selasky 	priv->params_ethtool.tx_queue_size = 1 << priv->params.log_sq_size;
484dc7e38acSHans Petter Selasky 	priv->params_ethtool.rx_queue_size = 1 << priv->params.log_rq_size;
485dc7e38acSHans Petter Selasky 	priv->params_ethtool.channels = priv->params.num_channels;
486dc7e38acSHans Petter Selasky 	priv->params_ethtool.coalesce_pkts_max = MLX5E_FLD_MAX(cqc, cq_max_count);
487dc7e38acSHans Petter Selasky 	priv->params_ethtool.coalesce_usecs_max = MLX5E_FLD_MAX(cqc, cq_period);
488dc7e38acSHans Petter Selasky 	priv->params_ethtool.rx_coalesce_mode = priv->params.rx_cq_moderation_mode;
489dc7e38acSHans Petter Selasky 	priv->params_ethtool.rx_coalesce_usecs = priv->params.rx_cq_moderation_usec;
490dc7e38acSHans Petter Selasky 	priv->params_ethtool.rx_coalesce_pkts = priv->params.rx_cq_moderation_pkts;
49174540a31SHans Petter Selasky 	priv->params_ethtool.tx_coalesce_mode = priv->params.tx_cq_moderation_mode;
492dc7e38acSHans Petter Selasky 	priv->params_ethtool.tx_coalesce_usecs = priv->params.tx_cq_moderation_usec;
493dc7e38acSHans Petter Selasky 	priv->params_ethtool.tx_coalesce_pkts = priv->params.tx_cq_moderation_pkts;
494dc7e38acSHans Petter Selasky 	priv->params_ethtool.hw_lro = priv->params.hw_lro_en;
49590cc1c77SHans Petter Selasky 	priv->params_ethtool.cqe_zipping = priv->params.cqe_zipping_en;
496dc7e38acSHans Petter Selasky 
497dc7e38acSHans Petter Selasky 	/* create root node */
498dc7e38acSHans Petter Selasky 	node = SYSCTL_ADD_NODE(&priv->sysctl_ctx,
499dc7e38acSHans Petter Selasky 	    SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
500dc7e38acSHans Petter Selasky 	    "conf", CTLFLAG_RW, NULL, "Configuration");
501dc7e38acSHans Petter Selasky 	if (node == NULL)
502dc7e38acSHans Petter Selasky 		return;
503dc7e38acSHans Petter Selasky 	for (x = 0; x != MLX5E_PARAMS_NUM; x++) {
504dc7e38acSHans Petter Selasky 		/* check for read-only parameter */
505dc7e38acSHans Petter Selasky 		if (strstr(mlx5e_params_desc[2 * x], "_max") != NULL) {
506dc7e38acSHans Petter Selasky 			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
507dc7e38acSHans Petter Selasky 			    mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RD |
508dc7e38acSHans Petter Selasky 			    CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU",
509dc7e38acSHans Petter Selasky 			    mlx5e_params_desc[2 * x + 1]);
510dc7e38acSHans Petter Selasky 		} else {
511ec0143b2SHans Petter Selasky #if (__FreeBSD_version < 1100000)
512ec0143b2SHans Petter Selasky 			char path[64];
513ec0143b2SHans Petter Selasky #endif
514ec0143b2SHans Petter Selasky 			/*
515ec0143b2SHans Petter Selasky 			 * NOTE: In FreeBSD-11 and newer the
516ec0143b2SHans Petter Selasky 			 * CTLFLAG_RWTUN flag will take care of
517ec0143b2SHans Petter Selasky 			 * loading default sysctl value from the
518ec0143b2SHans Petter Selasky 			 * kernel environment, if any:
519ec0143b2SHans Petter Selasky 			 */
520dc7e38acSHans Petter Selasky 			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
521dc7e38acSHans Petter Selasky 			    mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RWTUN |
522dc7e38acSHans Petter Selasky 			    CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU",
523dc7e38acSHans Petter Selasky 			    mlx5e_params_desc[2 * x + 1]);
524ec0143b2SHans Petter Selasky 
525ec0143b2SHans Petter Selasky #if (__FreeBSD_version < 1100000)
526ec0143b2SHans Petter Selasky 			/* compute path for sysctl */
527ec0143b2SHans Petter Selasky 			snprintf(path, sizeof(path), "dev.mce.%d.conf.%s",
528ec0143b2SHans Petter Selasky 			    device_get_unit(priv->mdev->pdev->dev.bsddev),
529ec0143b2SHans Petter Selasky 			    mlx5e_params_desc[2 * x]);
530ec0143b2SHans Petter Selasky 
531ec0143b2SHans Petter Selasky 			/* try to fetch tunable, if any */
532ec0143b2SHans Petter Selasky 			if (TUNABLE_QUAD_FETCH(path, &priv->params_ethtool.arg[x]))
533ec0143b2SHans Petter Selasky 				mlx5e_ethtool_handler(NULL, priv, x, NULL);
534ec0143b2SHans Petter Selasky #endif
535dc7e38acSHans Petter Selasky 		}
536dc7e38acSHans Petter Selasky 	}
537dc7e38acSHans Petter Selasky 
538dc7e38acSHans Petter Selasky 	SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
539dc7e38acSHans Petter Selasky 	    "debug_stats", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv,
540dc7e38acSHans Petter Selasky 	    0, &mlx5e_ethtool_debug_stats, "I", "Extended debug statistics");
541dc7e38acSHans Petter Selasky 
542dc7e38acSHans Petter Selasky 	pnameunit = device_get_nameunit(priv->mdev->pdev->dev.bsddev);
543dc7e38acSHans Petter Selasky 
544dc7e38acSHans Petter Selasky 	SYSCTL_ADD_STRING(&priv->sysctl_ctx, SYSCTL_CHILDREN(node),
545dc7e38acSHans Petter Selasky 	    OID_AUTO, "device_name", CTLFLAG_RD,
546dc7e38acSHans Petter Selasky 	    __DECONST(void *, pnameunit), 0,
547dc7e38acSHans Petter Selasky 	    "PCI device name");
548dc7e38acSHans Petter Selasky 
549dc7e38acSHans Petter Selasky 	/* EEPROM support */
550dc7e38acSHans Petter Selasky 	SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO, "eeprom_info",
551dc7e38acSHans Petter Selasky 	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0,
552dc7e38acSHans Petter Selasky 	    mlx5e_read_eeprom, "I", "EEPROM information");
553dc7e38acSHans Petter Selasky }
554