diff --git a/cli/diag.c b/cli/diag.c index 72c28bc3..22e22154 100644 --- a/cli/diag.c +++ b/cli/diag.c @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -1246,7 +1247,7 @@ static double *eye_observe_dev(struct switchtec_dev *dev, int port_id, struct switchtec_status status; int i, ret, first_lane, lane; size_t lane_cnt[num_lanes]; - int lane_mask[4] = {}; + int lane_mask[5] = {}; double tmp[500]; double *pixels; @@ -1391,7 +1392,7 @@ static double *eye_capture_dev_gen5(struct switchtec_dev *dev, int vstep) { int bin, j, ret, first_lane, num_phases_l, stride; - int lane_mask[4] = {}; + int lane_mask[5] = {}; struct switchtec_status sw_status; double tmp[64]; double* ber_data = NULL; @@ -1408,6 +1409,11 @@ static double *eye_capture_dev_gen5(struct switchtec_dev *dev, data_mode, eye_mode, refclk, vstep); if (ret) { switchtec_perror("eye_run"); + if (errno == EBUSY || + ERRNO_MRPC(errno) == ERR_EYE_CAP_STATE_INVAL) + fprintf(stderr, + "Hint: A previous eye capture may still be in progress.\n" + "Wait for it to complete or reset the device.\n"); return NULL; } @@ -1489,7 +1495,7 @@ static int eye(int argc, char **argv) .hstep = 1, .sar_sel = 10, .intleav_sel = 0, - .refclk = 0, + .refclk = 100000, .data_mode = SWITCHTEC_DIAG_EYE_ADC, .eye_modes_gen6 = SWITCHTEC_DIAG_EYE_FULL, }; @@ -1629,6 +1635,11 @@ static int eye(int argc, char **argv) return -1; } + if (cfg.dev && switchtec_is_gen6(cfg.dev) && cfg.refclk == 0) { + fprintf(stderr, "--refclk/-r must be non-zero for Gen6 eye capture\n"); + return -1; + } + if (!pixels) { if (switchtec_is_gen5(cfg.dev) || switchtec_is_gen6(cfg.dev)) { pixels = eye_capture_dev_gen5(cfg.dev, cfg.port_id, diff --git a/inc/switchtec/diag.h b/inc/switchtec/diag.h index cc3892c9..caa562e1 100644 --- a/inc/switchtec/diag.h +++ b/inc/switchtec/diag.h @@ -263,7 +263,7 @@ struct switchtec_gen6_diag_eye_run_in { uint8_t resvd1; uint8_t timeout_disable; uint8_t resvd2; - uint32_t lane_mask[4]; + uint32_t lane_mask[5]; uint8_t sar_sel; uint8_t intleav_sel; uint8_t vstep; diff --git a/inc/switchtec/errors.h b/inc/switchtec/errors.h index 5473e242..24cff7d4 100644 --- a/inc/switchtec/errors.h +++ b/inc/switchtec/errors.h @@ -85,6 +85,17 @@ enum { ERR_ACCESS_REFUSED = 0xFFFF0001, ERR_PAT_MON_IS_DISABLED = 0x70b02, + + ERR_EYE_CAP_LANE_MASK_INVAL = 0x70a02, + ERR_EYE_CAP_DEPTH_INVAL = 0x70a03, + ERR_EYE_CAP_TOO_MANY_LANES = 0x70a04, + ERR_EYE_CAP_ERROR = 0x70a05, + ERR_EYE_CAP_TIMEOUT = 0x70a06, + ERR_EYE_CAP_STATE_INVAL = 0x70a07, + ERR_EYE_CAP_LANE_ID_INVAL = 0x70a08, + ERR_EYE_CAP_BIN_NUM_INVAL = 0x70a09, + ERR_EYE_CAP_SUBCMD_INVAL = 0x70a0a, + ERR_EYE_CAP_HW_ALLOC_FAIL = 0x70a0f, }; #endif diff --git a/inc/switchtec/switchtec.h b/inc/switchtec/switchtec.h index ded071c1..38964c57 100644 --- a/inc/switchtec/switchtec.h +++ b/inc/switchtec/switchtec.h @@ -1791,7 +1791,7 @@ int switchtec_diag_eye_set_mode(struct switchtec_dev *dev, enum switchtec_diag_eye_data_mode mode); int switchtec_diag_eye_read(struct switchtec_dev *dev, int lane_id, int bin, int* num_phases, double* ber_data); -int switchtec_diag_eye_start(struct switchtec_dev *dev, int lane_mask[4], +int switchtec_diag_eye_start(struct switchtec_dev *dev, int lane_mask[5], struct range *x_range, struct range *y_range, int step_interval, int capture_depth, int sar_sel, int intleav_sel, int hstep, int data_mode, diff --git a/lib/diag.c b/lib/diag.c index 62b2b7dd..3d494b32 100644 --- a/lib/diag.c +++ b/lib/diag.c @@ -29,6 +29,9 @@ #define SWITCHTEC_LIB_CORE #define SWITCHTEC_LTSSM_MAX_LOGS 61 +#define EYE_CAP_STATUS_TIMEOUT_MS (5 * 60 * 1000) +#define EYE_CAP_STATUS_POLL_MS 200 +#define EYE_CAP_PROGRESS_INTERVAL 25 #include "switchtec_priv.h" #include "switchtec/diag.h" @@ -132,6 +135,8 @@ static int switchtec_diag_eye_status_gen5(struct switchtec_dev *dev) { int ret; int eye_status; + int elapsed_ms = 0; + int poll_count = 0; struct switchtec_gen5_diag_eye_status_in in = { .sub_cmd = MRPC_EYE_CAP_STATUS_GEN5, @@ -146,10 +151,25 @@ static int switchtec_diag_eye_status_gen5(struct switchtec_dev *dev) return -1; } eye_status = out.status; - usleep(200000); + usleep(EYE_CAP_STATUS_POLL_MS * 1000); + elapsed_ms += EYE_CAP_STATUS_POLL_MS; + poll_count++; + + if (poll_count % EYE_CAP_PROGRESS_INTERVAL == 0) + fprintf(stderr, "."); + + if (elapsed_ms >= EYE_CAP_STATUS_TIMEOUT_MS) { + fprintf(stderr, "\n"); + errno = ETIMEDOUT; + switchtec_perror("Eye capture timed out waiting for completion"); + return -1; + } } while (eye_status == SWITCHTEC_GEN5_DIAG_EYE_STATUS_IN_PROGRESS || eye_status == SWITCHTEC_GEN5_DIAG_EYE_STATUS_PENDING); + if (poll_count >= EYE_CAP_PROGRESS_INTERVAL) + fprintf(stderr, "\n"); + switch (eye_status) { case SWITCHTEC_GEN5_DIAG_EYE_STATUS_DONE: return 0; @@ -159,7 +179,7 @@ static int switchtec_diag_eye_status_gen5(struct switchtec_dev *dev) return -1; case SWITCHTEC_GEN5_DIAG_EYE_STATUS_TIMEOUT: errno = ETIMEDOUT; - switchtec_perror("Eye capture timeout"); + switchtec_perror("Eye capture firmware timeout"); return -1; case SWITCHTEC_GEN5_DIAG_EYE_STATUS_ERROR: errno = EIO; @@ -191,6 +211,20 @@ static int switchtec_diag_eye_cmd_gen5(struct switchtec_dev *dev, void *in, size_t size) { int ret; + struct switchtec_gen5_diag_eye_status_in status_in = { + .sub_cmd = MRPC_EYE_CAP_STATUS_GEN5, + }; + struct switchtec_gen5_diag_eye_status_out status_out; + + ret = switchtec_cmd(dev, MRPC_GEN5_EYE_CAPTURE, &status_in, + sizeof(status_in), &status_out, + sizeof(status_out)); + if (ret == 0 && + (status_out.status == SWITCHTEC_GEN5_DIAG_EYE_STATUS_IN_PROGRESS || + status_out.status == SWITCHTEC_GEN5_DIAG_EYE_STATUS_PENDING)) { + errno = EBUSY; + return -1; + } ret = switchtec_cmd(dev, MRPC_GEN5_EYE_CAPTURE, in, size, NULL, 0); @@ -306,7 +340,7 @@ int switchtec_diag_eye_read(struct switchtec_dev *dev, int lane_id, * * @return 0 on success, error code on failure */ -int switchtec_diag_eye_start(struct switchtec_dev *dev, int lane_mask[4], +int switchtec_diag_eye_start(struct switchtec_dev *dev, int lane_mask[5], struct range *x_range, struct range *y_range, int step_interval, int capture_depth, int sar_sel, int intleav_sel, int hstep, int data_mode, @@ -336,6 +370,7 @@ int switchtec_diag_eye_start(struct switchtec_dev *dev, int lane_mask[4], .lane_mask[1] = lane_mask[1], .lane_mask[2] = lane_mask[2], .lane_mask[3] = lane_mask[3], + .lane_mask[4] = lane_mask[4], .sar_sel = sar_sel, .intleav_sel = intleav_sel, .vstep = vstep, diff --git a/lib/switchtec.c b/lib/switchtec.c index 2d843d34..717ec41f 100644 --- a/lib/switchtec.c +++ b/lib/switchtec.c @@ -855,6 +855,31 @@ const char *switchtec_strerror(void) default: break; } break; + case MRPC_GEN5_EYE_CAPTURE: + switch (err) { + case ERR_EYE_CAP_LANE_MASK_INVAL: + msg = "Eye capture lane mask invalid"; break; + case ERR_EYE_CAP_DEPTH_INVAL: + msg = "Eye capture depth invalid"; break; + case ERR_EYE_CAP_TOO_MANY_LANES: + msg = "Eye capture too many lanes"; break; + case ERR_EYE_CAP_ERROR: + msg = "Eye capture error"; break; + case ERR_EYE_CAP_TIMEOUT: + msg = "Eye capture firmware timeout"; break; + case ERR_EYE_CAP_STATE_INVAL: + msg = "Eye capture state invalid (capture already in progress)"; break; + case ERR_EYE_CAP_LANE_ID_INVAL: + msg = "Eye capture lane ID invalid or inactive"; break; + case ERR_EYE_CAP_BIN_NUM_INVAL: + msg = "Eye capture bin number invalid"; break; + case ERR_EYE_CAP_SUBCMD_INVAL: + msg = "Eye capture sub-command invalid"; break; + case ERR_EYE_CAP_HW_ALLOC_FAIL: + msg = "Eye capture hardware resource allocation failed"; break; + default: break; + } + break; default: break; }