Velocity Userspace
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 
52 int switchtec_diag_cross_hair_enable(struct switchtec_dev *dev, int lane_id)
53 {
54  struct switchtec_diag_cross_hair_in in = {
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 
69 int switchtec_diag_cross_hair_disable(struct switchtec_dev *dev)
70 {
71  struct switchtec_diag_cross_hair_in in = {
72  .sub_cmd = MRPC_CROSS_HAIR_DISABLE,
73  };
74 
75  return switchtec_cmd(dev, MRPC_CROSS_HAIR, &in, sizeof(in), NULL, 0);
76 }
77 
87 int switchtec_diag_cross_hair_get(struct switchtec_dev *dev, int start_lane_id,
88  int num_lanes, struct switchtec_diag_cross_hair *res)
89 {
90  struct switchtec_diag_cross_hair_in in = {
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 
130 static 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 
146 static int switchtec_diag_eye_cmd(struct switchtec_dev *dev, void *in,
147  size_t size)
148 {
149  struct switchtec_diag_port_eye_cmd out;
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 
168 int 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 
191 int 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;
197  struct switchtec_diag_port_eye_start 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,
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 
222 static 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 
246 int 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 
256 retry:
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 
306 int 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 
334 int 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 
384 int 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;
397  struct switchtec_diag_loopback_ltssm_out lt_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 
442 int 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 
462 int 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  };
469  struct switchtec_diag_pat_gen_out out;
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 
491 int 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 
512 int 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  };
521  struct switchtec_diag_pat_gen_out out;
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 
551 int switchtec_diag_pattern_inject(struct switchtec_dev *dev, int port_id,
552  unsigned int err_cnt)
553 {
554  struct switchtec_diag_pat_gen_inject in = {
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 
578 int 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 = {};
583  struct switchtec_diag_rcvr_obj_dump_in in = {
584  .port_id = port_id,
585  .lane_id = lane_id,
586  };
587  struct switchtec_diag_ext_recv_obj_dump_in ext_in = {
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 
633 int 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  };
642  struct switchtec_diag_ext_dump_coeff_prev_in in_prev = {
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 
695 int 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 
755 int 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 {
760  struct switchtec_diag_port_eq_tx_fslf_out out = {};
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 
817 int 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 
862 int 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 
899 int 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 
917 int 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 
switchtec_diag_rcvr_ext_out
Definition: diag.h:121
switchtec_rcvr_obj
Definition: switchtec.h:1142
switchtec.h
Main Switchtec header.
switchtec_diag_loopback_out
Definition: diag.h:147
switchtec_diag_rcvr_ext
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
switchtec_diag_port_eq_tx_fslf_out
Definition: diag.h:98
switchtec_port_eq_coeff
Definition: switchtec.h:1151
diag.h
Diagnostic structures.
switchtec_rcvr_ext
Definition: switchtec.h:1180
switchtec_diag_pattern_inject
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
switchtec_diag_port_eq_tx_coeff
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
switchtec_diag_loopback_get
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
switchtec_diag_port_eq_table_out
Definition: diag.h:81
switchtec_diag_cross_hair_get
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:87
switchtec_diag_perm_table
int switchtec_diag_perm_table(struct switchtec_dev *dev, struct switchtec_mrpc table[MRPC_MAX_ID])
Get the permission table.
Definition: diag.c:862
switchtec_diag_pattern_gen_set
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
switchtec_gen_transfers
static const float switchtec_gen_transfers[]
Number of GT/s capable for each PCI generation or link_rate.
Definition: switchtec.h:679
switchtec_diag_ext_recv_obj_dump_in
Definition: diag.h:107
switchtec_diag_pattern_mon_get
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
switchtec_diag_cross_hair_get
Definition: diag.h:245
switchtec_diag_refclk_ctl_in
Definition: diag.h:130
switchtec_diag_port_eq_status_in2
Definition: diag.h:62
switchtec_diag_cross_hair_disable
int switchtec_diag_cross_hair_disable(struct switchtec_dev *dev)
Disable active cross hair.
Definition: diag.c:69
switchtec_diag_refclk_ctl
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
switchtec_diag_loopback_ltssm_out
Definition: diag.h:161
switchtec_diag_pattern_mon_set
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
switchtec_diag_port_eq_tx_fslf
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
switchtec_diag_ext_dump_coeff_prev_in
Definition: diag.h:114
switchtec_diag_port_eye_fetch
Definition: diag.h:211
switchtec_mrpc
Definition: switchtec.h:1187
switchtec_diag_pat_gen_in
Definition: diag.h:168
switchtec_diag_rcvr_obj_dump_out
Definition: diag.h:41
switchtec_diag_port_eq_status_out
Definition: diag.h:69
switchtec_diag_eye_cancel
int switchtec_diag_eye_cancel(struct switchtec_dev *dev)
Cancel in-progress eye capture.
Definition: diag.c:306
range
Definition: utils.h:34
switchtec_diag_eye_fetch
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
switchtec_diag_eye_start
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
switchtec_diag_eye_set_mode
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
switchtec_diag_loopback_ltssm_in
Definition: diag.h:154
switchtec_diag_rcvr_obj_dump_in
Definition: diag.h:35
switchtec_diag_cross_hair_in
Definition: diag.h:238
switchtec_diag_port_eye_cmd
Definition: diag.h:204
switchtec_diag_ltssm_log
Definition: switchtec.h:1231
switchtec_diag_cross_hair
Definition: switchtec.h:1119
switchtec_diag_loopback_set
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
switchtec_diag_port_eye_start
Definition: diag.h:190
switchtec_diag_loopback_in
Definition: diag.h:140
switchtec_port_eq_tx_fslf
Definition: switchtec.h:1175
switchtec_diag_pat_gen_inject
Definition: diag.h:175
switchtec_diag_port_eq_status_in
Definition: diag.h:55
switchtec_port_eq_table
Definition: switchtec.h:1159
switchtec_diag_pat_gen_out
Definition: diag.h:182
switchtec_diag_rcvr_obj
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
switchtec_diag_cross_hair_enable
int switchtec_diag_cross_hair_enable(struct switchtec_dev *dev, int lane_id)
Enable cross hair on specified lane.
Definition: diag.c:52
switchtec_diag_pattern_gen_get
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
switchtec_cmd
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
switchtec_diag_ltssm_log
int switchtec_diag_ltssm_log(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 switchtec device.
Definition: diag.c:917
switchtec_diag_port_eq_tx_table
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