mlx5_port.c revision 347821
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 347821 2019-05-16 17:30:20Z hselasky $
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)
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		MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin);
273	else
274		MLX5_SET(ptys_reg, in, ib_proto_admin, proto_admin);
275
276	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
277				   sizeof(out), MLX5_REG_PTYS, 0, 1);
278	return err;
279}
280EXPORT_SYMBOL_GPL(mlx5_set_port_proto);
281
282int mlx5_set_port_status(struct mlx5_core_dev *dev,
283			 enum mlx5_port_status status)
284{
285	u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0};
286	u32 out[MLX5_ST_SZ_DW(paos_reg)] = {0};
287	int err;
288
289	MLX5_SET(paos_reg, in, local_port, 1);
290
291	MLX5_SET(paos_reg, in, admin_status, status);
292	MLX5_SET(paos_reg, in, ase, 1);
293
294	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
295				   sizeof(out), MLX5_REG_PAOS, 0, 1);
296	return err;
297}
298
299int mlx5_query_port_status(struct mlx5_core_dev *dev, u8 *status)
300{
301	u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0};
302	u32 out[MLX5_ST_SZ_DW(paos_reg)] = {0};
303	int err;
304
305	MLX5_SET(paos_reg, in, local_port, 1);
306
307	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
308				   sizeof(out), MLX5_REG_PAOS, 0, 0);
309	if (err)
310		return err;
311
312	*status = MLX5_GET(paos_reg, out, oper_status);
313	return err;
314}
315
316int mlx5_query_port_admin_status(struct mlx5_core_dev *dev,
317				 enum mlx5_port_status *status)
318{
319	u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0};
320	u32 out[MLX5_ST_SZ_DW(paos_reg)];
321	int err;
322
323	MLX5_SET(paos_reg, in, local_port, 1);
324	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
325				   sizeof(out), MLX5_REG_PAOS, 0, 0);
326	if (err)
327		return err;
328	*status = MLX5_GET(paos_reg, out, admin_status);
329	return 0;
330}
331EXPORT_SYMBOL_GPL(mlx5_query_port_admin_status);
332
333static int mlx5_query_port_mtu(struct mlx5_core_dev *dev,
334			       int *admin_mtu, int *max_mtu, int *oper_mtu)
335{
336	u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
337	u32 out[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
338	int err;
339
340	MLX5_SET(pmtu_reg, in, local_port, 1);
341
342	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
343				   sizeof(out), MLX5_REG_PMTU, 0, 0);
344	if (err)
345		return err;
346
347	if (max_mtu)
348		*max_mtu  = MLX5_GET(pmtu_reg, out, max_mtu);
349	if (oper_mtu)
350		*oper_mtu = MLX5_GET(pmtu_reg, out, oper_mtu);
351	if (admin_mtu)
352		*admin_mtu = MLX5_GET(pmtu_reg, out, admin_mtu);
353
354	return err;
355}
356
357int mlx5_set_port_mtu(struct mlx5_core_dev *dev, int mtu)
358{
359	u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
360	u32 out[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
361
362	MLX5_SET(pmtu_reg, in, admin_mtu, mtu);
363	MLX5_SET(pmtu_reg, in, local_port, 1);
364
365	return mlx5_core_access_reg(dev, in, sizeof(in), out,
366				   sizeof(out), MLX5_REG_PMTU, 0, 1);
367}
368EXPORT_SYMBOL_GPL(mlx5_set_port_mtu);
369
370int mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, int *max_mtu)
371{
372	return mlx5_query_port_mtu(dev, NULL, max_mtu, NULL);
373}
374EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu);
375
376int mlx5_set_port_pause_and_pfc(struct mlx5_core_dev *dev, u32 port,
377				u8 rx_pause, u8 tx_pause,
378				u8 pfc_en_rx, u8 pfc_en_tx)
379{
380	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
381	u32 out[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
382
383	if (pfc_en_rx || pfc_en_tx) {
384		/* PFC and global pauseframes are incompatible features */
385		if (tx_pause || rx_pause)
386			return -EINVAL;
387	}
388
389	MLX5_SET(pfcc_reg, in, local_port, port);
390	MLX5_SET(pfcc_reg, in, pptx, tx_pause);
391	MLX5_SET(pfcc_reg, in, pprx, rx_pause);
392	MLX5_SET(pfcc_reg, in, pfctx, pfc_en_tx);
393	MLX5_SET(pfcc_reg, in, pfcrx, pfc_en_rx);
394	MLX5_SET(pfcc_reg, in, prio_mask_tx, pfc_en_tx);
395	MLX5_SET(pfcc_reg, in, prio_mask_rx, pfc_en_rx);
396
397	return mlx5_core_access_reg(dev, in, sizeof(in), out,
398				   sizeof(out), MLX5_REG_PFCC, 0, 1);
399}
400
401int mlx5_query_port_pause(struct mlx5_core_dev *dev, u32 port,
402			  u32 *rx_pause, u32 *tx_pause)
403{
404	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
405	u32 out[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
406	int err;
407
408	MLX5_SET(pfcc_reg, in, local_port, port);
409
410	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
411				   sizeof(out), MLX5_REG_PFCC, 0, 0);
412	if (err)
413		return err;
414
415	*rx_pause = MLX5_GET(pfcc_reg, out, pprx);
416	*tx_pause = MLX5_GET(pfcc_reg, out, pptx);
417
418	return 0;
419}
420
421int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx, u8 *pfc_en_rx)
422{
423	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {};
424	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
425	int err;
426
427	MLX5_SET(pfcc_reg, in, local_port, 1);
428	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
429				   sizeof(out), MLX5_REG_PFCC, 0, 0);
430	if (err)
431		return err;
432
433	if (pfc_en_tx != NULL)
434		*pfc_en_tx = MLX5_GET(pfcc_reg, out, pfctx);
435	if (pfc_en_rx != NULL)
436		*pfc_en_rx = MLX5_GET(pfcc_reg, out, pfcrx);
437	return 0;
438}
439EXPORT_SYMBOL_GPL(mlx5_query_port_pfc);
440
441int mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, int *oper_mtu)
442{
443	return mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu);
444}
445EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu);
446
447u8 mlx5_is_wol_supported(struct mlx5_core_dev *dev)
448{
449	u8 wol_supported = 0;
450
451	if (MLX5_CAP_GEN(dev, wol_s))
452		wol_supported |= MLX5_WOL_SECURED_MAGIC;
453	if (MLX5_CAP_GEN(dev, wol_g))
454		wol_supported |= MLX5_WOL_MAGIC;
455	if (MLX5_CAP_GEN(dev, wol_a))
456		wol_supported |= MLX5_WOL_ARP;
457	if (MLX5_CAP_GEN(dev, wol_b))
458		wol_supported |= MLX5_WOL_BROADCAST;
459	if (MLX5_CAP_GEN(dev, wol_m))
460		wol_supported |= MLX5_WOL_MULTICAST;
461	if (MLX5_CAP_GEN(dev, wol_u))
462		wol_supported |= MLX5_WOL_UNICAST;
463	if (MLX5_CAP_GEN(dev, wol_p))
464		wol_supported |= MLX5_WOL_PHY_ACTIVITY;
465
466	return wol_supported;
467}
468EXPORT_SYMBOL_GPL(mlx5_is_wol_supported);
469
470int mlx5_set_wol(struct mlx5_core_dev *dev, u8 wol_mode)
471{
472	u32 in[MLX5_ST_SZ_DW(set_wol_rol_in)] = {0};
473	u32 out[MLX5_ST_SZ_DW(set_wol_rol_out)] = {0};
474
475	MLX5_SET(set_wol_rol_in, in, opcode, MLX5_CMD_OP_SET_WOL_ROL);
476	MLX5_SET(set_wol_rol_in, in, wol_mode_valid, 1);
477	MLX5_SET(set_wol_rol_in, in, wol_mode, wol_mode);
478
479	return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
480}
481EXPORT_SYMBOL_GPL(mlx5_set_wol);
482
483int mlx5_query_dropless_mode(struct mlx5_core_dev *dev, u16 *timeout)
484{
485	u32 in[MLX5_ST_SZ_DW(query_delay_drop_params_in)] = {0};
486	u32 out[MLX5_ST_SZ_DW(query_delay_drop_params_out)] = {0};
487	int err = 0;
488
489	MLX5_SET(query_delay_drop_params_in, in, opcode,
490		 MLX5_CMD_OP_QUERY_DELAY_DROP_PARAMS);
491
492	err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
493	if (err)
494		return err;
495
496	*timeout = MLX5_GET(query_delay_drop_params_out, out,
497			    delay_drop_timeout);
498
499	return 0;
500}
501EXPORT_SYMBOL_GPL(mlx5_query_dropless_mode);
502
503int mlx5_set_dropless_mode(struct mlx5_core_dev *dev, u16 timeout)
504{
505	u32 in[MLX5_ST_SZ_DW(set_delay_drop_params_in)] = {0};
506	u32 out[MLX5_ST_SZ_DW(set_delay_drop_params_out)] = {0};
507
508	MLX5_SET(set_delay_drop_params_in, in, opcode,
509		 MLX5_CMD_OP_SET_DELAY_DROP_PARAMS);
510	MLX5_SET(set_delay_drop_params_in, in, delay_drop_timeout, timeout);
511
512	return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
513}
514EXPORT_SYMBOL_GPL(mlx5_set_dropless_mode);
515
516int mlx5_core_access_pvlc(struct mlx5_core_dev *dev,
517			  struct mlx5_pvlc_reg *pvlc, int write)
518{
519	int sz = MLX5_ST_SZ_BYTES(pvlc_reg);
520	u8 in[MLX5_ST_SZ_BYTES(pvlc_reg)] = {0};
521	u8 out[MLX5_ST_SZ_BYTES(pvlc_reg)] = {0};
522	int err;
523
524	MLX5_SET(pvlc_reg, in, local_port, pvlc->local_port);
525	if (write)
526		MLX5_SET(pvlc_reg, in, vl_admin, pvlc->vl_admin);
527
528	err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PVLC, 0,
529				   !!write);
530	if (err)
531		return err;
532
533	if (!write) {
534		pvlc->local_port = MLX5_GET(pvlc_reg, out, local_port);
535		pvlc->vl_hw_cap = MLX5_GET(pvlc_reg, out, vl_hw_cap);
536		pvlc->vl_admin = MLX5_GET(pvlc_reg, out, vl_admin);
537		pvlc->vl_operational = MLX5_GET(pvlc_reg, out, vl_operational);
538	}
539
540	return 0;
541}
542EXPORT_SYMBOL_GPL(mlx5_core_access_pvlc);
543
544int mlx5_core_access_ptys(struct mlx5_core_dev *dev,
545			  struct mlx5_ptys_reg *ptys, int write)
546{
547	int sz = MLX5_ST_SZ_BYTES(ptys_reg);
548	void *out = NULL;
549	void *in = NULL;
550	int err;
551
552	in = mlx5_vzalloc(sz);
553	if (!in)
554		return -ENOMEM;
555
556	out = mlx5_vzalloc(sz);
557	if (!out) {
558		kfree(in);
559		return -ENOMEM;
560	}
561
562	MLX5_SET(ptys_reg, in, local_port, ptys->local_port);
563	MLX5_SET(ptys_reg, in, proto_mask, ptys->proto_mask);
564	if (write) {
565		MLX5_SET(ptys_reg, in, eth_proto_capability,
566			 ptys->eth_proto_cap);
567		MLX5_SET(ptys_reg, in, ib_link_width_capability,
568			 ptys->ib_link_width_cap);
569		MLX5_SET(ptys_reg, in, ib_proto_capability,
570			 ptys->ib_proto_cap);
571		MLX5_SET(ptys_reg, in, eth_proto_admin, ptys->eth_proto_admin);
572		MLX5_SET(ptys_reg, in, ib_link_width_admin,
573			 ptys->ib_link_width_admin);
574		MLX5_SET(ptys_reg, in, ib_proto_admin, ptys->ib_proto_admin);
575		MLX5_SET(ptys_reg, in, eth_proto_oper, ptys->eth_proto_oper);
576		MLX5_SET(ptys_reg, in, ib_link_width_oper,
577			 ptys->ib_link_width_oper);
578		MLX5_SET(ptys_reg, in, ib_proto_oper, ptys->ib_proto_oper);
579		MLX5_SET(ptys_reg, in, eth_proto_lp_advertise,
580			 ptys->eth_proto_lp_advertise);
581	}
582
583	err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PTYS, 0,
584				   !!write);
585	if (err)
586		goto out;
587
588	if (!write) {
589		ptys->local_port = MLX5_GET(ptys_reg, out, local_port);
590		ptys->proto_mask = MLX5_GET(ptys_reg, out, proto_mask);
591		ptys->eth_proto_cap = MLX5_GET(ptys_reg, out,
592					       eth_proto_capability);
593		ptys->ib_link_width_cap = MLX5_GET(ptys_reg, out,
594					   ib_link_width_capability);
595		ptys->ib_proto_cap = MLX5_GET(ptys_reg, out,
596					      ib_proto_capability);
597		ptys->eth_proto_admin = MLX5_GET(ptys_reg, out,
598						 eth_proto_admin);
599		ptys->ib_link_width_admin = MLX5_GET(ptys_reg, out,
600						     ib_link_width_admin);
601		ptys->ib_proto_admin = MLX5_GET(ptys_reg, out, ib_proto_admin);
602		ptys->eth_proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper);
603		ptys->ib_link_width_oper = MLX5_GET(ptys_reg, out,
604						    ib_link_width_oper);
605		ptys->ib_proto_oper = MLX5_GET(ptys_reg, out, ib_proto_oper);
606		ptys->eth_proto_lp_advertise = MLX5_GET(ptys_reg, out,
607							eth_proto_lp_advertise);
608	}
609
610out:
611	kvfree(in);
612	kvfree(out);
613	return err;
614}
615EXPORT_SYMBOL_GPL(mlx5_core_access_ptys);
616
617static int mtu_to_ib_mtu(int mtu)
618{
619	switch (mtu) {
620	case 256: return 1;
621	case 512: return 2;
622	case 1024: return 3;
623	case 2048: return 4;
624	case 4096: return 5;
625	default:
626		printf("mlx5_core: WARN: ""invalid mtu\n");
627		return -1;
628	}
629}
630
631int mlx5_core_access_pmtu(struct mlx5_core_dev *dev,
632			  struct mlx5_pmtu_reg *pmtu, int write)
633{
634	int sz = MLX5_ST_SZ_BYTES(pmtu_reg);
635	void *out = NULL;
636	void *in = NULL;
637	int err;
638
639	in = mlx5_vzalloc(sz);
640	if (!in)
641		return -ENOMEM;
642
643	out = mlx5_vzalloc(sz);
644	if (!out) {
645		kfree(in);
646		return -ENOMEM;
647	}
648
649	MLX5_SET(pmtu_reg, in, local_port, pmtu->local_port);
650	if (write)
651		MLX5_SET(pmtu_reg, in, admin_mtu, pmtu->admin_mtu);
652
653	err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PMTU, 0,
654				   !!write);
655	if (err)
656		goto out;
657
658	if (!write) {
659		pmtu->local_port = MLX5_GET(pmtu_reg, out, local_port);
660		pmtu->max_mtu = mtu_to_ib_mtu(MLX5_GET(pmtu_reg, out,
661						       max_mtu));
662		pmtu->admin_mtu = mtu_to_ib_mtu(MLX5_GET(pmtu_reg, out,
663							 admin_mtu));
664		pmtu->oper_mtu = mtu_to_ib_mtu(MLX5_GET(pmtu_reg, out,
665							oper_mtu));
666	}
667
668out:
669	kvfree(in);
670	kvfree(out);
671	return err;
672}
673EXPORT_SYMBOL_GPL(mlx5_core_access_pmtu);
674
675int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num)
676{
677	u32 in[MLX5_ST_SZ_DW(pmlp_reg)] = {0};
678	u32 out[MLX5_ST_SZ_DW(pmlp_reg)] = {0};
679	int lane = 0;
680	int err;
681
682	MLX5_SET(pmlp_reg, in, local_port, 1);
683
684	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
685				   sizeof(out), MLX5_REG_PMLP, 0, 0);
686	if (err)
687		return err;
688
689	lane = MLX5_GET(pmlp_reg, out, lane0_module_mapping);
690	*module_num = lane & MLX5_EEPROM_IDENTIFIER_BYTE_MASK;
691
692	return 0;
693}
694EXPORT_SYMBOL_GPL(mlx5_query_module_num);
695
696int mlx5_query_eeprom(struct mlx5_core_dev *dev,
697		      int i2c_addr, int page_num, int device_addr,
698		      int size, int module_num, u32 *data, int *size_read)
699{
700	u32 in[MLX5_ST_SZ_DW(mcia_reg)] = {0};
701	u32 out[MLX5_ST_SZ_DW(mcia_reg)] = {0};
702	u32 *ptr = (u32 *)MLX5_ADDR_OF(mcia_reg, out, dword_0);
703	int status;
704	int err;
705
706	size = min_t(int, size, MLX5_EEPROM_MAX_BYTES);
707
708	MLX5_SET(mcia_reg, in, l, 0);
709	MLX5_SET(mcia_reg, in, module, module_num);
710	MLX5_SET(mcia_reg, in, i2c_device_address, i2c_addr);
711	MLX5_SET(mcia_reg, in, page_number, page_num);
712	MLX5_SET(mcia_reg, in, device_address, device_addr);
713	MLX5_SET(mcia_reg, in, size, size);
714
715	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
716				   sizeof(out), MLX5_REG_MCIA, 0, 0);
717	if (err)
718		return err;
719
720	status = MLX5_GET(mcia_reg, out, status);
721	if (status)
722		return status;
723
724	memcpy(data, ptr, size);
725	*size_read = size;
726	return 0;
727}
728EXPORT_SYMBOL_GPL(mlx5_query_eeprom);
729
730int mlx5_vxlan_udp_port_add(struct mlx5_core_dev *dev, u16 port)
731{
732	u32 in[MLX5_ST_SZ_DW(add_vxlan_udp_dport_in)] = {0};
733	u32 out[MLX5_ST_SZ_DW(add_vxlan_udp_dport_out)] = {0};
734	int err;
735
736	MLX5_SET(add_vxlan_udp_dport_in, in, opcode,
737		 MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT);
738	MLX5_SET(add_vxlan_udp_dport_in, in, vxlan_udp_port, port);
739
740	err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
741	if (err) {
742		mlx5_core_err(dev, "Failed %s, port %u, err - %d",
743			      mlx5_command_str(MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT),
744			      port, err);
745	}
746
747	return err;
748}
749
750int mlx5_vxlan_udp_port_delete(struct mlx5_core_dev *dev, u16 port)
751{
752	u32 in[MLX5_ST_SZ_DW(delete_vxlan_udp_dport_in)] = {0};
753	u32 out[MLX5_ST_SZ_DW(delete_vxlan_udp_dport_out)] = {0};
754	int err;
755
756	MLX5_SET(delete_vxlan_udp_dport_in, in, opcode,
757		 MLX5_CMD_OP_DELETE_VXLAN_UDP_DPORT);
758	MLX5_SET(delete_vxlan_udp_dport_in, in, vxlan_udp_port, port);
759
760	err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
761	if (err) {
762		mlx5_core_err(dev, "Failed %s, port %u, err - %d",
763			      mlx5_command_str(MLX5_CMD_OP_DELETE_VXLAN_UDP_DPORT),
764			      port, err);
765	}
766
767	return err;
768}
769
770int mlx5_query_wol(struct mlx5_core_dev *dev, u8 *wol_mode)
771{
772	u32 in[MLX5_ST_SZ_DW(query_wol_rol_in)] = {0};
773	u32 out[MLX5_ST_SZ_DW(query_wol_rol_out)] = {0};
774	int err;
775
776	MLX5_SET(query_wol_rol_in, in, opcode, MLX5_CMD_OP_QUERY_WOL_ROL);
777
778	err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
779
780	if (!err)
781		*wol_mode = MLX5_GET(query_wol_rol_out, out, wol_mode);
782
783	return err;
784}
785EXPORT_SYMBOL_GPL(mlx5_query_wol);
786
787int mlx5_query_port_cong_status(struct mlx5_core_dev *mdev, int protocol,
788				int priority, int *is_enable)
789{
790	u32 in[MLX5_ST_SZ_DW(query_cong_status_in)] = {0};
791	u32 out[MLX5_ST_SZ_DW(query_cong_status_out)] = {0};
792	int err;
793
794	*is_enable = 0;
795
796	MLX5_SET(query_cong_status_in, in, opcode,
797		 MLX5_CMD_OP_QUERY_CONG_STATUS);
798	MLX5_SET(query_cong_status_in, in, cong_protocol, protocol);
799	MLX5_SET(query_cong_status_in, in, priority, priority);
800
801	err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
802	if (!err)
803		*is_enable = MLX5_GET(query_cong_status_out, out, enable);
804	return err;
805}
806
807int mlx5_modify_port_cong_status(struct mlx5_core_dev *mdev, int protocol,
808				 int priority, int enable)
809{
810	u32 in[MLX5_ST_SZ_DW(modify_cong_status_in)] = {0};
811	u32 out[MLX5_ST_SZ_DW(modify_cong_status_out)] = {0};
812
813	MLX5_SET(modify_cong_status_in, in, opcode,
814		 MLX5_CMD_OP_MODIFY_CONG_STATUS);
815	MLX5_SET(modify_cong_status_in, in, cong_protocol, protocol);
816	MLX5_SET(modify_cong_status_in, in, priority, priority);
817	MLX5_SET(modify_cong_status_in, in, enable, enable);
818
819	return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
820}
821
822int mlx5_query_port_cong_params(struct mlx5_core_dev *mdev, int protocol,
823				void *out, int out_size)
824{
825	u32 in[MLX5_ST_SZ_DW(query_cong_params_in)] = {0};
826
827	MLX5_SET(query_cong_params_in, in, opcode,
828		 MLX5_CMD_OP_QUERY_CONG_PARAMS);
829	MLX5_SET(query_cong_params_in, in, cong_protocol, protocol);
830
831	return mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size);
832}
833
834static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out,
835				     int outlen)
836{
837	u32 in[MLX5_ST_SZ_DW(qetc_reg)];
838
839	if (!MLX5_CAP_GEN(mdev, ets))
840		return -ENOTSUPP;
841
842	memset(in, 0, sizeof(in));
843	return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen,
844				    MLX5_REG_QETCR, 0, 0);
845}
846
847int mlx5_max_tc(struct mlx5_core_dev *mdev)
848{
849	u8 num_tc = MLX5_CAP_GEN(mdev, max_tc) ? : 8;
850
851	return num_tc - 1;
852}
853EXPORT_SYMBOL_GPL(mlx5_max_tc);
854
855static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in,
856				   int inlen)
857{
858	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
859
860	if (!MLX5_CAP_GEN(mdev, ets))
861		return -ENOTSUPP;
862
863	return mlx5_core_access_reg(mdev, in, inlen, out, sizeof(out),
864				    MLX5_REG_QETCR, 0, 1);
865}
866
867int mlx5_query_port_tc_rate_limit(struct mlx5_core_dev *mdev,
868				   u8 *max_bw_value,
869				   u8 *max_bw_units)
870{
871	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
872	void *ets_tcn_conf;
873	int err;
874	int i;
875
876	err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
877	if (err)
878		return err;
879
880	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
881		ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, tc_configuration[i]);
882
883		max_bw_value[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
884					   max_bw_value);
885		max_bw_units[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
886					   max_bw_units);
887	}
888
889	return 0;
890}
891EXPORT_SYMBOL_GPL(mlx5_query_port_tc_rate_limit);
892
893int mlx5_modify_port_tc_rate_limit(struct mlx5_core_dev *mdev,
894				   const u8 *max_bw_value,
895				   const u8 *max_bw_units)
896{
897	u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {};
898	void *ets_tcn_conf;
899	int i;
900
901	MLX5_SET(qetc_reg, in, port_number, 1);
902
903	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
904		ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, in, tc_configuration[i]);
905
906		MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, r, 1);
907		MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_units,
908			 max_bw_units[i]);
909		MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_value,
910			 max_bw_value[i]);
911	}
912
913	return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
914}
915EXPORT_SYMBOL_GPL(mlx5_modify_port_tc_rate_limit);
916
917int mlx5_query_port_prio_tc(struct mlx5_core_dev *mdev,
918			    u8 prio, u8 *tc)
919{
920	u32 in[MLX5_ST_SZ_DW(qtct_reg)];
921	u32 out[MLX5_ST_SZ_DW(qtct_reg)];
922	int err;
923
924	memset(in, 0, sizeof(in));
925	memset(out, 0, sizeof(out));
926
927	MLX5_SET(qtct_reg, in, port_number, 1);
928	MLX5_SET(qtct_reg, in, prio, prio);
929
930	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
931				   sizeof(out), MLX5_REG_QTCT, 0, 0);
932	if (!err)
933		*tc = MLX5_GET(qtct_reg, out, tclass);
934
935	return err;
936}
937EXPORT_SYMBOL_GPL(mlx5_query_port_prio_tc);
938
939int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, int prio_index,
940			  const u8 prio_tc)
941{
942	u32 in[MLX5_ST_SZ_DW(qtct_reg)] = {};
943	u32 out[MLX5_ST_SZ_DW(qtct_reg)];
944	int err;
945
946	if (prio_tc > mlx5_max_tc(mdev))
947		return -EINVAL;
948
949	MLX5_SET(qtct_reg, in, prio, prio_index);
950	MLX5_SET(qtct_reg, in, tclass, prio_tc);
951
952	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
953				   sizeof(out), MLX5_REG_QTCT, 0, 1);
954
955	return (err);
956}
957EXPORT_SYMBOL_GPL(mlx5_set_port_prio_tc);
958
959int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, const u8 *tc_group)
960{
961	u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {};
962	int i;
963
964	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
965		MLX5_SET(qetc_reg, in, tc_configuration[i].g, 1);
966		MLX5_SET(qetc_reg, in, tc_configuration[i].group, tc_group[i]);
967	}
968
969	return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
970}
971EXPORT_SYMBOL_GPL(mlx5_set_port_tc_group);
972
973int mlx5_query_port_tc_group(struct mlx5_core_dev *mdev,
974			     u8 tc, u8 *tc_group)
975{
976	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
977	void *ets_tcn_conf;
978	int err;
979
980	err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
981	if (err)
982		return err;
983
984	ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out,
985				    tc_configuration[tc]);
986
987	*tc_group = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
988			     group);
989
990	return 0;
991}
992EXPORT_SYMBOL_GPL(mlx5_query_port_tc_group);
993
994int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, const u8 *tc_bw)
995{
996	u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {};
997	int i;
998
999	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
1000		MLX5_SET(qetc_reg, in, tc_configuration[i].b, 1);
1001		MLX5_SET(qetc_reg, in, tc_configuration[i].bw_allocation, tc_bw[i]);
1002	}
1003
1004	return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
1005}
1006EXPORT_SYMBOL_GPL(mlx5_set_port_tc_bw_alloc);
1007
1008int mlx5_query_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *bw_pct)
1009{
1010	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
1011	void *ets_tcn_conf;
1012	int err;
1013	int i;
1014
1015	err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
1016	if (err)
1017		return err;
1018
1019	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
1020		ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, tc_configuration[i]);
1021		bw_pct[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf, bw_allocation);
1022	}
1023	return 0;
1024}
1025EXPORT_SYMBOL_GPL(mlx5_query_port_tc_bw_alloc);
1026
1027int mlx5_modify_port_cong_params(struct mlx5_core_dev *mdev,
1028				 void *in, int in_size)
1029{
1030	u32 out[MLX5_ST_SZ_DW(modify_cong_params_out)] = {0};
1031
1032	MLX5_SET(modify_cong_params_in, in, opcode,
1033		 MLX5_CMD_OP_MODIFY_CONG_PARAMS);
1034
1035	return mlx5_cmd_exec(mdev, in, in_size, out, sizeof(out));
1036}
1037
1038int mlx5_query_port_cong_statistics(struct mlx5_core_dev *mdev, int clear,
1039				    void *out, int out_size)
1040{
1041	u32 in[MLX5_ST_SZ_DW(query_cong_statistics_in)] = {0};
1042
1043	MLX5_SET(query_cong_statistics_in, in, opcode,
1044		 MLX5_CMD_OP_QUERY_CONG_STATISTICS);
1045	MLX5_SET(query_cong_statistics_in, in, clear, clear);
1046
1047	return mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size);
1048}
1049
1050int mlx5_set_diagnostic_params(struct mlx5_core_dev *mdev, void *in,
1051			       int in_size)
1052{
1053	u32 out[MLX5_ST_SZ_DW(set_diagnostic_params_out)] = {0};
1054
1055	MLX5_SET(set_diagnostic_params_in, in, opcode,
1056		 MLX5_CMD_OP_SET_DIAGNOSTICS);
1057
1058	return mlx5_cmd_exec(mdev, in, in_size, out, sizeof(out));
1059}
1060
1061int mlx5_query_diagnostic_counters(struct mlx5_core_dev *mdev,
1062				   u8 num_of_samples, u16 sample_index,
1063				   void *out, int out_size)
1064{
1065	u32 in[MLX5_ST_SZ_DW(query_diagnostic_counters_in)] = {0};
1066
1067	MLX5_SET(query_diagnostic_counters_in, in, opcode,
1068		 MLX5_CMD_OP_QUERY_DIAGNOSTICS);
1069	MLX5_SET(query_diagnostic_counters_in, in, num_of_samples,
1070		 num_of_samples);
1071	MLX5_SET(query_diagnostic_counters_in, in, sample_index, sample_index);
1072
1073	return mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size);
1074}
1075
1076int mlx5_set_trust_state(struct mlx5_core_dev *mdev, u8 trust_state)
1077{
1078	u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {};
1079	u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {};
1080	int err;
1081
1082	MLX5_SET(qpts_reg, in, local_port, 1);
1083	MLX5_SET(qpts_reg, in, trust_state, trust_state);
1084
1085	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
1086				   sizeof(out), MLX5_REG_QPTS, 0, 1);
1087	return err;
1088}
1089
1090int mlx5_query_trust_state(struct mlx5_core_dev *mdev, u8 *trust_state)
1091{
1092	u32 out[MLX5_ST_SZ_DW(qpts_reg)] = {};
1093	u32 in[MLX5_ST_SZ_DW(qpts_reg)] = {};
1094	int err;
1095
1096	MLX5_SET(qpts_reg, in, local_port, 1);
1097
1098	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
1099				   sizeof(out), MLX5_REG_QPTS, 0, 0);
1100	if (!err)
1101		*trust_state = MLX5_GET(qpts_reg, out, trust_state);
1102
1103	return err;
1104}
1105
1106int mlx5_set_dscp2prio(struct mlx5_core_dev *mdev, const u8 *dscp2prio)
1107{
1108	int sz = MLX5_ST_SZ_BYTES(qpdpm_reg);
1109	void *qpdpm_dscp;
1110	void *out;
1111	void *in;
1112	int err;
1113	int i;
1114
1115	in = kzalloc(sz, GFP_KERNEL);
1116	out = kzalloc(sz, GFP_KERNEL);
1117	if (!in || !out) {
1118		err = -ENOMEM;
1119		goto out;
1120	}
1121
1122	MLX5_SET(qpdpm_reg, in, local_port, 1);
1123	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0);
1124	if (err)
1125		goto out;
1126
1127	memcpy(in, out, sz);
1128	MLX5_SET(qpdpm_reg, in, local_port, 1);
1129
1130	/* Update the corresponding dscp entry */
1131	for (i = 0; i < MLX5_MAX_SUPPORTED_DSCP; i++) {
1132		qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, in, dscp[i]);
1133		MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, prio, dscp2prio[i]);
1134		MLX5_SET16(qpdpm_dscp_reg, qpdpm_dscp, e, 1);
1135	}
1136	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 1);
1137out:
1138	kfree(in);
1139	kfree(out);
1140	return err;
1141}
1142
1143int mlx5_query_dscp2prio(struct mlx5_core_dev *mdev, u8 *dscp2prio)
1144{
1145	int sz = MLX5_ST_SZ_BYTES(qpdpm_reg);
1146	void *qpdpm_dscp;
1147	void *out;
1148	void *in;
1149	int err;
1150	int i;
1151
1152	in = kzalloc(sz, GFP_KERNEL);
1153	out = kzalloc(sz, GFP_KERNEL);
1154	if (!in || !out) {
1155		err = -ENOMEM;
1156		goto out;
1157	}
1158
1159	MLX5_SET(qpdpm_reg, in, local_port, 1);
1160	err = mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_QPDPM, 0, 0);
1161	if (err)
1162		goto out;
1163
1164	for (i = 0; i < MLX5_MAX_SUPPORTED_DSCP; i++) {
1165		qpdpm_dscp = MLX5_ADDR_OF(qpdpm_reg, out, dscp[i]);
1166		dscp2prio[i] = MLX5_GET16(qpdpm_dscp_reg, qpdpm_dscp, prio);
1167	}
1168out:
1169	kfree(in);
1170	kfree(out);
1171	return err;
1172}
1173
1174int mlx5_query_pddr_range_info(struct mlx5_core_dev *mdev, u8 local_port, u8 *is_er_type)
1175{
1176	u32 pddr_reg[MLX5_ST_SZ_DW(pddr_reg)] = {};
1177	int sz = MLX5_ST_SZ_BYTES(pddr_reg);
1178	int error;
1179	u8 ecc;
1180	u8 ci;
1181
1182	MLX5_SET(pddr_reg, pddr_reg, local_port, local_port);
1183	MLX5_SET(pddr_reg, pddr_reg, page_select, 3 /* module info page */);
1184
1185	error = mlx5_core_access_reg(mdev, pddr_reg, sz, pddr_reg, sz,
1186	    MLX5_ACCESS_REG_SUMMARY_CTRL_ID_PDDR, 0, 0);
1187	if (error != 0)
1188		return (error);
1189
1190	ecc = MLX5_GET(pddr_reg, pddr_reg, page_data.pddr_module_info.ethernet_compliance_code);
1191	ci = MLX5_GET(pddr_reg, pddr_reg, page_data.pddr_module_info.cable_identifier);
1192
1193	switch (ci) {
1194	case 0:	/* QSFP28 */
1195	case 1:	/* QSFP+ */
1196		*is_er_type = 0;
1197		break;
1198	case 2:	/* SFP28/SFP+ */
1199	case 3: /* QSA (QSFP->SFP) */
1200		*is_er_type = ((ecc & (1 << 7)) != 0);
1201		break;
1202	default:
1203		*is_er_type = 0;
1204		break;
1205	}
1206	return (0);
1207}
1208EXPORT_SYMBOL_GPL(mlx5_query_pddr_range_info);
1209