]> mj.ucw.cz Git - pciutils.git/blob - pcilmr.c
Add display function for cxl1.1 device link status information. (#183)
[pciutils.git] / pcilmr.c
1 /*
2  *      The PCI Utilities -- Margining utility main function
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 #include <memory.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14
15 #include "lmr/lmr.h"
16
17 const char program_name[] = "pcilmr";
18
19 static void
20 scan_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;
27   for (struct pci_dev *p = pacc->devices; p; p = p->next)
28     {
29       if (pci_find_cap(p, PCI_EXT_CAP_ID_LMR, PCI_CAP_EXTENDED) && margin_port_is_down(p))
30         {
31           struct pci_dev *down = NULL;
32           struct pci_dev *up = NULL;
33           margin_find_pair(pacc, p, &down, &up);
34
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
51 int
52 main(int argc, char **argv)
53 {
54   struct pci_access *pacc;
55
56   u8 links_n = 0;
57   struct margin_link *links;
58   bool *checks_status_ports;
59
60   enum margin_mode mode;
61
62   /* each link has several receivers -> several results */
63   struct margin_results **results;
64   u8 *results_n;
65
66   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
82   struct option long_options[]
83     = { { .name = "margin", .has_arg = no_argument, .flag = NULL, .val = 0 },
84         { .name = "scan", .has_arg = no_argument, .flag = NULL, .val = 1 },
85         { .name = "full", .has_arg = no_argument, .flag = NULL, .val = 2 },
86         { 0, 0, 0, 0 } };
87
88   opterr = 0;
89   int c;
90   c = getopt_long(argc, argv, "+", long_options, NULL);
91
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:
100         mode = SCAN;
101         if (optind == argc)
102           scan_links(pacc, false);
103         else
104           die("Invalid arguments\n\n%s", usage);
105         break;
106       case 2:
107         mode = FULL;
108         break;
109       default: /* unknown option symbol */
110         mode = MARGIN;
111         optind--;
112         break;
113     }
114
115   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++)
125     {
126       enum margin_test_status args_status;
127
128       if ((args_status = margin_process_args(&links[i])) != MARGIN_TEST_OK)
129         {
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;
137       struct margin_params params;
138       struct margin_link_args *link_args = &links[i].args;
139
140       for (int j = 0; j < link_args->recvs_n; j++)
141         {
142           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))
145             {
146               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;
151
152               u8 step_multiplier
153                 = link_args->lanes_n / parallel_recv + ((link_args->lanes_n % parallel_recv) > 0);
154
155               com_args->steps_utility += steps_t * step_multiplier;
156               if (params.ind_left_right_tim)
157                 com_args->steps_utility += steps_t * step_multiplier;
158               if (params.volt_support)
159                 {
160                   com_args->steps_utility += steps_v * step_multiplier;
161                   if (params.ind_up_down_volt)
162                     com_args->steps_utility += steps_v * step_multiplier;
163                 }
164             }
165         }
166     }
167
168   for (int i = 0; i < links_n; i++)
169     {
170       if (checks_status_ports[i])
171         results[i] = margin_test_link(&links[i], &results_n[i]);
172       else
173         {
174           results_n[i] = 1;
175           if (results[i]->test_status == MARGIN_TEST_ARGS_RECVS)
176             {
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
189   if (com_args->run_margin)
190     {
191       printf("Results:\n");
192       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
198       for (int i = 0; i < links_n; i++)
199         {
200           printf("Link ");
201           margin_log_bdfs(links[i].down_port.dev, links[i].up_port.dev);
202           printf(":\n\n");
203           margin_results_print_brief(results[i], results_n[i], &links[i].args);
204           if (com_args->save_csv)
205             margin_results_save_csv(results[i], results_n[i], &links[i]);
206           printf("\n");
207         }
208     }
209
210   for (int i = 0; i < links_n; i++)
211     margin_free_results(results[i], results_n[i]);
212   free(results_n);
213   free(results);
214   free(com_args);
215   free(links);
216   free(checks_status_ports);
217
218   pci_cleanup(pacc);
219   return 0;
220 }