X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=pcilmr.c;h=cb8bd77a04fded0a3d8c3c811aa040d538778717;hb=c76c7b8811598e8e62500e6b2c06e9fc64a14a23;hp=3c2f2502a002e9b0361d719358fe82322affe7ae;hpb=5648e3f67164f79efbaad88368587b83a175b3d4;p=pciutils.git diff --git a/pcilmr.c b/pcilmr.c index 3c2f250..cb8bd77 100644 --- a/pcilmr.c +++ b/pcilmr.c @@ -8,26 +8,29 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ -#include #include #include #include +#include #include "lmr/lmr.h" const char program_name[] = "pcilmr"; -enum mode { MARGIN, FULL }; +enum mode { MARGIN, FULL, SCAN }; static const char usage_msg[] - = "Usage:\n" + = "! Utility requires preliminary preparation of the system. Refer to the pcilmr man page !\n\n" + "Usage:\n" "pcilmr [--margin] [] ...\n" "pcilmr --full []\n" + "pcilmr --scan\n\n" "Device Specifier:\n" ":\t[:]:.\n\n" "Modes:\n" "--margin\t\tMargin selected Links\n" "--full\t\t\tMargin all ready for testing Links in the system (one by one)\n" + "--scan\t\t\tScan for Links available for margining\n\n" "Margining options:\n\n" "Margining Test settings:\n" "-c\t\t\tPrint Device Lane Margining Capabilities only. Do not run margining.\n" @@ -50,16 +53,19 @@ static const char usage_msg[] "-v \t\tSpecify maximum number of steps for Voltage Margining.\n" "Use only one of -T/-t options at the same time (same for -V/-v).\n" "Without these options utility will use MaxSteps from Device\n" - "capabilities as test limit.\n\n"; + "capabilities as test limit.\n\n" + "Margining Log settings:\n" + "-o \t\tSave margining results in csv form into the\n" + "\t\t\tspecified directory. Utility will generate file with the\n" + "\t\t\tname in form of 'lmr__Rx#_.csv'\n" + "\t\t\tfor each successfully tested receiver.\n"; static struct pci_dev * dev_for_filter(struct pci_access *pacc, char *filter) { struct pci_filter pci_filter; - char dev[17] = { 0 }; - strncpy(dev, filter, sizeof(dev) - 1); pci_filter_init(pacc, &pci_filter); - if (pci_filter_parse_slot(&pci_filter, dev)) + if (pci_filter_parse_slot(&pci_filter, filter)) die("Invalid device ID: %s\n", filter); if (pci_filter.bus == -1 || pci_filter.slot == -1 || pci_filter.func == -1) @@ -106,6 +112,36 @@ parse_csv_arg(char *arg, u8 *vals) return cnt; } +static void +scan_links(struct pci_access *pacc, bool only_ready) +{ + if (only_ready) + printf("Links ready for margining:\n"); + else + printf("Links with Lane Margining at the Receiver capabilities:\n"); + bool flag = true; + for (struct pci_dev *up = pacc->devices; up; up = up->next) + { + if (pci_find_cap(up, PCI_EXT_CAP_ID_LMR, PCI_CAP_EXTENDED)) + { + struct pci_dev *down = find_down_port_for_up(pacc, up); + + if (down && margin_verify_link(down, up)) + { + margin_log_bdfs(down, up); + if (!only_ready && (margin_check_ready_bit(down) || margin_check_ready_bit(up))) + printf(" - Ready"); + printf("\n"); + flag = false; + } + } + } + if (flag) + printf("Links not found or you don't have enough privileges.\n"); + pci_cleanup(pacc); + exit(0); +} + static u8 find_ready_links(struct pci_access *pacc, struct pci_dev **down_ports, struct pci_dev **up_ports, bool cnt_only) @@ -165,6 +201,9 @@ main(int argc, char **argv) bool run_margin = true; + char *dir_for_csv = NULL; + bool save_csv = false; + u64 total_steps = 0; pacc = pci_alloc(); @@ -185,7 +224,8 @@ main(int argc, char **argv) struct option long_options[] = { { .name = "margin", .has_arg = no_argument, .flag = NULL, .val = 0 }, - { .name = "full", .has_arg = no_argument, .flag = NULL, .val = 1 }, + { .name = "scan", .has_arg = no_argument, .flag = NULL, .val = 1 }, + { .name = "full", .has_arg = no_argument, .flag = NULL, .val = 2 }, { 0, 0, 0, 0 } }; int c; @@ -199,6 +239,12 @@ main(int argc, char **argv) mode = MARGIN; break; case 1: + mode = SCAN; + if (optind == argc) + scan_links(pacc, false); + optind--; + break; + case 2: mode = FULL; break; default: /* unknown option symbol */ @@ -207,7 +253,7 @@ main(int argc, char **argv) break; } - while ((c = getopt(argc, argv, ":r:e:l:cp:t:v:VT")) != -1) + while ((c = getopt(argc, argv, ":r:e:l:cp:t:v:VTo:")) != -1) { switch (c) { @@ -238,6 +284,10 @@ main(int argc, char **argv) case 'r': recvs_n = parse_csv_arg(optarg, recvs_arg); break; + case 'o': + dir_for_csv = optarg; + save_csv = true; + break; default: die("Invalid arguments\n\n%s", usage_msg); } @@ -410,6 +460,8 @@ main(int argc, char **argv) margin_log_bdfs(down_ports[i], up_ports[i]); printf(":\n\n"); margin_results_print_brief(results[i], results_n[i]); + if (save_csv) + margin_results_save_csv(results[i], results_n[i], dir_for_csv, up_ports[i]); printf("\n"); } }