diff options
Diffstat (limited to '')
-rw-r--r-- | lmr/margin_results.c | 322 |
1 files changed, 211 insertions, 111 deletions
diff --git a/lmr/margin_results.c b/lmr/margin_results.c index 4d28f04..b0c5c26 100644 --- a/lmr/margin_results.c +++ b/lmr/margin_results.c @@ -1,7 +1,7 @@ /* * The PCI Utilities -- Display/save margining results * - * Copyright (c) 2023 KNS Group LLC (YADRO) + * Copyright (c) 2023-2024 KNS Group LLC (YADRO) * * Can be freely distributed and used under the terms of the GNU GPL v2+. * @@ -16,25 +16,23 @@ #include "lmr.h" enum lane_rating { - BAD = 0, - OKAY, + FAIL = 0, + PASS, PERFECT, - WEIRD, INIT, }; -static char *const grades[] = { "Bad", "Okay", "Perfect", "Weird" }; +static char *const grades[] = { "Fail", "Pass", "Perfect" }; static char *const sts_strings[] = { "NAK", "LIM", "THR" }; -static const double ui[] = { 62.5 / 100, 31.25 / 100 }; static enum lane_rating rate_lane(double value, double min, double recommended, enum lane_rating cur_rate) { enum lane_rating res = PERFECT; if (value < recommended) - res = OKAY; + res = PASS; if (value < min) - res = BAD; + res = FAIL; if (cur_rate == INIT) return res; if (res < cur_rate) @@ -43,34 +41,9 @@ rate_lane(double value, double min, double recommended, enum lane_rating cur_rat return cur_rate; } -static bool -check_recv_weird(struct margin_results *results, double tim_min, double volt_min) -{ - bool result = true; - - struct margin_res_lane *lane; - for (int i = 0; i < results->lanes_n && result; i++) - { - lane = &(results->lanes[i]); - if (lane->steps[TIM_LEFT] * results->tim_coef != tim_min) - result = false; - if (results->params.ind_left_right_tim - && lane->steps[TIM_RIGHT] * results->tim_coef != tim_min) - result = false; - if (results->params.volt_support) - { - if (lane->steps[VOLT_UP] * results->volt_coef != volt_min) - result = false; - if (results->params.ind_up_down_volt - && lane->steps[VOLT_DOWN] * results->volt_coef != volt_min) - result = false; - } - } - return result; -} - void -margin_results_print_brief(struct margin_results *results, u8 recvs_n) +margin_results_print_brief(struct margin_results *results, u8 recvs_n, + struct margin_link_args *args) { struct margin_res_lane *lane; struct margin_results *res; @@ -80,6 +53,14 @@ margin_results_print_brief(struct margin_results *results, u8 recvs_n) u8 link_speed; + struct margin_recv_args grade_args; + bool spec_ref_only; + + double ew_min; + double ew_rec; + double eh_min; + double eh_rec; + char *no_test_msgs[] = { "", "Margining Ready bit is Clear", "Error during caps reading", @@ -102,6 +83,67 @@ margin_results_print_brief(struct margin_results *results, u8 recvs_n) continue; } + spec_ref_only = true; + grade_args = args->recv_args[res->recvn - 1]; + if (grade_args.t.criteria != 0) + { + spec_ref_only = false; + ew_min = grade_args.t.criteria; + ew_rec = grade_args.t.criteria; + } + else + { + ew_min = margin_ew_min[link_speed]; + ew_rec = margin_ew_rec[link_speed]; + } + + if (grade_args.v.criteria != 0) + { + spec_ref_only = false; + eh_min = grade_args.v.criteria; + eh_rec = grade_args.v.criteria; + } + else + { + eh_min = margin_eh_min[link_speed]; + eh_rec = margin_eh_rec[link_speed]; + } + + printf("Rx(%X) - Grading criteria:\n", 10 + res->recvn - 1); + if (spec_ref_only) + { + printf("\tUsing spec only:\n"); + printf("\tEW: minimum - %.2f ps; recommended - %.2f ps\n", ew_min, ew_rec); + printf("\tEH: minimum - %.2f mV; recommended - %.2f mV\n\n", eh_min, eh_rec); + } + else + { + printf("\tEW: pass - %.2f ps\n", ew_min); + printf("\tEH: pass - %.2f mV\n\n", eh_min); + } + + if (!params.ind_left_right_tim) + { + printf("Rx(%X) - EW: independent left/right timing margin is not supported:\n", + 10 + res->recvn - 1); + if (grade_args.t.one_side_is_whole) + printf("\tmanual setting - the entire margin across the eye " + "is what is reported by one side margining\n\n"); + else + printf("\tdefault - calculating EW as double one side result\n\n"); + } + + if (params.volt_support && !params.ind_up_down_volt) + { + printf("Rx(%X) - EH: independent up and down voltage margining is not supported:\n", + 10 + res->recvn - 1); + if (grade_args.v.one_side_is_whole) + printf("\tmanual setting - the entire margin across the eye " + "is what is reported by one side margining\n\n"); + else + printf("\tdefault - calculating EH as double one side result\n\n"); + } + if (res->lane_reversal) printf("Rx(%X) - Lane Reversal\n", 10 + res->recvn - 1); @@ -118,51 +160,60 @@ margin_results_print_brief(struct margin_results *results, u8 recvs_n) "reliable.\n\n", 10 + res->recvn - 1); - if (check_recv_weird(res, MARGIN_TIM_MIN, MARGIN_VOLT_MIN)) - lane_rating = WEIRD; - else - lane_rating = INIT; - - for (u8 j = 0; j < res->lanes_n; j++) + for (int j = 0; j < res->lanes_n; j++) { + if (spec_ref_only) + lane_rating = INIT; + else + lane_rating = PASS; + 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 left_ps = lane->steps[TIM_LEFT] * res->tim_coef / 100.0 * margin_ui[link_speed]; + double right_ps = lane->steps[TIM_RIGHT] * res->tim_coef / 100.0 * margin_ui[link_speed]; double up_volt = lane->steps[VOLT_UP] * res->volt_coef; double down_volt = lane->steps[VOLT_DOWN] * res->volt_coef; - if (lane_rating != WEIRD) + double ew = left_ps; + if (params.ind_left_right_tim) + ew += right_ps; + else if (!grade_args.t.one_side_is_whole) + ew *= 2.0; + + double eh = 0.0; + if (params.volt_support) { - 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); - } + eh += up_volt; + if (params.ind_up_down_volt) + eh += down_volt; + else if (!grade_args.v.one_side_is_whole) + eh *= 2.0; } - printf("Rx(%X) Lane %2d - %s\t", 10 + res->recvn - 1, lane->lane, grades[lane_rating]); + lane_rating = rate_lane(ew, ew_min, ew_rec, lane_rating); + if (params.volt_support) + lane_rating = rate_lane(eh, eh_min, eh_rec, lane_rating); + + printf("Rx(%X) Lane %2d: %s\t (W %4.1f%% UI - %5.2fps", 10 + res->recvn - 1, lane->lane, + grades[lane_rating], ew / margin_ui[link_speed] * 100.0, ew); + if (params.volt_support) + printf(", H %5.1f mV", eh); if (params.ind_left_right_tim) - printf("L %4.1f%% UI - %5.2fps - %2dst %s, R %4.1f%% UI - %5.2fps - %2dst %s", 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]]); + printf(") (L %4.1f%% UI - %5.2fps - %2dst %s) (R %4.1f%% UI - %5.2fps - %2dst %s)", + left_ps / margin_ui[link_speed] * 100.0, left_ps, lane->steps[TIM_LEFT], + sts_strings[lane->statuses[TIM_LEFT]], right_ps / margin_ui[link_speed] * 100.0, + right_ps, lane->steps[TIM_RIGHT], sts_strings[lane->statuses[TIM_RIGHT]]); else - printf("T %4.1f%% UI - %5.2fps - %2dst %s", left_ui, left_ui * ui[link_speed], - lane->steps[TIM_LEFT], sts_strings[lane->statuses[TIM_LEFT]]); + printf(") (T %4.1f%% UI - %5.2fps - %2dst %s)", + left_ps / margin_ui[link_speed] * 100.0, left_ps, lane->steps[TIM_LEFT], + sts_strings[lane->statuses[TIM_LEFT]]); if (params.volt_support) { if (params.ind_up_down_volt) - printf(", U %5.1f mV - %3dst %s, D %5.1f mV - %3dst %s", up_volt, + printf(" (U %5.1f mV - %3dst %s) (D %5.1f mV - %3dst %s)", 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 - printf(", V %5.1f mV - %3dst %s", up_volt, lane->steps[VOLT_UP], + printf(" (V %5.1f mV - %3dst %s)", up_volt, lane->steps[VOLT_UP], sts_strings[lane->statuses[VOLT_UP]]); } printf("\n"); @@ -172,13 +223,13 @@ 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) +margin_results_save_csv(struct margin_results *results, u8 recvs_n, struct margin_link *link) { char timestamp[64]; time_t tim = time(NULL); strftime(timestamp, sizeof(timestamp), "%Y-%m-%dT%H:%M:%S", gmtime(&tim)); + char *dir = link->args.common->dir_for_csv; size_t pathlen = strlen(dir) + 128; char *path = xmalloc(pathlen); FILE *csv; @@ -190,6 +241,16 @@ margin_results_save_csv(struct margin_results *results, u8 recvs_n, char *dir, enum lane_rating lane_rating; u8 link_speed; + struct margin_recv_args grade_args; + bool spec_ref_only; + + double ew_min; + double ew_rec; + double eh_min; + double eh_rec; + + struct pci_dev *port; + for (int i = 0; i < recvs_n; i++) { res = &(results[i]); @@ -198,81 +259,120 @@ margin_results_save_csv(struct margin_results *results, u8 recvs_n, char *dir, if (res->test_status != MARGIN_TEST_OK) continue; + + port = res->recvn == 6 ? link->up_port.dev : link->down_port.dev; 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); + port->domain_16 == 0xffff ? 8 : 4, port->domain, port->bus, port->dev, 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"); + fprintf(csv, "Lane,EW Min,EW Rec,EW,EH Min,EH Rec,EH,Lane Status,Left %% UI,Left " + "ps,Left Steps,Left Status,Right %% UI,Right ps,Right Steps,Right Status,Up " + "mV,Up Steps,Up Status,Down mV,Down Steps,Down Status\n"); - if (check_recv_weird(res, MARGIN_TIM_MIN, MARGIN_VOLT_MIN)) - lane_rating = WEIRD; + spec_ref_only = true; + grade_args = link->args.recv_args[res->recvn - 1]; + if (grade_args.t.criteria != 0) + { + spec_ref_only = false; + ew_min = grade_args.t.criteria; + ew_rec = grade_args.t.criteria; + } + else + { + ew_min = margin_ew_min[link_speed]; + ew_rec = margin_ew_rec[link_speed]; + } + if (grade_args.v.criteria != 0) + { + spec_ref_only = false; + eh_min = grade_args.v.criteria; + eh_rec = grade_args.v.criteria; + } else - lane_rating = INIT; + { + eh_min = margin_eh_min[link_speed]; + eh_rec = margin_eh_rec[link_speed]; + } for (int j = 0; j < res->lanes_n; j++) { + if (spec_ref_only) + lane_rating = INIT; + else + lane_rating = PASS; + 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 left_ps = lane->steps[TIM_LEFT] * res->tim_coef / 100.0 * margin_ui[link_speed]; + double right_ps = lane->steps[TIM_RIGHT] * res->tim_coef / 100.0 * margin_ui[link_speed]; double up_volt = lane->steps[VOLT_UP] * res->volt_coef; double down_volt = lane->steps[VOLT_DOWN] * res->volt_coef; - if (lane_rating != WEIRD) + double ew = left_ps; + if (params.ind_left_right_tim) + ew += right_ps; + else if (!grade_args.t.one_side_is_whole) + ew *= 2.0; + + double eh = 0.0; + if (params.volt_support) { - 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); - } + eh += up_volt; + if (params.ind_up_down_volt) + eh += down_volt; + else if (!grade_args.v.one_side_is_whole) + eh *= 2.0; } - fprintf(csv, "%d,%s,", lane->lane, grades[lane_rating]); - if (params.ind_left_right_tim) + lane_rating = rate_lane(ew, ew_min, ew_rec, lane_rating); + if (params.volt_support) + lane_rating = rate_lane(eh, eh_min, eh_rec, lane_rating); + + fprintf(csv, "%d,%f,", lane->lane, ew_min); + if (spec_ref_only) + fprintf(csv, "%f,", ew_rec); + else + fprintf(csv, "NA,"); + fprintf(csv, "%f,", ew); + if (params.volt_support) { - 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]]); + fprintf(csv, "%f,", eh_min); + if (spec_ref_only) + fprintf(csv, "%f,", eh_rec); + else + fprintf(csv, "NA,"); + fprintf(csv, "%f,", eh); } else + fprintf(csv, "NA,NA,NA,"); + fprintf(csv, "%s,", grades[lane_rating]); + + fprintf(csv, "%f,%f,%d,%s,", left_ps * 100.0 / margin_ui[link_speed], left_ps, + lane->steps[TIM_LEFT], sts_strings[lane->statuses[TIM_LEFT]]); + + if (params.ind_left_right_tim) + fprintf(csv, "%f,%f,%d,%s,", right_ps * 100.0 / margin_ui[link_speed], right_ps, + lane->steps[TIM_RIGHT], sts_strings[lane->statuses[TIM_RIGHT]]); + else { - for (int k = 0; k < 8; k++) + for (int k = 0; k < 4; 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) { + fprintf(csv, "%f,%d,%s,", up_volt, lane->steps[VOLT_UP], + sts_strings[lane->statuses[VOLT_UP]]); 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]]); - } + fprintf(csv, "%f,%d,%s\n", 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]]); - } + fprintf(csv, "NA,NA,NA\n"); } else { - for (int k = 0; k < 8; k++) + for (int k = 0; k < 5; k++) fprintf(csv, "NA,"); fprintf(csv, "NA\n"); } |