mlx5_port.c revision 365411
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: stable/11/sys/dev/mlx5/mlx5_core/mlx5_port.c 365411 2020-09-07 10:50:17Z kib $
26 */
27
28#include <linux/module.h>
29#include <dev/mlx5/port.h>
30#include "mlx5_core.h"
31
32int 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
62out:
63	kvfree(out);
64	kvfree(in);
65	return err;
66}
67EXPORT_SYMBOL_GPL(mlx5_core_access_reg);
68
69int 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}
80EXPORT_SYMBOL_GPL(mlx5_query_qcam_reg);
81
82int 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
94int 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
106struct 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 */
117void 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}
126EXPORT_SYMBOL_GPL(mlx5_toggle_port_link);
127
128int 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}
143EXPORT_SYMBOL_GPL(mlx5_set_port_caps);
144
145int 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}
160EXPORT_SYMBOL_GPL(mlx5_query_port_ptys);
161
162int 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}
179EXPORT_SYMBOL_GPL(mlx5_query_port_proto_cap);
180
181int 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}
196EXPORT_SYMBOL_GPL(mlx5_query_port_autoneg);
197
198int 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}
224EXPORT_SYMBOL_GPL(mlx5_set_port_autoneg);
225
226int 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}
243EXPORT_SYMBOL_GPL(mlx5_query_port_proto_admin);
244
245int 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}
260EXPORT_SYMBOL(mlx5_query_port_eth_proto_oper);
261
262int 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}
284EXPORT_SYMBOL_GPL(mlx5_set_port_proto);
285
286int 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
303int 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
320int 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}
335EXPORT_SYMBOL_GPL(mlx5_query_port_admin_status);
336
337static 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
361int 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}
372EXPORT_SYMBOL_GPL(mlx5_set_port_mtu);
373
374int 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}
378EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu);
379
380int 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
405int 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
425int 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}
443EXPORT_SYMBOL_GPL(mlx5_query_port_pfc);
444
445int 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}
449EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu);
450
451u8 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}
472EXPORT_SYMBOL_GPL(mlx5_is_wol_supported);
473
474int 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}
485EXPORT_SYMBOL_GPL(mlx5_set_wol);
486
487int 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}
505EXPORT_SYMBOL_GPL(mlx5_query_dropless_mode);
506
507int 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}
518EXPORT_SYMBOL_GPL(mlx5_set_dropless_mode);
519
520int 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}
546EXPORT_SYMBOL_GPL(mlx5_core_access_pvlc);
547
548int 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
614out:
615	kvfree(in);
616	kvfree(out);
617	return err;
618}
619EXPORT_SYMBOL_GPL(mlx5_core_access_ptys);
620
621static 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
635int 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
672out:
673	kvfree(in);
674	kvfree(out);
675	return err;
676}
677EXPORT_SYMBOL_GPL(mlx5_core_access_pmtu);
678
679int 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}
698EXPORT_SYMBOL_GPL(mlx5_query_module_num);
699
700int 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}
732EXPORT_SYMBOL_GPL(mlx5_query_eeprom);
733
734int 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
754int 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
774int 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}
789EXPORT_SYMBOL_GPL(mlx5_query_wol);
790
791int 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
811int 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
826int 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
838static 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
851int 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}
857EXPORT_SYMBOL_GPL(mlx5_max_tc);
858
859static 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
871int 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}
895EXPORT_SYMBOL_GPL(mlx5_query_port_tc_rate_limit);
896
897int 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}
919EXPORT_SYMBOL_GPL(mlx5_modify_port_tc_rate_limit);
920
921int 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}
941EXPORT_SYMBOL_GPL(mlx5_query_port_prio_tc);
942
943int 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}
961EXPORT_SYMBOL_GPL(mlx5_set_port_prio_tc);
962
963int 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}
975EXPORT_SYMBOL_GPL(mlx5_set_port_tc_group);
976
977int 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}
996EXPORT_SYMBOL_GPL(mlx5_query_port_tc_group);
997
998int 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}
1010EXPORT_SYMBOL_GPL(mlx5_set_port_tc_bw_alloc);
1011
1012int 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}
1029EXPORT_SYMBOL_GPL(mlx5_query_port_tc_bw_alloc);
1030
1031int 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
1042int 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
1054int 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
1065int 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
1080int 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
1094int 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
1110int 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);
1141out:
1142	kfree(in);
1143	kfree(out);
1144	return err;
1145}
1146
1147int 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	}
1172out:
1173	kfree(in);
1174	kfree(out);
1175	return err;
1176}
1177
1178static int mlx5_query_pddr(struct mlx5_core_dev *mdev,
1179    u8 local_port, int page_select, u32 *out, int outlen)
1180{
1181	u32 in[MLX5_ST_SZ_DW(pddr_reg)] = {0};
1182
1183	if (!MLX5_CAP_PCAM_REG(mdev, pddr))
1184		return -EOPNOTSUPP;
1185
1186	MLX5_SET(pddr_reg, in, local_port, local_port);
1187	MLX5_SET(pddr_reg, in, page_select, page_select);
1188
1189	return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen, MLX5_REG_PDDR, 0, 0);
1190}
1191
1192int mlx5_query_pddr_range_info(struct mlx5_core_dev *mdev, u8 local_port, u8 *is_er_type)
1193{
1194	u32 pddr_reg[MLX5_ST_SZ_DW(pddr_reg)] = {};
1195	int error;
1196	u8 ecc;
1197	u8 ci;
1198
1199	error = mlx5_query_pddr(mdev, local_port, MLX5_PDDR_MODULE_INFO_PAGE,
1200	    pddr_reg, sizeof(pddr_reg));
1201	if (error != 0)
1202		return (error);
1203
1204	ecc = MLX5_GET(pddr_reg, pddr_reg, page_data.pddr_module_info.ethernet_compliance_code);
1205	ci = MLX5_GET(pddr_reg, pddr_reg, page_data.pddr_module_info.cable_identifier);
1206
1207	switch (ci) {
1208	case 0:	/* QSFP28 */
1209	case 1:	/* QSFP+ */
1210		*is_er_type = 0;
1211		break;
1212	case 2:	/* SFP28/SFP+ */
1213	case 3: /* QSA (QSFP->SFP) */
1214		*is_er_type = ((ecc & (1 << 7)) != 0);
1215		break;
1216	default:
1217		*is_er_type = 0;
1218		break;
1219	}
1220	return (0);
1221}
1222EXPORT_SYMBOL_GPL(mlx5_query_pddr_range_info);
1223
1224int
1225mlx5_query_mfrl_reg(struct mlx5_core_dev *mdev, u8 *reset_level)
1226{
1227	u32 mfrl[MLX5_ST_SZ_DW(mfrl_reg)] = {};
1228	int sz = MLX5_ST_SZ_BYTES(mfrl_reg);
1229	int err;
1230
1231	err = mlx5_core_access_reg(mdev, mfrl, sz, mfrl, sz, MLX5_REG_MFRL,
1232	    0, 0);
1233	if (err == 0)
1234		*reset_level = MLX5_GET(mfrl_reg, mfrl, reset_level);
1235	return (err);
1236}
1237
1238int
1239mlx5_set_mfrl_reg(struct mlx5_core_dev *mdev, u8 reset_level)
1240{
1241	u32 mfrl[MLX5_ST_SZ_DW(mfrl_reg)] = {};
1242	int sz = MLX5_ST_SZ_BYTES(mfrl_reg);
1243
1244	MLX5_SET(mfrl_reg, mfrl, reset_level, reset_level);
1245
1246	return (mlx5_core_access_reg(mdev, mfrl, sz, mfrl, sz, MLX5_REG_MFRL,
1247	    0, 1));
1248}
1249
1250/* speed in units of 1Mb */
1251static const u32 mlx5e_link_speed[/*MLX5E_LINK_MODES_NUMBER*/] = {
1252	[MLX5E_1000BASE_CX_SGMII] = 1000,
1253	[MLX5E_1000BASE_KX]       = 1000,
1254	[MLX5E_10GBASE_CX4]       = 10000,
1255	[MLX5E_10GBASE_KX4]       = 10000,
1256	[MLX5E_10GBASE_KR]        = 10000,
1257	[MLX5E_20GBASE_KR2]       = 20000,
1258	[MLX5E_40GBASE_CR4]       = 40000,
1259	[MLX5E_40GBASE_KR4]       = 40000,
1260	[MLX5E_56GBASE_R4]        = 56000,
1261	[MLX5E_10GBASE_CR]        = 10000,
1262	[MLX5E_10GBASE_SR]        = 10000,
1263	[MLX5E_10GBASE_ER_LR]     = 10000,
1264	[MLX5E_40GBASE_SR4]       = 40000,
1265	[MLX5E_40GBASE_LR4_ER4]   = 40000,
1266	[MLX5E_50GBASE_SR2]       = 50000,
1267	[MLX5E_100GBASE_CR4]      = 100000,
1268	[MLX5E_100GBASE_SR4]      = 100000,
1269	[MLX5E_100GBASE_KR4]      = 100000,
1270	[MLX5E_100GBASE_LR4]      = 100000,
1271	[MLX5E_100BASE_TX]        = 100,
1272	[MLX5E_1000BASE_T]        = 1000,
1273	[MLX5E_10GBASE_T]         = 10000,
1274	[MLX5E_25GBASE_CR]        = 25000,
1275	[MLX5E_25GBASE_KR]        = 25000,
1276	[MLX5E_25GBASE_SR]        = 25000,
1277	[MLX5E_50GBASE_CR2]       = 50000,
1278	[MLX5E_50GBASE_KR2]       = 50000,
1279};
1280
1281static const u32 mlx5e_ext_link_speed[/*MLX5E_EXT_LINK_MODES_NUMBER*/] = {
1282	[MLX5E_SGMII_100M]			= 100,
1283	[MLX5E_1000BASE_X_SGMII]		= 1000,
1284	[MLX5E_5GBASE_R]			= 5000,
1285	[MLX5E_10GBASE_XFI_XAUI_1]		= 10000,
1286	[MLX5E_40GBASE_XLAUI_4_XLPPI_4]		= 40000,
1287	[MLX5E_25GAUI_1_25GBASE_CR_KR]		= 25000,
1288	[MLX5E_50GAUI_2_LAUI_2_50GBASE_CR2_KR2]	= 50000,
1289	[MLX5E_50GAUI_1_LAUI_1_50GBASE_CR_KR]	= 50000,
1290	[MLX5E_CAUI_4_100GBASE_CR4_KR4]		= 100000,
1291	[MLX5E_200GAUI_4_200GBASE_CR4_KR4]	= 200000,
1292	[MLX5E_400GAUI_8]			= 400000,
1293};
1294
1295static void mlx5e_port_get_speed_arr(struct mlx5_core_dev *mdev,
1296				     const u32 **arr, u32 *size)
1297{
1298	bool ext = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet);
1299
1300	*size = ext ? ARRAY_SIZE(mlx5e_ext_link_speed) :
1301		      ARRAY_SIZE(mlx5e_link_speed);
1302	*arr  = ext ? mlx5e_ext_link_speed : mlx5e_link_speed;
1303}
1304
1305u32 mlx5e_port_ptys2speed(struct mlx5_core_dev *mdev, u32 eth_proto_oper)
1306{
1307	unsigned long temp = eth_proto_oper;
1308	const u32 *table;
1309	u32 speed = 0;
1310	u32 max_size;
1311	int i;
1312
1313	mlx5e_port_get_speed_arr(mdev, &table, &max_size);
1314	i = find_first_bit(&temp, max_size);
1315	if (i < max_size)
1316		speed = table[i];
1317	return speed;
1318}
1319
1320int mlx5_port_query_eth_proto(struct mlx5_core_dev *dev, u8 port, bool ext,
1321			      struct mlx5e_port_eth_proto *eproto)
1322{
1323	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
1324	int err;
1325
1326	if (!eproto)
1327		return -EINVAL;
1328
1329	err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN, port);
1330	if (err)
1331		return err;
1332
1333	eproto->cap   = MLX5_GET_ETH_PROTO(ptys_reg, out, ext,
1334					   eth_proto_capability);
1335	eproto->admin = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_admin);
1336	eproto->oper  = MLX5_GET_ETH_PROTO(ptys_reg, out, ext, eth_proto_oper);
1337	return 0;
1338}
1339
1340int mlx5e_port_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
1341{
1342	struct mlx5e_port_eth_proto eproto;
1343	bool ext;
1344	int err;
1345
1346	ext = MLX5_CAP_PCAM_FEATURE(mdev, ptys_extended_ethernet);
1347	err = mlx5_port_query_eth_proto(mdev, 1, ext, &eproto);
1348	if (err)
1349		goto out;
1350
1351	*speed = mlx5e_port_ptys2speed(mdev, eproto.oper);
1352	if (!(*speed))
1353		err = -EINVAL;
1354
1355out:
1356	return err;
1357}
1358
1359int mlx5e_port_query_pbmc(struct mlx5_core_dev *mdev, void *out)
1360{
1361	int sz = MLX5_ST_SZ_BYTES(pbmc_reg);
1362	void *in;
1363	int err;
1364
1365	in = kzalloc(sz, GFP_KERNEL);
1366	if (!in)
1367		return -ENOMEM;
1368
1369	MLX5_SET(pbmc_reg, in, local_port, 1);
1370	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 0);
1371
1372	kfree(in);
1373	return err;
1374}
1375
1376int mlx5e_port_set_pbmc(struct mlx5_core_dev *mdev, void *in)
1377{
1378	int sz = MLX5_ST_SZ_BYTES(pbmc_reg);
1379	void *out;
1380	int err;
1381
1382	out = kzalloc(sz, GFP_KERNEL);
1383	if (!out)
1384		return -ENOMEM;
1385
1386	MLX5_SET(pbmc_reg, in, local_port, 1);
1387	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PBMC, 0, 1);
1388
1389	kfree(out);
1390	return err;
1391}
1392
1393/* buffer[i]: buffer that priority i mapped to */
1394int mlx5e_port_query_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer)
1395{
1396	int sz = MLX5_ST_SZ_BYTES(pptb_reg);
1397	u32 prio_x_buff;
1398	void *out;
1399	void *in;
1400	int prio;
1401	int err;
1402
1403	in = kzalloc(sz, GFP_KERNEL);
1404	out = kzalloc(sz, GFP_KERNEL);
1405	if (!in || !out) {
1406		err = -ENOMEM;
1407		goto out;
1408	}
1409
1410	MLX5_SET(pptb_reg, in, local_port, 1);
1411	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0);
1412	if (err)
1413		goto out;
1414
1415	prio_x_buff = MLX5_GET(pptb_reg, out, prio_x_buff);
1416	for (prio = 0; prio < 8; prio++) {
1417		buffer[prio] = (u8)(prio_x_buff >> (4 * prio)) & 0xF;
1418		mlx5_core_dbg(mdev, "prio %d, buffer %d\n", prio, buffer[prio]);
1419	}
1420out:
1421	kfree(in);
1422	kfree(out);
1423	return err;
1424}
1425
1426int mlx5e_port_set_priority2buffer(struct mlx5_core_dev *mdev, u8 *buffer)
1427{
1428	int sz = MLX5_ST_SZ_BYTES(pptb_reg);
1429	u32 prio_x_buff;
1430	void *out;
1431	void *in;
1432	int prio;
1433	int err;
1434
1435	in = kzalloc(sz, GFP_KERNEL);
1436	out = kzalloc(sz, GFP_KERNEL);
1437	if (!in || !out) {
1438		err = -ENOMEM;
1439		goto out;
1440	}
1441
1442	/* First query the pptb register */
1443	MLX5_SET(pptb_reg, in, local_port, 1);
1444	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 0);
1445	if (err)
1446		goto out;
1447
1448	memcpy(in, out, sz);
1449	MLX5_SET(pptb_reg, in, local_port, 1);
1450
1451	/* Update the pm and prio_x_buff */
1452	MLX5_SET(pptb_reg, in, pm, 0xFF);
1453
1454	prio_x_buff = 0;
1455	for (prio = 0; prio < 8; prio++)
1456		prio_x_buff |= (buffer[prio] << (4 * prio));
1457	MLX5_SET(pptb_reg, in, prio_x_buff, prio_x_buff);
1458
1459	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPTB, 0, 1);
1460
1461out:
1462	kfree(in);
1463	kfree(out);
1464	return err;
1465}
1466