xref: /aosp_15_r20/external/pciutils/lmr/lmr.h (revision c2e0c6b56a71da9abe8df5c8348fb3eb5c2c9251)
1 /*
2  *	The PCI Utilities -- Margining utility main header
3  *
4  *	Copyright (c) 2023-2024 KNS Group LLC (YADRO)
5  *
6  *	Can be freely distributed and used under the terms of the GNU GPL v2+.
7  *
8  *	SPDX-License-Identifier: GPL-2.0-or-later
9  */
10 
11 #ifndef _LMR_H
12 #define _LMR_H
13 
14 #include <stdbool.h>
15 
16 #include "pciutils.h"
17 
18 enum margin_hw { MARGIN_HW_DEFAULT, MARGIN_ICE_LAKE_RC };
19 
20 // in ps
21 static const double margin_ui[] = { 62.5, 31.25 };
22 
23 /* PCI Device wrapper for margining functions */
24 struct margin_dev {
25   struct pci_dev *dev;
26   int lmr_cap_addr;
27   u8 neg_width;
28   u8 max_width;
29   u8 retimers_n;
30   u8 link_speed;
31 
32   enum margin_hw hw;
33 
34   /* Saved Device settings to restore after margining */
35   u8 aspm;
36   bool hasd; // Hardware Autonomous Speed Disable
37   bool hawd; // Hardware Autonomous Width Disable
38 };
39 
40 /* Specification Revision 5.0 Table 8-11 */
41 struct margin_params {
42   bool ind_error_sampler;
43   bool sample_report_method;
44   bool ind_left_right_tim;
45   bool ind_up_down_volt;
46   bool volt_support;
47 
48   u8 max_lanes;
49 
50   u8 timing_steps;
51   u8 timing_offset;
52 
53   u8 volt_steps;
54   u8 volt_offset;
55 
56   u8 sample_rate_v;
57   u8 sample_rate_t;
58 };
59 
60 /* Step Margin Execution Status - Step command response */
61 enum margin_step_exec_sts {
62   MARGIN_NAK = 0, // NAK/Set up for margin
63   MARGIN_LIM,     // Too many errors (device limit)
64   MARGIN_THR      // Test threshold has been reached
65 };
66 
67 enum margin_dir { VOLT_UP = 0, VOLT_DOWN, TIM_LEFT, TIM_RIGHT };
68 
69 /* Margining results of one lane of the receiver */
70 struct margin_res_lane {
71   u8 lane;
72   u8 steps[4];
73   enum margin_step_exec_sts statuses[4];
74 };
75 
76 /* Reason not to run margining test on the Link/Receiver */
77 enum margin_test_status {
78   MARGIN_TEST_OK = 0,
79   MARGIN_TEST_READY_BIT,
80   MARGIN_TEST_CAPS,
81 
82   // Couldn't run test
83   MARGIN_TEST_PREREQS,
84   MARGIN_TEST_ARGS_LANES,
85   MARGIN_TEST_ARGS_RECVS,
86   MARGIN_TEST_ASPM
87 };
88 
89 /* All lanes Receiver results */
90 struct margin_results {
91   u8 recvn; // Receiver Number; from 1 to 6
92   struct margin_params params;
93   bool lane_reversal;
94   u8 link_speed;
95 
96   enum margin_test_status test_status;
97 
98   /* Used to convert steps to physical quantity.
99      Calculated from MaxOffset and NumSteps     */
100   double tim_coef; // from steps to % UI
101   double volt_coef;
102 
103   bool tim_off_reported;
104   bool volt_off_reported;
105 
106   u8 lanes_n;
107   struct margin_res_lane *lanes;
108 };
109 
110 /* pcilmr arguments */
111 
112 // Common args
113 struct margin_com_args {
114   u8 error_limit;    // [0; 63]
115   bool run_margin;   // Or print params only
116   u8 verbosity;      // 0 - basic;
117                      // 1 - add info about remaining time and lanes in progress during margining
118   u64 steps_utility; // For ETA logging
119   bool save_csv;
120   char *dir_for_csv;
121   u8 dwell_time;
122 };
123 
124 struct margin_recv_args {
125   // Grading options
126   struct {
127     bool valid;
128     double criteria; // in ps/mV
129     bool one_side_is_whole;
130   } t, v;
131 };
132 
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
143 };
144 
145 struct margin_link {
146   struct margin_dev down_port;
147   struct margin_dev up_port;
148   struct margin_link_args args;
149 };
150 
151 /* Receiver structure */
152 struct margin_recv {
153   struct margin_dev *dev;
154   u8 recvn; // Receiver Number; from 1 to 6
155   bool lane_reversal;
156   struct margin_params *params;
157 
158   u8 parallel_lanes;
159   u8 error_limit;
160   u8 dwell_time;
161 };
162 
163 struct margin_lanes_data {
164   struct margin_recv *recv;
165 
166   struct margin_res_lane *results;
167   u8 *lanes_numbers;
168   u8 lanes_n;
169 
170   bool ind;
171   enum margin_dir dir;
172 
173   u8 steps_lane_done;
174   u8 steps_lane_total;
175   u64 *steps_utility;
176 
177   u8 verbosity;
178 };
179 
180 /* margin_args */
181 
182 enum margin_mode { MARGIN, FULL, SCAN };
183 
184 extern const char *usage;
185 
186 struct margin_link *margin_parse_util_args(struct pci_access *pacc, int argc, char **argv,
187                                            enum margin_mode mode, u8 *links_n);
188 
189 /* margin_hw */
190 
191 bool margin_port_is_down(struct pci_dev *dev);
192 
193 /* Results through down/up ports */
194 bool margin_find_pair(struct pci_access *pacc, struct pci_dev *dev, struct pci_dev **down_port,
195                       struct pci_dev **up_port);
196 
197 /* Verify that devices form the link with 16 GT/s or 32 GT/s data rate */
198 bool margin_verify_link(struct pci_dev *down_port, struct pci_dev *up_port);
199 
200 /* Check Margining Ready bit from Margining Port Status Register */
201 bool margin_check_ready_bit(struct pci_dev *dev);
202 
203 /* Verify link and fill wrappers */
204 bool margin_fill_link(struct pci_dev *down_port, struct pci_dev *up_port,
205                       struct margin_link *wrappers);
206 
207 /* Disable ASPM, set Hardware Autonomous Speed/Width Disable bits */
208 bool margin_prep_link(struct margin_link *link);
209 
210 /* Restore ASPM, Hardware Autonomous Speed/Width settings */
211 void margin_restore_link(struct margin_link *link);
212 
213 /* margin */
214 
215 /* Fill margin_params without calling other functions */
216 bool margin_read_params(struct pci_access *pacc, struct pci_dev *dev, u8 recvn,
217                         struct margin_params *params);
218 
219 enum margin_test_status margin_process_args(struct margin_link *link);
220 
221 /* Awaits that links are prepared through process_args.
222    Returns number of margined Receivers through recvs_n */
223 struct margin_results *margin_test_link(struct margin_link *link, u8 *recvs_n);
224 
225 void margin_free_results(struct margin_results *results, u8 results_n);
226 
227 /* margin_log */
228 
229 extern bool margin_global_logging;
230 extern bool margin_print_domain;
231 
232 void margin_log(char *format, ...);
233 
234 /* b:d.f -> b:d.f */
235 void margin_log_bdfs(struct pci_dev *down_port, struct pci_dev *up_port);
236 void margin_gen_bdfs(struct pci_dev *down_port, struct pci_dev *up_port, char *dest, size_t maxlen);
237 
238 /* Print Link header (bdfs, neg_width, speed) */
239 void margin_log_link(struct margin_link *link);
240 
241 void margin_log_params(struct margin_params *params);
242 
243 /* Print receiver number */
244 void margin_log_recvn(struct margin_recv *recv);
245 
246 /* Print full info from Receiver struct */
247 void margin_log_receiver(struct margin_recv *recv);
248 
249 /* Margining in progress log */
250 void margin_log_margining(struct margin_lanes_data arg);
251 
252 void margin_log_hw_quirks(struct margin_recv *recv);
253 
254 /* margin_results */
255 
256 // Min values are taken from PCIe Base Spec Rev. 5.0 Section 8.4.2.
257 // Rec values are based on PCIe Arch PHY Test Spec Rev 5.0
258 // (Transmitter Electrical Compliance)
259 
260 // values in ps
261 static const double margin_ew_min[] = { 18.75, 9.375 };
262 static const double margin_ew_rec[] = { 23.75, 10.1565 };
263 
264 static const double margin_eh_min[] = { 15, 15 };
265 static const double margin_eh_rec[] = { 21, 19.75 };
266 
267 void margin_results_print_brief(struct margin_results *results, u8 recvs_n,
268                                 struct margin_link_args *args);
269 
270 void margin_results_save_csv(struct margin_results *results, u8 recvs_n, struct margin_link *link);
271 
272 #endif
273