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