]> mj.ucw.cz Git - pciutils.git/blobdiff - pcilmr.c
Merge pull request #177 from OscarL/cache-loc-on-man-pages
[pciutils.git] / pcilmr.c
index 3c2f2502a002e9b0361d719358fe82322affe7ae..cb8bd77a04fded0a3d8c3c811aa040d538778717 100644 (file)
--- a/pcilmr.c
+++ b/pcilmr.c
@@ -8,26 +8,29 @@
  *     SPDX-License-Identifier: GPL-2.0-or-later
  */
 
-#include <getopt.h>
 #include <memory.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #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] [<margining options>] <downstream component> ...\n"
     "pcilmr --full [<margining options>]\n"
+    "pcilmr --scan\n\n"
     "Device Specifier:\n"
     "<device/component>:\t[<domain>:]<bus>:<dev>.<func>\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 <steps>\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 <directory>\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_<downstream component>_Rx#_<timestamp>.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");
         }
     }