]> mj.ucw.cz Git - pciutils.git/blob - lmr/margin_results.c
pcilmr: Move most of pcilmr arguments parsing logic to the separate file
[pciutils.git] / lmr / margin_results.c
1 /*
2  *      The PCI Utilities -- Display/save margining results
3  *
4  *      Copyright (c) 2023-2024 KNS Group LLC (YADRO)
5  *
6  *      Can be freely distributed and used under the terms of the GNU GPL v2+.
7  *
8  *      SPDX-License-Identifier: GPL-2.0-or-later
9  */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <time.h>
15
16 #include "lmr.h"
17
18 enum lane_rating {
19   BAD = 0,
20   OKAY,
21   PERFECT,
22   WEIRD,
23   INIT,
24 };
25
26 static char *const grades[] = { "Bad", "Okay", "Perfect", "Weird" };
27 static char *const sts_strings[] = { "NAK", "LIM", "THR" };
28 static const double ui[] = { 62.5 / 100, 31.25 / 100 };
29
30 static enum lane_rating
31 rate_lane(double value, double min, double recommended, enum lane_rating cur_rate)
32 {
33   enum lane_rating res = PERFECT;
34   if (value < recommended)
35     res = OKAY;
36   if (value < min)
37     res = BAD;
38   if (cur_rate == INIT)
39     return res;
40   if (res < cur_rate)
41     return res;
42   else
43     return cur_rate;
44 }
45
46 static bool
47 check_recv_weird(struct margin_results *results, double tim_min, double volt_min)
48 {
49   bool result = true;
50
51   struct margin_res_lane *lane;
52   for (int i = 0; i < results->lanes_n && result; i++)
53     {
54       lane = &(results->lanes[i]);
55       if (lane->steps[TIM_LEFT] * results->tim_coef != tim_min)
56         result = false;
57       if (results->params.ind_left_right_tim
58           && lane->steps[TIM_RIGHT] * results->tim_coef != tim_min)
59         result = false;
60       if (results->params.volt_support)
61         {
62           if (lane->steps[VOLT_UP] * results->volt_coef != volt_min)
63             result = false;
64           if (results->params.ind_up_down_volt
65               && lane->steps[VOLT_DOWN] * results->volt_coef != volt_min)
66             result = false;
67         }
68     }
69   return result;
70 }
71
72 void
73 margin_results_print_brief(struct margin_results *results, u8 recvs_n)
74 {
75   struct margin_res_lane *lane;
76   struct margin_results *res;
77   struct margin_params params;
78
79   enum lane_rating lane_rating;
80
81   u8 link_speed;
82
83   char *no_test_msgs[] = { "",
84                            "Margining Ready bit is Clear",
85                            "Error during caps reading",
86                            "Margining prerequisites are not satisfied (16/32 GT/s, D0)",
87                            "Invalid lanes specified with arguments",
88                            "Invalid receivers specified with arguments",
89                            "Couldn't disable ASPM" };
90
91   for (int i = 0; i < recvs_n; i++)
92     {
93       res = &(results[i]);
94       params = res->params;
95       link_speed = res->link_speed - 4;
96
97       if (res->test_status != MARGIN_TEST_OK)
98         {
99           if (res->test_status < MARGIN_TEST_PREREQS)
100             printf("Rx(%X) -", 10 + res->recvn - 1);
101           printf(" Couldn't run test (%s)\n\n", no_test_msgs[res->test_status]);
102           continue;
103         }
104
105       if (res->lane_reversal)
106         printf("Rx(%X) - Lane Reversal\n", 10 + res->recvn - 1);
107
108       if (!res->tim_off_reported)
109         printf("Rx(%X) - Attention: Vendor chose not to report the Max Timing Offset.\n"
110                "Utility used its max possible value (50%% UI) for calculations of %% UI and ps.\n"
111                "Keep in mind that for timing results of this receiver only steps values are "
112                "reliable.\n\n",
113                10 + res->recvn - 1);
114       if (params.volt_support && !res->volt_off_reported)
115         printf("Rx(%X) - Attention: Vendor chose not to report the Max Voltage Offset.\n"
116                "Utility used its max possible value (500 mV) for calculations of mV.\n"
117                "Keep in mind that for voltage results of this receiver only steps values are "
118                "reliable.\n\n",
119                10 + res->recvn - 1);
120
121       if (check_recv_weird(res, MARGIN_TIM_MIN, MARGIN_VOLT_MIN))
122         lane_rating = WEIRD;
123       else
124         lane_rating = INIT;
125
126       for (u8 j = 0; j < res->lanes_n; j++)
127         {
128           lane = &(res->lanes[j]);
129           double left_ui = lane->steps[TIM_LEFT] * res->tim_coef;
130           double right_ui = lane->steps[TIM_RIGHT] * res->tim_coef;
131           double up_volt = lane->steps[VOLT_UP] * res->volt_coef;
132           double down_volt = lane->steps[VOLT_DOWN] * res->volt_coef;
133
134           if (lane_rating != WEIRD)
135             {
136               lane_rating = rate_lane(left_ui, MARGIN_TIM_MIN, MARGIN_TIM_RECOMMEND, INIT);
137               if (params.ind_left_right_tim)
138                 lane_rating
139                   = rate_lane(right_ui, MARGIN_TIM_MIN, MARGIN_TIM_RECOMMEND, lane_rating);
140               if (params.volt_support)
141                 {
142                   lane_rating = rate_lane(up_volt, MARGIN_VOLT_MIN, MARGIN_VOLT_MIN, lane_rating);
143                   if (params.ind_up_down_volt)
144                     lane_rating
145                       = rate_lane(down_volt, MARGIN_VOLT_MIN, MARGIN_VOLT_MIN, lane_rating);
146                 }
147             }
148
149           printf("Rx(%X) Lane %2d - %s\t", 10 + res->recvn - 1, lane->lane, grades[lane_rating]);
150           if (params.ind_left_right_tim)
151             printf("L %4.1f%% UI - %5.2fps - %2dst %s, R %4.1f%% UI - %5.2fps - %2dst %s", left_ui,
152                    left_ui * ui[link_speed], lane->steps[TIM_LEFT],
153                    sts_strings[lane->statuses[TIM_LEFT]], right_ui, right_ui * ui[link_speed],
154                    lane->steps[TIM_RIGHT], sts_strings[lane->statuses[TIM_RIGHT]]);
155           else
156             printf("T %4.1f%% UI - %5.2fps - %2dst %s", left_ui, left_ui * ui[link_speed],
157                    lane->steps[TIM_LEFT], sts_strings[lane->statuses[TIM_LEFT]]);
158           if (params.volt_support)
159             {
160               if (params.ind_up_down_volt)
161                 printf(", U %5.1f mV - %3dst %s, D %5.1f mV - %3dst %s", up_volt,
162                        lane->steps[VOLT_UP], sts_strings[lane->statuses[VOLT_UP]], down_volt,
163                        lane->steps[VOLT_DOWN], sts_strings[lane->statuses[VOLT_DOWN]]);
164               else
165                 printf(", V %5.1f mV - %3dst %s", up_volt, lane->steps[VOLT_UP],
166                        sts_strings[lane->statuses[VOLT_UP]]);
167             }
168           printf("\n");
169         }
170       printf("\n");
171     }
172 }
173
174 void
175 margin_results_save_csv(struct margin_results *results, u8 recvs_n, struct margin_link *link)
176 {
177   char timestamp[64];
178   time_t tim = time(NULL);
179   strftime(timestamp, sizeof(timestamp), "%Y-%m-%dT%H:%M:%S", gmtime(&tim));
180
181   char *dir = link->args.common->dir_for_csv;
182   size_t pathlen = strlen(dir) + 128;
183   char *path = xmalloc(pathlen);
184   FILE *csv;
185
186   struct margin_res_lane *lane;
187   struct margin_results *res;
188   struct margin_params params;
189
190   enum lane_rating lane_rating;
191   u8 link_speed;
192
193   struct pci_dev *port;
194
195   for (int i = 0; i < recvs_n; i++)
196     {
197       res = &(results[i]);
198       params = res->params;
199       link_speed = res->link_speed - 4;
200
201       if (res->test_status != MARGIN_TEST_OK)
202         continue;
203
204       port = res->recvn == 6 ? link->up_port.dev : link->down_port.dev;
205       snprintf(path, pathlen, "%s/lmr_%0*x.%02x.%02x.%x_Rx%X_%s.csv", dir,
206                port->domain_16 == 0xffff ? 8 : 4, port->domain, port->bus, port->dev,
207                port->func, 10 + res->recvn - 1, timestamp);
208       csv = fopen(path, "w");
209       if (!csv)
210         die("Error while saving %s\n", path);
211
212       fprintf(csv, "Lane,Lane Status,Left %% UI,Left ps,Left Steps,Left Status,"
213                    "Right %% UI,Right ps,Right Steps,Right Status,"
214                    "Time %% UI,Time ps,Time Steps,Time Status,"
215                    "Up mV,Up Steps,Up Status,Down mV,Down Steps,Down Status,"
216                    "Voltage mV,Voltage Steps,Voltage Status\n");
217
218       if (check_recv_weird(res, MARGIN_TIM_MIN, MARGIN_VOLT_MIN))
219         lane_rating = WEIRD;
220       else
221         lane_rating = INIT;
222
223       for (int j = 0; j < res->lanes_n; j++)
224         {
225           lane = &(res->lanes[j]);
226           double left_ui = lane->steps[TIM_LEFT] * res->tim_coef;
227           double right_ui = lane->steps[TIM_RIGHT] * res->tim_coef;
228           double up_volt = lane->steps[VOLT_UP] * res->volt_coef;
229           double down_volt = lane->steps[VOLT_DOWN] * res->volt_coef;
230
231           if (lane_rating != WEIRD)
232             {
233               lane_rating = rate_lane(left_ui, MARGIN_TIM_MIN, MARGIN_TIM_RECOMMEND, INIT);
234               if (params.ind_left_right_tim)
235                 lane_rating
236                   = rate_lane(right_ui, MARGIN_TIM_MIN, MARGIN_TIM_RECOMMEND, lane_rating);
237               if (params.volt_support)
238                 {
239                   lane_rating = rate_lane(up_volt, MARGIN_VOLT_MIN, MARGIN_VOLT_MIN, lane_rating);
240                   if (params.ind_up_down_volt)
241                     lane_rating
242                       = rate_lane(down_volt, MARGIN_VOLT_MIN, MARGIN_VOLT_MIN, lane_rating);
243                 }
244             }
245
246           fprintf(csv, "%d,%s,", lane->lane, grades[lane_rating]);
247           if (params.ind_left_right_tim)
248             {
249               fprintf(csv, "%f,%f,%d,%s,%f,%f,%d,%s,NA,NA,NA,NA,", left_ui,
250                       left_ui * ui[link_speed], lane->steps[TIM_LEFT],
251                       sts_strings[lane->statuses[TIM_LEFT]], right_ui, right_ui * ui[link_speed],
252                       lane->steps[TIM_RIGHT], sts_strings[lane->statuses[TIM_RIGHT]]);
253             }
254           else
255             {
256               for (int k = 0; k < 8; k++)
257                 fprintf(csv, "NA,");
258               fprintf(csv, "%f,%f,%d,%s,", left_ui, left_ui * ui[link_speed], lane->steps[TIM_LEFT],
259                       sts_strings[lane->statuses[TIM_LEFT]]);
260             }
261           if (params.volt_support)
262             {
263               if (params.ind_up_down_volt)
264                 {
265                   fprintf(csv, "%f,%d,%s,%f,%d,%s,NA,NA,NA\n", up_volt, lane->steps[VOLT_UP],
266                           sts_strings[lane->statuses[VOLT_UP]], down_volt, lane->steps[VOLT_DOWN],
267                           sts_strings[lane->statuses[VOLT_DOWN]]);
268                 }
269               else
270                 {
271                   for (int k = 0; k < 6; k++)
272                     fprintf(csv, "NA,");
273                   fprintf(csv, "%f,%d,%s\n", up_volt, lane->steps[VOLT_UP],
274                           sts_strings[lane->statuses[VOLT_UP]]);
275                 }
276             }
277           else
278             {
279               for (int k = 0; k < 8; k++)
280                 fprintf(csv, "NA,");
281               fprintf(csv, "NA\n");
282             }
283         }
284       fclose(csv);
285     }
286   free(path);
287 }