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