xref: /aosp_15_r20/external/pciutils/lmr/margin_args.c (revision c2e0c6b56a71da9abe8df5c8348fb3eb5c2c9251)
1*c2e0c6b5SAndroid Build Coastguard Worker /*
2*c2e0c6b5SAndroid Build Coastguard Worker  *	The PCI Utilities -- Parse pcilmr utility arguments
3*c2e0c6b5SAndroid Build Coastguard Worker  *
4*c2e0c6b5SAndroid Build Coastguard Worker  *	Copyright (c) 2024 KNS Group LLC (YADRO)
5*c2e0c6b5SAndroid Build Coastguard Worker  *
6*c2e0c6b5SAndroid Build Coastguard Worker  *	Can be freely distributed and used under the terms of the GNU GPL v2+.
7*c2e0c6b5SAndroid Build Coastguard Worker  *
8*c2e0c6b5SAndroid Build Coastguard Worker  *	SPDX-License-Identifier: GPL-2.0-or-later
9*c2e0c6b5SAndroid Build Coastguard Worker  */
10*c2e0c6b5SAndroid Build Coastguard Worker 
11*c2e0c6b5SAndroid Build Coastguard Worker #include <stdio.h>
12*c2e0c6b5SAndroid Build Coastguard Worker #include <stdlib.h>
13*c2e0c6b5SAndroid Build Coastguard Worker #include <string.h>
14*c2e0c6b5SAndroid Build Coastguard Worker 
15*c2e0c6b5SAndroid Build Coastguard Worker #include "lmr.h"
16*c2e0c6b5SAndroid Build Coastguard Worker 
17*c2e0c6b5SAndroid Build Coastguard Worker const char *usage
18*c2e0c6b5SAndroid Build Coastguard Worker   = "! Utility requires preliminary preparation of the system. Refer to the pcilmr man page !\n\n"
19*c2e0c6b5SAndroid Build Coastguard Worker     "Brief usage (see man for all options):\n"
20*c2e0c6b5SAndroid Build Coastguard Worker     "pcilmr [--margin] [<common options>] <link port> [<link options>] [<link port> [<link "
21*c2e0c6b5SAndroid Build Coastguard Worker     "options>] ...]\n"
22*c2e0c6b5SAndroid Build Coastguard Worker     "pcilmr --full [<common options>]\n"
23*c2e0c6b5SAndroid Build Coastguard Worker     "pcilmr --scan\n\n"
24*c2e0c6b5SAndroid Build Coastguard Worker     "You can specify Downstream or Upstream Port of the Link.\nPort Specifier:\n"
25*c2e0c6b5SAndroid Build Coastguard Worker     "<device/component>:\t[<domain>:]<bus>:<dev>.<func>\n\n"
26*c2e0c6b5SAndroid Build Coastguard Worker     "Modes:\n"
27*c2e0c6b5SAndroid Build Coastguard Worker     "--margin\t\tMargin selected Links\n"
28*c2e0c6b5SAndroid Build Coastguard Worker     "--full\t\t\tMargin all ready for testing Links in the system (one by one)\n"
29*c2e0c6b5SAndroid Build Coastguard Worker     "--scan\t\t\tScan for Links available for margining\n\n"
30*c2e0c6b5SAndroid Build Coastguard Worker     "Margining options (see man for all options):\n\n"
31*c2e0c6b5SAndroid Build Coastguard Worker     "Common (for all specified links) options:\n"
32*c2e0c6b5SAndroid Build Coastguard Worker     "-c\t\t\tPrint Device Lane Margining Capabilities only. Do not run margining.\n\n"
33*c2e0c6b5SAndroid Build Coastguard Worker     "Link specific options:\n"
34*c2e0c6b5SAndroid Build Coastguard Worker     "-r <recvn>[,<recvn>...]\tSpecify Receivers to select margining targets.\n"
35*c2e0c6b5SAndroid Build Coastguard Worker     "\t\t\tDefault: all available Receivers (including Retimers).\n"
36*c2e0c6b5SAndroid Build Coastguard Worker     "-t <steps>\t\tSpecify maximum number of steps for Time Margining.\n"
37*c2e0c6b5SAndroid Build Coastguard Worker     "-v <steps>\t\tSpecify maximum number of steps for Voltage Margining.\n";
38*c2e0c6b5SAndroid Build Coastguard Worker 
39*c2e0c6b5SAndroid Build Coastguard Worker static struct pci_dev *
dev_for_filter(struct pci_access * pacc,char * filter)40*c2e0c6b5SAndroid Build Coastguard Worker dev_for_filter(struct pci_access *pacc, char *filter)
41*c2e0c6b5SAndroid Build Coastguard Worker {
42*c2e0c6b5SAndroid Build Coastguard Worker   struct pci_filter pci_filter;
43*c2e0c6b5SAndroid Build Coastguard Worker   pci_filter_init(pacc, &pci_filter);
44*c2e0c6b5SAndroid Build Coastguard Worker   if (pci_filter_parse_slot(&pci_filter, filter))
45*c2e0c6b5SAndroid Build Coastguard Worker     die("Invalid device ID: %s\n", filter);
46*c2e0c6b5SAndroid Build Coastguard Worker 
47*c2e0c6b5SAndroid Build Coastguard Worker   if (pci_filter.bus == -1 || pci_filter.slot == -1 || pci_filter.func == -1)
48*c2e0c6b5SAndroid Build Coastguard Worker     die("Invalid device ID: %s\n", filter);
49*c2e0c6b5SAndroid Build Coastguard Worker 
50*c2e0c6b5SAndroid Build Coastguard Worker   if (pci_filter.domain == -1)
51*c2e0c6b5SAndroid Build Coastguard Worker     pci_filter.domain = 0;
52*c2e0c6b5SAndroid Build Coastguard Worker 
53*c2e0c6b5SAndroid Build Coastguard Worker   for (struct pci_dev *p = pacc->devices; p; p = p->next)
54*c2e0c6b5SAndroid Build Coastguard Worker     {
55*c2e0c6b5SAndroid Build Coastguard Worker       if (pci_filter_match(&pci_filter, p))
56*c2e0c6b5SAndroid Build Coastguard Worker         return p;
57*c2e0c6b5SAndroid Build Coastguard Worker     }
58*c2e0c6b5SAndroid Build Coastguard Worker 
59*c2e0c6b5SAndroid Build Coastguard Worker   die("No such PCI device: %s or you don't have enough privileges.\n", filter);
60*c2e0c6b5SAndroid Build Coastguard Worker }
61*c2e0c6b5SAndroid Build Coastguard Worker 
62*c2e0c6b5SAndroid Build Coastguard Worker static u8
parse_csv_arg(char * arg,u8 * vals)63*c2e0c6b5SAndroid Build Coastguard Worker parse_csv_arg(char *arg, u8 *vals)
64*c2e0c6b5SAndroid Build Coastguard Worker {
65*c2e0c6b5SAndroid Build Coastguard Worker   u8 cnt = 0;
66*c2e0c6b5SAndroid Build Coastguard Worker   char *token = strtok(arg, ",");
67*c2e0c6b5SAndroid Build Coastguard Worker   while (token)
68*c2e0c6b5SAndroid Build Coastguard Worker     {
69*c2e0c6b5SAndroid Build Coastguard Worker       vals[cnt] = atoi(token);
70*c2e0c6b5SAndroid Build Coastguard Worker       cnt++;
71*c2e0c6b5SAndroid Build Coastguard Worker       token = strtok(NULL, ",");
72*c2e0c6b5SAndroid Build Coastguard Worker     }
73*c2e0c6b5SAndroid Build Coastguard Worker   return cnt;
74*c2e0c6b5SAndroid Build Coastguard Worker }
75*c2e0c6b5SAndroid Build Coastguard Worker 
76*c2e0c6b5SAndroid Build Coastguard Worker static u8
find_ready_links(struct pci_access * pacc,struct margin_link * links,bool cnt_only)77*c2e0c6b5SAndroid Build Coastguard Worker find_ready_links(struct pci_access *pacc, struct margin_link *links, bool cnt_only)
78*c2e0c6b5SAndroid Build Coastguard Worker {
79*c2e0c6b5SAndroid Build Coastguard Worker   u8 cnt = 0;
80*c2e0c6b5SAndroid Build Coastguard Worker   for (struct pci_dev *p = pacc->devices; p; p = p->next)
81*c2e0c6b5SAndroid Build Coastguard Worker     {
82*c2e0c6b5SAndroid Build Coastguard Worker       if (pci_find_cap(p, PCI_EXT_CAP_ID_LMR, PCI_CAP_EXTENDED) && margin_port_is_down(p))
83*c2e0c6b5SAndroid Build Coastguard Worker         {
84*c2e0c6b5SAndroid Build Coastguard Worker           struct pci_dev *down = NULL;
85*c2e0c6b5SAndroid Build Coastguard Worker           struct pci_dev *up = NULL;
86*c2e0c6b5SAndroid Build Coastguard Worker           margin_find_pair(pacc, p, &down, &up);
87*c2e0c6b5SAndroid Build Coastguard Worker 
88*c2e0c6b5SAndroid Build Coastguard Worker           if (down && margin_verify_link(down, up)
89*c2e0c6b5SAndroid Build Coastguard Worker               && (margin_check_ready_bit(down) || margin_check_ready_bit(up)))
90*c2e0c6b5SAndroid Build Coastguard Worker             {
91*c2e0c6b5SAndroid Build Coastguard Worker               if (!cnt_only)
92*c2e0c6b5SAndroid Build Coastguard Worker                 margin_fill_link(down, up, &(links[cnt]));
93*c2e0c6b5SAndroid Build Coastguard Worker               cnt++;
94*c2e0c6b5SAndroid Build Coastguard Worker             }
95*c2e0c6b5SAndroid Build Coastguard Worker         }
96*c2e0c6b5SAndroid Build Coastguard Worker     }
97*c2e0c6b5SAndroid Build Coastguard Worker   return cnt;
98*c2e0c6b5SAndroid Build Coastguard Worker }
99*c2e0c6b5SAndroid Build Coastguard Worker 
100*c2e0c6b5SAndroid Build Coastguard Worker static void
init_link_args(struct margin_link_args * link_args,struct margin_com_args * com_args)101*c2e0c6b5SAndroid Build Coastguard Worker init_link_args(struct margin_link_args *link_args, struct margin_com_args *com_args)
102*c2e0c6b5SAndroid Build Coastguard Worker {
103*c2e0c6b5SAndroid Build Coastguard Worker   memset(link_args, 0, sizeof(*link_args));
104*c2e0c6b5SAndroid Build Coastguard Worker   link_args->common = com_args;
105*c2e0c6b5SAndroid Build Coastguard Worker   link_args->parallel_lanes = 1;
106*c2e0c6b5SAndroid Build Coastguard Worker }
107*c2e0c6b5SAndroid Build Coastguard Worker 
108*c2e0c6b5SAndroid Build Coastguard Worker static void
parse_dev_args(int argc,char ** argv,struct margin_link_args * args,u8 link_speed)109*c2e0c6b5SAndroid Build Coastguard Worker parse_dev_args(int argc, char **argv, struct margin_link_args *args, u8 link_speed)
110*c2e0c6b5SAndroid Build Coastguard Worker {
111*c2e0c6b5SAndroid Build Coastguard Worker   if (argc == optind)
112*c2e0c6b5SAndroid Build Coastguard Worker     return;
113*c2e0c6b5SAndroid Build Coastguard Worker   int c;
114*c2e0c6b5SAndroid Build Coastguard Worker   while ((c = getopt(argc, argv, "+r:l:p:t:v:VTg:")) != -1)
115*c2e0c6b5SAndroid Build Coastguard Worker     {
116*c2e0c6b5SAndroid Build Coastguard Worker       switch (c)
117*c2e0c6b5SAndroid Build Coastguard Worker         {
118*c2e0c6b5SAndroid Build Coastguard Worker           case 't':
119*c2e0c6b5SAndroid Build Coastguard Worker             args->steps_t = atoi(optarg);
120*c2e0c6b5SAndroid Build Coastguard Worker             break;
121*c2e0c6b5SAndroid Build Coastguard Worker           case 'T':
122*c2e0c6b5SAndroid Build Coastguard Worker             args->steps_t = 63;
123*c2e0c6b5SAndroid Build Coastguard Worker             break;
124*c2e0c6b5SAndroid Build Coastguard Worker           case 'v':
125*c2e0c6b5SAndroid Build Coastguard Worker             args->steps_v = atoi(optarg);
126*c2e0c6b5SAndroid Build Coastguard Worker             break;
127*c2e0c6b5SAndroid Build Coastguard Worker           case 'V':
128*c2e0c6b5SAndroid Build Coastguard Worker             args->steps_v = 127;
129*c2e0c6b5SAndroid Build Coastguard Worker             break;
130*c2e0c6b5SAndroid Build Coastguard Worker           case 'p':
131*c2e0c6b5SAndroid Build Coastguard Worker             args->parallel_lanes = atoi(optarg);
132*c2e0c6b5SAndroid Build Coastguard Worker             break;
133*c2e0c6b5SAndroid Build Coastguard Worker           case 'l':
134*c2e0c6b5SAndroid Build Coastguard Worker             args->lanes_n = parse_csv_arg(optarg, args->lanes);
135*c2e0c6b5SAndroid Build Coastguard Worker             break;
136*c2e0c6b5SAndroid Build Coastguard Worker           case 'r':
137*c2e0c6b5SAndroid Build Coastguard Worker             args->recvs_n = parse_csv_arg(optarg, args->recvs);
138*c2e0c6b5SAndroid Build Coastguard Worker             break;
139*c2e0c6b5SAndroid Build Coastguard Worker             case 'g': {
140*c2e0c6b5SAndroid Build Coastguard Worker               char recv[2] = { 0 };
141*c2e0c6b5SAndroid Build Coastguard Worker               char dir[2] = { 0 };
142*c2e0c6b5SAndroid Build Coastguard Worker               char unit[4] = { 0 };
143*c2e0c6b5SAndroid Build Coastguard Worker               float criteria = 0.0;
144*c2e0c6b5SAndroid Build Coastguard Worker               char eye[2] = { 0 };
145*c2e0c6b5SAndroid Build Coastguard Worker               int cons[3] = { 0 };
146*c2e0c6b5SAndroid Build Coastguard Worker 
147*c2e0c6b5SAndroid Build Coastguard Worker               int ret = sscanf(optarg, "%1[1-6]%1[tv]=%f%n%3[%,ps]%n%1[f]%n", recv, dir, &criteria,
148*c2e0c6b5SAndroid Build Coastguard Worker                                &cons[0], unit, &cons[1], eye, &cons[2]);
149*c2e0c6b5SAndroid Build Coastguard Worker               if (ret < 3)
150*c2e0c6b5SAndroid Build Coastguard Worker                 {
151*c2e0c6b5SAndroid Build Coastguard Worker                   ret = sscanf(optarg, "%1[1-6]%1[tv]=%1[f]%n,%f%n%2[ps%]%n", recv, dir, eye,
152*c2e0c6b5SAndroid Build Coastguard Worker                                &cons[0], &criteria, &cons[1], unit, &cons[2]);
153*c2e0c6b5SAndroid Build Coastguard Worker                   if (ret < 3)
154*c2e0c6b5SAndroid Build Coastguard Worker                     die("Invalid arguments\n\n%s", usage);
155*c2e0c6b5SAndroid Build Coastguard Worker                 }
156*c2e0c6b5SAndroid Build Coastguard Worker 
157*c2e0c6b5SAndroid Build Coastguard Worker               int consumed = 0;
158*c2e0c6b5SAndroid Build Coastguard Worker               for (int i = 0; i < 3; i++)
159*c2e0c6b5SAndroid Build Coastguard Worker                 if (cons[i] > consumed)
160*c2e0c6b5SAndroid Build Coastguard Worker                   consumed = cons[i];
161*c2e0c6b5SAndroid Build Coastguard Worker               if ((size_t)consumed != strlen(optarg))
162*c2e0c6b5SAndroid Build Coastguard Worker                 die("Invalid arguments\n\n%s", usage);
163*c2e0c6b5SAndroid Build Coastguard Worker               if (criteria < 0)
164*c2e0c6b5SAndroid Build Coastguard Worker                 die("Invalid arguments\n\n%s", usage);
165*c2e0c6b5SAndroid Build Coastguard Worker               if (strstr(unit, ",") && eye[0] == 0)
166*c2e0c6b5SAndroid Build Coastguard Worker                 die("Invalid arguments\n\n%s", usage);
167*c2e0c6b5SAndroid Build Coastguard Worker 
168*c2e0c6b5SAndroid Build Coastguard Worker               u8 recv_n = recv[0] - '0' - 1;
169*c2e0c6b5SAndroid Build Coastguard Worker               if (dir[0] == 'v')
170*c2e0c6b5SAndroid Build Coastguard Worker                 {
171*c2e0c6b5SAndroid Build Coastguard Worker                   if (unit[0] != ',' && unit[0] != 0)
172*c2e0c6b5SAndroid Build Coastguard Worker                     die("Invalid arguments\n\n%s", usage);
173*c2e0c6b5SAndroid Build Coastguard Worker                   args->recv_args[recv_n].v.valid = true;
174*c2e0c6b5SAndroid Build Coastguard Worker                   args->recv_args[recv_n].v.criteria = criteria;
175*c2e0c6b5SAndroid Build Coastguard Worker                   if (eye[0] != 0)
176*c2e0c6b5SAndroid Build Coastguard Worker                     args->recv_args[recv_n].v.one_side_is_whole = true;
177*c2e0c6b5SAndroid Build Coastguard Worker                 }
178*c2e0c6b5SAndroid Build Coastguard Worker               else
179*c2e0c6b5SAndroid Build Coastguard Worker                 {
180*c2e0c6b5SAndroid Build Coastguard Worker                   if (unit[0] == '%')
181*c2e0c6b5SAndroid Build Coastguard Worker                     criteria = criteria / 100.0 * margin_ui[link_speed];
182*c2e0c6b5SAndroid Build Coastguard Worker                   else if (unit[0] != 0 && (unit[0] != 'p' || unit[1] != 's'))
183*c2e0c6b5SAndroid Build Coastguard Worker                     die("Invalid arguments\n\n%s", usage);
184*c2e0c6b5SAndroid Build Coastguard Worker                   else if (unit[0] == 0 && criteria != 0)
185*c2e0c6b5SAndroid Build Coastguard Worker                     die("Invalid arguments\n\n%s", usage);
186*c2e0c6b5SAndroid Build Coastguard Worker                   args->recv_args[recv_n].t.valid = true;
187*c2e0c6b5SAndroid Build Coastguard Worker                   args->recv_args[recv_n].t.criteria = criteria;
188*c2e0c6b5SAndroid Build Coastguard Worker                   if (eye[0] != 0)
189*c2e0c6b5SAndroid Build Coastguard Worker                     args->recv_args[recv_n].t.one_side_is_whole = true;
190*c2e0c6b5SAndroid Build Coastguard Worker                 }
191*c2e0c6b5SAndroid Build Coastguard Worker               break;
192*c2e0c6b5SAndroid Build Coastguard Worker             }
193*c2e0c6b5SAndroid Build Coastguard Worker           case '?':
194*c2e0c6b5SAndroid Build Coastguard Worker             die("Invalid arguments\n\n%s", usage);
195*c2e0c6b5SAndroid Build Coastguard Worker             break;
196*c2e0c6b5SAndroid Build Coastguard Worker           default:
197*c2e0c6b5SAndroid Build Coastguard Worker             return;
198*c2e0c6b5SAndroid Build Coastguard Worker         }
199*c2e0c6b5SAndroid Build Coastguard Worker     }
200*c2e0c6b5SAndroid Build Coastguard Worker }
201*c2e0c6b5SAndroid Build Coastguard Worker 
202*c2e0c6b5SAndroid Build Coastguard Worker struct margin_link *
margin_parse_util_args(struct pci_access * pacc,int argc,char ** argv,enum margin_mode mode,u8 * links_n)203*c2e0c6b5SAndroid Build Coastguard Worker margin_parse_util_args(struct pci_access *pacc, int argc, char **argv, enum margin_mode mode,
204*c2e0c6b5SAndroid Build Coastguard Worker                        u8 *links_n)
205*c2e0c6b5SAndroid Build Coastguard Worker {
206*c2e0c6b5SAndroid Build Coastguard Worker   struct margin_com_args *com_args = xmalloc(sizeof(*com_args));
207*c2e0c6b5SAndroid Build Coastguard Worker   com_args->error_limit = 4;
208*c2e0c6b5SAndroid Build Coastguard Worker   com_args->run_margin = true;
209*c2e0c6b5SAndroid Build Coastguard Worker   com_args->verbosity = 1;
210*c2e0c6b5SAndroid Build Coastguard Worker   com_args->steps_utility = 0;
211*c2e0c6b5SAndroid Build Coastguard Worker   com_args->dir_for_csv = NULL;
212*c2e0c6b5SAndroid Build Coastguard Worker   com_args->save_csv = false;
213*c2e0c6b5SAndroid Build Coastguard Worker   com_args->dwell_time = 1;
214*c2e0c6b5SAndroid Build Coastguard Worker 
215*c2e0c6b5SAndroid Build Coastguard Worker   int c;
216*c2e0c6b5SAndroid Build Coastguard Worker   while ((c = getopt(argc, argv, "+e:co:d:")) != -1)
217*c2e0c6b5SAndroid Build Coastguard Worker     {
218*c2e0c6b5SAndroid Build Coastguard Worker       switch (c)
219*c2e0c6b5SAndroid Build Coastguard Worker         {
220*c2e0c6b5SAndroid Build Coastguard Worker           case 'c':
221*c2e0c6b5SAndroid Build Coastguard Worker             com_args->run_margin = false;
222*c2e0c6b5SAndroid Build Coastguard Worker             break;
223*c2e0c6b5SAndroid Build Coastguard Worker           case 'e':
224*c2e0c6b5SAndroid Build Coastguard Worker             com_args->error_limit = atoi(optarg);
225*c2e0c6b5SAndroid Build Coastguard Worker             break;
226*c2e0c6b5SAndroid Build Coastguard Worker           case 'o':
227*c2e0c6b5SAndroid Build Coastguard Worker             com_args->dir_for_csv = optarg;
228*c2e0c6b5SAndroid Build Coastguard Worker             com_args->save_csv = true;
229*c2e0c6b5SAndroid Build Coastguard Worker             break;
230*c2e0c6b5SAndroid Build Coastguard Worker           case 'd':
231*c2e0c6b5SAndroid Build Coastguard Worker             com_args->dwell_time = atoi(optarg);
232*c2e0c6b5SAndroid Build Coastguard Worker             break;
233*c2e0c6b5SAndroid Build Coastguard Worker           default:
234*c2e0c6b5SAndroid Build Coastguard Worker             die("Invalid arguments\n\n%s", usage);
235*c2e0c6b5SAndroid Build Coastguard Worker         }
236*c2e0c6b5SAndroid Build Coastguard Worker     }
237*c2e0c6b5SAndroid Build Coastguard Worker 
238*c2e0c6b5SAndroid Build Coastguard Worker   bool status = true;
239*c2e0c6b5SAndroid Build Coastguard Worker   if (mode == FULL && optind != argc)
240*c2e0c6b5SAndroid Build Coastguard Worker     status = false;
241*c2e0c6b5SAndroid Build Coastguard Worker   if (mode == MARGIN && optind == argc)
242*c2e0c6b5SAndroid Build Coastguard Worker     status = false;
243*c2e0c6b5SAndroid Build Coastguard Worker   if (!status && argc > 1)
244*c2e0c6b5SAndroid Build Coastguard Worker     die("Invalid arguments\n\n%s", usage);
245*c2e0c6b5SAndroid Build Coastguard Worker   if (!status)
246*c2e0c6b5SAndroid Build Coastguard Worker     {
247*c2e0c6b5SAndroid Build Coastguard Worker       printf("%s", usage);
248*c2e0c6b5SAndroid Build Coastguard Worker       exit(0);
249*c2e0c6b5SAndroid Build Coastguard Worker     }
250*c2e0c6b5SAndroid Build Coastguard Worker 
251*c2e0c6b5SAndroid Build Coastguard Worker   u8 ports_n = 0;
252*c2e0c6b5SAndroid Build Coastguard Worker   struct margin_link *links = NULL;
253*c2e0c6b5SAndroid Build Coastguard Worker   char err[128];
254*c2e0c6b5SAndroid Build Coastguard Worker 
255*c2e0c6b5SAndroid Build Coastguard Worker   if (mode == FULL)
256*c2e0c6b5SAndroid Build Coastguard Worker     {
257*c2e0c6b5SAndroid Build Coastguard Worker       ports_n = find_ready_links(pacc, NULL, true);
258*c2e0c6b5SAndroid Build Coastguard Worker       if (ports_n == 0)
259*c2e0c6b5SAndroid Build Coastguard Worker         die("Links not found or you don't have enough privileges.\n");
260*c2e0c6b5SAndroid Build Coastguard Worker       else
261*c2e0c6b5SAndroid Build Coastguard Worker         {
262*c2e0c6b5SAndroid Build Coastguard Worker           links = xmalloc(ports_n * sizeof(*links));
263*c2e0c6b5SAndroid Build Coastguard Worker           find_ready_links(pacc, links, false);
264*c2e0c6b5SAndroid Build Coastguard Worker           for (int i = 0; i < ports_n; i++)
265*c2e0c6b5SAndroid Build Coastguard Worker             init_link_args(&(links[i].args), com_args);
266*c2e0c6b5SAndroid Build Coastguard Worker         }
267*c2e0c6b5SAndroid Build Coastguard Worker     }
268*c2e0c6b5SAndroid Build Coastguard Worker   else if (mode == MARGIN)
269*c2e0c6b5SAndroid Build Coastguard Worker     {
270*c2e0c6b5SAndroid Build Coastguard Worker       while (optind != argc)
271*c2e0c6b5SAndroid Build Coastguard Worker         {
272*c2e0c6b5SAndroid Build Coastguard Worker           struct pci_dev *dev = dev_for_filter(pacc, argv[optind]);
273*c2e0c6b5SAndroid Build Coastguard Worker           optind++;
274*c2e0c6b5SAndroid Build Coastguard Worker           links = xrealloc(links, (ports_n + 1) * sizeof(*links));
275*c2e0c6b5SAndroid Build Coastguard Worker           struct pci_dev *down;
276*c2e0c6b5SAndroid Build Coastguard Worker           struct pci_dev *up;
277*c2e0c6b5SAndroid Build Coastguard Worker           if (!margin_find_pair(pacc, dev, &down, &up))
278*c2e0c6b5SAndroid Build Coastguard Worker             die("Cannot find pair for the specified device: %s\n", argv[optind - 1]);
279*c2e0c6b5SAndroid Build Coastguard Worker           struct pci_cap *cap = pci_find_cap(down, PCI_CAP_ID_EXP, PCI_CAP_NORMAL);
280*c2e0c6b5SAndroid Build Coastguard Worker           if (!cap)
281*c2e0c6b5SAndroid Build Coastguard Worker             die("Looks like you don't have enough privileges to access "
282*c2e0c6b5SAndroid Build Coastguard Worker                 "Device Configuration Space.\nTry to run utility as root.\n");
283*c2e0c6b5SAndroid Build Coastguard Worker           if (!margin_fill_link(down, up, &(links[ports_n])))
284*c2e0c6b5SAndroid Build Coastguard Worker             {
285*c2e0c6b5SAndroid Build Coastguard Worker               margin_gen_bdfs(down, up, err, sizeof(err));
286*c2e0c6b5SAndroid Build Coastguard Worker               die("Link %s is not ready for margining.\n"
287*c2e0c6b5SAndroid Build Coastguard Worker                   "Link data rate must be 16 GT/s or 32 GT/s.\n"
288*c2e0c6b5SAndroid Build Coastguard Worker                   "Downstream Component must be at D0 PM state.\n",
289*c2e0c6b5SAndroid Build Coastguard Worker                   err);
290*c2e0c6b5SAndroid Build Coastguard Worker             }
291*c2e0c6b5SAndroid Build Coastguard Worker           init_link_args(&(links[ports_n].args), com_args);
292*c2e0c6b5SAndroid Build Coastguard Worker           parse_dev_args(argc, argv, &(links[ports_n].args),
293*c2e0c6b5SAndroid Build Coastguard Worker                          links[ports_n].down_port.link_speed - 4);
294*c2e0c6b5SAndroid Build Coastguard Worker           ports_n++;
295*c2e0c6b5SAndroid Build Coastguard Worker         }
296*c2e0c6b5SAndroid Build Coastguard Worker     }
297*c2e0c6b5SAndroid Build Coastguard Worker   else
298*c2e0c6b5SAndroid Build Coastguard Worker     die("Bug in the args parsing!\n");
299*c2e0c6b5SAndroid Build Coastguard Worker 
300*c2e0c6b5SAndroid Build Coastguard Worker   *links_n = ports_n;
301*c2e0c6b5SAndroid Build Coastguard Worker   return links;
302*c2e0c6b5SAndroid Build Coastguard Worker }
303