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