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
30#define SWITCHTEC_LIB_CORE
31
32#include "switchtec_priv.h"
33#include "switchtec/diag.h"
34#include "switchtec/endian.h"
35#include "switchtec/switchtec.h"
36#include "switchtec/utils.h"
37
38#include <errno.h>
39#include <math.h>
40#include <string.h>
41#include <strings.h>
42#include <unistd.h>
43
52int switchtec_diag_cross_hair_enable(struct switchtec_dev *dev, int lane_id)
53{
55 .sub_cmd = MRPC_CROSS_HAIR_ENABLE,
56 .lane_id = lane_id,
57 .all_lanes = lane_id == SWITCHTEC_DIAG_CROSS_HAIR_ALL_LANES,
58 };
59
60 return switchtec_cmd(dev, MRPC_CROSS_HAIR, &in, sizeof(in), NULL, 0);
61}
62
69int switchtec_diag_cross_hair_disable(struct switchtec_dev *dev)
70{
72 .sub_cmd = MRPC_CROSS_HAIR_DISABLE,
73 };
74
75 return switchtec_cmd(dev, MRPC_CROSS_HAIR, &in, sizeof(in), NULL, 0);
76}
77
87int switchtec_diag_cross_hair_get(struct switchtec_dev *dev, int start_lane_id,
88 int num_lanes, struct switchtec_diag_cross_hair *res)
89{
91 .sub_cmd = MRPC_CROSS_HAIR_GET,
92 .lane_id = start_lane_id,
93 .num_lanes = num_lanes,
94 };
95 struct switchtec_diag_cross_hair_get out[num_lanes];
96 int i, ret;
97
98 ret = switchtec_cmd(dev, MRPC_CROSS_HAIR, &in, sizeof(in), &out,
99 sizeof(out));
100 if (ret)
101 return ret;
102
103 for (i = 0; i < num_lanes; i++) {
104 memset(&res[i], 0, sizeof(res[i]));
105 res[i].state = out[i].state;
106 res[i].lane_id = out[i].lane_id;
107
108 if (out[i].state <= SWITCHTEC_DIAG_CROSS_HAIR_WAITING) {
109 continue;
110 } else if (out[i].state < SWITCHTEC_DIAG_CROSS_HAIR_DONE) {
111 res[i].x_pos = out[i].x_pos;
112 res[i].y_pos = out[i].y_pos;
113 } else if (out[i].state == SWITCHTEC_DIAG_CROSS_HAIR_DONE) {
114 res[i].eye_left_lim = out[i].eye_left_lim;
115 res[i].eye_right_lim = out[i].eye_right_lim;
116 res[i].eye_bot_left_lim = out[i].eye_bot_left_lim;
117 res[i].eye_bot_right_lim = out[i].eye_bot_right_lim;
118 res[i].eye_top_left_lim = out[i].eye_top_left_lim;
119 res[i].eye_top_right_lim = out[i].eye_top_right_lim;
120 } else if (out[i].state == SWITCHTEC_DIAG_CROSS_HAIR_ERROR) {
121 res[i].x_pos = out[i].x_pos;
122 res[i].y_pos = out[i].y_pos;
123 res[i].prev_state = out[i].prev_state;
124 }
125 }
126
127 return 0;
128}
129
130static int switchtec_diag_eye_status(int status)
131{
132 switch (status) {
133 case 0: return 0;
134 case 2:
135 errno = EINVAL;
136 return -1;
137 case 3:
138 errno = EBUSY;
139 return -1;
140 default:
141 errno = EPROTO;
142 return -1;
143 }
144}
145
146static int switchtec_diag_eye_cmd(struct switchtec_dev *dev, void *in,
147 size_t size)
148{
150 int ret;
151
152 ret = switchtec_cmd(dev, MRPC_EYE_OBSERVE, in, size, &out,
153 sizeof(out));
154
155 if (ret)
156 return ret;
157
158 return switchtec_diag_eye_status(out.status);
159}
160
168int switchtec_diag_eye_set_mode(struct switchtec_dev *dev,
169 enum switchtec_diag_eye_data_mode mode)
170{
171 struct switchtec_diag_port_eye_cmd in = {
172 .sub_cmd = MRPC_EYE_OBSERVE_SET_DATA_MODE,
173 .data_mode = mode,
174 };
175
176 return switchtec_diag_eye_cmd(dev, &in, sizeof(in));
177}
178
191int switchtec_diag_eye_start(struct switchtec_dev *dev, int lane_mask[4],
192 struct range *x_range, struct range *y_range,
193 int step_interval)
194{
195 int err;
196 int ret;
198 .sub_cmd = MRPC_EYE_OBSERVE_START,
199 .lane_mask[0] = lane_mask[0],
200 .lane_mask[1] = lane_mask[1],
201 .lane_mask[2] = lane_mask[2],
202 .lane_mask[3] = lane_mask[3],
203 .x_start = x_range->start,
204 .y_start = y_range->start,
205 .x_end = x_range->end,
206 .y_end = y_range->end,
207 .x_step = x_range->step,
208 .y_step = y_range->step,
209 .step_interval = step_interval,
210 };
211
212 ret = switchtec_diag_eye_cmd(dev, &in, sizeof(in));
213
214 /* Add delay so hardware has enough time to start */
215 err = errno;
216 usleep(200000);
217 errno = err;
218
219 return ret;
220}
221
222static uint64_t hi_lo_to_uint64(uint32_t lo, uint32_t hi)
223{
224 uint64_t ret;
225
226 ret = le32toh(hi);
227 ret <<= 32;
228 ret |= le32toh(lo);
229
230 return ret;
231}
232
246int switchtec_diag_eye_fetch(struct switchtec_dev *dev, double *pixels,
247 size_t pixel_cnt, int *lane_id)
248{
249 struct switchtec_diag_port_eye_cmd in = {
250 .sub_cmd = MRPC_EYE_OBSERVE_FETCH,
251 };
253 uint64_t samples, errors;
254 int i, ret, data_count;
255
256retry:
257 ret = switchtec_cmd(dev, MRPC_EYE_OBSERVE, &in, sizeof(in), &out,
258 sizeof(out));
259 if (ret)
260 return ret;
261
262 if (out.status == 1) {
263 usleep(5000);
264 goto retry;
265 }
266
267 ret = switchtec_diag_eye_status(out.status);
268 if (ret)
269 return ret;
270
271 for (i = 0; i < 4; i++) {
272 *lane_id = ffs(out.lane_mask[i]);
273 if (*lane_id)
274 break;
275 }
276
277 data_count = out.data_count_lo | ((int)out.data_count_hi << 8);
278
279 for (i = 0; i < data_count && i < pixel_cnt; i++) {
280 switch (out.data_mode) {
281 case SWITCHTEC_DIAG_EYE_RAW:
282 errors = hi_lo_to_uint64(out.raw[i].error_cnt_lo,
283 out.raw[i].error_cnt_hi);
284 samples = hi_lo_to_uint64(out.raw[i].sample_cnt_lo,
285 out.raw[i].sample_cnt_hi);
286 if (samples)
287 pixels[i] = (double)errors / samples;
288 else
289 pixels[i] = nan("");
290 break;
291 case SWITCHTEC_DIAG_EYE_RATIO:
292 pixels[i] = le32toh(out.ratio[i].ratio) / 65536.;
293 break;
294 }
295 }
296
297 return data_count;
298}
299
306int switchtec_diag_eye_cancel(struct switchtec_dev *dev)
307{
308 int ret;
309 int err;
310 struct switchtec_diag_port_eye_cmd in = {
311 .sub_cmd = MRPC_EYE_OBSERVE_CANCEL,
312 };
313
314 ret = switchtec_diag_eye_cmd(dev, &in, sizeof(in));
315
316 /* Add delay so hardware can stop completely */
317 err = errno;
318 usleep(200000);
319 errno = err;
320
321 return ret;
322}
323
334int switchtec_diag_loopback_set(struct switchtec_dev *dev, int port_id,
335 int enable, enum switchtec_diag_ltssm_speed ltssm_speed)
336{
337 struct switchtec_diag_loopback_in int_in = {
338 .sub_cmd = MRPC_LOOPBACK_SET_INT_LOOPBACK,
339 .port_id = port_id,
340 .enable = enable,
341 };
342 struct switchtec_diag_loopback_ltssm_in ltssm_in = {
343 .sub_cmd = MRPC_LOOPBACK_SET_LTSSM_LOOPBACK,
344 .port_id = port_id,
345 .enable = !!(enable & SWITCHTEC_DIAG_LOOPBACK_LTSSM),
346 .speed = ltssm_speed,
347 };
348 int ret;
349
350 int_in.type = DIAG_LOOPBACK_RX_TO_TX;
351 int_in.enable = !!(enable & SWITCHTEC_DIAG_LOOPBACK_RX_TO_TX);
352
353 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &int_in,
354 sizeof(int_in), NULL, 0);
355 if (ret)
356 return ret;
357
358 int_in.type = DIAG_LOOPBACK_TX_TO_RX;
359 int_in.enable = !!(enable & SWITCHTEC_DIAG_LOOPBACK_TX_TO_RX);
360
361 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &int_in,
362 sizeof(int_in), NULL, 0);
363 if (ret)
364 return ret;
365
366 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &ltssm_in,
367 sizeof(ltssm_in), NULL, 0);
368 if (ret)
369 return ret;
370
371 return 0;
372}
373
384int switchtec_diag_loopback_get(struct switchtec_dev *dev, int port_id,
385 int *enabled, enum switchtec_diag_ltssm_speed *ltssm_speed)
386{
387 struct switchtec_diag_loopback_in int_in = {
388 .sub_cmd = MRPC_LOOPBACK_GET_INT_LOOPBACK,
389 .port_id = port_id,
390 .type = DIAG_LOOPBACK_RX_TO_TX,
391 };
392 struct switchtec_diag_loopback_ltssm_in lt_in = {
393 .sub_cmd = MRPC_LOOPBACK_GET_LTSSM_LOOPBACK,
394 .port_id = port_id,
395 };
396 struct switchtec_diag_loopback_out int_out;
398 int ret, en = 0;
399
400 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &int_in, sizeof(int_in),
401 &int_out, sizeof(int_out));
402 if (ret)
403 return ret;
404
405 if (int_out.enabled)
406 en |= SWITCHTEC_DIAG_LOOPBACK_RX_TO_TX;
407
408 int_in.type = DIAG_LOOPBACK_TX_TO_RX;
409 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &int_in, sizeof(int_in),
410 &int_out, sizeof(int_out));
411 if (ret)
412 return ret;
413
414 if (int_out.enabled)
415 en |= SWITCHTEC_DIAG_LOOPBACK_TX_TO_RX;
416
417 ret = switchtec_cmd(dev, MRPC_INT_LOOPBACK, &lt_in, sizeof(lt_in),
418 &lt_out, sizeof(lt_out));
419 if (ret)
420 return ret;
421
422 if (lt_out.enabled)
423 en |= SWITCHTEC_DIAG_LOOPBACK_LTSSM;
424
425 if (enabled)
426 *enabled = en;
427
428 if (ltssm_speed)
429 *ltssm_speed = lt_out.speed;
430
431 return 0;
432}
433
442int switchtec_diag_pattern_gen_set(struct switchtec_dev *dev, int port_id,
443 enum switchtec_diag_pattern type)
444{
445 struct switchtec_diag_pat_gen_in in = {
446 .sub_cmd = MRPC_PAT_GEN_SET_GEN,
447 .port_id = port_id,
448 .pattern_type = type,
449 };
450
451 return switchtec_cmd(dev, MRPC_PAT_GEN, &in, sizeof(in), NULL, 0);
452}
453
462int switchtec_diag_pattern_gen_get(struct switchtec_dev *dev, int port_id,
463 enum switchtec_diag_pattern *type)
464{
465 struct switchtec_diag_pat_gen_in in = {
466 .sub_cmd = MRPC_PAT_GEN_GET_GEN,
467 .port_id = port_id,
468 };
470 int ret;
471
472 ret = switchtec_cmd(dev, MRPC_PAT_GEN, &in, sizeof(in), &out,
473 sizeof(out));
474 if (ret)
475 return ret;
476
477 if (type)
478 *type = out.pattern_type;
479
480 return 0;
481}
482
491int switchtec_diag_pattern_mon_set(struct switchtec_dev *dev, int port_id,
492 enum switchtec_diag_pattern type)
493{
494 struct switchtec_diag_pat_gen_in in = {
495 .sub_cmd = MRPC_PAT_GEN_SET_MON,
496 .port_id = port_id,
497 .pattern_type = type,
498 };
499
500 return switchtec_cmd(dev, MRPC_PAT_GEN, &in, sizeof(in), NULL, 0);
501}
502
512int switchtec_diag_pattern_mon_get(struct switchtec_dev *dev, int port_id,
513 int lane_id, enum switchtec_diag_pattern *type,
514 unsigned long long *err_cnt)
515{
516 struct switchtec_diag_pat_gen_in in = {
517 .sub_cmd = MRPC_PAT_GEN_GET_MON,
518 .port_id = port_id,
519 .lane_id = lane_id,
520 };
522 int ret;
523
524 ret = switchtec_cmd(dev, MRPC_PAT_GEN, &in, sizeof(in), &out,
525 sizeof(out));
526 if (ret)
527 return ret;
528
529 if (type)
530 *type = out.pattern_type;
531
532 if (err_cnt)
533 *err_cnt = (htole32(out.err_cnt_lo) |
534 ((uint64_t)htole32(out.err_cnt_hi) << 32));
535
536 return 0;
537}
538
551int switchtec_diag_pattern_inject(struct switchtec_dev *dev, int port_id,
552 unsigned int err_cnt)
553{
555 .sub_cmd = MRPC_PAT_GEN_INJ_ERR,
556 .port_id = port_id,
557 .err_cnt = err_cnt,
558 };
559 int ret;
560
561 ret = switchtec_cmd(dev, MRPC_PAT_GEN, &in, sizeof(in), NULL, 0);
562 if (ret)
563 return ret;
564
565 return 0;
566}
567
578int switchtec_diag_rcvr_obj(struct switchtec_dev *dev, int port_id,
579 int lane_id, enum switchtec_diag_link link,
580 struct switchtec_rcvr_obj *res)
581{
582 struct switchtec_diag_rcvr_obj_dump_out out = {};
584 .port_id = port_id,
585 .lane_id = lane_id,
586 };
588 .sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_PREV,
589 .port_id = port_id,
590 .lane_id = lane_id,
591 };
592 int i, ret;
593
594 if (!res) {
595 errno = -EINVAL;
596 return -1;
597 }
598
599 if (link == SWITCHTEC_DIAG_LINK_CURRENT) {
600 ret = switchtec_cmd(dev, MRPC_RCVR_OBJ_DUMP, &in, sizeof(in),
601 &out, sizeof(out));
602 } else if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
603 ret = switchtec_cmd(dev, MRPC_EXT_RCVR_OBJ_DUMP, &ext_in,
604 sizeof(ext_in), &out, sizeof(out));
605 } else {
606 errno = -EINVAL;
607 return -1;
608 }
609
610 if (ret)
611 return -1;
612
613 res->port_id = out.port_id;
614 res->lane_id = out.lane_id;
615 res->ctle = out.ctle;
616 res->target_amplitude = out.target_amplitude;
617 res->speculative_dfe = out.speculative_dfe;
618 for (i = 0; i < ARRAY_SIZE(res->dynamic_dfe); i++)
619 res->dynamic_dfe[i] = out.dynamic_dfe[i];
620
621 return 0;
622}
623
633int switchtec_diag_port_eq_tx_coeff(struct switchtec_dev *dev, int port_id,
634 enum switchtec_diag_end end, enum switchtec_diag_link link,
635 struct switchtec_port_eq_coeff *res)
636{
637 struct switchtec_diag_port_eq_status_out out = {};
639 .op_type = DIAG_PORT_EQ_STATUS_OP_PER_PORT,
640 .port_id = port_id,
641 };
643 .op_type = DIAG_PORT_EQ_STATUS_OP_PER_PORT,
644 .port_id = port_id,
645 };
646 int ret, i;
647
648 if (!res) {
649 errno = -EINVAL;
650 return -1;
651 }
652
653 if (end == SWITCHTEC_DIAG_LOCAL) {
654 in.sub_cmd = MRPC_PORT_EQ_LOCAL_TX_COEFF_DUMP;
655 in_prev.sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_LOCAL_TX_COEFF_PREV;
656 } else if (end == SWITCHTEC_DIAG_FAR_END) {
657 in.sub_cmd = MRPC_PORT_EQ_FAR_END_TX_COEFF_DUMP;
658 in_prev.sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_FAR_END_TX_COEFF_PREV;
659 } else {
660 errno = -EINVAL;
661 return -1;
662 }
663
664 if (link == SWITCHTEC_DIAG_LINK_CURRENT) {
665 ret = switchtec_cmd(dev, MRPC_PORT_EQ_STATUS, &in, sizeof(in),
666 &out, sizeof(out));
667 } else if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
668 ret = switchtec_cmd(dev, MRPC_EXT_RCVR_OBJ_DUMP, &in_prev,
669 sizeof(in_prev), &out, sizeof(out));
670 } else {
671 errno = -EINVAL;
672 return -1;
673 }
674
675 if (ret)
676 return -1;
677
678 res->lane_cnt = out.lane_id + 1;
679 for (i = 0; i < res->lane_cnt; i++) {
680 res->cursors[i].pre = out.cursors[i].pre;
681 res->cursors[i].post = out.cursors[i].post;
682 }
683
684 return 0;
685}
686
695int switchtec_diag_port_eq_tx_table(struct switchtec_dev *dev, int port_id,
696 enum switchtec_diag_link link,
697 struct switchtec_port_eq_table *res)
698{
699 struct switchtec_diag_port_eq_table_out out = {};
701 .sub_cmd = MRPC_PORT_EQ_FAR_END_TX_EQ_TABLE_DUMP,
702 .port_id = port_id,
703 };
704 struct switchtec_diag_port_eq_status_in2 in_prev = {
705 .sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_EQ_TX_TABLE_PREV,
706 .port_id = port_id,
707 };
708 int ret, i;
709
710 if (!res) {
711 errno = -EINVAL;
712 return -1;
713 }
714
715 if (link == SWITCHTEC_DIAG_LINK_CURRENT) {
716 ret = switchtec_cmd(dev, MRPC_PORT_EQ_STATUS, &in, sizeof(in),
717 &out, sizeof(out));
718 } else if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
719 ret = switchtec_cmd(dev, MRPC_EXT_RCVR_OBJ_DUMP, &in_prev,
720 sizeof(in_prev), &out, sizeof(out));
721 } else {
722 errno = -EINVAL;
723 return -1;
724 }
725
726 if (ret)
727 return -1;
728
729 res->lane_id = out.lane_id;
730 res->step_cnt = out.step_cnt;
731 for (i = 0; i < res->step_cnt; i++) {
732 res->steps[i].pre_cursor = out.steps[i].pre_cursor;
733 res->steps[i].post_cursor = out.steps[i].post_cursor;
734 res->steps[i].fom = out.steps[i].fom;
735 res->steps[i].pre_cursor_up = out.steps[i].pre_cursor_up;
736 res->steps[i].post_cursor_up = out.steps[i].post_cursor_up;
737 res->steps[i].error_status = out.steps[i].error_status;
738 res->steps[i].active_status = out.steps[i].active_status;
739 res->steps[i].speed = out.steps[i].speed;
740 }
741
742 return 0;
743}
744
755int switchtec_diag_port_eq_tx_fslf(struct switchtec_dev *dev, int port_id,
756 int lane_id, enum switchtec_diag_end end,
757 enum switchtec_diag_link link,
758 struct switchtec_port_eq_tx_fslf *res)
759{
762 .port_id = port_id,
763 .lane_id = lane_id,
764 };
765 struct switchtec_diag_ext_recv_obj_dump_in in_prev = {
766 .port_id = port_id,
767 .lane_id = lane_id,
768 };
769 int ret;
770
771 if (!res) {
772 errno = -EINVAL;
773 return -1;
774 }
775
776 if (end == SWITCHTEC_DIAG_LOCAL) {
777 in.sub_cmd = MRPC_PORT_EQ_LOCAL_TX_FSLF_DUMP;
778 in_prev.sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_LOCAL_TX_FSLF_PREV;
779 } else if (end == SWITCHTEC_DIAG_FAR_END) {
780 in.sub_cmd = MRPC_PORT_EQ_FAR_END_TX_FSLF_DUMP;
781 in_prev.sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_FAR_END_TX_FSLF_PREV;
782 } else {
783 errno = -EINVAL;
784 return -1;
785 }
786
787 if (link == SWITCHTEC_DIAG_LINK_CURRENT) {
788 ret = switchtec_cmd(dev, MRPC_PORT_EQ_STATUS, &in, sizeof(in),
789 &out, sizeof(out));
790 } else if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
791 ret = switchtec_cmd(dev, MRPC_EXT_RCVR_OBJ_DUMP, &in_prev,
792 sizeof(in_prev), &out, sizeof(out));
793 } else {
794 errno = -EINVAL;
795 return -1;
796 }
797
798 if (ret)
799 return -1;
800
801 res->fs = out.fs;
802 res->lf = out.lf;
803
804 return 0;
805}
806
817int switchtec_diag_rcvr_ext(struct switchtec_dev *dev, int port_id,
818 int lane_id, enum switchtec_diag_link link,
819 struct switchtec_rcvr_ext *res)
820{
821 struct switchtec_diag_rcvr_ext_out out = {};
823 .port_id = port_id,
824 .lane_id = lane_id,
825 };
826 int ret;
827
828 if (!res) {
829 errno = -EINVAL;
830 return -1;
831 }
832
833 if (link == SWITCHTEC_DIAG_LINK_CURRENT) {
834 in.sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_RCVR_EXT;
835 } else if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
836 in.sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_RCVR_EXT_PREV;
837 } else {
838 errno = -EINVAL;
839 return -1;
840 }
841
842 ret = switchtec_cmd(dev, MRPC_EXT_RCVR_OBJ_DUMP, &in, sizeof(in),
843 &out, sizeof(out));
844 if (ret)
845 return -1;
846
847 res->ctle2_rx_mode = out.ctle2_rx_mode;
848 res->dtclk_9 = out.dtclk_9;
849 res->dtclk_8_6 = out.dtclk_8_6;
850 res->dtclk_5 = out.dtclk_5;
851
852 return 0;
853}
854
862int switchtec_diag_perm_table(struct switchtec_dev *dev,
863 struct switchtec_mrpc table[MRPC_MAX_ID])
864{
865 uint32_t perms[(MRPC_MAX_ID + 31) / 32];
866 int i, ret;
867
868 ret = switchtec_cmd(dev, MRPC_MRPC_PERM_TABLE_GET, NULL, 0,
869 perms, sizeof(perms));
870 if (ret)
871 return -1;
872
873 for (i = 0; i < MRPC_MAX_ID; i++) {
874 if (perms[i >> 5] & (1 << (i & 0x1f))) {
875 if (switchtec_mrpc_table[i].tag) {
876 table[i] = switchtec_mrpc_table[i];
877 } else {
878 table[i].tag = "UNKNOWN";
879 table[i].desc = "Unknown MRPC Command";
880 table[i].reserved = true;
881 }
882 } else {
883 table[i].tag = NULL;
884 table[i].desc = NULL;
885 }
886 }
887
888 return 0;
889}
890
899int switchtec_diag_refclk_ctl(struct switchtec_dev *dev, int stack_id, bool en)
900{
901 struct switchtec_diag_refclk_ctl_in cmd = {
902 .sub_cmd = en ? MRPC_REFCLK_S_ENABLE : MRPC_REFCLK_S_DISABLE,
903 .stack_id = stack_id,
904 };
905
906 return switchtec_cmd(dev, MRPC_REFCLK_S, &cmd, sizeof(cmd), NULL, 0);
907}
908
917int switchtec_diag_ltssm_log(struct switchtec_dev *dev,
918 int port, int *log_count,
919 struct switchtec_diag_ltssm_log *log_data)
920{
921 struct {
922 uint8_t sub_cmd;
923 uint8_t port;
924 uint8_t freeze;
925 uint8_t unused;
926 } ltssm_freeze;
927
928 struct {
929 uint8_t sub_cmd;
930 uint8_t port;
931 } status;
932 struct {
933 uint32_t w0_trigger_count;
934 uint32_t w1_trigger_count;
935 uint8_t log_num;
936 } status_output;
937
938 struct {
939 uint8_t sub_cmd;
940 uint8_t port;
941 uint8_t log_index;
942 uint8_t no_of_logs;
943 } log_dump;
944 struct {
945 uint32_t dw0;
946 uint32_t dw1;
947 } log_dump_out[256];
948
949 uint32_t dw1;
950 uint32_t dw0;
951 int major;
952 int minor;
953 int rate;
954 int ret;
955 int i;
956
957 /* freeze logs */
958 ltssm_freeze.sub_cmd = 14;
959 ltssm_freeze.port = port;
960 ltssm_freeze.freeze = 1;
961
962 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &ltssm_freeze,
963 sizeof(ltssm_freeze), NULL, 0);
964 if (ret)
965 return ret;
966
967 /* get number of entries */
968 status.sub_cmd = 13;
969 status.port = port;
970 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &status,
971 sizeof(status), &status_output,
972 sizeof(status_output));
973 if (ret)
974 return ret;
975
976 if (status_output.log_num < *log_count)
977 *log_count = status_output.log_num;
978
979 /* get log data */
980 log_dump.sub_cmd = 15;
981 log_dump.port = port;
982 log_dump.log_index = 0;
983 log_dump.no_of_logs = *log_count;
984 if(log_dump.no_of_logs <= 126) {
985 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &log_dump,
986 sizeof(log_dump), log_dump_out,
987 8 * log_dump.no_of_logs);
988 if (ret)
989 return ret;
990 } else {
991 log_dump.no_of_logs = 126;
992 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &log_dump,
993 sizeof(log_dump), log_dump_out,
994 8 * log_dump.no_of_logs);
995 if (ret)
996 return ret;
997
998 log_dump.log_index = 126;
999 log_dump.no_of_logs = *log_count - 126;
1000
1001 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &log_dump,
1002 sizeof(log_dump), log_dump_out + 126,
1003 8 * log_dump.no_of_logs);
1004 if (ret)
1005 return ret;
1006 }
1007 for (i = 0; i < *log_count; i++) {
1008 dw1 = log_dump_out[i].dw1;
1009 dw0 = log_dump_out[i].dw0;
1010 rate = (dw0 >> 13) & 0x3;
1011 major = (dw0 >> 7) & 0xf;
1012 minor = (dw0 >> 3) & 0xf;
1013
1014 log_data[i].timestamp = dw1 & 0x3ffffff;
1015 log_data[i].link_rate = switchtec_gen_transfers[rate + 1];
1016 log_data[i].link_state = major | (minor << 8);
1017 }
1018
1019 /* unfreeze logs */
1020 ltssm_freeze.sub_cmd = 14;
1021 ltssm_freeze.port = port;
1022 ltssm_freeze.freeze = 0;
1023
1024 ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &ltssm_freeze,
1025 sizeof(ltssm_freeze), NULL, 0);
1026
1027 return ret;
1028}
1029
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:817
int switchtec_diag_cross_hair_disable(struct switchtec_dev *dev)
Disable active cross hair.
Definition diag.c:69
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:512
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:462
int switchtec_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 far end TX equalization table.
Definition diag.c:695
int switchtec_diag_loopback_set(struct switchtec_dev *dev, int port_id, int enable, enum switchtec_diag_ltssm_speed ltssm_speed)
Setup Loopback Mode.
Definition diag.c:334
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:384
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:246
int switchtec_diag_pattern_inject(struct switchtec_dev *dev, int port_id, unsigned int err_cnt)
Inject error into pattern generator.
Definition diag.c:551
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:578
int switchtec_diag_refclk_ctl(struct switchtec_dev *dev, int stack_id, bool en)
Control the refclk output for a stack.
Definition diag.c:899
int switchtec_diag_perm_table(struct switchtec_dev *dev, struct switchtec_mrpc table[MRPC_MAX_ID])
Get the permission table.
Definition diag.c:862
int switchtec_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 port equalization TX coefficients.
Definition diag.c:633
int switchtec_diag_cross_hair_enable(struct switchtec_dev *dev, int lane_id)
Enable cross hair on specified lane.
Definition diag.c:52
int switchtec_diag_eye_cancel(struct switchtec_dev *dev)
Cancel in-progress eye capture.
Definition diag.c:306
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:168
int switchtec_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 equalization FS/LF.
Definition diag.c:755
int switchtec_diag_eye_start(struct switchtec_dev *dev, int lane_mask[4], struct range *x_range, struct range *y_range, int step_interval)
Start a PCIe Eye Capture.
Definition diag.c:191
int switchtec_diag_pattern_mon_set(struct switchtec_dev *dev, int port_id, enum switchtec_diag_pattern type)
Setup Pattern Monitor.
Definition diag.c:491
int switchtec_diag_pattern_gen_set(struct switchtec_dev *dev, int port_id, enum switchtec_diag_pattern type)
Setup Pattern Generator.
Definition diag.c:442
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:164
Definition utils.h:34
Main Switchtec header.
static const float switchtec_gen_transfers[]
Number of GT/s capable for each PCI generation or link_rate.
Definition switchtec.h:635