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