From a095e4233ddd5c21a3219e6fae470ac1a43e5544 Mon Sep 17 00:00:00 2001 From: BenReed161 Date: Mon, 15 Dec 2025 14:55:09 -0800 Subject: [PATCH 01/10] Add gen6 support for Link Status Add gen6 option for the switchtec status command. --- lib/switchtec.c | 138 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 125 insertions(+), 13 deletions(-) diff --git a/lib/switchtec.c b/lib/switchtec.c index 0ba402b0..4f93dc1a 100644 --- a/lib/switchtec.c +++ b/lib/switchtec.c @@ -471,6 +471,20 @@ static const char *lane_reversal_str(int link_up, } } +static const char *lane_reversal_str_gen6(int link_up, + int lane_reversal) +{ + if (!link_up) + return "N/A"; + + switch(lane_reversal) { + case 0: return "Normal Lane Ordering"; + case 1: return "Lane Reversal in effect"; + default: return "Unknown Lane Ordering"; + } +} + + static void generate_lane_str(struct switchtec_status *s) { int i, l; @@ -498,19 +512,8 @@ static void generate_lane_str(struct switchtec_status *s) } } -/** - * @brief Get the status of all the ports on a switchtec device - * @param[in] dev Switchtec device handle - * @param[out] status A pointer to an allocated list of port statuses - * @return The number of ports in the status list or a negative value - * on failure - * - * This function a allocates memory for the number of ports in the - * system. The returned \p status structure should be freed with the - * switchtec_status_free() function. - */ -int switchtec_status(struct switchtec_dev *dev, - struct switchtec_status **status) +static int switchtec_status_gen345(struct switchtec_dev *dev, + struct switchtec_status **status) { uint64_t port_bitmap = 0; int ret; @@ -588,6 +591,115 @@ int switchtec_status(struct switchtec_dev *dev, return nr_ports; } +static int switchtec_status_gen6(struct switchtec_dev *dev, + struct switchtec_status **status) +{ + struct { + uint64_t map1; + uint16_t map2; + uint16_t rsvrd1; + uint32_t rsvrd2; + } port_bitmap = { + .map1 = 0, + .map2 = 0 + }; + + int ret; + int i, p; + int nr_ports = 0; + struct switchtec_status *s; + int max_ports; + + if (!status) { + errno = EINVAL; + return -errno; + } + + max_ports = switchtec_max_supported_ports(dev); + + struct { + uint8_t phys_port_id; + uint8_t par_id; + uint8_t log_port_id; + uint8_t stk_id; + uint8_t cfg_lnk_width; + uint8_t neg_lnk_width; + uint8_t usp_flag; + uint8_t linkup_linkrate; + uint8_t ltssm_major; + uint8_t ltssm_minor; + uint8_t lane_reversal; + uint8_t first_act_lane; + } ports[max_ports]; + + ret = switchtec_cmd(dev, MRPC_LNKSTAT, &port_bitmap, sizeof(port_bitmap), + ports, sizeof(ports)); + if (ret) + return -1; + + + for (i = 0; i < max_ports; i++) { + if ((ports[i].stk_id >> 4) > SWITCHTEC_MAX_STACKS) + continue; + nr_ports++; + } + + s = *status = calloc(nr_ports, sizeof(*s)); + if (!s) + return -ENOMEM; + + for (i = 0, p = 0; i < max_ports && p < nr_ports; i++) { + if ((ports[i].stk_id >> 4) > SWITCHTEC_MAX_STACKS) + continue; + + s[p].port.partition = ports[i].par_id; + s[p].port.stack = ports[i].stk_id >> 4; + s[p].port.upstream = ports[i].usp_flag; + s[p].port.stk_id = ports[i].stk_id & 0xF; + s[p].port.phys_id = ports[i].phys_port_id; + s[p].port.log_id = ports[i].log_port_id; + + s[p].cfg_lnk_width = ports[i].cfg_lnk_width; + s[p].neg_lnk_width = ports[i].neg_lnk_width; + s[p].link_up = ports[i].linkup_linkrate >> 7; + s[p].link_rate = ports[i].linkup_linkrate & 0x7F; + s[p].ltssm = le16toh(ports[i].ltssm_major); + s[p].ltssm_str = switchtec_ltssm_str(s[p].ltssm, 1, dev); + s[p].lane_reversal = ports[i].lane_reversal; + s[p].lane_reversal_str = lane_reversal_str_gen6(s[p].link_up, + s[p].lane_reversal); + s[p].first_act_lane = ports[i].first_act_lane & 0xF; + s[p].acs_ctrl = -1; + generate_lane_str(&s[p]); + + p++; + } + + qsort(s, nr_ports, sizeof(*s), compare_status); + + return nr_ports; +} + +/** + * @brief Get the status of all the ports on a switchtec device + * @param[in] dev Switchtec device handle + * @param[out] status A pointer to an allocated list of port statuses + * @return The number of ports in the status list or a negative value + * on failure + * + * This function a allocates memory for the number of ports in the + * system. The returned \p status structure should be freed with the + * switchtec_status_free() function. + */ +int switchtec_status(struct switchtec_dev *dev, + struct switchtec_status **status) +{ + if (switchtec_is_gen6(dev)) + return switchtec_status_gen6(dev, status); + else + return switchtec_status_gen345(dev, status); +} + /** * @brief Free a list of status structures allocated by switchtec_status() * @param[in] status Status structure list From 051dfa63d16205921f7a30afb057698c6c6db08f Mon Sep 17 00:00:00 2001 From: BenReed161 Date: Tue, 16 Dec 2025 13:57:41 -0800 Subject: [PATCH 02/10] Update the OSA command for gen6 Update the OSA commands to support the new Gen6 output structures and new os type TS0. Updated stack ID arguement to support the new stacks introduced in Gen6. Fix minor spelling of "capture_control" --- cli/diag.c | 135 +++++++++++++++++++++++++++++++---------------------- lib/diag.c | 66 +++++++++++++++++++------- 2 files changed, 127 insertions(+), 74 deletions(-) diff --git a/cli/diag.c b/cli/diag.c index 7b7d7b6c..46becd72 100644 --- a/cli/diag.c +++ b/cli/diag.c @@ -81,6 +81,11 @@ static const struct argconfig_choice port_eq_prev_speeds[] = { .choices=port_eq_prev_speeds \ } +#define OSA_STACK_ID_OPTION { \ + "stack_id", 's', "STACK_ID", CFG_INT, &cfg.stack_id, \ + required_argument,"ID of the stack (0-5), 7 for mangement stack (Gen5). ID of the stack (0-9) (Gen6)", \ +} + static int get_port(struct switchtec_dev *dev, int port_id, struct switchtec_status *port) { @@ -2653,6 +2658,22 @@ static int linkerr_inject(int argc, char ** argv) return ret; } +static int stack_id_check(struct switchtec_dev *dev, int stack_id) +{ + if (switchtec_is_gen6(dev)) { + if (stack_id < 0 || stack_id > 9) + goto invalid_stack; + } else { + if (stack_id < 0 || (stack_id > 5 && stack_id != 7)) + goto invalid_stack; + } + return 0; + +invalid_stack: + fprintf(stderr, "Invalid stack ID.\n"); + return -1; +} + #define CMD_ORDERED_SET_ANALYZER "Ordered set analyzer" static int osa(int argc, char **argv) @@ -2665,8 +2686,7 @@ static int osa(int argc, char **argv) } cfg; const struct argconfig_options opts[] = { DEVICE_OPTION, - {"stack_id", 's', "STACK_ID", CFG_INT, &cfg.stack_id, - required_argument,"ID of the stack (0-5), 7 for mangement stack"}, + OSA_STACK_ID_OPTION, {"operation", 'o', "0/1/2/3/4/5", CFG_INT, &cfg.operation, required_argument,"operations:\n- stop:0\n- start:1\n- trigger:2\n- reset:3\n- release:4\n- status:5"}, {NULL}}; @@ -2674,10 +2694,9 @@ static int osa(int argc, char **argv) argconfig_parse(argc, argv, CMD_ORDERED_SET_ANALYZER, opts, &cfg, sizeof(cfg)); - if (cfg.stack_id < 0 || (cfg.stack_id > 5 && cfg.stack_id != 7)) { - fprintf(stderr, "Invalid stack ID.\n"); - return -1; - } + ret = stack_id_check(cfg.dev, cfg.stack_id); + if (ret) + return ret; if (cfg.operation > 5 || cfg.operation < 0) { printf("Invalid operation!\n"); @@ -2712,8 +2731,7 @@ static int osa_config_type(int argc, char **argv) } cfg; const struct argconfig_options opts[] = { DEVICE_OPTION, - {"stack_id", 's', "STACK_ID", CFG_INT, &cfg.stack_id, - required_argument,"ID of the stack (0-5), 7 for mangement stack"}, + OSA_STACK_ID_OPTION, {"lane_mask", 'm', "LANE_MASK", CFG_STRING, &cfg.lane_mask, required_argument, "16 bit lane mask, 1 enables the triggering for that specified lane. " \ @@ -2724,23 +2742,22 @@ static int osa_config_type(int argc, char **argv) "(If left blank defaults to all bits set to 0). Input as a hexidecimal value prefixed with 0x\nBit 0 : tx\nBit 1 : rx"}, {"link_rate", 'r', "LINK_RATE", CFG_STRING, &cfg.link_rate, required_argument, - "5 bit mask for link rate, 1 enables the corrisponding link rate. " \ + "6 bit mask for link rate, 1 enables the corrisponding link rate. " \ "(If left blank defaults to all bits set to 0). Input as a hexidecimal value prefixed with " \ - "0x\nBit 0 : Gen1\nBit 1 : Gen2\nBit 2 : Gen3\nBit 3 : Gen4\nBit 4 : Gen5"}, + "0x\nBit 0 : Gen1\nBit 1 : Gen2\nBit 2 : Gen3\nBit 3 : Gen4\nBit 4 : Gen5\nBit 5 : Gen6"}, {"os_types", 't', "OS_TYPES", CFG_STRING, &cfg.os_types, required_argument, - "4 bit mask for OS types, 1 enables the corrisponding OS type. "\ - "(If left blank defaults to all bits set to 0). Input as a hexidecimal value prefixed with "\ - "0x\nBit 0 : TS1\nBit 1 : TS2\nBit 2 : FTS\nBit 3 : CTL_SKP"}, + "4 bit mask for OS types, 5 bit mask Gen6 only. 1 enables the corrisponding OS type. "\ + "(If left blank defaults to all bits set to 0). Input as a hexidecimal value prefixed with 0x."\ + "\n\t\tGen5\tGen6\nBit 0\tTS1\tTS0\nBit 1\tTS2\tTS1\nBit 2\tFTS\tTS2\nBit 3\tCTL_SKP\tFTS\nBit 4\t----\tCTL_SKP"}, {NULL}}; argconfig_parse(argc, argv, CMD_ORDERED_SET_ANALYZER_CONF, opts, &cfg, sizeof(cfg)); - if (cfg.stack_id < 0 || (cfg.stack_id > 5 && cfg.stack_id != 7)) { - fprintf(stderr, "Invalid stack ID.\n"); - return -1; - } + ret = stack_id_check(cfg.dev, cfg.stack_id); + if (ret) + return ret; if (cfg.lane_mask) { ret = convert_hex_str(cfg.lane_mask, &lane_mask, &num_dwords, 4); @@ -2770,8 +2787,14 @@ static int osa_config_type(int argc, char **argv) fprintf(stderr, "Error with link rate mask.\n"); return -1; } - if (*link_rate_mask > 31) { - fprintf(stderr, "Link rate cannot be greater than 0x1F.\n"); + if ((*link_rate_mask > 31 || (*link_rate_mask | 0x20)) && switchtec_is_gen5(cfg.dev)) { + fprintf(stderr, "Cannot enable Gen6 link rate or mask greater than 0x1F (Gen5 Switchtec devices).\n"); + free(lane_mask); + free(direction_mask); + free(link_rate_mask); + return -1; + } else if (*link_rate_mask > 63 && switchtec_is_gen6(cfg.dev)) { + fprintf(stderr, "Link rate cannot be greater than 0x3F (Gen6 Switchtec devices).\n"); free(lane_mask); free(direction_mask); free(link_rate_mask); @@ -2842,9 +2865,9 @@ static int osa_config_pat(int argc, char **argv) "(If left blank defaults to all bits set to 0). Input as a hexidecimal value prefixed with 0x\nBit 0 : tx\nBit 1 : rx"}, {"link_rate", 'r', "LINK_RATE", CFG_STRING, &cfg.link_rate, required_argument, - "5 bit mask for link rate, 1 enables the corrisponding link rate. "\ + "6 bit mask for link rate, 1 enables the corrisponding link rate. "\ "(If left blank defaults to all bits set to 0). Input as a hexidecimal value "\ - "prefixed with 0x\nBit 0 : Gen1\nBit 1 : Gen2\nBit 2 : Gen3\nBit 3 : Gen4\nBit 4 : Gen5"}, + "prefixed with 0x\nBit 0 : Gen1\nBit 1 : Gen2\nBit 2 : Gen3\nBit 3 : Gen4\nBit 4 : Gen5\nBit 5 : Gen6"}, {"dwords_value", 'V', "\"val_dword0 val_dword1 etc.\"", CFG_STRING, &cfg.value_dwords, required_argument, "(Maximum 4 DWs) Dwords should be surrounded by quotations, each "\ @@ -2858,10 +2881,9 @@ static int osa_config_pat(int argc, char **argv) argconfig_parse(argc, argv, CMD_ORDERED_SET_ANALYZER_CONF, opts, &cfg, sizeof(cfg)); - if (cfg.stack_id < 0 || (cfg.stack_id > 5 && cfg.stack_id != 7)) { - fprintf(stderr, "Invalid stack ID.\n"); - return -1; - } + ret = stack_id_check(cfg.dev, cfg.stack_id); + if (ret) + return ret; if (cfg.lane_mask) { ret = convert_hex_str(cfg.lane_mask, &lane_mask, &num_dwords, 4); @@ -2891,8 +2913,14 @@ static int osa_config_pat(int argc, char **argv) fprintf(stderr, "Error with link rate mask.\n"); return -1; } - if (*link_rate_mask > 31) { - fprintf(stderr, "Link rate cannot be greater than 0x1F.\n"); + if ((*link_rate_mask > 31 || (*link_rate_mask | 0x20)) && switchtec_is_gen5(cfg.dev)) { + fprintf(stderr, "Cannot enable Gen6 link rate or mask greater than 0x1F (Gen5 Switchtec devices).\n"); + free(lane_mask); + free(direction_mask); + free(link_rate_mask); + return -1; + } else if (*link_rate_mask > 63 && switchtec_is_gen6(cfg.dev)) { + fprintf(stderr, "Link rate cannot be greater than 0x3F (Gen6 Switchtec devices).\n"); free(lane_mask); free(direction_mask); free(link_rate_mask); @@ -2961,8 +2989,7 @@ static int osa_config_misc(int argc, char **argv) } cfg; const struct argconfig_options opts[] = { DEVICE_OPTION, - {"stack_id", 's', "STACK_ID", CFG_INT, &cfg.stack_id, - required_argument,"ID of the stack (0-5), 7 for mangement stack"}, + OSA_STACK_ID_OPTION, {"trigger_en", 't', "ENABLED", CFG_STRING, &cfg.trigger_en, required_argument, "3 bit mask for trigger enable, 1 enables the correisponding trigger. "\ @@ -2973,10 +3000,9 @@ static int osa_config_misc(int argc, char **argv) argconfig_parse(argc, argv, CMD_ORDERED_SET_ANALYZER_MISC_CONF, opts, &cfg, sizeof(cfg)); - if (cfg.stack_id < 0 || (cfg.stack_id > 5 && cfg.stack_id != 7)) { - fprintf(stderr, "Invalid stack ID.\n"); - return -1; - } + ret = stack_id_check(cfg.dev, cfg.stack_id); + if (ret) + return ret; if (cfg.trigger_en) { ret = convert_hex_str(cfg.trigger_en, &trigger_mask, @@ -3003,7 +3029,7 @@ static int osa_config_misc(int argc, char **argv) #define CMD_ORDERED_SET_ANALYZER_CAP_CTRL "Ordered set analyzer capture control" -static int osa_capture_contol(int argc, char **argv) +static int osa_capture_control(int argc, char **argv) { int ret = 0; uint32_t * os_type_mask = NULL; @@ -3029,8 +3055,7 @@ static int osa_capture_contol(int argc, char **argv) const struct argconfig_options opts[] = { DEVICE_OPTION, - {"stack_id", 's', "STACK_ID", CFG_INT, &cfg.stack_id, - required_argument,"ID of the stack (0-5), 7 for mangement stack"}, + OSA_STACK_ID_OPTION, {"lane_mask", 'm', "LANE_MASK", CFG_STRING, &cfg.lane_mask, required_argument, "16 bit lane mask, 1 enables the triggering for that specified lane. "\ @@ -3041,7 +3066,7 @@ static int osa_capture_contol(int argc, char **argv) "(If left blank defaults to all bits set to 0). Input as a hexidecimal value prefixed with 0x\nBit 0 : tx\nBit 1 : rx"}, {"drop_single_os", 'o', "", CFG_NONE, &cfg.drop_single_os, no_argument, - "When set to 1, the single TS1, TS2, FTS, and CTL_SKP OS's are excluded from the capture."}, + "When set to 1, the single TS0(Gen6), TS1, TS2, FTS, and CTL_SKP OS's are excluded from the capture."}, {"stop_mode", 'S', "", CFG_NONE, &cfg.stop_mode, no_argument, "Controls when the OSA stops capturing. disabled: any lane has stopped, enabled: all lanes have stopped. (Default: disabled)"}, @@ -3055,17 +3080,17 @@ static int osa_capture_contol(int argc, char **argv) "Max 256 entries.\n(Required if disabling --snapshot_mode -s)"}, {"os_types", 't', "OS_TYPES", CFG_STRING, &cfg.os_types, required_argument, - "8 bit mask for OS types, 1 enables the corrisponding OS type. "\ - "(If left blank defaults to all bits set to 0). Input as a hexidecimal value prefixed "\ - "with 0x\nBit 0 : TS1\nBit 1 : TS2\nBit 2 : FTS\nBit 3 : CTL_SKP\nBit 4 : SKP\nBit 5 : EIEOS\nBit 6 : EIOS\nBit 7 : ERR_OS"}, + "4 bit mask for OS types, 5 bit mask Gen6 only. 1 enables the corrisponding OS type. "\ + "(If left blank defaults to all bits set to 0). Input as a hexidecimal value prefixed with 0x."\ + "\n\t\tGen5\tGen6\nBit 0\tTS1\tTS0\nBit 1\tTS2\tTS1\nBit 2\tFTS\tTS2\nBit 3\tCTL_SKP\tFTS\n" \ + "Bit 4\tSKP\tCTL_SKP\nBit 5\tEIEOS\tSKP\nBit 6\tEIOS\tEIEOS\nBit 7\tERR_OS\tEIOS\nBit 8\t----\tERR_OS"}, {NULL}}; argconfig_parse(argc, argv, CMD_ORDERED_SET_ANALYZER_CAP_CTRL, opts, &cfg, sizeof(cfg)); - if (cfg.stack_id < 0 || (cfg.stack_id > 5 && cfg.stack_id != 7)) { - fprintf(stderr, "Invalid stack ID.\n"); - return -1; - } + ret = stack_id_check(cfg.dev, cfg.stack_id); + if (ret) + return ret; if (cfg.post_trig_entries && cfg.snapshot_mode) { fprintf(stderr, "Cannot enable snapshot mode and set the number of post trigger entries.\n"); @@ -3134,17 +3159,15 @@ static int osa_dump_config(int argc, char **argv) } cfg; const struct argconfig_options opts[] = { DEVICE_OPTION, - {"stack_id", 's', "STACK_ID", CFG_INT, &cfg.stack_id, - required_argument,"ID of the stack (0-5), 7 for mangement stack"}, + OSA_STACK_ID_OPTION, {NULL}}; argconfig_parse(argc, argv, CMD_ORDERED_SET_ANALYZER, opts, &cfg, sizeof(cfg)); - if (cfg.stack_id < 0 || (cfg.stack_id > 5 && cfg.stack_id != 7)) { - fprintf(stderr, "Invalid stack ID.\n"); - return -1; - } + ret = stack_id_check(cfg.dev, cfg.stack_id); + if (ret) + return ret; ret = switchtec_osa_dump_conf(cfg.dev, cfg.stack_id); if (ret) { @@ -3167,8 +3190,7 @@ static int osa_dump_data(int argc, char **argv) } cfg; const struct argconfig_options opts[] = { DEVICE_OPTION, - {"stack_id", 's', "STACK_ID", CFG_INT, &cfg.stack_id, - required_argument,"ID of the stack (0-5), 7 for mangement stack"}, + OSA_STACK_ID_OPTION, {"lane", 'l', "lane", CFG_INT, &cfg.lane, required_argument,"lane ID"}, {"direction", 'd', "0/1", CFG_INT, &cfg.direction, @@ -3178,10 +3200,9 @@ static int osa_dump_data(int argc, char **argv) argconfig_parse(argc, argv, CMD_ORDERED_SET_ANALYZER, opts, &cfg, sizeof(cfg)); - if (cfg.stack_id < 0 || (cfg.stack_id > 5 && cfg.stack_id != 7)) { - fprintf(stderr, "Invalid stack ID.\n"); - return -1; - } + ret = stack_id_check(cfg.dev, cfg.stack_id); + if (ret) + return ret; if (cfg.direction > 1) { fprintf(stderr, "Direction must be either 0 or 1\n"); @@ -3217,7 +3238,7 @@ static const struct cmd commands[] = { CMD(osa_config_type, CMD_ORDERED_SET_ANALYZER_CONF), CMD(osa_config_pat, CMD_ORDERED_SET_ANALYZER_PAT_CONF), CMD(osa_config_misc, CMD_ORDERED_SET_ANALYZER_MISC_CONF), - CMD(osa_capture_contol, CMD_ORDERED_SET_ANALYZER_CAP_CTRL), + CMD(osa_capture_control, CMD_ORDERED_SET_ANALYZER_CAP_CTRL), CMD(osa_dump_config, CMD_ORDERED_SET_ANALYZER_DUMP_CONF), CMD(osa_dump_data, CMD_ORDERED_SET_ANALYZER_DUMP_DATA), {} diff --git a/lib/diag.c b/lib/diag.c index 354ff381..3df688b6 100644 --- a/lib/diag.c +++ b/lib/diag.c @@ -2481,12 +2481,23 @@ int switchtec_osa_dump_conf(struct switchtec_dev *dev, int stack_id) printf("%s", (osa_dmp_out.os_type_trig_link_rate >> 2) & 1 ? "GEN3," : ""); printf("%s", (osa_dmp_out.os_type_trig_link_rate >> 3) & 1 ? "GEN4," : ""); printf("%s\n", (osa_dmp_out.os_type_trig_link_rate >> 4) & 1 ? "GEN5" : ""); - - printf("os types: \t\t%s", osa_dmp_out.os_type_trig_os_types & 1 ? "TS1," : ""); - printf("%s", (osa_dmp_out.os_type_trig_os_types >> 1) & 1 ? "TS2," : ""); - printf("%s", (osa_dmp_out.os_type_trig_os_types >> 2) & 1 ? "FTS," : ""); - printf("%s\n", (osa_dmp_out.os_type_trig_os_types >> 3) & 1 ? "CTL_SKP" : ""); - + if (switchtec_is_gen6(dev)) + printf("%s\n", (osa_dmp_out.os_type_trig_link_rate >> 5) & 1 ? "GEN6" : ""); + + printf("os types: \t\t"); + if (switchtec_is_gen6(dev)) { + printf("%s", osa_dmp_out.os_type_trig_os_types & 1 ? "TS0," : ""); + printf("%s", (osa_dmp_out.os_type_trig_os_types >> 1) & 1 ? "TS1," : ""); + printf("%s", (osa_dmp_out.os_type_trig_os_types >> 2) & 1 ? "TS2," : ""); + printf("%s\n", (osa_dmp_out.os_type_trig_os_types >> 3) & 1 ? "FTS" : ""); + printf("%s\n", (osa_dmp_out.os_type_trig_os_types >> 4) & 1 ? "CTL_SKP" : ""); + } else { + printf("%s", osa_dmp_out.os_type_trig_os_types & 1 ? "TS1," : ""); + printf("%s", (osa_dmp_out.os_type_trig_os_types >> 1) & 1 ? "TS2," : ""); + printf("%s", (osa_dmp_out.os_type_trig_os_types >> 2) & 1 ? "FTS," : ""); + printf("%s\n", (osa_dmp_out.os_type_trig_os_types >> 3) & 1 ? "CTL_SKP" : ""); + } + printf("------- OS Pattern ---------------------\n"); printf("lanes: \t\t\t%s", osa_dmp_out.os_pat_trig_lane_mask & 1 ? "0," : ""); for (int i = 1; i < 16; i++) { @@ -2506,6 +2517,8 @@ int switchtec_osa_dump_conf(struct switchtec_dev *dev, int stack_id) printf("%s", (osa_dmp_out.os_pat_trig_link_rate >> 2) & 1 ? "GEN3," : ""); printf("%s", (osa_dmp_out.os_pat_trig_link_rate >> 3) & 1 ? "GEN4," : ""); printf("%s\n", (osa_dmp_out.os_pat_trig_link_rate >> 4) & 1 ? "GEN5" : ""); + if (switchtec_is_gen6(dev)) + printf("%s\n", (osa_dmp_out.os_type_trig_link_rate >> 5) & 1 ? "GEN6" : ""); printf("patttern: \t\t0x%08x %08x %08x %08x\n", osa_dmp_out.os_pat_trig_val_dw0, osa_dmp_out.os_pat_trig_val_dw1, osa_dmp_out.os_pat_trig_val_dw2, @@ -2536,9 +2549,15 @@ int switchtec_osa_dump_conf(struct switchtec_dev *dev, int stack_id) printf("direciton: \t\t%s", osa_dmp_out.capture_dir & 1 ? "RX," : ""); printf("%s\n", (osa_dmp_out.capture_dir >> 1) & 1 ? "TX" : ""); - printf("drop single os: \t%d: Single TS1, TS2, FTS and CTL_SKP OS's %s in the capture\n", - osa_dmp_out.capture_drop_os, - osa_dmp_out.capture_drop_os ? " excluded" : "included"); + if (switchtec_is_gen6(dev)) + printf("drop single os: \t%d: Single TS0, TS1, TS2, FTS and CTL_SKP OS's %s in the capture\n", + osa_dmp_out.capture_drop_os, + osa_dmp_out.capture_drop_os ? " excluded" : "included"); + else + printf("drop single os: \t%d: Single TS1, TS2, FTS and CTL_SKP OS's %s in the capture\n", + osa_dmp_out.capture_drop_os, + osa_dmp_out.capture_drop_os ? " excluded" : "included"); + printf("stop mode: \t\t%d: OSA will stop capturing after %s lane has stopped writing into %s allocated RAMs\n", osa_dmp_out.capture_stop_mode, osa_dmp_out.capture_stop_mode ? "all" : "any", @@ -2548,14 +2567,27 @@ int switchtec_osa_dump_conf(struct switchtec_dev *dev, int stack_id) osa_dmp_out.capture_snap_mode ? "until the RAM is full" : "according to the Post-Trigger Entries value"); printf("post-trigger entries: \t%d\n", osa_dmp_out.capture_post_trig_entries); - printf("os types: \t\t%s", (osa_dmp_out.capture_os_types & 1) ? "TS1," : ""); - printf("%s", (osa_dmp_out.capture_os_types >> 1) & 1 ? "TS2," : ""); - printf("%s", (osa_dmp_out.capture_os_types >> 2) & 1 ? "FTS," : ""); - printf("%s", (osa_dmp_out.capture_os_types >> 3) & 1 ? "CTL_SKP," : ""); - printf("%s", (osa_dmp_out.capture_os_types >> 4) & 1 ? "SKP," : ""); - printf("%s", (osa_dmp_out.capture_os_types >> 5) & 1 ? "EIEOS," : ""); - printf("%s", (osa_dmp_out.capture_os_types >> 6) & 1 ? "EIOS," : ""); - printf("%s", (osa_dmp_out.capture_os_types >> 7) & 1 ? "ERR_OS," : ""); + printf("os types: \t\t"); + if (switchtec_is_gen6(dev)) { + printf("%s", (osa_dmp_out.capture_os_types & 1) ? "TS0," : ""); + printf("%s", (osa_dmp_out.capture_os_types >> 1) & 1 ? "TS2," : ""); + printf("%s", (osa_dmp_out.capture_os_types >> 2) & 1 ? "TS2," : ""); + printf("%s", (osa_dmp_out.capture_os_types >> 3) & 1 ? "FTS," : ""); + printf("%s", (osa_dmp_out.capture_os_types >> 4) & 1 ? "CTL_SKP," : ""); + printf("%s", (osa_dmp_out.capture_os_types >> 5) & 1 ? "SKP," : ""); + printf("%s", (osa_dmp_out.capture_os_types >> 6) & 1 ? "EIEOS," : ""); + printf("%s", (osa_dmp_out.capture_os_types >> 7) & 1 ? "EIOS," : ""); + printf("%s", (osa_dmp_out.capture_os_types >> 8) & 1 ? "ERR_OS," : ""); + } else { + printf("%s", (osa_dmp_out.capture_os_types & 1) ? "TS1," : ""); + printf("%s", (osa_dmp_out.capture_os_types >> 1) & 1 ? "TS2," : ""); + printf("%s", (osa_dmp_out.capture_os_types >> 2) & 1 ? "FTS," : ""); + printf("%s", (osa_dmp_out.capture_os_types >> 3) & 1 ? "CTL_SKP," : ""); + printf("%s", (osa_dmp_out.capture_os_types >> 4) & 1 ? "SKP," : ""); + printf("%s", (osa_dmp_out.capture_os_types >> 5) & 1 ? "EIEOS," : ""); + printf("%s", (osa_dmp_out.capture_os_types >> 6) & 1 ? "EIOS," : ""); + printf("%s", (osa_dmp_out.capture_os_types >> 7) & 1 ? "ERR_OS," : ""); + } printf("\n"); return ret; } From a1efa6c005ecf8d0a33636a313cfa63eb30161e6 Mon Sep 17 00:00:00 2001 From: BenReed161 Date: Wed, 17 Dec 2025 14:28:58 -0800 Subject: [PATCH 03/10] Update Pattern Mon/Gen to Gen6 Add support for new Gen6 pattern types for pattern mon/gen commands. Add Gen6 link speed option --- cli/diag.c | 96 ++++++++++++++++++++++++++++++++++----- inc/switchtec/switchtec.h | 13 ++++++ 2 files changed, 98 insertions(+), 11 deletions(-) diff --git a/cli/diag.c b/cli/diag.c index 46becd72..fecd678b 100644 --- a/cli/diag.c +++ b/cli/diag.c @@ -1767,6 +1767,20 @@ static int loopback(int argc, char **argv) return print_loopback_mode(cfg.dev, cfg.port_id); } +static const struct argconfig_choice all_pattern_types[] = { + {"PRBS7", SWITCHTEC_DIAG_PATTERN_PRBS_7, "PRBS 7"}, + {"PRBS11", SWITCHTEC_DIAG_PATTERN_PRBS_11, "PRBS 11"}, + {"PRBS23", SWITCHTEC_DIAG_PATTERN_PRBS_23, "PRBS 23"}, + {"PRBS31", SWITCHTEC_DIAG_PATTERN_PRBS_31, "PRBS 31"}, + {"PRBS9", SWITCHTEC_DIAG_PATTERN_PRBS_9, "PRBS 9"}, + {"PRBS15", SWITCHTEC_DIAG_PATTERN_PRBS_15, "PRBS 15"}, + {"PRBS5", SWITCHTEC_DIAG_GEN_5_PATTERN_PRBS_5, "PRBS 5 (Gen 5)"}, + {"PRBS20", SWITCHTEC_DIAG_GEN_5_PATTERN_PRBS_20, "PRBS 20 (Gen 5)"}, + {"PRBS13", SWITCHTEC_DIAG_GEN_6_PATTERN_PRBS_13, "PRBS 13 (Gen 6)"}, + {"52UI", SWITCHTEC_DIAG_GEN_6_PATTERN_PCIE_52_UI_JIT, "PCIe 52UI Jitter (Gen 6)"}, + {} +}; + static const struct argconfig_choice pattern_types[] = { {"PRBS7", SWITCHTEC_DIAG_PATTERN_PRBS_7, "PRBS 7"}, {"PRBS11", SWITCHTEC_DIAG_PATTERN_PRBS_11, "PRBS 11"}, @@ -1779,12 +1793,25 @@ static const struct argconfig_choice pattern_types[] = { {} }; +static const struct argconfig_choice pattern_types_gen6[] = { + {"PRBS7", SWITCHTEC_DIAG_GEN_6_PATTERN_PRBS_7, "PRBS 7"}, + {"PRBS11", SWITCHTEC_DIAG_GEN_6_PATTERN_PRBS_9, "PRBS 9"}, + {"PRBS23", SWITCHTEC_DIAG_GEN_6_PATTERN_PRBS_11, "PRBS 11"}, + {"PRBS31", SWITCHTEC_DIAG_GEN_6_PATTERN_PRBS_13, "PRBS 13"}, + {"PRBS9", SWITCHTEC_DIAG_GEN_6_PATTERN_PRBS_15, "PRBS 15"}, + {"PRBS15", SWITCHTEC_DIAG_GEN_6_PATTERN_PRBS_23, "PRBS 23"}, + {"PRBS5", SWITCHTEC_DIAG_GEN_6_PATTERN_PRBS_31, "PRBS 31"}, + {"PRBS20", SWITCHTEC_DIAG_GEN_6_PATTERN_PCIE_52_UI_JIT, "PCIe 52UI Jitter"}, + {} +}; + static const struct argconfig_choice pat_gen_link_speeds[] = { {"GEN1", SWITCHTEC_DIAG_PAT_LINK_GEN1, "GEN1 Pattern Generator Speed"}, {"GEN2", SWITCHTEC_DIAG_PAT_LINK_GEN2, "GEN2 Pattern Generator Speed"}, {"GEN3", SWITCHTEC_DIAG_PAT_LINK_GEN3, "GEN3 Pattern Generator Speed"}, {"GEN4", SWITCHTEC_DIAG_PAT_LINK_GEN4, "GEN4 Pattern Generator Speed"}, {"GEN5", SWITCHTEC_DIAG_PAT_LINK_GEN5, "GEN5 Pattern Generator Speed"}, + {"GEN6", SWITCHTEC_DIAG_PAT_LINK_GEN6, "GEN6 Pattern Generator Speed"}, }; static const char *pattern_to_str(enum switchtec_diag_pattern type) @@ -1799,6 +1826,18 @@ static const char *pattern_to_str(enum switchtec_diag_pattern type) return "UNKNOWN"; } +static const char *pattern_to_str_gen6(enum switchtec_diag_pattern_gen6 type) +{ + const struct argconfig_choice *s; + + for (s = pattern_types_gen6; s->name; s++) { + if (s->value == type) + return s->name; + } + + return "UNKNOWN"; +} + static const char *link_speed_to_str(enum switchtec_diag_pattern_link_rate type) { const struct argconfig_choice *s; @@ -1816,6 +1855,7 @@ static int print_pattern_mode(struct switchtec_dev *dev, { enum switchtec_diag_pattern gen_pat, mon_pat; int gen_pat_gen5, mon_pat_gen5; + enum switchtec_diag_pattern_gen6 mon_pat_gen6, gen_pat_gen6; unsigned long long err_cnt; int ret, lane_id; int err = 0; @@ -1826,6 +1866,7 @@ static int print_pattern_mode(struct switchtec_dev *dev, return -1; } gen_pat_gen5 = gen_pat; + gen_pat_gen6 = gen_pat; if (gen_pat_gen5 == SWITCHTEC_DIAG_GEN_5_PATTERN_PRBS_DISABLED) { fprintf(stderr, "!! The pattern generator is disabled on either the TX or RX port\n"); err = 1; @@ -1834,6 +1875,7 @@ static int print_pattern_mode(struct switchtec_dev *dev, ret = switchtec_diag_pattern_mon_get(dev, port_id, 0, &mon_pat, &err_cnt); mon_pat_gen5 = mon_pat; + mon_pat_gen6 = mon_pat; if (ret == ERR_PAT_MON_IS_DISABLED || mon_pat_gen5 == SWITCHTEC_DIAG_GEN_5_PATTERN_PRBS_DISABLED) { fprintf(stderr, "!! The pattern monitor is disabled on either the TX or RX port\n"); err = 1; @@ -1849,15 +1891,22 @@ static int print_pattern_mode(struct switchtec_dev *dev, } printf("Port: %d\n", port_id); - if (gen_pat == SWITCHTEC_DIAG_PATTERN_PRBS_DISABLED && switchtec_is_gen4(dev)) + if (gen_pat == SWITCHTEC_DIAG_PATTERN_PRBS_DISABLED && switchtec_is_gen4(dev)) { printf(" Generator: Disabled\n"); - else - printf(" Generator: %s\n", pattern_to_str(gen_pat)); + } else { + if (switchtec_is_gen6(dev)) + printf(" Generator: %s\n", pattern_to_str_gen6(gen_pat_gen6)); + else + printf(" Generator: %s\n", pattern_to_str(gen_pat)); + } if (mon_pat == SWITCHTEC_DIAG_PATTERN_PRBS_DISABLED && switchtec_is_gen4(dev)) { printf(" Monitor: Disabled\n"); } else { - printf(" Monitor: %-20s\n", pattern_to_str(mon_pat)); + if (switchtec_is_gen6(dev)) + printf(" Monitor: %-20s\n", pattern_to_str_gen6(mon_pat_gen6)); + else + printf(" Monitor: %-20s\n", pattern_to_str(mon_pat)); printf(" Lane %-2d Errors: 0x%llx\n", 0, err_cnt); for (lane_id = 1; lane_id < port->cfg_lnk_width; lane_id++) { ret = switchtec_diag_pattern_mon_get(dev, port_id, @@ -1896,7 +1945,7 @@ static int pattern(int argc, char **argv) int link_speed; } cfg = { .port_id = -1, - .pattern = SWITCHTEC_DIAG_PATTERN_PRBS_31, + .pattern = SWITCHTEC_DIAG_PATTERN_PRBS_7, }; const struct argconfig_options opts[] = { @@ -1915,8 +1964,8 @@ static int pattern(int argc, char **argv) "Enable Pattern Monitor on specified port"}, {"pattern", 't', "PATTERN", CFG_CHOICES, &cfg.pattern, required_argument, - "pattern to generate or monitor for (default: PRBS31)", - .choices = pattern_types}, + "pattern to generate or monitor for (default: PRBS7)", + .choices = all_pattern_types}, {"speed", 's', "SPEED", CFG_CHOICES, &cfg.link_speed, required_argument, "link speed that applies to the pattern generator (default: GEN1)", @@ -1930,6 +1979,26 @@ static int pattern(int argc, char **argv) "Cannot enable link speed -s / --speed on pattern monitor\n"); return -1; } + + if (cfg.pattern == SWITCHTEC_DIAG_GEN_6_PATTERN_PRBS_13 && !switchtec_is_gen6(cfg.dev)) { + fprintf(stderr, "Cannot set PRBS 13 pattern for non Gen6 Switchtec device.\n"); + return -1; + } + + if (cfg.pattern == SWITCHTEC_DIAG_GEN_6_PATTERN_PCIE_52_UI_JIT && !switchtec_is_gen6(cfg.dev)) { + fprintf(stderr, "Cannot set PCIe 52 UI Jitter pattern for non Gen6 Switchtec device.\n"); + return -1; + } + + if (cfg.pattern == SWITCHTEC_DIAG_GEN_5_PATTERN_PRBS_5 && !switchtec_is_gen5(cfg.dev)) { + fprintf(stderr, "Cannot set PRBS 5 pattern for non Gen6 Switchtec device.\n"); + return -1; + } + + if (cfg.pattern == SWITCHTEC_DIAG_GEN_5_PATTERN_PRBS_20 && !switchtec_is_gen5(cfg.dev)) { + fprintf(stderr, "Cannot set PRBS 20 pattern for non Gen6 Switchtec device.\n"); + return -1; + } if (!cfg.link_speed) { if (switchtec_is_gen5(cfg.dev)) @@ -1965,12 +2034,17 @@ static int pattern(int argc, char **argv) switchtec_perror("pattern_mon_set"); return -1; } - if (cfg.disable) + if (cfg.disable) { printf("Disabled pattern monitor on port %d\n", cfg.port_id); - else - printf("Pattern monitor set for port %d with pattern type %s\n", - cfg.port_id, pattern_to_str(cfg.pattern)); + } else { + if (switchtec_is_gen6(cfg.dev)) + printf("Pattern monitor set for port %d with pattern type %s\n", + cfg.port_id, pattern_to_str_gen6(cfg.pattern)); + else + printf("Pattern monitor set for port %d with pattern type %s\n", + cfg.port_id, pattern_to_str(cfg.pattern)); + } } if (cfg.generate) { diff --git a/inc/switchtec/switchtec.h b/inc/switchtec/switchtec.h index 0fded978..059b4b88 100644 --- a/inc/switchtec/switchtec.h +++ b/inc/switchtec/switchtec.h @@ -1574,6 +1574,18 @@ enum switchtec_diag_pattern_gen5 { SWITCHTEC_DIAG_GEN_5_PATTERN_PRBS_DISABLED, }; +enum switchtec_diag_pattern_gen6 { + SWITCHTEC_DIAG_GEN_6_PATTERN_PRBS_7, + SWITCHTEC_DIAG_GEN_6_PATTERN_PRBS_9, + SWITCHTEC_DIAG_GEN_6_PATTERN_PRBS_11, + SWITCHTEC_DIAG_GEN_6_PATTERN_PRBS_13, + SWITCHTEC_DIAG_GEN_6_PATTERN_PRBS_15, + SWITCHTEC_DIAG_GEN_6_PATTERN_PRBS_23, + SWITCHTEC_DIAG_GEN_6_PATTERN_PRBS_31, + SWITCHTEC_DIAG_GEN_6_PATTERN_PCIE_52_UI_JIT = 0x19, + SWITCHTEC_DIAG_GEN_6_PATTERN_PRBS_DISABLED = 0x1A, +}; + enum switchtec_diag_pattern_link_rate { SWITCHTEC_DIAG_PAT_LINK_DISABLED = 0, SWITCHTEC_DIAG_PAT_LINK_GEN1 = 1, @@ -1581,6 +1593,7 @@ enum switchtec_diag_pattern_link_rate { SWITCHTEC_DIAG_PAT_LINK_GEN3 = 3, SWITCHTEC_DIAG_PAT_LINK_GEN4 = 4, SWITCHTEC_DIAG_PAT_LINK_GEN5 = 5, + SWITCHTEC_DIAG_PAT_LINK_GEN6 = 6, }; enum switchtec_diag_ltssm_speed { From 50d53d691aa76f94f5b6f5292e02992f0e24df67 Mon Sep 17 00:00:00 2001 From: BenReed161 Date: Mon, 22 Dec 2025 14:00:04 -0800 Subject: [PATCH 04/10] Update eye capture to gen6 Add support for Gen6 eye capture data structures and data modes. --- cli/diag.c | 72 ++++++++++++++++++++++++++++++++++++--- inc/switchtec/diag.h | 17 +++++++++ inc/switchtec/mrpc.h | 3 ++ inc/switchtec/switchtec.h | 23 ++++++++++++- lib/diag.c | 25 +++++++++++++- 5 files changed, 133 insertions(+), 7 deletions(-) diff --git a/cli/diag.c b/cli/diag.c index fecd678b..68c225bd 100644 --- a/cli/diag.c +++ b/cli/diag.c @@ -221,6 +221,33 @@ static int ltssm_log(int argc, char **argv) { return ret; } +static const struct argconfig_choice data_mode_choices[] = { + {"ADC", SWITCHTEC_DIAG_EYE_ADC, + "ADC data mode"}, + {"FFE", SWITCHTEC_DIAG_EYE_FFE, + "FFE eye data mode"}, + {"DFE", SWITCHTEC_DIAG_EYE_DFE, + "enumated DFE data eye data mode"}, + {} +}; + +static const struct argconfig_choice eye_modes_gen6[] = { + {"FULL", SWITCHTEC_DIAG_EYE_FULL, + "the full eye diagram"}, + {"INTERLEAVE", SWITCHTEC_DIAG_EYE_INTERLEAVE, + "interleaver eye diagram"}, + {"SAR", SWITCHTEC_DIAG_EYE_SAR, + "interleaver eye diagram"}, + {} +}; + +static const struct argconfig_choice hstep_choices[] = { + {"ultra-fine", SWITCHTEC_DIAG_EYE_ULTRA_FINE, "ultra-fine"}, + {"fine", SWITCHTEC_DIAG_EYE_FINE, "fine"}, + {"medium", SWITCHTEC_DIAG_EYE_MEDIUM, "medium"}, + {"coarse", SWITCHTEC_DIAG_EYE_COARSE, "coarse"}, +}; + static const struct argconfig_choice eye_modes[] = { {"RAW", SWITCHTEC_DIAG_EYE_RAW, "raw data mode (slow, more accurate)"}, @@ -1248,7 +1275,8 @@ static double *eye_observe_dev(struct switchtec_dev *dev, int port_id, goto out_err; } - ret = switchtec_diag_eye_start(dev, lane_mask, X, Y, interval, 0); + ret = switchtec_diag_eye_start(dev, lane_mask, X, Y, interval, + 0, 0, 0, 0, 0, 0, 0, 0); if (ret) { switchtec_perror("eye_start"); goto out_err; @@ -1355,7 +1383,10 @@ static int eye_graph(enum output_format fmt, struct range *X, struct range *Y, static double *eye_capture_dev_gen5(struct switchtec_dev *dev, int port_id, int lane_id, int num_lanes, - int capture_depth, int* num_phases, int* gen) + int capture_depth, int* num_phases, int* gen, + int sar_sel, int intleav_sel, int hstep, + int data_mode, int eye_mode, uint64_t refclk, + int vstep) { int bin, j, ret, first_lane, num_phases_l, stride; int lane_mask[4] = {}; @@ -1371,7 +1402,8 @@ static double *eye_capture_dev_gen5(struct switchtec_dev *dev, } ret = switchtec_diag_eye_start(dev, lane_mask, NULL, NULL, 0, - capture_depth); + capture_depth, sar_sel, intleav_sel, hstep, + data_mode, eye_mode, refclk, vstep); if (ret) { switchtec_perror("eye_run"); return NULL; @@ -1432,6 +1464,12 @@ static int eye(int argc, char **argv) const char *plot_filename; FILE *crosshair_file; const char *crosshair_filename; + int eye_modes_gen6; + int hstep; + int sar_sel; + int intleav_sel; + uint64_t refclk; + int data_mode; } cfg = { .fmt = FMT_DEFAULT, .port_id = -1, @@ -1446,6 +1484,12 @@ static int eye(int argc, char **argv) .y_range.end = 255, .y_range.step = 5, .step_interval = 1, + .hstep = 1, + .sar_sel = 10, + .intleav_sel = 0, + .refclk = 0, + .data_mode = SWITCHTEC_DIAG_EYE_ADC, + .eye_modes_gen6 = SWITCHTEC_DIAG_EYE_FULL, }; const struct argconfig_options opts[] = { DEVICE_OPTION_OPTIONAL, @@ -1460,6 +1504,12 @@ static int eye(int argc, char **argv) {"mode", 'm', "MODE", CFG_CHOICES, &cfg.mode, required_argument, "data mode for the capture", .choices=eye_modes}, + {"mode-gen6", 'M', "MODE", CFG_CHOICES, &cfg.mode, + required_argument, "eye mode for the capture for gen6", + .choices=eye_modes_gen6}, + {"data-mode", 'd', "MODE", CFG_CHOICES, &cfg.data_mode, + required_argument, "data mode for the eye capture gen6", + .choices=data_mode_choices}, {"num-lanes", 'n', "NUM", CFG_POSITIVE, &cfg.num_lanes, required_argument, "number of lanes to capture, if greater than one, format must be csv (default: 1)"}, @@ -1483,6 +1533,15 @@ static int eye(int argc, char **argv) required_argument, "step interval in ms (default: 1ms)"}, {"capture-depth", 'd', "NUM", CFG_POSITIVE, &cfg.capture_depth, required_argument, "capture depth (6 to 40; default: 24)"}, + {"h-step", 'H', "NUM", CFG_CHOICES, &cfg.hstep, + required_argument, "Granularity of the X-axis Gen 6 only", + .choices=hstep_choices}, + {"sar-sel", 'e', "NUM", CFG_NONNEGATIVE, &cfg.sar_sel, + required_argument, "Eye scan for a particular slice (10 to 15) Gen 6 only"}, + {"intleav-sel", 'I', "NUM", CFG_NONNEGATIVE, &cfg.intleav_sel, + required_argument, "Eye scan for a particular interleave (0 to 3) Gen6 only"}, + {"refclk", 'r', "NUM", CFG_NONNEGATIVE, &cfg.refclk, required_argument, + "Configures the number of ref clk cycles used to sample the data (0 to 48 bit num max) Gen 6 only"}, {NULL}}; argconfig_parse(argc, argv, CMD_DESC_EYE, opts, &cfg, @@ -1569,11 +1628,14 @@ static int eye(int argc, char **argv) } if (!pixels) { - if (switchtec_is_gen5(cfg.dev)) { + if (switchtec_is_gen5(cfg.dev) || switchtec_is_gen6(cfg.dev)) { pixels = eye_capture_dev_gen5(cfg.dev, cfg.port_id, cfg.lane_id, cfg.num_lanes, cfg.capture_depth, - &num_phases, &gen); + &num_phases, &gen, cfg.sar_sel, + cfg.intleav_sel, cfg.hstep, + cfg.data_mode, cfg.eye_modes_gen6, + cfg.refclk, cfg.y_range.step); if (!pixels) return -1; diff --git a/inc/switchtec/diag.h b/inc/switchtec/diag.h index 7c657156..f82212bf 100644 --- a/inc/switchtec/diag.h +++ b/inc/switchtec/diag.h @@ -252,6 +252,23 @@ struct switchtec_gen5_diag_eye_run_in { uint32_t lane_mask[4]; }; +struct switchtec_gen6_diag_eye_run_in { + uint8_t sub_cmd; + uint8_t resvd1; + uint8_t timeout_disable; + uint8_t resvd2; + uint32_t lane_mask[4]; + uint8_t sar_sel; + uint8_t intleav_sel; + uint8_t vstep; + int8_t hstep; + uint8_t data_mode; + uint8_t eye_mode; + uint16_t resvd3; + uint32_t ref_timer_lwr; + uint32_t ref_timer_upp; +}; + struct switchtec_diag_cross_hair_in { uint8_t sub_cmd; uint8_t lane_id; diff --git a/inc/switchtec/mrpc.h b/inc/switchtec/mrpc.h index 84e7e403..d7d1b744 100644 --- a/inc/switchtec/mrpc.h +++ b/inc/switchtec/mrpc.h @@ -313,6 +313,9 @@ enum mrpc_sub_cmd { MRPC_EYE_CAP_STATUS_GEN5 = 1, MRPC_EYE_CAP_READ_GEN5 = 2, + MRPC_EYE_CAP_RUN_GEN6 = 3, + MRPC_EYE_CAP_READ_GEN6 = 4, + MRPC_CROSS_HAIR_ENABLE = 0, MRPC_CROSS_HAIR_DISABLE = 1, MRPC_CROSS_HAIR_GET = 2, diff --git a/inc/switchtec/switchtec.h b/inc/switchtec/switchtec.h index 059b4b88..fef5820d 100644 --- a/inc/switchtec/switchtec.h +++ b/inc/switchtec/switchtec.h @@ -1519,6 +1519,25 @@ enum switchtec_diag_eye_data_mode { SWITCHTEC_DIAG_EYE_RATIO, }; +enum switchtec_diag_eye_data_mode_gen6 { + SWITCHTEC_DIAG_EYE_ADC, + SWITCHTEC_DIAG_EYE_FFE, + SWITCHTEC_DIAG_EYE_DFE, +}; + +enum switchtec_diag_eye_mode_gen6 { + SWITCHTEC_DIAG_EYE_FULL, + SWITCHTEC_DIAG_EYE_INTERLEAVE, + SWITCHTEC_DIAG_EYE_SAR, +}; + +enum switchtec_diag_eye_h_step { + SWITCHTEC_DIAG_EYE_ULTRA_FINE = 1, + SWITCHTEC_DIAG_EYE_FINE = 2, + SWITCHTEC_DIAG_EYE_MEDIUM = 3, + SWITCHTEC_DIAG_EYE_COARSE = 4, +}; + struct switchtec_gen5_diag_eye_status_in { uint8_t sub_cmd; uint8_t resvd1[3]; @@ -1645,7 +1664,9 @@ 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], struct range *x_range, struct range *y_range, - int step_interval, int capture_depth); + int step_interval, int capture_depth, int sar_sel, + int intleav_sel, int hstep, int data_mode, + int eye_mode, uint64_t refclk, int vstep); int switchtec_diag_eye_fetch(struct switchtec_dev *dev, double *pixels, size_t pixel_cnt, int *lane_id); int switchtec_diag_eye_cancel(struct switchtec_dev *dev); diff --git a/lib/diag.c b/lib/diag.c index 3df688b6..19e8a284 100644 --- a/lib/diag.c +++ b/lib/diag.c @@ -281,7 +281,9 @@ int switchtec_diag_eye_read(struct switchtec_dev *dev, int lane_id, */ int switchtec_diag_eye_start(struct switchtec_dev *dev, int lane_mask[4], struct range *x_range, struct range *y_range, - int step_interval, int capture_depth) + int step_interval, int capture_depth, int sar_sel, + int intleav_sel, int hstep, int data_mode, + int eye_mode, uint64_t refclk, int vstep) { int err, ret; if (switchtec_is_gen5(dev)) { @@ -295,6 +297,27 @@ int switchtec_diag_eye_start(struct switchtec_dev *dev, int lane_mask[4], .lane_mask[3] = lane_mask[3], }; + ret = switchtec_diag_eye_cmd_gen5(dev, &in, sizeof(in)); + err = errno; + errno = err; + return ret; + } else if (switchtec_is_gen6(dev)) { + struct switchtec_gen6_diag_eye_run_in in = { + .sub_cmd = MRPC_EYE_CAP_RUN_GEN6, + .timeout_disable = 1, + .lane_mask[0] = lane_mask[0], + .lane_mask[1] = lane_mask[1], + .lane_mask[2] = lane_mask[2], + .lane_mask[3] = lane_mask[3], + .sar_sel = sar_sel, + .intleav_sel = intleav_sel, + .vstep = vstep, + .data_mode = data_mode, + .eye_mode = eye_mode, + .ref_timer_lwr = refclk & 0xFFFFFFFF, + .ref_timer_upp = refclk >> 32, + }; + ret = switchtec_diag_eye_cmd_gen5(dev, &in, sizeof(in)); err = errno; errno = err; From 8683a7050b94ceae95759afccda4a75ccda57482 Mon Sep 17 00:00:00 2001 From: BenReed161 Date: Tue, 23 Dec 2025 11:07:51 -0800 Subject: [PATCH 05/10] Add alignment to the UID / PSID for mfg info DWORD align for the UID and PSID printf to make them easier to read. --- cli/mfg.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/cli/mfg.c b/cli/mfg.c index 879d8c8b..023f3055 100644 --- a/cli/mfg.c +++ b/cli/mfg.c @@ -475,21 +475,23 @@ static int info(int argc, char **argv) printf("----------------- UID info --------------------------------\n"); printf("Device Unique ID: \t\t\t0x"); - for (int i = 0; i < SWITCHTEC_UID_DWORD_S; i++) { - printf("%08X", *sn_info.UID); + printf("%08X\n", *sn_info.UID); + sn_info.UID++; + for (int i = 1; i < SWITCHTEC_UID_DWORD_S; i++) { + printf("\t\t\t\t\t %08X\n", *sn_info.UID); sn_info.UID++; } - printf("\n"); printf("Status: \t\t\t\t%s\n", status[(sn_info.PSID_UID_valid_flags >> 4) & 0x3]); printf("Mask Read Mask Enable: \t\t\t0x%0x\n", (sn_info.PSID_UID_valid_flags >> 6) & 0x1); printf("Read Mask Request Enable: \t\t0x%0x\n", (sn_info.PSID_UID_valid_flags >> 7) & 0x1); printf("----------------- PSID info -------------------------------\n"); printf("Device PSID: \t\t\t\t0x"); - for (int i = 0; i < SWITCHTEC_PSID_DWORD_S; i++) { - printf("%08X", *sn_info.PSID0); + printf("%08X\n", *sn_info.PSID0); + sn_info.PSID0++; + for (int i = 1; i < SWITCHTEC_PSID_DWORD_S; i++) { + printf("\t\t\t\t\t %08X\n", *sn_info.PSID0); sn_info.PSID0++; } - printf("\n"); printf("Status: \t\t\t\t%s\n", status[(sn_info.PSID_UID_valid_flags) & 0x3]); printf("Read Mask Enable: \t\t\t0x%0x\n", (sn_info.PSID_UID_valid_flags >> 2) & 0x1); printf("Read Mask Request Enable: \t\t0x%0x\n", (sn_info.PSID_UID_valid_flags >> 3) & 0x1); From 268a8cd1d70ed6f10317c98ac3f0ffe2bcd2db53 Mon Sep 17 00:00:00 2001 From: BenReed161 Date: Tue, 23 Dec 2025 11:37:11 -0800 Subject: [PATCH 06/10] Update the Gen6 LTSSM states to match previous Updated the Gen6 LTSSM states decode string function to match the prev Gen5 version. --- inc/switchtec/switchtec.h | 72 +++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/inc/switchtec/switchtec.h b/inc/switchtec/switchtec.h index fef5820d..a021b34f 100644 --- a/inc/switchtec/switchtec.h +++ b/inc/switchtec/switchtec.h @@ -932,42 +932,42 @@ static inline const char *switchtec_ltssm_str_gen5(int ltssm, int show_minor) static inline const char *switchtec_ltssm_str_gen6(int ltssm_major) { switch(ltssm_major) { - case 0x00: return "DETECT_QUIET"; - case 0x01: return "DETECT_ACTIVE"; - case 0x02: return "POLL_ACTIVE"; - case 0x03: return "POLL_COMPLIANCE"; - case 0x04: return "POLL_CONFIG"; - case 0x05: return "PRE_DETECT_QUIET"; - case 0x06: return "DETECT_WAIT"; - case 0x07: return "CFG_LINKWD_START"; - case 0x08: return "CFG_LINKWD_ACEPT"; - case 0x09: return "CFG_LANENUM_WAI"; - case 0x0A: return "CFG_LANENUM_ACEPT"; - case 0x0B: return "CFG_COMPLETE"; - case 0x0C: return "CFG_IDLE"; - case 0x0D: return "RCVRY_LOCK"; - case 0x0E: return "RCVRY_SPEED"; - case 0x0F: return "RCVRY_RCVRCFG"; - case 0x10: return "RCVRY_IDLE"; - case 0x11: return "L0"; - case 0x12: return "L0S"; - case 0x13: return "L123_SEND_EIDLE"; - case 0x14: return "L1_IDLE"; - case 0x15: return "L2_IDLE"; - case 0x16: return "L2_WAKE"; - case 0x17: return "DISABLED_ENTRY"; - case 0x18: return "DISABLED_IDLE"; - case 0x19: return "DISABLED"; - case 0x1A: return "LPBK_ENTRY"; - case 0x1B: return "LPBK_ACTIVE"; - case 0x1C: return "LPBK_EXIT"; - case 0x1D: return "LPBK_EXIT_TIMEOUT"; - case 0x1E: return "HOT_RESET_ENTRY"; - case 0x1F: return "HOT_RESET"; - case 0x20: return "RCVRY_EQ0"; - case 0x21: return "RCVRY_EQ1"; - case 0x22: return "RCVRY_EQ2"; - case 0x23: return "RCVRY_EQ3"; + case 0x00: return "Detect (QUIET)"; + case 0x01: return "Detect (ACTIVE)"; + case 0x02: return "Polling (ACTIVE)"; + case 0x03: return "Polling (COMPLIANCE)"; + case 0x04: return "Polling (CONFIG)"; + case 0x05: return "Detect (PRE_DETECT_QUIET)"; + case 0x06: return "Detect (DETECT_WAIT)"; + case 0x07: return "Configuration (LINKWD_START)"; + case 0x08: return "Configuration (LINKWD_ACCEPT)"; + case 0x09: return "Configuration (LANENUM_WAIT)"; + case 0x0A: return "Configuration (LANENUM_ACCEPT)"; + case 0x0B: return "Configuration (COMPLETE)"; + case 0x0C: return "Configuration (IDLE)"; + case 0x0D: return "Recovery (LOCK)"; + case 0x0E: return "Recovery (SPEED)"; + case 0x0F: return "Recovery (RCVRCFG)"; + case 0x10: return "Recovery (IDLE)"; + case 0x11: return "L0 (ACTIVE)"; + case 0x12: return "L0s (IDLE)"; + case 0x13: return "L1/L2/L3 (SEND_EIDLE)"; + case 0x14: return "L1 (IDLE)"; + case 0x15: return "L2 (IDLE)"; + case 0x16: return "L2 (WAKE)"; + case 0x17: return "Disabled (ENTRY)"; + case 0x18: return "Disabled (IDLE)"; + case 0x19: return "Disabled"; + case 0x1A: return "Loopback (ENTRY)"; + case 0x1B: return "Loopback (ACTIVE)"; + case 0x1C: return "Loopback (EXIT)"; + case 0x1D: return "Loopback (EXIT_TIMEOUT)"; + case 0x1E: return "Hot Reset (ENTRY)"; + case 0x1F: return "Hot Reset"; + case 0x20: return "Recovery (EQ0)"; + case 0x21: return "Recovery (EQ1)"; + case 0x22: return "Recovery (EQ2)"; + case 0x23: return "Recovery (EQ3)"; default: return "UNKNOWN"; } } From ba8277160f5330781d7d1020d3388d070c376aff Mon Sep 17 00:00:00 2001 From: BenReed161 Date: Wed, 28 Jan 2026 11:53:22 -0800 Subject: [PATCH 07/10] Fix issue with Gen6 redundant partitions Redundant partitions in Gen6 did not work as expected since it was not accounting for the lack of Riotcore paritions from past generation. Fixed code to account for this previous paritition in the data. Added redundant flag sets in the Gen6 fw part info --- cli/main.c | 8 ++++++-- lib/fw.c | 17 ++++++++++++++--- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/cli/main.c b/cli/main.c index 13782f13..4adc7b2e 100644 --- a/cli/main.c +++ b/cli/main.c @@ -2242,8 +2242,8 @@ static int fw_redundant(int argc, char **argv) argconfig_parse(argc, argv, CMD_DESC_FW_REDUNDANT, opts, &cfg, sizeof(cfg)); - if (!switchtec_is_gen5(cfg.dev)) { - fprintf(stderr, "Setting the redundant flag is only supported on Gen5 switches\n"); + if (!switchtec_is_gen5(cfg.dev) && !switchtec_is_gen6(cfg.dev)) { + fprintf(stderr, "Setting the redundant flag is only supported on Gen5/6 switches\n"); return 1; } if (!cfg.bl2 && !cfg.key && !cfg.firmware && !cfg.config && !cfg.riotcore) { @@ -2254,6 +2254,10 @@ static int fw_redundant(int argc, char **argv) fprintf(stderr, "Set redundant flag to either set - 1 or unset - 0\n"); return 1; } + if (switchtec_is_gen6(cfg.dev) && cfg.riotcore) { + fprintf(stderr, "Setting riotcore partition is not supported on Gen6 switches\n"); + return 1; + } ret = switchtec_fw_set_redundant_flag(cfg.dev, cfg.key, cfg.riotcore, cfg.bl2, diff --git a/lib/fw.c b/lib/fw.c index d5e227de..da848816 100644 --- a/lib/fw.c +++ b/lib/fw.c @@ -306,7 +306,10 @@ static int set_redundant(struct switchtec_dev *dev, int type, int set) cmd.subcmd = MRPC_FWDNLD_SET_RDNDNT; cmd.redundant_val = set; - cmd.part_type = type; + if (switchtec_is_gen6(dev) && type != 1) + cmd.part_type = type - 1; + else + cmd.part_type = type; printf("%s redundant flag \t(%s)\n", set ? "Checking" : "Un-checking", part_types[type-1]); @@ -1443,12 +1446,12 @@ struct switchtec_flash_info_gen6 { uint8_t running_cfg_flag; uint8_t running_img_flag; uint8_t running_key_flag; - uint8_t rsvd2[3]; + uint8_t rsvd2[4]; uint8_t key_redundant_flag; uint8_t bl2_redundant_flag; uint8_t cfg_redundant_flag; uint8_t img_redundant_flag; - uint8_t rsvd3[3]; + uint8_t rsvd3[2]; uint32_t rsvd4[9]; struct switchtec_flash_part_info_gen4 map0, map1, keyman0, keyman1, bl20, bl21, cfg0, cfg1, img0, img1, @@ -1629,27 +1632,35 @@ static int switchtec_fw_part_info_gen6(struct switchtec_dev *dev, part_info = &all->map1; break; case SWITCHTEC_FW_PART_ID_G6_KEY0: + inf->redundant = all->key_redundant_flag; part_info = &all->keyman0; break; case SWITCHTEC_FW_PART_ID_G6_KEY1: + inf->redundant = all->key_redundant_flag; part_info = &all->keyman1; break; case SWITCHTEC_FW_PART_ID_G6_BL20: + inf->redundant = all->bl2_redundant_flag; part_info = &all->bl20; break; case SWITCHTEC_FW_PART_ID_G6_BL21: + inf->redundant = all->bl2_redundant_flag; part_info = &all->bl21; break; case SWITCHTEC_FW_PART_ID_G6_IMG0: + inf->redundant = all->img_redundant_flag; part_info = &all->img0; break; case SWITCHTEC_FW_PART_ID_G6_IMG1: + inf->redundant = all->img_redundant_flag; part_info = &all->img1; break; case SWITCHTEC_FW_PART_ID_G6_CFG0: + inf->redundant = all->cfg_redundant_flag; part_info = &all->cfg0; break; case SWITCHTEC_FW_PART_ID_G6_CFG1: + inf->redundant = all->cfg_redundant_flag; part_info = &all->cfg1; break; case SWITCHTEC_FW_PART_ID_G6_NVLOG: From aacd83bfb1a577ba4be2702f62480e9c978cc813 Mon Sep 17 00:00:00 2001 From: BenReed161 Date: Wed, 28 Jan 2026 15:35:16 -0800 Subject: [PATCH 08/10] Add support for bl2 recov images Added support for new header magic for the BL2 Recovery image process in Gen6. --- cli/main.c | 4 +++- lib/fw.c | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/cli/main.c b/cli/main.c index 4adc7b2e..e4d6a884 100644 --- a/cli/main.c +++ b/cli/main.c @@ -1856,8 +1856,10 @@ enum switchtec_fw_type check_and_print_fw_image(int img_fd, fprintf(stderr, "%s: Invalid image file format\n", img_filename); return ret; + } else if (ret > 0) { + return SWITCHTEC_FW_TYPE_BL2; } - + printf("File: %s\n", get_basename(img_filename)); printf("Gen: %s\n", switchtec_fw_image_gen_str(&info)); printf("Type: %s\n", switchtec_fw_image_type(&info)); diff --git a/lib/fw.c b/lib/fw.c index da848816..b98448e4 100644 --- a/lib/fw.c +++ b/lib/fw.c @@ -1059,6 +1059,8 @@ int switchtec_fw_file_info(int fd, struct switchtec_fw_image_info *info) return switchtec_fw_file_info_gen3(fd, info); } else if (!strncmp(magic, "MSCC", sizeof(magic))) { return switchtec_fw_file_info_gen45(fd, info); + } else if (!strncmp(magic, "DCBI", sizeof(magic))) { + return 1; } else { errno = ENOEXEC; return -1; From 746b0405fb774e1da7c2eb6edd0c318902d5ead8 Mon Sep 17 00:00:00 2001 From: BenReed161 Date: Wed, 28 Jan 2026 15:49:38 -0800 Subject: [PATCH 09/10] Cleanup fw-read command Remove redundant config arg from fw-read command. Re-write command description to reflect the command behavior. --- cli/main.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cli/main.c b/cli/main.c index e4d6a884..a0f4ea05 100644 --- a/cli/main.c +++ b/cli/main.c @@ -2276,7 +2276,7 @@ static int fw_redundant(int argc, char **argv) return ret; } -#define CMD_DESC_FW_READ "read a firmware image from flash" +#define CMD_DESC_FW_READ "read a firmware image from flash, default(no args) reads main firmware image" static int fw_read(int argc, char **argv) { @@ -2308,8 +2308,6 @@ static int fw_read(int argc, char **argv) "assume yes when prompted"}, {"inactive", 'i', "", CFG_NONE, &cfg.inactive, no_argument, "read the inactive partition"}, - {"data", 'd', "", CFG_NONE, &cfg.data, no_argument, - "read the data/config partiton instead of the main firmware"}, {"config", 'c', "", CFG_NONE, &cfg.data, no_argument, "read the data/config partiton instead of the main firmware"}, {"bl2", 'b', "", CFG_NONE, &cfg.bl2, no_argument, From 00e32bd5397e16894b8ed276208f7fa8e0968a06 Mon Sep 17 00:00:00 2001 From: BenReed161 Date: Tue, 3 Feb 2026 12:04:16 -0800 Subject: [PATCH 10/10] Fix issue with BL2 stage fw toggle Gen6 Seperate download commands to fix toggle issue seen in i2c interface when in the BL2 stage. --- lib/fw.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/lib/fw.c b/lib/fw.c index b98448e4..33dbb790 100644 --- a/lib/fw.c +++ b/lib/fw.c @@ -459,6 +459,7 @@ int switchtec_fw_toggle_active_partition(struct switchtec_dev *dev, { uint32_t cmd_id; size_t cmd_size; + int ret; struct { uint8_t subcmd; uint8_t toggle_fw; @@ -466,26 +467,40 @@ int switchtec_fw_toggle_active_partition(struct switchtec_dev *dev, uint8_t toggle_bl2; uint8_t toggle_key; uint8_t toggle_riotcore; + uint16_t reserved; } cmd; if (switchtec_boot_phase(dev) == SWITCHTEC_BOOT_PHASE_BL2) { + cmd_size = sizeof(cmd); cmd_id = get_fw_tx_id(dev); cmd.subcmd = MRPC_FW_TX_TOGGLE; - } else { - cmd_id = MRPC_FWDNLD; - cmd.subcmd = MRPC_FWDNLD_TOGGLE; + cmd.toggle_bl2 = !!toggle_bl2; + ret = switchtec_cmd(dev, cmd_id, &cmd, cmd_size, NULL, 0); + if (ret) + return ret; + cmd.toggle_bl2 = 0; + cmd.toggle_fw = !!toggle_fw; + ret = switchtec_cmd(dev, cmd_id, &cmd, cmd_size, NULL, 0); + if (ret) + return ret; + cmd.toggle_fw = 0; + cmd.toggle_cfg = !!toggle_cfg; + ret = switchtec_cmd(dev, cmd_id, &cmd, cmd_size, NULL, 0); + if (ret) + return ret; + + return 0; } - + + cmd_id = MRPC_FWDNLD; + cmd.subcmd = MRPC_FWDNLD_TOGGLE; cmd.toggle_bl2 = !!toggle_bl2; cmd.toggle_key = !!toggle_key; cmd.toggle_fw = !!toggle_fw; cmd.toggle_cfg = !!toggle_cfg; - if (switchtec_is_gen5(dev)) { + if (switchtec_is_gen5(dev)) cmd.toggle_riotcore = !!toggle_riotcore; - cmd_size = sizeof(cmd); - } else { - cmd_size = sizeof(cmd) - 1; - } + cmd_size = sizeof(cmd); return switchtec_cmd(dev, cmd_id, &cmd, cmd_size, NULL, 0);