Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions cli/diag.c
Original file line number Diff line number Diff line change
Expand Up @@ -2026,6 +2026,109 @@ static int refclk(int argc, char **argv)
return 0;
}

static int convert_str_to_dwords(char *str, uint32_t **dwords, int *num_dwords)
{
*num_dwords = 0;
const char *ptr = str;
int dword_len = 0;
while (*ptr != '\0') {
if (*ptr == '0' && *(ptr + 1) == 'x') {
(*num_dwords)++;
ptr += 2;
dword_len = 0;
}
while (*ptr != ' ' && *ptr != '\0') {
ptr++;
dword_len++;
}
if (dword_len > 8) {
printf("Entered dword longer than allowed\n");
return -1;
}
if (*ptr == ' ')
ptr++;
}

*dwords = (uint32_t *)malloc(*num_dwords * sizeof(uint32_t));
if (*dwords == NULL)
return -1;

ptr = str;
for (int i = 0; i < *num_dwords; i++) {
char *endptr;
(*dwords)[i] = (uint32_t)strtoul(ptr, &endptr, 0);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if user incorrectly input value like '0x0102030405' which exceeds a DW size?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we handle this somewhere else?

if (endptr == ptr || (*endptr != ' ' && *endptr != '\0')) {
free(*dwords);
return -1;
}
ptr = endptr;
while (*ptr == ' ')
ptr++;
}

return 0;
}

#define CMD_TLP_INJECT "Inject a raw TLP"

static int tlp_inject (int argc, char **argv)
{
int ret = 0;
uint32_t * raw_tlp_dwords = NULL;
int num_dwords = 0;
static struct {
struct switchtec_dev *dev;
int port_id;
int tlp_type;
int ecrc;
char * raw_tlp_data;
} cfg = {
.tlp_type = 0
};

const struct argconfig_options opts[] = {
DEVICE_OPTION,
{"port", 'p', "PORT_ID", CFG_NONNEGATIVE, &cfg.port_id,
required_argument, "destination port ID"},
{"tlp_type", 't', "TYPE", CFG_NONNEGATIVE, &cfg.tlp_type,
required_argument, "tlp type:\n0: P - Posted\n1: NP - Non-posted\n2: CP - Completion\n(default 0)"},
{"enable_ecrc", 'e', "", CFG_NONE, &cfg.ecrc, no_argument,
"Enable the ecrc to be included at the end of the input data (Default: disabled)"},
{"tlp_data", 'd', "\"DW0 DW1 ... DW131\"", CFG_STRING,
&cfg.raw_tlp_data, required_argument,
"DWs to be sent as part of the raw TLP (Maximum 132 DWs). Every DW must start with \'0x\'"},
{NULL}
};

argconfig_parse(argc, argv, CMD_TLP_INJECT, opts, &cfg, sizeof(cfg));

if (cfg.raw_tlp_data == NULL) {
fprintf(stderr, "Must set tlp data --tlp_data -d \n");
return -1;
}
ret = convert_str_to_dwords(cfg.raw_tlp_data, &raw_tlp_dwords,
&num_dwords);
if (ret) {
fprintf(stderr, "Error with tlp data provided \n");
return -1;
}
if (num_dwords > SWITCHTEC_DIAG_MAX_TLP_DWORDS) {
fprintf(stderr, "TLP data cannot exceed %d dwords \n",
SWITCHTEC_DIAG_MAX_TLP_DWORDS);
free(raw_tlp_dwords);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is not mentioned in the commit message. The free() call looks a bit suspicious but its removal should probably have some comments with it.

return -1;
}

ret = switchtec_tlp_inject(cfg.dev, cfg.port_id, cfg.tlp_type,
num_dwords, cfg.ecrc, raw_tlp_dwords);
if (ret != 0) {
switchtec_perror("tlp_inject");
return -1;
}

return 0;
}

static const struct cmd commands[] = {
CMD(crosshair, CMD_DESC_CROSS_HAIR),
CMD(eye, CMD_DESC_EYE),
Expand All @@ -2039,6 +2142,7 @@ static const struct cmd commands[] = {
CMD(rcvr_obj, CMD_DESC_RCVR_OBJ),
CMD(refclk, CMD_DESC_REF_CLK),
CMD(ltssm_log, CMD_DESC_LTSSM_LOG),
CMD(tlp_inject, CMD_TLP_INJECT),
{}
};

Expand Down
10 changes: 10 additions & 0 deletions inc/switchtec/diag.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
#ifndef LIBSWITCHTEC_DIAG_H
#define LIBSWITCHTEC_DIAG_H

#include "switchtec.h"

#include <stdint.h>

/**
Expand Down Expand Up @@ -279,5 +281,13 @@ struct switchtec_diag_ltssm_log_dmp_out {
uint32_t arc;
};

struct switchtec_tlp_inject_in {
uint32_t dest_port;
uint32_t tlp_type;
uint32_t tlp_length;
uint32_t ecrc;
uint32_t raw_tlp_data[SWITCHTEC_DIAG_MAX_TLP_DWORDS];
};

#endif
/**@}*/
5 changes: 4 additions & 1 deletion inc/switchtec/switchtec.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ struct switchtec_dev;
#define SWITCHTEC_PAX_ID_MASK 0x1f
#define SWITCHTEC_PAX_ID_LOCAL SWITCHTEC_PAX_ID_MASK

#define SWITCHTEC_DIAG_MAX_TLP_DWORDS 132

#ifdef __CHECKER__
#define __gas __attribute__((noderef, address_space(1)))
#else
Expand Down Expand Up @@ -1243,7 +1245,8 @@ int switchtec_diag_refclk_ctl(struct switchtec_dev *dev, int stack_id, bool en);
int switchtec_diag_ltssm_log(struct switchtec_dev *dev,
int port, int *log_count,
struct switchtec_diag_ltssm_log *log_data);

int switchtec_tlp_inject(struct switchtec_dev * dev, int port_id, int tlp_type,
int tlp_length, int ecrc, uint32_t * raw_tlp_data);
#ifdef __cplusplus
}
#endif
Expand Down
21 changes: 21 additions & 0 deletions lib/diag.c
Original file line number Diff line number Diff line change
Expand Up @@ -1214,4 +1214,25 @@ int switchtec_diag_ltssm_log(struct switchtec_dev *dev,
return ret;
}

int switchtec_tlp_inject(struct switchtec_dev * dev, int port_id, int tlp_type,
int tlp_length, int ecrc, uint32_t * raw_tlp_data)
{
uint32_t tlp_out;
int ret = 1;
struct switchtec_tlp_inject_in tlp_in = {
.dest_port = port_id,
.tlp_type = tlp_type,
.tlp_length = tlp_length,
.ecrc = ecrc
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For multi-byte field, need to handle endianness properly on input/output data.

};
for (int i = 0; i < tlp_in.tlp_length; i++) {
tlp_in.raw_tlp_data[i] = htole32(*(raw_tlp_data + i));
}
free(raw_tlp_data);

ret = switchtec_cmd(dev, MRPC_DIAG_TLP_INJECT, &tlp_in, sizeof(tlp_in),
&tlp_out, sizeof(tlp_out));
return ret;
}

/**@}*/