Skip to content

Commit 3beebe7

Browse files
Chetana2791BenReed161
authored andcommitted
Add Link error injection commands
Add new link error injection commands introduced with gen5 allows the user to inject a link error into a physical port. List of Errors: - DLLP - DLLP CRC - TLP LCRC - TLP seq num err - ACK/NAK err - Credit timeout err Include the inject header file for switchtec library to invoke the link inject error options.
1 parent 6328dc5 commit 3beebe7

File tree

5 files changed

+424
-0
lines changed

5 files changed

+424
-0
lines changed

cli/diag.c

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2194,6 +2194,160 @@ static int aer_event_gen(int argc, char **argv)
21942194
return 0;
21952195
}
21962196

2197+
#define CMD_DESC_LNKERR_INJECT "Inject a link error"
2198+
2199+
static int linkerr_inject(int argc, char ** argv)
2200+
{
2201+
int ret = 0;
2202+
uint32_t * dllp_data_dword = NULL;
2203+
int num_dwords = 0;
2204+
static struct {
2205+
struct switchtec_dev *dev;
2206+
int inject_dllp;
2207+
int inject_dllp_crc;
2208+
int inject_tlp_lcrc;
2209+
int inject_tlp_seq;
2210+
int inject_nack;
2211+
int inject_cto;
2212+
uint8_t enable;
2213+
uint8_t count;
2214+
uint16_t dllp_rate;
2215+
uint16_t tlp_rate;
2216+
uint16_t seq_num;
2217+
char * dllp_data;
2218+
int phy_port;
2219+
} cfg = {};
2220+
2221+
const struct argconfig_options opts[] = {
2222+
DEVICE_OPTION,
2223+
{"dllp", 'd', "", CFG_NONE, &cfg.inject_dllp,
2224+
no_argument, "Inject a DLLP"},
2225+
{"dllp-crc", 'D', "", CFG_NONE, &cfg.inject_dllp_crc,
2226+
no_argument, "Inject a DLLP CRC error"},
2227+
{"tlp-lcrc", 'l', "", CFG_NONE, &cfg.inject_tlp_lcrc,
2228+
no_argument, "Inject a TLP LCRC error"},
2229+
{"tlp-seq", 's', "", CFG_NONE, &cfg.inject_tlp_seq,
2230+
no_argument, "Inject a TLP Sequence Number error"},
2231+
{"nack", 'n', "", CFG_NONE, &cfg.inject_nack, no_argument,
2232+
"Inject an ACK to NACK error"},
2233+
{"cto", 't', "", CFG_NONE, &cfg.inject_cto, no_argument,
2234+
"Inject a TLP Credit Timeout"},
2235+
{"port", 'p', "", CFG_NONNEGATIVE, &cfg.phy_port,
2236+
required_argument, "physical port ID, default: port 0"},
2237+
{"enable", 'e', "", CFG_NONNEGATIVE, &cfg.enable,
2238+
required_argument, "enable DLLP CRC Error Injection or TLP LCRC Error Injection, default: 0"},
2239+
{"data", 'i', "", CFG_STRING, &cfg.dllp_data, required_argument,
2240+
"DLLP data to inject, a single dword in hex prefixed with \"0x\""},
2241+
{"seq_num", 'S', "", CFG_NONNEGATIVE, &cfg.seq_num,
2242+
required_argument, "sequence number of ACK to be replaced by NACK (0-4095)"},
2243+
{"count", 'c', "", CFG_NONNEGATIVE, &cfg.count,
2244+
required_argument, "number of times to replace ACK with NACK (0-255)"},
2245+
{"dllp-crc-rate", 'r', "", CFG_NONNEGATIVE, &cfg.dllp_rate,
2246+
required_argument, "valid range (0-4096). errors are injected at intervals of rate x 256 x clk "},
2247+
{"tlp-lcrc-rate", 'R', "", CFG_NONNEGATIVE, &cfg.tlp_rate,
2248+
required_argument, "valid range (0-7). Ex. rate = 1 -> every other TLP has an error"},
2249+
{NULL}
2250+
};
2251+
2252+
argconfig_parse(argc, argv, CMD_DESC_LNKERR_INJECT, opts, &cfg,
2253+
sizeof(cfg));
2254+
2255+
uint8_t *ptr = (uint8_t *)&cfg + 5;
2256+
int total_en = 0;
2257+
for (size_t i = 0; i < 6; i++) {
2258+
ptr += 3;
2259+
if (ptr[i] == 1)
2260+
total_en++;
2261+
}
2262+
if (total_en > 1) {
2263+
fprintf(stderr, "Cannot enable more than one link error injection command at a time.\n");
2264+
return -1;
2265+
}
2266+
if (total_en == 0) {
2267+
fprintf(stderr, "Must enable one link error injection command.\n");
2268+
return -1;
2269+
}
2270+
2271+
if (cfg.enable && !(cfg.inject_dllp_crc || cfg.inject_tlp_lcrc))
2272+
printf("Ignoring -e enable flag, not valid for the currently selected command.\n");
2273+
if (!cfg.inject_nack && cfg.count)
2274+
printf("Ignoring -c flag, not valid for the currently selected command.\n");
2275+
if (!cfg.inject_nack && cfg.seq_num)
2276+
printf("Ignoring -S flag, not valid for the currently selected command.\n");
2277+
if (!cfg.inject_tlp_lcrc && cfg.tlp_rate)
2278+
printf("Ignoring -R flag, not valid for the currently selected command.\n");
2279+
if (!cfg.inject_dllp_crc && cfg.dllp_rate)
2280+
printf("Ignoring -r flag, not valid for the currently selected command.\n");
2281+
if (!cfg.inject_dllp && cfg.dllp_data) {
2282+
printf("Ignoring -i flag, not valid for the currently selected command.\n");
2283+
} else if (cfg.inject_dllp && cfg.dllp_data) {
2284+
ret = convert_str_to_dwords(cfg.dllp_data, &dllp_data_dword,
2285+
&num_dwords);
2286+
if (ret) {
2287+
fprintf(stderr, "Error with DLLP data provided\n");
2288+
return -1;
2289+
}
2290+
if (num_dwords == 0) {
2291+
fprintf(stderr, "Must provide a single valid DLLP data dword\n");
2292+
free(dllp_data_dword);
2293+
return -1;
2294+
}
2295+
}
2296+
2297+
if (cfg.dllp_rate && cfg.tlp_rate) {
2298+
fprintf(stderr, "Cannot enable both rate configurations.\n");
2299+
return -1;
2300+
}
2301+
2302+
if (cfg.inject_dllp) {
2303+
ret = switchtec_inject_err_dllp(cfg.dev, cfg.phy_port,
2304+
cfg.dllp_data != NULL ? *dllp_data_dword : 0);
2305+
free(dllp_data_dword);
2306+
}
2307+
if (cfg.inject_dllp_crc) {
2308+
if (cfg.dllp_rate > 4096) {
2309+
fprintf(stderr, "DLLP CRC rate out of range. Valid range is 0-4095.\n");
2310+
return -1;
2311+
}
2312+
ret = switchtec_inject_err_dllp_crc(cfg.dev, cfg.phy_port,
2313+
cfg.enable, cfg.dllp_rate);
2314+
}
2315+
if (cfg.inject_tlp_lcrc) {
2316+
if (cfg.tlp_rate > 7) {
2317+
fprintf(stderr, "TLP LCRC rate out of range. Valid range is 0-7.\n");
2318+
return -1;
2319+
}
2320+
ret = switchtec_inject_err_tlp_lcrc(cfg.dev, cfg.phy_port,
2321+
cfg.enable, cfg.tlp_rate);
2322+
if (ret)
2323+
return -1;
2324+
}
2325+
if (cfg.inject_tlp_seq)
2326+
ret = switchtec_inject_err_tlp_seq_num(cfg.dev, cfg.phy_port);
2327+
if (cfg.inject_nack) {
2328+
if (cfg.seq_num > 4095) {
2329+
fprintf(stderr, "Sequence number out of range. Valid range is 0-4095).\n");
2330+
return -1;
2331+
}
2332+
if (cfg.count > 255) {
2333+
fprintf(stderr, "Count out of range. Valid range is 0-255\n");
2334+
return -1;
2335+
}
2336+
ret = switchtec_inject_err_ack_nack(cfg.dev, cfg.phy_port,
2337+
cfg.seq_num, cfg.count);
2338+
}
2339+
if (cfg.inject_cto) {
2340+
if (!switchtec_is_gen5(cfg.dev)) {
2341+
fprintf(stderr, "Credit timeout error injection is only supported on Gen5.\n");
2342+
return -1;
2343+
}
2344+
ret = switchtec_inject_err_cto(cfg.dev, cfg.phy_port);
2345+
}
2346+
2347+
switchtec_perror("linkerr-inject");
2348+
return ret;
2349+
}
2350+
21972351
static const struct cmd commands[] = {
21982352
CMD(crosshair, CMD_DESC_CROSS_HAIR),
21992353
CMD(eye, CMD_DESC_EYE),
@@ -2209,6 +2363,7 @@ static const struct cmd commands[] = {
22092363
CMD(ltssm_log, CMD_DESC_LTSSM_LOG),
22102364
CMD(tlp_inject, CMD_TLP_INJECT),
22112365
CMD(aer_event_gen, CMD_DESC_AER_EVENT_GEN),
2366+
CMD(linkerr_inject, CMD_DESC_LNKERR_INJECT),
22122367
{}
22132368
};
22142369

inc/switchtec/inject.h

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Microsemi Switchtec(tm) PCIe Management Library
3+
* Copyright (c) 2025, Microsemi Corporation
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a
6+
* copy of this software and associated documentation files (the "Software"),
7+
* to deal in the Software without restriction, including without limitation
8+
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
9+
* and/or sell copies of the Software, and to permit persons to whom the
10+
* Software is furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included
13+
* in all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16+
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18+
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19+
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20+
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21+
* OTHER DEALINGS IN THE SOFTWARE.
22+
*
23+
*/
24+
25+
#include <switchtec/switchtec.h>
26+
#include <stdint.h>
27+
28+
struct switchtec_lnkerr_dllp_in {
29+
uint8_t subcmd;
30+
uint8_t phys_port_id;
31+
uint8_t resvd[2];
32+
uint32_t data;
33+
};
34+
35+
struct switchtec_lnkerr_dllp_crc_in {
36+
uint8_t subcmd;
37+
uint8_t phys_port_id;
38+
uint8_t enable;
39+
uint8_t resvd1;
40+
uint16_t rate;
41+
uint8_t resvd2[2];
42+
};
43+
44+
struct switchtec_lnkerr_tlp_lcrc_gen5_in {
45+
uint8_t subcmd;
46+
uint8_t phys_port_id;
47+
uint8_t enable;
48+
uint8_t resvd1;
49+
uint8_t rate;
50+
uint8_t resvd[3];
51+
};
52+
53+
struct switchtec_lnkerr_tlp_lcrc_gen4_in {
54+
uint8_t subcmd;
55+
uint8_t phys_port_id;
56+
uint8_t enable;
57+
uint8_t rate;
58+
};
59+
60+
struct switchtec_lnkerr_tlp_seqn_in {
61+
uint8_t subcmd;
62+
uint8_t phys_port_id;
63+
uint8_t resvd[2];
64+
};
65+
66+
struct switchtec_lnkerr_ack_nack_in {
67+
uint8_t subcmd;
68+
uint8_t phys_port_id;
69+
uint8_t resvd1[2];
70+
uint16_t seq_num;
71+
uint8_t count;
72+
uint8_t resvd2;
73+
};
74+
75+
struct switchtec_lnkerr_cto_in {
76+
uint8_t subcmd;
77+
uint8_t phys_port_id;
78+
uint8_t resvd[2];
79+
};

inc/switchtec/mrpc.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,13 @@ enum mrpc_sub_cmd {
283283
MRPC_LTMON_LOG_DUMP_GEN4 = 15,
284284
MRPC_LTMON_GET_STATUS_GEN5 = 20,
285285
MRPC_LTMON_LOG_DUMP_GEN5 = 21,
286+
287+
MRPC_ERR_INJ_DLLP = 0,
288+
MRPC_ERR_INJ_DLLP_CRC = 1,
289+
MRPC_ERR_INJ_TLP_LCRC = 2,
290+
MRPC_ERR_INJ_TLP_SEQ = 3,
291+
MRPC_ERR_INJ_ACK_NACK = 4,
292+
MRPC_ERR_INJ_CTO = 5,
286293
};
287294

288295
#endif

inc/switchtec/switchtec.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "portable.h"
3636
#include "registers.h"
3737
#include "utils.h"
38+
#include "inject.h"
3839

3940
#include <stdbool.h>
4041
#include <stdlib.h>
@@ -423,6 +424,22 @@ int switchtec_calc_lane_mask(struct switchtec_dev *dev, int phys_port_id,
423424
int lane_id, int num_lanes, int *lane_mask,
424425
struct switchtec_status *port);
425426

427+
/**
428+
* @brief Return Link error injection command outputs for DLLP, DLLP_CRC,
429+
* LCRC, SEQ_NUM, ACK_NACK, CTO.
430+
*/
431+
432+
int switchtec_inject_err_dllp(struct switchtec_dev *dev, int phys_port_id,
433+
int data);
434+
int switchtec_inject_err_dllp_crc(struct switchtec_dev *dev, int phys_port_id,
435+
int enable, uint16_t rate);
436+
int switchtec_inject_err_tlp_lcrc(struct switchtec_dev *dev, int phys_port_id,
437+
int enable, uint8_t rate);
438+
int switchtec_inject_err_tlp_seq_num(struct switchtec_dev *dev, int phys_port_id);
439+
int switchtec_inject_err_ack_nack(struct switchtec_dev *dev, int phys_port_id,
440+
uint16_t seq_num, uint8_t count);
441+
int switchtec_inject_err_cto(struct switchtec_dev *dev, int phys_port_id);
442+
426443
/**
427444
* @brief Return whether a Switchtec device is a Gen 3 device.
428445
*/

0 commit comments

Comments
 (0)