2 * The PCI Utilities -- Display/save margining results
4 * Copyright (c) 2023 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, char *dir,
176 struct pci_dev *up_port)
179 time_t tim = time(NULL);
180 strftime(timestamp, sizeof(timestamp), "%Y-%m-%dT%H:%M:%S", gmtime(&tim));
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 for (int i = 0; i < recvs_n; i++)
196 params = res->params;
197 link_speed = res->link_speed - 4;
199 if (res->test_status != MARGIN_TEST_OK)
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");
206 die("Error while saving %s\n", path);
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");
214 if (check_recv_weird(res, MARGIN_TIM_MIN, MARGIN_VOLT_MIN))
219 for (int j = 0; j < res->lanes_n; j++)
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;
227 if (lane_rating != WEIRD)
229 lane_rating = rate_lane(left_ui, MARGIN_TIM_MIN, MARGIN_TIM_RECOMMEND, INIT);
230 if (params.ind_left_right_tim)
232 = rate_lane(right_ui, MARGIN_TIM_MIN, MARGIN_TIM_RECOMMEND, lane_rating);
233 if (params.volt_support)
235 lane_rating = rate_lane(up_volt, MARGIN_VOLT_MIN, MARGIN_VOLT_MIN, lane_rating);
236 if (params.ind_up_down_volt)
238 = rate_lane(down_volt, MARGIN_VOLT_MIN, MARGIN_VOLT_MIN, lane_rating);
242 fprintf(csv, "%d,%s,", lane->lane, grades[lane_rating]);
243 if (params.ind_left_right_tim)
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]]);
252 for (int k = 0; k < 8; k++)
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]]);
257 if (params.volt_support)
259 if (params.ind_up_down_volt)
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]]);
267 for (int k = 0; k < 6; k++)
269 fprintf(csv, "%f,%d,%s\n", up_volt, lane->steps[VOLT_UP],
270 sts_strings[lane->statuses[VOLT_UP]]);
275 for (int k = 0; k < 8; k++)
277 fprintf(csv, "NA\n");