mlx5_port.c revision 331583
1/*-
2 * Copyright (c) 2013-2015, 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 331583 2018-03-26 20:50:28Z 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	struct mlx5_access_reg_mbox_in *in = NULL;
37	struct mlx5_access_reg_mbox_out *out = NULL;
38	int err = -ENOMEM;
39
40	in = mlx5_vzalloc(sizeof(*in) + size_in);
41	if (!in)
42		return -ENOMEM;
43
44	out = mlx5_vzalloc(sizeof(*out) + size_out);
45	if (!out)
46		goto ex1;
47
48	memcpy(in->data, data_in, size_in);
49	in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ACCESS_REG);
50	in->hdr.opmod = cpu_to_be16(!write);
51	in->arg = cpu_to_be32(arg);
52	in->register_id = cpu_to_be16(reg_num);
53	err = mlx5_cmd_exec(dev, in, sizeof(*in) + size_in, out,
54			    sizeof(*out) + size_out);
55	if (err)
56		goto ex2;
57
58	if (out->hdr.status)
59		err = mlx5_cmd_status_to_err(&out->hdr);
60
61	if (!err)
62		memcpy(data_out, out->data, size_out);
63
64ex2:
65	kvfree(out);
66ex1:
67	kvfree(in);
68	return err;
69}
70EXPORT_SYMBOL_GPL(mlx5_core_access_reg);
71
72
73struct mlx5_reg_pcap {
74	u8			rsvd0;
75	u8			port_num;
76	u8			rsvd1[2];
77	__be32			caps_127_96;
78	__be32			caps_95_64;
79	__be32			caps_63_32;
80	__be32			caps_31_0;
81};
82
83/* This function should be used after setting a port register only */
84void mlx5_toggle_port_link(struct mlx5_core_dev *dev)
85{
86	enum mlx5_port_status ps;
87
88	mlx5_query_port_admin_status(dev, &ps);
89	mlx5_set_port_status(dev, MLX5_PORT_DOWN);
90	if (ps == MLX5_PORT_UP)
91		mlx5_set_port_status(dev, MLX5_PORT_UP);
92}
93EXPORT_SYMBOL_GPL(mlx5_toggle_port_link);
94
95int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps)
96{
97	struct mlx5_reg_pcap in;
98	struct mlx5_reg_pcap out;
99	int err;
100
101	memset(&in, 0, sizeof(in));
102	in.caps_127_96 = cpu_to_be32(caps);
103	in.port_num = port_num;
104
105	err = mlx5_core_access_reg(dev, &in, sizeof(in), &out,
106				   sizeof(out), MLX5_REG_PCAP, 0, 1);
107
108	return err;
109}
110EXPORT_SYMBOL_GPL(mlx5_set_port_caps);
111
112int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys,
113			 int ptys_size, int proto_mask, u8 local_port)
114{
115	u32 in[MLX5_ST_SZ_DW(ptys_reg)];
116	int err;
117
118	memset(in, 0, sizeof(in));
119	MLX5_SET(ptys_reg, in, local_port, local_port);
120	MLX5_SET(ptys_reg, in, proto_mask, proto_mask);
121
122	err = mlx5_core_access_reg(dev, in, sizeof(in), ptys,
123				   ptys_size, MLX5_REG_PTYS, 0, 0);
124
125	return err;
126}
127EXPORT_SYMBOL_GPL(mlx5_query_port_ptys);
128
129int mlx5_query_port_proto_cap(struct mlx5_core_dev *dev,
130			      u32 *proto_cap, int proto_mask)
131{
132	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
133	int err;
134
135	err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1);
136	if (err)
137		return err;
138
139	if (proto_mask == MLX5_PTYS_EN)
140		*proto_cap = MLX5_GET(ptys_reg, out, eth_proto_capability);
141	else
142		*proto_cap = MLX5_GET(ptys_reg, out, ib_proto_capability);
143
144	return 0;
145}
146EXPORT_SYMBOL_GPL(mlx5_query_port_proto_cap);
147
148int mlx5_query_port_autoneg(struct mlx5_core_dev *dev, int proto_mask,
149			    u8 *an_disable_cap, u8 *an_disable_status)
150{
151	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
152	int err;
153
154	err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1);
155	if (err)
156		return err;
157
158	*an_disable_status = MLX5_GET(ptys_reg, out, an_disable_admin);
159	*an_disable_cap = MLX5_GET(ptys_reg, out, an_disable_cap);
160
161	return 0;
162}
163EXPORT_SYMBOL_GPL(mlx5_query_port_autoneg);
164
165int mlx5_set_port_autoneg(struct mlx5_core_dev *dev, bool disable,
166			  u32 eth_proto_admin, int proto_mask)
167{
168	u32 in[MLX5_ST_SZ_DW(ptys_reg)];
169	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
170	u8 an_disable_cap;
171	u8 an_disable_status;
172	int err;
173
174	err = mlx5_query_port_autoneg(dev, proto_mask, &an_disable_cap,
175				      &an_disable_status);
176	if (err)
177		return err;
178	if (!an_disable_cap)
179		return -EPERM;
180
181	memset(in, 0, sizeof(in));
182
183	MLX5_SET(ptys_reg, in, local_port, 1);
184	MLX5_SET(ptys_reg, in, an_disable_admin, disable);
185	MLX5_SET(ptys_reg, in, proto_mask, proto_mask);
186	if (proto_mask == MLX5_PTYS_EN)
187		MLX5_SET(ptys_reg, in, eth_proto_admin, eth_proto_admin);
188
189	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
190				   sizeof(out), MLX5_REG_PTYS, 0, 1);
191	return err;
192}
193EXPORT_SYMBOL_GPL(mlx5_set_port_autoneg);
194
195int mlx5_query_port_proto_admin(struct mlx5_core_dev *dev,
196				u32 *proto_admin, int proto_mask)
197{
198	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
199	int err;
200
201	err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1);
202	if (err)
203		return err;
204
205	if (proto_mask == MLX5_PTYS_EN)
206		*proto_admin = MLX5_GET(ptys_reg, out, eth_proto_admin);
207	else
208		*proto_admin = MLX5_GET(ptys_reg, out, ib_proto_admin);
209
210	return 0;
211}
212EXPORT_SYMBOL_GPL(mlx5_query_port_proto_admin);
213
214int mlx5_query_port_eth_proto_oper(struct mlx5_core_dev *dev,
215				   u32 *proto_oper, u8 local_port)
216{
217	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
218	int err;
219
220	err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN,
221				   local_port);
222	if (err)
223		return err;
224
225	*proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper);
226
227	return 0;
228}
229EXPORT_SYMBOL(mlx5_query_port_eth_proto_oper);
230
231int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin,
232			int proto_mask)
233{
234	u32 in[MLX5_ST_SZ_DW(ptys_reg)];
235	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
236	int err;
237
238	memset(in, 0, sizeof(in));
239
240	MLX5_SET(ptys_reg, in, local_port, 1);
241	MLX5_SET(ptys_reg, in, proto_mask, proto_mask);
242	if (proto_mask == MLX5_PTYS_EN)
243		MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin);
244	else
245		MLX5_SET(ptys_reg, in, ib_proto_admin, proto_admin);
246
247	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
248				   sizeof(out), MLX5_REG_PTYS, 0, 1);
249	return err;
250}
251EXPORT_SYMBOL_GPL(mlx5_set_port_proto);
252
253int mlx5_set_port_status(struct mlx5_core_dev *dev,
254			 enum mlx5_port_status status)
255{
256	u32 in[MLX5_ST_SZ_DW(paos_reg)];
257	u32 out[MLX5_ST_SZ_DW(paos_reg)];
258	int err;
259
260	memset(in, 0, sizeof(in));
261
262	MLX5_SET(paos_reg, in, local_port, 1);
263
264	MLX5_SET(paos_reg, in, admin_status, status);
265	MLX5_SET(paos_reg, in, ase, 1);
266
267	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
268				   sizeof(out), MLX5_REG_PAOS, 0, 1);
269	return err;
270}
271
272int mlx5_query_port_status(struct mlx5_core_dev *dev, u8 *status)
273{
274	u32 in[MLX5_ST_SZ_DW(paos_reg)];
275	u32 out[MLX5_ST_SZ_DW(paos_reg)];
276	int err;
277
278	memset(in, 0, sizeof(in));
279
280	MLX5_SET(paos_reg, in, local_port, 1);
281
282	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
283				   sizeof(out), MLX5_REG_PAOS, 0, 0);
284	if (err)
285		return err;
286
287	*status = MLX5_GET(paos_reg, out, oper_status);
288	return err;
289}
290
291int mlx5_query_port_admin_status(struct mlx5_core_dev *dev,
292				 enum mlx5_port_status *status)
293{
294	u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0};
295	u32 out[MLX5_ST_SZ_DW(paos_reg)];
296	int err;
297
298	MLX5_SET(paos_reg, in, local_port, 1);
299	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
300				   sizeof(out), MLX5_REG_PAOS, 0, 0);
301	if (err)
302		return err;
303	*status = MLX5_GET(paos_reg, out, admin_status);
304	return 0;
305}
306EXPORT_SYMBOL_GPL(mlx5_query_port_admin_status);
307
308static int mlx5_query_port_mtu(struct mlx5_core_dev *dev,
309			       int *admin_mtu, int *max_mtu, int *oper_mtu)
310{
311	u32 in[MLX5_ST_SZ_DW(pmtu_reg)];
312	u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
313	int err;
314
315	memset(in, 0, sizeof(in));
316
317	MLX5_SET(pmtu_reg, in, local_port, 1);
318
319	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
320				   sizeof(out), MLX5_REG_PMTU, 0, 0);
321	if (err)
322		return err;
323
324	if (max_mtu)
325		*max_mtu  = MLX5_GET(pmtu_reg, out, max_mtu);
326	if (oper_mtu)
327		*oper_mtu = MLX5_GET(pmtu_reg, out, oper_mtu);
328	if (admin_mtu)
329		*admin_mtu = MLX5_GET(pmtu_reg, out, admin_mtu);
330
331	return err;
332}
333
334int mlx5_set_port_mtu(struct mlx5_core_dev *dev, int mtu)
335{
336	u32 in[MLX5_ST_SZ_DW(pmtu_reg)];
337	u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
338
339	memset(in, 0, sizeof(in));
340
341	MLX5_SET(pmtu_reg, in, admin_mtu, mtu);
342	MLX5_SET(pmtu_reg, in, local_port, 1);
343
344	return mlx5_core_access_reg(dev, in, sizeof(in), out,
345				   sizeof(out), MLX5_REG_PMTU, 0, 1);
346}
347EXPORT_SYMBOL_GPL(mlx5_set_port_mtu);
348
349int mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, int *max_mtu)
350{
351	return mlx5_query_port_mtu(dev, NULL, max_mtu, NULL);
352}
353EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu);
354
355int mlx5_set_port_pause_and_pfc(struct mlx5_core_dev *dev, u32 port,
356				u8 rx_pause, u8 tx_pause,
357				u8 pfc_en_rx, u8 pfc_en_tx)
358{
359	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
360	u32 out[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
361
362	if (pfc_en_rx || pfc_en_tx) {
363		/* PFC and global pauseframes are incompatible features */
364		if (tx_pause || rx_pause)
365			return -EINVAL;
366	}
367
368	MLX5_SET(pfcc_reg, in, local_port, port);
369	MLX5_SET(pfcc_reg, in, pptx, tx_pause);
370	MLX5_SET(pfcc_reg, in, pprx, rx_pause);
371	MLX5_SET(pfcc_reg, in, pfctx, pfc_en_tx);
372	MLX5_SET(pfcc_reg, in, pfcrx, pfc_en_rx);
373	MLX5_SET(pfcc_reg, in, prio_mask_tx, pfc_en_tx);
374	MLX5_SET(pfcc_reg, in, prio_mask_rx, pfc_en_rx);
375
376	return mlx5_core_access_reg(dev, in, sizeof(in), out,
377				   sizeof(out), MLX5_REG_PFCC, 0, 1);
378}
379
380int mlx5_query_port_pause(struct mlx5_core_dev *dev, u32 port,
381			  u32 *rx_pause, u32 *tx_pause)
382{
383	u32 in[MLX5_ST_SZ_DW(pfcc_reg)];
384	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
385	int err;
386
387	memset(in, 0, sizeof(in));
388	memset(out, 0, sizeof(out));
389
390	MLX5_SET(pfcc_reg, in, local_port, port);
391
392	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
393				   sizeof(out), MLX5_REG_PFCC, 0, 0);
394	if (err)
395		return err;
396
397	*rx_pause = MLX5_GET(pfcc_reg, out, pprx);
398	*tx_pause = MLX5_GET(pfcc_reg, out, pptx);
399
400	return 0;
401}
402
403int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx, u8 *pfc_en_rx)
404{
405	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {};
406	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
407	int err;
408
409	MLX5_SET(pfcc_reg, in, local_port, 1);
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	if (pfc_en_tx != NULL)
416		*pfc_en_tx = MLX5_GET(pfcc_reg, out, pfctx);
417	if (pfc_en_rx != NULL)
418		*pfc_en_rx = MLX5_GET(pfcc_reg, out, pfcrx);
419	return 0;
420}
421EXPORT_SYMBOL_GPL(mlx5_query_port_pfc);
422
423int mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, int *oper_mtu)
424{
425	return mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu);
426}
427EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu);
428
429u8 mlx5_is_wol_supported(struct mlx5_core_dev *dev)
430{
431	u8 wol_supported = 0;
432
433	if (MLX5_CAP_GEN(dev, wol_s))
434		wol_supported |= MLX5_WOL_SECURED_MAGIC;
435	if (MLX5_CAP_GEN(dev, wol_g))
436		wol_supported |= MLX5_WOL_MAGIC;
437	if (MLX5_CAP_GEN(dev, wol_a))
438		wol_supported |= MLX5_WOL_ARP;
439	if (MLX5_CAP_GEN(dev, wol_b))
440		wol_supported |= MLX5_WOL_BROADCAST;
441	if (MLX5_CAP_GEN(dev, wol_m))
442		wol_supported |= MLX5_WOL_MULTICAST;
443	if (MLX5_CAP_GEN(dev, wol_u))
444		wol_supported |= MLX5_WOL_UNICAST;
445	if (MLX5_CAP_GEN(dev, wol_p))
446		wol_supported |= MLX5_WOL_PHY_ACTIVITY;
447
448	return wol_supported;
449}
450EXPORT_SYMBOL_GPL(mlx5_is_wol_supported);
451
452int mlx5_set_wol(struct mlx5_core_dev *dev, u8 wol_mode)
453{
454	u32 in[MLX5_ST_SZ_DW(set_wol_rol_in)];
455	u32 out[MLX5_ST_SZ_DW(set_wol_rol_out)];
456
457	memset(in, 0, sizeof(in));
458	memset(out, 0, sizeof(out));
459
460	MLX5_SET(set_wol_rol_in, in, opcode, MLX5_CMD_OP_SET_WOL_ROL);
461	MLX5_SET(set_wol_rol_in, in, wol_mode_valid, 1);
462	MLX5_SET(set_wol_rol_in, in, wol_mode, wol_mode);
463
464	return mlx5_cmd_exec_check_status(dev, in, sizeof(in),
465					  out, sizeof(out));
466}
467EXPORT_SYMBOL_GPL(mlx5_set_wol);
468
469int mlx5_query_dropless_mode(struct mlx5_core_dev *dev, u16 *timeout)
470{
471	u32 in[MLX5_ST_SZ_DW(query_delay_drop_params_in)];
472	u32 out[MLX5_ST_SZ_DW(query_delay_drop_params_out)];
473	int err = 0;
474
475	memset(in, 0, sizeof(in));
476	memset(out, 0, sizeof(out));
477
478	MLX5_SET(query_delay_drop_params_in, in, opcode,
479		 MLX5_CMD_OP_QUERY_DELAY_DROP_PARAMS);
480
481	err = mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out));
482	if (err)
483		return err;
484
485	*timeout = MLX5_GET(query_delay_drop_params_out, out,
486			    delay_drop_timeout);
487
488	return 0;
489}
490EXPORT_SYMBOL_GPL(mlx5_query_dropless_mode);
491
492int mlx5_set_dropless_mode(struct mlx5_core_dev *dev, u16 timeout)
493{
494	u32 in[MLX5_ST_SZ_DW(set_delay_drop_params_in)];
495	u32 out[MLX5_ST_SZ_DW(set_delay_drop_params_out)];
496
497	memset(in, 0, sizeof(in));
498	memset(out, 0, sizeof(out));
499
500	MLX5_SET(set_delay_drop_params_in, in, opcode,
501		 MLX5_CMD_OP_SET_DELAY_DROP_PARAMS);
502	MLX5_SET(set_delay_drop_params_in, in, delay_drop_timeout, timeout);
503
504	return mlx5_cmd_exec_check_status(dev, in, sizeof(in),
505					   out, sizeof(out));
506}
507EXPORT_SYMBOL_GPL(mlx5_set_dropless_mode);
508
509int mlx5_core_access_pvlc(struct mlx5_core_dev *dev,
510			  struct mlx5_pvlc_reg *pvlc, int write)
511{
512	int sz = MLX5_ST_SZ_BYTES(pvlc_reg);
513	u8 in[MLX5_ST_SZ_BYTES(pvlc_reg)];
514	u8 out[MLX5_ST_SZ_BYTES(pvlc_reg)];
515	int err;
516
517	memset(out, 0, sizeof(out));
518	memset(in, 0, sizeof(in));
519
520	MLX5_SET(pvlc_reg, in, local_port, pvlc->local_port);
521	if (write)
522		MLX5_SET(pvlc_reg, in, vl_admin, pvlc->vl_admin);
523
524	err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PVLC, 0,
525				   !!write);
526	if (err)
527		return err;
528
529	if (!write) {
530		pvlc->local_port = MLX5_GET(pvlc_reg, out, local_port);
531		pvlc->vl_hw_cap = MLX5_GET(pvlc_reg, out, vl_hw_cap);
532		pvlc->vl_admin = MLX5_GET(pvlc_reg, out, vl_admin);
533		pvlc->vl_operational = MLX5_GET(pvlc_reg, out, vl_operational);
534	}
535
536	return 0;
537}
538EXPORT_SYMBOL_GPL(mlx5_core_access_pvlc);
539
540int mlx5_core_access_ptys(struct mlx5_core_dev *dev,
541			  struct mlx5_ptys_reg *ptys, int write)
542{
543	int sz = MLX5_ST_SZ_BYTES(ptys_reg);
544	void *out = NULL;
545	void *in = NULL;
546	int err;
547
548	in = mlx5_vzalloc(sz);
549	if (!in)
550		return -ENOMEM;
551
552	out = mlx5_vzalloc(sz);
553	if (!out) {
554		kfree(in);
555		return -ENOMEM;
556	}
557
558	MLX5_SET(ptys_reg, in, local_port, ptys->local_port);
559	MLX5_SET(ptys_reg, in, proto_mask, ptys->proto_mask);
560	if (write) {
561		MLX5_SET(ptys_reg, in, eth_proto_capability,
562			 ptys->eth_proto_cap);
563		MLX5_SET(ptys_reg, in, ib_link_width_capability,
564			 ptys->ib_link_width_cap);
565		MLX5_SET(ptys_reg, in, ib_proto_capability,
566			 ptys->ib_proto_cap);
567		MLX5_SET(ptys_reg, in, eth_proto_admin, ptys->eth_proto_admin);
568		MLX5_SET(ptys_reg, in, ib_link_width_admin,
569			 ptys->ib_link_width_admin);
570		MLX5_SET(ptys_reg, in, ib_proto_admin, ptys->ib_proto_admin);
571		MLX5_SET(ptys_reg, in, eth_proto_oper, ptys->eth_proto_oper);
572		MLX5_SET(ptys_reg, in, ib_link_width_oper,
573			 ptys->ib_link_width_oper);
574		MLX5_SET(ptys_reg, in, ib_proto_oper, ptys->ib_proto_oper);
575		MLX5_SET(ptys_reg, in, eth_proto_lp_advertise,
576			 ptys->eth_proto_lp_advertise);
577	}
578
579	err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PTYS, 0,
580				   !!write);
581	if (err)
582		goto out;
583
584	if (!write) {
585		ptys->local_port = MLX5_GET(ptys_reg, out, local_port);
586		ptys->proto_mask = MLX5_GET(ptys_reg, out, proto_mask);
587		ptys->eth_proto_cap = MLX5_GET(ptys_reg, out,
588					       eth_proto_capability);
589		ptys->ib_link_width_cap = MLX5_GET(ptys_reg, out,
590					   ib_link_width_capability);
591		ptys->ib_proto_cap = MLX5_GET(ptys_reg, out,
592					      ib_proto_capability);
593		ptys->eth_proto_admin = MLX5_GET(ptys_reg, out,
594						 eth_proto_admin);
595		ptys->ib_link_width_admin = MLX5_GET(ptys_reg, out,
596						     ib_link_width_admin);
597		ptys->ib_proto_admin = MLX5_GET(ptys_reg, out, ib_proto_admin);
598		ptys->eth_proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper);
599		ptys->ib_link_width_oper = MLX5_GET(ptys_reg, out,
600						    ib_link_width_oper);
601		ptys->ib_proto_oper = MLX5_GET(ptys_reg, out, ib_proto_oper);
602		ptys->eth_proto_lp_advertise = MLX5_GET(ptys_reg, out,
603							eth_proto_lp_advertise);
604	}
605
606out:
607	kvfree(in);
608	kvfree(out);
609	return err;
610}
611EXPORT_SYMBOL_GPL(mlx5_core_access_ptys);
612
613static int mtu_to_ib_mtu(int mtu)
614{
615	switch (mtu) {
616	case 256: return 1;
617	case 512: return 2;
618	case 1024: return 3;
619	case 2048: return 4;
620	case 4096: return 5;
621	default:
622		printf("mlx5_core: WARN: ""invalid mtu\n");
623		return -1;
624	}
625}
626
627int mlx5_core_access_pmtu(struct mlx5_core_dev *dev,
628			  struct mlx5_pmtu_reg *pmtu, int write)
629{
630	int sz = MLX5_ST_SZ_BYTES(pmtu_reg);
631	void *out = NULL;
632	void *in = NULL;
633	int err;
634
635	in = mlx5_vzalloc(sz);
636	if (!in)
637		return -ENOMEM;
638
639	out = mlx5_vzalloc(sz);
640	if (!out) {
641		kfree(in);
642		return -ENOMEM;
643	}
644
645	MLX5_SET(pmtu_reg, in, local_port, pmtu->local_port);
646	if (write)
647		MLX5_SET(pmtu_reg, in, admin_mtu, pmtu->admin_mtu);
648
649	err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PMTU, 0,
650				   !!write);
651	if (err)
652		goto out;
653
654	if (!write) {
655		pmtu->local_port = MLX5_GET(pmtu_reg, out, local_port);
656		pmtu->max_mtu = mtu_to_ib_mtu(MLX5_GET(pmtu_reg, out,
657						       max_mtu));
658		pmtu->admin_mtu = mtu_to_ib_mtu(MLX5_GET(pmtu_reg, out,
659							 admin_mtu));
660		pmtu->oper_mtu = mtu_to_ib_mtu(MLX5_GET(pmtu_reg, out,
661							oper_mtu));
662	}
663
664out:
665	kvfree(in);
666	kvfree(out);
667	return err;
668}
669EXPORT_SYMBOL_GPL(mlx5_core_access_pmtu);
670
671int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num)
672{
673	u32 in[MLX5_ST_SZ_DW(pmlp_reg)];
674	u32 out[MLX5_ST_SZ_DW(pmlp_reg)];
675	int lane = 0;
676	int err;
677
678	memset(in, 0, sizeof(in));
679
680	MLX5_SET(pmlp_reg, in, local_port, 1);
681
682	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
683				   sizeof(out), MLX5_REG_PMLP, 0, 0);
684	if (err)
685		return err;
686
687	lane = MLX5_GET(pmlp_reg, out, lane0_module_mapping);
688	*module_num = lane & MLX5_EEPROM_IDENTIFIER_BYTE_MASK;
689
690	return 0;
691}
692EXPORT_SYMBOL_GPL(mlx5_query_module_num);
693
694int mlx5_query_eeprom(struct mlx5_core_dev *dev,
695		      int i2c_addr, int page_num, int device_addr,
696		      int size, int module_num, u32 *data, int *size_read)
697{
698	u32 in[MLX5_ST_SZ_DW(mcia_reg)];
699	u32 out[MLX5_ST_SZ_DW(mcia_reg)];
700	u32 *ptr = (u32 *)MLX5_ADDR_OF(mcia_reg, out, dword_0);
701	int status;
702	int err;
703
704	memset(in, 0, sizeof(in));
705	size = min_t(int, size, MLX5_EEPROM_MAX_BYTES);
706
707	MLX5_SET(mcia_reg, in, l, 0);
708	MLX5_SET(mcia_reg, in, module, module_num);
709	MLX5_SET(mcia_reg, in, i2c_device_address, i2c_addr);
710	MLX5_SET(mcia_reg, in, page_number, page_num);
711	MLX5_SET(mcia_reg, in, device_address, device_addr);
712	MLX5_SET(mcia_reg, in, size, size);
713
714	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
715				   sizeof(out), MLX5_REG_MCIA, 0, 0);
716	if (err)
717		return err;
718
719	status = MLX5_GET(mcia_reg, out, status);
720	if (status)
721		return status;
722
723	memcpy(data, ptr, size);
724	*size_read = size;
725	return 0;
726}
727EXPORT_SYMBOL_GPL(mlx5_query_eeprom);
728
729int mlx5_vxlan_udp_port_add(struct mlx5_core_dev *dev, u16 port)
730{
731	u32 in[MLX5_ST_SZ_DW(add_vxlan_udp_dport_in)];
732	u32 out[MLX5_ST_SZ_DW(add_vxlan_udp_dport_out)];
733	int err;
734
735	memset(in, 0, sizeof(in));
736	memset(out, 0, sizeof(out));
737
738	MLX5_SET(add_vxlan_udp_dport_in, in, opcode,
739		 MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT);
740	MLX5_SET(add_vxlan_udp_dport_in, in, vxlan_udp_port, port);
741
742	err = mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out));
743	if (err) {
744		mlx5_core_err(dev, "Failed %s, port %u, err - %d",
745			      mlx5_command_str(MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT),
746			      port, err);
747	}
748
749	return err;
750}
751
752int mlx5_vxlan_udp_port_delete(struct mlx5_core_dev *dev, u16 port)
753{
754	u32 in[MLX5_ST_SZ_DW(delete_vxlan_udp_dport_in)];
755	u32 out[MLX5_ST_SZ_DW(delete_vxlan_udp_dport_out)];
756	int err;
757
758	memset(in, 0, sizeof(in));
759	memset(out, 0, sizeof(out));
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_check_status(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)];
778	u32 out[MLX5_ST_SZ_DW(query_wol_rol_out)];
779	int err;
780
781	memset(in, 0, sizeof(in));
782	memset(out, 0, sizeof(out));
783
784	MLX5_SET(query_wol_rol_in, in, opcode, MLX5_CMD_OP_QUERY_WOL_ROL);
785
786	err = mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out));
787
788	if (!err)
789		*wol_mode = MLX5_GET(query_wol_rol_out, out, wol_mode);
790
791	return err;
792}
793EXPORT_SYMBOL_GPL(mlx5_query_wol);
794
795int mlx5_query_port_cong_status(struct mlx5_core_dev *mdev, int protocol,
796				int priority, int *is_enable)
797{
798	u32 in[MLX5_ST_SZ_DW(query_cong_status_in)];
799	u32 out[MLX5_ST_SZ_DW(query_cong_status_out)];
800	int err;
801
802	memset(in, 0, sizeof(in));
803	memset(out, 0, sizeof(out));
804
805	*is_enable = 0;
806
807	MLX5_SET(query_cong_status_in, in, opcode,
808		 MLX5_CMD_OP_QUERY_CONG_STATUS);
809	MLX5_SET(query_cong_status_in, in, cong_protocol, protocol);
810	MLX5_SET(query_cong_status_in, in, priority, priority);
811
812	err = mlx5_cmd_exec_check_status(mdev, in, sizeof(in),
813					 out, sizeof(out));
814	if (!err)
815		*is_enable = MLX5_GET(query_cong_status_out, out, enable);
816	return err;
817}
818
819int mlx5_modify_port_cong_status(struct mlx5_core_dev *mdev, int protocol,
820				 int priority, int enable)
821{
822	u32 in[MLX5_ST_SZ_DW(modify_cong_status_in)];
823	u32 out[MLX5_ST_SZ_DW(modify_cong_status_out)];
824
825	memset(in, 0, sizeof(in));
826	memset(out, 0, sizeof(out));
827
828	MLX5_SET(modify_cong_status_in, in, opcode,
829		 MLX5_CMD_OP_MODIFY_CONG_STATUS);
830	MLX5_SET(modify_cong_status_in, in, cong_protocol, protocol);
831	MLX5_SET(modify_cong_status_in, in, priority, priority);
832	MLX5_SET(modify_cong_status_in, in, enable, enable);
833
834	return mlx5_cmd_exec_check_status(mdev, in, sizeof(in),
835					  out, sizeof(out));
836}
837
838int mlx5_query_port_cong_params(struct mlx5_core_dev *mdev, int protocol,
839				void *out, int out_size)
840{
841	u32 in[MLX5_ST_SZ_DW(query_cong_params_in)];
842
843	memset(in, 0, sizeof(in));
844
845	MLX5_SET(query_cong_params_in, in, opcode,
846		 MLX5_CMD_OP_QUERY_CONG_PARAMS);
847	MLX5_SET(query_cong_params_in, in, cong_protocol, protocol);
848
849	return mlx5_cmd_exec_check_status(mdev, in, sizeof(in),
850					  out, out_size);
851}
852
853static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out,
854				     int outlen)
855{
856	u32 in[MLX5_ST_SZ_DW(qtct_reg)];
857
858	if (!MLX5_CAP_GEN(mdev, ets))
859		return -ENOTSUPP;
860
861	memset(in, 0, sizeof(in));
862	return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen,
863				    MLX5_REG_QETCR, 0, 0);
864}
865
866int mlx5_max_tc(struct mlx5_core_dev *mdev)
867{
868	u8 num_tc = MLX5_CAP_GEN(mdev, max_tc) ? : 8;
869
870	return num_tc - 1;
871}
872EXPORT_SYMBOL_GPL(mlx5_max_tc);
873
874static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in,
875				   int inlen)
876{
877	u32 out[MLX5_ST_SZ_DW(qtct_reg)];
878
879	if (!MLX5_CAP_GEN(mdev, ets))
880		return -ENOTSUPP;
881
882	return mlx5_core_access_reg(mdev, in, inlen, out, sizeof(out),
883				    MLX5_REG_QETCR, 0, 1);
884}
885
886int mlx5_query_port_tc_rate_limit(struct mlx5_core_dev *mdev,
887				   u8 *max_bw_value,
888				   u8 *max_bw_units)
889{
890	u32 out[MLX5_ST_SZ_DW(qetc_reg)];
891	void *ets_tcn_conf;
892	int err;
893	int i;
894
895	err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
896	if (err)
897		return err;
898
899	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
900		ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, tc_configuration[i]);
901
902		max_bw_value[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
903					   max_bw_value);
904		max_bw_units[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
905					   max_bw_units);
906	}
907
908	return 0;
909}
910EXPORT_SYMBOL_GPL(mlx5_query_port_tc_rate_limit);
911
912int mlx5_modify_port_tc_rate_limit(struct mlx5_core_dev *mdev,
913				   const u8 *max_bw_value,
914				   const u8 *max_bw_units)
915{
916	u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {};
917	void *ets_tcn_conf;
918	int i;
919
920	MLX5_SET(qetc_reg, in, port_number, 1);
921
922	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
923		ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, in, tc_configuration[i]);
924
925		MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, r, 1);
926		MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_units,
927			 max_bw_units[i]);
928		MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_value,
929			 max_bw_value[i]);
930	}
931
932	return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
933}
934EXPORT_SYMBOL_GPL(mlx5_modify_port_tc_rate_limit);
935
936int mlx5_query_port_prio_tc(struct mlx5_core_dev *mdev,
937			    u8 prio, u8 *tc)
938{
939	u32 in[MLX5_ST_SZ_DW(qtct_reg)];
940	u32 out[MLX5_ST_SZ_DW(qtct_reg)];
941	int err;
942
943	memset(in, 0, sizeof(in));
944	memset(out, 0, sizeof(out));
945
946	MLX5_SET(qtct_reg, in, port_number, 1);
947	MLX5_SET(qtct_reg, in, prio, prio);
948
949	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
950				   sizeof(out), MLX5_REG_QTCT, 0, 0);
951	if (!err)
952		*tc = MLX5_GET(qtct_reg, out, tclass);
953
954	return err;
955}
956EXPORT_SYMBOL_GPL(mlx5_query_port_prio_tc);
957
958int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, int prio_index,
959			  const u8 prio_tc)
960{
961	u32 in[MLX5_ST_SZ_DW(qtct_reg)] = {};
962	u32 out[MLX5_ST_SZ_DW(qtct_reg)];
963	int err;
964
965	if (prio_tc > mlx5_max_tc(mdev))
966		return -EINVAL;
967
968	MLX5_SET(qtct_reg, in, prio, prio_index);
969	MLX5_SET(qtct_reg, in, tclass, prio_tc);
970
971	err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
972				   sizeof(out), MLX5_REG_QTCT, 0, 1);
973
974	return (err);
975}
976EXPORT_SYMBOL_GPL(mlx5_set_port_prio_tc);
977
978int mlx5_modify_port_cong_params(struct mlx5_core_dev *mdev,
979				 void *in, int in_size)
980{
981	u32 out[MLX5_ST_SZ_DW(modify_cong_params_out)];
982
983	memset(out, 0, sizeof(out));
984
985	MLX5_SET(modify_cong_params_in, in, opcode,
986		 MLX5_CMD_OP_MODIFY_CONG_PARAMS);
987
988	return mlx5_cmd_exec_check_status(mdev, in, in_size, out, sizeof(out));
989}
990
991int mlx5_query_port_cong_statistics(struct mlx5_core_dev *mdev, int clear,
992				    void *out, int out_size)
993{
994	u32 in[MLX5_ST_SZ_DW(query_cong_statistics_in)];
995
996	memset(in, 0, sizeof(in));
997
998	MLX5_SET(query_cong_statistics_in, in, opcode,
999		 MLX5_CMD_OP_QUERY_CONG_STATISTICS);
1000	MLX5_SET(query_cong_statistics_in, in, clear, clear);
1001
1002	return mlx5_cmd_exec_check_status(mdev, in, sizeof(in),
1003					  out, out_size);
1004}
1005
1006int mlx5_set_diagnostic_params(struct mlx5_core_dev *mdev, void *in,
1007			       int in_size)
1008{
1009	u32 out[MLX5_ST_SZ_DW(set_diagnostic_params_out)];
1010
1011	memset(out, 0, sizeof(out));
1012
1013	MLX5_SET(set_diagnostic_params_in, in, opcode,
1014		 MLX5_CMD_OP_SET_DIAGNOSTICS);
1015
1016	return mlx5_cmd_exec_check_status(mdev, in, in_size, out, sizeof(out));
1017}
1018
1019int mlx5_query_diagnostic_counters(struct mlx5_core_dev *mdev,
1020				   u8 num_of_samples, u16 sample_index,
1021				   void *out, int out_size)
1022{
1023	u32 in[MLX5_ST_SZ_DW(query_diagnostic_counters_in)];
1024
1025	memset(in, 0, sizeof(in));
1026
1027	MLX5_SET(query_diagnostic_counters_in, in, opcode,
1028		 MLX5_CMD_OP_QUERY_DIAGNOSTICS);
1029	MLX5_SET(query_diagnostic_counters_in, in, num_of_samples,
1030		 num_of_samples);
1031	MLX5_SET(query_diagnostic_counters_in, in, sample_index, sample_index);
1032
1033	return mlx5_cmd_exec_check_status(mdev, in, sizeof(in), out, out_size);
1034}
1035