1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33#include <linux/module.h>
34#include <linux/mlx5/driver.h>
35#include <linux/mlx5/port.h>
36#include <linux/mlx5/cmd.h>
37#include "mlx5_core.h"
38
39int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in,
40 int size_in, void *data_out, int size_out,
41 u16 reg_id, int arg, int write)
42{
43 int outlen = MLX5_ST_SZ_BYTES(access_register_out) + size_out;
44 int inlen = MLX5_ST_SZ_BYTES(access_register_in) + size_in;
45 int err = -ENOMEM;
46 u32 *out = NULL;
47 u32 *in = NULL;
48 void *data;
49
50 in = kvzalloc(inlen, GFP_KERNEL);
51 out = kvzalloc(outlen, GFP_KERNEL);
52 if (!in || !out)
53 goto out;
54
55 data = MLX5_ADDR_OF(access_register_in, in, register_data);
56 memcpy(data, data_in, size_in);
57
58 MLX5_SET(access_register_in, in, opcode, MLX5_CMD_OP_ACCESS_REG);
59 MLX5_SET(access_register_in, in, op_mod, !write);
60 MLX5_SET(access_register_in, in, argument, arg);
61 MLX5_SET(access_register_in, in, register_id, reg_id);
62
63 err = mlx5_cmd_exec(dev, in, inlen, out, outlen);
64 if (err)
65 goto out;
66
67 data = MLX5_ADDR_OF(access_register_out, out, register_data);
68 memcpy(data_out, data, size_out);
69
70out:
71 kvfree(out);
72 kvfree(in);
73 return err;
74}
75EXPORT_SYMBOL_GPL(mlx5_core_access_reg);
76
77int mlx5_query_pcam_reg(struct mlx5_core_dev *dev, u32 *pcam, u8 feature_group,
78 u8 access_reg_group)
79{
80 u32 in[MLX5_ST_SZ_DW(pcam_reg)] = {0};
81 int sz = MLX5_ST_SZ_BYTES(pcam_reg);
82
83 MLX5_SET(pcam_reg, in, feature_group, feature_group);
84 MLX5_SET(pcam_reg, in, access_reg_group, access_reg_group);
85
86 return mlx5_core_access_reg(dev, in, sz, pcam, sz, MLX5_REG_PCAM, 0, 0);
87}
88
89int mlx5_query_mcam_reg(struct mlx5_core_dev *dev, u32 *mcam, u8 feature_group,
90 u8 access_reg_group)
91{
92 u32 in[MLX5_ST_SZ_DW(mcam_reg)] = {0};
93 int sz = MLX5_ST_SZ_BYTES(mcam_reg);
94
95 MLX5_SET(mcam_reg, in, feature_group, feature_group);
96 MLX5_SET(mcam_reg, in, access_reg_group, access_reg_group);
97
98 return mlx5_core_access_reg(dev, in, sz, mcam, sz, MLX5_REG_MCAM, 0, 0);
99}
100
101struct mlx5_reg_pcap {
102 u8 rsvd0;
103 u8 port_num;
104 u8 rsvd1[2];
105 __be32 caps_127_96;
106 __be32 caps_95_64;
107 __be32 caps_63_32;
108 __be32 caps_31_0;
109};
110
111int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps)
112{
113 struct mlx5_reg_pcap in;
114 struct mlx5_reg_pcap out;
115
116 memset(&in, 0, sizeof(in));
117 in.caps_127_96 = cpu_to_be32(caps);
118 in.port_num = port_num;
119
120 return mlx5_core_access_reg(dev, &in, sizeof(in), &out,
121 sizeof(out), MLX5_REG_PCAP, 0, 1);
122}
123EXPORT_SYMBOL_GPL(mlx5_set_port_caps);
124
125int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys,
126 int ptys_size, int proto_mask, u8 local_port)
127{
128 u32 in[MLX5_ST_SZ_DW(ptys_reg)] = {0};
129
130 MLX5_SET(ptys_reg, in, local_port, local_port);
131 MLX5_SET(ptys_reg, in, proto_mask, proto_mask);
132 return mlx5_core_access_reg(dev, in, sizeof(in), ptys,
133 ptys_size, MLX5_REG_PTYS, 0, 0);
134}
135EXPORT_SYMBOL_GPL(mlx5_query_port_ptys);
136
137int mlx5_set_port_beacon(struct mlx5_core_dev *dev, u16 beacon_duration)
138{
139 u32 in[MLX5_ST_SZ_DW(mlcr_reg)] = {0};
140 u32 out[MLX5_ST_SZ_DW(mlcr_reg)];
141
142 MLX5_SET(mlcr_reg, in, local_port, 1);
143 MLX5_SET(mlcr_reg, in, beacon_duration, beacon_duration);
144 return mlx5_core_access_reg(dev, in, sizeof(in), out,
145 sizeof(out), MLX5_REG_MLCR, 0, 1);
146}
147
148int mlx5_query_port_proto_cap(struct mlx5_core_dev *dev,
149 u32 *proto_cap, int proto_mask)
150{
151 u32 out[MLX5_ST_SZ_DW(ptys_reg)];
152 int err;
153
154 err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1);
155 if (err)
156 return err;
157
158 if (proto_mask == MLX5_PTYS_EN)
159 *proto_cap = MLX5_GET(ptys_reg, out, eth_proto_capability);
160 else
161 *proto_cap = MLX5_GET(ptys_reg, out, ib_proto_capability);
162
163 return 0;
164}
165EXPORT_SYMBOL_GPL(mlx5_query_port_proto_cap);
166
167int mlx5_query_port_proto_admin(struct mlx5_core_dev *dev,
168 u32 *proto_admin, int proto_mask)
169{
170 u32 out[MLX5_ST_SZ_DW(ptys_reg)];
171 int err;
172
173 err = mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1);
174 if (err)
175 return err;
176
177 if (proto_mask == MLX5_PTYS_EN)
178 *proto_admin = MLX5_GET(ptys_reg, out, eth_proto_admin);
179 else
180 *proto_admin = MLX5_GET(ptys_reg, out, ib_proto_admin);
181
182 return 0;
183}
184EXPORT_SYMBOL_GPL(mlx5_query_port_proto_admin);
185
186int mlx5_query_port_link_width_oper(struct mlx5_core_dev *dev,
187 u8 *link_width_oper, u8 local_port)
188{
189 u32 out[MLX5_ST_SZ_DW(ptys_reg)];
190 int err;
191
192 err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_IB, local_port);
193 if (err)
194 return err;
195
196 *link_width_oper = MLX5_GET(ptys_reg, out, ib_link_width_oper);
197
198 return 0;
199}
200EXPORT_SYMBOL_GPL(mlx5_query_port_link_width_oper);
201
202int mlx5_query_port_eth_proto_oper(struct mlx5_core_dev *dev,
203 u32 *proto_oper, u8 local_port)
204{
205 u32 out[MLX5_ST_SZ_DW(ptys_reg)];
206 int err;
207
208 err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_EN,
209 local_port);
210 if (err)
211 return err;
212
213 *proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper);
214
215 return 0;
216}
217EXPORT_SYMBOL(mlx5_query_port_eth_proto_oper);
218
219int mlx5_query_port_ib_proto_oper(struct mlx5_core_dev *dev,
220 u8 *proto_oper, u8 local_port)
221{
222 u32 out[MLX5_ST_SZ_DW(ptys_reg)];
223 int err;
224
225 err = mlx5_query_port_ptys(dev, out, sizeof(out), MLX5_PTYS_IB,
226 local_port);
227 if (err)
228 return err;
229
230 *proto_oper = MLX5_GET(ptys_reg, out, ib_proto_oper);
231
232 return 0;
233}
234EXPORT_SYMBOL(mlx5_query_port_ib_proto_oper);
235
236int mlx5_set_port_ptys(struct mlx5_core_dev *dev, bool an_disable,
237 u32 proto_admin, int proto_mask)
238{
239 u32 out[MLX5_ST_SZ_DW(ptys_reg)];
240 u32 in[MLX5_ST_SZ_DW(ptys_reg)];
241 u8 an_disable_admin;
242 u8 an_disable_cap;
243 u8 an_status;
244
245 mlx5_query_port_autoneg(dev, proto_mask, &an_status,
246 &an_disable_cap, &an_disable_admin);
247 if (!an_disable_cap && an_disable)
248 return -EPERM;
249
250 memset(in, 0, sizeof(in));
251
252 MLX5_SET(ptys_reg, in, local_port, 1);
253 MLX5_SET(ptys_reg, in, an_disable_admin, an_disable);
254 MLX5_SET(ptys_reg, in, proto_mask, proto_mask);
255 if (proto_mask == MLX5_PTYS_EN)
256 MLX5_SET(ptys_reg, in, eth_proto_admin, proto_admin);
257 else
258 MLX5_SET(ptys_reg, in, ib_proto_admin, proto_admin);
259
260 return mlx5_core_access_reg(dev, in, sizeof(in), out,
261 sizeof(out), MLX5_REG_PTYS, 0, 1);
262}
263EXPORT_SYMBOL_GPL(mlx5_set_port_ptys);
264
265
266void mlx5_toggle_port_link(struct mlx5_core_dev *dev)
267{
268 enum mlx5_port_status ps;
269
270 mlx5_query_port_admin_status(dev, &ps);
271 mlx5_set_port_admin_status(dev, MLX5_PORT_DOWN);
272 if (ps == MLX5_PORT_UP)
273 mlx5_set_port_admin_status(dev, MLX5_PORT_UP);
274}
275EXPORT_SYMBOL_GPL(mlx5_toggle_port_link);
276
277int mlx5_set_port_admin_status(struct mlx5_core_dev *dev,
278 enum mlx5_port_status status)
279{
280 u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0};
281 u32 out[MLX5_ST_SZ_DW(paos_reg)];
282
283 MLX5_SET(paos_reg, in, local_port, 1);
284 MLX5_SET(paos_reg, in, admin_status, status);
285 MLX5_SET(paos_reg, in, ase, 1);
286 return mlx5_core_access_reg(dev, in, sizeof(in), out,
287 sizeof(out), MLX5_REG_PAOS, 0, 1);
288}
289EXPORT_SYMBOL_GPL(mlx5_set_port_admin_status);
290
291int mlx5_query_port_admin_status(struct mlx5_core_dev *dev,
292 enum mlx5_port_status *status)
293{
294 u32 in[MLX5_ST_SZ_DW(paos_reg)] = {0};
295 u32 out[MLX5_ST_SZ_DW(paos_reg)];
296 int err;
297
298 MLX5_SET(paos_reg, in, local_port, 1);
299 err = mlx5_core_access_reg(dev, in, sizeof(in), out,
300 sizeof(out), MLX5_REG_PAOS, 0, 0);
301 if (err)
302 return err;
303 *status = MLX5_GET(paos_reg, out, admin_status);
304 return 0;
305}
306EXPORT_SYMBOL_GPL(mlx5_query_port_admin_status);
307
308static void mlx5_query_port_mtu(struct mlx5_core_dev *dev, u16 *admin_mtu,
309 u16 *max_mtu, u16 *oper_mtu, u8 port)
310{
311 u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
312 u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
313
314 MLX5_SET(pmtu_reg, in, local_port, port);
315 mlx5_core_access_reg(dev, in, sizeof(in), out,
316 sizeof(out), MLX5_REG_PMTU, 0, 0);
317
318 if (max_mtu)
319 *max_mtu = MLX5_GET(pmtu_reg, out, max_mtu);
320 if (oper_mtu)
321 *oper_mtu = MLX5_GET(pmtu_reg, out, oper_mtu);
322 if (admin_mtu)
323 *admin_mtu = MLX5_GET(pmtu_reg, out, admin_mtu);
324}
325
326int mlx5_set_port_mtu(struct mlx5_core_dev *dev, u16 mtu, u8 port)
327{
328 u32 in[MLX5_ST_SZ_DW(pmtu_reg)] = {0};
329 u32 out[MLX5_ST_SZ_DW(pmtu_reg)];
330
331 MLX5_SET(pmtu_reg, in, admin_mtu, mtu);
332 MLX5_SET(pmtu_reg, in, local_port, port);
333 return mlx5_core_access_reg(dev, in, sizeof(in), out,
334 sizeof(out), MLX5_REG_PMTU, 0, 1);
335}
336EXPORT_SYMBOL_GPL(mlx5_set_port_mtu);
337
338void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, u16 *max_mtu,
339 u8 port)
340{
341 mlx5_query_port_mtu(dev, NULL, max_mtu, NULL, port);
342}
343EXPORT_SYMBOL_GPL(mlx5_query_port_max_mtu);
344
345void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, u16 *oper_mtu,
346 u8 port)
347{
348 mlx5_query_port_mtu(dev, NULL, NULL, oper_mtu, port);
349}
350EXPORT_SYMBOL_GPL(mlx5_query_port_oper_mtu);
351
352static int mlx5_query_module_num(struct mlx5_core_dev *dev, int *module_num)
353{
354 u32 in[MLX5_ST_SZ_DW(pmlp_reg)] = {0};
355 u32 out[MLX5_ST_SZ_DW(pmlp_reg)];
356 int module_mapping;
357 int err;
358
359 MLX5_SET(pmlp_reg, in, local_port, 1);
360 err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out),
361 MLX5_REG_PMLP, 0, 0);
362 if (err)
363 return err;
364
365 module_mapping = MLX5_GET(pmlp_reg, out, lane0_module_mapping);
366 *module_num = module_mapping & MLX5_EEPROM_IDENTIFIER_BYTE_MASK;
367
368 return 0;
369}
370
371int mlx5_query_module_eeprom(struct mlx5_core_dev *dev,
372 u16 offset, u16 size, u8 *data)
373{
374 u32 out[MLX5_ST_SZ_DW(mcia_reg)];
375 u32 in[MLX5_ST_SZ_DW(mcia_reg)];
376 int module_num;
377 u16 i2c_addr;
378 int status;
379 int err;
380 void *ptr = MLX5_ADDR_OF(mcia_reg, out, dword_0);
381
382 err = mlx5_query_module_num(dev, &module_num);
383 if (err)
384 return err;
385
386 memset(in, 0, sizeof(in));
387 size = min_t(int, size, MLX5_EEPROM_MAX_BYTES);
388
389 if (offset < MLX5_EEPROM_PAGE_LENGTH &&
390 offset + size > MLX5_EEPROM_PAGE_LENGTH)
391
392 size -= offset + size - MLX5_EEPROM_PAGE_LENGTH;
393
394 i2c_addr = MLX5_I2C_ADDR_LOW;
395 if (offset >= MLX5_EEPROM_PAGE_LENGTH) {
396 i2c_addr = MLX5_I2C_ADDR_HIGH;
397 offset -= MLX5_EEPROM_PAGE_LENGTH;
398 }
399
400 MLX5_SET(mcia_reg, in, l, 0);
401 MLX5_SET(mcia_reg, in, module, module_num);
402 MLX5_SET(mcia_reg, in, i2c_device_address, i2c_addr);
403 MLX5_SET(mcia_reg, in, page_number, 0);
404 MLX5_SET(mcia_reg, in, device_address, offset);
405 MLX5_SET(mcia_reg, in, size, size);
406
407 err = mlx5_core_access_reg(dev, in, sizeof(in), out,
408 sizeof(out), MLX5_REG_MCIA, 0, 0);
409 if (err)
410 return err;
411
412 status = MLX5_GET(mcia_reg, out, status);
413 if (status) {
414 mlx5_core_err(dev, "query_mcia_reg failed: status: 0x%x\n",
415 status);
416 return -EIO;
417 }
418
419 memcpy(data, ptr, size);
420
421 return size;
422}
423EXPORT_SYMBOL_GPL(mlx5_query_module_eeprom);
424
425static int mlx5_query_port_pvlc(struct mlx5_core_dev *dev, u32 *pvlc,
426 int pvlc_size, u8 local_port)
427{
428 u32 in[MLX5_ST_SZ_DW(pvlc_reg)] = {0};
429
430 MLX5_SET(pvlc_reg, in, local_port, local_port);
431 return mlx5_core_access_reg(dev, in, sizeof(in), pvlc,
432 pvlc_size, MLX5_REG_PVLC, 0, 0);
433}
434
435int mlx5_query_port_vl_hw_cap(struct mlx5_core_dev *dev,
436 u8 *vl_hw_cap, u8 local_port)
437{
438 u32 out[MLX5_ST_SZ_DW(pvlc_reg)];
439 int err;
440
441 err = mlx5_query_port_pvlc(dev, out, sizeof(out), local_port);
442 if (err)
443 return err;
444
445 *vl_hw_cap = MLX5_GET(pvlc_reg, out, vl_hw_cap);
446
447 return 0;
448}
449EXPORT_SYMBOL_GPL(mlx5_query_port_vl_hw_cap);
450
451int mlx5_core_query_ib_ppcnt(struct mlx5_core_dev *dev,
452 u8 port_num, void *out, size_t sz)
453{
454 u32 *in;
455 int err;
456
457 in = kvzalloc(sz, GFP_KERNEL);
458 if (!in) {
459 err = -ENOMEM;
460 return err;
461 }
462
463 MLX5_SET(ppcnt_reg, in, local_port, port_num);
464
465 MLX5_SET(ppcnt_reg, in, grp, MLX5_INFINIBAND_PORT_COUNTERS_GROUP);
466 err = mlx5_core_access_reg(dev, in, sz, out,
467 sz, MLX5_REG_PPCNT, 0, 0);
468
469 kvfree(in);
470 return err;
471}
472EXPORT_SYMBOL_GPL(mlx5_core_query_ib_ppcnt);
473
474int mlx5_set_port_pause(struct mlx5_core_dev *dev, u32 rx_pause, u32 tx_pause)
475{
476 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
477 u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
478
479 MLX5_SET(pfcc_reg, in, local_port, 1);
480 MLX5_SET(pfcc_reg, in, pptx, tx_pause);
481 MLX5_SET(pfcc_reg, in, pprx, rx_pause);
482
483 return mlx5_core_access_reg(dev, in, sizeof(in), out,
484 sizeof(out), MLX5_REG_PFCC, 0, 1);
485}
486EXPORT_SYMBOL_GPL(mlx5_set_port_pause);
487
488int mlx5_query_port_pause(struct mlx5_core_dev *dev,
489 u32 *rx_pause, u32 *tx_pause)
490{
491 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
492 u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
493 int err;
494
495 MLX5_SET(pfcc_reg, in, local_port, 1);
496 err = mlx5_core_access_reg(dev, in, sizeof(in), out,
497 sizeof(out), MLX5_REG_PFCC, 0, 0);
498 if (err)
499 return err;
500
501 if (rx_pause)
502 *rx_pause = MLX5_GET(pfcc_reg, out, pprx);
503
504 if (tx_pause)
505 *tx_pause = MLX5_GET(pfcc_reg, out, pptx);
506
507 return 0;
508}
509EXPORT_SYMBOL_GPL(mlx5_query_port_pause);
510
511int mlx5_set_port_pfc(struct mlx5_core_dev *dev, u8 pfc_en_tx, u8 pfc_en_rx)
512{
513 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
514 u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
515
516 MLX5_SET(pfcc_reg, in, local_port, 1);
517 MLX5_SET(pfcc_reg, in, pfctx, pfc_en_tx);
518 MLX5_SET(pfcc_reg, in, pfcrx, pfc_en_rx);
519 MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_tx);
520 MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_rx);
521
522 return mlx5_core_access_reg(dev, in, sizeof(in), out,
523 sizeof(out), MLX5_REG_PFCC, 0, 1);
524}
525EXPORT_SYMBOL_GPL(mlx5_set_port_pfc);
526
527int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx, u8 *pfc_en_rx)
528{
529 u32 in[MLX5_ST_SZ_DW(pfcc_reg)] = {0};
530 u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
531 int err;
532
533 MLX5_SET(pfcc_reg, in, local_port, 1);
534 err = mlx5_core_access_reg(dev, in, sizeof(in), out,
535 sizeof(out), MLX5_REG_PFCC, 0, 0);
536 if (err)
537 return err;
538
539 if (pfc_en_tx)
540 *pfc_en_tx = MLX5_GET(pfcc_reg, out, pfctx);
541
542 if (pfc_en_rx)
543 *pfc_en_rx = MLX5_GET(pfcc_reg, out, pfcrx);
544
545 return 0;
546}
547EXPORT_SYMBOL_GPL(mlx5_query_port_pfc);
548
549void mlx5_query_port_autoneg(struct mlx5_core_dev *dev, int proto_mask,
550 u8 *an_status,
551 u8 *an_disable_cap, u8 *an_disable_admin)
552{
553 u32 out[MLX5_ST_SZ_DW(ptys_reg)];
554
555 *an_status = 0;
556 *an_disable_cap = 0;
557 *an_disable_admin = 0;
558
559 if (mlx5_query_port_ptys(dev, out, sizeof(out), proto_mask, 1))
560 return;
561
562 *an_status = MLX5_GET(ptys_reg, out, an_status);
563 *an_disable_cap = MLX5_GET(ptys_reg, out, an_disable_cap);
564 *an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin);
565}
566EXPORT_SYMBOL_GPL(mlx5_query_port_autoneg);
567
568int mlx5_max_tc(struct mlx5_core_dev *mdev)
569{
570 u8 num_tc = MLX5_CAP_GEN(mdev, max_tc) ? : 8;
571
572 return num_tc - 1;
573}
574
575int mlx5_query_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *out)
576{
577 u32 in[MLX5_ST_SZ_DW(dcbx_param)] = {0};
578
579 MLX5_SET(dcbx_param, in, port_number, 1);
580
581 return mlx5_core_access_reg(mdev, in, sizeof(in), out,
582 sizeof(in), MLX5_REG_DCBX_PARAM, 0, 0);
583}
584
585int mlx5_set_port_dcbx_param(struct mlx5_core_dev *mdev, u32 *in)
586{
587 u32 out[MLX5_ST_SZ_DW(dcbx_param)];
588
589 MLX5_SET(dcbx_param, in, port_number, 1);
590
591 return mlx5_core_access_reg(mdev, in, sizeof(out), out,
592 sizeof(out), MLX5_REG_DCBX_PARAM, 0, 1);
593}
594
595int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, u8 *prio_tc)
596{
597 u32 in[MLX5_ST_SZ_DW(qtct_reg)] = {0};
598 u32 out[MLX5_ST_SZ_DW(qtct_reg)];
599 int err;
600 int i;
601
602 for (i = 0; i < 8; i++) {
603 if (prio_tc[i] > mlx5_max_tc(mdev))
604 return -EINVAL;
605
606 MLX5_SET(qtct_reg, in, prio, i);
607 MLX5_SET(qtct_reg, in, tclass, prio_tc[i]);
608
609 err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
610 sizeof(out), MLX5_REG_QTCT, 0, 1);
611 if (err)
612 return err;
613 }
614
615 return 0;
616}
617EXPORT_SYMBOL_GPL(mlx5_set_port_prio_tc);
618
619int mlx5_query_port_prio_tc(struct mlx5_core_dev *mdev,
620 u8 prio, u8 *tc)
621{
622 u32 in[MLX5_ST_SZ_DW(qtct_reg)];
623 u32 out[MLX5_ST_SZ_DW(qtct_reg)];
624 int err;
625
626 memset(in, 0, sizeof(in));
627 memset(out, 0, sizeof(out));
628
629 MLX5_SET(qtct_reg, in, port_number, 1);
630 MLX5_SET(qtct_reg, in, prio, prio);
631
632 err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
633 sizeof(out), MLX5_REG_QTCT, 0, 0);
634 if (!err)
635 *tc = MLX5_GET(qtct_reg, out, tclass);
636
637 return err;
638}
639EXPORT_SYMBOL_GPL(mlx5_query_port_prio_tc);
640
641static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in,
642 int inlen)
643{
644 u32 out[MLX5_ST_SZ_DW(qtct_reg)];
645
646 if (!MLX5_CAP_GEN(mdev, ets))
647 return -EOPNOTSUPP;
648
649 return mlx5_core_access_reg(mdev, in, inlen, out, sizeof(out),
650 MLX5_REG_QETCR, 0, 1);
651}
652
653static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out,
654 int outlen)
655{
656 u32 in[MLX5_ST_SZ_DW(qtct_reg)];
657
658 if (!MLX5_CAP_GEN(mdev, ets))
659 return -EOPNOTSUPP;
660
661 memset(in, 0, sizeof(in));
662 return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen,
663 MLX5_REG_QETCR, 0, 0);
664}
665
666int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, u8 *tc_group)
667{
668 u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
669 int i;
670
671 for (i = 0; i <= mlx5_max_tc(mdev); i++) {
672 MLX5_SET(qetc_reg, in, tc_configuration[i].g, 1);
673 MLX5_SET(qetc_reg, in, tc_configuration[i].group, tc_group[i]);
674 }
675
676 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
677}
678EXPORT_SYMBOL_GPL(mlx5_set_port_tc_group);
679
680int mlx5_query_port_tc_group(struct mlx5_core_dev *mdev,
681 u8 tc, u8 *tc_group)
682{
683 u32 out[MLX5_ST_SZ_DW(qetc_reg)];
684 void *ets_tcn_conf;
685 int err;
686
687 err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
688 if (err)
689 return err;
690
691 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out,
692 tc_configuration[tc]);
693
694 *tc_group = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
695 group);
696
697 return 0;
698}
699EXPORT_SYMBOL_GPL(mlx5_query_port_tc_group);
700
701int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw)
702{
703 u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
704 int i;
705
706 for (i = 0; i <= mlx5_max_tc(mdev); i++) {
707 MLX5_SET(qetc_reg, in, tc_configuration[i].b, 1);
708 MLX5_SET(qetc_reg, in, tc_configuration[i].bw_allocation, tc_bw[i]);
709 }
710
711 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
712}
713EXPORT_SYMBOL_GPL(mlx5_set_port_tc_bw_alloc);
714
715int mlx5_query_port_tc_bw_alloc(struct mlx5_core_dev *mdev,
716 u8 tc, u8 *bw_pct)
717{
718 u32 out[MLX5_ST_SZ_DW(qetc_reg)];
719 void *ets_tcn_conf;
720 int err;
721
722 err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
723 if (err)
724 return err;
725
726 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out,
727 tc_configuration[tc]);
728
729 *bw_pct = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
730 bw_allocation);
731
732 return 0;
733}
734EXPORT_SYMBOL_GPL(mlx5_query_port_tc_bw_alloc);
735
736int mlx5_modify_port_ets_rate_limit(struct mlx5_core_dev *mdev,
737 u8 *max_bw_value,
738 u8 *max_bw_units)
739{
740 u32 in[MLX5_ST_SZ_DW(qetc_reg)] = {0};
741 void *ets_tcn_conf;
742 int i;
743
744 MLX5_SET(qetc_reg, in, port_number, 1);
745
746 for (i = 0; i <= mlx5_max_tc(mdev); i++) {
747 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, in, tc_configuration[i]);
748
749 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, r, 1);
750 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_units,
751 max_bw_units[i]);
752 MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_value,
753 max_bw_value[i]);
754 }
755
756 return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
757}
758EXPORT_SYMBOL_GPL(mlx5_modify_port_ets_rate_limit);
759
760int mlx5_query_port_ets_rate_limit(struct mlx5_core_dev *mdev,
761 u8 *max_bw_value,
762 u8 *max_bw_units)
763{
764 u32 out[MLX5_ST_SZ_DW(qetc_reg)];
765 void *ets_tcn_conf;
766 int err;
767 int i;
768
769 err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
770 if (err)
771 return err;
772
773 for (i = 0; i <= mlx5_max_tc(mdev); i++) {
774 ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, tc_configuration[i]);
775
776 max_bw_value[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
777 max_bw_value);
778 max_bw_units[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
779 max_bw_units);
780 }
781
782 return 0;
783}
784EXPORT_SYMBOL_GPL(mlx5_query_port_ets_rate_limit);
785
786int mlx5_set_port_wol(struct mlx5_core_dev *mdev, u8 wol_mode)
787{
788 u32 in[MLX5_ST_SZ_DW(set_wol_rol_in)] = {0};
789 u32 out[MLX5_ST_SZ_DW(set_wol_rol_out)] = {0};
790
791 MLX5_SET(set_wol_rol_in, in, opcode, MLX5_CMD_OP_SET_WOL_ROL);
792 MLX5_SET(set_wol_rol_in, in, wol_mode_valid, 1);
793 MLX5_SET(set_wol_rol_in, in, wol_mode, wol_mode);
794 return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
795}
796EXPORT_SYMBOL_GPL(mlx5_set_port_wol);
797
798int mlx5_query_port_wol(struct mlx5_core_dev *mdev, u8 *wol_mode)
799{
800 u32 in[MLX5_ST_SZ_DW(query_wol_rol_in)] = {0};
801 u32 out[MLX5_ST_SZ_DW(query_wol_rol_out)] = {0};
802 int err;
803
804 MLX5_SET(query_wol_rol_in, in, opcode, MLX5_CMD_OP_QUERY_WOL_ROL);
805 err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
806 if (!err)
807 *wol_mode = MLX5_GET(query_wol_rol_out, out, wol_mode);
808
809 return err;
810}
811EXPORT_SYMBOL_GPL(mlx5_query_port_wol);
812
813static int mlx5_query_ports_check(struct mlx5_core_dev *mdev, u32 *out,
814 int outlen)
815{
816 u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0};
817
818 MLX5_SET(pcmr_reg, in, local_port, 1);
819 return mlx5_core_access_reg(mdev, in, sizeof(in), out,
820 outlen, MLX5_REG_PCMR, 0, 0);
821}
822
823static int mlx5_set_ports_check(struct mlx5_core_dev *mdev, u32 *in, int inlen)
824{
825 u32 out[MLX5_ST_SZ_DW(pcmr_reg)];
826
827 return mlx5_core_access_reg(mdev, in, inlen, out,
828 sizeof(out), MLX5_REG_PCMR, 0, 1);
829}
830
831int mlx5_set_port_fcs(struct mlx5_core_dev *mdev, u8 enable)
832{
833 u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {0};
834
835 MLX5_SET(pcmr_reg, in, local_port, 1);
836 MLX5_SET(pcmr_reg, in, fcs_chk, enable);
837 return mlx5_set_ports_check(mdev, in, sizeof(in));
838}
839
840void mlx5_query_port_fcs(struct mlx5_core_dev *mdev, bool *supported,
841 bool *enabled)
842{
843 u32 out[MLX5_ST_SZ_DW(pcmr_reg)];
844
845 *supported = false;
846 *enabled = true;
847
848 if (!MLX5_CAP_GEN(mdev, ports_check))
849 return;
850
851 if (mlx5_query_ports_check(mdev, out, sizeof(out)))
852 return;
853
854 *supported = !!(MLX5_GET(pcmr_reg, out, fcs_cap));
855 *enabled = !!(MLX5_GET(pcmr_reg, out, fcs_chk));
856}
857
858static const char *mlx5_pme_status[MLX5_MODULE_STATUS_NUM] = {
859 "Cable plugged",
860 "Cable unplugged",
861 "Cable error",
862};
863
864static const char *mlx5_pme_error[MLX5_MODULE_EVENT_ERROR_NUM] = {
865 "Power budget exceeded",
866 "Long Range for non MLNX cable",
867 "Bus stuck(I2C or data shorted)",
868 "No EEPROM/retry timeout",
869 "Enforce part number list",
870 "Unknown identifier",
871 "High Temperature",
872 "Bad or shorted cable/module",
873 "Unknown status",
874};
875
876void mlx5_port_module_event(struct mlx5_core_dev *dev, struct mlx5_eqe *eqe)
877{
878 enum port_module_event_status_type module_status;
879 enum port_module_event_error_type error_type;
880 struct mlx5_eqe_port_module *module_event_eqe;
881 struct mlx5_priv *priv = &dev->priv;
882 u8 module_num;
883
884 module_event_eqe = &eqe->data.port_module;
885 module_num = module_event_eqe->module;
886 module_status = module_event_eqe->module_status &
887 PORT_MODULE_EVENT_MODULE_STATUS_MASK;
888 error_type = module_event_eqe->error_type &
889 PORT_MODULE_EVENT_ERROR_TYPE_MASK;
890
891 if (module_status < MLX5_MODULE_STATUS_ERROR) {
892 priv->pme_stats.status_counters[module_status - 1]++;
893 } else if (module_status == MLX5_MODULE_STATUS_ERROR) {
894 if (error_type >= MLX5_MODULE_EVENT_ERROR_UNKNOWN)
895
896 error_type = MLX5_MODULE_EVENT_ERROR_UNKNOWN;
897 priv->pme_stats.error_counters[error_type]++;
898 }
899
900 if (!printk_ratelimit())
901 return;
902
903 if (module_status < MLX5_MODULE_STATUS_ERROR)
904 mlx5_core_info(dev,
905 "Port module event: module %u, %s\n",
906 module_num, mlx5_pme_status[module_status - 1]);
907
908 else if (module_status == MLX5_MODULE_STATUS_ERROR)
909 mlx5_core_info(dev,
910 "Port module event[error]: module %u, %s, %s\n",
911 module_num, mlx5_pme_status[module_status - 1],
912 mlx5_pme_error[error_type]);
913}
914
915int mlx5_query_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size)
916{
917 u32 in[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
918
919 return mlx5_core_access_reg(mdev, in, sizeof(in), mtpps,
920 mtpps_size, MLX5_REG_MTPPS, 0, 0);
921}
922
923int mlx5_set_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size)
924{
925 u32 out[MLX5_ST_SZ_DW(mtpps_reg)] = {0};
926
927 return mlx5_core_access_reg(mdev, mtpps, mtpps_size, out,
928 sizeof(out), MLX5_REG_MTPPS, 0, 1);
929}
930
931int mlx5_query_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 *arm, u8 *mode)
932{
933 u32 out[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
934 u32 in[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
935 int err = 0;
936
937 MLX5_SET(mtppse_reg, in, pin, pin);
938
939 err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
940 sizeof(out), MLX5_REG_MTPPSE, 0, 0);
941 if (err)
942 return err;
943
944 *arm = MLX5_GET(mtppse_reg, in, event_arm);
945 *mode = MLX5_GET(mtppse_reg, in, event_generation_mode);
946
947 return err;
948}
949
950int mlx5_set_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 arm, u8 mode)
951{
952 u32 out[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
953 u32 in[MLX5_ST_SZ_DW(mtppse_reg)] = {0};
954
955 MLX5_SET(mtppse_reg, in, pin, pin);
956 MLX5_SET(mtppse_reg, in, event_arm, arm);
957 MLX5_SET(mtppse_reg, in, event_generation_mode, mode);
958
959 return mlx5_core_access_reg(mdev, in, sizeof(in), out,
960 sizeof(out), MLX5_REG_MTPPSE, 0, 1);
961}
962