2 * The PCI Utilities -- Display/save margining results
4 * Copyright (c) 2023-2024 KNS Group LLC (YADRO)
6 * Can be freely distributed and used under the terms of the GNU GPL v2+.
8 * SPDX-License-Identifier: GPL-2.0-or-later
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 };
30 static enum lane_rating
31 rate_lane(double value, double min, double recommended, enum lane_rating cur_rate)
33 enum lane_rating res = PERFECT;
34 if (value < recommended)
47 check_recv_weird(struct margin_results *results, double tim_min, double volt_min)
51 struct margin_res_lane *lane;
52 for (int i = 0; i < results->lanes_n && result; i++)
54 lane = &(results->lanes[i]);
55 if (lane->steps[TIM_LEFT] * results->tim_coef != tim_min)
57 if (results->params.ind_left_right_tim
58 && lane->steps[TIM_RIGHT] * results->tim_coef != tim_min)
60 if (results->params.volt_support)
62 if (lane->steps[VOLT_UP] * results->volt_coef != volt_min)
64 if (results->params.ind_up_down_volt
65 && lane->steps[VOLT_DOWN] * results->volt_coef != volt_min)
73 margin_results_print_brief(struct margin_results *results, u8 recvs_n)
75 struct margin_res_lane *lane;
76 struct margin_results *res;
77 struct margin_params params;
79 enum lane_rating lane_rating;
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" };
91 for (int i = 0; i < recvs_n; i++)
95 link_speed = res->link_speed - 4;
97 if (res->test_status != MARGIN_TEST_OK)
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]);
105 if (res->lane_reversal)
106 printf("Rx(%X) - Lane Reversal\n", 10 + res->recvn - 1);
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 "
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 "
119 10 + res->recvn - 1);
121 if (check_recv_weird(res, MARGIN_TIM_MIN, MARGIN_VOLT_MIN))
126 for (u8 j = 0; j < res->lanes_n; j++)
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;
134 if (lane_rating != WEIRD)
136 lane_rating = rate_lane(left_ui, MARGIN_TIM_MIN, MARGIN_TIM_RECOMMEND, INIT);
137 if (params.ind_left_right_tim)
139 = rate_lane(right_ui, MARGIN_TIM_MIN, MARGIN_TIM_RECOMMEND, lane_rating);
140 if (params.volt_support)
142 lane_rating = rate_lane(up_volt, MARGIN_VOLT_MIN, MARGIN_VOLT_MIN, lane_rating);
143 if (params.ind_up_down_volt)
145 = rate_lane(down_volt, MARGIN_VOLT_MIN, MARGIN_VOLT_MIN, lane_rating);
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]]);
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)
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]]);
165 printf(", V %5.1f mV - %3dst %s", up_volt, lane->steps[VOLT_UP],
166 sts_strings[lane->statuses[VOLT_UP]]);
175 margin_results_save_csv(struct margin_results *results, u8 recvs_n, struct margin_link *link)
178 time_t tim = time(NULL);
179 strftime(timestamp, sizeof(timestamp), "%Y-%m-%dT%H:%M:%S", gmtime(&tim));
181 char *dir = link->args.common->dir_for_csv;
182 size_t pathlen = strlen(dir) + 128;
183 char *path = xmalloc(pathlen);
186 struct margin_res_lane *lane;
187 struct margin_results *res;
188 struct margin_params params;
190 enum lane_rating lane_rating;
193 struct pci_dev *port;
195 for (int i = 0; i < recvs_n; i++)
198 params = res->params;
199 link_speed = res->link_speed - 4;
201 if (res->test_status != MARGIN_TEST_OK)
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");
210 die("Error while saving %s\n", path);
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");
218 if (check_recv_weird(res, MARGIN_TIM_MIN, MARGIN_VOLT_MIN))
223 for (int j = 0; j < res->lanes_n; j++)
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;
231 if (lane_rating != WEIRD)
233 lane_rating = rate_lane(left_ui, MARGIN_TIM_MIN, MARGIN_TIM_RECOMMEND, INIT);
234 if (params.ind_left_right_tim)
236 = rate_lane(right_ui, MARGIN_TIM_MIN, MARGIN_TIM_RECOMMEND, lane_rating);
237 if (params.volt_support)
239 lane_rating = rate_lane(up_volt, MARGIN_VOLT_MIN, MARGIN_VOLT_MIN, lane_rating);
240 if (params.ind_up_down_volt)
242 = rate_lane(down_volt, MARGIN_VOLT_MIN, MARGIN_VOLT_MIN, lane_rating);
246 fprintf(csv, "%d,%s,", lane->lane, grades[lane_rating]);
247 if (params.ind_left_right_tim)
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]]);
256 for (int k = 0; k < 8; k++)
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]]);
261 if (params.volt_support)
263 if (params.ind_up_down_volt)
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]]);
271 for (int k = 0; k < 6; k++)
273 fprintf(csv, "%f,%d,%s\n", up_volt, lane->steps[VOLT_UP],
274 sts_strings[lane->statuses[VOLT_UP]]);
279 for (int k = 0; k < 8; k++)
281 fprintf(csv, "NA\n");