summaryrefslogtreecommitdiffstats
path: root/lmr/margin_results.c
diff options
context:
space:
mode:
Diffstat (limited to 'lmr/margin_results.c')
-rw-r--r--lmr/margin_results.c322
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");
}