]> mj.ucw.cz Git - pciutils.git/blob - lmr/margin_results.c
Merge pull request #177 from OscarL/cache-loc-on-man-pages
[pciutils.git] / lmr / margin_results.c
1 /*
2  *      The PCI Utilities -- Display/save margining results
3  *
4  *      Copyright (c) 2023 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, char *dir,
176                         struct pci_dev *up_port)
177 {
178   char timestamp[64];
179   time_t tim = time(NULL);
180   strftime(timestamp, sizeof(timestamp), "%Y-%m-%dT%H:%M:%S", gmtime(&tim));
181
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   for (int i = 0; i < recvs_n; i++)
194     {
195       res = &(results[i]);
196       params = res->params;
197       link_speed = res->link_speed - 4;
198
199       if (res->test_status != MARGIN_TEST_OK)
200         continue;
201       snprintf(path, pathlen, "%s/lmr_%0*x.%02x.%02x.%x_Rx%X_%s.csv", dir,
202                up_port->domain_16 == 0xffff ? 8 : 4, up_port->domain, up_port->bus, up_port->dev,
203                up_port->func, 10 + res->recvn - 1, timestamp);
204       csv = fopen(path, "w");
205       if (!csv)
206         die("Error while saving %s\n", path);
207
208       fprintf(csv, "Lane,Lane Status,Left %% UI,Left ps,Left Steps,Left Status,"
209                    "Right %% UI,Right ps,Right Steps,Right Status,"
210                    "Time %% UI,Time ps,Time Steps,Time Status,"
211                    "Up mV,Up Steps,Up Status,Down mV,Down Steps,Down Status,"
212                    "Voltage mV,Voltage Steps,Voltage Status\n");
213
214       if (check_recv_weird(res, MARGIN_TIM_MIN, MARGIN_VOLT_MIN))
215         lane_rating = WEIRD;
216       else
217         lane_rating = INIT;
218
219       for (int j = 0; j < res->lanes_n; j++)
220         {
221           lane = &(res->lanes[j]);
222           double left_ui = lane->steps[TIM_LEFT] * res->tim_coef;
223           double right_ui = lane->steps[TIM_RIGHT] * res->tim_coef;
224           double up_volt = lane->steps[VOLT_UP] * res->volt_coef;
225           double down_volt = lane->steps[VOLT_DOWN] * res->volt_coef;
226
227           if (lane_rating != WEIRD)
228             {
229               lane_rating = rate_lane(left_ui, MARGIN_TIM_MIN, MARGIN_TIM_RECOMMEND, INIT);
230               if (params.ind_left_right_tim)
231                 lane_rating
232                   = rate_lane(right_ui, MARGIN_TIM_MIN, MARGIN_TIM_RECOMMEND, lane_rating);
233               if (params.volt_support)
234                 {
235                   lane_rating = rate_lane(up_volt, MARGIN_VOLT_MIN, MARGIN_VOLT_MIN, lane_rating);
236                   if (params.ind_up_down_volt)
237                     lane_rating
238                       = rate_lane(down_volt, MARGIN_VOLT_MIN, MARGIN_VOLT_MIN, lane_rating);
239                 }
240             }
241
242           fprintf(csv, "%d,%s,", lane->lane, grades[lane_rating]);
243           if (params.ind_left_right_tim)
244             {
245               fprintf(csv, "%f,%f,%d,%s,%f,%f,%d,%s,NA,NA,NA,NA,", left_ui,
246                       left_ui * ui[link_speed], lane->steps[TIM_LEFT],
247                       sts_strings[lane->statuses[TIM_LEFT]], right_ui, right_ui * ui[link_speed],
248                       lane->steps[TIM_RIGHT], sts_strings[lane->statuses[TIM_RIGHT]]);
249             }
250           else
251             {
252               for (int k = 0; k < 8; k++)
253                 fprintf(csv, "NA,");
254               fprintf(csv, "%f,%f,%d,%s,", left_ui, left_ui * ui[link_speed], lane->steps[TIM_LEFT],
255                       sts_strings[lane->statuses[TIM_LEFT]]);
256             }
257           if (params.volt_support)
258             {
259               if (params.ind_up_down_volt)
260                 {
261                   fprintf(csv, "%f,%d,%s,%f,%d,%s,NA,NA,NA\n", up_volt, lane->steps[VOLT_UP],
262                           sts_strings[lane->statuses[VOLT_UP]], down_volt, lane->steps[VOLT_DOWN],
263                           sts_strings[lane->statuses[VOLT_DOWN]]);
264                 }
265               else
266                 {
267                   for (int k = 0; k < 6; k++)
268                     fprintf(csv, "NA,");
269                   fprintf(csv, "%f,%d,%s\n", up_volt, lane->steps[VOLT_UP],
270                           sts_strings[lane->statuses[VOLT_UP]]);
271                 }
272             }
273           else
274             {
275               for (int k = 0; k < 8; k++)
276                 fprintf(csv, "NA,");
277               fprintf(csv, "NA\n");
278             }
279         }
280       fclose(csv);
281     }
282   free(path);
283 }