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/10/sys/dev/mlx5/mlx5_core/mlx5_port.c 308684 2016-11-15 08:58:51Z hselasky $
26  */
27 
28 #include <linux/module.h>
29 #include <dev/mlx5/driver.h>
30 #include "mlx5_core.h"
31 
mlx5_core_access_reg(struct mlx5_core_dev * dev,void * data_in,int size_in,void * data_out,int size_out,u16 reg_num,int arg,int write)32 int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in,
33 			 int size_in, void *data_out, int size_out,
34 			 u16 reg_num, int arg, int write)
35 {
36 	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 
64 ex2:
65 	kvfree(out);
66 ex1:
67 	kvfree(in);
68 	return err;
69 }
70 EXPORT_SYMBOL_GPL(mlx5_core_access_reg);
71 
72 
73 struct 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 */
mlx5_toggle_port_link(struct mlx5_core_dev * dev)84 void 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 }
93 EXPORT_SYMBOL_GPL(mlx5_toggle_port_link);
94 
mlx5_set_port_caps(struct mlx5_core_dev * dev,u8 port_num,u32 caps)95 int 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 }
110 EXPORT_SYMBOL_GPL(mlx5_set_port_caps);
111 
mlx5_query_port_ptys(struct mlx5_core_dev * dev,u32 * ptys,int ptys_size,int proto_mask)112 int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys,
113 			 int ptys_size, int proto_mask)
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, 1);
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 }
127 EXPORT_SYMBOL_GPL(mlx5_query_port_ptys);
128 
mlx5_query_port_proto_cap(struct mlx5_core_dev * dev,u32 * proto_cap,int proto_mask)129 int 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);
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 }
146 EXPORT_SYMBOL_GPL(mlx5_query_port_proto_cap);
147 
mlx5_query_port_autoneg(struct mlx5_core_dev * dev,int proto_mask,u8 * an_disable_cap,u8 * an_disable_status)148 int 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);
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 }
163 EXPORT_SYMBOL_GPL(mlx5_query_port_autoneg);
164 
mlx5_set_port_autoneg(struct mlx5_core_dev * dev,bool disable,u32 eth_proto_admin,int proto_mask)165 int 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 }
193 EXPORT_SYMBOL_GPL(mlx5_set_port_autoneg);
194 
mlx5_query_port_proto_admin(struct mlx5_core_dev * dev,u32 * proto_admin,int proto_mask)195 int 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);
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 }
212 EXPORT_SYMBOL_GPL(mlx5_query_port_proto_admin);
213 
mlx5_set_port_proto(struct mlx5_core_dev * dev,u32 proto_admin,int proto_mask)214 int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin,
215 			int proto_mask)
216 {
217 	u32 in[MLX5_ST_SZ_DW(ptys_reg)];
218 	u32 out[MLX5_ST_SZ_DW(ptys_reg)];
219 	int err;
220 
221 	memset(in, 0, sizeof(in));
222 
223 	MLX5_SET(ptys_reg, in, local_port, 1);
224 	MLX5_SET(ptys_reg, in, proto_mask, proto_mask);
225 	if (proto_mask == MLX5_PTYS_EN)
226 		MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin);
227 	else
228 		MLX5_SET(ptys_reg, in, ib_proto_admin, proto_admin);
229 
230 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
231 				   sizeof(out), MLX5_REG_PTYS, 0, 1);
232 	return err;
233 }
234 EXPORT_SYMBOL_GPL(mlx5_set_port_proto);
235 
mlx5_set_port_status(struct mlx5_core_dev * dev,enum mlx5_port_status status)236 int mlx5_set_port_status(struct mlx5_core_dev *dev,
237 			 enum mlx5_port_status status)
238 {
239 	u32 in[MLX5_ST_SZ_DW(paos_reg)];
240 	u32 out[MLX5_ST_SZ_DW(paos_reg)];
241 	int err;
242 
243 	memset(in, 0, sizeof(in));
244 
245 	MLX5_SET(paos_reg, in, local_port, 1);
246 
247 	MLX5_SET(paos_reg, in, admin_status, status);
248 	MLX5_SET(paos_reg, in, ase, 1);
249 
250 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
251 				   sizeof(out), MLX5_REG_PAOS, 0, 1);
252 	return err;
253 }
254 
mlx5_query_port_status(struct mlx5_core_dev * dev,u8 * status)255 int mlx5_query_port_status(struct mlx5_core_dev *dev, u8 *status)
256 {
257 	u32 in[MLX5_ST_SZ_DW(paos_reg)];
258 	u32 out[MLX5_ST_SZ_DW(paos_reg)];
259 	int err;
260 
261 	memset(in, 0, sizeof(in));
262 
263 	MLX5_SET(paos_reg, in, local_port, 1);
264 
265 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
266 				   sizeof(out), MLX5_REG_PAOS, 0, 0);
267 	if (err)
268 		return err;
269 
270 	*status = MLX5_GET(paos_reg, out, oper_status);
271 	return err;
272 }
273 
mlx5_query_port_admin_status(struct mlx5_core_dev * dev,enum mlx5_port_status * status)274 int mlx5_query_port_admin_status(struct mlx5_core_dev *dev,
275 				 enum mlx5_port_status *status)
276 {
277 	u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0};
278 	u32 out[MLX5_ST_SZ_DW(paos_reg)];
279 	int err;
280 
281 	MLX5_SET(paos_reg, in, local_port, 1);
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 	*status = MLX5_GET(paos_reg, out, admin_status);
287 	return 0;
288 }
289 EXPORT_SYMBOL_GPL(mlx5_query_port_admin_status);
290 
mlx5_query_port_mtu(struct mlx5_core_dev * dev,int * admin_mtu,int * max_mtu,int * oper_mtu)291 static int mlx5_query_port_mtu(struct mlx5_core_dev *dev,
292 			       int *admin_mtu, int *max_mtu, int *oper_mtu)
293 {
294 	u32 in[MLX5_ST_SZ_DW(pmtu_reg)];
295 	u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
296 	int err;
297 
298 	memset(in, 0, sizeof(in));
299 
300 	MLX5_SET(pmtu_reg, in, local_port, 1);
301 
302 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
303 				   sizeof(out), MLX5_REG_PMTU, 0, 0);
304 	if (err)
305 		return err;
306 
307 	if (max_mtu)
308 		*max_mtu  = MLX5_GET(pmtu_reg, out, max_mtu);
309 	if (oper_mtu)
310 		*oper_mtu = MLX5_GET(pmtu_reg, out, oper_mtu);
311 	if (admin_mtu)
312 		*admin_mtu = MLX5_GET(pmtu_reg, out, admin_mtu);
313 
314 	return err;
315 }
316 
mlx5_set_port_mtu(struct mlx5_core_dev * dev,int mtu)317 int mlx5_set_port_mtu(struct mlx5_core_dev *dev, int mtu)
318 {
319 	u32 in[MLX5_ST_SZ_DW(pmtu_reg)];
320 	u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
321 
322 	memset(in, 0, sizeof(in));
323 
324 	MLX5_SET(pmtu_reg, in, admin_mtu, mtu);
325 	MLX5_SET(pmtu_reg, in, local_port, 1);
326 
327 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
328 				   sizeof(out), MLX5_REG_PMTU, 0, 1);
329 }
330 EXPORT_SYMBOL_GPL(mlx5_set_port_mtu);
331 
mlx5_query_port_max_mtu(struct mlx5_core_dev * dev,int * max_mtu)332 int mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, int *max_mtu)
333 {
334 	return mlx5_query_port_mtu(dev, NULL, max_mtu, NULL);
335 }
336 EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu);
337 
mlx5_set_port_pause(struct mlx5_core_dev * dev,u32 port,u32 rx_pause,u32 tx_pause)338 int mlx5_set_port_pause(struct mlx5_core_dev *dev, u32 port,
339 			u32 rx_pause, u32 tx_pause)
340 {
341 	u32 in[MLX5_ST_SZ_DW(pfcc_reg)];
342 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
343 
344 	memset(in, 0, sizeof(in));
345 	memset(out, 0, sizeof(out));
346 
347 	MLX5_SET(pfcc_reg, in, local_port, port);
348 	MLX5_SET(pfcc_reg, in, pptx, tx_pause);
349 	MLX5_SET(pfcc_reg, in, pprx, rx_pause);
350 
351 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
352 				   sizeof(out), MLX5_REG_PFCC, 0, 1);
353 }
354 
mlx5_query_port_pause(struct mlx5_core_dev * dev,u32 port,u32 * rx_pause,u32 * tx_pause)355 int mlx5_query_port_pause(struct mlx5_core_dev *dev, u32 port,
356 			  u32 *rx_pause, u32 *tx_pause)
357 {
358 	u32 in[MLX5_ST_SZ_DW(pfcc_reg)];
359 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
360 	int err;
361 
362 	memset(in, 0, sizeof(in));
363 	memset(out, 0, sizeof(out));
364 
365 	MLX5_SET(pfcc_reg, in, local_port, port);
366 
367 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
368 				   sizeof(out), MLX5_REG_PFCC, 0, 0);
369 	if (err)
370 		return err;
371 
372 	*rx_pause = MLX5_GET(pfcc_reg, out, pprx);
373 	*tx_pause = MLX5_GET(pfcc_reg, out, pptx);
374 
375 	return 0;
376 }
377 
mlx5_set_port_pfc(struct mlx5_core_dev * dev,u8 pfc_en_tx,u8 pfc_en_rx)378 int mlx5_set_port_pfc(struct mlx5_core_dev *dev, u8 pfc_en_tx, u8 pfc_en_rx)
379 {
380 	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
381 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
382 
383 	MLX5_SET(pfcc_reg, in, local_port, 1);
384 	MLX5_SET(pfcc_reg, in, pfctx, pfc_en_tx);
385 	MLX5_SET(pfcc_reg, in, pfcrx, pfc_en_rx);
386 	MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_tx);
387 	MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_rx);
388 
389 	return mlx5_core_access_reg(dev, in, sizeof(in), out,
390 				    sizeof(out), MLX5_REG_PFCC, 0, 1);
391 }
392 EXPORT_SYMBOL_GPL(mlx5_set_port_pfc);
393 
mlx5_query_port_pfc(struct mlx5_core_dev * dev,u8 * pfc_en_tx,u8 * pfc_en_rx)394 int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx, u8 *pfc_en_rx)
395 {
396 	u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
397 	u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
398 	int err;
399 
400 	MLX5_SET(pfcc_reg, in, local_port, 1);
401 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
402 				   sizeof(out), MLX5_REG_PFCC, 0, 0);
403 	if (err)
404 		return err;
405 
406 	if (pfc_en_tx)
407 		*pfc_en_tx = MLX5_GET(pfcc_reg, out, pfctx);
408 
409 	if (pfc_en_rx)
410 		*pfc_en_rx = MLX5_GET(pfcc_reg, out, pfcrx);
411 
412 	return 0;
413 }
414 EXPORT_SYMBOL_GPL(mlx5_query_port_pfc);
415 
mlx5_query_port_oper_mtu(struct mlx5_core_dev * dev,int * oper_mtu)416 int mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, int *oper_mtu)
417 {
418 	return mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu);
419 }
420 EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu);
421 
mlx5_is_wol_supported(struct mlx5_core_dev * dev)422 u8 mlx5_is_wol_supported(struct mlx5_core_dev *dev)
423 {
424 	u8 wol_supported = 0;
425 
426 	if (MLX5_CAP_GEN(dev, wol_s))
427 		wol_supported |= MLX5_WOL_SECURED_MAGIC;
428 	if (MLX5_CAP_GEN(dev, wol_g))
429 		wol_supported |= MLX5_WOL_MAGIC;
430 	if (MLX5_CAP_GEN(dev, wol_a))
431 		wol_supported |= MLX5_WOL_ARP;
432 	if (MLX5_CAP_GEN(dev, wol_b))
433 		wol_supported |= MLX5_WOL_BROADCAST;
434 	if (MLX5_CAP_GEN(dev, wol_m))
435 		wol_supported |= MLX5_WOL_MULTICAST;
436 	if (MLX5_CAP_GEN(dev, wol_u))
437 		wol_supported |= MLX5_WOL_UNICAST;
438 	if (MLX5_CAP_GEN(dev, wol_p))
439 		wol_supported |= MLX5_WOL_PHY_ACTIVITY;
440 
441 	return wol_supported;
442 }
443 EXPORT_SYMBOL_GPL(mlx5_is_wol_supported);
444 
mlx5_set_wol(struct mlx5_core_dev * dev,u8 wol_mode)445 int mlx5_set_wol(struct mlx5_core_dev *dev, u8 wol_mode)
446 {
447 	u32 in[MLX5_ST_SZ_DW(set_wol_rol_in)];
448 	u32 out[MLX5_ST_SZ_DW(set_wol_rol_out)];
449 
450 	memset(in, 0, sizeof(in));
451 	memset(out, 0, sizeof(out));
452 
453 	MLX5_SET(set_wol_rol_in, in, opcode, MLX5_CMD_OP_SET_WOL_ROL);
454 	MLX5_SET(set_wol_rol_in, in, wol_mode_valid, 1);
455 	MLX5_SET(set_wol_rol_in, in, wol_mode, wol_mode);
456 
457 	return mlx5_cmd_exec_check_status(dev, in, sizeof(in),
458 					  out, sizeof(out));
459 }
460 EXPORT_SYMBOL_GPL(mlx5_set_wol);
461 
mlx5_core_access_pvlc(struct mlx5_core_dev * dev,struct mlx5_pvlc_reg * pvlc,int write)462 int mlx5_core_access_pvlc(struct mlx5_core_dev *dev,
463 			  struct mlx5_pvlc_reg *pvlc, int write)
464 {
465 	int sz = MLX5_ST_SZ_BYTES(pvlc_reg);
466 	u8 in[MLX5_ST_SZ_BYTES(pvlc_reg)];
467 	u8 out[MLX5_ST_SZ_BYTES(pvlc_reg)];
468 	int err;
469 
470 	memset(out, 0, sizeof(out));
471 	memset(in, 0, sizeof(in));
472 
473 	MLX5_SET(pvlc_reg, in, local_port, pvlc->local_port);
474 	if (write)
475 		MLX5_SET(pvlc_reg, in, vl_admin, pvlc->vl_admin);
476 
477 	err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PVLC, 0,
478 				   !!write);
479 	if (err)
480 		return err;
481 
482 	if (!write) {
483 		pvlc->local_port = MLX5_GET(pvlc_reg, out, local_port);
484 		pvlc->vl_hw_cap = MLX5_GET(pvlc_reg, out, vl_hw_cap);
485 		pvlc->vl_admin = MLX5_GET(pvlc_reg, out, vl_admin);
486 		pvlc->vl_operational = MLX5_GET(pvlc_reg, out, vl_operational);
487 	}
488 
489 	return 0;
490 }
491 EXPORT_SYMBOL_GPL(mlx5_core_access_pvlc);
492 
mlx5_core_access_ptys(struct mlx5_core_dev * dev,struct mlx5_ptys_reg * ptys,int write)493 int mlx5_core_access_ptys(struct mlx5_core_dev *dev,
494 			  struct mlx5_ptys_reg *ptys, int write)
495 {
496 	int sz = MLX5_ST_SZ_BYTES(ptys_reg);
497 	void *out = NULL;
498 	void *in = NULL;
499 	int err;
500 
501 	in = mlx5_vzalloc(sz);
502 	if (!in)
503 		return -ENOMEM;
504 
505 	out = mlx5_vzalloc(sz);
506 	if (!out) {
507 		kfree(in);
508 		return -ENOMEM;
509 	}
510 
511 	MLX5_SET(ptys_reg, in, local_port, ptys->local_port);
512 	MLX5_SET(ptys_reg, in, proto_mask, ptys->proto_mask);
513 	if (write) {
514 		MLX5_SET(ptys_reg, in, eth_proto_capability,
515 			 ptys->eth_proto_cap);
516 		MLX5_SET(ptys_reg, in, ib_link_width_capability,
517 			 ptys->ib_link_width_cap);
518 		MLX5_SET(ptys_reg, in, ib_proto_capability,
519 			 ptys->ib_proto_cap);
520 		MLX5_SET(ptys_reg, in, eth_proto_admin, ptys->eth_proto_admin);
521 		MLX5_SET(ptys_reg, in, ib_link_width_admin,
522 			 ptys->ib_link_width_admin);
523 		MLX5_SET(ptys_reg, in, ib_proto_admin, ptys->ib_proto_admin);
524 		MLX5_SET(ptys_reg, in, eth_proto_oper, ptys->eth_proto_oper);
525 		MLX5_SET(ptys_reg, in, ib_link_width_oper,
526 			 ptys->ib_link_width_oper);
527 		MLX5_SET(ptys_reg, in, ib_proto_oper, ptys->ib_proto_oper);
528 		MLX5_SET(ptys_reg, in, eth_proto_lp_advertise,
529 			 ptys->eth_proto_lp_advertise);
530 	}
531 
532 	err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PTYS, 0,
533 				   !!write);
534 	if (err)
535 		goto out;
536 
537 	if (!write) {
538 		ptys->local_port = MLX5_GET(ptys_reg, out, local_port);
539 		ptys->proto_mask = MLX5_GET(ptys_reg, out, proto_mask);
540 		ptys->eth_proto_cap = MLX5_GET(ptys_reg, out,
541 					       eth_proto_capability);
542 		ptys->ib_link_width_cap = MLX5_GET(ptys_reg, out,
543 					   ib_link_width_capability);
544 		ptys->ib_proto_cap = MLX5_GET(ptys_reg, out,
545 					      ib_proto_capability);
546 		ptys->eth_proto_admin = MLX5_GET(ptys_reg, out,
547 						 eth_proto_admin);
548 		ptys->ib_link_width_admin = MLX5_GET(ptys_reg, out,
549 						     ib_link_width_admin);
550 		ptys->ib_proto_admin = MLX5_GET(ptys_reg, out, ib_proto_admin);
551 		ptys->eth_proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper);
552 		ptys->ib_link_width_oper = MLX5_GET(ptys_reg, out,
553 						    ib_link_width_oper);
554 		ptys->ib_proto_oper = MLX5_GET(ptys_reg, out, ib_proto_oper);
555 		ptys->eth_proto_lp_advertise = MLX5_GET(ptys_reg, out,
556 							eth_proto_lp_advertise);
557 	}
558 
559 out:
560 	kvfree(in);
561 	kvfree(out);
562 	return err;
563 }
564 EXPORT_SYMBOL_GPL(mlx5_core_access_ptys);
565 
mtu_to_ib_mtu(int mtu)566 static int mtu_to_ib_mtu(int mtu)
567 {
568 	switch (mtu) {
569 	case 256: return 1;
570 	case 512: return 2;
571 	case 1024: return 3;
572 	case 2048: return 4;
573 	case 4096: return 5;
574 	default:
575 		printf("mlx5_core: WARN: ""invalid mtu\n");
576 		return -1;
577 	}
578 }
579 
mlx5_core_access_pmtu(struct mlx5_core_dev * dev,struct mlx5_pmtu_reg * pmtu,int write)580 int mlx5_core_access_pmtu(struct mlx5_core_dev *dev,
581 			  struct mlx5_pmtu_reg *pmtu, int write)
582 {
583 	int sz = MLX5_ST_SZ_BYTES(pmtu_reg);
584 	void *out = NULL;
585 	void *in = NULL;
586 	int err;
587 
588 	in = mlx5_vzalloc(sz);
589 	if (!in)
590 		return -ENOMEM;
591 
592 	out = mlx5_vzalloc(sz);
593 	if (!out) {
594 		kfree(in);
595 		return -ENOMEM;
596 	}
597 
598 	MLX5_SET(pmtu_reg, in, local_port, pmtu->local_port);
599 	if (write)
600 		MLX5_SET(pmtu_reg, in, admin_mtu, pmtu->admin_mtu);
601 
602 	err = mlx5_core_access_reg(dev, in, sz, out, sz, MLX5_REG_PMTU, 0,
603 				   !!write);
604 	if (err)
605 		goto out;
606 
607 	if (!write) {
608 		pmtu->local_port = MLX5_GET(pmtu_reg, out, local_port);
609 		pmtu->max_mtu = mtu_to_ib_mtu(MLX5_GET(pmtu_reg, out,
610 						       max_mtu));
611 		pmtu->admin_mtu = mtu_to_ib_mtu(MLX5_GET(pmtu_reg, out,
612 							 admin_mtu));
613 		pmtu->oper_mtu = mtu_to_ib_mtu(MLX5_GET(pmtu_reg, out,
614 							oper_mtu));
615 	}
616 
617 out:
618 	kvfree(in);
619 	kvfree(out);
620 	return err;
621 }
622 EXPORT_SYMBOL_GPL(mlx5_core_access_pmtu);
623 
mlx5_query_module_num(struct mlx5_core_dev * dev,int * module_num)624 int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num)
625 {
626 	u32 in[MLX5_ST_SZ_DW(pmlp_reg)];
627 	u32 out[MLX5_ST_SZ_DW(pmlp_reg)];
628 	int lane = 0;
629 	int err;
630 
631 	memset(in, 0, sizeof(in));
632 
633 	MLX5_SET(pmlp_reg, in, local_port, 1);
634 
635 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
636 				   sizeof(out), MLX5_REG_PMLP, 0, 0);
637 	if (err)
638 		return err;
639 
640 	lane = MLX5_GET(pmlp_reg, out, lane0_module_mapping);
641 	*module_num = lane & MLX5_EEPROM_IDENTIFIER_BYTE_MASK;
642 
643 	return 0;
644 }
645 EXPORT_SYMBOL_GPL(mlx5_query_module_num);
646 
mlx5_query_eeprom(struct mlx5_core_dev * dev,int i2c_addr,int page_num,int device_addr,int size,int module_num,u32 * data,int * size_read)647 int mlx5_query_eeprom(struct mlx5_core_dev *dev,
648 		      int i2c_addr, int page_num, int device_addr,
649 		      int size, int module_num, u32 *data, int *size_read)
650 {
651 	u32 in[MLX5_ST_SZ_DW(mcia_reg)];
652 	u32 out[MLX5_ST_SZ_DW(mcia_reg)];
653 	u32 *ptr = (u32 *)MLX5_ADDR_OF(mcia_reg, out, dword_0);
654 	int status;
655 	int err;
656 
657 	memset(in, 0, sizeof(in));
658 	size = min_t(int, size, MLX5_EEPROM_MAX_BYTES);
659 
660 	MLX5_SET(mcia_reg, in, l, 0);
661 	MLX5_SET(mcia_reg, in, module, module_num);
662 	MLX5_SET(mcia_reg, in, i2c_device_address, i2c_addr);
663 	MLX5_SET(mcia_reg, in, page_number, page_num);
664 	MLX5_SET(mcia_reg, in, device_address, device_addr);
665 	MLX5_SET(mcia_reg, in, size, size);
666 
667 	err = mlx5_core_access_reg(dev, in, sizeof(in), out,
668 				   sizeof(out), MLX5_REG_MCIA, 0, 0);
669 	if (err)
670 		return err;
671 
672 	status = MLX5_GET(mcia_reg, out, status);
673 	if (status)
674 		return status;
675 
676 	memcpy(data, ptr, size);
677 	*size_read = size;
678 	return 0;
679 }
680 EXPORT_SYMBOL_GPL(mlx5_query_eeprom);
681 
mlx5_vxlan_udp_port_add(struct mlx5_core_dev * dev,u16 port)682 int mlx5_vxlan_udp_port_add(struct mlx5_core_dev *dev, u16 port)
683 {
684 	u32 in[MLX5_ST_SZ_DW(add_vxlan_udp_dport_in)];
685 	u32 out[MLX5_ST_SZ_DW(add_vxlan_udp_dport_out)];
686 	int err;
687 
688 	memset(in, 0, sizeof(in));
689 	memset(out, 0, sizeof(out));
690 
691 	MLX5_SET(add_vxlan_udp_dport_in, in, opcode,
692 		 MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT);
693 	MLX5_SET(add_vxlan_udp_dport_in, in, vxlan_udp_port, port);
694 
695 	err = mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out));
696 	if (err) {
697 		mlx5_core_err(dev, "Failed %s, port %u, err - %d",
698 			      mlx5_command_str(MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT),
699 			      port, err);
700 	}
701 
702 	return err;
703 }
704 
mlx5_vxlan_udp_port_delete(struct mlx5_core_dev * dev,u16 port)705 int mlx5_vxlan_udp_port_delete(struct mlx5_core_dev *dev, u16 port)
706 {
707 	u32 in[MLX5_ST_SZ_DW(delete_vxlan_udp_dport_in)];
708 	u32 out[MLX5_ST_SZ_DW(delete_vxlan_udp_dport_out)];
709 	int err;
710 
711 	memset(in, 0, sizeof(in));
712 	memset(out, 0, sizeof(out));
713 
714 	MLX5_SET(delete_vxlan_udp_dport_in, in, opcode,
715 		 MLX5_CMD_OP_DELETE_VXLAN_UDP_DPORT);
716 	MLX5_SET(delete_vxlan_udp_dport_in, in, vxlan_udp_port, port);
717 
718 	err = mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out));
719 	if (err) {
720 		mlx5_core_err(dev, "Failed %s, port %u, err - %d",
721 			      mlx5_command_str(MLX5_CMD_OP_DELETE_VXLAN_UDP_DPORT),
722 			      port, err);
723 	}
724 
725 	return err;
726 }
727 
mlx5_query_wol(struct mlx5_core_dev * dev,u8 * wol_mode)728 int mlx5_query_wol(struct mlx5_core_dev *dev, u8 *wol_mode)
729 {
730 	u32 in[MLX5_ST_SZ_DW(query_wol_rol_in)];
731 	u32 out[MLX5_ST_SZ_DW(query_wol_rol_out)];
732 	int err;
733 
734 	memset(in, 0, sizeof(in));
735 	memset(out, 0, sizeof(out));
736 
737 	MLX5_SET(query_wol_rol_in, in, opcode, MLX5_CMD_OP_QUERY_WOL_ROL);
738 
739 	err = mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out));
740 
741 	if (!err)
742 		*wol_mode = MLX5_GET(query_wol_rol_out, out, wol_mode);
743 
744 	return err;
745 }
746 EXPORT_SYMBOL_GPL(mlx5_query_wol);
747 
mlx5_query_port_cong_status(struct mlx5_core_dev * mdev,int protocol,int priority,int * is_enable)748 int mlx5_query_port_cong_status(struct mlx5_core_dev *mdev, int protocol,
749 				int priority, int *is_enable)
750 {
751 	u32 in[MLX5_ST_SZ_DW(query_cong_status_in)];
752 	u32 out[MLX5_ST_SZ_DW(query_cong_status_out)];
753 	int err;
754 
755 	memset(in, 0, sizeof(in));
756 	memset(out, 0, sizeof(out));
757 
758 	*is_enable = 0;
759 
760 	MLX5_SET(query_cong_status_in, in, opcode,
761 		 MLX5_CMD_OP_QUERY_CONG_STATUS);
762 	MLX5_SET(query_cong_status_in, in, cong_protocol, protocol);
763 	MLX5_SET(query_cong_status_in, in, priority, priority);
764 
765 	err = mlx5_cmd_exec_check_status(mdev, in, sizeof(in),
766 					 out, sizeof(out));
767 	if (!err)
768 		*is_enable = MLX5_GET(query_cong_status_out, out, enable);
769 	return err;
770 }
771 
mlx5_modify_port_cong_status(struct mlx5_core_dev * mdev,int protocol,int priority,int enable)772 int mlx5_modify_port_cong_status(struct mlx5_core_dev *mdev, int protocol,
773 				 int priority, int enable)
774 {
775 	u32 in[MLX5_ST_SZ_DW(modify_cong_status_in)];
776 	u32 out[MLX5_ST_SZ_DW(modify_cong_status_out)];
777 
778 	memset(in, 0, sizeof(in));
779 	memset(out, 0, sizeof(out));
780 
781 	MLX5_SET(modify_cong_status_in, in, opcode,
782 		 MLX5_CMD_OP_MODIFY_CONG_STATUS);
783 	MLX5_SET(modify_cong_status_in, in, cong_protocol, protocol);
784 	MLX5_SET(modify_cong_status_in, in, priority, priority);
785 	MLX5_SET(modify_cong_status_in, in, enable, enable);
786 
787 	return mlx5_cmd_exec_check_status(mdev, in, sizeof(in),
788 					  out, sizeof(out));
789 }
790 
mlx5_query_port_cong_params(struct mlx5_core_dev * mdev,int protocol,void * out,int out_size)791 int mlx5_query_port_cong_params(struct mlx5_core_dev *mdev, int protocol,
792 				void *out, int out_size)
793 {
794 	u32 in[MLX5_ST_SZ_DW(query_cong_params_in)];
795 
796 	memset(in, 0, sizeof(in));
797 
798 	MLX5_SET(query_cong_params_in, in, opcode,
799 		 MLX5_CMD_OP_QUERY_CONG_PARAMS);
800 	MLX5_SET(query_cong_params_in, in, cong_protocol, protocol);
801 
802 	return mlx5_cmd_exec_check_status(mdev, in, sizeof(in),
803 					  out, out_size);
804 }
805 
mlx5_modify_port_cong_params(struct mlx5_core_dev * mdev,void * in,int in_size)806 int mlx5_modify_port_cong_params(struct mlx5_core_dev *mdev,
807 				 void *in, int in_size)
808 {
809 	u32 out[MLX5_ST_SZ_DW(modify_cong_params_out)];
810 
811 	memset(out, 0, sizeof(out));
812 
813 	MLX5_SET(modify_cong_params_in, in, opcode,
814 		 MLX5_CMD_OP_MODIFY_CONG_PARAMS);
815 
816 	return mlx5_cmd_exec_check_status(mdev, in, in_size, out, sizeof(out));
817 }
818 
mlx5_query_port_cong_statistics(struct mlx5_core_dev * mdev,int clear,void * out,int out_size)819 int mlx5_query_port_cong_statistics(struct mlx5_core_dev *mdev, int clear,
820 				    void *out, int out_size)
821 {
822 	u32 in[MLX5_ST_SZ_DW(query_cong_statistics_in)];
823 
824 	memset(in, 0, sizeof(in));
825 
826 	MLX5_SET(query_cong_statistics_in, in, opcode,
827 		 MLX5_CMD_OP_QUERY_CONG_STATISTICS);
828 	MLX5_SET(query_cong_statistics_in, in, clear, clear);
829 
830 	return mlx5_cmd_exec_check_status(mdev, in, sizeof(in),
831 					  out, out_size);
832 }
833 
mlx5_set_diagnostic_params(struct mlx5_core_dev * mdev,void * in,int in_size)834 int mlx5_set_diagnostic_params(struct mlx5_core_dev *mdev, void *in,
835 			       int in_size)
836 {
837 	u32 out[MLX5_ST_SZ_DW(set_diagnostic_params_out)];
838 
839 	memset(out, 0, sizeof(out));
840 
841 	MLX5_SET(set_diagnostic_params_in, in, opcode,
842 		 MLX5_CMD_OP_SET_DIAGNOSTICS);
843 
844 	return mlx5_cmd_exec_check_status(mdev, in, in_size, out, sizeof(out));
845 }
846 
mlx5_query_diagnostic_counters(struct mlx5_core_dev * mdev,u8 num_of_samples,u16 sample_index,void * out,int out_size)847 int mlx5_query_diagnostic_counters(struct mlx5_core_dev *mdev,
848 				   u8 num_of_samples, u16 sample_index,
849 				   void *out, int out_size)
850 {
851 	u32 in[MLX5_ST_SZ_DW(query_diagnostic_counters_in)];
852 
853 	memset(in, 0, sizeof(in));
854 
855 	MLX5_SET(query_diagnostic_counters_in, in, opcode,
856 		 MLX5_CMD_OP_QUERY_DIAGNOSTICS);
857 	MLX5_SET(query_diagnostic_counters_in, in, num_of_samples,
858 		 num_of_samples);
859 	MLX5_SET(query_diagnostic_counters_in, in, sample_index, sample_index);
860 
861 	return mlx5_cmd_exec_check_status(mdev, in, sizeof(in), out, out_size);
862 }
863