2 * The PCI Utilities -- Margining utility main header
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
18 #define MARGIN_STEP_MS 1000
20 enum margin_hw { MARGIN_HW_DEFAULT, MARGIN_ICE_LAKE_RC };
23 static const double margin_ui[] = { 62.5, 31.25 };
25 /* PCI Device wrapper for margining functions */
35 /* Saved Device settings to restore after margining */
37 bool hasd; // Hardware Autonomous Speed Disable
38 bool hawd; // Hardware Autonomous Width Disable
41 /* Specification Revision 5.0 Table 8-11 */
42 struct margin_params {
43 bool ind_error_sampler;
44 bool sample_report_method;
45 bool ind_left_right_tim;
46 bool ind_up_down_volt;
61 /* Step Margin Execution Status - Step command response */
62 enum margin_step_exec_sts {
63 MARGIN_NAK = 0, // NAK/Set up for margin
64 MARGIN_LIM, // Too many errors (device limit)
65 MARGIN_THR // Test threshold has been reached
68 enum margin_dir { VOLT_UP = 0, VOLT_DOWN, TIM_LEFT, TIM_RIGHT };
70 /* Margining results of one lane of the receiver */
71 struct margin_res_lane {
74 enum margin_step_exec_sts statuses[4];
77 /* Reason not to run margining test on the Link/Receiver */
78 enum margin_test_status {
80 MARGIN_TEST_READY_BIT,
85 MARGIN_TEST_ARGS_LANES,
86 MARGIN_TEST_ARGS_RECVS,
90 /* All lanes Receiver results */
91 struct margin_results {
92 u8 recvn; // Receiver Number; from 1 to 6
93 struct margin_params params;
97 enum margin_test_status test_status;
99 /* Used to convert steps to physical quantity.
100 Calculated from MaxOffset and NumSteps */
101 double tim_coef; // from steps to % UI
104 bool tim_off_reported;
105 bool volt_off_reported;
108 struct margin_res_lane *lanes;
111 /* pcilmr arguments */
114 struct margin_com_args {
115 u8 error_limit; // [0; 63]
116 bool run_margin; // Or print params only
117 u8 verbosity; // 0 - basic;
118 // 1 - add info about remaining time and lanes in progress during margining
119 u64 steps_utility; // For ETA logging
124 struct margin_recv_args {
128 double criteria; // in ps/mV
129 bool one_side_is_whole;
133 struct margin_link_args {
134 struct margin_com_args *common;
135 u8 steps_t; // 0 == use NumTimingSteps
136 u8 steps_v; // 0 == use NumVoltageSteps
137 u8 parallel_lanes; // [1; MaxLanes + 1]
138 u8 recvs[6]; // Receivers Numbers
139 u8 recvs_n; // 0 == margin all available receivers
140 struct margin_recv_args recv_args[6];
141 u8 lanes[32]; // Lanes to Margin
142 u8 lanes_n; // 0 == margin all available lanes
146 struct margin_dev down_port;
147 struct margin_dev up_port;
148 struct margin_link_args args;
151 /* Receiver structure */
153 struct margin_dev *dev;
154 u8 recvn; // Receiver Number; from 1 to 6
156 struct margin_params *params;
162 struct margin_lanes_data {
163 struct margin_recv *recv;
165 struct margin_res_lane *results;
181 enum margin_mode { MARGIN, FULL, SCAN };
183 extern const char *usage;
185 struct margin_link *margin_parse_util_args(struct pci_access *pacc, int argc, char **argv,
186 enum margin_mode mode, u8 *links_n);
190 bool margin_port_is_down(struct pci_dev *dev);
192 /* Results through down/up ports */
193 bool margin_find_pair(struct pci_access *pacc, struct pci_dev *dev, struct pci_dev **down_port,
194 struct pci_dev **up_port);
196 /* Verify that devices form the link with 16 GT/s or 32 GT/s data rate */
197 bool margin_verify_link(struct pci_dev *down_port, struct pci_dev *up_port);
199 /* Check Margining Ready bit from Margining Port Status Register */
200 bool margin_check_ready_bit(struct pci_dev *dev);
202 /* Verify link and fill wrappers */
203 bool margin_fill_link(struct pci_dev *down_port, struct pci_dev *up_port,
204 struct margin_link *wrappers);
206 /* Disable ASPM, set Hardware Autonomous Speed/Width Disable bits */
207 bool margin_prep_link(struct margin_link *link);
209 /* Restore ASPM, Hardware Autonomous Speed/Width settings */
210 void margin_restore_link(struct margin_link *link);
214 /* Fill margin_params without calling other functions */
215 bool margin_read_params(struct pci_access *pacc, struct pci_dev *dev, u8 recvn,
216 struct margin_params *params);
218 enum margin_test_status margin_process_args(struct margin_link *link);
220 /* Awaits that links are prepared through process_args.
221 Returns number of margined Receivers through recvs_n */
222 struct margin_results *margin_test_link(struct margin_link *link, u8 *recvs_n);
224 void margin_free_results(struct margin_results *results, u8 results_n);
228 extern bool margin_global_logging;
229 extern bool margin_print_domain;
231 void margin_log(char *format, ...);
234 void margin_log_bdfs(struct pci_dev *down_port, struct pci_dev *up_port);
235 void margin_gen_bdfs(struct pci_dev *down_port, struct pci_dev *up_port, char *dest, size_t maxlen);
237 /* Print Link header (bdfs, width, speed) */
238 void margin_log_link(struct margin_link *link);
240 void margin_log_params(struct margin_params *params);
242 /* Print receiver number */
243 void margin_log_recvn(struct margin_recv *recv);
245 /* Print full info from Receiver struct */
246 void margin_log_receiver(struct margin_recv *recv);
248 /* Margining in progress log */
249 void margin_log_margining(struct margin_lanes_data arg);
251 void margin_log_hw_quirks(struct margin_recv *recv);
255 // Min values are taken from PCIe Base Spec Rev. 5.0 Section 8.4.2.
256 // Rec values are based on PCIe Arch PHY Test Spec Rev 5.0
257 // (Transmitter Electrical Compliance)
260 static const double margin_ew_min[] = { 18.75, 9.375 };
261 static const double margin_ew_rec[] = { 23.75, 10.1565 };
263 static const double margin_eh_min[] = { 15, 15 };
264 static const double margin_eh_rec[] = { 21, 19.75 };
266 void margin_results_print_brief(struct margin_results *results, u8 recvs_n,
267 struct margin_link_args *args);
269 void margin_results_save_csv(struct margin_results *results, u8 recvs_n, struct margin_link *link);