Switchtec Userspace PROJECT_NUMBER = 4.4
Loading...
Searching...
No Matches
diag.c
Go to the documentation of this file.
1/*
2 * Microsemi Switchtec(tm) PCIe Management Library
3 * Copyright (c) 2021, Microsemi Corporation
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
22 *
23 */
24
29
30#define SWITCHTEC_LIB_CORE
31#define SWITCHTEC_LTSSM_MAX_LOGS 61
32
33#include "switchtec_priv.h"
34#include "switchtec/diag.h"
35#include "switchtec/endian.h"
36#include "switchtec/switchtec.h"
37#include "switchtec/utils.h"
38
39#include <errno.h>
40#include <math.h>
41#include <string.h>
42#include <strings.h>
43#include <unistd.h>
44
53int switchtec_diag_cross_hair_enable(struct switchtec_dev *dev, int lane_id)
54{
56 .sub_cmd = MRPC_CROSS_HAIR_ENABLE,
57 .lane_id = lane_id,
58 .all_lanes = lane_id == SWITCHTEC_DIAG_CROSS_HAIR_ALL_LANES,
59 };
60
61 return switchtec_cmd(dev, MRPC_CROSS_HAIR, &in, sizeof(in), NULL, 0);
62}
63
70int switchtec_diag_cross_hair_disable(struct switchtec_dev *dev)
71{
73 .sub_cmd = MRPC_CROSS_HAIR_DISABLE,
74 };
75
76 return switchtec_cmd(dev, MRPC_CROSS_HAIR, &in, sizeof(in), NULL, 0);
77}
78
88int switchtec_diag_cross_hair_get(struct switchtec_dev *dev, int start_lane_id,
89 int num_lanes, struct switchtec_diag_cross_hair *res)
90{
92 .sub_cmd = MRPC_CROSS_HAIR_GET,
93 .lane_id = start_lane_id,
94 .num_lanes = num_lanes,
95 };
96 struct switchtec_diag_cross_hair_get out[num_lanes];
97 int i, ret;
98
99 ret = switchtec_cmd(dev, MRPC_CROSS_HAIR, &in, sizeof(in), &out,
100 sizeof(out));
101 if (ret)
102 return ret;
103
104 for (i = 0; i < num_lanes; i++) {
105 memset(&res[i], 0, sizeof(res[i]));
106 res[i].state = out[i].state;
107 res[i].lane_id = out[i].lane_id;
108
109 if (out[i].state <= SWITCHTEC_DIAG_CROSS_HAIR_WAITING) {
110 continue;
111 } else if (out[i].state < SWITCHTEC_DIAG_CROSS_HAIR_DONE) {
112 res[i].x_pos = out[i].x_pos;
113 res[i].y_pos = out[i].y_pos;
114 } else if (out[i].state == SWITCHTEC_DIAG_CROSS_HAIR_DONE) {
115 res[i].eye_left_lim = out[i].eye_left_lim;
116 res[i].eye_right_lim = out[i].eye_right_lim;
117 res[i].eye_bot_left_lim = out[i].eye_bot_left_lim;
118 res[i].eye_bot_right_lim = out[i].eye_bot_right_lim;
119 res[i].eye_top_left_lim = out[i].eye_top_left_lim;
120 res[i].eye_top_right_lim = out[i].eye_top_right_lim;
121 } else if (out[i].state == SWITCHTEC_DIAG_CROSS_HAIR_ERROR) {
122 res[i].x_pos = out[i].x_pos;
123 res[i].y_pos = out[i].y_pos;
124 res[i].prev_state = out[i].prev_state;
125 }
126 }
127
128 return 0;
129}
130
131static int switchtec_diag_eye_status_gen5(struct switchtec_dev *dev)
132{
133 int ret;
134 int eye_status;
135
137 .sub_cmd = MRPC_EYE_CAP_STATUS_GEN5,
138 };
140
141 do {
142 ret = switchtec_cmd(dev, MRPC_GEN5_EYE_CAPTURE, &in, sizeof(in),
143 &out, sizeof(out));
144 if (ret) {
145 switchtec_perror("eye_status");
146 return -1;
147 }
148 eye_status = out.status;
149 usleep(200000);
150 } while (eye_status == SWITCHTEC_GEN5_DIAG_EYE_STATUS_IN_PROGRESS ||
151 eye_status == SWITCHTEC_GEN5_DIAG_EYE_STATUS_PENDING);
152
153 switch (eye_status) {
154 case SWITCHTEC_GEN5_DIAG_EYE_STATUS_DONE:
155 return 0;
156 case SWITCHTEC_GEN5_DIAG_EYE_STATUS_IDLE:
157 errno = ENODATA;
158 switchtec_perror("Eye capture idle");
159 return -1;
160 case SWITCHTEC_GEN5_DIAG_EYE_STATUS_TIMEOUT:
161 errno = ETIMEDOUT;
162 switchtec_perror("Eye capture timeout");
163 return -1;
164 case SWITCHTEC_GEN5_DIAG_EYE_STATUS_ERROR:
165 errno = EIO;
166 switchtec_perror("Eye capture error");
167 return -1;
168 }
169 errno = EPROTO;
170 switchtec_perror("Unknown eye capture state");
171 return -1;
172}
173
174static int switchtec_diag_eye_status(int status)
175{
176 switch (status) {
177 case 0: return 0;
178 case 2:
179 errno = EINVAL;
180 return -1;
181 case 3:
182 errno = EBUSY;
183 return -1;
184 default:
185 errno = EPROTO;
186 return -1;
187 }
188}
189
190static int switchtec_diag_eye_cmd_gen5(struct switchtec_dev *dev, void *in,
191 size_t size)
192{
193 int ret;
194
195 ret = switchtec_cmd(dev, MRPC_GEN5_EYE_CAPTURE, in, size,
196 NULL, 0);
197 if (ret)
198 return ret;
199
200 usleep(200000);
201
202 return switchtec_diag_eye_status_gen5(dev);
203}
204
205static int switchtec_diag_eye_cmd_gen4(struct switchtec_dev *dev, void *in,
206 size_t size)
207{
209 int ret;
210
211 ret = switchtec_cmd(dev, MRPC_EYE_OBSERVE, in, size, &out,
212 sizeof(out));
213
214 if (ret)
215 return ret;
216
217 return switchtec_diag_eye_status(out.status);
218}
219
227int switchtec_diag_eye_set_mode(struct switchtec_dev *dev,
228 enum switchtec_diag_eye_data_mode mode)
229{
230 struct switchtec_diag_port_eye_cmd in = {
231 .sub_cmd = MRPC_EYE_OBSERVE_SET_DATA_MODE,
232 .data_mode = mode,
233 };
234
235 return switchtec_diag_eye_cmd_gen4(dev, &in, sizeof(in));
236}
237
248int switchtec_diag_eye_read(struct switchtec_dev *dev, int lane_id,
249 int bin, int *num_phases, double *ber_data)
250{
251 int i, ret;
252
253 if (switchtec_is_gen6(dev)) {
255 .sub_cmd = MRPC_EYE_CAP_READ_GEN6,
256 .lane_id = lane_id,
257 .bin_num = bin,
258 };
260
261 ret = switchtec_cmd(dev, MRPC_GEN5_EYE_CAPTURE, &in,
262 sizeof(in), &out, sizeof(out));
263 if (ret)
264 return ret;
265
266 *num_phases = out.num_phases;
267
268 for (i = 0; i < out.num_phases; i++)
269 ber_data[i] = (double)le32toh(out.ndes_data[i]);
270
271 return 0;
272 } else if (switchtec_is_gen5(dev)) {
274 .sub_cmd = MRPC_EYE_CAP_READ_GEN5,
275 .lane_id = lane_id,
276 .bin = bin,
277 };
279
280 ret = switchtec_cmd(dev, MRPC_GEN5_EYE_CAPTURE, &in,
281 sizeof(in), &out, sizeof(out));
282 if (ret)
283 return ret;
284
285 *num_phases = out.num_phases;
286
287 for (i = 0; i < out.num_phases; i++)
288 ber_data[i] = le64toh(out.ber_data[i]) / 281474976710656.;
289
290 return 0;
291 }
292
293 fprintf(stderr, "Eye read not supported on Gen 4 switches.\n");
294 return -1;
295}
296
309int switchtec_diag_eye_start(struct switchtec_dev *dev, int lane_mask[4],
310 struct range *x_range, struct range *y_range,
311 int step_interval, int capture_depth, int sar_sel,
312 int intleav_sel, int hstep, int data_mode,
313 int eye_mode, uint64_t refclk, int vstep)
314{
315 int err, ret;
316 if (switchtec_is_gen5(dev)) {
318 .sub_cmd = MRPC_EYE_CAP_RUN_GEN5,
319 .capture_depth = capture_depth,
320 .timeout_disable = 1,
321 .lane_mask[0] = lane_mask[0],
322 .lane_mask[1] = lane_mask[1],
323 .lane_mask[2] = lane_mask[2],
324 .lane_mask[3] = lane_mask[3],
325 };
326
327 ret = switchtec_diag_eye_cmd_gen5(dev, &in, sizeof(in));
328 err = errno;
329 errno = err;
330 return ret;
331 } else if (switchtec_is_gen6(dev)) {
333 .sub_cmd = MRPC_EYE_CAP_RUN_GEN6,
334 .timeout_disable = 1,
335 .lane_mask[0] = lane_mask[0],
336 .lane_mask[1] = lane_mask[1],
337 .lane_mask[2] = lane_mask[2],
338 .lane_mask[3] = lane_mask[3],
339 .sar_sel = sar_sel,
340 .intleav_sel = intleav_sel,
341 .vstep = vstep,
342 .hstep = hstep,
343 .data_mode = data_mode,
344 .eye_mode = eye_mode,
345 .ref_timer_lwr = refclk & 0xFFFFFFFF,
346 .ref_timer_upp = refclk >> 32,
347 };
348
349 ret = switchtec_diag_eye_cmd_gen5(dev, &in, sizeof(in));
350 err = errno;
351 errno = err;
352 return ret;
353 } else {
355 .sub_cmd = MRPC_EYE_OBSERVE_START,
356 .lane_mask[0] = lane_mask[0],
357 .lane_mask[1] = lane_mask[1],
358 .lane_mask[2] = lane_mask[2],
359 .lane_mask[3] = lane_mask[3],
360 .x_start = x_range->start,
361 .y_start = y_range->start,
362 .x_end = x_range->end,
363 .y_end = y_range->end,
364 .x_step = x_range->step,
365 .y_step = y_range->step,
366 .step_interval = step_interval,
367 };
368
369 ret = switchtec_diag_eye_cmd_gen4(dev, &in, sizeof(in));
370 /* Add delay so hardware has enough time to start */
371 err = errno;
372 usleep(200000);
373 errno = err;
374 return ret;
375 }
376 return -1;
377}
378
379static uint64_t hi_lo_to_uint64(uint32_t lo, uint32_t hi)
380{
381 uint64_t ret;
382
383 ret = le32toh(hi);
384 ret <<= 32;
385 ret |= le32toh(lo);
386
387 return ret;
388}
389
403int switchtec_diag_eye_fetch(struct switchtec_dev *dev, double *pixels,
404 size_t pixel_cnt, int *lane_id)
405{
406 struct switchtec_diag_port_eye_cmd in = {
407 .sub_cmd = MRPC_EYE_OBSERVE_FETCH,
408 };
410 uint64_t samples, errors;
411 int i, ret, data_count;
412
413retry:
414 ret = switchtec_cmd(dev, MRPC_EYE_OBSERVE, &in, sizeof(in), &out,
415 sizeof(out));
416 if (ret)
417 return ret;
418
419 if (out.status == 1) {
420 usleep(5000);
421 goto retry;
422 }
423
424 ret = switchtec_diag_eye_status(out.status);
425 if (ret)
426 return ret;
427
428 for (i = 0; i < 4; i++) {
429 *lane_id = ffs(out.lane_mask[i]);
430 if (*lane_id)
431 break;
432 }
433
434 data_count = out.data_count_lo | ((int)out.data_count_hi << 8);
435
436 for (i = 0; i < data_count && i < pixel_cnt; i++) {
437 switch (out.data_mode) {
438 case SWITCHTEC_DIAG_EYE_RAW:
439 errors = hi_lo_to_uint64(out.raw[i].error_cnt_lo,
440 out.raw[i].error_cnt_hi);
441 samples = hi_lo_to_uint64(out.raw[i].sample_cnt_lo,
442 out.raw[i].sample_cnt_hi);
443 if (samples)
444 pixels[i] = (double)errors / samples;
445 else
446 pixels[i] = nan("");
447 break;
448 case SWITCHTEC_DIAG_EYE_RATIO:
449 pixels[i] = le32toh(out.ratio[i].ratio) / 65536.;
450 break;
451 }
452 }
453
454 return data_count;
455}
456
463int switchtec_diag_eye_cancel(struct switchtec_dev *dev)
464{
465 int ret;
466 int err;
467 struct switchtec_diag_port_eye_cmd in = {
468 .sub_cmd = MRPC_EYE_OBSERVE_CANCEL,
469 };
470
471 ret = switchtec_diag_eye_cmd_gen4(dev, &in, sizeof(in));
472
473 /* Add delay so hardware can stop completely */
474 err = errno;
475 usleep(200000);
476 errno = err;
477
478 return ret;
479}
480
481static int switchtec_diag_loopback_set_gen56(struct switchtec_dev *dev,
482 int port_id, int enable_parallel,
483 int enable_external,
484 int enable_ltssm, int enable_pipe,
485 enum switchtec_diag_ltssm_speed ltssm_speed)
486{
487 struct switchtec_diag_loopback_in int_in = {
488 .sub_cmd = MRPC_LOOPBACK_SET_INT_LOOPBACK,
489 .port_id = port_id,
490 .enable = 1,
491 };
492 struct switchtec_diag_loopback_ltssm_in ltssm_in = {
493 .sub_cmd = MRPC_LOOPBACK_SET_LTSSM_LOOPBACK,
494 .port_id = port_id,
495 .enable = enable_ltssm,
496 .speed = ltssm_speed,
497 };
498 int ret;
499
500 if (enable_ltssm && !(enable_external || enable_parallel)) {
501 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &ltssm_in,
502 sizeof(ltssm_in), NULL, 0);
503 if (ret)
504 return ret;
505 } else {
506 int_in.type = DIAG_LOOPBACK_PARALEL_DATAPATH;
507 int_in.enable = enable_parallel;
508 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &int_in,
509 sizeof(int_in), NULL, 0);
510 if (ret)
511 return ret;
512 if (!enable_parallel) {
513 int_in.type = DIAG_LOOPBACK_EXTERNAL_DATAPATH;
514 int_in.enable = enable_external;
515 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &int_in,
516 sizeof(int_in), NULL, 0);
517 if (ret)
518 return ret;
519 }
520 int_in.type = DIAG_LOOPBACK_PIPE_DATAPATH;
521 int_in.enable = enable_pipe;
522 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &int_in,
523 sizeof(int_in), NULL, 0);
524 if (ret)
525 return ret;
526
527 ltssm_in.enable = enable_ltssm;
528 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &ltssm_in,
529 sizeof(ltssm_in), NULL, 0);
530 if (ret)
531 return ret;
532 }
533 return 0;
534}
535
536static int switchtec_diag_loopback_set_gen4(struct switchtec_dev *dev,
537 int port_id, int enable,
538 enum switchtec_diag_ltssm_speed
539 ltssm_speed)
540{
541 struct switchtec_diag_loopback_in int_in = {
542 .sub_cmd = MRPC_LOOPBACK_SET_INT_LOOPBACK,
543 .port_id = port_id,
544 .enable = enable,
545 };
546 struct switchtec_diag_loopback_ltssm_in ltssm_in = {
547 .sub_cmd = MRPC_LOOPBACK_SET_LTSSM_LOOPBACK,
548 .port_id = port_id,
549 .enable = !!(enable & SWITCHTEC_DIAG_LOOPBACK_LTSSM),
550 .speed = ltssm_speed,
551 };
552 int ret;
553
554 int_in.type = DIAG_LOOPBACK_RX_TO_TX;
555 int_in.enable = !!(enable & SWITCHTEC_DIAG_LOOPBACK_RX_TO_TX);
556
557 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &int_in,
558 sizeof(int_in), NULL, 0);
559 if (ret)
560 return ret;
561
562 int_in.type = DIAG_LOOPBACK_TX_TO_RX;
563 int_in.enable = !!(enable & SWITCHTEC_DIAG_LOOPBACK_TX_TO_RX);
564
565 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &int_in,
566 sizeof(int_in), NULL, 0);
567 if (ret)
568 return ret;
569
570 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &ltssm_in,
571 sizeof(ltssm_in), NULL, 0);
572 if (ret)
573 return ret;
574
575 return 0;
576}
577
590int switchtec_diag_loopback_set(struct switchtec_dev *dev, int port_id,
591 int enable, int enable_parallel,
592 int enable_external, int enable_ltssm,
593 int enable_pipe,
594 enum switchtec_diag_ltssm_speed ltssm_speed)
595{
596 int ret = 0;
597 if (switchtec_is_gen5(dev)) {
598 ret = switchtec_diag_loopback_set_gen56(dev, port_id, enable_parallel,
599 enable_external, enable_ltssm,
600 enable_pipe, ltssm_speed);
601 if (ret)
602 return ret;
603 }
604 else {
605 ret = switchtec_diag_loopback_set_gen4(dev, port_id, enable,
606 ltssm_speed);
607 if (ret)
608 return ret;
609 }
610 return 0;
611}
612
623int switchtec_diag_loopback_get(struct switchtec_dev *dev,
624 int port_id, int *enabled,
625 enum switchtec_diag_ltssm_speed *ltssm_speed)
626{
627 struct switchtec_diag_loopback_in int_in = {
628 .sub_cmd = MRPC_LOOPBACK_GET_INT_LOOPBACK,
629 .port_id = port_id,
630 };
631 struct switchtec_diag_loopback_ltssm_in lt_in = {
632 .sub_cmd = MRPC_LOOPBACK_GET_LTSSM_LOOPBACK,
633 .port_id = port_id,
634 };
635 struct switchtec_diag_loopback_out int_out;
637 int ret, en = 0;
638
639 if (switchtec_is_gen5(dev))
640 int_in.type = DIAG_LOOPBACK_PARALEL_DATAPATH;
641 else
642 int_in.type = DIAG_LOOPBACK_RX_TO_TX;
643
644 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &int_in, sizeof(int_in),
645 &int_out, sizeof(int_out));
646 if (ret)
647 return ret;
648
649 if (int_out.enabled)
650 en |= SWITCHTEC_DIAG_LOOPBACK_RX_TO_TX;
651
652 if (switchtec_is_gen5(dev))
653 int_in.type = DIAG_LOOPBACK_EXTERNAL_DATAPATH;
654 else
655 int_in.type = DIAG_LOOPBACK_TX_TO_RX;
656
657 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &int_in, sizeof(int_in),
658 &int_out, sizeof(int_out));
659 if (ret)
660 return ret;
661
662 if (int_out.enabled)
663 en |= SWITCHTEC_DIAG_LOOPBACK_TX_TO_RX;
664
665 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &lt_in, sizeof(lt_in),
666 &lt_out, sizeof(lt_out));
667 if (ret)
668 return ret;
669
670 if (lt_out.enabled)
671 en |= SWITCHTEC_DIAG_LOOPBACK_LTSSM;
672
673 if (enabled)
674 *enabled = en;
675
676 if (ltssm_speed)
677 *ltssm_speed = lt_out.speed;
678
679 return 0;
680}
681
690int switchtec_diag_pattern_gen_set(struct switchtec_dev *dev, int port_id,
691 enum switchtec_diag_pattern type,
692 enum switchtec_diag_pattern_link_rate link_speed)
693{
694 struct switchtec_diag_pat_gen_in in = {
695 .sub_cmd = MRPC_PAT_GEN_SET_GEN,
696 .port_id = port_id,
697 .pattern_type = type,
698 .lane_id = link_speed
699 };
700 if (switchtec_is_gen5(dev))
701 in.sub_cmd = MRPC_PAT_GEN_SET_GEN_GEN5;
702 if (switchtec_is_gen6(dev))
703 in.sub_cmd = MRPC_PAT_GEN_SET_GEN_GEN6;
704
705 return switchtec_cmd(dev, MRPC_PAT_GEN, &in, sizeof(in), NULL, 0);
706}
707
716int switchtec_diag_pattern_gen_get(struct switchtec_dev *dev, int port_id,
717 enum switchtec_diag_pattern *type)
718{
719 struct switchtec_diag_pat_gen_in in = {
720 .sub_cmd = MRPC_PAT_GEN_GET_GEN,
721 .port_id = port_id,
722 };
723 if (switchtec_is_gen6(dev))
724 in.sub_cmd = MRPC_PAT_GEN_GET_GEN_GEN6;
726 int ret;
727
728 ret = switchtec_cmd(dev, MRPC_PAT_GEN, &in, sizeof(in), &out,
729 sizeof(out));
730 if (ret)
731 return ret;
732
733 if (type)
734 *type = out.pattern_type;
735
736 return 0;
737}
738
747int switchtec_diag_pattern_mon_set(struct switchtec_dev *dev, int port_id,
748 enum switchtec_diag_pattern type)
749{
750 struct switchtec_diag_pat_gen_in in = {
751 .sub_cmd = MRPC_PAT_GEN_SET_MON,
752 .port_id = port_id,
753 .pattern_type = type,
754 };
755 if (switchtec_is_gen6(dev))
756 in.sub_cmd = MRPC_PAT_GEN_SET_MON_GEN6;
757
758 return switchtec_cmd(dev, MRPC_PAT_GEN, &in, sizeof(in), NULL, 0);
759}
760
770int switchtec_diag_pattern_mon_get(struct switchtec_dev *dev, int port_id,
771 int lane_id, enum switchtec_diag_pattern *type,
772 unsigned long long *err_cnt)
773{
774 struct switchtec_diag_pat_gen_in in = {
775 .sub_cmd = MRPC_PAT_GEN_GET_MON,
776 .port_id = port_id,
777 .lane_id = lane_id,
778 };
779 if (switchtec_is_gen6(dev))
780 in.sub_cmd = MRPC_PAT_GEN_GET_MON_GEN6;
782 int ret;
783
784 ret = switchtec_cmd(dev, MRPC_PAT_GEN, &in, sizeof(in), &out,
785 sizeof(out));
786 if (ret)
787 return ret;
788
789 if (type)
790 *type = out.pattern_type;
791
792 if (err_cnt)
793 *err_cnt = (htole32(out.err_cnt_lo) |
794 ((uint64_t)htole32(out.err_cnt_hi) << 32));
795
796 return 0;
797}
798
811int switchtec_diag_pattern_inject(struct switchtec_dev *dev, int port_id,
812 unsigned int err_cnt)
813{
815 .sub_cmd = MRPC_PAT_GEN_INJ_ERR,
816 .port_id = port_id,
817 .err_cnt = err_cnt,
818 };
819 int ret;
820
821 ret = switchtec_cmd(dev, MRPC_PAT_GEN, &in, sizeof(in), NULL, 0);
822 if (ret)
823 return ret;
824
825 return 0;
826}
827
838int switchtec_diag_rcvr_obj(struct switchtec_dev *dev, int port_id,
839 int lane_id, enum switchtec_diag_link link,
840 struct switchtec_rcvr_obj *res)
841{
842 struct switchtec_diag_rcvr_obj_dump_out out = {};
844 .port_id = port_id,
845 .lane_id = lane_id,
846 };
848 .sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_PREV,
849 .port_id = port_id,
850 .lane_id = lane_id,
851 };
852 int i, ret;
853
854 if (!res) {
855 errno = -EINVAL;
856 return -1;
857 }
858
859 if (link == SWITCHTEC_DIAG_LINK_CURRENT) {
860 ret = switchtec_cmd(dev, MRPC_RCVR_OBJ_DUMP, &in, sizeof(in),
861 &out, sizeof(out));
862 } else if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
863 ret = switchtec_cmd(dev, MRPC_EXT_RCVR_OBJ_DUMP, &ext_in,
864 sizeof(ext_in), &out, sizeof(out));
865 } else {
866 errno = -EINVAL;
867 return -1;
868 }
869
870 if (ret)
871 return -1;
872
873 res->port_id = out.port_id;
874 res->lane_id = out.lane_id;
875 res->ctle = out.ctle;
876 res->target_amplitude = out.target_amplitude;
877 res->speculative_dfe = out.speculative_dfe;
878 for (i = 0; i < ARRAY_SIZE(res->dynamic_dfe); i++)
879 res->dynamic_dfe[i] = out.dynamic_dfe[i];
880
881 return 0;
882}
883
893static int switchtec_gen5_diag_port_eq_tx_coeff(struct switchtec_dev *dev,
894 int port_id, int prev_speed,
895 enum switchtec_diag_end end,
896 enum switchtec_diag_link link,
898 *res)
899{
900 struct switchtec_port_eq_coeff *loc_out;
901 struct switchtec_rem_port_eq_coeff *rem_out;
903 uint8_t *buf;
904 uint32_t buf_size;
905 uint32_t in_size = sizeof(struct switchtec_port_eq_coeff_in);
906 uint32_t out_size = 0;
907 int ret = 0;
908 int i;
909
910 if (!res) {
911 fprintf(stderr, "Error inval output buffer\n");
912 errno = -EINVAL;
913 return -1;
914 }
915
916 buf_size = in_size;
917 if (end == SWITCHTEC_DIAG_LOCAL) {
918 buf_size += sizeof(struct switchtec_port_eq_coeff);
919 out_size = sizeof(struct switchtec_port_eq_coeff);
920 } else if (end == SWITCHTEC_DIAG_FAR_END) {
921 buf_size += sizeof(struct switchtec_rem_port_eq_coeff);
922 out_size = sizeof(struct switchtec_rem_port_eq_coeff);
923 } else {
924 fprintf(stderr, "Error inval end option\n");
925 errno = -EINVAL;
926 }
927 buf = (uint8_t *)malloc(buf_size);
928 if (!buf) {
929 fprintf(stderr, "Error in buffer alloc\n");
930 errno = -ENOMEM;
931 return -1;
932 }
933
934 in = (struct switchtec_port_eq_coeff_in *)buf;
935 in->op_type = DIAG_PORT_EQ_STATUS_OP_PER_PORT;
936 in->phys_port_id = port_id;
937 in->lane_id = 0;
938 in->dump_type = LANE_EQ_DUMP_TYPE_CURR;
939
940 if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
941 in->dump_type = LANE_EQ_DUMP_TYPE_PREV;
942 in->prev_rate = prev_speed;
943 }
944
945 if (end == SWITCHTEC_DIAG_LOCAL) {
946 in->cmd = MRPC_GEN5_PORT_EQ_LOCAL_TX_COEFF_DUMP;
947 loc_out = (struct switchtec_port_eq_coeff *)&buf[in_size];
948 ret = switchtec_cmd(dev, MRPC_PORT_EQ_STATUS, in, in_size,
949 loc_out, out_size);
950 if (ret) {
951 fprintf(stderr, "Error in switchtec cmd:%d\n", ret);
952 goto end;
953 }
954 } else if (end == SWITCHTEC_DIAG_FAR_END) {
955 in->cmd = MRPC_GEN5_PORT_EQ_FAR_END_TX_COEFF_DUMP;
956 rem_out = (struct switchtec_rem_port_eq_coeff *)&buf[in_size];
957 ret = switchtec_cmd(dev, MRPC_PORT_EQ_STATUS, in, in_size,
958 rem_out, out_size);
959 if (ret) {
960 fprintf(stderr, "Error in switchtec cmd:%d\n", ret);
961 goto end;
962 }
963 } else {
964 fprintf(stderr, "Error inval end request\n");
965 errno = -EINVAL;
966 goto end;
967 }
968
969 if (end == SWITCHTEC_DIAG_LOCAL) {
970 res->lane_cnt = loc_out->lane_cnt + 1;
971 for (i = 0; i < res->lane_cnt; i++) {
972 res->cursors[i].pre = loc_out->cursors[i].pre;
973 res->cursors[i].post = loc_out->cursors[i].post;
974 }
975 } else {
976 res->lane_cnt = rem_out->lane_cnt + 1;
977 for (i = 0; i < res->lane_cnt; i++) {
978 res->cursors[i].pre = rem_out->cursors[i].pre;
979 res->cursors[i].post = rem_out->cursors[i].post;
980 }
981 }
982
983end:
984 if (buf)
985 free(buf);
986
987 return ret;
988}
989
999static int switchtec_gen4_diag_port_eq_tx_coeff(struct switchtec_dev *dev,
1000 int port_id,
1001 enum switchtec_diag_end end,
1002 enum switchtec_diag_link link,
1004 *res)
1005{
1006 struct switchtec_diag_port_eq_status_out out = {};
1008 .op_type = DIAG_PORT_EQ_STATUS_OP_PER_PORT,
1009 .port_id = port_id,
1010 };
1011 struct switchtec_diag_ext_dump_coeff_prev_in in_prev = {
1012 .op_type = DIAG_PORT_EQ_STATUS_OP_PER_PORT,
1013 .port_id = port_id,
1014 };
1015 int ret, i;
1016
1017 if (!res) {
1018 errno = -EINVAL;
1019 return -1;
1020 }
1021
1022 if (end == SWITCHTEC_DIAG_LOCAL) {
1023 in.sub_cmd = MRPC_PORT_EQ_LOCAL_TX_COEFF_DUMP;
1024 in_prev.sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_LOCAL_TX_COEFF_PREV;
1025 } else if (end == SWITCHTEC_DIAG_FAR_END) {
1026 in.sub_cmd = MRPC_PORT_EQ_FAR_END_TX_COEFF_DUMP;
1027 in_prev.sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_FAR_END_TX_COEFF_PREV;
1028 } else {
1029 errno = -EINVAL;
1030 return -1;
1031 }
1032
1033 if (link == SWITCHTEC_DIAG_LINK_CURRENT) {
1034 ret = switchtec_cmd(dev, MRPC_PORT_EQ_STATUS, &in, sizeof(in),
1035 &out, sizeof(out));
1036 } else if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
1037 ret = switchtec_cmd(dev, MRPC_EXT_RCVR_OBJ_DUMP, &in_prev,
1038 sizeof(in_prev), &out, sizeof(out));
1039 } else {
1040 errno = -EINVAL;
1041 return -1;
1042 }
1043
1044 if (ret)
1045 return -1;
1046
1047 res->lane_cnt = out.lane_id + 1;
1048 for (i = 0; i < res->lane_cnt; i++) {
1049 res->cursors[i].pre = out.cursors[i].pre;
1050 res->cursors[i].post = out.cursors[i].post;
1051 }
1052
1053 return 0;
1054}
1055
1056static int switchtec_gen6_diag_port_eq_tx_coeff(struct switchtec_dev *dev,
1057 int port_id, int prev_speed,
1058 enum switchtec_diag_end end,
1059 enum switchtec_diag_link link,
1061 *res)
1062{
1063 struct switchtec_port_eq_coeff *loc_out;
1064 struct switchtec_rem_port_eq_coeff *rem_out;
1065 struct switchtec_port_eq_coeff_in *in;
1066 uint8_t *buf;
1067 uint32_t buf_size;
1068 uint32_t in_size = sizeof(struct switchtec_port_eq_coeff_in);
1069 uint32_t out_size = 0;
1070 int ret = 0;
1071 int i;
1072
1073 if (!res) {
1074 errno = -EINVAL;
1075 return -1;
1076 }
1077
1078 buf_size = in_size;
1079 if (end == SWITCHTEC_DIAG_LOCAL) {
1080 buf_size += sizeof(struct switchtec_port_eq_coeff);
1081 out_size = sizeof(struct switchtec_port_eq_coeff);
1082 } else if (end == SWITCHTEC_DIAG_FAR_END) {
1083 buf_size += sizeof(struct switchtec_rem_port_eq_coeff);
1084 out_size = sizeof(struct switchtec_rem_port_eq_coeff);
1085 } else {
1086 errno = -EINVAL;
1087 return -1;
1088 }
1089
1090 buf = (uint8_t *)malloc(buf_size);
1091 if (!buf) {
1092 errno = -ENOMEM;
1093 return -1;
1094 }
1095
1096 in = (struct switchtec_port_eq_coeff_in *)buf;
1097 in->op_type = DIAG_PORT_EQ_STATUS_OP_PER_PORT;
1098 in->phys_port_id = port_id;
1099 in->lane_id = 0;
1100 in->dump_type = LANE_EQ_DUMP_TYPE_CURR;
1101
1102 if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
1103 in->dump_type = LANE_EQ_DUMP_TYPE_PREV;
1104 in->prev_rate = prev_speed;
1105 }
1106
1107 if (end == SWITCHTEC_DIAG_LOCAL) {
1108 in->cmd = MRPC_GEN6_PORT_EQ_LOCAL_TX_COEFF_DUMP;
1109 loc_out = (struct switchtec_port_eq_coeff *)&buf[in_size];
1110 ret = switchtec_cmd(dev, MRPC_PORT_EQ_STATUS, in, in_size,
1111 loc_out, out_size);
1112 if (ret)
1113 goto end;
1114 } else {
1115 in->cmd = MRPC_GEN6_PORT_EQ_FAR_END_TX_COEFF_DUMP;
1116 rem_out = (struct switchtec_rem_port_eq_coeff *)&buf[in_size];
1117 ret = switchtec_cmd(dev, MRPC_PORT_EQ_STATUS, in, in_size,
1118 rem_out, out_size);
1119 if (ret)
1120 goto end;
1121 }
1122
1123 if (end == SWITCHTEC_DIAG_LOCAL) {
1124 res->lane_cnt = loc_out->lane_cnt + 1;
1125 for (i = 0; i < res->lane_cnt; i++) {
1126 res->cursors[i].pre = loc_out->cursors[i].pre;
1127 res->cursors[i].post = loc_out->cursors[i].post;
1128 }
1129 } else {
1130 res->lane_cnt = rem_out->lane_cnt + 1;
1131 for (i = 0; i < res->lane_cnt; i++) {
1132 res->cursors[i].pre = rem_out->cursors[i].pre;
1133 res->cursors[i].post = rem_out->cursors[i].post;
1134 }
1135 }
1136
1137end:
1138 free(buf);
1139 return ret;
1140}
1141
1151int switchtec_diag_port_eq_tx_coeff(struct switchtec_dev *dev, int port_id,
1152 int prev_speed, enum switchtec_diag_end end,
1153 enum switchtec_diag_link link,
1154 struct switchtec_port_eq_coeff *res)
1155{
1156 int ret = -1;
1157
1158 if (switchtec_is_gen6(dev))
1159 ret = switchtec_gen6_diag_port_eq_tx_coeff(dev, port_id,
1160 prev_speed, end,
1161 link, res);
1162 else if (switchtec_is_gen5(dev))
1163 ret = switchtec_gen5_diag_port_eq_tx_coeff(dev, port_id,
1164 prev_speed, end,
1165 link, res);
1166 else if (switchtec_is_gen4(dev))
1167 ret = switchtec_gen4_diag_port_eq_tx_coeff(dev, port_id, end,
1168 link, res);
1169 else
1170 errno = EOPNOTSUPP;
1171
1172 return ret;
1173}
1174
1183static int switchtec_gen5_diag_port_eq_tx_table(struct switchtec_dev *dev,
1184 int port_id, int prev_speed,
1185 enum switchtec_diag_link link,
1187 *res)
1188{
1189 struct switchtec_gen5_port_eq_table out = {};
1190 struct switchtec_port_eq_table_in in = {
1191 .sub_cmd = MRPC_GEN5_PORT_EQ_FAR_END_TX_EQ_TABLE_DUMP,
1192 .port_id = port_id,
1193 };
1194 int ret, i;
1195
1196 if (!res) {
1197 errno = -EINVAL;
1198 return -1;
1199 }
1200
1201 in.dump_type = LANE_EQ_DUMP_TYPE_CURR;
1202 in.prev_rate = 0;
1203
1204 if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
1205 in.dump_type = LANE_EQ_DUMP_TYPE_PREV;
1206 in.prev_rate = prev_speed;
1207 }
1208
1209 ret = switchtec_cmd(dev, MRPC_PORT_EQ_STATUS, &in,
1210 sizeof(struct switchtec_port_eq_table_in),
1211 &out, sizeof(struct switchtec_gen5_port_eq_table));
1212 if (ret)
1213 return -1;
1214
1215 res->lane_id = out.lane_id;
1216 res->step_cnt = out.step_cnt;
1217
1218 for (i = 0; i < res->step_cnt; i++) {
1219 res->steps[i].pre_cursor = out.steps[i].pre_cursor;
1220 res->steps[i].post_cursor = out.steps[i].post_cursor;
1221 res->steps[i].fom = 0;
1222 res->steps[i].pre_cursor_up = 0;
1223 res->steps[i].post_cursor_up = 0;
1224 res->steps[i].error_status = out.steps[i].error_status;
1225 res->steps[i].active_status = out.steps[i].active_status;
1226 res->steps[i].speed = out.steps[i].speed;
1227 }
1228
1229 return 0;
1230}
1231
1240static int switchtec_gen4_diag_port_eq_tx_table(struct switchtec_dev *dev,
1241 int port_id,
1242 enum switchtec_diag_link link,
1244 *res)
1245{
1246 struct switchtec_diag_port_eq_table_out out = {};
1248 .sub_cmd = MRPC_PORT_EQ_FAR_END_TX_EQ_TABLE_DUMP,
1249 .port_id = port_id,
1250 };
1251 struct switchtec_diag_port_eq_status_in2 in_prev = {
1252 .sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_EQ_TX_TABLE_PREV,
1253 .port_id = port_id,
1254 };
1255 int ret, i;
1256
1257 if (!res) {
1258 errno = -EINVAL;
1259 return -1;
1260 }
1261
1262 if (link == SWITCHTEC_DIAG_LINK_CURRENT) {
1263 ret = switchtec_cmd(dev, MRPC_PORT_EQ_STATUS, &in, sizeof(in),
1264 &out, sizeof(out));
1265 } else if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
1266 ret = switchtec_cmd(dev, MRPC_EXT_RCVR_OBJ_DUMP, &in_prev,
1267 sizeof(in_prev), &out, sizeof(out));
1268 } else {
1269 errno = -EINVAL;
1270 return -1;
1271 }
1272
1273 if (ret)
1274 return -1;
1275
1276 res->lane_id = out.lane_id;
1277 res->step_cnt = out.step_cnt;
1278 for (i = 0; i < res->step_cnt; i++) {
1279 res->steps[i].pre_cursor = out.steps[i].pre_cursor;
1280 res->steps[i].post_cursor = out.steps[i].post_cursor;
1281 res->steps[i].fom = out.steps[i].fom;
1282 res->steps[i].pre_cursor_up = out.steps[i].pre_cursor_up;
1283 res->steps[i].post_cursor_up = out.steps[i].post_cursor_up;
1284 res->steps[i].error_status = out.steps[i].error_status;
1285 res->steps[i].active_status = out.steps[i].active_status;
1286 res->steps[i].speed = out.steps[i].speed;
1287 }
1288
1289 return 0;
1290}
1291
1300int switchtec_diag_port_eq_tx_table(struct switchtec_dev *dev, int port_id, int prev_speed,
1301 enum switchtec_diag_link link,
1302 struct switchtec_port_eq_table *res)
1303{
1304 int ret = -1;
1305
1306 if (switchtec_is_gen6(dev))
1307 ret = switchtec_gen5_diag_port_eq_tx_table(dev, port_id,
1308 prev_speed, link,
1309 res);
1310 else if (switchtec_is_gen5(dev))
1311 ret = switchtec_gen5_diag_port_eq_tx_table(dev, port_id,
1312 prev_speed, link,
1313 res);
1314 else if (switchtec_is_gen4(dev))
1315 ret = switchtec_gen4_diag_port_eq_tx_table(dev, port_id, link,
1316 res);
1317 else
1318 errno = EOPNOTSUPP;
1319
1320 return ret;
1321}
1322
1333static int switchtec_gen5_diag_port_eq_tx_fslf(struct switchtec_dev *dev,
1334 int port_id, int prev_speed,
1335 int lane_id,
1336 enum switchtec_diag_end end,
1337 enum switchtec_diag_link link,
1339 *res)
1340{
1341 struct switchtec_port_eq_tx_fslf_in in = {};
1342 struct switchtec_port_eq_tx_fslf_out out = {};
1343 int ret;
1344
1345 if (!res) {
1346 errno = -EINVAL;
1347 return -1;
1348 }
1349
1350 in.port_id = port_id;
1351 in.lane_id = lane_id;
1352
1353
1354 if (end == SWITCHTEC_DIAG_LOCAL) {
1355 in.sub_cmd = MRPC_GEN5_PORT_EQ_LOCAL_TX_FSLF_DUMP;
1356 } else if (end == SWITCHTEC_DIAG_FAR_END) {
1357 in.sub_cmd = MRPC_GEN5_PORT_EQ_FAR_END_TX_FSLF_DUMP;
1358 } else {
1359 errno = -EINVAL;
1360 return -1;
1361 }
1362
1363 if (link == SWITCHTEC_DIAG_LINK_CURRENT) {
1364 in.dump_type = LANE_EQ_DUMP_TYPE_CURR;
1365 } else {
1366 in.dump_type = LANE_EQ_DUMP_TYPE_PREV;
1367 in.prev_rate = prev_speed;
1368 }
1369
1370 ret = switchtec_cmd(dev, MRPC_PORT_EQ_STATUS, &in,
1371 sizeof(struct switchtec_port_eq_tx_fslf_in), &out,
1372 sizeof(struct switchtec_port_eq_tx_fslf_out));
1373 if (ret)
1374 return -1;
1375
1376 res->fs = out.fs;
1377 res->lf = out.lf;
1378
1379 return 0;
1380}
1381
1392static int switchtec_gen4_diag_port_eq_tx_fslf(struct switchtec_dev *dev,
1393 int port_id, int lane_id,
1394 enum switchtec_diag_end end,
1395 enum switchtec_diag_link link,
1397 *res)
1398{
1399 struct switchtec_diag_port_eq_tx_fslf_out out = {};
1401 .port_id = port_id,
1402 .lane_id = lane_id,
1403 };
1404 struct switchtec_diag_ext_recv_obj_dump_in in_prev = {
1405 .port_id = port_id,
1406 .lane_id = lane_id,
1407 };
1408 int ret;
1409
1410 if (!res) {
1411 errno = -EINVAL;
1412 return -1;
1413 }
1414
1415 if (end == SWITCHTEC_DIAG_LOCAL) {
1416 in.sub_cmd = MRPC_PORT_EQ_LOCAL_TX_FSLF_DUMP;
1417 in_prev.sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_LOCAL_TX_FSLF_PREV;
1418 } else if (end == SWITCHTEC_DIAG_FAR_END) {
1419 in.sub_cmd = MRPC_PORT_EQ_FAR_END_TX_FSLF_DUMP;
1420 in_prev.sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_FAR_END_TX_FSLF_PREV;
1421 } else {
1422 errno = -EINVAL;
1423 return -1;
1424 }
1425
1426 if (link == SWITCHTEC_DIAG_LINK_CURRENT) {
1427 ret = switchtec_cmd(dev, MRPC_PORT_EQ_STATUS, &in, sizeof(in),
1428 &out, sizeof(out));
1429 } else if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
1430 ret = switchtec_cmd(dev, MRPC_EXT_RCVR_OBJ_DUMP, &in_prev,
1431 sizeof(in_prev), &out, sizeof(out));
1432 } else {
1433 errno = -EINVAL;
1434 return -1;
1435 }
1436
1437 if (ret)
1438 return -1;
1439
1440 res->fs = out.fs;
1441 res->lf = out.lf;
1442
1443 return 0;
1444}
1445
1446static int switchtec_gen6_diag_port_eq_tx_fslf(struct switchtec_dev *dev,
1447 int port_id, int prev_speed,
1448 int lane_id,
1449 enum switchtec_diag_end end,
1450 enum switchtec_diag_link link,
1452 *res)
1453{
1454 struct switchtec_port_eq_tx_fslf_in in = {};
1455 struct switchtec_port_eq_tx_fslf_out out = {};
1456 int ret;
1457
1458 if (!res) {
1459 errno = -EINVAL;
1460 return -1;
1461 }
1462
1463 in.port_id = port_id;
1464 in.lane_id = lane_id;
1465
1466 if (end == SWITCHTEC_DIAG_LOCAL) {
1467 in.sub_cmd = MRPC_GEN6_PORT_EQ_LOCAL_TX_FSLF_DUMP;
1468 } else if (end == SWITCHTEC_DIAG_FAR_END) {
1469 in.sub_cmd = MRPC_GEN6_PORT_EQ_FAR_END_TX_FSLF_DUMP;
1470 } else {
1471 errno = -EINVAL;
1472 return -1;
1473 }
1474
1475 if (link == SWITCHTEC_DIAG_LINK_CURRENT) {
1476 in.dump_type = LANE_EQ_DUMP_TYPE_CURR;
1477 } else {
1478 in.dump_type = LANE_EQ_DUMP_TYPE_PREV;
1479 in.prev_rate = prev_speed;
1480 }
1481
1482 ret = switchtec_cmd(dev, MRPC_PORT_EQ_STATUS, &in,
1483 sizeof(struct switchtec_port_eq_tx_fslf_in), &out,
1484 sizeof(struct switchtec_port_eq_tx_fslf_out));
1485 if (ret)
1486 return -1;
1487
1488 res->fs = out.fs;
1489 res->lf = out.lf;
1490
1491 return 0;
1492}
1493
1504int switchtec_diag_port_eq_tx_fslf(struct switchtec_dev *dev, int port_id,
1505 int prev_speed, int lane_id,
1506 enum switchtec_diag_end end,
1507 enum switchtec_diag_link link,
1508 struct switchtec_port_eq_tx_fslf *res)
1509{
1510 int ret = -1;
1511
1512 if (switchtec_is_gen6(dev))
1513 ret = switchtec_gen6_diag_port_eq_tx_fslf(dev, port_id,
1514 prev_speed, lane_id,
1515 end, link, res);
1516 else if (switchtec_is_gen5(dev))
1517 ret = switchtec_gen5_diag_port_eq_tx_fslf(dev, port_id,
1518 prev_speed, lane_id,
1519 end, link, res);
1520 else if (switchtec_is_gen4(dev))
1521 ret = switchtec_gen4_diag_port_eq_tx_fslf(dev, port_id,
1522 lane_id, end,
1523 link, res);
1524 else
1525 errno = EOPNOTSUPP;
1526
1527 return ret;
1528}
1529
1540int switchtec_diag_rcvr_ext(struct switchtec_dev *dev, int port_id,
1541 int lane_id, enum switchtec_diag_link link,
1542 struct switchtec_rcvr_ext *res)
1543{
1544 struct switchtec_diag_rcvr_ext_out out = {};
1546 .port_id = port_id,
1547 .lane_id = lane_id,
1548 };
1549 int ret;
1550
1551 if (!res) {
1552 errno = -EINVAL;
1553 return -1;
1554 }
1555
1556 if (link == SWITCHTEC_DIAG_LINK_CURRENT) {
1557 in.sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_RCVR_EXT;
1558 } else if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
1559 in.sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_RCVR_EXT_PREV;
1560 } else {
1561 errno = -EINVAL;
1562 return -1;
1563 }
1564
1565 ret = switchtec_cmd(dev, MRPC_EXT_RCVR_OBJ_DUMP, &in, sizeof(in),
1566 &out, sizeof(out));
1567 if (ret)
1568 return -1;
1569
1570 res->ctle2_rx_mode = out.ctle2_rx_mode;
1571 res->dtclk_9 = out.dtclk_9;
1572 res->dtclk_8_6 = out.dtclk_8_6;
1573 res->dtclk_5 = out.dtclk_5;
1574
1575 return 0;
1576}
1577
1585int switchtec_diag_perm_table(struct switchtec_dev *dev,
1586 struct switchtec_mrpc table[MRPC_MAX_ID])
1587{
1588 uint32_t perms[(MRPC_MAX_ID + 31) / 32];
1589 int i, ret;
1590
1591 ret = switchtec_cmd(dev, MRPC_MRPC_PERM_TABLE_GET, NULL, 0,
1592 perms, sizeof(perms));
1593 if (ret)
1594 return -1;
1595
1596 for (i = 0; i < MRPC_MAX_ID; i++) {
1597 if (perms[i >> 5] & (1 << (i & 0x1f))) {
1598 if (switchtec_mrpc_table[i].tag) {
1599 table[i] = switchtec_mrpc_table[i];
1600 } else {
1601 table[i].tag = "UNKNOWN";
1602 table[i].desc = "Unknown MRPC Command";
1603 table[i].reserved = true;
1604 }
1605 } else {
1606 table[i].tag = NULL;
1607 table[i].desc = NULL;
1608 }
1609 }
1610
1611 return 0;
1612}
1613
1622int switchtec_diag_refclk_ctl(struct switchtec_dev *dev, int id, bool en)
1623{
1624 if (switchtec_is_gen6(dev)) {
1626 .sub_cmd = en ? MRPC_REFCLK_S_ENABLE_GEN6 :
1627 MRPC_REFCLK_S_DISABLE_GEN6,
1628 .csu_id = id,
1629 };
1630
1631 return switchtec_cmd(dev, MRPC_REFCLK_S, &cmd, sizeof(cmd),
1632 NULL, 0);
1633 } else {
1634 struct switchtec_diag_refclk_ctl_in cmd = {
1635 .sub_cmd = en ? MRPC_REFCLK_S_ENABLE :
1636 MRPC_REFCLK_S_DISABLE,
1637 .stack_id = id,
1638 };
1639
1640 return switchtec_cmd(dev, MRPC_REFCLK_S, &cmd, sizeof(cmd),
1641 NULL, 0);
1642 }
1643}
1644
1651int switchtec_diag_refclk_status(struct switchtec_dev *dev, uint8_t *info)
1652{
1653 if (switchtec_is_gen6(dev)) {
1655 .sub_cmd = MRPC_REFCLK_S_STATUS_GEN6,
1656 };
1657
1658 return switchtec_cmd(dev, MRPC_REFCLK_S, &cmd, sizeof(cmd),
1659 info,
1660 sizeof(uint8_t) * SWITCHTEC_MAX_STACKS_GEN6);
1661 } else {
1662 struct switchtec_diag_refclk_ctl_in cmd = {
1663 .sub_cmd = MRPC_REFCLK_S_STATUS,
1664 };
1665
1666 return switchtec_cmd(dev, MRPC_REFCLK_S, &cmd, sizeof(cmd),
1667 info,
1668 sizeof(uint8_t) * SWITCHTEC_MAX_STACKS);
1669 }
1670}
1671
1672static void switchtec_diag_ltssm_set_log_data_gen5(struct switchtec_diag_ltssm_log
1673 *log_data,
1675 *log_dump_out_ptr,
1676 int curr_idx, uint16_t num_of_logs)
1677{
1678 uint32_t dw0;
1679 uint32_t timestamp;
1680
1681 int major;
1682 int minor;
1683 int rate;
1684
1685 for (int j = 0; j < num_of_logs; j++) {
1686 dw0 = log_dump_out_ptr[j].dw0;
1687 timestamp = log_dump_out_ptr[j].ram_timestamp;
1688
1689 rate = (dw0 >> 13) & 0x7;
1690 major = (dw0 >> 7) & 0x3f;
1691 minor = (dw0 >> 3) & 0xf;
1692
1693 log_data[curr_idx + j].timestamp = timestamp;
1694 log_data[curr_idx + j].link_rate = switchtec_gen_transfers[rate+1];
1695 log_data[curr_idx + j].link_state = major | (minor << 8);
1696 }
1697}
1698
1699static void switchtec_diag_ltssm_set_log_data_gen6(struct switchtec_diag_ltssm_log
1700 *log_data,
1702 *log_dump_out_ptr,
1703 int curr_idx, uint16_t num_of_logs)
1704{
1705 uint32_t dw0;
1706 uint32_t timestamp;
1707
1708 int major;
1709 int rate;
1710 int link_width;
1711
1712 for (int j = 0; j < num_of_logs; j++) {
1713 dw0 = log_dump_out_ptr[j].dw0;
1714 timestamp = log_dump_out_ptr[j].ram_timestamp;
1715
1716 link_width = (dw0 >> 16) & 0x3f;
1717 rate = (dw0 >> 12) & 0x7;
1718 major = (dw0 >> 6) & 0x3f;
1719
1720 log_data[curr_idx + j].timestamp = timestamp;
1721 log_data[curr_idx + j].link_rate = switchtec_gen_transfers[rate+1];
1722 log_data[curr_idx + j].link_state = major;
1723 log_data[curr_idx + j].link_width = link_width;
1724 }
1725}
1726
1734static int switchtec_diag_ltssm_log_gen5(struct switchtec_dev *dev,
1735 int port, int *log_count,
1736 struct switchtec_diag_ltssm_log *log_data)
1737{
1738 struct {
1739 uint8_t sub_cmd;
1740 uint8_t port;
1741 uint8_t freeze;
1742 uint8_t unused;
1743 } ltssm_freeze;
1744
1745 struct {
1746 uint8_t sub_cmd;
1747 uint8_t port;
1748 } status;
1749
1750 struct {
1751 uint16_t log_count;
1752 uint16_t w0_trigger_count;
1753 uint16_t w1_trigger_count;
1754 } status_output;
1755
1756 struct {
1757 uint8_t sub_cmd;
1758 uint8_t port;
1759 uint16_t log_index;
1760 uint16_t no_of_logs;
1761 } log_dump;
1762
1763 uint8_t log_buffer[1024];
1764
1765 struct switchtec_diag_ltssm_log_dmp_out *log_dump_out_ptr = NULL;
1766
1767 int ret;
1768 int log_dmp_size = sizeof(struct switchtec_diag_ltssm_log_dmp_out);
1769
1770 /* freeze logs */
1771 ltssm_freeze.sub_cmd = MRPC_LTMON_FREEZE;
1772 ltssm_freeze.port = port;
1773 ltssm_freeze.freeze = 1;
1774
1775 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &ltssm_freeze,
1776 sizeof(ltssm_freeze), NULL, 0);
1777 if (ret)
1778 return ret;
1779
1780 /* get number of entries */
1781 status.sub_cmd = MRPC_LTMON_GET_STATUS_GEN5;
1782 status.port = port;
1783 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &status,
1784 sizeof(status), &status_output,
1785 sizeof(status_output));
1786 if (ret)
1787 return ret;
1788
1789 *log_count = status_output.log_count;
1790
1791 /* get log data */
1792 log_dump.sub_cmd = MRPC_LTMON_LOG_DUMP_GEN5;
1793 log_dump.port = port;
1794 log_dump.log_index = 0;
1795 log_dump.no_of_logs = *log_count;
1796
1797 if (log_dump.no_of_logs <= SWITCHTEC_LTSSM_MAX_LOGS) {
1798 /* Single buffer log case */
1799 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &log_dump,
1800 sizeof(log_dump), &log_buffer[0],
1801 log_dump.no_of_logs * log_dmp_size + 4);
1802 if (ret)
1803 return ret;
1804 log_dump_out_ptr =
1806 &(log_buffer[4]);
1807
1808 switchtec_diag_ltssm_set_log_data_gen5(log_data,
1809 log_dump_out_ptr,
1810 0, log_dump.no_of_logs);
1811 } else {
1812 /* Multiple buffer log case */
1813 int buff_count = log_dump.no_of_logs / SWITCHTEC_LTSSM_MAX_LOGS;
1814 int curr_idx = 0;
1815 int buffer_size = SWITCHTEC_LTSSM_MAX_LOGS * log_dmp_size + 4;
1816
1817 for (int i = 0; i < buff_count; i++) {
1818 log_dump.no_of_logs = SWITCHTEC_LTSSM_MAX_LOGS;
1819 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG,
1820 &log_dump, sizeof(log_dump),
1821 &log_buffer[0], buffer_size);
1822 if (ret)
1823 return ret;
1824 log_dump_out_ptr =
1826 &(log_buffer[4]);
1827
1828 switchtec_diag_ltssm_set_log_data_gen5(log_data,
1829 log_dump_out_ptr,
1830 curr_idx,
1831 log_dump.no_of_logs);
1832 curr_idx += SWITCHTEC_LTSSM_MAX_LOGS;
1833 log_dump.log_index = curr_idx;
1834 }
1835 if (*log_count % SWITCHTEC_LTSSM_MAX_LOGS) {
1836 log_dump.no_of_logs = *log_count - curr_idx;
1837 buffer_size = log_dump.no_of_logs * log_dmp_size + 4;
1838 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG,
1839 &log_dump, sizeof(log_dump),
1840 &log_buffer[0], buffer_size);
1841 if (ret)
1842 return ret;
1843 log_dump_out_ptr =
1845 &(log_buffer[4]);
1846
1847 switchtec_diag_ltssm_set_log_data_gen5(log_data,
1848 log_dump_out_ptr,
1849 curr_idx,
1850 log_dump.no_of_logs);
1851 }
1852 }
1853
1854 /* unfreeze logs */
1855 ltssm_freeze.sub_cmd = MRPC_LTMON_FREEZE;
1856 ltssm_freeze.port = port;
1857 ltssm_freeze.freeze = 0;
1858
1859 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &ltssm_freeze,
1860 sizeof(ltssm_freeze), NULL, 0);
1861
1862 return ret;
1863}
1864
1872static int switchtec_diag_ltssm_log_gen6(struct switchtec_dev *dev,
1873 int port, int *log_count,
1874 struct switchtec_diag_ltssm_log *log_data)
1875{
1876 struct {
1877 uint8_t sub_cmd;
1878 uint8_t port;
1879 uint8_t freeze;
1880 uint8_t unused;
1881 } ltssm_freeze;
1882
1883 struct {
1884 uint8_t sub_cmd;
1885 uint8_t port;
1886 } status;
1887
1888 struct {
1889 uint16_t log_count;
1890 uint16_t w0_trigger_count;
1891 uint16_t w1_trigger_count;
1892 } status_output;
1893
1894 struct {
1895 uint8_t sub_cmd;
1896 uint8_t port;
1897 uint16_t log_index;
1898 uint16_t no_of_logs;
1899 } log_dump;
1900
1901 uint8_t log_buffer[1024];
1902
1903 struct switchtec_diag_ltssm_log_dmp_out *log_dump_out_ptr = NULL;
1904
1905 int ret;
1906 int log_dmp_size = sizeof(struct switchtec_diag_ltssm_log_dmp_out);
1907
1908 /* freeze logs */
1909 ltssm_freeze.sub_cmd = MRPC_LTMON_FREEZE;
1910 ltssm_freeze.port = port;
1911 ltssm_freeze.freeze = 1;
1912
1913 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &ltssm_freeze,
1914 sizeof(ltssm_freeze), NULL, 0);
1915 if (ret)
1916 return ret;
1917
1918 /* get number of entries */
1919 status.sub_cmd = MRPC_LTMON_GET_STATUS_GEN5;
1920 status.port = port;
1921 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &status,
1922 sizeof(status), &status_output,
1923 sizeof(status_output));
1924 if (ret)
1925 return ret;
1926
1927 *log_count = status_output.log_count;
1928
1929 /* get log data */
1930 log_dump.sub_cmd = MRPC_LTMON_LOG_DUMP_GEN5;
1931 log_dump.port = port;
1932 log_dump.log_index = 0;
1933 log_dump.no_of_logs = *log_count;
1934
1935 if (log_dump.no_of_logs <= SWITCHTEC_LTSSM_MAX_LOGS) {
1936 /* Single buffer log case */
1937 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &log_dump,
1938 sizeof(log_dump), &log_buffer[0],
1939 log_dump.no_of_logs * log_dmp_size + 4);
1940 if (ret)
1941 return ret;
1942 log_dump_out_ptr =
1944 &(log_buffer[4]);
1945
1946 switchtec_diag_ltssm_set_log_data_gen6(log_data,
1947 log_dump_out_ptr,
1948 0, log_dump.no_of_logs);
1949 } else {
1950 /* Multiple buffer log case */
1951 int buff_count = log_dump.no_of_logs / SWITCHTEC_LTSSM_MAX_LOGS;
1952 int curr_idx = 0;
1953 int buffer_size = SWITCHTEC_LTSSM_MAX_LOGS * log_dmp_size + 4;
1954
1955 for (int i = 0; i < buff_count; i++) {
1956 log_dump.no_of_logs = SWITCHTEC_LTSSM_MAX_LOGS;
1957 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG,
1958 &log_dump, sizeof(log_dump),
1959 &log_buffer[0], buffer_size);
1960 if (ret)
1961 return ret;
1962 log_dump_out_ptr =
1964 &(log_buffer[4]);
1965
1966 switchtec_diag_ltssm_set_log_data_gen6(log_data,
1967 log_dump_out_ptr,
1968 curr_idx,
1969 log_dump.no_of_logs);
1970 curr_idx += SWITCHTEC_LTSSM_MAX_LOGS;
1971 log_dump.log_index = curr_idx;
1972 }
1973 if (*log_count % SWITCHTEC_LTSSM_MAX_LOGS) {
1974 log_dump.no_of_logs = *log_count - curr_idx;
1975 buffer_size = log_dump.no_of_logs * log_dmp_size + 4;
1976 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG,
1977 &log_dump, sizeof(log_dump),
1978 &log_buffer[0], buffer_size);
1979 if (ret)
1980 return ret;
1981 log_dump_out_ptr =
1983 &(log_buffer[4]);
1984
1985 switchtec_diag_ltssm_set_log_data_gen6(log_data,
1986 log_dump_out_ptr,
1987 curr_idx,
1988 log_dump.no_of_logs);
1989 }
1990 }
1991
1992 /* unfreeze logs */
1993 ltssm_freeze.sub_cmd = MRPC_LTMON_FREEZE;
1994 ltssm_freeze.port = port;
1995 ltssm_freeze.freeze = 0;
1996
1997 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &ltssm_freeze,
1998 sizeof(ltssm_freeze), NULL, 0);
1999
2000 return ret;
2001}
2002
2010static int switchtec_diag_ltssm_log_gen4(struct switchtec_dev *dev,
2011 int port, int *log_count,
2012 struct switchtec_diag_ltssm_log *log_data)
2013{
2014 struct {
2015 uint8_t sub_cmd;
2016 uint8_t port;
2017 uint8_t freeze;
2018 uint8_t unused;
2019 } ltssm_freeze;
2020
2021 struct {
2022 uint8_t sub_cmd;
2023 uint8_t port;
2024 } status;
2025 struct {
2026 uint32_t w0_trigger_count;
2027 uint32_t w1_trigger_count;
2028 uint8_t log_num;
2029 } status_output;
2030
2031 struct {
2032 uint8_t sub_cmd;
2033 uint8_t port;
2034 uint8_t log_index;
2035 uint8_t no_of_logs;
2036 } log_dump;
2037 struct {
2038 uint32_t dw0;
2039 uint32_t dw1;
2040 } log_dump_out[256];
2041
2042 uint32_t dw1;
2043 uint32_t dw0;
2044 int major;
2045 int minor;
2046 int rate;
2047 int ret;
2048 int i;
2049
2050 /* freeze logs */
2051 ltssm_freeze.sub_cmd = MRPC_LTMON_FREEZE;
2052 ltssm_freeze.port = port;
2053 ltssm_freeze.freeze = 1;
2054
2055 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &ltssm_freeze,
2056 sizeof(ltssm_freeze), NULL, 0);
2057 if (ret)
2058 return ret;
2059
2060 /* get number of entries */
2061 status.sub_cmd = MRPC_LTMON_GET_STATUS_GEN4;
2062 status.port = port;
2063 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &status,
2064 sizeof(status), &status_output,
2065 sizeof(status_output));
2066 if (ret)
2067 return ret;
2068
2069 if (status_output.log_num < *log_count)
2070 *log_count = status_output.log_num;
2071
2072 /* get log data */
2073 log_dump.sub_cmd = MRPC_LTMON_LOG_DUMP_GEN4;
2074 log_dump.port = port;
2075 log_dump.log_index = 0;
2076 log_dump.no_of_logs = *log_count;
2077 if (log_dump.no_of_logs <= 126) {
2078 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &log_dump,
2079 sizeof(log_dump), log_dump_out,
2080 8 * log_dump.no_of_logs);
2081 if (ret)
2082 return ret;
2083 } else {
2084 log_dump.no_of_logs = 126;
2085 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &log_dump,
2086 sizeof(log_dump), log_dump_out,
2087 8 * log_dump.no_of_logs);
2088 if (ret)
2089 return ret;
2090
2091 log_dump.log_index = 126;
2092 log_dump.no_of_logs = *log_count - 126;
2093
2094 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &log_dump,
2095 sizeof(log_dump), log_dump_out + 126,
2096 8 * log_dump.no_of_logs);
2097 if (ret)
2098 return ret;
2099 }
2100 for (i = 0; i < *log_count; i++) {
2101 dw1 = log_dump_out[i].dw1;
2102 dw0 = log_dump_out[i].dw0;
2103 rate = (dw0 >> 13) & 0x3;
2104 major = (dw0 >> 7) & 0xf;
2105 minor = (dw0 >> 3) & 0xf;
2106
2107 log_data[i].timestamp = dw1 & 0x3ffffff;
2108 log_data[i].link_rate = switchtec_gen_transfers[rate + 1];
2109 log_data[i].link_state = major | (minor << 8);
2110 }
2111
2112 /* unfreeze logs */
2113 ltssm_freeze.sub_cmd = MRPC_LTMON_FREEZE;
2114 ltssm_freeze.port = port;
2115 ltssm_freeze.freeze = 0;
2116
2117 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &ltssm_freeze,
2118 sizeof(ltssm_freeze), NULL, 0);
2119
2120 return ret;
2121}
2122
2130int switchtec_diag_ltssm_log(struct switchtec_dev *dev,
2131 int port, int *log_count,
2132 struct switchtec_diag_ltssm_log *log_data)
2133{
2134 int ret;
2135 if (switchtec_is_gen6(dev))
2136 ret = switchtec_diag_ltssm_log_gen6(dev, port, log_count, log_data);
2137 else if (switchtec_is_gen5(dev))
2138 ret = switchtec_diag_ltssm_log_gen5(dev, port, log_count, log_data);
2139 else
2140 ret = switchtec_diag_ltssm_log_gen4(dev, port, log_count, log_data);
2141 return ret;
2142}
2143
2149int switchtec_diag_ltssm_clear(struct switchtec_dev *dev, int port)
2150{
2151 int ret;
2152 struct {
2153 uint8_t subcmd;
2154 uint8_t port_id;
2155 uint16_t reserved;
2156 } ltssm_clear;
2157
2158 ltssm_clear.subcmd = MRPC_LTMON_CLEAR_LOG;
2159 ltssm_clear.port_id = port;
2160
2161 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &ltssm_clear,
2162 sizeof(ltssm_clear), NULL, 0);
2163 return ret;
2164}
2165
2166int switchtec_tlp_inject(struct switchtec_dev *dev, int port_id, int tlp_type,
2167 int tlp_length, int ecrc, uint32_t *raw_tlp_data)
2168{
2169 uint32_t tlp_out;
2170 int ret = 1;
2171 struct switchtec_tlp_inject_in tlp_in = {
2172 .dest_port = port_id,
2173 .tlp_type = tlp_type,
2174 .tlp_length = tlp_length,
2175 .ecrc = ecrc
2176 };
2177 for (int i = 0; i < tlp_in.tlp_length; i++) {
2178 tlp_in.raw_tlp_data[i] = htole32(*(raw_tlp_data + i));
2179 }
2180 free(raw_tlp_data);
2181
2182 ret = switchtec_cmd(dev, MRPC_DIAG_TLP_INJECT, &tlp_in, sizeof(tlp_in),
2183 &tlp_out, sizeof(tlp_out));
2184 return ret;
2185}
2186
2194int switchtec_aer_event_gen(struct switchtec_dev *dev, int port_id,
2195 int aer_error_id, int trigger_event)
2196{
2197 uint32_t output;
2198 int ret_val;
2199
2200 struct switchtec_aer_event_gen_in sub_cmd_id = {
2201 .sub_cmd = trigger_event,
2202 .phys_port_id = port_id,
2203 .err_mask = aer_error_id,
2204 .hdr_log[0] = 0,
2205 .hdr_log[1] = 0,
2206 .hdr_log[2] = 0,
2207 .hdr_log[3] = 0
2208 };
2209
2210 ret_val = switchtec_cmd(dev, MRPC_AER_GEN, &sub_cmd_id,
2211 sizeof(sub_cmd_id), &output, sizeof(output));
2212 return ret_val;
2213}
2214
2222int switchtec_inject_err_dllp(struct switchtec_dev *dev, int phys_port_id,
2223 int data)
2224{
2225 uint32_t output;
2226
2227 struct switchtec_lnkerr_dllp_in cmd = {
2228 .subcmd = MRPC_ERR_INJ_DLLP,
2229 .phys_port_id = phys_port_id,
2230 .data = data,
2231 };
2232
2233 return switchtec_cmd(dev, MRPC_MRPC_ERR_INJ, &cmd,
2234 sizeof(cmd), &output, sizeof(output));
2235}
2236
2245int switchtec_inject_err_dllp_crc(struct switchtec_dev *dev,
2246 int phys_port_id, int enable,
2247 uint16_t rate)
2248{
2249 uint32_t output;
2250
2251 struct switchtec_lnkerr_dllp_crc_in cmd = {
2252 .subcmd = MRPC_ERR_INJ_DLLP_CRC,
2253 .phys_port_id = phys_port_id,
2254 .enable = enable,
2255 .rate = rate,
2256 };
2257
2258 return switchtec_cmd(dev, MRPC_MRPC_ERR_INJ, &cmd,
2259 sizeof(cmd), &output, sizeof(output));
2260}
2261
2262static int switchtec_inject_err_tlp_lcrc_gen4(struct switchtec_dev *dev,
2263 int phys_port_id, int enable,
2264 uint8_t rate)
2265{
2266 uint32_t output;
2267
2269 .subcmd = MRPC_ERR_INJ_TLP_LCRC,
2270 .phys_port_id = phys_port_id,
2271 .enable = enable,
2272 .rate = rate,
2273 };
2274 return switchtec_cmd(dev, MRPC_MRPC_ERR_INJ, &cmd,
2275 sizeof(cmd), &output, sizeof(output));
2276}
2277
2278static int switchtec_inject_err_tlp_lcrc_gen5(struct switchtec_dev *dev,
2279 int phys_port_id, int enable,
2280 uint8_t rate)
2281{
2282 uint32_t output;
2283
2285 .subcmd = MRPC_ERR_INJ_TLP_LCRC,
2286 .phys_port_id = phys_port_id,
2287 .enable = enable,
2288 .rate = rate,
2289 };
2290
2291 return switchtec_cmd(dev, MRPC_MRPC_ERR_INJ, &cmd,
2292 sizeof(cmd), &output, sizeof(output));
2293}
2294
2302int switchtec_inject_err_tlp_lcrc(struct switchtec_dev *dev, int phy_port,
2303 int enable, uint8_t rate)
2304{
2305 int ret;
2306 if (switchtec_is_gen4(dev)) {
2307 ret = switchtec_inject_err_tlp_lcrc_gen4(dev, phy_port, enable, rate);
2308 return ret;
2309 } else if (switchtec_is_gen5(dev) || switchtec_is_gen6(dev)) {
2310 ret = switchtec_inject_err_tlp_lcrc_gen5(dev, phy_port, enable, rate);
2311 return ret;
2312 }
2313 fprintf(stderr, "TLP LCRC error injection is not supported on this device.\n");
2314 return -1;
2315}
2316
2323int switchtec_inject_err_tlp_seq_num(struct switchtec_dev *dev, int phys_port_id)
2324{
2325 uint32_t output;
2326
2327 struct switchtec_lnkerr_tlp_seqn_in cmd = {
2328 .subcmd = MRPC_ERR_INJ_TLP_SEQ,
2329 .phys_port_id = phys_port_id,
2330 };
2331
2332 return switchtec_cmd(dev, MRPC_MRPC_ERR_INJ, &cmd,
2333 sizeof(cmd), &output, sizeof(output));
2334}
2335
2344int switchtec_inject_err_ack_nack(struct switchtec_dev *dev, int phys_port_id,
2345 uint16_t seq_num, uint8_t count)
2346{
2347 uint32_t output;
2348
2349 struct switchtec_lnkerr_ack_nack_in cmd = {
2350 .subcmd = MRPC_ERR_INJ_ACK_NACK,
2351 .phys_port_id = phys_port_id,
2352 .seq_num = seq_num,
2353 .count = count,
2354 };
2355
2356 return switchtec_cmd(dev, MRPC_MRPC_ERR_INJ, &cmd,
2357 sizeof(cmd), &output, sizeof(output));
2358}
2359
2366int switchtec_inject_err_cto(struct switchtec_dev *dev, int phys_port_id)
2367{
2368 uint32_t output;
2369
2370 struct switchtec_lnkerr_cto_in cmd = {
2371 .subcmd = MRPC_ERR_INJ_CTO,
2372 .phys_port_id = phys_port_id,
2373 };
2374
2375 return switchtec_cmd(dev, MRPC_MRPC_ERR_INJ, &cmd,
2376 sizeof(cmd), &output, sizeof(output));
2377}
2378
2379int switchtec_osa_capture_data(struct switchtec_dev *dev, int stack_id,
2380 int lane, int direction,
2381 struct switchtec_osa_capture_data *data)
2382{
2383 int ret = 0;
2384 struct {
2385 uint8_t sub_cmd;
2386 uint8_t stack_id;
2387 uint8_t lane;
2388 uint8_t direction;
2389 uint16_t start_entry;
2390 uint8_t num_entries;
2391 uint8_t reserved;
2392 } osa_data_read_in;
2393
2394 struct {
2395 uint8_t entries_read;
2396 uint8_t stack_id;
2397 uint8_t lane;
2398 uint8_t direction;
2399 uint16_t next_entry;
2400 uint16_t entries_remaining;
2401 uint16_t wrap;
2402 uint16_t reserved;
2403 } osa_data_entries_out;
2404
2405 osa_data_read_in.sub_cmd = MRPC_OSA_DATA_READ;
2406 osa_data_read_in.stack_id = stack_id;
2407 osa_data_read_in.lane = lane;
2408 osa_data_read_in.direction = direction;
2409
2410 osa_data_read_in.start_entry = 0;
2411 osa_data_read_in.num_entries = 0;
2412
2413 struct {
2414 uint8_t sub_cmd;
2415 uint8_t stack_id;
2416 uint16_t reserved;
2417 } osa_status_query_in;
2418
2419 struct {
2420 uint8_t state;
2421 uint8_t trigger_lane;
2422 uint8_t trigger_dir;
2423 uint8_t reserved;
2424 uint16_t trigger_reason;
2425 uint16_t reserved2;
2426 } osa_status_query_out;
2427
2428 osa_status_query_in.sub_cmd = MRPC_OSA_STATUS_QUERY;
2429 if (switchtec_is_gen6(dev))
2430 osa_status_query_in.sub_cmd = MRPC_OSA_STATUS_QUERY_GEN6;
2431 osa_status_query_in.stack_id = stack_id;
2432
2433 ret = switchtec_cmd(dev, MRPC_ORDERED_SET_ANALYZER, &osa_status_query_in,
2434 sizeof(osa_status_query_in), &osa_status_query_out,
2435 sizeof(osa_status_query_out));
2436
2437 ret = switchtec_cmd(dev, MRPC_ORDERED_SET_ANALYZER, &osa_data_read_in,
2438 sizeof(osa_data_read_in), &osa_data_entries_out,
2439 sizeof(osa_data_entries_out));
2440 if (ret) {
2441 switchtec_perror("OSA data dump");
2442 return ret;
2443 }
2444
2445 struct {
2446 uint8_t entries_read;
2447 uint8_t stack_id;
2448 uint8_t lane;
2449 uint8_t direction;
2450 uint16_t next_entry;
2451 uint16_t entries_remaining;
2452 uint16_t wrap;
2453 uint16_t reserved;
2454 uint32_t entry_dwords[osa_data_entries_out.entries_remaining * 6];
2455 } osa_data_read_out;
2456
2457 osa_data_read_out.entries_remaining = osa_data_entries_out.entries_remaining;
2458 osa_data_read_out.next_entry = osa_data_entries_out.next_entry;
2459
2460 if (data) {
2461 data->stack_id = stack_id;
2462 data->lane = lane;
2463 data->direction = direction;
2464 data->total_entries = osa_data_entries_out.entries_remaining;
2465 data->wrap_occurred = osa_data_entries_out.wrap;
2466 data->entry_count = 0;
2467 }
2468
2469 int total_dword = 0;
2470 int total_entries = 0;
2471 int curr_entry_dword = 0;
2472 uint64_t timestamp;
2473 uint32_t timestamp_lower, timestamp_upper, counter;
2474 uint8_t link_rate, trigger, os_droppped;
2475 uint32_t osa_data_dwords[4];
2476 int osa_data_idx = 0;
2477
2478 while (osa_data_read_out.entries_remaining != 0) {
2479 if (data && total_entries >= SWITCHTEC_OSA_MAX_ENTRIES)
2480 break;
2481
2482 osa_data_read_in.num_entries = osa_data_read_out.entries_remaining;
2483 osa_data_read_in.start_entry = osa_data_read_out.next_entry;
2484
2485 ret = switchtec_cmd(dev, MRPC_ORDERED_SET_ANALYZER,
2486 &osa_data_read_in, sizeof(osa_data_read_in),
2487 &osa_data_read_out, sizeof(osa_data_read_out));
2488 if (ret)
2489 return -1;
2490
2491 for (int i = total_dword; i < total_dword + (osa_data_read_out.entries_read * 6); i++) {
2492 if (curr_entry_dword < 4) {
2493 osa_data_dwords[osa_data_idx++] = osa_data_read_out.entry_dwords[i];
2494 } else if (curr_entry_dword == 4) {
2495 timestamp_lower = (osa_data_read_out.entry_dwords[i] >> 22) & 0x3FF;
2496 timestamp_upper = (osa_data_read_out.entry_dwords[i+1] & 0x1A);
2497 timestamp = timestamp_upper | timestamp_lower;
2498
2499 link_rate = osa_data_read_out.entry_dwords[i] & 0x3;
2500 counter = (osa_data_read_out.entry_dwords[i] >> 3) & 0x12;
2501 trigger = (osa_data_read_out.entry_dwords[i+1] >> 28) & 0x1;
2502 os_droppped = (osa_data_read_out.entry_dwords[i+1] >> 29) & 0x1;
2503
2504 if (data && total_entries < SWITCHTEC_OSA_MAX_ENTRIES) {
2505 data->entries[total_entries].timestamp = timestamp;
2506 data->entries[total_entries].link_rate = link_rate;
2507 data->entries[total_entries].counter = counter;
2508 data->entries[total_entries].trigger_indication = trigger;
2509 data->entries[total_entries].os_dropped = os_droppped;
2510 data->entries[total_entries].osa_data[0] = osa_data_dwords[0];
2511 data->entries[total_entries].osa_data[1] = osa_data_dwords[1];
2512 data->entries[total_entries].osa_data[2] = osa_data_dwords[2];
2513 data->entries[total_entries].osa_data[3] = osa_data_dwords[3];
2514 data->entry_count++;
2515 }
2516
2517 osa_data_idx = 0;
2518 total_entries++;
2519 }
2520 curr_entry_dword++;
2521 if (i != 0 && i % 5 == 0) {
2522 curr_entry_dword = 0;
2523 }
2524 }
2525 total_dword += osa_data_read_out.entries_read;
2526 }
2527
2528 return ret;
2529}
2530
2531int switchtec_osa_capture_control(struct switchtec_dev *dev, int stack_id,
2532 int lane_mask, int direction,
2533 int drop_single_os, int stop_mode,
2534 int snapshot_mode, int post_trigger,
2535 int os_types)
2536{
2537 int ret = 0;
2538
2540
2541 osa_capture_ctrl_in.sub_cmd = MRPC_OSA_CAPTURE_CTRL;
2542 if (switchtec_is_gen6(dev))
2543 osa_capture_ctrl_in.sub_cmd = MRPC_OSA_CAPTURE_CTRL_GEN6;
2544 osa_capture_ctrl_in.stack_id = stack_id;
2545 osa_capture_ctrl_in.lane_mask = lane_mask;
2546 osa_capture_ctrl_in.direction = direction;
2547 osa_capture_ctrl_in.drop_single_os = drop_single_os;
2548 osa_capture_ctrl_in.stop_mode = stop_mode;
2549 osa_capture_ctrl_in.snapshot_mode = snapshot_mode;
2550 osa_capture_ctrl_in.post_trig_entries = post_trigger;
2551 osa_capture_ctrl_in.os_types = os_types;
2552
2553 ret = switchtec_cmd(dev, MRPC_ORDERED_SET_ANALYZER, &osa_capture_ctrl_in,
2554 sizeof(osa_capture_ctrl_in), NULL, 0);
2555 if (ret)
2556 switchtec_perror("OSA capture control");
2557
2558 return ret;
2559}
2560
2561int switchtec_osa_config_misc(struct switchtec_dev *dev, int stack_id,
2562 int trigger_en)
2563{
2564 int ret = 0;
2565 struct {
2566 uint8_t sub_cmd;
2567 uint8_t stack_id;
2568 uint16_t reserved;
2569 uint8_t trigger_en;
2570 uint8_t reserved2;
2571 uint16_t reserved3;
2572 } osa_misc_config_in;
2573
2574 osa_misc_config_in.sub_cmd = MRPC_OSA_MISC_TRIG_CONFIG;
2575 osa_misc_config_in.stack_id = stack_id;
2576 osa_misc_config_in.trigger_en = trigger_en;
2577
2578 ret = switchtec_cmd(dev, MRPC_ORDERED_SET_ANALYZER, &osa_misc_config_in,
2579 sizeof(osa_misc_config_in), NULL, 0);
2580 if (ret)
2581 switchtec_perror("OSA misc config");
2582
2583 return ret;
2584}
2585
2586int switchtec_osa_config_pattern(struct switchtec_dev *dev, int stack_id,
2587 int direction, int lane_mask, int link_rate,
2588 uint32_t *value_data, uint32_t *mask_data)
2589{
2590 int ret = 1;
2591
2593 osa_pattern_config_in.sub_cmd = MRPC_OSA_PAT_TRIG_CONFIG;
2594 osa_pattern_config_in.stack_id = stack_id;
2595 osa_pattern_config_in.direction = direction;
2596 osa_pattern_config_in.lane_mask = lane_mask;
2597 osa_pattern_config_in.link_rate = link_rate;
2598 osa_pattern_config_in.pat_val_dword0 = value_data[0];
2599 osa_pattern_config_in.pat_val_dword1 = value_data[1];
2600 osa_pattern_config_in.pat_val_dword2 = value_data[2];
2601 osa_pattern_config_in.pat_val_dword3 = value_data[3];
2602 osa_pattern_config_in.pat_mask_dword0 = mask_data[0];
2603 osa_pattern_config_in.pat_mask_dword1 = mask_data[1];
2604 osa_pattern_config_in.pat_mask_dword2 = mask_data[2];
2605 osa_pattern_config_in.pat_mask_dword3 = mask_data[3];
2606
2607 ret = switchtec_cmd(dev, MRPC_ORDERED_SET_ANALYZER,
2609 sizeof(osa_pattern_config_in), NULL, 0);
2610 if (ret)
2611 switchtec_perror("OSA pattern config");
2612
2613 return ret;
2614}
2615
2616int switchtec_osa_config_type(struct switchtec_dev *dev, int stack_id,
2617 int direction, int lane_mask, int link_rate, int os_types)
2618{
2619 int ret = 1;
2620
2622
2623 osa_type_config_in.sub_cmd = MRPC_OSA_TYPE_TRIG_CONFIG;
2624 if (switchtec_is_gen6(dev))
2625 osa_type_config_in.sub_cmd = MRPC_OSA_TYPE_TRIG_CONFIG_GEN6;
2626 osa_type_config_in.stack_id = stack_id;
2627 osa_type_config_in.lane_mask = lane_mask;
2628 osa_type_config_in.direction = direction;
2629 osa_type_config_in.link_rate = link_rate;
2630 osa_type_config_in.os_types = os_types;
2631
2632 ret = switchtec_cmd(dev, MRPC_ORDERED_SET_ANALYZER, &osa_type_config_in,
2633 sizeof(osa_type_config_in), NULL, 0);
2634 if (ret)
2635 switchtec_perror("OSA type config");
2636
2637 return ret;
2638}
2639
2640int switchtec_osa_dump_conf(struct switchtec_dev *dev, int stack_id,
2641 struct switchtec_osa_config *config)
2642{
2643 int ret = 0;
2644
2645 struct {
2646 uint8_t sub_cmd;
2647 uint8_t stack_id;
2648 uint16_t reserved;
2649 } osa_dmp_in;
2650
2651 struct {
2652 int16_t os_type_trig_lane_mask;
2653 uint8_t os_type_trig_dir;
2654 uint8_t os_type_trig_link_rate;
2655 uint16_t os_type_trig_os_types;
2656 uint16_t reserved;
2657 uint16_t os_pat_trig_lane_mask;
2658 uint8_t os_pat_trig_dir;
2659 uint8_t os_pat_trig_link_rate;
2660 uint32_t os_pat_trig_val_dw0;
2661 uint32_t os_pat_trig_val_dw1;
2662 uint32_t os_pat_trig_val_dw2;
2663 uint32_t os_pat_trig_val_dw3;
2664 uint32_t os_pat_trig_mask_dw0;
2665 uint32_t os_pat_trig_mask_dw1;
2666 uint32_t os_pat_trig_mask_dw2;
2667 uint32_t os_pat_trig_mask_dw3;
2668 uint8_t misc_trig_en;
2669 uint8_t reserved3;
2670 uint16_t reserved4;
2671 uint16_t capture_lane_mask;
2672 uint8_t capture_dir;
2673 uint8_t capture_drop_os;
2674 uint8_t capture_stop_mode;
2675 uint8_t capture_snap_mode;
2676 uint16_t capture_post_trig_entries;
2677 uint16_t capture_os_types;
2678 uint16_t reserved5;
2679 } osa_dmp_out;
2680
2681 osa_dmp_in.stack_id = stack_id;
2682 osa_dmp_in.sub_cmd = MRPC_OSA_CONFIG_DMP;
2683 if (switchtec_is_gen6(dev))
2684 osa_dmp_in.sub_cmd = MRPC_OSA_CONFIG_DMP_GEN6;
2685
2686 ret = switchtec_cmd(dev, MRPC_ORDERED_SET_ANALYZER, &osa_dmp_in,
2687 sizeof(osa_dmp_in), &osa_dmp_out,
2688 sizeof(osa_dmp_out));
2689 if (ret) {
2690 switchtec_perror("OSA config dump");
2691 return ret;
2692 }
2693
2694 if (config) {
2695 /* OS Type Trigger */
2696 config->os_type_lane_mask = osa_dmp_out.os_type_trig_lane_mask;
2697 config->os_type_direction = osa_dmp_out.os_type_trig_dir;
2698 config->os_type_link_rate = osa_dmp_out.os_type_trig_link_rate;
2699 config->os_type_os_types = osa_dmp_out.os_type_trig_os_types;
2700
2701 /* OS Pattern Trigger */
2702 config->os_pat_lane_mask = osa_dmp_out.os_pat_trig_lane_mask;
2703 config->os_pat_direction = osa_dmp_out.os_pat_trig_dir;
2704 config->os_pat_link_rate = osa_dmp_out.os_pat_trig_link_rate;
2705 config->os_pat_value[0] = osa_dmp_out.os_pat_trig_val_dw0;
2706 config->os_pat_value[1] = osa_dmp_out.os_pat_trig_val_dw1;
2707 config->os_pat_value[2] = osa_dmp_out.os_pat_trig_val_dw2;
2708 config->os_pat_value[3] = osa_dmp_out.os_pat_trig_val_dw3;
2709 config->os_pat_mask[0] = osa_dmp_out.os_pat_trig_mask_dw0;
2710 config->os_pat_mask[1] = osa_dmp_out.os_pat_trig_mask_dw1;
2711 config->os_pat_mask[2] = osa_dmp_out.os_pat_trig_mask_dw2;
2712 config->os_pat_mask[3] = osa_dmp_out.os_pat_trig_mask_dw3;
2713
2714 /* Misc Trigger */
2715 config->misc_trig_enable = osa_dmp_out.misc_trig_en;
2716
2717 /* Capture Config */
2718 config->capture_lane_mask = osa_dmp_out.capture_lane_mask;
2719 config->capture_direction = osa_dmp_out.capture_dir;
2720 config->capture_drop_single_os = osa_dmp_out.capture_drop_os;
2721 config->capture_stop_mode = osa_dmp_out.capture_stop_mode;
2722 config->capture_snapshot_mode = osa_dmp_out.capture_snap_mode;
2723 config->capture_post_trig_entries = osa_dmp_out.capture_post_trig_entries;
2724 config->capture_os_types = osa_dmp_out.capture_os_types;
2725 }
2726
2727 return ret;
2728}
2729
2730int switchtec_osa(struct switchtec_dev *dev, int stack_id, int operation,
2731 struct switchtec_osa_status *status)
2732{
2733 int ret = 0;
2734 struct {
2735 uint8_t sub_cmd;
2736 uint8_t stack_id;
2737 uint16_t reserved;
2738 } osa_rel_access_perm_in;
2739
2740 struct {
2741 uint8_t sub_cmd;
2742 uint8_t stack_id;
2743 uint16_t reserved;
2744 } osa_status_query_in;
2745
2746 struct {
2747 uint8_t state;
2748 uint8_t trigger_lane;
2749 uint8_t trigger_dir;
2750 uint8_t reserved;
2751 uint16_t trigger_reason;
2752 uint16_t reserved2;
2753 } osa_status_query_out;
2754
2755 struct {
2756 uint8_t sub_cmd;
2757 uint8_t stack_id;
2758 uint8_t operation;
2759 uint8_t reserved;
2760 } osa_op_in;
2761
2762 if (operation == 4) {
2763 osa_rel_access_perm_in.sub_cmd = MRPC_OSA_REL_ACCESS_PERM;
2764 osa_rel_access_perm_in.stack_id = stack_id;
2765
2766 ret = switchtec_cmd(dev, MRPC_ORDERED_SET_ANALYZER,
2767 &osa_rel_access_perm_in,
2768 sizeof(osa_rel_access_perm_in), NULL, 0);
2769 }
2770 else if (operation == 5) {
2771 osa_status_query_in.sub_cmd = MRPC_OSA_STATUS_QUERY;
2772 if (switchtec_is_gen6(dev))
2773 osa_status_query_in.sub_cmd = MRPC_OSA_STATUS_QUERY_GEN6;
2774 osa_status_query_in.stack_id = stack_id;
2775
2776 ret = switchtec_cmd(dev, MRPC_ORDERED_SET_ANALYZER,
2777 &osa_status_query_in, sizeof(osa_status_query_in),
2778 &osa_status_query_out, sizeof(osa_status_query_out));
2779 if (ret) {
2780 switchtec_perror("OSA operation");
2781 return ret;
2782 }
2783
2784 if (status) {
2785 status->state = osa_status_query_out.state;
2786 status->trigger_lane = osa_status_query_out.trigger_lane;
2787 status->trigger_dir = osa_status_query_out.trigger_dir;
2788 status->trigger_reason = osa_status_query_out.trigger_reason;
2789 }
2790 }
2791 else {
2792 osa_op_in.sub_cmd = MRPC_OSA_ANALYZER_OP;
2793 osa_op_in.stack_id = stack_id;
2794 osa_op_in.operation = operation;
2795
2796 ret = switchtec_cmd(dev, MRPC_ORDERED_SET_ANALYZER, &osa_op_in,
2797 sizeof(osa_op_in), NULL, 0);
2798 }
2799
2800 if (ret)
2801 switchtec_perror("OSA operation");
2802
2803 return ret;
2804}
2805
int switchtec_diag_rcvr_ext(struct switchtec_dev *dev, int port_id, int lane_id, enum switchtec_diag_link link, struct switchtec_rcvr_ext *res)
Get the Extended Receiver Object.
Definition diag.c:1540
static int switchtec_gen5_diag_port_eq_tx_table(struct switchtec_dev *dev, int port_id, int prev_speed, enum switchtec_diag_link link, struct switchtec_port_eq_table *res)
Get the Gen5 far end TX equalization table.
Definition diag.c:1183
int switchtec_diag_cross_hair_disable(struct switchtec_dev *dev)
Disable active cross hair.
Definition diag.c:70
int switchtec_diag_pattern_mon_get(struct switchtec_dev *dev, int port_id, int lane_id, enum switchtec_diag_pattern *type, unsigned long long *err_cnt)
Get Pattern Monitor.
Definition diag.c:770
static int switchtec_diag_ltssm_log_gen6(struct switchtec_dev *dev, int port, int *log_count, struct switchtec_diag_ltssm_log *log_data)
Get the LTSSM log of a port on a gen6 switchtec device.
Definition diag.c:1872
int switchtec_diag_pattern_gen_get(struct switchtec_dev *dev, int port_id, enum switchtec_diag_pattern *type)
Get Pattern Generator set on port.
Definition diag.c:716
int switchtec_diag_port_eq_tx_table(struct switchtec_dev *dev, int port_id, int prev_speed, enum switchtec_diag_link link, struct switchtec_port_eq_table *res)
Get the far end TX equalization table.
Definition diag.c:1300
int switchtec_diag_port_eq_tx_fslf(struct switchtec_dev *dev, int port_id, int prev_speed, int lane_id, enum switchtec_diag_end end, enum switchtec_diag_link link, struct switchtec_port_eq_tx_fslf *res)
Get the equalization FS/LF.
Definition diag.c:1504
static int switchtec_diag_ltssm_log_gen4(struct switchtec_dev *dev, int port, int *log_count, struct switchtec_diag_ltssm_log *log_data)
Get the LTSSM log of a port on a gen4 switchtec device.
Definition diag.c:2010
int switchtec_diag_loopback_get(struct switchtec_dev *dev, int port_id, int *enabled, enum switchtec_diag_ltssm_speed *ltssm_speed)
Setup Loopback Mode.
Definition diag.c:623
int switchtec_inject_err_dllp_crc(struct switchtec_dev *dev, int phys_port_id, int enable, uint16_t rate)
Inject a DLLP CRC error into a physical port.
Definition diag.c:2245
int switchtec_diag_eye_read(struct switchtec_dev *dev, int lane_id, int bin, int *num_phases, double *ber_data)
Start a PCIe Eye Read Gen5.
Definition diag.c:248
int switchtec_diag_eye_fetch(struct switchtec_dev *dev, double *pixels, size_t pixel_cnt, int *lane_id)
Start a PCIe Eye Capture.
Definition diag.c:403
static int switchtec_gen4_diag_port_eq_tx_fslf(struct switchtec_dev *dev, int port_id, int lane_id, enum switchtec_diag_end end, enum switchtec_diag_link link, struct switchtec_port_eq_tx_fslf *res)
Get the Gen4 equalization FS/LF.
Definition diag.c:1392
int switchtec_diag_pattern_inject(struct switchtec_dev *dev, int port_id, unsigned int err_cnt)
Inject error into pattern generator.
Definition diag.c:811
int switchtec_diag_rcvr_obj(struct switchtec_dev *dev, int port_id, int lane_id, enum switchtec_diag_link link, struct switchtec_rcvr_obj *res)
Get the receiver object.
Definition diag.c:838
int switchtec_diag_eye_start(struct switchtec_dev *dev, int lane_mask[4], struct range *x_range, struct range *y_range, int step_interval, int capture_depth, int sar_sel, int intleav_sel, int hstep, int data_mode, int eye_mode, uint64_t refclk, int vstep)
Start a PCIe Eye Capture.
Definition diag.c:309
int switchtec_diag_perm_table(struct switchtec_dev *dev, struct switchtec_mrpc table[MRPC_MAX_ID])
Get the permission table.
Definition diag.c:1585
static int switchtec_diag_ltssm_log_gen5(struct switchtec_dev *dev, int port, int *log_count, struct switchtec_diag_ltssm_log *log_data)
Get the LTSSM log of a port on a gen5 switchtec device.
Definition diag.c:1734
int switchtec_inject_err_tlp_lcrc(struct switchtec_dev *dev, int phy_port, int enable, uint8_t rate)
Inject a TLP LCRC error into a physical port.
Definition diag.c:2302
int switchtec_diag_ltssm_log(struct switchtec_dev *dev, int port, int *log_count, struct switchtec_diag_ltssm_log *log_data)
Determine the generation and call the related LTSSM log func.
Definition diag.c:2130
int switchtec_inject_err_ack_nack(struct switchtec_dev *dev, int phys_port_id, uint16_t seq_num, uint8_t count)
Inject an ACK to NACK error into a physical port.
Definition diag.c:2344
int switchtec_diag_refclk_status(struct switchtec_dev *dev, uint8_t *info)
Get the status of all stacks/CSUs of the refclk.
Definition diag.c:1651
int switchtec_aer_event_gen(struct switchtec_dev *dev, int port_id, int aer_error_id, int trigger_event)
Call the aer event gen function to generate AER events.
Definition diag.c:2194
int switchtec_diag_cross_hair_enable(struct switchtec_dev *dev, int lane_id)
Enable cross hair on specified lane.
Definition diag.c:53
static int switchtec_gen5_diag_port_eq_tx_fslf(struct switchtec_dev *dev, int port_id, int prev_speed, int lane_id, enum switchtec_diag_end end, enum switchtec_diag_link link, struct switchtec_port_eq_tx_fslf *res)
Get the Gen5 equalization FS/LF.
Definition diag.c:1333
int switchtec_diag_eye_cancel(struct switchtec_dev *dev)
Cancel in-progress eye capture.
Definition diag.c:463
int switchtec_diag_pattern_gen_set(struct switchtec_dev *dev, int port_id, enum switchtec_diag_pattern type, enum switchtec_diag_pattern_link_rate link_speed)
Setup Pattern Generator.
Definition diag.c:690
int switchtec_diag_port_eq_tx_coeff(struct switchtec_dev *dev, int port_id, int prev_speed, enum switchtec_diag_end end, enum switchtec_diag_link link, struct switchtec_port_eq_coeff *res)
Get the port equalization TX coefficients.
Definition diag.c:1151
int switchtec_inject_err_dllp(struct switchtec_dev *dev, int phys_port_id, int data)
Inject a DLLP into a physical port.
Definition diag.c:2222
int switchtec_diag_eye_set_mode(struct switchtec_dev *dev, enum switchtec_diag_eye_data_mode mode)
Set the data mode for the next Eye Capture.
Definition diag.c:227
int switchtec_diag_cross_hair_get(struct switchtec_dev *dev, int start_lane_id, int num_lanes, struct switchtec_diag_cross_hair *res)
Disable active cross hair.
Definition diag.c:88
int switchtec_diag_loopback_set(struct switchtec_dev *dev, int port_id, int enable, int enable_parallel, int enable_external, int enable_ltssm, int enable_pipe, enum switchtec_diag_ltssm_speed ltssm_speed)
Setup Loopback Mode.
Definition diag.c:590
static int switchtec_gen5_diag_port_eq_tx_coeff(struct switchtec_dev *dev, int port_id, int prev_speed, enum switchtec_diag_end end, enum switchtec_diag_link link, struct switchtec_port_eq_coeff *res)
Get the Gen5 port equalization TX coefficients.
Definition diag.c:893
int switchtec_inject_err_cto(struct switchtec_dev *dev, int phys_port_id)
Inject Credit Timeout error into a physical port.
Definition diag.c:2366
int switchtec_inject_err_tlp_seq_num(struct switchtec_dev *dev, int phys_port_id)
Inject a TLP Sequence Number error into a physical port.
Definition diag.c:2323
int switchtec_diag_ltssm_clear(struct switchtec_dev *dev, int port)
Call the LTSSM clear MRPC command.
Definition diag.c:2149
int switchtec_diag_refclk_ctl(struct switchtec_dev *dev, int id, bool en)
Control the refclk output for a stack or CSU.
Definition diag.c:1622
static int switchtec_gen4_diag_port_eq_tx_table(struct switchtec_dev *dev, int port_id, enum switchtec_diag_link link, struct switchtec_port_eq_table *res)
Get the Gen4 far end TX equalization table.
Definition diag.c:1240
int switchtec_diag_pattern_mon_set(struct switchtec_dev *dev, int port_id, enum switchtec_diag_pattern type)
Setup Pattern Monitor.
Definition diag.c:747
static int switchtec_gen4_diag_port_eq_tx_coeff(struct switchtec_dev *dev, int port_id, enum switchtec_diag_end end, enum switchtec_diag_link link, struct switchtec_port_eq_coeff *res)
Get the Gen4 port equalization TX coefficients.
Definition diag.c:999
Diagnostic structures.
int switchtec_cmd(struct switchtec_dev *dev, uint32_t cmd, const void *payload, size_t payload_len, void *resp, size_t resp_len)
Execute an MRPC command.
Definition platform.c:178
void switchtec_perror(const char *str)
Print an error string to stdout.
Definition switchtec.c:871
Definition utils.h:34
OSA configuration dump result.
Definition switchtec.h:1730
OSA status query result.
Definition switchtec.h:1720
Main Switchtec header.
@ LANE_EQ_DUMP_TYPE_PREV
Previous link-up settings.
Definition switchtec.h:1466
@ LANE_EQ_DUMP_TYPE_CURR
Current settings.
Definition switchtec.h:1465
static int switchtec_is_gen6(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 6 device.
Definition switchtec.h:524
static const float switchtec_gen_transfers[]
Number of GT/s capable for each PCI generation or link_rate.
Definition switchtec.h:729
static int switchtec_is_gen4(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 4 device.
Definition switchtec.h:508
static int switchtec_is_gen5(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 5 device.
Definition switchtec.h:516
#define SWITCHTEC_OSA_MAX_ENTRIES
OSA capture data collection.
Definition switchtec.h:1772