xref: /pciutils/pcilmr.c (revision 390902d6)
1ce123c88SNikita Proshkin /*
2ce123c88SNikita Proshkin  *	The PCI Utilities -- Margining utility main function
3ce123c88SNikita Proshkin  *
492399f44SNikita Proshkin  *	Copyright (c) 2023-2024 KNS Group LLC (YADRO)
5ce123c88SNikita Proshkin  *
6ce123c88SNikita Proshkin  *	Can be freely distributed and used under the terms of the GNU GPL v2+.
7ce123c88SNikita Proshkin  *
8ce123c88SNikita Proshkin  *	SPDX-License-Identifier: GPL-2.0-or-later
9ce123c88SNikita Proshkin  */
10ce123c88SNikita Proshkin 
11ce123c88SNikita Proshkin #include <memory.h>
12ce123c88SNikita Proshkin #include <stdio.h>
13ce123c88SNikita Proshkin #include <stdlib.h>
14ce123c88SNikita Proshkin 
15ce123c88SNikita Proshkin #include "lmr/lmr.h"
16ce123c88SNikita Proshkin 
17ce123c88SNikita Proshkin const char program_name[] = "pcilmr";
18ce123c88SNikita Proshkin 
1965f3c322SNikita Proshkin static void
scan_links(struct pci_access * pacc,bool only_ready)2065f3c322SNikita Proshkin scan_links(struct pci_access *pacc, bool only_ready)
2165f3c322SNikita Proshkin {
2265f3c322SNikita Proshkin   if (only_ready)
2365f3c322SNikita Proshkin     printf("Links ready for margining:\n");
2465f3c322SNikita Proshkin   else
2565f3c322SNikita Proshkin     printf("Links with Lane Margining at the Receiver capabilities:\n");
2665f3c322SNikita Proshkin   bool flag = true;
2792399f44SNikita Proshkin   for (struct pci_dev *p = pacc->devices; p; p = p->next)
2865f3c322SNikita Proshkin     {
2992399f44SNikita Proshkin       if (pci_find_cap(p, PCI_EXT_CAP_ID_LMR, PCI_CAP_EXTENDED) && margin_port_is_down(p))
3065f3c322SNikita Proshkin         {
3192399f44SNikita Proshkin           struct pci_dev *down = NULL;
3292399f44SNikita Proshkin           struct pci_dev *up = NULL;
3392399f44SNikita Proshkin           margin_find_pair(pacc, p, &down, &up);
3465f3c322SNikita Proshkin 
3565f3c322SNikita Proshkin           if (down && margin_verify_link(down, up))
3665f3c322SNikita Proshkin             {
3765f3c322SNikita Proshkin               margin_log_bdfs(down, up);
3865f3c322SNikita Proshkin               if (!only_ready && (margin_check_ready_bit(down) || margin_check_ready_bit(up)))
3965f3c322SNikita Proshkin                 printf(" - Ready");
4065f3c322SNikita Proshkin               printf("\n");
4165f3c322SNikita Proshkin               flag = false;
4265f3c322SNikita Proshkin             }
4365f3c322SNikita Proshkin         }
4465f3c322SNikita Proshkin     }
4565f3c322SNikita Proshkin   if (flag)
4665f3c322SNikita Proshkin     printf("Links not found or you don't have enough privileges.\n");
4765f3c322SNikita Proshkin   pci_cleanup(pacc);
4865f3c322SNikita Proshkin   exit(0);
4965f3c322SNikita Proshkin }
5065f3c322SNikita Proshkin 
51ce123c88SNikita Proshkin int
main(int argc,char ** argv)52ce123c88SNikita Proshkin main(int argc, char **argv)
53ce123c88SNikita Proshkin {
54ce123c88SNikita Proshkin   struct pci_access *pacc;
55ce123c88SNikita Proshkin 
5626359ed3SNikita Proshkin   u8 links_n = 0;
575648e3f6SNikita Proshkin   struct margin_link *links;
585648e3f6SNikita Proshkin   bool *checks_status_ports;
59ce123c88SNikita Proshkin 
6026359ed3SNikita Proshkin   enum margin_mode mode;
61ce123c88SNikita Proshkin 
625648e3f6SNikita Proshkin   /* each link has several receivers -> several results */
635648e3f6SNikita Proshkin   struct margin_results **results;
645648e3f6SNikita Proshkin   u8 *results_n;
65ce123c88SNikita Proshkin 
66ce123c88SNikita Proshkin   pacc = pci_alloc();
67ce123c88SNikita Proshkin   pci_init(pacc);
68ce123c88SNikita Proshkin   pci_scan_bus(pacc);
69ce123c88SNikita Proshkin 
70ce123c88SNikita Proshkin   margin_print_domain = false;
71ce123c88SNikita Proshkin   for (struct pci_dev *dev = pacc->devices; dev; dev = dev->next)
72ce123c88SNikita Proshkin     {
73ce123c88SNikita Proshkin       if (dev->domain != 0)
74ce123c88SNikita Proshkin         {
75ce123c88SNikita Proshkin           margin_print_domain = true;
76ce123c88SNikita Proshkin           break;
77ce123c88SNikita Proshkin         }
78ce123c88SNikita Proshkin     }
79ce123c88SNikita Proshkin 
80ce123c88SNikita Proshkin   margin_global_logging = true;
81ce123c88SNikita Proshkin 
825648e3f6SNikita Proshkin   struct option long_options[]
835648e3f6SNikita Proshkin     = { { .name = "margin", .has_arg = no_argument, .flag = NULL, .val = 0 },
8465f3c322SNikita Proshkin         { .name = "scan", .has_arg = no_argument, .flag = NULL, .val = 1 },
8565f3c322SNikita Proshkin         { .name = "full", .has_arg = no_argument, .flag = NULL, .val = 2 },
865648e3f6SNikita Proshkin         { 0, 0, 0, 0 } };
875648e3f6SNikita Proshkin 
8826359ed3SNikita Proshkin   opterr = 0;
89ce123c88SNikita Proshkin   int c;
9026359ed3SNikita Proshkin   c = getopt_long(argc, argv, "+", long_options, NULL);
915648e3f6SNikita Proshkin 
925648e3f6SNikita Proshkin   switch (c)
935648e3f6SNikita Proshkin     {
945648e3f6SNikita Proshkin       case -1: /* no options (strings like component are possible) */
955648e3f6SNikita Proshkin         /* FALLTHROUGH */
965648e3f6SNikita Proshkin       case 0:
975648e3f6SNikita Proshkin         mode = MARGIN;
985648e3f6SNikita Proshkin         break;
995648e3f6SNikita Proshkin       case 1:
10065f3c322SNikita Proshkin         mode = SCAN;
10165f3c322SNikita Proshkin         if (optind == argc)
10265f3c322SNikita Proshkin           scan_links(pacc, false);
10326359ed3SNikita Proshkin         else
10426359ed3SNikita Proshkin           die("Invalid arguments\n\n%s", usage);
10565f3c322SNikita Proshkin         break;
10665f3c322SNikita Proshkin       case 2:
1075648e3f6SNikita Proshkin         mode = FULL;
1085648e3f6SNikita Proshkin         break;
1095648e3f6SNikita Proshkin       default: /* unknown option symbol */
1105648e3f6SNikita Proshkin         mode = MARGIN;
1115648e3f6SNikita Proshkin         optind--;
1125648e3f6SNikita Proshkin         break;
1135648e3f6SNikita Proshkin     }
114ce123c88SNikita Proshkin 
11526359ed3SNikita Proshkin   opterr = 1;
116ce123c88SNikita Proshkin 
11726359ed3SNikita Proshkin   links = margin_parse_util_args(pacc, argc, argv, mode, &links_n);
11826359ed3SNikita Proshkin   struct margin_com_args *com_args = links[0].args.common;
119ce123c88SNikita Proshkin 
12026359ed3SNikita Proshkin   results = xmalloc(links_n * sizeof(*results));
12126359ed3SNikita Proshkin   results_n = xmalloc(links_n * sizeof(*results_n));
12226359ed3SNikita Proshkin   checks_status_ports = xmalloc(links_n * sizeof(*checks_status_ports));
123ce123c88SNikita Proshkin 
12426359ed3SNikita Proshkin   for (int i = 0; i < links_n; i++)
1255648e3f6SNikita Proshkin     {
126ce123c88SNikita Proshkin       enum margin_test_status args_status;
127ce123c88SNikita Proshkin 
12826359ed3SNikita Proshkin       if ((args_status = margin_process_args(&links[i])) != MARGIN_TEST_OK)
129ce123c88SNikita Proshkin         {
1305648e3f6SNikita Proshkin           checks_status_ports[i] = false;
1315648e3f6SNikita Proshkin           results[i] = xmalloc(sizeof(*results[i]));
1325648e3f6SNikita Proshkin           results[i]->test_status = args_status;
1335648e3f6SNikita Proshkin           continue;
1345648e3f6SNikita Proshkin         }
1355648e3f6SNikita Proshkin 
1365648e3f6SNikita Proshkin       checks_status_ports[i] = true;
137ce123c88SNikita Proshkin       struct margin_params params;
13826359ed3SNikita Proshkin       struct margin_link_args *link_args = &links[i].args;
139ce123c88SNikita Proshkin 
14026359ed3SNikita Proshkin       for (int j = 0; j < link_args->recvs_n; j++)
141ce123c88SNikita Proshkin         {
14226359ed3SNikita Proshkin           if (margin_read_params(
14326359ed3SNikita Proshkin                 pacc, link_args->recvs[j] == 6 ? links[i].up_port.dev : links[i].down_port.dev,
14426359ed3SNikita Proshkin                 link_args->recvs[j], &params))
145ce123c88SNikita Proshkin             {
14626359ed3SNikita Proshkin               u8 steps_t = link_args->steps_t ? link_args->steps_t : params.timing_steps;
14726359ed3SNikita Proshkin               u8 steps_v = link_args->steps_v ? link_args->steps_v : params.volt_steps;
14826359ed3SNikita Proshkin               u8 parallel_recv = link_args->parallel_lanes > params.max_lanes + 1 ?
14926359ed3SNikita Proshkin                                    params.max_lanes + 1 :
15026359ed3SNikita Proshkin                                    link_args->parallel_lanes;
151ce123c88SNikita Proshkin 
152ce123c88SNikita Proshkin               u8 step_multiplier
15326359ed3SNikita Proshkin                 = link_args->lanes_n / parallel_recv + ((link_args->lanes_n % parallel_recv) > 0);
154ce123c88SNikita Proshkin 
15526359ed3SNikita Proshkin               com_args->steps_utility += steps_t * step_multiplier;
156ce123c88SNikita Proshkin               if (params.ind_left_right_tim)
15726359ed3SNikita Proshkin                 com_args->steps_utility += steps_t * step_multiplier;
158ce123c88SNikita Proshkin               if (params.volt_support)
159ce123c88SNikita Proshkin                 {
16026359ed3SNikita Proshkin                   com_args->steps_utility += steps_v * step_multiplier;
161ce123c88SNikita Proshkin                   if (params.ind_up_down_volt)
16226359ed3SNikita Proshkin                     com_args->steps_utility += steps_v * step_multiplier;
163ce123c88SNikita Proshkin                 }
164ce123c88SNikita Proshkin             }
165ce123c88SNikita Proshkin         }
166ce123c88SNikita Proshkin     }
167ce123c88SNikita Proshkin 
16826359ed3SNikita Proshkin   for (int i = 0; i < links_n; i++)
169ce123c88SNikita Proshkin     {
1705648e3f6SNikita Proshkin       if (checks_status_ports[i])
17126359ed3SNikita Proshkin         results[i] = margin_test_link(&links[i], &results_n[i]);
1725648e3f6SNikita Proshkin       else
1735648e3f6SNikita Proshkin         {
1745648e3f6SNikita Proshkin           results_n[i] = 1;
17526359ed3SNikita Proshkin           if (results[i]->test_status == MARGIN_TEST_ARGS_RECVS)
1765648e3f6SNikita Proshkin             {
1775648e3f6SNikita Proshkin               margin_log_link(&links[i]);
1785648e3f6SNikita Proshkin               printf("\nInvalid RecNums specified.\n");
1795648e3f6SNikita Proshkin             }
1805648e3f6SNikita Proshkin           else if (results[i]->test_status == MARGIN_TEST_ARGS_LANES)
1815648e3f6SNikita Proshkin             {
1825648e3f6SNikita Proshkin               margin_log_link(&links[i]);
1835648e3f6SNikita Proshkin               printf("\nInvalid lanes specified.\n");
1845648e3f6SNikita Proshkin             }
1855648e3f6SNikita Proshkin         }
1865648e3f6SNikita Proshkin       printf("\n----\n\n");
1875648e3f6SNikita Proshkin     }
1885648e3f6SNikita Proshkin 
18926359ed3SNikita Proshkin   if (com_args->run_margin)
1905648e3f6SNikita Proshkin     {
1915648e3f6SNikita Proshkin       printf("Results:\n");
192ce123c88SNikita Proshkin       printf(
193ce123c88SNikita Proshkin         "Margining statuses:\nLIM -\tErrorCount exceeded Error Count Limit (found device limit)\n");
194ce123c88SNikita Proshkin       printf("NAK -\tDevice didn't execute last command, \n\tso result may be less reliable\n");
195ce123c88SNikita Proshkin       printf("THR -\tThe set (using the utility options) \n\tstep threshold has been reached\n\n");
196ce123c88SNikita Proshkin       printf("Notations:\nst - steps\n\n");
197ce123c88SNikita Proshkin 
19826359ed3SNikita Proshkin       for (int i = 0; i < links_n; i++)
1995648e3f6SNikita Proshkin         {
2005648e3f6SNikita Proshkin           printf("Link ");
20126359ed3SNikita Proshkin           margin_log_bdfs(links[i].down_port.dev, links[i].up_port.dev);
2025648e3f6SNikita Proshkin           printf(":\n\n");
203*390902d6SNikita Proshkin           margin_results_print_brief(results[i], results_n[i], &links[i].args);
20426359ed3SNikita Proshkin           if (com_args->save_csv)
20526359ed3SNikita Proshkin             margin_results_save_csv(results[i], results_n[i], &links[i]);
2065648e3f6SNikita Proshkin           printf("\n");
2075648e3f6SNikita Proshkin         }
208ce123c88SNikita Proshkin     }
209ce123c88SNikita Proshkin 
21026359ed3SNikita Proshkin   for (int i = 0; i < links_n; i++)
2115648e3f6SNikita Proshkin     margin_free_results(results[i], results_n[i]);
2125648e3f6SNikita Proshkin   free(results_n);
2135648e3f6SNikita Proshkin   free(results);
21426359ed3SNikita Proshkin   free(com_args);
2155648e3f6SNikita Proshkin   free(links);
2165648e3f6SNikita Proshkin   free(checks_status_ports);
217ce123c88SNikita Proshkin 
218ce123c88SNikita Proshkin   pci_cleanup(pacc);
219ce123c88SNikita Proshkin   return 0;
220ce123c88SNikita Proshkin }
221