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