diff mbox series

[v2,13/15] pciutils-pcilmr: Add option to save margining results in csv form

Message ID 20231227094504.32257-14-n.proshkin@yadro.com (mailing list archive)
State Handled Elsewhere
Headers show
Series pciutils: Add utility for Lane Margining | expand

Commit Message

Nikita Proshkin Dec. 27, 2023, 9:45 a.m. UTC
Reviewed-by: Sergei Miroshnichenko <s.miroshnichenko@yadro.com>
Signed-off-by: Nikita Proshkin <n.proshkin@yadro.com>
---
 lmr/lmr.h            |   3 ++
 lmr/margin_results.c | 111 +++++++++++++++++++++++++++++++++++++++++++
 pcilmr.c             |  18 ++++++-
 3 files changed, 130 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/lmr/lmr.h b/lmr/lmr.h
index bb188fc..c9dcd69 100644
--- a/lmr/lmr.h
+++ b/lmr/lmr.h
@@ -219,4 +219,7 @@  void margin_log_hw_quirks(struct margin_recv *recv);
 
 void margin_results_print_brief(struct margin_results *results, u8 recvs_n);
 
+void margin_results_save_csv(struct margin_results *results, u8 recvs_n, char *dir,
+                             struct pci_dev *up_port);
+
 #endif
diff --git a/lmr/margin_results.c b/lmr/margin_results.c
index 5ee065d..aca3ab7 100644
--- a/lmr/margin_results.c
+++ b/lmr/margin_results.c
@@ -157,3 +157,114 @@  margin_results_print_brief(struct margin_results *results, u8 recvs_n)
       printf("\n");
     }
 }
+
+void
+margin_results_save_csv(struct margin_results *results, u8 recvs_n, char *dir,
+                        struct pci_dev *up_port)
+{
+  char timestamp[64];
+  time_t tim = time(NULL);
+  strftime(timestamp, sizeof(timestamp), "%FT%H.%M.%S", gmtime(&tim));
+
+  size_t pathlen = strlen(dir) + 128;
+  char *path = xmalloc(pathlen);
+  FILE *csv;
+
+  struct margin_res_lane *lane;
+  struct margin_results *res;
+  struct margin_params params;
+
+  enum lane_rating lane_rating;
+  u8 link_speed;
+
+  for (int i = 0; i < recvs_n; i++)
+    {
+      res = &(results[i]);
+      params = res->params;
+      link_speed = res->link_speed - 4;
+
+      if (res->test_status != MARGIN_TEST_OK)
+        continue;
+      snprintf(path, pathlen, "%s/lmr_%0*x.%02x.%02x.%x_Rx%X_%s.csv", dir,
+               up_port->domain_16 == 0xffff ? 8 : 4, up_port->domain, up_port->bus, up_port->dev,
+               up_port->func, 10 + res->recvn - 1, timestamp);
+      csv = fopen(path, "w");
+      if (!csv)
+        die("Error while saving %s\n", path);
+
+      fprintf(csv, "Lane,Lane Status,Left %% UI,Left ps,Left Steps,Left Status,"
+                   "Right %% UI,Right ps,Right Steps,Right Status,"
+                   "Time %% UI,Time ps,Time Steps,Time Status,"
+                   "Up mV,Up Steps,Up Status,Down mV,Down Steps,Down Status,"
+                   "Voltage mV,Voltage Steps,Voltage Status\n");
+
+      if (check_recv_weird(res, MARGIN_TIM_MIN, MARGIN_VOLT_MIN))
+        lane_rating = WEIRD;
+      else
+        lane_rating = INIT;
+
+      for (int j = 0; j < res->lanes_n; j++)
+        {
+          lane = &(res->lanes[j]);
+          double left_ui = lane->steps[TIM_LEFT] * res->tim_coef;
+          double right_ui = lane->steps[TIM_RIGHT] * res->tim_coef;
+          double up_volt = lane->steps[VOLT_UP] * res->volt_coef;
+          double down_volt = lane->steps[VOLT_DOWN] * res->volt_coef;
+
+          if (lane_rating != WEIRD)
+            {
+              lane_rating = rate_lane(left_ui, MARGIN_TIM_MIN, MARGIN_TIM_RECOMMEND, INIT);
+              if (params.ind_left_right_tim)
+                lane_rating
+                  = rate_lane(right_ui, MARGIN_TIM_MIN, MARGIN_TIM_RECOMMEND, lane_rating);
+              if (params.volt_support)
+                {
+                  lane_rating = rate_lane(up_volt, MARGIN_VOLT_MIN, MARGIN_VOLT_MIN, lane_rating);
+                  if (params.ind_up_down_volt)
+                    lane_rating
+                      = rate_lane(down_volt, MARGIN_VOLT_MIN, MARGIN_VOLT_MIN, lane_rating);
+                }
+            }
+
+          fprintf(csv, "%d,%s,", lane->lane, grades[lane_rating]);
+          if (params.ind_left_right_tim)
+            {
+              fprintf(csv, "%f,%f,%d,%s,%f,%f,%d,%s,NA,NA,NA,NA,", left_ui,
+                      left_ui * ui[link_speed], lane->steps[TIM_LEFT],
+                      sts_strings[lane->statuses[TIM_LEFT]], right_ui, right_ui * ui[link_speed],
+                      lane->steps[TIM_RIGHT], sts_strings[lane->statuses[TIM_RIGHT]]);
+            }
+          else
+            {
+              for (int k = 0; k < 8; k++)
+                fprintf(csv, "NA,");
+              fprintf(csv, "%f,%f,%d,%s,", left_ui, left_ui * ui[link_speed], lane->steps[TIM_LEFT],
+                      sts_strings[lane->statuses[TIM_LEFT]]);
+            }
+          if (params.volt_support)
+            {
+              if (params.ind_up_down_volt)
+                {
+                  fprintf(csv, "%f,%d,%s,%f,%d,%s,NA,NA,NA\n", up_volt, lane->steps[VOLT_UP],
+                          sts_strings[lane->statuses[VOLT_UP]], down_volt, lane->steps[VOLT_DOWN],
+                          sts_strings[lane->statuses[VOLT_DOWN]]);
+                }
+              else
+                {
+                  for (int k = 0; k < 6; k++)
+                    fprintf(csv, "NA,");
+                  fprintf(csv, "%f,%d,%s\n", up_volt, lane->steps[VOLT_UP],
+                          sts_strings[lane->statuses[VOLT_UP]]);
+                }
+            }
+          else
+            {
+              for (int k = 0; k < 8; k++)
+                fprintf(csv, "NA,");
+              fprintf(csv, "NA\n");
+            }
+        }
+      fclose(csv);
+    }
+  free(path);
+}
diff --git a/pcilmr.c b/pcilmr.c
index 43e791d..eb5d947 100644
--- a/pcilmr.c
+++ b/pcilmr.c
@@ -52,7 +52,12 @@  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)
@@ -197,6 +202,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();
@@ -246,7 +254,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)
         {
@@ -277,6 +285,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);
         }
@@ -449,6 +461,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");
         }
     }