Switchtec Userspace PROJECT_NUMBER = 4.2
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_IDLE:
155 switchtec_perror("Eye capture idle");
156 case SWITCHTEC_GEN5_DIAG_EYE_STATUS_DONE:
157 return 0;
158 case SWITCHTEC_GEN5_DIAG_EYE_STATUS_TIMEOUT:
159 switchtec_perror("Eye capture timeout");
160 case SWITCHTEC_GEN5_DIAG_EYE_STATUS_ERROR:
161 switchtec_perror("Eye capture error");
162 return -1;
163 }
164 switchtec_perror("Unknown eye capture state");
165 return -1;
166}
167
168static int switchtec_diag_eye_status(int status)
169{
170 switch (status) {
171 case 0: return 0;
172 case 2:
173 errno = EINVAL;
174 return -1;
175 case 3:
176 errno = EBUSY;
177 return -1;
178 default:
179 errno = EPROTO;
180 return -1;
181 }
182}
183
184static int switchtec_diag_eye_cmd_gen5(struct switchtec_dev *dev, void *in,
185 size_t size)
186{
187 int ret;
188
189 ret = switchtec_cmd(dev, MRPC_GEN5_EYE_CAPTURE, in, size,
190 NULL, 0);
191 if (ret)
192 return ret;
193
194 usleep(200000);
195
196 return switchtec_diag_eye_status_gen5(dev);
197}
198
199static int switchtec_diag_eye_cmd_gen4(struct switchtec_dev *dev, void *in,
200 size_t size)
201{
203 int ret;
204
205 ret = switchtec_cmd(dev, MRPC_EYE_OBSERVE, in, size, &out,
206 sizeof(out));
207
208 if (ret)
209 return ret;
210
211 return switchtec_diag_eye_status(out.status);
212}
213
221int switchtec_diag_eye_set_mode(struct switchtec_dev *dev,
222 enum switchtec_diag_eye_data_mode mode)
223{
224 struct switchtec_diag_port_eye_cmd in = {
225 .sub_cmd = MRPC_EYE_OBSERVE_SET_DATA_MODE,
226 .data_mode = mode,
227 };
228
229 return switchtec_diag_eye_cmd_gen4(dev, &in, sizeof(in));
230}
231
242int switchtec_diag_eye_read(struct switchtec_dev *dev, int lane_id,
243 int bin, int* num_phases, double* ber_data)
244{
245 if (dev) {
246 fprintf(stderr, "Eye read not supported on Gen 4 switches.\n");
247 return -1;
248 }
250 .sub_cmd = MRPC_EYE_CAP_READ_GEN5,
251 .lane_id = lane_id,
252 .bin = bin,
253 };
255 int i, ret;
256
257 ret = switchtec_cmd(dev, MRPC_GEN5_EYE_CAPTURE, &in, sizeof(in),
258 &out, sizeof(out));
259 if (ret)
260 return ret;
261
262 *num_phases = out.num_phases;
263
264 for(i = 0; i < out.num_phases; i++)
265 ber_data[i] = le64toh(out.ber_data[i]) / 281474976710656.;
266
267 return ret;
268}
269
282int switchtec_diag_eye_start(struct switchtec_dev *dev, int lane_mask[4],
283 struct range *x_range, struct range *y_range,
284 int step_interval, int capture_depth)
285{
286 int err, ret;
287 if (switchtec_is_gen5(dev)) {
289 .sub_cmd = MRPC_EYE_CAP_RUN_GEN5,
290 .capture_depth = capture_depth,
291 .timeout_disable = 1,
292 .lane_mask[0] = lane_mask[0],
293 .lane_mask[1] = lane_mask[1],
294 .lane_mask[2] = lane_mask[2],
295 .lane_mask[3] = lane_mask[3],
296 };
297
298 ret = switchtec_diag_eye_cmd_gen5(dev, &in, sizeof(in));
299 err = errno;
300 errno = err;
301 return ret;
302 } else {
304 .sub_cmd = MRPC_EYE_OBSERVE_START,
305 .lane_mask[0] = lane_mask[0],
306 .lane_mask[1] = lane_mask[1],
307 .lane_mask[2] = lane_mask[2],
308 .lane_mask[3] = lane_mask[3],
309 .x_start = x_range->start,
310 .y_start = y_range->start,
311 .x_end = x_range->end,
312 .y_end = y_range->end,
313 .x_step = x_range->step,
314 .y_step = y_range->step,
315 .step_interval = step_interval,
316 };
317
318 ret = switchtec_diag_eye_cmd_gen4(dev, &in, sizeof(in));
319 /* Add delay so hardware has enough time to start */
320 err = errno;
321 usleep(200000);
322 errno = err;
323 return ret;
324 }
325 return -1;
326}
327
328static uint64_t hi_lo_to_uint64(uint32_t lo, uint32_t hi)
329{
330 uint64_t ret;
331
332 ret = le32toh(hi);
333 ret <<= 32;
334 ret |= le32toh(lo);
335
336 return ret;
337}
338
352int switchtec_diag_eye_fetch(struct switchtec_dev *dev, double *pixels,
353 size_t pixel_cnt, int *lane_id)
354{
355 struct switchtec_diag_port_eye_cmd in = {
356 .sub_cmd = MRPC_EYE_OBSERVE_FETCH,
357 };
359 uint64_t samples, errors;
360 int i, ret, data_count;
361
362retry:
363 ret = switchtec_cmd(dev, MRPC_EYE_OBSERVE, &in, sizeof(in), &out,
364 sizeof(out));
365 if (ret)
366 return ret;
367
368 if (out.status == 1) {
369 usleep(5000);
370 goto retry;
371 }
372
373 ret = switchtec_diag_eye_status(out.status);
374 if (ret)
375 return ret;
376
377 for (i = 0; i < 4; i++) {
378 *lane_id = ffs(out.lane_mask[i]);
379 if (*lane_id)
380 break;
381 }
382
383 data_count = out.data_count_lo | ((int)out.data_count_hi << 8);
384
385 for (i = 0; i < data_count && i < pixel_cnt; i++) {
386 switch (out.data_mode) {
387 case SWITCHTEC_DIAG_EYE_RAW:
388 errors = hi_lo_to_uint64(out.raw[i].error_cnt_lo,
389 out.raw[i].error_cnt_hi);
390 samples = hi_lo_to_uint64(out.raw[i].sample_cnt_lo,
391 out.raw[i].sample_cnt_hi);
392 if (samples)
393 pixels[i] = (double)errors / samples;
394 else
395 pixels[i] = nan("");
396 break;
397 case SWITCHTEC_DIAG_EYE_RATIO:
398 pixels[i] = le32toh(out.ratio[i].ratio) / 65536.;
399 break;
400 }
401 }
402
403 return data_count;
404}
405
412int switchtec_diag_eye_cancel(struct switchtec_dev *dev)
413{
414 int ret;
415 int err;
416 struct switchtec_diag_port_eye_cmd in = {
417 .sub_cmd = MRPC_EYE_OBSERVE_CANCEL,
418 };
419
420 ret = switchtec_diag_eye_cmd_gen4(dev, &in, sizeof(in));
421
422 /* Add delay so hardware can stop completely */
423 err = errno;
424 usleep(200000);
425 errno = err;
426
427 return ret;
428}
429
430static int switchtec_diag_loopback_set_gen5(struct switchtec_dev *dev,
431 int port_id, int enable_parallel,
432 int enable_external,
433 int enable_ltssm,
434 enum switchtec_diag_ltssm_speed
435 ltssm_speed)
436{
437 struct switchtec_diag_loopback_in int_in = {
438 .sub_cmd = MRPC_LOOPBACK_SET_INT_LOOPBACK,
439 .port_id = port_id,
440 .enable = 1,
441 };
442 struct switchtec_diag_loopback_ltssm_in ltssm_in = {
443 .sub_cmd = MRPC_LOOPBACK_SET_LTSSM_LOOPBACK,
444 .port_id = port_id,
445 .enable = enable_ltssm,
446 .speed = ltssm_speed,
447 };
448 int ret;
449
450 if (enable_ltssm && !(enable_external || enable_parallel)) {
451 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &ltssm_in,
452 sizeof(ltssm_in), NULL, 0);
453 if (ret)
454 return ret;
455 } else {
456 int_in.type = DIAG_LOOPBACK_PARALEL_DATAPATH;
457 int_in.enable = enable_parallel;
458 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &int_in,
459 sizeof(int_in), NULL, 0);
460 if (ret)
461 return ret;
462 if (!enable_parallel) {
463 int_in.type = DIAG_LOOPBACK_EXTERNAL_DATAPATH;
464 int_in.enable = enable_external;
465 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &int_in,
466 sizeof(int_in), NULL, 0);
467 if (ret)
468 return ret;
469 }
470
471 ltssm_in.enable = enable_ltssm;
472 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &ltssm_in,
473 sizeof(ltssm_in), NULL, 0);
474 if (ret)
475 return ret;
476 }
477 return 0;
478}
479
480static int switchtec_diag_loopback_set_gen4(struct switchtec_dev *dev,
481 int port_id, int enable,
482 enum switchtec_diag_ltssm_speed
483 ltssm_speed)
484{
485 struct switchtec_diag_loopback_in int_in = {
486 .sub_cmd = MRPC_LOOPBACK_SET_INT_LOOPBACK,
487 .port_id = port_id,
488 .enable = enable,
489 };
490 struct switchtec_diag_loopback_ltssm_in ltssm_in = {
491 .sub_cmd = MRPC_LOOPBACK_SET_LTSSM_LOOPBACK,
492 .port_id = port_id,
493 .enable = !!(enable & SWITCHTEC_DIAG_LOOPBACK_LTSSM),
494 .speed = ltssm_speed,
495 };
496 int ret;
497
498 int_in.type = DIAG_LOOPBACK_RX_TO_TX;
499 int_in.enable = !!(enable & SWITCHTEC_DIAG_LOOPBACK_RX_TO_TX);
500
501 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &int_in,
502 sizeof(int_in), NULL, 0);
503 if (ret)
504 return ret;
505
506 int_in.type = DIAG_LOOPBACK_TX_TO_RX;
507 int_in.enable = !!(enable & SWITCHTEC_DIAG_LOOPBACK_TX_TO_RX);
508
509 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &int_in,
510 sizeof(int_in), NULL, 0);
511 if (ret)
512 return ret;
513
514 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &ltssm_in,
515 sizeof(ltssm_in), NULL, 0);
516 if (ret)
517 return ret;
518
519 return 0;
520}
521
534int switchtec_diag_loopback_set(struct switchtec_dev *dev, int port_id,
535 int enable, int enable_parallel,
536 int enable_external, int enable_ltssm,
537 enum switchtec_diag_ltssm_speed ltssm_speed)
538{
539 int ret = 0;
540 if (switchtec_is_gen5(dev)) {
541 ret = switchtec_diag_loopback_set_gen5(dev, port_id,
542 enable_parallel,
543 enable_external,
544 enable_ltssm,
545 ltssm_speed);
546 if (ret)
547 return ret;
548 }
549 else {
550 ret = switchtec_diag_loopback_set_gen4(dev, port_id, enable,
551 ltssm_speed);
552 if (ret)
553 return ret;
554 }
555 return 0;
556}
557
568int switchtec_diag_loopback_get(struct switchtec_dev *dev,
569 int port_id, int *enabled,
570 enum switchtec_diag_ltssm_speed *ltssm_speed)
571{
572 struct switchtec_diag_loopback_in int_in = {
573 .sub_cmd = MRPC_LOOPBACK_GET_INT_LOOPBACK,
574 .port_id = port_id,
575 };
576 struct switchtec_diag_loopback_ltssm_in lt_in = {
577 .sub_cmd = MRPC_LOOPBACK_GET_LTSSM_LOOPBACK,
578 .port_id = port_id,
579 };
580 struct switchtec_diag_loopback_out int_out;
582 int ret, en = 0;
583
584 if (switchtec_is_gen5(dev))
585 int_in.type = DIAG_LOOPBACK_PARALEL_DATAPATH;
586 else
587 int_in.type = DIAG_LOOPBACK_RX_TO_TX;
588
589 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &int_in, sizeof(int_in),
590 &int_out, sizeof(int_out));
591 if (ret)
592 return ret;
593
594 if (int_out.enabled)
595 en |= SWITCHTEC_DIAG_LOOPBACK_RX_TO_TX;
596
597 if (switchtec_is_gen5(dev))
598 int_in.type = DIAG_LOOPBACK_EXTERNAL_DATAPATH;
599 else
600 int_in.type = DIAG_LOOPBACK_TX_TO_RX;
601
602 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &int_in, sizeof(int_in),
603 &int_out, sizeof(int_out));
604 if (ret)
605 return ret;
606
607 if (int_out.enabled)
608 en |= SWITCHTEC_DIAG_LOOPBACK_TX_TO_RX;
609
610 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &lt_in, sizeof(lt_in),
611 &lt_out, sizeof(lt_out));
612 if (ret)
613 return ret;
614
615 if (lt_out.enabled)
616 en |= SWITCHTEC_DIAG_LOOPBACK_LTSSM;
617
618 if (enabled)
619 *enabled = en;
620
621 if (ltssm_speed)
622 *ltssm_speed = lt_out.speed;
623
624 return 0;
625}
626
635int switchtec_diag_pattern_gen_set(struct switchtec_dev *dev, int port_id,
636 enum switchtec_diag_pattern type,
637 enum switchtec_diag_pattern_link_rate link_speed)
638{
639 struct switchtec_diag_pat_gen_in in = {
640 .sub_cmd = MRPC_PAT_GEN_SET_GEN,
641 .port_id = port_id,
642 .pattern_type = type,
643 .lane_id = link_speed
644 };
645 if (switchtec_is_gen5(dev))
646 in.sub_cmd = MRPC_PAT_GEN_SET_GEN_GEN5;
647
648 return switchtec_cmd(dev, MRPC_PAT_GEN, &in, sizeof(in), NULL, 0);
649}
650
659int switchtec_diag_pattern_gen_get(struct switchtec_dev *dev, int port_id,
660 enum switchtec_diag_pattern *type)
661{
662 struct switchtec_diag_pat_gen_in in = {
663 .sub_cmd = MRPC_PAT_GEN_GET_GEN,
664 .port_id = port_id,
665 };
667 int ret;
668
669 ret = switchtec_cmd(dev, MRPC_PAT_GEN, &in, sizeof(in), &out,
670 sizeof(out));
671 if (ret)
672 return ret;
673
674 if (type)
675 *type = out.pattern_type;
676
677 return 0;
678}
679
688int switchtec_diag_pattern_mon_set(struct switchtec_dev *dev, int port_id,
689 enum switchtec_diag_pattern type)
690{
691 struct switchtec_diag_pat_gen_in in = {
692 .sub_cmd = MRPC_PAT_GEN_SET_MON,
693 .port_id = port_id,
694 .pattern_type = type,
695 };
696
697 return switchtec_cmd(dev, MRPC_PAT_GEN, &in, sizeof(in), NULL, 0);
698}
699
709int switchtec_diag_pattern_mon_get(struct switchtec_dev *dev, int port_id,
710 int lane_id, enum switchtec_diag_pattern *type,
711 unsigned long long *err_cnt)
712{
713 struct switchtec_diag_pat_gen_in in = {
714 .sub_cmd = MRPC_PAT_GEN_GET_MON,
715 .port_id = port_id,
716 .lane_id = lane_id,
717 };
719 int ret;
720
721 ret = switchtec_cmd(dev, MRPC_PAT_GEN, &in, sizeof(in), &out,
722 sizeof(out));
723 if (ret)
724 return ret;
725
726 if (type)
727 *type = out.pattern_type;
728
729 if (err_cnt)
730 *err_cnt = (htole32(out.err_cnt_lo) |
731 ((uint64_t)htole32(out.err_cnt_hi) << 32));
732
733 return 0;
734}
735
748int switchtec_diag_pattern_inject(struct switchtec_dev *dev, int port_id,
749 unsigned int err_cnt)
750{
752 .sub_cmd = MRPC_PAT_GEN_INJ_ERR,
753 .port_id = port_id,
754 .err_cnt = err_cnt,
755 };
756 int ret;
757
758 ret = switchtec_cmd(dev, MRPC_PAT_GEN, &in, sizeof(in), NULL, 0);
759 if (ret)
760 return ret;
761
762 return 0;
763}
764
775int switchtec_diag_rcvr_obj(struct switchtec_dev *dev, int port_id,
776 int lane_id, enum switchtec_diag_link link,
777 struct switchtec_rcvr_obj *res)
778{
779 struct switchtec_diag_rcvr_obj_dump_out out = {};
781 .port_id = port_id,
782 .lane_id = lane_id,
783 };
785 .sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_PREV,
786 .port_id = port_id,
787 .lane_id = lane_id,
788 };
789 int i, ret;
790
791 if (!res) {
792 errno = -EINVAL;
793 return -1;
794 }
795
796 if (link == SWITCHTEC_DIAG_LINK_CURRENT) {
797 ret = switchtec_cmd(dev, MRPC_RCVR_OBJ_DUMP, &in, sizeof(in),
798 &out, sizeof(out));
799 } else if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
800 ret = switchtec_cmd(dev, MRPC_EXT_RCVR_OBJ_DUMP, &ext_in,
801 sizeof(ext_in), &out, sizeof(out));
802 } else {
803 errno = -EINVAL;
804 return -1;
805 }
806
807 if (ret)
808 return -1;
809
810 res->port_id = out.port_id;
811 res->lane_id = out.lane_id;
812 res->ctle = out.ctle;
813 res->target_amplitude = out.target_amplitude;
814 res->speculative_dfe = out.speculative_dfe;
815 for (i = 0; i < ARRAY_SIZE(res->dynamic_dfe); i++)
816 res->dynamic_dfe[i] = out.dynamic_dfe[i];
817
818 return 0;
819}
820
830static int switchtec_gen5_diag_port_eq_tx_coeff(struct switchtec_dev *dev,
831 int port_id, int prev_speed,
832 enum switchtec_diag_end end,
833 enum switchtec_diag_link link,
835 *res)
836{
837 struct switchtec_port_eq_coeff *loc_out;
838 struct switchtec_rem_port_eq_coeff *rem_out;
840 uint8_t *buf;
841 uint32_t buf_size;
842 uint32_t in_size = sizeof(struct switchtec_port_eq_coeff_in);
843 uint32_t out_size = 0;
844 int ret = 0;
845 int i;
846
847 if (!res) {
848 fprintf(stderr, "Error inval output buffer\n");
849 errno = -EINVAL;
850 return -1;
851 }
852
853 buf_size = in_size;
854 if (end == SWITCHTEC_DIAG_LOCAL) {
855 buf_size += sizeof(struct switchtec_port_eq_coeff);
856 out_size = sizeof(struct switchtec_port_eq_coeff);
857 } else if (end == SWITCHTEC_DIAG_FAR_END) {
858 buf_size += sizeof(struct switchtec_rem_port_eq_coeff);
859 out_size = sizeof(struct switchtec_rem_port_eq_coeff);
860 } else {
861 fprintf(stderr, "Error inval end option\n");
862 errno = -EINVAL;
863 }
864 buf = (uint8_t *)malloc(buf_size);
865 if (!buf) {
866 fprintf(stderr, "Error in buffer alloc\n");
867 errno = -ENOMEM;
868 return -1;
869 }
870
871 in = (struct switchtec_port_eq_coeff_in *)buf;
872 in->op_type = DIAG_PORT_EQ_STATUS_OP_PER_PORT;
873 in->phys_port_id = port_id;
874 in->lane_id = 0;
875 in->dump_type = LANE_EQ_DUMP_TYPE_CURR;
876
877 if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
878 in->dump_type = LANE_EQ_DUMP_TYPE_PREV;
879 in->prev_rate = prev_speed;
880 }
881
882 if (end == SWITCHTEC_DIAG_LOCAL) {
883 in->cmd = MRPC_GEN5_PORT_EQ_LOCAL_TX_COEFF_DUMP;
884 loc_out = (struct switchtec_port_eq_coeff *)&buf[in_size];
885 ret = switchtec_cmd(dev, MRPC_PORT_EQ_STATUS, in, in_size,
886 loc_out, out_size);
887 if (ret) {
888 fprintf(stderr, "Error in switchtec cmd:%d\n", ret);
889 goto end;
890 }
891 } else if (end == SWITCHTEC_DIAG_FAR_END) {
892 in->cmd = MRPC_GEN5_PORT_EQ_FAR_END_TX_COEFF_DUMP;
893 rem_out = (struct switchtec_rem_port_eq_coeff *)&buf[in_size];
894 ret = switchtec_cmd(dev, MRPC_PORT_EQ_STATUS, in, in_size,
895 rem_out, out_size);
896 if (ret) {
897 fprintf(stderr, "Error in switchtec cmd:%d\n", ret);
898 goto end;
899 }
900 } else {
901 fprintf(stderr, "Error inval end request\n");
902 errno = -EINVAL;
903 goto end;
904 }
905
906 if (end == SWITCHTEC_DIAG_LOCAL) {
907 res->lane_cnt = loc_out->lane_cnt + 1;
908 for (i = 0; i < res->lane_cnt; i++) {
909 res->cursors[i].pre = loc_out->cursors[i].pre;
910 res->cursors[i].post = loc_out->cursors[i].post;
911 }
912 } else {
913 res->lane_cnt = rem_out->lane_cnt + 1;
914 for (i = 0; i < res->lane_cnt; i++) {
915 res->cursors[i].pre = rem_out->cursors[i].pre;
916 res->cursors[i].post = rem_out->cursors[i].post;
917 }
918 }
919
920end:
921 if (buf)
922 free(buf);
923
924 return ret;
925}
926
936static int switchtec_gen4_diag_port_eq_tx_coeff(struct switchtec_dev *dev,
937 int port_id,
938 enum switchtec_diag_end end,
939 enum switchtec_diag_link link,
941 *res)
942{
943 struct switchtec_diag_port_eq_status_out out = {};
945 .op_type = DIAG_PORT_EQ_STATUS_OP_PER_PORT,
946 .port_id = port_id,
947 };
949 .op_type = DIAG_PORT_EQ_STATUS_OP_PER_PORT,
950 .port_id = port_id,
951 };
952 int ret, i;
953
954 if (!res) {
955 errno = -EINVAL;
956 return -1;
957 }
958
959 if (end == SWITCHTEC_DIAG_LOCAL) {
960 in.sub_cmd = MRPC_PORT_EQ_LOCAL_TX_COEFF_DUMP;
961 in_prev.sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_LOCAL_TX_COEFF_PREV;
962 } else if (end == SWITCHTEC_DIAG_FAR_END) {
963 in.sub_cmd = MRPC_PORT_EQ_FAR_END_TX_COEFF_DUMP;
964 in_prev.sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_FAR_END_TX_COEFF_PREV;
965 } else {
966 errno = -EINVAL;
967 return -1;
968 }
969
970 if (link == SWITCHTEC_DIAG_LINK_CURRENT) {
971 ret = switchtec_cmd(dev, MRPC_PORT_EQ_STATUS, &in, sizeof(in),
972 &out, sizeof(out));
973 } else if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
974 ret = switchtec_cmd(dev, MRPC_EXT_RCVR_OBJ_DUMP, &in_prev,
975 sizeof(in_prev), &out, sizeof(out));
976 } else {
977 errno = -EINVAL;
978 return -1;
979 }
980
981 if (ret)
982 return -1;
983
984 res->lane_cnt = out.lane_id + 1;
985 for (i = 0; i < res->lane_cnt; i++) {
986 res->cursors[i].pre = out.cursors[i].pre;
987 res->cursors[i].post = out.cursors[i].post;
988 }
989
990 return 0;
991}
992
1002int switchtec_diag_port_eq_tx_coeff(struct switchtec_dev *dev, int port_id,
1003 int prev_speed, enum switchtec_diag_end end,
1004 enum switchtec_diag_link link,
1005 struct switchtec_port_eq_coeff *res)
1006{
1007 int ret = -1;
1008
1009 if (switchtec_is_gen5(dev))
1010 ret = switchtec_gen5_diag_port_eq_tx_coeff(dev, port_id, prev_speed, end,
1011 link, res);
1012 else if (switchtec_is_gen4(dev))
1013 ret = switchtec_gen4_diag_port_eq_tx_coeff(dev, port_id, end,
1014 link, res);
1015
1016 return ret;
1017}
1018
1027static int switchtec_gen5_diag_port_eq_tx_table(struct switchtec_dev *dev,
1028 int port_id, int prev_speed,
1029 enum switchtec_diag_link link,
1031 *res)
1032{
1033 struct switchtec_gen5_port_eq_table out = {};
1034 struct switchtec_port_eq_table_in in = {
1035 .sub_cmd = MRPC_GEN5_PORT_EQ_FAR_END_TX_EQ_TABLE_DUMP,
1036 .port_id = port_id,
1037 };
1038 int ret, i;
1039
1040 if (!res) {
1041 errno = -EINVAL;
1042 return -1;
1043 }
1044
1045 in.dump_type = LANE_EQ_DUMP_TYPE_CURR;
1046 in.prev_rate = 0;
1047
1048 if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
1049 in.dump_type = LANE_EQ_DUMP_TYPE_PREV;
1050 in.prev_rate = prev_speed;
1051 }
1052
1053 ret = switchtec_cmd(dev, MRPC_PORT_EQ_STATUS, &in,
1054 sizeof(struct switchtec_port_eq_table_in),
1055 &out, sizeof(struct switchtec_gen5_port_eq_table));
1056 if (ret)
1057 return -1;
1058
1059 res->lane_id = out.lane_id;
1060 res->step_cnt = out.step_cnt;
1061
1062 for (i = 0; i < res->step_cnt; i++) {
1063 res->steps[i].pre_cursor = out.steps[i].pre_cursor;
1064 res->steps[i].post_cursor = out.steps[i].post_cursor;
1065 res->steps[i].fom = 0;
1066 res->steps[i].pre_cursor_up = 0;
1067 res->steps[i].post_cursor_up = 0;
1068 res->steps[i].error_status = out.steps[i].error_status;
1069 res->steps[i].active_status = out.steps[i].active_status;
1070 res->steps[i].speed = out.steps[i].speed;
1071 }
1072
1073 return 0;
1074}
1075
1084static int switchtec_gen4_diag_port_eq_tx_table(struct switchtec_dev *dev,
1085 int port_id,
1086 enum switchtec_diag_link link,
1088 *res)
1089{
1090 struct switchtec_diag_port_eq_table_out out = {};
1092 .sub_cmd = MRPC_PORT_EQ_FAR_END_TX_EQ_TABLE_DUMP,
1093 .port_id = port_id,
1094 };
1095 struct switchtec_diag_port_eq_status_in2 in_prev = {
1096 .sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_EQ_TX_TABLE_PREV,
1097 .port_id = port_id,
1098 };
1099 int ret, i;
1100
1101 if (!res) {
1102 errno = -EINVAL;
1103 return -1;
1104 }
1105
1106 if (link == SWITCHTEC_DIAG_LINK_CURRENT) {
1107 ret = switchtec_cmd(dev, MRPC_PORT_EQ_STATUS, &in, sizeof(in),
1108 &out, sizeof(out));
1109 } else if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
1110 ret = switchtec_cmd(dev, MRPC_EXT_RCVR_OBJ_DUMP, &in_prev,
1111 sizeof(in_prev), &out, sizeof(out));
1112 } else {
1113 errno = -EINVAL;
1114 return -1;
1115 }
1116
1117 if (ret)
1118 return -1;
1119
1120 res->lane_id = out.lane_id;
1121 res->step_cnt = out.step_cnt;
1122 for (i = 0; i < res->step_cnt; i++) {
1123 res->steps[i].pre_cursor = out.steps[i].pre_cursor;
1124 res->steps[i].post_cursor = out.steps[i].post_cursor;
1125 res->steps[i].fom = out.steps[i].fom;
1126 res->steps[i].pre_cursor_up = out.steps[i].pre_cursor_up;
1127 res->steps[i].post_cursor_up = out.steps[i].post_cursor_up;
1128 res->steps[i].error_status = out.steps[i].error_status;
1129 res->steps[i].active_status = out.steps[i].active_status;
1130 res->steps[i].speed = out.steps[i].speed;
1131 }
1132
1133 return 0;
1134}
1135
1144int switchtec_diag_port_eq_tx_table(struct switchtec_dev *dev, int port_id, int prev_speed,
1145 enum switchtec_diag_link link,
1146 struct switchtec_port_eq_table *res)
1147{
1148 int ret = -1;
1149
1150 if (switchtec_is_gen5(dev))
1151 ret = switchtec_gen5_diag_port_eq_tx_table(dev, port_id,
1152 prev_speed, link,
1153 res);
1154 else if (switchtec_is_gen4(dev))
1155 ret = switchtec_gen4_diag_port_eq_tx_table(dev, port_id, link,
1156 res);
1157
1158 return ret;
1159}
1160
1171static int switchtec_gen5_diag_port_eq_tx_fslf(struct switchtec_dev *dev,
1172 int port_id, int prev_speed,
1173 int lane_id,
1174 enum switchtec_diag_end end,
1175 enum switchtec_diag_link link,
1177 *res)
1178{
1179 struct switchtec_port_eq_tx_fslf_in in = {};
1180 struct switchtec_port_eq_tx_fslf_out out = {};
1181 int ret;
1182
1183 if (!res) {
1184 errno = -EINVAL;
1185 return -1;
1186 }
1187
1188 in.port_id = port_id;
1189 in.lane_id = lane_id;
1190
1191
1192 if (end == SWITCHTEC_DIAG_LOCAL) {
1193 in.sub_cmd = MRPC_GEN5_PORT_EQ_LOCAL_TX_FSLF_DUMP;
1194 } else if (end == SWITCHTEC_DIAG_FAR_END) {
1195 in.sub_cmd = MRPC_GEN5_PORT_EQ_FAR_END_TX_FSLF_DUMP;
1196 } else {
1197 errno = -EINVAL;
1198 return -1;
1199 }
1200
1201 if (link == SWITCHTEC_DIAG_LINK_CURRENT) {
1202 in.dump_type = LANE_EQ_DUMP_TYPE_CURR;
1203 } else {
1204 in.dump_type = LANE_EQ_DUMP_TYPE_PREV;
1205 in.prev_rate = prev_speed;
1206 }
1207
1208 ret = switchtec_cmd(dev, MRPC_PORT_EQ_STATUS, &in,
1209 sizeof(struct switchtec_port_eq_tx_fslf_in), &out,
1210 sizeof(struct switchtec_port_eq_tx_fslf_out));
1211 if (ret)
1212 return -1;
1213
1214 res->fs = out.fs;
1215 res->lf = out.lf;
1216
1217 return 0;
1218}
1219
1230static int switchtec_gen4_diag_port_eq_tx_fslf(struct switchtec_dev *dev,
1231 int port_id, int lane_id,
1232 enum switchtec_diag_end end,
1233 enum switchtec_diag_link link,
1235 *res)
1236{
1237 struct switchtec_diag_port_eq_tx_fslf_out out = {};
1239 .port_id = port_id,
1240 .lane_id = lane_id,
1241 };
1242 struct switchtec_diag_ext_recv_obj_dump_in in_prev = {
1243 .port_id = port_id,
1244 .lane_id = lane_id,
1245 };
1246 int ret;
1247
1248 if (!res) {
1249 errno = -EINVAL;
1250 return -1;
1251 }
1252
1253 if (end == SWITCHTEC_DIAG_LOCAL) {
1254 in.sub_cmd = MRPC_PORT_EQ_LOCAL_TX_FSLF_DUMP;
1255 in_prev.sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_LOCAL_TX_FSLF_PREV;
1256 } else if (end == SWITCHTEC_DIAG_FAR_END) {
1257 in.sub_cmd = MRPC_PORT_EQ_FAR_END_TX_FSLF_DUMP;
1258 in_prev.sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_FAR_END_TX_FSLF_PREV;
1259 } else {
1260 errno = -EINVAL;
1261 return -1;
1262 }
1263
1264 if (link == SWITCHTEC_DIAG_LINK_CURRENT) {
1265 ret = switchtec_cmd(dev, MRPC_PORT_EQ_STATUS, &in, sizeof(in),
1266 &out, sizeof(out));
1267 } else if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
1268 ret = switchtec_cmd(dev, MRPC_EXT_RCVR_OBJ_DUMP, &in_prev,
1269 sizeof(in_prev), &out, sizeof(out));
1270 } else {
1271 errno = -EINVAL;
1272 return -1;
1273 }
1274
1275 if (ret)
1276 return -1;
1277
1278 res->fs = out.fs;
1279 res->lf = out.lf;
1280
1281 return 0;
1282}
1283
1294int switchtec_diag_port_eq_tx_fslf(struct switchtec_dev *dev, int port_id,
1295 int prev_speed, int lane_id,
1296 enum switchtec_diag_end end,
1297 enum switchtec_diag_link link,
1298 struct switchtec_port_eq_tx_fslf *res)
1299{
1300 int ret = -1;
1301
1302 if (switchtec_is_gen5(dev))
1303 ret = switchtec_gen5_diag_port_eq_tx_fslf(dev, port_id,
1304 prev_speed, lane_id,
1305 end, link, res);
1306 else if (switchtec_is_gen4(dev))
1307 ret = switchtec_gen4_diag_port_eq_tx_fslf(dev, port_id,
1308 lane_id, end,
1309 link, res);
1310
1311 return ret;
1312}
1313
1324int switchtec_diag_rcvr_ext(struct switchtec_dev *dev, int port_id,
1325 int lane_id, enum switchtec_diag_link link,
1326 struct switchtec_rcvr_ext *res)
1327{
1328 struct switchtec_diag_rcvr_ext_out out = {};
1330 .port_id = port_id,
1331 .lane_id = lane_id,
1332 };
1333 int ret;
1334
1335 if (!res) {
1336 errno = -EINVAL;
1337 return -1;
1338 }
1339
1340 if (link == SWITCHTEC_DIAG_LINK_CURRENT) {
1341 in.sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_RCVR_EXT;
1342 } else if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
1343 in.sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_RCVR_EXT_PREV;
1344 } else {
1345 errno = -EINVAL;
1346 return -1;
1347 }
1348
1349 ret = switchtec_cmd(dev, MRPC_EXT_RCVR_OBJ_DUMP, &in, sizeof(in),
1350 &out, sizeof(out));
1351 if (ret)
1352 return -1;
1353
1354 res->ctle2_rx_mode = out.ctle2_rx_mode;
1355 res->dtclk_9 = out.dtclk_9;
1356 res->dtclk_8_6 = out.dtclk_8_6;
1357 res->dtclk_5 = out.dtclk_5;
1358
1359 return 0;
1360}
1361
1369int switchtec_diag_perm_table(struct switchtec_dev *dev,
1370 struct switchtec_mrpc table[MRPC_MAX_ID])
1371{
1372 uint32_t perms[(MRPC_MAX_ID + 31) / 32];
1373 int i, ret;
1374
1375 ret = switchtec_cmd(dev, MRPC_MRPC_PERM_TABLE_GET, NULL, 0,
1376 perms, sizeof(perms));
1377 if (ret)
1378 return -1;
1379
1380 for (i = 0; i < MRPC_MAX_ID; i++) {
1381 if (perms[i >> 5] & (1 << (i & 0x1f))) {
1382 if (switchtec_mrpc_table[i].tag) {
1383 table[i] = switchtec_mrpc_table[i];
1384 } else {
1385 table[i].tag = "UNKNOWN";
1386 table[i].desc = "Unknown MRPC Command";
1387 table[i].reserved = true;
1388 }
1389 } else {
1390 table[i].tag = NULL;
1391 table[i].desc = NULL;
1392 }
1393 }
1394
1395 return 0;
1396}
1397
1406int switchtec_diag_refclk_ctl(struct switchtec_dev *dev, int stack_id, bool en)
1407{
1408 struct switchtec_diag_refclk_ctl_in cmd = {
1409 .sub_cmd = en ? MRPC_REFCLK_S_ENABLE : MRPC_REFCLK_S_DISABLE,
1410 .stack_id = stack_id,
1411 };
1412
1413 return switchtec_cmd(dev, MRPC_REFCLK_S, &cmd, sizeof(cmd), NULL, 0);
1414}
1415
1422int switchtec_diag_refclk_status(struct switchtec_dev *dev, uint8_t *stack_info)
1423{
1424 struct switchtec_diag_refclk_ctl_in cmd = {
1425 .sub_cmd = MRPC_REFCLK_S_STATUS,
1426 };
1427
1428 return switchtec_cmd(dev, MRPC_REFCLK_S, &cmd, sizeof(cmd), stack_info,
1429 sizeof(uint8_t) * SWITCHTEC_MAX_STACKS);
1430}
1431
1432static void switchtec_diag_ltssm_set_log_data(struct switchtec_diag_ltssm_log
1433 *log_data,
1435 *log_dump_out_ptr,
1436 int curr_idx, uint16_t num_of_logs)
1437{
1438 uint32_t dw0;
1439 uint32_t timestamp;
1440
1441 int major;
1442 int minor;
1443 int rate;
1444
1445 for (int j = 0; j < num_of_logs; j++) {
1446 dw0 = log_dump_out_ptr[j].dw0;
1447 timestamp = log_dump_out_ptr[j].ram_timestamp;
1448
1449 rate = (dw0 >> 13) & 0x7;
1450 major = (dw0 >> 7) & 0x3f;
1451 minor = (dw0 >> 3) & 0xf;
1452
1453 log_data[curr_idx + j].timestamp = timestamp;
1454 log_data[curr_idx + j].link_rate = switchtec_gen_transfers[rate+1];
1455 log_data[curr_idx + j].link_state = major | (minor << 8);
1456 }
1457}
1458
1466static int switchtec_diag_ltssm_log_gen5(struct switchtec_dev *dev,
1467 int port, int *log_count,
1468 struct switchtec_diag_ltssm_log *log_data)
1469{
1470 struct {
1471 uint8_t sub_cmd;
1472 uint8_t port;
1473 uint8_t freeze;
1474 uint8_t unused;
1475 } ltssm_freeze;
1476
1477 struct {
1478 uint8_t sub_cmd;
1479 uint8_t port;
1480 } status;
1481
1482 struct {
1483 uint16_t log_count;
1484 uint16_t w0_trigger_count;
1485 uint16_t w1_trigger_count;
1486 } status_output;
1487
1488 struct {
1489 uint8_t sub_cmd;
1490 uint8_t port;
1491 uint16_t log_index;
1492 uint16_t no_of_logs;
1493 } log_dump;
1494
1495 uint8_t log_buffer[1024];
1496
1497 struct switchtec_diag_ltssm_log_dmp_out *log_dump_out_ptr = NULL;
1498
1499 int ret;
1500 int log_dmp_size = sizeof(struct switchtec_diag_ltssm_log_dmp_out);
1501
1502 /* freeze logs */
1503 ltssm_freeze.sub_cmd = MRPC_LTMON_FREEZE;
1504 ltssm_freeze.port = port;
1505 ltssm_freeze.freeze = 1;
1506
1507 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &ltssm_freeze,
1508 sizeof(ltssm_freeze), NULL, 0);
1509 if (ret)
1510 return ret;
1511
1512 /* get number of entries */
1513 status.sub_cmd = MRPC_LTMON_GET_STATUS_GEN5;
1514 status.port = port;
1515 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &status,
1516 sizeof(status), &status_output,
1517 sizeof(status_output));
1518 if (ret)
1519 return ret;
1520
1521 *log_count = status_output.log_count;
1522
1523 /* get log data */
1524 log_dump.sub_cmd = MRPC_LTMON_LOG_DUMP_GEN5;
1525 log_dump.port = port;
1526 log_dump.log_index = 0;
1527 log_dump.no_of_logs = *log_count;
1528
1529 if(log_dump.no_of_logs <= SWITCHTEC_LTSSM_MAX_LOGS) {
1530 /* Single buffer log case */
1531 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &log_dump,
1532 sizeof(log_dump), &log_buffer[0],
1533 log_dump.no_of_logs * log_dmp_size + 4);
1534 if (ret)
1535 return ret;
1536 log_dump_out_ptr =
1538 &(log_buffer[4]);
1539
1540 switchtec_diag_ltssm_set_log_data(log_data,
1541 log_dump_out_ptr,
1542 0, log_dump.no_of_logs);
1543 } else {
1544 /* Multiple buffer log case */
1545 int buff_count = log_dump.no_of_logs / SWITCHTEC_LTSSM_MAX_LOGS;
1546 int curr_idx = 0;
1547 int buffer_size = SWITCHTEC_LTSSM_MAX_LOGS * log_dmp_size + 4;
1548
1549 for (int i = 0; i < buff_count; i++) {
1550 log_dump.no_of_logs = SWITCHTEC_LTSSM_MAX_LOGS;
1551 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG,
1552 &log_dump, sizeof(log_dump),
1553 &log_buffer[0], buffer_size);
1554 if (ret)
1555 return ret;
1556 log_dump_out_ptr =
1558 &(log_buffer[4]);
1559
1560 switchtec_diag_ltssm_set_log_data(log_data,
1561 log_dump_out_ptr,
1562 curr_idx,
1563 log_dump.no_of_logs);
1564 curr_idx += SWITCHTEC_LTSSM_MAX_LOGS;
1565 log_dump.log_index = curr_idx;
1566 }
1567 if (*log_count % SWITCHTEC_LTSSM_MAX_LOGS) {
1568 log_dump.no_of_logs = *log_count - curr_idx;
1569 buffer_size = log_dump.no_of_logs * log_dmp_size + 4;
1570 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG,
1571 &log_dump, sizeof(log_dump),
1572 &log_buffer[0], buffer_size);
1573 if (ret)
1574 return ret;
1575 log_dump_out_ptr =
1577 &(log_buffer[4]);
1578
1579 switchtec_diag_ltssm_set_log_data(log_data,
1580 log_dump_out_ptr,
1581 curr_idx,
1582 log_dump.no_of_logs);
1583 }
1584 }
1585
1586 /* unfreeze logs */
1587 ltssm_freeze.sub_cmd = MRPC_LTMON_FREEZE;
1588 ltssm_freeze.port = port;
1589 ltssm_freeze.freeze = 0;
1590
1591 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &ltssm_freeze,
1592 sizeof(ltssm_freeze), NULL, 0);
1593
1594 return ret;
1595}
1596
1604static int switchtec_diag_ltssm_log_gen4(struct switchtec_dev *dev,
1605 int port, int *log_count,
1606 struct switchtec_diag_ltssm_log *log_data)
1607{
1608 struct {
1609 uint8_t sub_cmd;
1610 uint8_t port;
1611 uint8_t freeze;
1612 uint8_t unused;
1613 } ltssm_freeze;
1614
1615 struct {
1616 uint8_t sub_cmd;
1617 uint8_t port;
1618 } status;
1619 struct {
1620 uint32_t w0_trigger_count;
1621 uint32_t w1_trigger_count;
1622 uint8_t log_num;
1623 } status_output;
1624
1625 struct {
1626 uint8_t sub_cmd;
1627 uint8_t port;
1628 uint8_t log_index;
1629 uint8_t no_of_logs;
1630 } log_dump;
1631 struct {
1632 uint32_t dw0;
1633 uint32_t dw1;
1634 } log_dump_out[256];
1635
1636 uint32_t dw1;
1637 uint32_t dw0;
1638 int major;
1639 int minor;
1640 int rate;
1641 int ret;
1642 int i;
1643
1644 /* freeze logs */
1645 ltssm_freeze.sub_cmd = MRPC_LTMON_FREEZE;
1646 ltssm_freeze.port = port;
1647 ltssm_freeze.freeze = 1;
1648
1649 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &ltssm_freeze,
1650 sizeof(ltssm_freeze), NULL, 0);
1651 if (ret)
1652 return ret;
1653
1654 /* get number of entries */
1655 status.sub_cmd = MRPC_LTMON_GET_STATUS_GEN4;
1656 status.port = port;
1657 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &status,
1658 sizeof(status), &status_output,
1659 sizeof(status_output));
1660 if (ret)
1661 return ret;
1662
1663 if (status_output.log_num < *log_count)
1664 *log_count = status_output.log_num;
1665
1666 /* get log data */
1667 log_dump.sub_cmd = MRPC_LTMON_LOG_DUMP_GEN4;
1668 log_dump.port = port;
1669 log_dump.log_index = 0;
1670 log_dump.no_of_logs = *log_count;
1671 if(log_dump.no_of_logs <= 126) {
1672 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &log_dump,
1673 sizeof(log_dump), log_dump_out,
1674 8 * log_dump.no_of_logs);
1675 if (ret)
1676 return ret;
1677 } else {
1678 log_dump.no_of_logs = 126;
1679 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &log_dump,
1680 sizeof(log_dump), log_dump_out,
1681 8 * log_dump.no_of_logs);
1682 if (ret)
1683 return ret;
1684
1685 log_dump.log_index = 126;
1686 log_dump.no_of_logs = *log_count - 126;
1687
1688 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &log_dump,
1689 sizeof(log_dump), log_dump_out + 126,
1690 8 * log_dump.no_of_logs);
1691 if (ret)
1692 return ret;
1693 }
1694 for (i = 0; i < *log_count; i++) {
1695 dw1 = log_dump_out[i].dw1;
1696 dw0 = log_dump_out[i].dw0;
1697 rate = (dw0 >> 13) & 0x3;
1698 major = (dw0 >> 7) & 0xf;
1699 minor = (dw0 >> 3) & 0xf;
1700
1701 log_data[i].timestamp = dw1 & 0x3ffffff;
1702 log_data[i].link_rate = switchtec_gen_transfers[rate + 1];
1703 log_data[i].link_state = major | (minor << 8);
1704 }
1705
1706 /* unfreeze logs */
1707 ltssm_freeze.sub_cmd = MRPC_LTMON_FREEZE;
1708 ltssm_freeze.port = port;
1709 ltssm_freeze.freeze = 0;
1710
1711 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &ltssm_freeze,
1712 sizeof(ltssm_freeze), NULL, 0);
1713
1714 return ret;
1715}
1716
1724int switchtec_diag_ltssm_log(struct switchtec_dev *dev,
1725 int port, int *log_count,
1726 struct switchtec_diag_ltssm_log *log_data)
1727{
1728 int ret;
1729 if (switchtec_is_gen5(dev))
1730 ret = switchtec_diag_ltssm_log_gen5(dev, port, log_count, log_data);
1731 else
1732 ret = switchtec_diag_ltssm_log_gen4(dev, port, log_count, log_data);
1733 return ret;
1734}
1735
1741int switchtec_diag_ltssm_clear(struct switchtec_dev *dev, int port)
1742{
1743 int ret;
1744 struct {
1745 uint8_t subcmd;
1746 uint8_t port_id;
1747 uint16_t reserved;
1748 } ltssm_clear;
1749
1750 ltssm_clear.subcmd = MRPC_LTMON_CLEAR_LOG;
1751 ltssm_clear.port_id = port;
1752
1753 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &ltssm_clear,
1754 sizeof(ltssm_clear), NULL, 0);
1755 return ret;
1756}
1757
1758int switchtec_tlp_inject(struct switchtec_dev *dev, int port_id, int tlp_type,
1759 int tlp_length, int ecrc, uint32_t *raw_tlp_data)
1760{
1761 uint32_t tlp_out;
1762 int ret = 1;
1763 struct switchtec_tlp_inject_in tlp_in = {
1764 .dest_port = port_id,
1765 .tlp_type = tlp_type,
1766 .tlp_length = tlp_length,
1767 .ecrc = ecrc
1768 };
1769 for (int i = 0; i < tlp_in.tlp_length; i++) {
1770 tlp_in.raw_tlp_data[i] = htole32(*(raw_tlp_data + i));
1771 }
1772 free(raw_tlp_data);
1773
1774 ret = switchtec_cmd(dev, MRPC_DIAG_TLP_INJECT, &tlp_in, sizeof(tlp_in),
1775 &tlp_out, sizeof(tlp_out));
1776 return ret;
1777}
1778
1786int switchtec_aer_event_gen(struct switchtec_dev *dev, int port_id,
1787 int aer_error_id, int trigger_event)
1788{
1789 uint32_t output;
1790 int ret_val;
1791
1792 struct switchtec_aer_event_gen_in sub_cmd_id = {
1793 .sub_cmd = trigger_event,
1794 .phys_port_id = port_id,
1795 .err_mask = aer_error_id,
1796 .hdr_log[0] = 0,
1797 .hdr_log[1] = 0,
1798 .hdr_log[2] = 0,
1799 .hdr_log[3] = 0
1800 };
1801
1802 ret_val = switchtec_cmd(dev, MRPC_AER_GEN, &sub_cmd_id,
1803 sizeof(sub_cmd_id), &output, sizeof(output));
1804 return ret_val;
1805}
1806
1814int switchtec_inject_err_dllp(struct switchtec_dev *dev, int phys_port_id,
1815 int data)
1816{
1817 uint32_t output;
1818
1819 struct switchtec_lnkerr_dllp_in cmd = {
1820 .subcmd = MRPC_ERR_INJ_DLLP,
1821 .phys_port_id = phys_port_id,
1822 .data = data,
1823 };
1824
1825 return switchtec_cmd(dev, MRPC_MRPC_ERR_INJ, &cmd,
1826 sizeof(cmd), &output, sizeof(output));
1827}
1828
1837int switchtec_inject_err_dllp_crc(struct switchtec_dev *dev,
1838 int phys_port_id, int enable,
1839 uint16_t rate)
1840{
1841 uint32_t output;
1842
1843 struct switchtec_lnkerr_dllp_crc_in cmd = {
1844 .subcmd = MRPC_ERR_INJ_DLLP_CRC,
1845 .phys_port_id = phys_port_id,
1846 .enable = enable,
1847 .rate = rate,
1848 };
1849
1850 return switchtec_cmd(dev, MRPC_MRPC_ERR_INJ, &cmd,
1851 sizeof(cmd), &output, sizeof(output));
1852}
1853
1854static int switchtec_inject_err_tlp_lcrc_gen4(struct switchtec_dev *dev,
1855 int phys_port_id, int enable,
1856 uint8_t rate)
1857{
1858 uint32_t output;
1859
1861 .subcmd = MRPC_ERR_INJ_TLP_LCRC,
1862 .phys_port_id = phys_port_id,
1863 .enable = enable,
1864 .rate = rate,
1865 };
1866 printf("enable: %d\n", enable);
1867
1868 return switchtec_cmd(dev, MRPC_MRPC_ERR_INJ, &cmd,
1869 sizeof(cmd), &output, sizeof(output));
1870}
1871
1872static int switchtec_inject_err_tlp_lcrc_gen5(struct switchtec_dev *dev,
1873 int phys_port_id, int enable,
1874 uint8_t rate)
1875{
1876 uint32_t output;
1877
1879 .subcmd = MRPC_ERR_INJ_TLP_LCRC,
1880 .phys_port_id = phys_port_id,
1881 .enable = enable,
1882 .rate = rate,
1883 };
1884
1885 return switchtec_cmd(dev, MRPC_MRPC_ERR_INJ, &cmd,
1886 sizeof(cmd), &output, sizeof(output));
1887}
1888
1896int switchtec_inject_err_tlp_lcrc(struct switchtec_dev *dev, int phy_port,
1897 int enable, uint8_t rate)
1898{
1899 int ret;
1900 if (switchtec_is_gen4(dev)) {
1901 ret = switchtec_inject_err_tlp_lcrc_gen4(dev, phy_port, enable, rate);
1902 return ret;
1903 } else if (switchtec_is_gen5(dev)) {
1904 ret = switchtec_inject_err_tlp_lcrc_gen5(dev, phy_port, enable, rate);
1905 return ret;
1906 }
1907 fprintf(stderr, "The TLP LCRC is not supported for Gen3 switches.\n");
1908 return -1;
1909}
1910
1917int switchtec_inject_err_tlp_seq_num(struct switchtec_dev *dev, int phys_port_id)
1918{
1919 uint32_t output;
1920
1921 struct switchtec_lnkerr_tlp_seqn_in cmd = {
1922 .subcmd = MRPC_ERR_INJ_TLP_SEQ,
1923 .phys_port_id = phys_port_id,
1924 };
1925
1926 return switchtec_cmd(dev, MRPC_MRPC_ERR_INJ, &cmd,
1927 sizeof(cmd), &output, sizeof(output));
1928}
1929
1938int switchtec_inject_err_ack_nack(struct switchtec_dev *dev, int phys_port_id,
1939 uint16_t seq_num, uint8_t count)
1940{
1941 uint32_t output;
1942
1943 struct switchtec_lnkerr_ack_nack_in cmd = {
1944 .subcmd = MRPC_ERR_INJ_ACK_NACK,
1945 .phys_port_id = phys_port_id,
1946 .seq_num = seq_num,
1947 .count = count,
1948 };
1949
1950 return switchtec_cmd(dev, MRPC_MRPC_ERR_INJ, &cmd,
1951 sizeof(cmd), &output, sizeof(output));
1952}
1953
1960int switchtec_inject_err_cto(struct switchtec_dev *dev, int phys_port_id)
1961{
1962 uint32_t output;
1963
1964 struct switchtec_lnkerr_cto_in cmd = {
1965 .subcmd = MRPC_ERR_INJ_CTO,
1966 .phys_port_id = phys_port_id,
1967 };
1968
1969 return switchtec_cmd(dev, MRPC_MRPC_ERR_INJ, &cmd,
1970 sizeof(cmd), &output, sizeof(output));
1971}
1972
1973static void osa_dword_data_helper(const uint32_t dwords[4], char *buffer) {
1974 char *ptr = buffer;
1975 for (int i = 3; i >= 0; --i) {
1976 int tmp = sprintf(ptr, "0x%08X", dwords[i]);
1977 ptr += tmp;
1978 *ptr = ' ';
1979 ptr++;
1980 }
1981 *ptr = '\0';
1982}
1983
1984static void print_osa_capture_data(uint32_t* entry_dwords, uint8_t entries_read)
1985{
1986 int curr_idx = 0;
1987 uint32_t timestamp_upper = 0;
1988 uint32_t timestamp_lower = 0;
1989 uint64_t timestamp = 0;
1990 char data_string[45];
1991 uint32_t osa_dword_data[4];
1992
1993 printf("IDX\tTIMESTAMP\tCNT\tRATE\tDRP\tTRIG\tDATA\n");
1994 for (int i = 0; i < entries_read; i++) {
1995 printf("%d\t", i);
1996 curr_idx = (i * 6);
1997 for (int j = 0; j < 6; j++) {
1998 if (j >= 0 && j <= 3) {
1999 osa_dword_data[j] = entry_dwords[curr_idx];
2000 }
2001 else if (j == 4) {
2002 osa_dword_data_helper(osa_dword_data, data_string);
2003 timestamp_lower = (entry_dwords[curr_idx] >> 22) & 0x3FF;
2004 timestamp_upper = (entry_dwords[curr_idx+1] & 0x7FFFFFF);
2005 printf("time_upper: %d\n", timestamp_upper);
2006 printf("time_lower: %d\n", timestamp_lower);
2007 timestamp = (uint64_t)timestamp_upper << 12 | timestamp_lower;
2008 printf("0x%08lx\t", timestamp);
2009 printf("%d\t", (entry_dwords[curr_idx] >> 3) & 0x7FFFF);
2010 printf("%d\t", entry_dwords[curr_idx] & 0x7);
2011 printf("%d\t", (entry_dwords[curr_idx+1] >> 28) & 0x1);
2012 printf("%d\t", (entry_dwords[curr_idx+1] >> 27) & 0x1);
2013 printf("%s\n", data_string);
2014 }
2015 curr_idx++;
2016 }
2017 printf("\n");
2018 }
2019}
2020
2021int switchtec_osa_capture_data(struct switchtec_dev *dev, int stack_id,
2022 int lane, int direction)
2023{
2024 int ret = 0;
2025 struct {
2026 uint8_t sub_cmd;
2027 uint8_t stack_id;
2028 uint8_t lane;
2029 uint8_t direction;
2030 uint16_t start_entry;
2031 uint8_t num_entries;
2032 uint8_t reserved;
2033 } osa_data_read_in;
2034
2035 struct {
2036 uint8_t entries_read;
2037 uint8_t stack_id;
2038 uint8_t lane;
2039 uint8_t direction;
2040 uint16_t next_entry;
2041 uint16_t entries_remaining;
2042 uint16_t wrap;
2043 uint16_t reserved;
2044 } osa_data_entries_out;
2045
2046 osa_data_read_in.sub_cmd = MRPC_OSA_DATA_READ;
2047 osa_data_read_in.stack_id = stack_id;
2048 osa_data_read_in.lane = lane;
2049 osa_data_read_in.direction = direction;
2050
2051 osa_data_read_in.start_entry = 0;
2052 osa_data_read_in.num_entries = 0;
2053
2054 struct {
2055 uint8_t sub_cmd;
2056 uint8_t stack_id;
2057 uint16_t reserved;
2058 } osa_status_query_in;
2059
2060 struct {
2061 uint8_t state;
2062 uint8_t trigger_lane;
2063 uint8_t trigger_dir;
2064 uint8_t reserved;
2065 uint16_t trigger_reason;
2066 uint16_t reserved2;
2067 } osa_status_query_out;
2068
2069 osa_status_query_in.sub_cmd = MRPC_OSA_STATUS_QUERY;
2070 osa_status_query_in.stack_id = stack_id;
2071
2072 ret = switchtec_cmd(dev, MRPC_ORDERED_SET_ANALYZER, &osa_status_query_in,
2073 sizeof(osa_status_query_in), &osa_status_query_out,
2074 sizeof(osa_status_query_out));
2075
2076 printf("Current status of stack %d\n", stack_id);
2077 printf("state: %d\n", osa_status_query_out.state);
2078 printf("trigger_lane: %d\n", osa_status_query_out.trigger_lane);
2079 printf("trigger_dir: %d\n", osa_status_query_out.trigger_dir);
2080 printf("trigger_reason: %d\n", osa_status_query_out.trigger_reason);
2081
2082 ret = switchtec_cmd(dev, MRPC_ORDERED_SET_ANALYZER, &osa_data_read_in,
2083 sizeof(osa_data_read_in), &osa_data_entries_out,
2084 sizeof(osa_data_entries_out));
2085 if (ret) {
2086 switchtec_perror("OSA data dump");
2087 return ret;
2088 }
2089 printf("OSA: Captured Data \n");
2090
2091 struct {
2092 uint8_t entries_read;
2093 uint8_t stack_id;
2094 uint8_t lane;
2095 uint8_t direction;
2096 uint16_t next_entry;
2097 uint16_t entries_remaining;
2098 uint16_t wrap;
2099 uint16_t reserved;
2100 uint32_t entry_dwords[];
2101 } *osa_data_read_out = alloca(sizeof(*osa_data_read_out) +
2102 osa_data_entries_out.entries_remaining * 6 *
2103 sizeof(uint32_t));
2104
2105 osa_data_read_out->entries_remaining = osa_data_entries_out.entries_remaining;
2106 osa_data_read_out->next_entry = osa_data_entries_out.next_entry;
2107
2108 while (osa_data_read_out->entries_remaining != 0) {
2109 osa_data_read_in.num_entries = osa_data_read_out->entries_remaining;
2110 osa_data_read_in.start_entry = osa_data_read_out->next_entry;
2111
2112 ret = switchtec_cmd(dev, MRPC_ORDERED_SET_ANALYZER,
2113 &osa_data_read_in, sizeof(osa_data_read_in),
2114 osa_data_read_out, sizeof(*osa_data_read_out));
2115
2116 if (ret) {
2117 return -1;
2118 }
2119 print_osa_capture_data(osa_data_read_out->entry_dwords,
2120 osa_data_read_out->entries_read);
2121 }
2122
2123 return ret;
2124}
2125
2126int switchtec_osa_capture_control(struct switchtec_dev *dev, int stack_id,
2127 int lane_mask, int direction,
2128 int drop_single_os, int stop_mode,
2129 int snapshot_mode, int post_trigger,
2130 int os_types)
2131{
2132 int ret = 0;
2133
2135
2136 osa_capture_ctrl_in.sub_cmd = MRPC_OSA_CAPTURE_CTRL;
2137 osa_capture_ctrl_in.stack_id = stack_id;
2138 osa_capture_ctrl_in.lane_mask = lane_mask;
2139 osa_capture_ctrl_in.direction = direction;
2140 osa_capture_ctrl_in.drop_single_os = drop_single_os;
2141 osa_capture_ctrl_in.stop_mode = stop_mode;
2142 osa_capture_ctrl_in.snapshot_mode = snapshot_mode;
2143 osa_capture_ctrl_in.post_trig_entries = post_trigger;
2144 osa_capture_ctrl_in.os_types = os_types;
2145
2146 ret = switchtec_cmd(dev, MRPC_ORDERED_SET_ANALYZER, &osa_capture_ctrl_in,
2147 sizeof(osa_capture_ctrl_in), NULL, 0);
2148 if (ret) {
2149 switchtec_perror("OSA capture control");
2150 return ret;
2151 }
2152 printf("OSA: Configuring capture control on stack %d\n", stack_id);
2153 return ret;
2154}
2155
2156int switchtec_osa_config_misc(struct switchtec_dev *dev, int stack_id,
2157 int trigger_en)
2158{
2159 int ret = 0;
2160 struct {
2161 uint8_t sub_cmd;
2162 uint8_t stack_id;
2163 uint16_t reserved;
2164 uint8_t trigger_en;
2165 uint8_t reserved2;
2166 uint16_t reserved3;
2167 } osa_misc_config_in;
2168
2169 osa_misc_config_in.sub_cmd = MRPC_OSA_MISC_TRIG_CONFIG;
2170 osa_misc_config_in.stack_id = stack_id;
2171 osa_misc_config_in.trigger_en = trigger_en;
2172
2173 ret = switchtec_cmd(dev, MRPC_ORDERED_SET_ANALYZER, &osa_misc_config_in,
2174 sizeof(osa_misc_config_in), NULL, 0);
2175 if (ret) {
2176 switchtec_perror("OSA misc config");
2177 return ret;
2178 }
2179 printf("OSA: Enabled misc triggering config on stack %d\n", stack_id);
2180 return ret;
2181}
2182
2183int switchtec_osa_config_pattern(struct switchtec_dev *dev, int stack_id,
2184 int direction, int lane_mask, int link_rate,
2185 uint32_t *value_data, uint32_t *mask_data)
2186{
2187 int ret = 1;
2188
2190 osa_pattern_config_in.sub_cmd = MRPC_OSA_PAT_TRIG_CONFIG;
2191 osa_pattern_config_in.stack_id = stack_id;
2192 osa_pattern_config_in.direction = direction;
2193 osa_pattern_config_in.lane_mask = lane_mask;
2194 osa_pattern_config_in.link_rate = link_rate;
2195 osa_pattern_config_in.pat_val_dword0 = value_data[0];
2196 osa_pattern_config_in.pat_val_dword1 = value_data[1];
2197 osa_pattern_config_in.pat_val_dword2 = value_data[2];
2198 osa_pattern_config_in.pat_val_dword3 = value_data[3];
2199 osa_pattern_config_in.pat_mask_dword0 = mask_data[0];
2200 osa_pattern_config_in.pat_mask_dword1 = mask_data[1];
2201 osa_pattern_config_in.pat_mask_dword2 = mask_data[2];
2202 osa_pattern_config_in.pat_mask_dword3 = mask_data[3];
2203
2204 ret = switchtec_cmd(dev, MRPC_ORDERED_SET_ANALYZER,
2206 sizeof(osa_pattern_config_in), NULL, 0);
2207 if (ret) {
2208 switchtec_perror("OSA pattern config");
2209 return ret;
2210 }
2211 printf("OSA: Enabled pattern triggering config on stack %d\n", stack_id);
2212 return ret;
2213}
2214
2215int switchtec_osa_config_type(struct switchtec_dev *dev, int stack_id,
2216 int direction, int lane_mask, int link_rate, int os_types)
2217{
2218 int ret = 1;
2219
2221
2222 osa_type_config_in.sub_cmd = MRPC_OSA_TYPE_TRIG_CONFIG;
2223 osa_type_config_in.stack_id = stack_id;
2224 osa_type_config_in.lane_mask = lane_mask;
2225 osa_type_config_in.direction = direction;
2226 osa_type_config_in.link_rate = link_rate;
2227 osa_type_config_in.os_types = os_types;
2228
2229 printf("%d : %d : %d : %d : %d\n", stack_id, lane_mask, direction,
2230 link_rate, os_types);
2231 ret = switchtec_cmd(dev, MRPC_ORDERED_SET_ANALYZER, &osa_type_config_in,
2232 sizeof(osa_type_config_in), NULL, 0);
2233 if (ret) {
2234 switchtec_perror("OSA type config");
2235 return ret;
2236 }
2237 printf("OSA: Enabled type triggering config on stack %d\n", stack_id);
2238 return ret;
2239}
2240
2241int switchtec_osa_dump_conf(struct switchtec_dev *dev, int stack_id)
2242{
2243 int ret = 0;
2244
2245 struct {
2246 uint8_t sub_cmd;
2247 uint8_t stack_id;
2248 uint16_t reserved;
2249 } osa_dmp_in;
2250
2251 struct {
2252 int16_t os_type_trig_lane_mask;
2253 uint8_t os_type_trig_dir;
2254 uint8_t os_type_trig_link_rate;
2255 uint8_t os_type_trig_os_types;
2256 uint8_t reserved;
2257 uint16_t reserved2;
2258 uint16_t os_pat_trig_lane_mask;
2259 uint8_t os_pat_trig_dir;
2260 uint8_t os_pat_trig_link_rate;
2261 uint32_t os_pat_trig_val_dw0;
2262 uint32_t os_pat_trig_val_dw1;
2263 uint32_t os_pat_trig_val_dw2;
2264 uint32_t os_pat_trig_val_dw3;
2265 uint32_t os_pat_trig_mask_dw0;
2266 uint32_t os_pat_trig_mask_dw1;
2267 uint32_t os_pat_trig_mask_dw2;
2268 uint32_t os_pat_trig_mask_dw3;
2269 uint8_t misc_trig_en;
2270 uint8_t reserved3;
2271 uint16_t reserved4;
2272 uint16_t capture_lane_mask;
2273 uint8_t capture_dir;
2274 uint8_t capture_drop_os;
2275 uint8_t capture_stop_mode;
2276 uint8_t capture_snap_mode;
2277 uint16_t capture_post_trig_entries;
2278 uint8_t capture_os_types;
2279 uint8_t reserved5;
2280 uint16_t reserved6;
2281 } osa_dmp_out;
2282
2283 osa_dmp_in.stack_id = stack_id;
2284 osa_dmp_in.sub_cmd = MRPC_OSA_CONFIG_DMP;
2285
2286 ret = switchtec_cmd(dev, MRPC_ORDERED_SET_ANALYZER, &osa_dmp_in,
2287 sizeof(osa_dmp_in), &osa_dmp_out,
2288 sizeof(osa_dmp_out));
2289 if (ret) {
2290 switchtec_perror("OSA config dump");
2291 return ret;
2292 }
2293 printf("Config dump \n");
2294 printf("---- OS Type ---------------\n");
2295 printf("lane mask: \t\t%d\n", osa_dmp_out.os_type_trig_lane_mask);
2296 printf("direciton: \t\t%d\n", osa_dmp_out.os_type_trig_dir);
2297 printf("link rate: \t\t%d\n", osa_dmp_out.os_type_trig_link_rate);
2298 printf("os types: \t\t%d\n", osa_dmp_out.os_type_trig_os_types);
2299 printf("---- OS Pattern ------------\n");
2300 printf("lane mask: \t\t%d\n", osa_dmp_out.os_pat_trig_lane_mask);
2301 printf("direciton: \t\t%d\n", osa_dmp_out.os_pat_trig_dir);
2302 printf("link rate: \t\t%d\n", osa_dmp_out.os_pat_trig_link_rate);
2303 printf("patttern: \t\t%d %d %d %d\n", osa_dmp_out.os_pat_trig_val_dw0,
2304 osa_dmp_out.os_pat_trig_val_dw1, osa_dmp_out.os_pat_trig_val_dw2,
2305 osa_dmp_out.os_pat_trig_val_dw3);
2306 printf("mask: \t\t\t%d %d %d %d\n", osa_dmp_out.os_pat_trig_mask_dw0,
2307 osa_dmp_out.os_pat_trig_mask_dw1, osa_dmp_out.os_pat_trig_mask_dw2,
2308 osa_dmp_out.os_pat_trig_mask_dw3);
2309 printf("---- Misc ------------------\n");
2310 printf("Misc trigger enabled: \t%d\n", osa_dmp_out.misc_trig_en);
2311 printf("---- Capture ---------------\n");
2312 printf("lane mask: \t\t%d\n", osa_dmp_out.capture_lane_mask);
2313 printf("direciton: \t\t%d\n", osa_dmp_out.capture_dir);
2314 printf("drop single os: \t%d\n", osa_dmp_out.capture_drop_os);
2315 printf("stop mode: \t\t%d\n", osa_dmp_out.capture_stop_mode);
2316 printf("snaphot mode: \t\t%d\n", osa_dmp_out.capture_snap_mode);
2317 printf("post-trigger entries: \t%d\n", osa_dmp_out.capture_post_trig_entries);
2318 printf("os types: \t\t%d\n", osa_dmp_out.capture_os_types);
2319 return ret;
2320}
2321
2322int switchtec_osa(struct switchtec_dev *dev, int stack_id, int operation)
2323{
2324 int ret = 0;
2325 struct {
2326 uint8_t sub_cmd;
2327 uint8_t stack_id;
2328 uint16_t reserved;
2329 } osa_rel_access_perm_in;
2330
2331 struct {
2332 uint8_t sub_cmd;
2333 uint8_t stack_id;
2334 uint16_t reserved;
2335 } osa_status_query_in;
2336
2337 struct {
2338 uint8_t state;
2339 uint8_t trigger_lane;
2340 uint8_t trigger_dir;
2341 uint8_t reserved;
2342 uint16_t trigger_reason;
2343 uint16_t reserved2;
2344 } osa_status_query_out;
2345
2346 struct {
2347 uint8_t sub_cmd;
2348 uint8_t stack_id;
2349 uint8_t operation;
2350 uint8_t reserved;
2351 } osa_op_in;
2352
2353 char *valid_ops[6] = {"stop", "start", "trigger", "reset", "release",
2354 "status"};
2355 char *states[5] = {"Deactivated (not armed)", "Started (armed), not triggered",
2356 "Started (armted), triggered", "Stopped, not triggered",
2357 "Stopped, triggered"};
2358 char *directions[2] = {"TX", "RX"};
2359 printf("Attempting %s operation...\n", valid_ops[operation]);
2360 if (operation == 4) {
2361 osa_rel_access_perm_in.sub_cmd = MRPC_OSA_REL_ACCESS_PERM;
2362 osa_rel_access_perm_in.stack_id = stack_id;
2363
2364 ret = switchtec_cmd(dev, MRPC_ORDERED_SET_ANALYZER,
2365 &osa_rel_access_perm_in,
2366 sizeof(osa_rel_access_perm_in), NULL, 0);
2367 }
2368 else if (operation == 5) {
2369 osa_status_query_in.sub_cmd = MRPC_OSA_STATUS_QUERY;
2370 osa_status_query_in.stack_id = stack_id;
2371
2372 ret = switchtec_cmd(dev, MRPC_ORDERED_SET_ANALYZER,
2373 &osa_status_query_in, sizeof(osa_status_query_in),
2374 &osa_status_query_out, sizeof(osa_status_query_out));
2375 if (ret) {
2376 switchtec_perror("OSA operation");
2377 return ret;
2378 }
2379 printf("Status of stack %d\n", stack_id);
2380 printf("STATE: %s\n", states[osa_status_query_out.state]);
2381 printf("TRIGGER_LANE: %d\n", osa_status_query_out.trigger_lane);
2382 printf("TRIGGER_DIR: %s\n", directions[osa_status_query_out.trigger_dir]);
2383 printf("REASON_BITMASK: %d\n", osa_status_query_out.trigger_reason);
2384 }
2385 else {
2386 osa_op_in.sub_cmd = MRPC_OSA_ANALYZER_OP;
2387 osa_op_in.stack_id = stack_id;
2388 osa_op_in.operation = operation;
2389
2390 ret = switchtec_cmd(dev, MRPC_ORDERED_SET_ANALYZER, &osa_op_in,
2391 sizeof(osa_op_in), NULL, 0);
2392 }
2393 if (ret) {
2394 switchtec_perror("OSA operation");
2395 return ret;
2396 }
2397 printf("Successful %s operation!\n", valid_ops[operation]);
2398
2399 return ret;
2400}
2401
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:1324
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:1027
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:709
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:659
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:1144
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:1294
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:1604
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:568
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:1837
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:242
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:352
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:1230
int switchtec_diag_pattern_inject(struct switchtec_dev *dev, int port_id, unsigned int err_cnt)
Inject error into pattern generator.
Definition diag.c:748
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:775
int switchtec_diag_refclk_ctl(struct switchtec_dev *dev, int stack_id, bool en)
Control the refclk output for a stack.
Definition diag.c:1406
int switchtec_diag_perm_table(struct switchtec_dev *dev, struct switchtec_mrpc table[MRPC_MAX_ID])
Get the permission table.
Definition diag.c:1369
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:1466
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:1896
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:1724
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:1938
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:1786
int switchtec_diag_loopback_set(struct switchtec_dev *dev, int port_id, int enable, int enable_parallel, int enable_external, int enable_ltssm, enum switchtec_diag_ltssm_speed ltssm_speed)
Setup Loopback Mode.
Definition diag.c:534
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:1171
int switchtec_diag_eye_cancel(struct switchtec_dev *dev)
Cancel in-progress eye capture.
Definition diag.c:412
int switchtec_diag_refclk_status(struct switchtec_dev *dev, uint8_t *stack_info)
Get the status of all stacks of the refclk.
Definition diag.c:1422
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:635
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:1002
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:1814
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:221
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
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:830
int switchtec_inject_err_cto(struct switchtec_dev *dev, int phys_port_id)
Inject Credit Timeout error into a physical port.
Definition diag.c:1960
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:1917
int switchtec_diag_ltssm_clear(struct switchtec_dev *dev, int port)
Call the LTSSM clear MRPC command.
Definition diag.c:1741
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:1084
int switchtec_diag_pattern_mon_set(struct switchtec_dev *dev, int port_id, enum switchtec_diag_pattern type)
Setup Pattern Monitor.
Definition diag.c:688
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:936
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)
Start a PCIe Eye Capture.
Definition diag.c:282
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:743
Definition utils.h:34
Main Switchtec header.
@ LANE_EQ_DUMP_TYPE_PREV
Previous link-up settings.
Definition switchtec.h:1305
@ LANE_EQ_DUMP_TYPE_CURR
Current settings.
Definition switchtec.h:1304
static const float switchtec_gen_transfers[]
Number of GT/s capable for each PCI generation or link_rate.
Definition switchtec.h:671
static int switchtec_is_gen4(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 4 device.
Definition switchtec.h:469
static int switchtec_is_gen5(struct switchtec_dev *dev)
Return whether a Switchtec device is a Gen 5 device.
Definition switchtec.h:477