30 #define SWITCHTEC_LIB_CORE
32 #include "switchtec_priv.h"
34 #include "switchtec/endian.h"
36 #include "switchtec/utils.h"
55 .sub_cmd = MRPC_CROSS_HAIR_ENABLE,
57 .all_lanes = lane_id == SWITCHTEC_DIAG_CROSS_HAIR_ALL_LANES,
60 return switchtec_cmd(dev, MRPC_CROSS_HAIR, &in,
sizeof(in), NULL, 0);
72 .sub_cmd = MRPC_CROSS_HAIR_DISABLE,
75 return switchtec_cmd(dev, MRPC_CROSS_HAIR, &in,
sizeof(in), NULL, 0);
91 .sub_cmd = MRPC_CROSS_HAIR_GET,
92 .lane_id = start_lane_id,
93 .num_lanes = num_lanes,
98 ret =
switchtec_cmd(dev, MRPC_CROSS_HAIR, &in,
sizeof(in), &out,
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;
108 if (out[i].state <= SWITCHTEC_DIAG_CROSS_HAIR_WAITING) {
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;
130 static int switchtec_diag_eye_status(
int status)
146 static int switchtec_diag_eye_cmd(
struct switchtec_dev *dev,
void *in,
158 return switchtec_diag_eye_status(out.status);
169 enum switchtec_diag_eye_data_mode mode)
172 .sub_cmd = MRPC_EYE_OBSERVE_SET_DATA_MODE,
176 return switchtec_diag_eye_cmd(dev, &in,
sizeof(in));
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,
212 ret = switchtec_diag_eye_cmd(dev, &in,
sizeof(in));
222 static uint64_t hi_lo_to_uint64(uint32_t lo, uint32_t hi)
247 size_t pixel_cnt,
int *lane_id)
250 .sub_cmd = MRPC_EYE_OBSERVE_FETCH,
253 uint64_t samples, errors;
254 int i, ret, data_count;
257 ret =
switchtec_cmd(dev, MRPC_EYE_OBSERVE, &in,
sizeof(in), &out,
262 if (out.status == 1) {
267 ret = switchtec_diag_eye_status(out.status);
271 for (i = 0; i < 4; i++) {
272 *lane_id = ffs(out.lane_mask[i]);
277 data_count = out.data_count_lo | ((int)out.data_count_hi << 8);
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);
287 pixels[i] = (double)errors / samples;
291 case SWITCHTEC_DIAG_EYE_RATIO:
292 pixels[i] = le32toh(out.ratio[i].ratio) / 65536.;
311 .sub_cmd = MRPC_EYE_OBSERVE_CANCEL,
314 ret = switchtec_diag_eye_cmd(dev, &in,
sizeof(in));
335 int enable,
enum switchtec_diag_ltssm_speed ltssm_speed)
338 .sub_cmd = MRPC_LOOPBACK_SET_INT_LOOPBACK,
343 .sub_cmd = MRPC_LOOPBACK_SET_LTSSM_LOOPBACK,
345 .enable = !!(enable & SWITCHTEC_DIAG_LOOPBACK_LTSSM),
346 .speed = ltssm_speed,
350 int_in.type = DIAG_LOOPBACK_RX_TO_TX;
351 int_in.enable = !!(enable & SWITCHTEC_DIAG_LOOPBACK_RX_TO_TX);
354 sizeof(int_in), NULL, 0);
358 int_in.type = DIAG_LOOPBACK_TX_TO_RX;
359 int_in.enable = !!(enable & SWITCHTEC_DIAG_LOOPBACK_TX_TO_RX);
362 sizeof(int_in), NULL, 0);
367 sizeof(ltssm_in), NULL, 0);
385 int *enabled,
enum switchtec_diag_ltssm_speed *ltssm_speed)
388 .sub_cmd = MRPC_LOOPBACK_GET_INT_LOOPBACK,
390 .type = DIAG_LOOPBACK_RX_TO_TX,
393 .sub_cmd = MRPC_LOOPBACK_GET_LTSSM_LOOPBACK,
400 ret =
switchtec_cmd(dev, MRPC_INT_LOOPBACK, &int_in,
sizeof(int_in),
401 &int_out,
sizeof(int_out));
406 en |= SWITCHTEC_DIAG_LOOPBACK_RX_TO_TX;
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));
415 en |= SWITCHTEC_DIAG_LOOPBACK_TX_TO_RX;
417 ret =
switchtec_cmd(dev, MRPC_INT_LOOPBACK, <_in,
sizeof(lt_in),
418 <_out,
sizeof(lt_out));
423 en |= SWITCHTEC_DIAG_LOOPBACK_LTSSM;
429 *ltssm_speed = lt_out.speed;
443 enum switchtec_diag_pattern type)
446 .sub_cmd = MRPC_PAT_GEN_SET_GEN,
448 .pattern_type = type,
451 return switchtec_cmd(dev, MRPC_PAT_GEN, &in,
sizeof(in), NULL, 0);
463 enum switchtec_diag_pattern *type)
466 .sub_cmd = MRPC_PAT_GEN_GET_GEN,
472 ret =
switchtec_cmd(dev, MRPC_PAT_GEN, &in,
sizeof(in), &out,
478 *type = out.pattern_type;
492 enum switchtec_diag_pattern type)
495 .sub_cmd = MRPC_PAT_GEN_SET_MON,
497 .pattern_type = type,
500 return switchtec_cmd(dev, MRPC_PAT_GEN, &in,
sizeof(in), NULL, 0);
513 int lane_id,
enum switchtec_diag_pattern *type,
514 unsigned long long *err_cnt)
517 .sub_cmd = MRPC_PAT_GEN_GET_MON,
524 ret =
switchtec_cmd(dev, MRPC_PAT_GEN, &in,
sizeof(in), &out,
530 *type = out.pattern_type;
533 *err_cnt = (htole32(out.err_cnt_lo) |
534 ((uint64_t)htole32(out.err_cnt_hi) << 32));
552 unsigned int err_cnt)
555 .sub_cmd = MRPC_PAT_GEN_INJ_ERR,
561 ret =
switchtec_cmd(dev, MRPC_PAT_GEN, &in,
sizeof(in), NULL, 0);
579 int lane_id,
enum switchtec_diag_link link,
588 .sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_PREV,
599 if (link == SWITCHTEC_DIAG_LINK_CURRENT) {
600 ret =
switchtec_cmd(dev, MRPC_RCVR_OBJ_DUMP, &in,
sizeof(in),
602 }
else if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
604 sizeof(ext_in), &out,
sizeof(out));
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];
634 enum switchtec_diag_end end,
enum switchtec_diag_link link,
639 .op_type = DIAG_PORT_EQ_STATUS_OP_PER_PORT,
643 .op_type = DIAG_PORT_EQ_STATUS_OP_PER_PORT,
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;
664 if (link == SWITCHTEC_DIAG_LINK_CURRENT) {
665 ret =
switchtec_cmd(dev, MRPC_PORT_EQ_STATUS, &in,
sizeof(in),
667 }
else if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
669 sizeof(in_prev), &out,
sizeof(out));
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;
696 enum switchtec_diag_link link,
701 .sub_cmd = MRPC_PORT_EQ_FAR_END_TX_EQ_TABLE_DUMP,
705 .sub_cmd = MRPC_EXT_RCVR_OBJ_DUMP_EQ_TX_TABLE_PREV,
715 if (link == SWITCHTEC_DIAG_LINK_CURRENT) {
716 ret =
switchtec_cmd(dev, MRPC_PORT_EQ_STATUS, &in,
sizeof(in),
718 }
else if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
720 sizeof(in_prev), &out,
sizeof(out));
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;
756 int lane_id,
enum switchtec_diag_end end,
757 enum switchtec_diag_link link,
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;
787 if (link == SWITCHTEC_DIAG_LINK_CURRENT) {
788 ret =
switchtec_cmd(dev, MRPC_PORT_EQ_STATUS, &in,
sizeof(in),
790 }
else if (link == SWITCHTEC_DIAG_LINK_PREVIOUS) {
792 sizeof(in_prev), &out,
sizeof(out));
818 int lane_id,
enum switchtec_diag_link link,
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;
842 ret =
switchtec_cmd(dev, MRPC_EXT_RCVR_OBJ_DUMP, &in,
sizeof(in),
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;
865 uint32_t perms[(MRPC_MAX_ID + 31) / 32];
869 perms,
sizeof(perms));
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];
878 table[i].tag =
"UNKNOWN";
879 table[i].desc =
"Unknown MRPC Command";
880 table[i].reserved =
true;
884 table[i].desc = NULL;
902 .sub_cmd = en ? MRPC_REFCLK_S_ENABLE : MRPC_REFCLK_S_DISABLE,
903 .stack_id = stack_id,
906 return switchtec_cmd(dev, MRPC_REFCLK_S, &cmd,
sizeof(cmd), NULL, 0);
918 int port,
int *log_count,
933 uint32_t w0_trigger_count;
934 uint32_t w1_trigger_count;
958 ltssm_freeze.sub_cmd = 14;
959 ltssm_freeze.port = port;
960 ltssm_freeze.freeze = 1;
962 ret =
switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, <ssm_freeze,
963 sizeof(ltssm_freeze), NULL, 0);
971 sizeof(status), &status_output,
972 sizeof(status_output));
976 if (status_output.log_num < *log_count)
977 *log_count = status_output.log_num;
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);
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);
998 log_dump.log_index = 126;
999 log_dump.no_of_logs = *log_count - 126;
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);
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;
1014 log_data[i].timestamp = dw1 & 0x3ffffff;
1016 log_data[i].link_state = major | (minor << 8);
1020 ltssm_freeze.sub_cmd = 14;
1021 ltssm_freeze.port = port;
1022 ltssm_freeze.freeze = 0;
1024 ret =
switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, <ssm_freeze,
1025 sizeof(ltssm_freeze), NULL, 0);