From 4f86533a1ee9169986ce1bb8a4acc0becc3139b3 Mon Sep 17 00:00:00 2001 From: BenReed161 Date: Thu, 13 Mar 2025 12:57:36 -0700 Subject: [PATCH] Added support for ltssm diag command for gen5 Added new set of function to handle gen5 ltssm log requests. Data structures to handle I/O of the MRPC data have been updated to gen5 structures and offsets. Sub command ID has been updated to gen5 subcommand IDs. Added buffering option for logs larger than 61 entries to send multiple ltssm MRPC commands as per the spec. --- cli/diag.c | 8 +- inc/switchtec/diag.h | 7 ++ inc/switchtec/mrpc.h | 6 ++ lib/diag.c | 203 +++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 214 insertions(+), 10 deletions(-) diff --git a/cli/diag.c b/cli/diag.c index 97cf1115..9644da7d 100644 --- a/cli/diag.c +++ b/cli/diag.c @@ -126,16 +126,20 @@ static int ltssm_log(int argc, char **argv) { DEVICE_OPTION, PORT_OPTION, {} }; - struct switchtec_diag_ltssm_log output[128]; int ret; int port; - int log_count = 128; int i; ret = diag_parse_common_cfg(argc, argv, CMD_DESC_LTSSM_LOG, &cfg, opts); if (ret) return ret; + + int log_count = 512; + if (switchtec_is_gen4(cfg.dev)) + log_count = 128; + + struct switchtec_diag_ltssm_log output[log_count]; if (switchtec_is_gen3(cfg.dev)) { fprintf (stderr, diff --git a/inc/switchtec/diag.h b/inc/switchtec/diag.h index 91963810..5e137d5d 100644 --- a/inc/switchtec/diag.h +++ b/inc/switchtec/diag.h @@ -272,5 +272,12 @@ struct switchtec_diag_cross_hair_get { }; }; +struct switchtec_diag_ltssm_log_dmp_out { + uint32_t dw0; + uint32_t ram_timestamp; + uint32_t unused; + uint32_t arc; +}; + #endif /**@}*/ diff --git a/inc/switchtec/mrpc.h b/inc/switchtec/mrpc.h index b5b7882a..c2a5d051 100644 --- a/inc/switchtec/mrpc.h +++ b/inc/switchtec/mrpc.h @@ -276,6 +276,12 @@ enum mrpc_sub_cmd { MRPC_CROSS_HAIR_ENABLE = 0, MRPC_CROSS_HAIR_DISABLE = 1, MRPC_CROSS_HAIR_GET = 2, + + MRPC_LTMON_GET_STATUS_GEN4 = 13, + MRPC_LTMON_FREEZE = 14, + MRPC_LTMON_LOG_DUMP_GEN4 = 15, + MRPC_LTMON_GET_STATUS_GEN5 = 20, + MRPC_LTMON_LOG_DUMP_GEN5 = 21, }; #endif diff --git a/lib/diag.c b/lib/diag.c index af6ec5b7..eb9e8157 100644 --- a/lib/diag.c +++ b/lib/diag.c @@ -28,6 +28,7 @@ */ #define SWITCHTEC_LIB_CORE +#define SWITCHTEC_LTSSM_MAX_LOGS 61 #include "switchtec_priv.h" #include "switchtec/diag.h" @@ -906,17 +907,183 @@ int switchtec_diag_refclk_ctl(struct switchtec_dev *dev, int stack_id, bool en) return switchtec_cmd(dev, MRPC_REFCLK_S, &cmd, sizeof(cmd), NULL, 0); } +static void switchtec_diag_ltssm_set_log_data(struct switchtec_diag_ltssm_log + *log_data, + struct switchtec_diag_ltssm_log_dmp_out + *log_dump_out_ptr, + int curr_idx, uint16_t num_of_logs) +{ + uint32_t dw0; + uint32_t timestamp; + + int major; + int minor; + int rate; + + for (int j = 0; j < num_of_logs; j++) { + dw0 = log_dump_out_ptr[j].dw0; + timestamp = log_dump_out_ptr[j].ram_timestamp; + + rate = (dw0 >> 13) & 0x7; + major = (dw0 >> 7) & 0x3f; + minor = (dw0 >> 3) & 0xf; + + log_data[curr_idx + j].timestamp = timestamp; + log_data[curr_idx + j].link_rate = switchtec_gen_transfers[rate+1]; + log_data[curr_idx + j].link_state = major | (minor << 8); + } +} + /** - * @brief Get the LTSSM log of a port on a switchtec device + * @brief Get the LTSSM log of a port on a gen5 switchtec device * @param[in] dev Switchtec device handle * @param[in] port Switchtec Port * @param[inout] log_count number of log entries * @param[out] log A pointer to an array containing the log * */ -int switchtec_diag_ltssm_log(struct switchtec_dev *dev, - int port, int *log_count, - struct switchtec_diag_ltssm_log *log_data) +static int switchtec_diag_ltssm_log_gen5(struct switchtec_dev *dev, + int port, int *log_count, + struct switchtec_diag_ltssm_log *log_data) +{ + struct { + uint8_t sub_cmd; + uint8_t port; + uint8_t freeze; + uint8_t unused; + } ltssm_freeze; + + struct { + uint8_t sub_cmd; + uint8_t port; + } status; + + struct { + uint16_t log_count; + uint16_t w0_trigger_count; + uint16_t w1_trigger_count; + } status_output; + + struct { + uint8_t sub_cmd; + uint8_t port; + uint16_t log_index; + uint16_t no_of_logs; + } log_dump; + + uint8_t log_buffer[1024]; + + struct switchtec_diag_ltssm_log_dmp_out *log_dump_out_ptr = NULL; + + int ret; + int log_dmp_size = sizeof(struct switchtec_diag_ltssm_log_dmp_out); + + /* freeze logs */ + ltssm_freeze.sub_cmd = MRPC_LTMON_FREEZE; + ltssm_freeze.port = port; + ltssm_freeze.freeze = 1; + + ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, <ssm_freeze, + sizeof(ltssm_freeze), NULL, 0); + if (ret) + return ret; + + /* get number of entries */ + status.sub_cmd = MRPC_LTMON_GET_STATUS_GEN5; + status.port = port; + ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &status, + sizeof(status), &status_output, + sizeof(status_output)); + if (ret) + return ret; + + *log_count = status_output.log_count; + + /* get log data */ + log_dump.sub_cmd = MRPC_LTMON_LOG_DUMP_GEN5; + log_dump.port = port; + log_dump.log_index = 0; + log_dump.no_of_logs = *log_count; + + if(log_dump.no_of_logs <= SWITCHTEC_LTSSM_MAX_LOGS) { + /* Single buffer log case */ + ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &log_dump, + sizeof(log_dump), &log_buffer[0], + log_dump.no_of_logs * log_dmp_size + 4); + if (ret) + return ret; + log_dump_out_ptr = + (struct switchtec_diag_ltssm_log_dmp_out *) + &(log_buffer[4]); + + switchtec_diag_ltssm_set_log_data(log_data, + log_dump_out_ptr, + 0, log_dump.no_of_logs); + } else { + /* Multiple buffer log case */ + int buff_count = log_dump.no_of_logs / SWITCHTEC_LTSSM_MAX_LOGS; + int curr_idx = 0; + int buffer_size = SWITCHTEC_LTSSM_MAX_LOGS * log_dmp_size + 4; + + for (int i = 0; i < buff_count; i++) { + log_dump.no_of_logs = SWITCHTEC_LTSSM_MAX_LOGS; + ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, + &log_dump, sizeof(log_dump), + &log_buffer[0], buffer_size); + if (ret) + return ret; + log_dump_out_ptr = + (struct switchtec_diag_ltssm_log_dmp_out *) + &(log_buffer[4]); + + switchtec_diag_ltssm_set_log_data(log_data, + log_dump_out_ptr, + curr_idx, + log_dump.no_of_logs); + curr_idx += SWITCHTEC_LTSSM_MAX_LOGS; + log_dump.log_index = curr_idx; + } + if (*log_count % SWITCHTEC_LTSSM_MAX_LOGS) { + log_dump.no_of_logs = *log_count - curr_idx; + buffer_size = log_dump.no_of_logs * log_dmp_size + 4; + ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, + &log_dump, sizeof(log_dump), + &log_buffer[0], buffer_size); + if (ret) + return ret; + log_dump_out_ptr = + (struct switchtec_diag_ltssm_log_dmp_out *) + &(log_buffer[4]); + + switchtec_diag_ltssm_set_log_data(log_data, + log_dump_out_ptr, + curr_idx, + log_dump.no_of_logs); + } + } + + /* unfreeze logs */ + ltssm_freeze.sub_cmd = MRPC_LTMON_FREEZE; + ltssm_freeze.port = port; + ltssm_freeze.freeze = 0; + + ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, <ssm_freeze, + sizeof(ltssm_freeze), NULL, 0); + + return ret; +} + +/** + * @brief Get the LTSSM log of a port on a gen4 switchtec device + * @param[in] dev Switchtec device handle + * @param[in] port Switchtec Port + * @param[inout] log_count number of log entries + * @param[out] log A pointer to an array containing the log + * + */ +static int switchtec_diag_ltssm_log_gen4(struct switchtec_dev *dev, + int port, int *log_count, + struct switchtec_diag_ltssm_log *log_data) { struct { uint8_t sub_cmd; @@ -955,7 +1122,7 @@ int switchtec_diag_ltssm_log(struct switchtec_dev *dev, int i; /* freeze logs */ - ltssm_freeze.sub_cmd = 14; + ltssm_freeze.sub_cmd = MRPC_LTMON_FREEZE; ltssm_freeze.port = port; ltssm_freeze.freeze = 1; @@ -965,7 +1132,7 @@ int switchtec_diag_ltssm_log(struct switchtec_dev *dev, return ret; /* get number of entries */ - status.sub_cmd = 13; + status.sub_cmd = MRPC_LTMON_GET_STATUS_GEN4; status.port = port; ret = switchtec_cmd(dev, MRPC_DIAG_PORT_LTSSM_LOG, &status, sizeof(status), &status_output, @@ -977,7 +1144,7 @@ int switchtec_diag_ltssm_log(struct switchtec_dev *dev, *log_count = status_output.log_num; /* get log data */ - log_dump.sub_cmd = 15; + log_dump.sub_cmd = MRPC_LTMON_LOG_DUMP_GEN4; log_dump.port = port; log_dump.log_index = 0; log_dump.no_of_logs = *log_count; @@ -1017,7 +1184,7 @@ int switchtec_diag_ltssm_log(struct switchtec_dev *dev, } /* unfreeze logs */ - ltssm_freeze.sub_cmd = 14; + ltssm_freeze.sub_cmd = MRPC_LTMON_FREEZE; ltssm_freeze.port = port; ltssm_freeze.freeze = 0; @@ -1027,4 +1194,24 @@ int switchtec_diag_ltssm_log(struct switchtec_dev *dev, return ret; } +/** + * @brief Determine the generation and call the related LTSSM log func + * @param[in] dev Switchtec device handle + * @param[in] port Switchtec Port + * @param[inout] log_count number of log entries + * @param[out] log A pointer to an array containing the log + * + */ +int switchtec_diag_ltssm_log(struct switchtec_dev *dev, + int port, int *log_count, + struct switchtec_diag_ltssm_log *log_data) +{ + int ret; + if (switchtec_is_gen5(dev)) + ret = switchtec_diag_ltssm_log_gen5(dev, port, log_count, log_data); + else + ret = switchtec_diag_ltssm_log_gen4(dev, port, log_count, log_data); + return ret; +} + /**@}*/