@@ -1,4 +1,4 @@
-OBJS=margin_hw margin margin_log
+OBJS=margin_hw margin margin_log margin_results
INCL=$(addsuffix .h,$(OBJS)) $(addprefix ../,$(PCIINC))
$(addsuffix .o, $(OBJS)): %.o: %.c $(INCL)
new file mode 100644
@@ -0,0 +1,135 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "margin_results.h"
+
+enum lane_rating {
+ BAD = 0,
+ OKAY,
+ PERFECT,
+ WEIRD,
+ INIT,
+};
+
+static char *const grades[] = {"Bad", "Okay", "Perfect", "Weird"};
+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;
+ if (value < min)
+ res = BAD;
+ if (cur_rate == INIT)
+ return res;
+ if (res < cur_rate)
+ return res;
+ else
+ 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 (uint8_t 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->ind_left_right_tim && lane->steps[TIM_RIGHT] * results->tim_coef != tim_min)
+ result = false;
+ if (results->volt_support)
+ {
+ if (lane->steps[VOLT_UP] * results->volt_coef != volt_min)
+ result = false;
+ if (results->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, uint8_t recvs_n)
+{
+ struct margin_res_lane *lane;
+ struct margin_results *recv;
+
+ enum lane_rating lane_rating;
+
+ uint8_t link_speed;
+
+ char *no_test_msgs[] = {
+ "", "Margining Ready bit is Clear",
+ "Error during caps reading",
+ "Margining prerequisites are not satisfied (Gen 4/5, D0)",
+ "Invalid lanes specified with arguments",
+ "Invalid receivers specified with arguments",
+ "Couldn't disable ASPM"};
+
+ for (uint8_t i = 0; i < recvs_n; i++)
+ {
+ recv = &(results[i]);
+ link_speed = recv->link_speed - 4;
+
+ if (recv->test_status != MARGIN_TEST_OK)
+ {
+ if (recv->test_status < MARGIN_TEST_PREREQS)
+ printf("Rx(%X) -", 10 + recv->recvn - 1);
+ printf(" Couldn't run test (%s)\n\n", no_test_msgs[recv->test_status]);
+ continue;
+ }
+
+ if (recv->lane_reversal)
+ printf("Rx(%X) - Lane Reversal\n", 10 + recv->recvn - 1);
+ if (check_recv_weird(recv, MARGIN_TIM_MIN, MARGIN_VOLT_MIN))
+ lane_rating = WEIRD;
+ else
+ lane_rating = INIT;
+
+ for (uint8_t j = 0; j < recv->lanes_n; j++)
+ {
+ lane = &(recv->lanes[j]);
+ double left_ui = lane->steps[TIM_LEFT] * recv->tim_coef;
+ double right_ui = lane->steps[TIM_RIGHT] * recv->tim_coef;
+ double up_volt = lane->steps[VOLT_UP] * recv->volt_coef;
+ double down_volt = lane->steps[VOLT_DOWN] * recv->volt_coef;
+
+ if (lane_rating != WEIRD)
+ {
+ lane_rating = rate_lane(left_ui, MARGIN_TIM_MIN, MARGIN_TIM_RECOMMEND, INIT);
+ if (recv->ind_left_right_tim)
+ lane_rating = rate_lane(right_ui, MARGIN_TIM_MIN, MARGIN_TIM_RECOMMEND, lane_rating);
+ if (recv->volt_support)
+ {
+ lane_rating = rate_lane(up_volt, MARGIN_VOLT_MIN, MARGIN_VOLT_MIN, lane_rating);
+ if (recv->ind_up_down_volt)
+ lane_rating = rate_lane(down_volt, MARGIN_VOLT_MIN, MARGIN_VOLT_MIN, lane_rating);
+ }
+ }
+
+ printf("Rx(%X) Lane %2d - %s\t", 10 + recv->recvn - 1, lane->lane, grades[lane_rating]);
+ if (recv->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]]);
+ 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]]);
+ if (recv->volt_support)
+ {
+ if (recv->ind_up_down_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], sts_strings[lane->statuses[VOLT_UP]]);
+ }
+ printf("\n");
+ }
+ printf("\n");
+ }
+}
new file mode 100644
@@ -0,0 +1,13 @@
+#ifndef _MARGIN_RESULTS_H
+#define _MARGIN_RESULTS_H
+
+#include "margin.h"
+
+#define MARGIN_TIM_MIN 20
+#define MARGIN_TIM_RECOMMEND 30
+
+#define MARGIN_VOLT_MIN 50
+
+void margin_results_print_brief(struct margin_results *results, uint8_t recvs_n);
+
+#endif