2 * The PCI Utilities -- Parse pcilmr utility arguments
4 * Copyright (c) 2024 KNS Group LLC (YADRO)
6 * Can be freely distributed and used under the terms of the GNU GPL v2+.
8 * SPDX-License-Identifier: GPL-2.0-or-later
18 = "! Utility requires preliminary preparation of the system. Refer to the pcilmr man page !\n\n"
20 "pcilmr [--margin] [<margining options>] <downstream component> ...\n"
21 "pcilmr --full [<margining options>]\n"
24 "<device/component>:\t[<domain>:]<bus>:<dev>.<func>\n\n"
26 "--margin\t\tMargin selected Links\n"
27 "--full\t\t\tMargin all ready for testing Links in the system (one by one)\n"
28 "--scan\t\t\tScan for Links available for margining\n\n"
29 "Margining options:\n\n"
30 "Margining Test settings:\n"
31 "-c\t\t\tPrint Device Lane Margining Capabilities only. Do not run margining.\n"
32 "-l <lane>[,<lane>...]\tSpecify lanes for margining. Default: all link lanes.\n"
33 "\t\t\tRemember that Device may use Lane Reversal for Lane numbering.\n"
34 "\t\t\tHowever, utility uses logical lane numbers in arguments and for logging.\n"
35 "\t\t\tUtility will automatically determine Lane Reversal and tune its calls.\n"
36 "-e <errors>\t\tSpecify Error Count Limit for margining. Default: 4.\n"
37 "-r <recvn>[,<recvn>...]\tSpecify Receivers to select margining targets.\n"
38 "\t\t\tDefault: all available Receivers (including Retimers).\n"
39 "-p <parallel_lanes>\tSpecify number of lanes to margin simultaneously.\n"
41 "\t\t\tAccording to spec it's possible for Receiver to margin up\n"
42 "\t\t\tto MaxLanes + 1 lanes simultaneously, but usually this works\n"
43 "\t\t\tbad, so this option is for experiments mostly.\n"
44 "-T\t\t\tTime Margining will continue until the Error Count is no more\n"
45 "\t\t\tthan an Error Count Limit. Use this option to find Link limit.\n"
46 "-V\t\t\tSame as -T option, but for Voltage.\n"
47 "-t <steps>\t\tSpecify maximum number of steps for Time Margining.\n"
48 "-v <steps>\t\tSpecify maximum number of steps for Voltage Margining.\n"
49 "Use only one of -T/-t options at the same time (same for -V/-v).\n"
50 "Without these options utility will use MaxSteps from Device\n"
51 "capabilities as test limit.\n\n"
52 "Margining Log settings:\n"
53 "-o <directory>\t\tSave margining results in csv form into the\n"
54 "\t\t\tspecified directory. Utility will generate file with the\n"
55 "\t\t\tname in form of 'lmr_<downstream component>_Rx#_<timestamp>.csv'\n"
56 "\t\t\tfor each successfully tested receiver.\n";
58 static struct pci_dev *
59 dev_for_filter(struct pci_access *pacc, char *filter)
61 struct pci_filter pci_filter;
62 pci_filter_init(pacc, &pci_filter);
63 if (pci_filter_parse_slot(&pci_filter, filter))
64 die("Invalid device ID: %s\n", filter);
66 if (pci_filter.bus == -1 || pci_filter.slot == -1 || pci_filter.func == -1)
67 die("Invalid device ID: %s\n", filter);
69 if (pci_filter.domain == -1)
70 pci_filter.domain = 0;
72 for (struct pci_dev *p = pacc->devices; p; p = p->next)
74 if (pci_filter_match(&pci_filter, p))
78 die("No such PCI device: %s or you don't have enough privileges.\n", filter);
82 parse_csv_arg(char *arg, u8 *vals)
85 char *token = strtok(arg, ",");
88 vals[cnt] = atoi(token);
90 token = strtok(NULL, ",");
96 find_ready_links(struct pci_access *pacc, struct margin_link *links, bool cnt_only)
99 for (struct pci_dev *p = pacc->devices; p; p = p->next)
101 if (pci_find_cap(p, PCI_EXT_CAP_ID_LMR, PCI_CAP_EXTENDED) && margin_port_is_down(p))
103 struct pci_dev *down = NULL;
104 struct pci_dev *up = NULL;
105 margin_find_pair(pacc, p, &down, &up);
107 if (down && margin_verify_link(down, up)
108 && (margin_check_ready_bit(down) || margin_check_ready_bit(up)))
111 margin_fill_link(down, up, &(links[cnt]));
120 init_link_args(struct margin_link_args *link_args, struct margin_com_args *com_args)
122 memset(link_args, 0, sizeof(*link_args));
123 link_args->common = com_args;
124 link_args->parallel_lanes = 1;
128 parse_dev_args(int argc, char **argv, struct margin_link_args *args, u8 link_speed)
133 while ((c = getopt(argc, argv, "+r:l:p:t:v:VT")) != -1)
138 args->steps_t = atoi(optarg);
144 args->steps_v = atoi(optarg);
150 args->parallel_lanes = atoi(optarg);
153 args->lanes_n = parse_csv_arg(optarg, args->lanes);
156 args->recvs_n = parse_csv_arg(optarg, args->recvs);
159 die("Invalid arguments\n\n%s", usage);
168 margin_parse_util_args(struct pci_access *pacc, int argc, char **argv, enum margin_mode mode,
171 struct margin_com_args *com_args = xmalloc(sizeof(*com_args));
172 com_args->error_limit = 4;
173 com_args->run_margin = true;
174 com_args->verbosity = 1;
175 com_args->steps_utility = 0;
176 com_args->dir_for_csv = NULL;
177 com_args->save_csv = false;
180 while ((c = getopt(argc, argv, "+e:co:")) != -1)
185 com_args->run_margin = false;
188 com_args->error_limit = atoi(optarg);
191 com_args->dir_for_csv = optarg;
192 com_args->save_csv = true;
195 die("Invalid arguments\n\n%s", usage);
200 if (mode == FULL && optind != argc)
202 if (mode == MARGIN && optind == argc)
204 if (!status && argc > 1)
205 die("Invalid arguments\n\n%s", usage);
213 struct margin_link *links = NULL;
218 ports_n = find_ready_links(pacc, NULL, true);
220 die("Links not found or you don't have enough privileges.\n");
223 links = xmalloc(ports_n * sizeof(*links));
224 find_ready_links(pacc, links, false);
225 for (int i = 0; i < ports_n; i++)
226 init_link_args(&(links[i].args), com_args);
229 else if (mode == MARGIN)
231 while (optind != argc)
233 struct pci_dev *dev = dev_for_filter(pacc, argv[optind]);
235 links = xrealloc(links, (ports_n + 1) * sizeof(*links));
236 struct pci_dev *down;
238 if (!margin_find_pair(pacc, dev, &down, &up))
239 die("Cannot find pair for the specified device: %s\n", argv[optind]);
240 struct pci_cap *cap = pci_find_cap(down, PCI_CAP_ID_EXP, PCI_CAP_NORMAL);
242 die("Looks like you don't have enough privileges to access "
243 "Device Configuration Space.\nTry to run utility as root.\n");
244 if (!margin_fill_link(down, up, &(links[ports_n])))
246 margin_gen_bdfs(down, up, err, sizeof(err));
247 die("Link %s is not ready for margining.\n"
248 "Link data rate must be 16 GT/s or 32 GT/s.\n"
249 "Downstream Component must be at D0 PM state.\n",
252 init_link_args(&(links[ports_n].args), com_args);
253 parse_dev_args(argc, argv, &(links[ports_n].args),
254 links[ports_n].down_port.link_speed - 4);
259 die("Bug in the args parsing!\n");