blob: accee447ed05f9104a32720c695689129d2c819e [file] [log] [blame]
Nikita Proshkince123c82023-12-27 14:44:58 +05001/*
2 * The PCI Utilities -- Margining utility main function
3 *
Nikita Proshkin92399f42024-05-22 19:06:29 +03004 * Copyright (c) 2023-2024 KNS Group LLC (YADRO)
Nikita Proshkince123c82023-12-27 14:44:58 +05005 *
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
Nikita Proshkince123c82023-12-27 14:44:58 +050011#include <memory.h>
12#include <stdio.h>
13#include <stdlib.h>
14
15#include "lmr/lmr.h"
16
17const char program_name[] = "pcilmr";
18
Nikita Proshkin65f3c322023-12-27 14:45:01 +050019static void
20scan_links(struct pci_access *pacc, bool only_ready)
21{
22 if (only_ready)
23 printf("Links ready for margining:\n");
24 else
25 printf("Links with Lane Margining at the Receiver capabilities:\n");
26 bool flag = true;
Nikita Proshkin92399f42024-05-22 19:06:29 +030027 for (struct pci_dev *p = pacc->devices; p; p = p->next)
Nikita Proshkin65f3c322023-12-27 14:45:01 +050028 {
Nikita Proshkin92399f42024-05-22 19:06:29 +030029 if (pci_find_cap(p, PCI_EXT_CAP_ID_LMR, PCI_CAP_EXTENDED) && margin_port_is_down(p))
Nikita Proshkin65f3c322023-12-27 14:45:01 +050030 {
Nikita Proshkin92399f42024-05-22 19:06:29 +030031 struct pci_dev *down = NULL;
32 struct pci_dev *up = NULL;
33 margin_find_pair(pacc, p, &down, &up);
Nikita Proshkin65f3c322023-12-27 14:45:01 +050034
35 if (down && margin_verify_link(down, up))
36 {
37 margin_log_bdfs(down, up);
38 if (!only_ready && (margin_check_ready_bit(down) || margin_check_ready_bit(up)))
39 printf(" - Ready");
40 printf("\n");
41 flag = false;
42 }
43 }
44 }
45 if (flag)
46 printf("Links not found or you don't have enough privileges.\n");
47 pci_cleanup(pacc);
48 exit(0);
49}
50
Nikita Proshkince123c82023-12-27 14:44:58 +050051int
52main(int argc, char **argv)
53{
54 struct pci_access *pacc;
55
Nikita Proshkin26359ed2024-05-22 19:06:30 +030056 u8 links_n = 0;
Nikita Proshkin5648e3f2023-12-27 14:45:00 +050057 struct margin_link *links;
58 bool *checks_status_ports;
Nikita Proshkince123c82023-12-27 14:44:58 +050059
Nikita Proshkin26359ed2024-05-22 19:06:30 +030060 enum margin_mode mode;
Nikita Proshkince123c82023-12-27 14:44:58 +050061
Nikita Proshkin5648e3f2023-12-27 14:45:00 +050062 /* each link has several receivers -> several results */
63 struct margin_results **results;
64 u8 *results_n;
Nikita Proshkince123c82023-12-27 14:44:58 +050065
Nikita Proshkince123c82023-12-27 14:44:58 +050066 pacc = pci_alloc();
67 pci_init(pacc);
68 pci_scan_bus(pacc);
69
70 margin_print_domain = false;
71 for (struct pci_dev *dev = pacc->devices; dev; dev = dev->next)
72 {
73 if (dev->domain != 0)
74 {
75 margin_print_domain = true;
76 break;
77 }
78 }
79
80 margin_global_logging = true;
81
Nikita Proshkin5648e3f2023-12-27 14:45:00 +050082 struct option long_options[]
83 = { { .name = "margin", .has_arg = no_argument, .flag = NULL, .val = 0 },
Nikita Proshkin65f3c322023-12-27 14:45:01 +050084 { .name = "scan", .has_arg = no_argument, .flag = NULL, .val = 1 },
85 { .name = "full", .has_arg = no_argument, .flag = NULL, .val = 2 },
Nikita Proshkin5648e3f2023-12-27 14:45:00 +050086 { 0, 0, 0, 0 } };
87
Nikita Proshkin26359ed2024-05-22 19:06:30 +030088 opterr = 0;
Nikita Proshkince123c82023-12-27 14:44:58 +050089 int c;
Nikita Proshkin26359ed2024-05-22 19:06:30 +030090 c = getopt_long(argc, argv, "+", long_options, NULL);
Nikita Proshkin5648e3f2023-12-27 14:45:00 +050091
92 switch (c)
93 {
94 case -1: /* no options (strings like component are possible) */
95 /* FALLTHROUGH */
96 case 0:
97 mode = MARGIN;
98 break;
99 case 1:
Nikita Proshkin65f3c322023-12-27 14:45:01 +0500100 mode = SCAN;
101 if (optind == argc)
102 scan_links(pacc, false);
Nikita Proshkin26359ed2024-05-22 19:06:30 +0300103 else
104 die("Invalid arguments\n\n%s", usage);
Nikita Proshkin65f3c322023-12-27 14:45:01 +0500105 break;
106 case 2:
Nikita Proshkin5648e3f2023-12-27 14:45:00 +0500107 mode = FULL;
108 break;
109 default: /* unknown option symbol */
110 mode = MARGIN;
111 optind--;
112 break;
113 }
Nikita Proshkince123c82023-12-27 14:44:58 +0500114
Nikita Proshkin26359ed2024-05-22 19:06:30 +0300115 opterr = 1;
116
117 links = margin_parse_util_args(pacc, argc, argv, mode, &links_n);
118 struct margin_com_args *com_args = links[0].args.common;
119
120 results = xmalloc(links_n * sizeof(*results));
121 results_n = xmalloc(links_n * sizeof(*results_n));
122 checks_status_ports = xmalloc(links_n * sizeof(*checks_status_ports));
123
124 for (int i = 0; i < links_n; i++)
Nikita Proshkince123c82023-12-27 14:44:58 +0500125 {
Nikita Proshkince123c82023-12-27 14:44:58 +0500126 enum margin_test_status args_status;
127
Nikita Proshkin26359ed2024-05-22 19:06:30 +0300128 if ((args_status = margin_process_args(&links[i])) != MARGIN_TEST_OK)
Nikita Proshkin5648e3f2023-12-27 14:45:00 +0500129 {
130 checks_status_ports[i] = false;
131 results[i] = xmalloc(sizeof(*results[i]));
132 results[i]->test_status = args_status;
133 continue;
134 }
135
136 checks_status_ports[i] = true;
Nikita Proshkince123c82023-12-27 14:44:58 +0500137 struct margin_params params;
Nikita Proshkin26359ed2024-05-22 19:06:30 +0300138 struct margin_link_args *link_args = &links[i].args;
Nikita Proshkince123c82023-12-27 14:44:58 +0500139
Nikita Proshkin26359ed2024-05-22 19:06:30 +0300140 for (int j = 0; j < link_args->recvs_n; j++)
Nikita Proshkince123c82023-12-27 14:44:58 +0500141 {
Nikita Proshkin26359ed2024-05-22 19:06:30 +0300142 if (margin_read_params(
143 pacc, link_args->recvs[j] == 6 ? links[i].up_port.dev : links[i].down_port.dev,
144 link_args->recvs[j], &params))
Nikita Proshkince123c82023-12-27 14:44:58 +0500145 {
Nikita Proshkin26359ed2024-05-22 19:06:30 +0300146 u8 steps_t = link_args->steps_t ? link_args->steps_t : params.timing_steps;
147 u8 steps_v = link_args->steps_v ? link_args->steps_v : params.volt_steps;
148 u8 parallel_recv = link_args->parallel_lanes > params.max_lanes + 1 ?
149 params.max_lanes + 1 :
150 link_args->parallel_lanes;
Nikita Proshkince123c82023-12-27 14:44:58 +0500151
152 u8 step_multiplier
Nikita Proshkin26359ed2024-05-22 19:06:30 +0300153 = link_args->lanes_n / parallel_recv + ((link_args->lanes_n % parallel_recv) > 0);
Nikita Proshkince123c82023-12-27 14:44:58 +0500154
Nikita Proshkin26359ed2024-05-22 19:06:30 +0300155 com_args->steps_utility += steps_t * step_multiplier;
Nikita Proshkince123c82023-12-27 14:44:58 +0500156 if (params.ind_left_right_tim)
Nikita Proshkin26359ed2024-05-22 19:06:30 +0300157 com_args->steps_utility += steps_t * step_multiplier;
Nikita Proshkince123c82023-12-27 14:44:58 +0500158 if (params.volt_support)
159 {
Nikita Proshkin26359ed2024-05-22 19:06:30 +0300160 com_args->steps_utility += steps_v * step_multiplier;
Nikita Proshkince123c82023-12-27 14:44:58 +0500161 if (params.ind_up_down_volt)
Nikita Proshkin26359ed2024-05-22 19:06:30 +0300162 com_args->steps_utility += steps_v * step_multiplier;
Nikita Proshkince123c82023-12-27 14:44:58 +0500163 }
164 }
165 }
Nikita Proshkince123c82023-12-27 14:44:58 +0500166 }
167
Nikita Proshkin26359ed2024-05-22 19:06:30 +0300168 for (int i = 0; i < links_n; i++)
Nikita Proshkince123c82023-12-27 14:44:58 +0500169 {
Nikita Proshkin5648e3f2023-12-27 14:45:00 +0500170 if (checks_status_ports[i])
Nikita Proshkin26359ed2024-05-22 19:06:30 +0300171 results[i] = margin_test_link(&links[i], &results_n[i]);
Nikita Proshkin5648e3f2023-12-27 14:45:00 +0500172 else
173 {
174 results_n[i] = 1;
Nikita Proshkin26359ed2024-05-22 19:06:30 +0300175 if (results[i]->test_status == MARGIN_TEST_ARGS_RECVS)
Nikita Proshkin5648e3f2023-12-27 14:45:00 +0500176 {
177 margin_log_link(&links[i]);
178 printf("\nInvalid RecNums specified.\n");
179 }
180 else if (results[i]->test_status == MARGIN_TEST_ARGS_LANES)
181 {
182 margin_log_link(&links[i]);
183 printf("\nInvalid lanes specified.\n");
184 }
185 }
186 printf("\n----\n\n");
187 }
188
Nikita Proshkin26359ed2024-05-22 19:06:30 +0300189 if (com_args->run_margin)
Nikita Proshkin5648e3f2023-12-27 14:45:00 +0500190 {
191 printf("Results:\n");
Nikita Proshkince123c82023-12-27 14:44:58 +0500192 printf(
193 "Margining statuses:\nLIM -\tErrorCount exceeded Error Count Limit (found device limit)\n");
194 printf("NAK -\tDevice didn't execute last command, \n\tso result may be less reliable\n");
195 printf("THR -\tThe set (using the utility options) \n\tstep threshold has been reached\n\n");
196 printf("Notations:\nst - steps\n\n");
197
Nikita Proshkin26359ed2024-05-22 19:06:30 +0300198 for (int i = 0; i < links_n; i++)
Nikita Proshkin5648e3f2023-12-27 14:45:00 +0500199 {
200 printf("Link ");
Nikita Proshkin26359ed2024-05-22 19:06:30 +0300201 margin_log_bdfs(links[i].down_port.dev, links[i].up_port.dev);
Nikita Proshkin5648e3f2023-12-27 14:45:00 +0500202 printf(":\n\n");
Nikita Proshkin390902d2024-05-22 19:06:31 +0300203 margin_results_print_brief(results[i], results_n[i], &links[i].args);
Nikita Proshkin26359ed2024-05-22 19:06:30 +0300204 if (com_args->save_csv)
205 margin_results_save_csv(results[i], results_n[i], &links[i]);
Nikita Proshkin5648e3f2023-12-27 14:45:00 +0500206 printf("\n");
207 }
Nikita Proshkince123c82023-12-27 14:44:58 +0500208 }
209
Nikita Proshkin26359ed2024-05-22 19:06:30 +0300210 for (int i = 0; i < links_n; i++)
Nikita Proshkin5648e3f2023-12-27 14:45:00 +0500211 margin_free_results(results[i], results_n[i]);
212 free(results_n);
213 free(results);
Nikita Proshkin26359ed2024-05-22 19:06:30 +0300214 free(com_args);
Nikita Proshkin5648e3f2023-12-27 14:45:00 +0500215 free(links);
216 free(checks_status_ports);
Nikita Proshkince123c82023-12-27 14:44:58 +0500217
218 pci_cleanup(pacc);
219 return 0;
220}