From d3194459ad5bc6cfc9d7617e99a2554cf60d802b Mon Sep 17 00:00:00 2001 From: BenReed161 Date: Thu, 28 May 2026 17:18:32 -0700 Subject: [PATCH 1/2] Add error and timeout polling for eye command Add error cases for Eye capture to avoid error messages that are difficult to decode. Added a command to poll for the eye capture and wait for the timeout. Eye captures on i2c were taking longer than expected. Add error for an inprogress eye. Update gen6 refclk input variable from 0 to 100000. The value 100000 gives enough sampling time per voltage/phase step to accumulate statistically meaningful error counts. Previous default value of 0 was unhelpful as a default value, as 0 sampling time did not give enough time. Add validation check of the gen6 refclk value. --- cli/diag.c | 13 ++++++++++++- inc/switchtec/errors.h | 11 +++++++++++ lib/diag.c | 38 ++++++++++++++++++++++++++++++++++++-- lib/switchtec.c | 25 +++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 3 deletions(-) diff --git a/cli/diag.c b/cli/diag.c index 72c28bc3b..72f9fdebe 100644 --- a/cli/diag.c +++ b/cli/diag.c @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -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/errors.h b/inc/switchtec/errors.h index 5473e2422..24cff7d41 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/lib/diag.c b/lib/diag.c index 62b2b7ddd..82d543f39 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); diff --git a/lib/switchtec.c b/lib/switchtec.c index 2d843d345..717ec41f0 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; } From 7a037c55cd8b44e4d46e0739fe1dede0aac3e026 Mon Sep 17 00:00:00 2001 From: BenReed161 Date: Fri, 29 May 2026 09:40:16 -0700 Subject: [PATCH 2/2] Update mask from 4 to 5 switchtec_gen6_diag_eye_run_in had lane_mask[4] but Gen6 firmware expected lane_mask[5] for 160 bits to cover all 160 lanes. This caused values to be misread as it was offset incorrectly in input structure. --- cli/diag.c | 4 ++-- inc/switchtec/diag.h | 2 +- inc/switchtec/switchtec.h | 2 +- lib/diag.c | 3 ++- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cli/diag.c b/cli/diag.c index 72f9fdebe..22e221546 100644 --- a/cli/diag.c +++ b/cli/diag.c @@ -1247,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; @@ -1392,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; diff --git a/inc/switchtec/diag.h b/inc/switchtec/diag.h index cc3892c96..caa562e12 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/switchtec.h b/inc/switchtec/switchtec.h index ded071c1f..38964c57c 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 82d543f39..3d494b323 100644 --- a/lib/diag.c +++ b/lib/diag.c @@ -340,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, @@ -370,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,