xref: /freebsd/sys/dev/mlx5/mlx5_core/mlx5_port.c (revision 2f513db7)
1 /*-
2  * Copyright (c) 2013-2018, Mellanox Technologies, Ltd.  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$
26  */
27 
28 #include <linux/module.h>
29 #include <dev/mlx5/port.h>
30 #include "mlx5_core.h"
31 
32 int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in,
33 			 int size_in, void *data_out, int size_out,
34 			 u16 reg_num, int arg, int write)
35 {
36 	int outlen = MLX5_ST_SZ_BYTES(access_register_out) + size_out;
37 	int inlen = MLX5_ST_SZ_BYTES(access_register_in) + size_in;
38 	int err = -ENOMEM;
39 	u32 *out = NULL;
40 	u32 *in = NULL;
41 	void *data;
42 
43 	in = mlx5_vzalloc(inlen);
44 	out = mlx5_vzalloc(outlen);
45 	if (!in || !out)
46 		goto out;
47 
48 	data = MLX5_ADDR_OF(access_register_in, in, register_data);
49 	memcpy(data, data_in, size_in);
50 
51 	MLX5_SET(access_register_in, in, opcode, MLX5_CMD_OP_ACCESS_REG);
52 	MLX5_SET(access_register_in, in, op_mod, !write);
53 	MLX5_SET(access_register_in, in, argument, arg);
54 	MLX5_SET(access_register_in, in, register_id, reg_num);
55 
56 	err = mlx5_cmd_exec(dev, in, inlen, out, outlen);
57 	if (err)
58 		goto out;
59 	data = MLX5_ADDR_OF(access_register_out, out, register_data);
60 	memcpy(data_out, data, size_out);
61 
62 out:
63 	kvfree(out);
64 	kvfree(in);
65 	return err;
66 }
67 EXPORT_SYMBOL_GPL(mlx5_core_access_reg);
68 
69 int mlx5_query_qcam_reg(struct mlx5_core_dev *mdev, u32 *qcam,
70 			u8 feature_group, u8 access_reg_group)
71 {
72 	u32 in[MLX5_ST_SZ_DW(qcam_reg)] = {};
73 	int sz = MLX5_ST_SZ_BYTES(qcam_reg);
74 
75 	MLX5_SET(qcam_reg, in, feature_group, feature_group);
76 	MLX5_SET(qcam_reg, in, access_reg_group, access_reg_group);
77 
78 	return mlx5_core_access_reg(mdev, in, sz, qcam, sz, MLX5_REG_QCAM, 0, 0);
79 }
80 EXPORT_SYMBOL_GPL(mlx5_query_qcam_reg);
81 
82 int mlx5_query_pcam_reg(struct mlx5_core_dev *dev, u32 *pcam, u8 feature_group,
83 			u8 access_reg_group)
84 {
85 	u32 in[MLX5_ST_SZ_DW(pcam_reg)] = {};
86 	int sz = MLX5_ST_SZ_BYTES(pcam_reg);
87 
88 	MLX5_SET(pcam_reg, in, feature_group, feature_group);
89 	MLX5_SET(pcam_reg, in, access_reg_group, access_reg_group);
90 
91 	return mlx5_core_access_reg(dev, in, sz, pcam, sz, MLX5_REG_PCAM, 0, 0);
92 }
93 
94 int mlx5_query_mcam_reg(struct mlx5_core_dev *dev, u32 *mcam, u8 feature_group,
95 			u8 access_reg_group)
96 {
97 	u32 in[MLX5_ST_SZ_DW(mcam_reg)] = {};
98 	int sz = MLX5_ST_SZ_BYTES(mcam_reg);
99 
100 	MLX5_SET(mcam_reg, in, feature_group, feature_group);
101 	MLX5_SET(mcam_reg, in, access_reg_group, access_reg_group);
102 
103 	return mlx5_core_access_reg(dev, in, sz, mcam, sz, MLX5_REG_MCAM, 0, 0);
104 }
105 
106 struct mlx5_reg_pcap {
107 	u8			rsvd0;
108 	u8			port_num;
109 	u8			rsvd1[2];
110 	__be32			caps_127_96;
111 	__be32			caps_95_64;
112 	__be32			caps_63_32;
113 	__be32			caps_31_0;
114 };
115 
116 /* This function should be used after setting a port register only */
117 void mlx5_toggle_port_link(struct mlx5_core_dev *dev)
118 {
119 	enum mlx5_port_status ps;
120 
121 	mlx5_query_port_admin_status(dev, &ps);
122 	mlx5_set_port_status(dev, MLX5_PORT_DOWN);
123 	if (ps == MLX5_PORT_UP)
124 		mlx5_set_port_status(dev, MLX5_PORT_UP);
125 }
126 EXPORT_SYMBOL_GPL(mlx5_toggle_port_link);
127 
128 int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps)
129 {
130 	struct mlx5_reg_pcap in;
131 	struct mlx5_reg_pcap out;
132 	int err;
133 
134 	memset(&in, 0, sizeof(in));
135 	in.caps_127_96 = cpu_to_be32(caps);
136 	in.port_num = port_num;
137 
138 	err = mlx5_core_access_reg(dev, &in, sizeof(in), &out,
139 				   sizeof(out), MLX5_REG_PCAP, 0, 1);
140 
141 	return err;
142 }
143 EXPORT_SYMBOL_GPL(mlx5_set_port_caps);
144 
145 int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys,
146 			 int ptys_size, int proto_mask, u8 local_port)
147 {
148 	u32 in[MLX5_ST_SZ_DW(ptys_reg)];
149 	int err;
150 
151 	memset(in, 0, sizeof(in));
152 	MLX5_SET(ptys_reg, in, local_port, local_port);
153 	MLX5_SET(ptys_reg, in, proto_mask, proto_mask);
154 
155 	err = mlx5_core_access_reg(dev, in, sizeof(in), ptys,
156 				   ptys_size, MLX5_REG_PTYS, 0, 0);
157 
158 	return err;
159 }
160 EXPORT_SYMBOL_GPL(mlx5_query_port_ptys);
161 
162 int mlx5_query_port_proto_cap(struct mlx5_core_dev *dev,
163 			      u32 *proto_cap, int proto_mask)
164 {
165 	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
166 	int err;
167 
168 	err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1);
169 	if (err)
170 		return err;
171 
172 	if (proto_mask == MLX5_PTYS_EN)
173 		*proto_cap = MLX5_GET(ptys_reg, out, eth_proto_capability);
174 	else
175 		*proto_cap = MLX5_GET(ptys_reg, out, ib_proto_capability);
176 
177 	return 0;
178 }
179 EXPORT_SYMBOL_GPL(mlx5_query_port_proto_cap);
180 
181 int mlx5_query_port_autoneg(struct mlx5_core_dev *dev, int proto_mask,
182 			    u8 *an_disable_cap, u8 *an_disable_status)
183 {
184 	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
185 	int err;
186 
187 	err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1);
188 	if (err)
189 		return err;
190 
191 	*an_disable_status = MLX5_GET(ptys_reg, out, an_disable_admin);
192 	*an_disable_cap = MLX5_GET(ptys_reg, out, an_disable_cap);
193 
194 	return 0;
195 }
196 EXPORT_SYMBOL_GPL(mlx5_query_port_autoneg);
197 
198 int mlx5_set_port_autoneg(struct mlx5_core_dev *dev, bool disable,
199 			  u32 eth_proto_admin, int proto_mask)
200 {
201 	u32 in[MLX5_ST_SZ_DW(ptys_reg)] = {0};
202 	u32 out[MLX5_ST_SZ_DW(ptys_reg)] = {0};
203 	u8 an_disable_cap;
204 	u8 an_disable_status;
205 	int err;
206 
207 	err = mlx5_query_port_autoneg(dev, proto_mask, &an_disable_cap,
208 				      &an_disable_status);
209 	if (err)
210 		return err;
211 	if (!an_disable_cap)
212 		return -EPERM;
213 
214 	MLX5_SET(ptys_reg, in, local_port, 1);
215 	MLX5_SET(ptys_reg, in, an_disable_admin, disable);
216 	MLX5_SET(ptys_reg, in, proto_mask, proto_mask);
217 	if (proto_mask == MLX5_PTYS_EN)
218 		MLX5_SET(ptys_reg, in, eth_proto_admin, eth_proto_admin);
219 
220 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
221 				   sizeof(out), MLX5_REG_PTYS, 0, 1);
222 	return err;
223 }
224 EXPORT_SYMBOL_GPL(mlx5_set_port_autoneg);
225 
226 int mlx5_query_port_proto_admin(struct mlx5_core_dev *dev,
227 				u32 *proto_admin, int proto_mask)
228 {
229 	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
230 	int err;
231 
232 	err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1);
233 	if (err)
234 		return err;
235 
236 	if (proto_mask == MLX5_PTYS_EN)
237 		*proto_admin = MLX5_GET(ptys_reg, out, eth_proto_admin);
238 	else
239 		*proto_admin = MLX5_GET(ptys_reg, out, ib_proto_admin);
240 
241 	return 0;
242 }
243 EXPORT_SYMBOL_GPL(mlx5_query_port_proto_admin);
244 
245 int mlx5_query_port_eth_proto_oper(struct mlx5_core_dev *dev,
246 				   u32 *proto_oper, u8 local_port)
247 {
248 	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
249 	int err;
250 
251 	err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN,
252 				   local_port);
253 	if (err)
254 		return err;
255 
256 	*proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper);
257 
258 	return 0;
259 }
260 EXPORT_SYMBOL(mlx5_query_port_eth_proto_oper);
261 
262 int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin,
263 			int proto_mask, bool ext)
264 {
265 	u32 in[MLX5_ST_SZ_DW(ptys_reg)] = {0};
266 	u32 out[MLX5_ST_SZ_DW(ptys_reg)] = {0};
267 	int err;
268 
269 	MLX5_SET(ptys_reg, in, local_port, 1);
270 	MLX5_SET(ptys_reg, in, proto_mask, proto_mask);
271 	if (proto_mask == MLX5_PTYS_EN) {
272 		if (ext)
273 			MLX5_SET(ptys_reg, in, ext_eth_proto_admin, proto_admin);
274 		else
275 			MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin);
276 	} else {
277 		MLX5_SET(ptys_reg, in, ib_proto_admin, proto_admin);
278 	}
279 
280 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
281 				   sizeof(out), MLX5_REG_PTYS, 0, 1);
282 	return err;
283 }
284 EXPORT_SYMBOL_GPL(mlx5_set_port_proto);
285 
286 int mlx5_set_port_status(struct mlx5_core_dev *dev,
287 			 enum mlx5_port_status status)
288 {
289 	u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0};
290 	u32 out[MLX5_ST_SZ_DW(paos_reg)] = {0};
291 	int err;
292 
293 	MLX5_SET(paos_reg, in, local_port, 1);
294 
295 	MLX5_SET(paos_reg, in, admin_status, status);
296 	MLX5_SET(paos_reg, in, ase, 1);
297 
298 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
299 				   sizeof(out), MLX5_REG_PAOS, 0, 1);
300 	return err;
301 }
302 
303 int mlx5_query_port_status(struct mlx5_core_dev *dev, u8 *status)
304 {
305 	u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0};
306 	u32 out[MLX5_ST_SZ_DW(paos_reg)] = {0};
307 	int err;
308 
309 	MLX5_SET(paos_reg, in, local_port, 1);
310 
311 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
312 				   sizeof(out), MLX5_REG_PAOS, 0, 0);
313 	if (err)
314 		return err;
315 
316 	*status = MLX5_GET(paos_reg, out, oper_status);
317 	return err;
318 }
319 
320 int mlx5_query_port_admin_status(struct mlx5_core_dev *dev,
321 				 enum mlx5_port_status *status)
322 {
323 	u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0};
324 	u32 out[MLX5_ST_SZ_DW(paos_reg)];
325 	int err;
326 
327 	MLX5_SET(paos_reg, in, local_port, 1);
328 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
329 				   sizeof(out), MLX5_REG_PAOS, 0, 0);
330 	if (err)
331 		return err;
332 	*status = MLX5_GET(paos_reg, out, admin_status);
333 	return 0;
334 }
335 EXPORT_SYMBOL_GPL(mlx5_query_port_admin_status);
336 
337 static int mlx5_query_port_mtu(struct mlx5_core_dev *dev,
338 			       int *admin_mtu, int *max_mtu, int *oper_mtu)
339 {
340 	u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
341 	u32 out[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
342 	int err;
343 
344 	MLX5_SET(pmtu_reg, in, local_port, 1);
345 
346 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
347 				   sizeof(out), MLX5_REG_PMTU, 0, 0);
348 	if (err)
349 		return err;
350 
351 	if (max_mtu)
352 		*max_mtu  = MLX5_GET(pmtu_reg, out, max_mtu);
353 	if (oper_mtu)
354 		*oper_mtu = MLX5_GET(pmtu_reg, out, oper_mtu);
355 	if (admin_mtu)
356 		*admin_mtu = MLX5_GET(pmtu_reg, out, admin_mtu);
357 
358 	return err;
359 }
360 
361 int mlx5_set_port_mtu(struct mlx5_core_dev *dev, int mtu)
362 {
363 	u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
364 	u32 out[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
365 
366 	MLX5_SET(pmtu_reg, in, admin_mtu, mtu);
367 	MLX5_SET(pmtu_reg, in, local_port, 1);
368 
369 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
370 				   sizeof(out), MLX5_REG_PMTU, 0, 1);
371 }
372 EXPORT_SYMBOL_GPL(mlx5_set_port_mtu);
373 
374 int mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, int *max_mtu)
375 {
376 	return mlx5_query_port_mtu(dev, NULL, max_mtu, NULL);
377 }
378 EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu);
379 
380 int mlx5_set_port_pause_and_pfc(struct mlx5_core_dev *dev, u32 port,
381 				u8 rx_pause, u8 tx_pause,
382 				u8 pfc_en_rx, u8 pfc_en_tx)
383 {
384 	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
385 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
386 
387 	if (pfc_en_rx || pfc_en_tx) {
388 		/* PFC and global pauseframes are incompatible features */
389 		if (tx_pause || rx_pause)
390 			return -EINVAL;
391 	}
392 
393 	MLX5_SET(pfcc_reg, in, local_port, port);
394 	MLX5_SET(pfcc_reg, in, pptx, tx_pause);
395 	MLX5_SET(pfcc_reg, in, pprx, rx_pause);
396 	MLX5_SET(pfcc_reg, in, pfctx, pfc_en_tx);
397 	MLX5_SET(pfcc_reg, in, pfcrx, pfc_en_rx);
398 	MLX5_SET(pfcc_reg, in, prio_mask_tx, pfc_en_tx);
399 	MLX5_SET(pfcc_reg, in, prio_mask_rx, pfc_en_rx);
400 
401 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
402 				   sizeof(out), MLX5_REG_PFCC, 0, 1);
403 }
404 
405 int mlx5_query_port_pause(struct mlx5_core_dev *dev, u32 port,
406 			  u32 *rx_pause, u32 *tx_pause)
407 {
408 	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
409 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
410 	int err;
411 
412 	MLX5_SET(pfcc_reg, in, local_port, port);
413 
414 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
415 				   sizeof(out), MLX5_REG_PFCC, 0, 0);
416 	if (err)
417 		return err;
418 
419 	*rx_pause = MLX5_GET(pfcc_reg, out, pprx);
420 	*tx_pause = MLX5_GET(pfcc_reg, out, pptx);
421 
422 	return 0;
423 }
424 
425 int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx, u8 *pfc_en_rx)
426 {
427 	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {};
428 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
429 	int err;
430 
431 	MLX5_SET(pfcc_reg, in, local_port, 1);
432 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
433 				   sizeof(out), MLX5_REG_PFCC, 0, 0);
434 	if (err)
435 		return err;
436 
437 	if (pfc_en_tx != NULL)
438 		*pfc_en_tx = MLX5_GET(pfcc_reg, out, pfctx);
439 	if (pfc_en_rx != NULL)
440 		*pfc_en_rx = MLX5_GET(pfcc_reg, out, pfcrx);
441 	return 0;
442 }
443 EXPORT_SYMBOL_GPL(mlx5_query_port_pfc);
444 
445 int mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, int *oper_mtu)
446 {
447 	return mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu);
448 }
449 EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu);
450 
451 u8 mlx5_is_wol_supported(struct mlx5_core_dev *dev)
452 {
453 	u8 wol_supported = 0;
454 
455 	if (MLX5_CAP_GEN(dev, wol_s))
456 		wol_supported |= MLX5_WOL_SECURED_MAGIC;
457 	if (MLX5_CAP_GEN(dev, wol_g))
458 		wol_supported |= MLX5_WOL_MAGIC;
459 	if (MLX5_CAP_GEN(dev, wol_a))
460 		wol_supported |= MLX5_WOL_ARP;
461 	if (MLX5_CAP_GEN(dev, wol_b))
462 		wol_supported |= MLX5_WOL_BROADCAST;
463 	if (MLX5_CAP_GEN(dev, wol_m))
464 		wol_supported |= MLX5_WOL_MULTICAST;
465 	if (MLX5_CAP_GEN(dev, wol_u))
466 		wol_supported |= MLX5_WOL_UNICAST;
467 	if (MLX5_CAP_GEN(dev, wol_p))
468 		wol_supported |= MLX5_WOL_PHY_ACTIVITY;
469 
470 	return wol_supported;
471 }
472 EXPORT_SYMBOL_GPL(mlx5_is_wol_supported);
473 
474 int mlx5_set_wol(struct mlx5_core_dev *dev, u8 wol_mode)
475 {
476 	u32 in[MLX5_ST_SZ_DW(set_wol_rol_in)] = {0};
477 	u32 out[MLX5_ST_SZ_DW(set_wol_rol_out)] = {0};
478 
479 	MLX5_SET(set_wol_rol_in, in, opcode, MLX5_CMD_OP_SET_WOL_ROL);
480 	MLX5_SET(set_wol_rol_in, in, wol_mode_valid, 1);
481 	MLX5_SET(set_wol_rol_in, in, wol_mode, wol_mode);
482 
483 	return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
484 }
485 EXPORT_SYMBOL_GPL(mlx5_set_wol);
486 
487 int mlx5_query_dropless_mode(struct mlx5_core_dev *dev, u16 *timeout)
488 {
489 	u32 in[MLX5_ST_SZ_DW(query_delay_drop_params_in)] = {0};
490 	u32 out[MLX5_ST_SZ_DW(query_delay_drop_params_out)] = {0};
491 	int err = 0;
492 
493 	MLX5_SET(query_delay_drop_params_in, in, opcode,
494 		 MLX5_CMD_OP_QUERY_DELAY_DROP_PARAMS);
495 
496 	err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
497 	if (err)
498 		return err;
499 
500 	*timeout = MLX5_GET(query_delay_drop_params_out, out,
501 			    delay_drop_timeout);
502 
503 	return 0;
504 }
505 EXPORT_SYMBOL_GPL(mlx5_query_dropless_mode);
506 
507 int mlx5_set_dropless_mode(struct mlx5_core_dev *dev, u16 timeout)
508 {
509 	u32 in[MLX5_ST_SZ_DW(set_delay_drop_params_in)] = {0};
510 	u32 out[MLX5_ST_SZ_DW(set_delay_drop_params_out)] = {0};
511 
512 	MLX5_SET(set_delay_drop_params_in, in, opcode,
513 		 MLX5_CMD_OP_SET_DELAY_DROP_PARAMS);
514 	MLX5_SET(set_delay_drop_params_in, in, delay_drop_timeout, timeout);
515 
516 	return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
517 }
518 EXPORT_SYMBOL_GPL(mlx5_set_dropless_mode);
519 
520 int mlx5_core_access_pvlc(struct mlx5_core_dev *dev,
521 			  struct mlx5_pvlc_reg *pvlc, int write)
522 {
523 	int sz = MLX5_ST_SZ_BYTES(pvlc_reg);
524 	u8 in[MLX5_ST_SZ_BYTES(pvlc_reg)] = {0};
525 	u8 out[MLX5_ST_SZ_BYTES(pvlc_reg)] = {0};
526 	int err;
527 
528 	MLX5_SET(pvlc_reg, in, local_port, pvlc->local_port);
529 	if (write)
530 		MLX5_SET(pvlc_reg, in, vl_admin, pvlc->vl_admin);
531 
532 	err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PVLC, 0,
533 				   !!write);
534 	if (err)
535 		return err;
536 
537 	if (!write) {
538 		pvlc->local_port = MLX5_GET(pvlc_reg, out, local_port);
539 		pvlc->vl_hw_cap = MLX5_GET(pvlc_reg, out, vl_hw_cap);
540 		pvlc->vl_admin = MLX5_GET(pvlc_reg, out, vl_admin);
541 		pvlc->vl_operational = MLX5_GET(pvlc_reg, out, vl_operational);
542 	}
543 
544 	return 0;
545 }
546 EXPORT_SYMBOL_GPL(mlx5_core_access_pvlc);
547 
548 int mlx5_core_access_ptys(struct mlx5_core_dev *dev,
549 			  struct mlx5_ptys_reg *ptys, int write)
550 {
551 	int sz = MLX5_ST_SZ_BYTES(ptys_reg);
552 	void *out = NULL;
553 	void *in = NULL;
554 	int err;
555 
556 	in = mlx5_vzalloc(sz);
557 	if (!in)
558 		return -ENOMEM;
559 
560 	out = mlx5_vzalloc(sz);
561 	if (!out) {
562 		kfree(in);
563 		return -ENOMEM;
564 	}
565 
566 	MLX5_SET(ptys_reg, in, local_port, ptys->local_port);
567 	MLX5_SET(ptys_reg, in, proto_mask, ptys->proto_mask);
568 	if (write) {
569 		MLX5_SET(ptys_reg, in, eth_proto_capability,
570 			 ptys->eth_proto_cap);
571 		MLX5_SET(ptys_reg, in, ib_link_width_capability,
572 			 ptys->ib_link_width_cap);
573 		MLX5_SET(ptys_reg, in, ib_proto_capability,
574 			 ptys->ib_proto_cap);
575 		MLX5_SET(ptys_reg, in, eth_proto_admin, ptys->eth_proto_admin);
576 		MLX5_SET(ptys_reg, in, ib_link_width_admin,
577 			 ptys->ib_link_width_admin);
578 		MLX5_SET(ptys_reg, in, ib_proto_admin, ptys->ib_proto_admin);
579 		MLX5_SET(ptys_reg, in, eth_proto_oper, ptys->eth_proto_oper);
580 		MLX5_SET(ptys_reg, in, ib_link_width_oper,
581 			 ptys->ib_link_width_oper);
582 		MLX5_SET(ptys_reg, in, ib_proto_oper, ptys->ib_proto_oper);
583 		MLX5_SET(ptys_reg, in, eth_proto_lp_advertise,
584 			 ptys->eth_proto_lp_advertise);
585 	}
586 
587 	err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PTYS, 0,
588 				   !!write);
589 	if (err)
590 		goto out;
591 
592 	if (!write) {
593 		ptys->local_port = MLX5_GET(ptys_reg, out, local_port);
594 		ptys->proto_mask = MLX5_GET(ptys_reg, out, proto_mask);
595 		ptys->eth_proto_cap = MLX5_GET(ptys_reg, out,
596 					       eth_proto_capability);
597 		ptys->ib_link_width_cap = MLX5_GET(ptys_reg, out,
598 					   ib_link_width_capability);
599 		ptys->ib_proto_cap = MLX5_GET(ptys_reg, out,
600 					      ib_proto_capability);
601 		ptys->eth_proto_admin = MLX5_GET(ptys_reg, out,
602 						 eth_proto_admin);
603 		ptys->ib_link_width_admin = MLX5_GET(ptys_reg, out,
604 						     ib_link_width_admin);
605 		ptys->ib_proto_admin = MLX5_GET(ptys_reg, out, ib_proto_admin);
606 		ptys->eth_proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper);
607 		ptys->ib_link_width_oper = MLX5_GET(ptys_reg, out,
608 						    ib_link_width_oper);
609 		ptys->ib_proto_oper = MLX5_GET(ptys_reg, out, ib_proto_oper);
610 		ptys->eth_proto_lp_advertise = MLX5_GET(ptys_reg, out,
611 							eth_proto_lp_advertise);
612 	}
613 
614 out:
615 	kvfree(in);
616 	kvfree(out);
617 	return err;
618 }
619 EXPORT_SYMBOL_GPL(mlx5_core_access_ptys);
620 
621 static int mtu_to_ib_mtu(struct mlx5_core_dev *dev, int mtu)
622 {
623 	switch (mtu) {
624 	case 256: return 1;
625 	case 512: return 2;
626 	case 1024: return 3;
627 	case 2048: return 4;
628 	case 4096: return 5;
629 	default:
630 		mlx5_core_warn(dev, "invalid mtu\n");
631 		return -1;
632 	}
633 }
634 
635 int mlx5_core_access_pmtu(struct mlx5_core_dev *dev,
636 			  struct mlx5_pmtu_reg *pmtu, int write)
637 {
638 	int sz = MLX5_ST_SZ_BYTES(pmtu_reg);
639 	void *out = NULL;
640 	void *in = NULL;
641 	int err;
642 
643 	in = mlx5_vzalloc(sz);
644 	if (!in)
645 		return -ENOMEM;
646 
647 	out = mlx5_vzalloc(sz);
648 	if (!out) {
649 		kfree(in);
650 		return -ENOMEM;
651 	}
652 
653 	MLX5_SET(pmtu_reg, in, local_port, pmtu->local_port);
654 	if (write)
655 		MLX5_SET(pmtu_reg, in, admin_mtu, pmtu->admin_mtu);
656 
657 	err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PMTU, 0,
658 				   !!write);
659 	if (err)
660 		goto out;
661 
662 	if (!write) {
663 		pmtu->local_port = MLX5_GET(pmtu_reg, out, local_port);
664 		pmtu->max_mtu = mtu_to_ib_mtu(dev, MLX5_GET(pmtu_reg, out,
665 						       max_mtu));
666 		pmtu->admin_mtu = mtu_to_ib_mtu(dev, MLX5_GET(pmtu_reg, out,
667 							 admin_mtu));
668 		pmtu->oper_mtu = mtu_to_ib_mtu(dev, MLX5_GET(pmtu_reg, out,
669 							oper_mtu));
670 	}
671 
672 out:
673 	kvfree(in);
674 	kvfree(out);
675 	return err;
676 }
677 EXPORT_SYMBOL_GPL(mlx5_core_access_pmtu);
678 
679 int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num)
680 {
681 	u32 in[MLX5_ST_SZ_DW(pmlp_reg)] = {0};
682 	u32 out[MLX5_ST_SZ_DW(pmlp_reg)] = {0};
683 	int lane = 0;
684 	int err;
685 
686 	MLX5_SET(pmlp_reg, in, local_port, 1);
687 
688 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
689 				   sizeof(out), MLX5_REG_PMLP, 0, 0);
690 	if (err)
691 		return err;
692 
693 	lane = MLX5_GET(pmlp_reg, out, lane0_module_mapping);
694 	*module_num = lane & MLX5_EEPROM_IDENTIFIER_BYTE_MASK;
695 
696 	return 0;
697 }
698 EXPORT_SYMBOL_GPL(mlx5_query_module_num);
699 
700 int mlx5_query_eeprom(struct mlx5_core_dev *dev,
701 		      int i2c_addr, int page_num, int device_addr,
702 		      int size, int module_num, u32 *data, int *size_read)
703 {
704 	u32 in[MLX5_ST_SZ_DW(mcia_reg)] = {0};
705 	u32 out[MLX5_ST_SZ_DW(mcia_reg)] = {0};
706 	u32 *ptr = (u32 *)MLX5_ADDR_OF(mcia_reg, out, dword_0);
707 	int status;
708 	int err;
709 
710 	size = min_t(int, size, MLX5_EEPROM_MAX_BYTES);
711 
712 	MLX5_SET(mcia_reg, in, l, 0);
713 	MLX5_SET(mcia_reg, in, module, module_num);
714 	MLX5_SET(mcia_reg, in, i2c_device_address, i2c_addr);
715 	MLX5_SET(mcia_reg, in, page_number, page_num);
716 	MLX5_SET(mcia_reg, in, device_address, device_addr);
717 	MLX5_SET(mcia_reg, in, size, size);
718 
719 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
720 				   sizeof(out), MLX5_REG_MCIA, 0, 0);
721 	if (err)
722 		return err;
723 
724 	status = MLX5_GET(mcia_reg, out, status);
725 	if (status)
726 		return status;
727 
728 	memcpy(data, ptr, size);
729 	*size_read = size;
730 	return 0;
731 }
732 EXPORT_SYMBOL_GPL(mlx5_query_eeprom);
733 
734 int mlx5_vxlan_udp_port_add(struct mlx5_core_dev *dev, u16 port)
735 {
736 	u32 in[MLX5_ST_SZ_DW(add_vxlan_udp_dport_in)] = {0};
737 	u32 out[MLX5_ST_SZ_DW(add_vxlan_udp_dport_out)] = {0};
738 	int err;
739 
740 	MLX5_SET(add_vxlan_udp_dport_in, in, opcode,
741 		 MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT);
742 	MLX5_SET(add_vxlan_udp_dport_in, in, vxlan_udp_port, port);
743 
744 	err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
745 	if (err) {
746 		mlx5_core_err(dev, "Failed %s, port %u, err - %d",
747 			      mlx5_command_str(MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT),
748 			      port, err);
749 	}
750 
751 	return err;
752 }
753 
754 int mlx5_vxlan_udp_port_delete(struct mlx5_core_dev *dev, u16 port)
755 {
756 	u32 in[MLX5_ST_SZ_DW(delete_vxlan_udp_dport_in)] = {0};
757 	u32 out[MLX5_ST_SZ_DW(delete_vxlan_udp_dport_out)] = {0};
758 	int err;
759 
760 	MLX5_SET(delete_vxlan_udp_dport_in, in, opcode,
761 		 MLX5_CMD_OP_DELETE_VXLAN_UDP_DPORT);
762 	MLX5_SET(delete_vxlan_udp_dport_in, in, vxlan_udp_port, port);
763 
764 	err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
765 	if (err) {
766 		mlx5_core_err(dev, "Failed %s, port %u, err - %d",
767 			      mlx5_command_str(MLX5_CMD_OP_DELETE_VXLAN_UDP_DPORT),
768 			      port, err);
769 	}
770 
771 	return err;
772 }
773 
774 int mlx5_query_wol(struct mlx5_core_dev *dev, u8 *wol_mode)
775 {
776 	u32 in[MLX5_ST_SZ_DW(query_wol_rol_in)] = {0};
777 	u32 out[MLX5_ST_SZ_DW(query_wol_rol_out)] = {0};
778 	int err;
779 
780 	MLX5_SET(query_wol_rol_in, in, opcode, MLX5_CMD_OP_QUERY_WOL_ROL);
781 
782 	err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
783 
784 	if (!err)
785 		*wol_mode = MLX5_GET(query_wol_rol_out, out, wol_mode);
786 
787 	return err;
788 }
789 EXPORT_SYMBOL_GPL(mlx5_query_wol);
790 
791 int mlx5_query_port_cong_status(struct mlx5_core_dev *mdev, int protocol,
792 				int priority, int *is_enable)
793 {
794 	u32 in[MLX5_ST_SZ_DW(query_cong_status_in)] = {0};
795 	u32 out[MLX5_ST_SZ_DW(query_cong_status_out)] = {0};
796 	int err;
797 
798 	*is_enable = 0;
799 
800 	MLX5_SET(query_cong_status_in, in, opcode,
801 		 MLX5_CMD_OP_QUERY_CONG_STATUS);
802 	MLX5_SET(query_cong_status_in, in, cong_protocol, protocol);
803 	MLX5_SET(query_cong_status_in, in, priority, priority);
804 
805 	err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
806 	if (!err)
807 		*is_enable = MLX5_GET(query_cong_status_out, out, enable);
808 	return err;
809 }
810 
811 int mlx5_modify_port_cong_status(struct mlx5_core_dev *mdev, int protocol,
812 				 int priority, int enable)
813 {
814 	u32 in[MLX5_ST_SZ_DW(modify_cong_status_in)] = {0};
815 	u32 out[MLX5_ST_SZ_DW(modify_cong_status_out)] = {0};
816 
817 	MLX5_SET(modify_cong_status_in, in, opcode,
818 		 MLX5_CMD_OP_MODIFY_CONG_STATUS);
819 	MLX5_SET(modify_cong_status_in, in, cong_protocol, protocol);
820 	MLX5_SET(modify_cong_status_in, in, priority, priority);
821 	MLX5_SET(modify_cong_status_in, in, enable, enable);
822 
823 	return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
824 }
825 
826 int mlx5_query_port_cong_params(struct mlx5_core_dev *mdev, int protocol,
827 				void *out, int out_size)
828 {
829 	u32 in[MLX5_ST_SZ_DW(query_cong_params_in)] = {0};
830 
831 	MLX5_SET(query_cong_params_in, in, opcode,
832 		 MLX5_CMD_OP_QUERY_CONG_PARAMS);
833 	MLX5_SET(query_cong_params_in, in, cong_protocol, protocol);
834 
835 	return mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size);
836 }
837 
838 static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out,
839 				     int outlen)
840 {
841 	u32 in[MLX5_ST_SZ_DW(qetc_reg)];
842 
843 	if (!MLX5_CAP_GEN(mdev, ets))
844 		return -ENOTSUPP;
845 
846 	memset(in, 0, sizeof(in));
847 	return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen,
848 				    MLX5_REG_QETCR, 0, 0);
849 }
850 
851 int mlx5_max_tc(struct mlx5_core_dev *mdev)
852 {
853 	u8 num_tc = MLX5_CAP_GEN(mdev, max_tc) ? : 8;
854 
855 	return num_tc - 1;
856 }
857 EXPORT_SYMBOL_GPL(mlx5_max_tc);
858 
859 static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in,
860 				   int inlen)
861 {
862 	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
863 
864 	if (!MLX5_CAP_GEN(mdev, ets))
865 		return -ENOTSUPP;
866 
867 	return mlx5_core_access_reg(mdev, in, inlen, out, sizeof(out),
868 				    MLX5_REG_QETCR, 0, 1);
869 }
870 
871 int mlx5_query_port_tc_rate_limit(struct mlx5_core_dev *mdev,
872 				   u8 *max_bw_value,
873 				   u8 *max_bw_units)
874 {
875 	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
876 	void *ets_tcn_conf;
877 	int err;
878 	int i;
879 
880 	err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
881 	if (err)
882 		return err;
883 
884 	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
885 		ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, tc_configuration[i]);
886 
887 		max_bw_value[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
888 					   max_bw_value);
889 		max_bw_units[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
890 					   max_bw_units);
891 	}
892 
893 	return 0;
894 }
895 EXPORT_SYMBOL_GPL(mlx5_query_port_tc_rate_limit);
896 
897 int mlx5_modify_port_tc_rate_limit(struct mlx5_core_dev *mdev,
898 				   const u8 *max_bw_value,
899 				   const u8 *max_bw_units)
900 {
901 	u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {};
902 	void *ets_tcn_conf;
903 	int i;
904 
905 	MLX5_SET(qetc_reg, in, port_number, 1);
906 
907 	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
908 		ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, in, tc_configuration[i]);
909 
910 		MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, r, 1);
911 		MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_units,
912 			 max_bw_units[i]);
913 		MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_value,
914 			 max_bw_value[i]);
915 	}
916 
917 	return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
918 }
919 EXPORT_SYMBOL_GPL(mlx5_modify_port_tc_rate_limit);
920 
921 int mlx5_query_port_prio_tc(struct mlx5_core_dev *mdev,
922 			    u8 prio, u8 *tc)
923 {
924 	u32 in[MLX5_ST_SZ_DW(qtct_reg)];
925 	u32 out[MLX5_ST_SZ_DW(qtct_reg)];
926 	int err;
927 
928 	memset(in, 0, sizeof(in));
929 	memset(out, 0, sizeof(out));
930 
931 	MLX5_SET(qtct_reg, in, port_number, 1);
932 	MLX5_SET(qtct_reg, in, prio, prio);
933 
934 	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
935 				   sizeof(out), MLX5_REG_QTCT, 0, 0);
936 	if (!err)
937 		*tc = MLX5_GET(qtct_reg, out, tclass);
938 
939 	return err;
940 }
941 EXPORT_SYMBOL_GPL(mlx5_query_port_prio_tc);
942 
943 int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, int prio_index,
944 			  const u8 prio_tc)
945 {
946 	u32 in[MLX5_ST_SZ_DW(qtct_reg)] = {};
947 	u32 out[MLX5_ST_SZ_DW(qtct_reg)];
948 	int err;
949 
950 	if (prio_tc > mlx5_max_tc(mdev))
951 		return -EINVAL;
952 
953 	MLX5_SET(qtct_reg, in, prio, prio_index);
954 	MLX5_SET(qtct_reg, in, tclass, prio_tc);
955 
956 	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
957 				   sizeof(out), MLX5_REG_QTCT, 0, 1);
958 
959 	return (err);
960 }
961 EXPORT_SYMBOL_GPL(mlx5_set_port_prio_tc);
962 
963 int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, const u8 *tc_group)
964 {
965 	u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {};
966 	int i;
967 
968 	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
969 		MLX5_SET(qetc_reg, in, tc_configuration[i].g, 1);
970 		MLX5_SET(qetc_reg, in, tc_configuration[i].group, tc_group[i]);
971 	}
972 
973 	return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
974 }
975 EXPORT_SYMBOL_GPL(mlx5_set_port_tc_group);
976 
977 int mlx5_query_port_tc_group(struct mlx5_core_dev *mdev,
978 			     u8 tc, u8 *tc_group)
979 {
980 	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
981 	void *ets_tcn_conf;
982 	int err;
983 
984 	err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
985 	if (err)
986 		return err;
987 
988 	ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out,
989 				    tc_configuration[tc]);
990 
991 	*tc_group = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
992 			     group);
993 
994 	return 0;
995 }
996 EXPORT_SYMBOL_GPL(mlx5_query_port_tc_group);
997 
998 int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, const u8 *tc_bw)
999 {
1000 	u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {};
1001 	int i;
1002 
1003 	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
1004 		MLX5_SET(qetc_reg, in, tc_configuration[i].b, 1);
1005 		MLX5_SET(qetc_reg, in, tc_configuration[i].bw_allocation, tc_bw[i]);
1006 	}
1007 
1008 	return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
1009 }
1010 EXPORT_SYMBOL_GPL(mlx5_set_port_tc_bw_alloc);
1011 
1012 int mlx5_query_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *bw_pct)
1013 {
1014 	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
1015 	void *ets_tcn_conf;
1016 	int err;
1017 	int i;
1018 
1019 	err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
1020 	if (err)
1021 		return err;
1022 
1023 	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
1024 		ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, tc_configuration[i]);
1025 		bw_pct[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf, bw_allocation);
1026 	}
1027 	return 0;
1028 }
1029 EXPORT_SYMBOL_GPL(mlx5_query_port_tc_bw_alloc);
1030 
1031 int mlx5_modify_port_cong_params(struct mlx5_core_dev *mdev,
1032 				 void *in, int in_size)
1033 {
1034 	u32 out[MLX5_ST_SZ_DW(modify_cong_params_out)] = {0};
1035 
1036 	MLX5_SET(modify_cong_params_in, in, opcode,
1037 		 MLX5_CMD_OP_MODIFY_CONG_PARAMS);
1038 
1039 	return mlx5_cmd_exec(mdev, in, in_size, out, sizeof(out));
1040 }
1041 
1042 int mlx5_query_port_cong_statistics(struct mlx5_core_dev *mdev, int clear,
1043 				    void *out, int out_size)
1044 {
1045 	u32 in[MLX5_ST_SZ_DW(query_cong_statistics_in)] = {0};
1046 
1047 	MLX5_SET(query_cong_statistics_in, in, opcode,
1048 		 MLX5_CMD_OP_QUERY_CONG_STATISTICS);
1049 	MLX5_SET(query_cong_statistics_in, in, clear, clear);
1050 
1051 	return mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size);
1052 }
1053 
1054 int mlx5_set_diagnostic_params(struct mlx5_core_dev *mdev, void *in,
1055 			       int in_size)
1056 {
1057 	u32 out[MLX5_ST_SZ_DW(set_diagnostic_params_out)] = {0};
1058 
1059 	MLX5_SET(set_diagnostic_params_in, in, opcode,
1060 		 MLX5_CMD_OP_SET_DIAGNOSTICS);
1061 
1062 	return mlx5_cmd_exec(mdev, in, in_size, out, sizeof(out));
1063 }
1064 
1065 int mlx5_query_diagnostic_counters(struct mlx5_core_dev *mdev,
1066 				   u8 num_of_samples, u16 sample_index,
1067 				   void *out, int out_size)
1068 {
1069 	u32 in[MLX5_ST_SZ_DW(query_diagnostic_counters_in)] = {0};
1070 
1071 	MLX5_SET(query_diagnostic_counters_in, in, opcode,
1072 		 MLX5_CMD_OP_QUERY_DIAGNOSTICS);
1073 	MLX5_SET(query_diagnostic_counters_in, in, num_of_samples,
1074 		 num_of_samples);
1075 	MLX5_SET(query_diagnostic_counters_in, in, sample_index, sample_index);
1076 
1077 	return mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size);
1078 }
1079 
1080 int mlx5_set_trust_state(struct mlx5_core_dev *mdev, u8 trust_state)
1081 {
1082 	u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {};
1083 	u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {};
1084 	int err;
1085 
1086 	MLX5_SET(qpts_reg, in, local_port, 1);
1087 	MLX5_SET(qpts_reg, in, trust_state, trust_state);
1088 
1089 	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
1090 				   sizeof(out), MLX5_REG_QPTS, 0, 1);
1091 	return err;
1092 }
1093 
1094 int mlx5_query_trust_state(struct mlx5_core_dev *mdev, u8 *trust_state)
1095 {
1096 	u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {};
1097 	u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {};
1098 	int err;
1099 
1100 	MLX5_SET(qpts_reg, in, local_port, 1);
1101 
1102 	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
1103 				   sizeof(out), MLX5_REG_QPTS, 0, 0);
1104 	if (!err)
1105 		*trust_state = MLX5_GET(qpts_reg, out, trust_state);
1106 
1107 	return err;
1108 }
1109 
1110 int mlx5_set_dscp2prio(struct mlx5_core_dev *mdev, const u8 *dscp2prio)
1111 {
1112 	int sz = MLX5_ST_SZ_BYTES(qpdpm_reg);
1113 	void *qpdpm_dscp;
1114 	void *out;
1115 	void *in;
1116 	int err;
1117 	int i;
1118 
1119 	in = kzalloc(sz, GFP_KERNEL);
1120 	out = kzalloc(sz, GFP_KERNEL);
1121 	if (!in || !out) {
1122 		err = -ENOMEM;
1123 		goto out;
1124 	}
1125 
1126 	MLX5_SET(qpdpm_reg, in, local_port, 1);
1127 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0);
1128 	if (err)
1129 		goto out;
1130 
1131 	memcpy(in, out, sz);
1132 	MLX5_SET(qpdpm_reg, in, local_port, 1);
1133 
1134 	/* Update the corresponding dscp entry */
1135 	for (i = 0; i < MLX5_MAX_SUPPORTED_DSCP; i++) {
1136 		qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, in, dscp[i]);
1137 		MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, prio, dscp2prio[i]);
1138 		MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, e, 1);
1139 	}
1140 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 1);
1141 out:
1142 	kfree(in);
1143 	kfree(out);
1144 	return err;
1145 }
1146 
1147 int mlx5_query_dscp2prio(struct mlx5_core_dev *mdev, u8 *dscp2prio)
1148 {
1149 	int sz = MLX5_ST_SZ_BYTES(qpdpm_reg);
1150 	void *qpdpm_dscp;
1151 	void *out;
1152 	void *in;
1153 	int err;
1154 	int i;
1155 
1156 	in = kzalloc(sz, GFP_KERNEL);
1157 	out = kzalloc(sz, GFP_KERNEL);
1158 	if (!in || !out) {
1159 		err = -ENOMEM;
1160 		goto out;
1161 	}
1162 
1163 	MLX5_SET(qpdpm_reg, in, local_port, 1);
1164 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0);
1165 	if (err)
1166 		goto out;
1167 
1168 	for (i = 0; i < MLX5_MAX_SUPPORTED_DSCP; i++) {
1169 		qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, out, dscp[i]);
1170 		dscp2prio[i] = MLX5_GET16(qpdpm_dscp_reg, qpdpm_dscp, prio);
1171 	}
1172 out:
1173 	kfree(in);
1174 	kfree(out);
1175 	return err;
1176 }
1177 
1178 int mlx5_query_pddr_range_info(struct mlx5_core_dev *mdev, u8 local_port, u8 *is_er_type)
1179 {
1180 	u32 pddr_reg[MLX5_ST_SZ_DW(pddr_reg)] = {};
1181 	int sz = MLX5_ST_SZ_BYTES(pddr_reg);
1182 	int error;
1183 	u8 ecc;
1184 	u8 ci;
1185 
1186 	MLX5_SET(pddr_reg, pddr_reg, local_port, local_port);
1187 	MLX5_SET(pddr_reg, pddr_reg, page_select, 3 /* module info page */);
1188 
1189 	error = mlx5_core_access_reg(mdev, pddr_reg, sz, pddr_reg, sz,
1190 	    MLX5_ACCESS_REG_SUMMARY_CTRL_ID_PDDR, 0, 0);
1191 	if (error != 0)
1192 		return (error);
1193 
1194 	ecc = MLX5_GET(pddr_reg, pddr_reg, page_data.pddr_module_info.ethernet_compliance_code);
1195 	ci = MLX5_GET(pddr_reg, pddr_reg, page_data.pddr_module_info.cable_identifier);
1196 
1197 	switch (ci) {
1198 	case 0:	/* QSFP28 */
1199 	case 1:	/* QSFP+ */
1200 		*is_er_type = 0;
1201 		break;
1202 	case 2:	/* SFP28/SFP+ */
1203 	case 3: /* QSA (QSFP->SFP) */
1204 		*is_er_type = ((ecc & (1 << 7)) != 0);
1205 		break;
1206 	default:
1207 		*is_er_type = 0;
1208 		break;
1209 	}
1210 	return (0);
1211 }
1212 EXPORT_SYMBOL_GPL(mlx5_query_pddr_range_info);
1213 
1214 int
1215 mlx5_query_mfrl_reg(struct mlx5_core_dev *mdev, u8 *reset_level)
1216 {
1217 	u32 mfrl[MLX5_ST_SZ_DW(mfrl_reg)] = {};
1218 	int sz = MLX5_ST_SZ_BYTES(mfrl_reg);
1219 	int err;
1220 
1221 	err = mlx5_core_access_reg(mdev, mfrl, sz, mfrl, sz, MLX5_REG_MFRL,
1222 	    0, 0);
1223 	if (err == 0)
1224 		*reset_level = MLX5_GET(mfrl_reg, mfrl, reset_level);
1225 	return (err);
1226 }
1227 
1228 int
1229 mlx5_set_mfrl_reg(struct mlx5_core_dev *mdev, u8 reset_level)
1230 {
1231 	u32 mfrl[MLX5_ST_SZ_DW(mfrl_reg)] = {};
1232 	int sz = MLX5_ST_SZ_BYTES(mfrl_reg);
1233 
1234 	MLX5_SET(mfrl_reg, mfrl, reset_level, reset_level);
1235 
1236 	return (mlx5_core_access_reg(mdev, mfrl, sz, mfrl, sz, MLX5_REG_MFRL,
1237 	    0, 1));
1238 }
1239 
1240 /* speed in units of 1Mb */
1241 static const u32 mlx5e_link_speed[/*MLX5E_LINK_MODES_NUMBER*/] = {
1242 	[MLX5E_1000BASE_CX_SGMII] = 1000,
1243 	[MLX5E_1000BASE_KX]       = 1000,
1244 	[MLX5E_10GBASE_CX4]       = 10000,
1245 	[MLX5E_10GBASE_KX4]       = 10000,
1246 	[MLX5E_10GBASE_KR]        = 10000,
1247 	[MLX5E_20GBASE_KR2]       = 20000,
1248 	[MLX5E_40GBASE_CR4]       = 40000,
1249 	[MLX5E_40GBASE_KR4]       = 40000,
1250 	[MLX5E_56GBASE_R4]        = 56000,
1251 	[MLX5E_10GBASE_CR]        = 10000,
1252 	[MLX5E_10GBASE_SR]        = 10000,
1253 	[MLX5E_10GBASE_ER_LR]     = 10000,
1254 	[MLX5E_40GBASE_SR4]       = 40000,
1255 	[MLX5E_40GBASE_LR4_ER4]   = 40000,
1256 	[MLX5E_50GBASE_SR2]       = 50000,
1257 	[MLX5E_100GBASE_CR4]      = 100000,
1258 	[MLX5E_100GBASE_SR4]      = 100000,
1259 	[MLX5E_100GBASE_KR4]      = 100000,
1260 	[MLX5E_100GBASE_LR4]      = 100000,
1261 	[MLX5E_100BASE_TX]        = 100,
1262 	[MLX5E_1000BASE_T]        = 1000,
1263 	[MLX5E_10GBASE_T]         = 10000,
1264 	[MLX5E_25GBASE_CR]        = 25000,
1265 	[MLX5E_25GBASE_KR]        = 25000,
1266 	[MLX5E_25GBASE_SR]        = 25000,
1267 	[MLX5E_50GBASE_CR2]       = 50000,
1268 	[MLX5E_50GBASE_KR2]       = 50000,
1269 };
1270 
1271 static const u32 mlx5e_ext_link_speed[/*MLX5E_EXT_LINK_MODES_NUMBER*/] = {
1272 	[MLX5E_SGMII_100M]			= 100,
1273 	[MLX5E_1000BASE_X_SGMII]		= 1000,
1274 	[MLX5E_5GBASE_R]			= 5000,
1275 	[MLX5E_10GBASE_XFI_XAUI_1]		= 10000,
1276 	[MLX5E_40GBASE_XLAUI_4_XLPPI_4]		= 40000,
1277 	[MLX5E_25GAUI_1_25GBASE_CR_KR]		= 25000,
1278 	[MLX5E_50GAUI_2_LAUI_2_50GBASE_CR2_KR2]	= 50000,
1279 	[MLX5E_50GAUI_1_LAUI_1_50GBASE_CR_KR]	= 50000,
1280 	[MLX5E_CAUI_4_100GBASE_CR4_KR4]		= 100000,
1281 	[MLX5E_200GAUI_4_200GBASE_CR4_KR4]	= 200000,
1282 	[MLX5E_400GAUI_8]			= 400000,
1283 };
1284 
1285 static void mlx5e_port_get_speed_arr(struct mlx5_core_dev *mdev,
1286 				     const u32 **arr, u32 *size)
1287 {
1288 	bool ext = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet);
1289 
1290 	*size = ext ? ARRAY_SIZE(mlx5e_ext_link_speed) :
1291 		      ARRAY_SIZE(mlx5e_link_speed);
1292 	*arr  = ext ? mlx5e_ext_link_speed : mlx5e_link_speed;
1293 }
1294 
1295 u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper)
1296 {
1297 	unsigned long temp = eth_proto_oper;
1298 	const u32 *table;
1299 	u32 speed = 0;
1300 	u32 max_size;
1301 	int i;
1302 
1303 	mlx5e_port_get_speed_arr(mdev, &table, &max_size);
1304 	i = find_first_bit(&temp, max_size);
1305 	if (i < max_size)
1306 		speed = table[i];
1307 	return speed;
1308 }
1309 
1310 int mlx5_port_query_eth_proto(struct mlx5_core_dev *dev, u8 port, bool ext,
1311 			      struct mlx5e_port_eth_proto *eproto)
1312 {
1313 	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
1314 	int err;
1315 
1316 	if (!eproto)
1317 		return -EINVAL;
1318 
1319 	err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, port);
1320 	if (err)
1321 		return err;
1322 
1323 	eproto->cap   = MLX5_GET_ETH_PROTO(ptys_reg, out, ext,
1324 					   eth_proto_capability);
1325 	eproto->admin = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_admin);
1326 	eproto->oper  = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_oper);
1327 	return 0;
1328 }
1329 
1330 int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
1331 {
1332 	struct mlx5e_port_eth_proto eproto;
1333 	bool ext;
1334 	int err;
1335 
1336 	ext = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet);
1337 	err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto);
1338 	if (err)
1339 		goto out;
1340 
1341 	*speed = mlx5e_port_ptys2speed(mdev, eproto.oper);
1342 	if (!(*speed))
1343 		err = -EINVAL;
1344 
1345 out:
1346 	return err;
1347 }
1348 
1349 int mlx5e_port_query_pbmc(struct mlx5_core_dev *mdev, void *out)
1350 {
1351 	int sz = MLX5_ST_SZ_BYTES(pbmc_reg);
1352 	void *in;
1353 	int err;
1354 
1355 	in = kzalloc(sz, GFP_KERNEL);
1356 	if (!in)
1357 		return -ENOMEM;
1358 
1359 	MLX5_SET(pbmc_reg, in, local_port, 1);
1360 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 0);
1361 
1362 	kfree(in);
1363 	return err;
1364 }
1365 
1366 int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in)
1367 {
1368 	int sz = MLX5_ST_SZ_BYTES(pbmc_reg);
1369 	void *out;
1370 	int err;
1371 
1372 	out = kzalloc(sz, GFP_KERNEL);
1373 	if (!out)
1374 		return -ENOMEM;
1375 
1376 	MLX5_SET(pbmc_reg, in, local_port, 1);
1377 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 1);
1378 
1379 	kfree(out);
1380 	return err;
1381 }
1382 
1383 /* buffer[i]: buffer that priority i mapped to */
1384 int mlx5e_port_query_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer)
1385 {
1386 	int sz = MLX5_ST_SZ_BYTES(pptb_reg);
1387 	u32 prio_x_buff;
1388 	void *out;
1389 	void *in;
1390 	int prio;
1391 	int err;
1392 
1393 	in = kzalloc(sz, GFP_KERNEL);
1394 	out = kzalloc(sz, GFP_KERNEL);
1395 	if (!in || !out) {
1396 		err = -ENOMEM;
1397 		goto out;
1398 	}
1399 
1400 	MLX5_SET(pptb_reg, in, local_port, 1);
1401 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0);
1402 	if (err)
1403 		goto out;
1404 
1405 	prio_x_buff = MLX5_GET(pptb_reg, out, prio_x_buff);
1406 	for (prio = 0; prio < 8; prio++) {
1407 		buffer[prio] = (u8)(prio_x_buff >> (4 * prio)) & 0xF;
1408 		mlx5_core_dbg(mdev, "prio %d, buffer %d\n", prio, buffer[prio]);
1409 	}
1410 out:
1411 	kfree(in);
1412 	kfree(out);
1413 	return err;
1414 }
1415 
1416 int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer)
1417 {
1418 	int sz = MLX5_ST_SZ_BYTES(pptb_reg);
1419 	u32 prio_x_buff;
1420 	void *out;
1421 	void *in;
1422 	int prio;
1423 	int err;
1424 
1425 	in = kzalloc(sz, GFP_KERNEL);
1426 	out = kzalloc(sz, GFP_KERNEL);
1427 	if (!in || !out) {
1428 		err = -ENOMEM;
1429 		goto out;
1430 	}
1431 
1432 	/* First query the pptb register */
1433 	MLX5_SET(pptb_reg, in, local_port, 1);
1434 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0);
1435 	if (err)
1436 		goto out;
1437 
1438 	memcpy(in, out, sz);
1439 	MLX5_SET(pptb_reg, in, local_port, 1);
1440 
1441 	/* Update the pm and prio_x_buff */
1442 	MLX5_SET(pptb_reg, in, pm, 0xFF);
1443 
1444 	prio_x_buff = 0;
1445 	for (prio = 0; prio < 8; prio++)
1446 		prio_x_buff |= (buffer[prio] << (4 * prio));
1447 	MLX5_SET(pptb_reg, in, prio_x_buff, prio_x_buff);
1448 
1449 	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 1);
1450 
1451 out:
1452 	kfree(in);
1453 	kfree(out);
1454 	return err;
1455 }
1456