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;
130static int switchtec_diag_eye_status(
int status)
146static 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));
222static 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);
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.
int switchtec_diag_cross_hair_disable(struct switchtec_dev *dev)
Disable active cross hair.
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.
int switchtec_diag_pattern_gen_get(struct switchtec_dev *dev, int port_id, enum switchtec_diag_pattern *type)
Get Pattern Generator set on port.
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.
int switchtec_diag_loopback_set(struct switchtec_dev *dev, int port_id, int enable, enum switchtec_diag_ltssm_speed ltssm_speed)
Setup Loopback Mode.
int switchtec_diag_loopback_get(struct switchtec_dev *dev, int port_id, int *enabled, enum switchtec_diag_ltssm_speed *ltssm_speed)
Setup Loopback Mode.
int switchtec_diag_eye_fetch(struct switchtec_dev *dev, double *pixels, size_t pixel_cnt, int *lane_id)
Start a PCIe Eye Capture.
int switchtec_diag_pattern_inject(struct switchtec_dev *dev, int port_id, unsigned int err_cnt)
Inject error into pattern generator.
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.
int switchtec_diag_refclk_ctl(struct switchtec_dev *dev, int stack_id, bool en)
Control the refclk output for a stack.
int switchtec_diag_perm_table(struct switchtec_dev *dev, struct switchtec_mrpc table[MRPC_MAX_ID])
Get the permission table.
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.
int switchtec_diag_cross_hair_enable(struct switchtec_dev *dev, int lane_id)
Enable cross hair on specified lane.
int switchtec_diag_eye_cancel(struct switchtec_dev *dev)
Cancel in-progress eye capture.
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.
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.
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.
int switchtec_diag_pattern_mon_set(struct switchtec_dev *dev, int port_id, enum switchtec_diag_pattern type)
Setup Pattern Monitor.
int switchtec_diag_pattern_gen_set(struct switchtec_dev *dev, int port_id, enum switchtec_diag_pattern type)
Setup Pattern Generator.
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.
static const float switchtec_gen_transfers[]
Number of GT/s capable for each PCI generation or link_rate.