1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2025 Oxide Computer Company
14 */
15
16 /*
17 * This file contains logic to walk and print a large chunk of configuration
18 * space and many of the capabilities. There are multiple sub-commands that
19 * vector into the same logic (e.g. 'save-cfgspace' and 'show-cfgspace'). In
20 * general, there are a few major goals with this bit of code:
21 *
22 * o Every field should strive to be parsable and therefore selectable for
23 * output. This drove the idea that every field has both a short name and a
24 * human name. The short name is a dot-delineated name. When in parsable
25 * mode, the name will always refer to a single field. However, for
26 * convenience for humans, when not trying to be parsable, we show the
27 * parents in the tree. That is if you specify something like
28 * 'pcie.linkcap.maxspeed', in parsable mode you'll only get that; however,
29 * in non-parsable mode, you'll get an indication of the capability and
30 * register that field was in.
31 *
32 * o Related to the above, parsable mode always outputs a raw, uninterpreted
33 * value. This was done on purpose. Some fields require interpreting multiple
34 * registers to have meaning and long strings aren't always the most useful.
35 *
36 * o Every field isn't always pretty printed. This was generally just a
37 * decision based upon the field itself and how much work it'd be to fit it
38 * into the framework we have. In general, the ones we're mostly guilty of
39 * doing this with are related to cases where there's a scaling value in a
40 * subsequent register. If you find yourself wanting this, feel free to add
41 * it.
42 *
43 * o Currently designated vendor-specific capabilities aren't included here (or
44 * any specific vendor-specific capabilities for that matter). If they are
45 * added, they should follow the same angle of using a name to represent a
46 * sub-capability as we did with HyperTransport.
47 */
48
49 #include <err.h>
50 #include <strings.h>
51 #include <sys/sysmacros.h>
52 #include <sys/pci.h>
53 #include <sys/pcie.h>
54 #include <sys/debug.h>
55 #include <ofmt.h>
56 #include <sys/types.h>
57 #include <sys/stat.h>
58 #include <fcntl.h>
59 #include <unistd.h>
60 #include <sys/bitext.h>
61
62 #include "pcieadm.h"
63
64 /*
65 * A few required forwards
66 */
67 struct pcieadm_cfgspace_walk;
68 struct pcieadm_regdef;
69
70 typedef enum pcieadm_cfgspace_op {
71 PCIEADM_CFGSPACE_OP_PRINT,
72 PCIEADM_CFGSPACE_OP_WRITE
73 } pcieadm_cfgspace_op_t;
74
75 typedef enum piceadm_cfgspace_flag {
76 PCIEADM_CFGSPACE_F_PARSE = 1 << 0,
77 PCIEADM_CFGSPACE_F_SHORT = 1 << 1,
78 } pcieadm_cfgspace_flags_t;
79
80 typedef enum pcieadm_cfgspace_otype {
81 PCIEADM_CFGSPACE_OT_SHORT,
82 PCIEADM_CFGSPACE_OT_HUMAN,
83 PCIEADM_CFGSPACE_OT_VALUE
84 } pcieadm_cfgsapce_otype_t;
85
86 typedef struct pcieadm_cfgspace_ofmt {
87 const char *pco_base;
88 const char *pco_short;
89 const char *pco_human;
90 uint64_t pco_value;
91 const char *pco_strval;
92 } pcieadm_cfgspace_ofmt_t;
93
94 typedef enum pcieadm_regdef_val {
95 PRDV_STRVAL,
96 PRDV_BITFIELD,
97 PRDV_HEX,
98 PRDV_CUSTOM
99 } pcieadm_regdef_val_t;
100
101 typedef struct pcieadm_regdef_addend {
102 uint8_t pra_shift;
103 int64_t pra_addend;
104 } pcieadm_regdef_addend_t;
105
106 typedef struct pcieadm_regdef {
107 uint8_t prd_lowbit;
108 uint8_t prd_hibit;
109 const char *prd_short;
110 const char *prd_human;
111 pcieadm_regdef_val_t prd_valtype;
112 union {
113 /*
114 * Enough space for up to an 8-bit fields worth of values
115 * (though we expect most to be sparse).
116 */
117 const char *prdv_strval[128];
118 pcieadm_regdef_addend_t prdv_hex;
119 void (*prdv_func)(struct pcieadm_cfgspace_walk *,
120 const struct pcieadm_regdef *, uint64_t);
121 } prd_val;
122 } pcieadm_regdef_t;
123
124 typedef struct pcieadm_unitdef {
125 const char *pcd_unit;
126 uint32_t pcd_mult;
127 } pcieadm_unitdef_t;
128
129 typedef struct pcieadm_strmap {
130 const char *psr_str;
131 uint64_t psr_val;
132 } pcieadm_strmap_t;
133
134 typedef struct pcieadm_cfgspace_filter {
135 const char *pcf_string;
136 size_t pcf_len;
137 boolean_t pcf_used;
138 } pcieadm_cfgspace_filter_t;
139
140 typedef struct pcieadm_strfilt {
141 struct pcieadm_strfilt *pstr_next;
142 const char *pstr_str;
143 char pstr_curgen[256];
144 } pcieadm_strfilt_t;
145
146 /*
147 * Data is sized to be large enough that we can hold all of PCIe extended
148 * configuration space.
149 */
150 typedef union pcieadm_cfgspace_data {
151 uint8_t pcb_u8[PCIE_CONF_HDR_SIZE];
152 uint32_t pcb_u32[PCIE_CONF_HDR_SIZE / 4];
153 } pcieadm_cfgspace_data_t;
154
155 typedef struct pcieadm_cfgspace_walk {
156 pcieadm_t *pcw_pcieadm;
157 pcieadm_cfgspace_op_t pcw_op;
158 uint32_t pcw_valid;
159 pcieadm_cfgspace_data_t *pcw_data;
160 uint16_t pcw_capoff;
161 uint32_t pcw_caplen;
162 int pcw_outfd;
163 uint_t pcw_dtype;
164 uint_t pcw_nlanes;
165 uint_t pcw_pcietype;
166 uint_t pcw_nfilters;
167 pcieadm_cfgspace_filter_t *pcw_filters;
168 pcieadm_cfgspace_flags_t pcw_flags;
169 ofmt_handle_t pcw_ofmt;
170 pcieadm_strfilt_t *pcw_filt;
171 } pcieadm_cfgspace_walk_t;
172
173 void
pcieadm_strfilt_pop(pcieadm_cfgspace_walk_t * walkp)174 pcieadm_strfilt_pop(pcieadm_cfgspace_walk_t *walkp)
175 {
176 pcieadm_strfilt_t *filt;
177
178 VERIFY3P(walkp->pcw_filt, !=, NULL);
179 filt = walkp->pcw_filt;
180 walkp->pcw_filt = filt->pstr_next;
181 free(filt);
182 }
183
184 void
pcieadm_strfilt_push(pcieadm_cfgspace_walk_t * walkp,const char * str)185 pcieadm_strfilt_push(pcieadm_cfgspace_walk_t *walkp, const char *str)
186 {
187 pcieadm_strfilt_t *filt;
188 size_t len;
189
190 filt = calloc(1, sizeof (*filt));
191 if (filt == NULL) {
192 errx(EXIT_FAILURE, "failed to allocate memory for string "
193 "filter");
194 }
195
196 filt->pstr_str = str;
197 if (walkp->pcw_filt == NULL) {
198 len = strlcat(filt->pstr_curgen, str,
199 sizeof (filt->pstr_curgen));
200 } else {
201 len = snprintf(filt->pstr_curgen, sizeof (filt->pstr_curgen),
202 "%s.%s", walkp->pcw_filt->pstr_curgen, str);
203 filt->pstr_next = walkp->pcw_filt;
204 }
205
206 if (len >= sizeof (filt->pstr_curgen)) {
207 errx(EXIT_FAILURE, "overflowed internal string buffer "
208 "appending %s", str);
209 }
210
211 walkp->pcw_filt = filt;
212 }
213
214 static boolean_t
pcieadm_cfgspace_filter(pcieadm_cfgspace_walk_t * walkp,const char * str)215 pcieadm_cfgspace_filter(pcieadm_cfgspace_walk_t *walkp, const char *str)
216 {
217 char buf[1024];
218 size_t len;
219
220 if (walkp->pcw_nfilters == 0) {
221 return (B_TRUE);
222 }
223
224 if (str == NULL) {
225 return (B_FALSE);
226 }
227
228 if (walkp->pcw_filt != NULL) {
229 len = snprintf(buf, sizeof (buf), "%s.%s",
230 walkp->pcw_filt->pstr_curgen, str);
231 } else {
232 len = snprintf(buf, sizeof (buf), "%s", str);
233 }
234
235 if (len >= sizeof (buf)) {
236 abort();
237 }
238
239 for (uint_t i = 0; i < walkp->pcw_nfilters; i++) {
240 if (strcmp(buf, walkp->pcw_filters[i].pcf_string) == 0) {
241 walkp->pcw_filters[i].pcf_used = B_TRUE;
242 return (B_TRUE);
243 }
244
245 /*
246 * If we're in non-parsable mode, we want to do a little bit
247 * more in a few cases. We want to make sure that we print the
248 * parents of more-specific entries. That is, if someone
249 * specified 'header.command.serr', then we want to print
250 * 'header', and 'header.command'. Similarly, if someone
251 * specifies an individual field, we want to print all of its
252 * subfields, that is asking for 'header.command', really gets
253 * that and all of 'header.command.*'.
254 */
255 if ((walkp->pcw_flags & PCIEADM_CFGSPACE_F_PARSE) != 0) {
256 continue;
257 }
258
259 if (len >= walkp->pcw_filters[i].pcf_len) {
260 if (strncmp(buf, walkp->pcw_filters[i].pcf_string,
261 walkp->pcw_filters[i].pcf_len) == 0 &&
262 buf[walkp->pcw_filters[i].pcf_len] == '.') {
263 return (B_TRUE);
264 }
265 } else {
266 if (strncmp(buf, walkp->pcw_filters[i].pcf_string,
267 len) == 0 &&
268 walkp->pcw_filters[i].pcf_string[len] == '.') {
269 return (B_TRUE);
270 }
271 }
272 }
273
274 return (B_FALSE);
275 }
276
277 static boolean_t
pcieadm_cfgspace_ofmt_cb(ofmt_arg_t * ofarg,char * buf,uint_t buflen)278 pcieadm_cfgspace_ofmt_cb(ofmt_arg_t *ofarg, char *buf, uint_t buflen)
279 {
280 pcieadm_cfgspace_ofmt_t *pco = ofarg->ofmt_cbarg;
281
282 switch (ofarg->ofmt_id) {
283 case PCIEADM_CFGSPACE_OT_SHORT:
284 if (snprintf(buf, buflen, "%s.%s", pco->pco_base,
285 pco->pco_short) >= buflen) {
286 return (B_FALSE);
287 }
288 break;
289 case PCIEADM_CFGSPACE_OT_HUMAN:
290 if (strlcpy(buf, pco->pco_human, buflen) >= buflen) {
291 return (B_FALSE);
292 }
293 break;
294 case PCIEADM_CFGSPACE_OT_VALUE:
295 if (pco->pco_strval != NULL) {
296 if (strlcpy(buf, pco->pco_strval, buflen) >= buflen) {
297 return (B_FALSE);
298 }
299 } else {
300 if (snprintf(buf, buflen, "0x%" PRIx64,
301 pco->pco_value) >= buflen) {
302 return (B_FALSE);
303 }
304 }
305 break;
306 default:
307 abort();
308 }
309
310 return (B_TRUE);
311 }
312
313
314 static const ofmt_field_t pcieadm_cfgspace_ofmt[] = {
315 { "SHORT", 30, PCIEADM_CFGSPACE_OT_SHORT, pcieadm_cfgspace_ofmt_cb },
316 { "HUMAN", 30, PCIEADM_CFGSPACE_OT_HUMAN, pcieadm_cfgspace_ofmt_cb },
317 { "VALUE", 20, PCIEADM_CFGSPACE_OT_VALUE, pcieadm_cfgspace_ofmt_cb },
318 { NULL, 0, 0, NULL }
319 };
320
321 static void
pcieadm_cfgspace_print_parse(pcieadm_cfgspace_walk_t * walkp,const char * sname,const char * human,uint64_t value)322 pcieadm_cfgspace_print_parse(pcieadm_cfgspace_walk_t *walkp,
323 const char *sname, const char *human, uint64_t value)
324 {
325 pcieadm_cfgspace_ofmt_t pco;
326
327 VERIFY3P(walkp->pcw_filt, !=, NULL);
328 pco.pco_base = walkp->pcw_filt->pstr_curgen;
329 pco.pco_short = sname;
330 pco.pco_human = human;
331 pco.pco_value = value;
332 pco.pco_strval = NULL;
333 ofmt_print(walkp->pcw_ofmt, &pco);
334 }
335
336 typedef struct pcieadm_cfgspace_print pcieadm_cfgspace_print_t;
337 typedef void (*pcieadm_cfgspace_print_f)(pcieadm_cfgspace_walk_t *,
338 const pcieadm_cfgspace_print_t *, const void *);
339
340 struct pcieadm_cfgspace_print {
341 uint8_t pcp_off;
342 uint8_t pcp_len;
343 const char *pcp_short;
344 const char *pcp_human;
345 pcieadm_cfgspace_print_f pcp_print;
346 const void *pcp_arg;
347 };
348
349 static uint32_t
pcieadm_cfgspace_getcap32(pcieadm_cfgspace_walk_t * walkp,uint32_t off)350 pcieadm_cfgspace_getcap32(pcieadm_cfgspace_walk_t *walkp, uint32_t off)
351 {
352 off += walkp->pcw_capoff;
353 VERIFY3U(off, <, PCIE_CONF_HDR_SIZE);
354 VERIFY0(off % 4);
355 return (walkp->pcw_data->pcb_u32[off / 4]);
356 }
357
358 static void
pcieadm_field_printf(pcieadm_cfgspace_walk_t * walkp,const char * shortf,const char * humanf,uint64_t val,const char * fmt,...)359 pcieadm_field_printf(pcieadm_cfgspace_walk_t *walkp, const char *shortf,
360 const char *humanf, uint64_t val, const char *fmt, ...)
361 {
362 va_list ap;
363
364 if (!pcieadm_cfgspace_filter(walkp, shortf))
365 return;
366
367 if (walkp->pcw_ofmt != NULL) {
368 pcieadm_cfgspace_print_parse(walkp, shortf, humanf, val);
369 return;
370 }
371
372 if (walkp->pcw_pcieadm->pia_indent > 0) {
373 (void) printf("%*s", walkp->pcw_pcieadm->pia_indent, "");
374 }
375
376 if ((walkp->pcw_flags & PCIEADM_CFGSPACE_F_SHORT) != 0) {
377 (void) printf("|--> %s (%s.%s): ", humanf,
378 walkp->pcw_filt->pstr_curgen, shortf);
379 } else {
380 (void) printf("|--> %s: ", humanf);
381 }
382
383 va_start(ap, fmt);
384 (void) vprintf(fmt, ap);
385 va_end(ap);
386
387 }
388
389 static void
pcieadm_cfgspace_printf(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,uint64_t val,const char * fmt,...)390 pcieadm_cfgspace_printf(pcieadm_cfgspace_walk_t *walkp,
391 const pcieadm_cfgspace_print_t *print, uint64_t val, const char *fmt, ...)
392 {
393 va_list ap;
394
395 if (!pcieadm_cfgspace_filter(walkp, print->pcp_short))
396 return;
397
398 if (walkp->pcw_ofmt != NULL) {
399 pcieadm_cfgspace_print_parse(walkp, print->pcp_short,
400 print->pcp_human, val);
401 return;
402 }
403
404 if (walkp->pcw_pcieadm->pia_indent > 0) {
405 (void) printf("%*s", walkp->pcw_pcieadm->pia_indent, "");
406 }
407
408 if ((walkp->pcw_flags & PCIEADM_CFGSPACE_F_SHORT) != 0) {
409 (void) printf("%s (%s.%s): ", print->pcp_human,
410 walkp->pcw_filt->pstr_curgen, print->pcp_short);
411 } else {
412 (void) printf("%s: ", print->pcp_human);
413 }
414
415 va_start(ap, fmt);
416 (void) vprintf(fmt, ap);
417 va_end(ap);
418 }
419
420 static void
pcieadm_cfgspace_puts(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const char * str)421 pcieadm_cfgspace_puts(pcieadm_cfgspace_walk_t *walkp,
422 const pcieadm_cfgspace_print_t *print, const char *str)
423 {
424 if (!pcieadm_cfgspace_filter(walkp, print->pcp_short))
425 return;
426
427 if (walkp->pcw_ofmt != NULL) {
428 pcieadm_cfgspace_ofmt_t pco;
429
430 VERIFY3P(walkp->pcw_filt, !=, NULL);
431 pco.pco_base = walkp->pcw_filt->pstr_curgen;
432 pco.pco_short = print->pcp_short;
433 pco.pco_human = print->pcp_human;
434 pco.pco_strval = str;
435 ofmt_print(walkp->pcw_ofmt, &pco);
436 return;
437 }
438
439 if (walkp->pcw_pcieadm->pia_indent > 0) {
440 (void) printf("%*s", walkp->pcw_pcieadm->pia_indent, "");
441 }
442
443 if ((walkp->pcw_flags & PCIEADM_CFGSPACE_F_SHORT) != 0) {
444 (void) printf("%s (%s.%s): %s\n", print->pcp_human,
445 walkp->pcw_filt->pstr_curgen, print->pcp_short, str);
446 } else {
447 (void) printf("%s: %s\n", print->pcp_human, str);
448 }
449 }
450
451 static uint64_t
pcieadm_cfgspace_extract(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print)452 pcieadm_cfgspace_extract(pcieadm_cfgspace_walk_t *walkp,
453 const pcieadm_cfgspace_print_t *print)
454 {
455 uint32_t val = 0;
456
457 VERIFY3U(print->pcp_len, <=, 8);
458 VERIFY3U(print->pcp_off + print->pcp_len + walkp->pcw_capoff, <=,
459 walkp->pcw_valid);
460 for (uint8_t i = print->pcp_len; i > 0; i--) {
461 val <<= 8;
462 val |= walkp->pcw_data->pcb_u8[walkp->pcw_capoff +
463 print->pcp_off + i - 1];
464 }
465
466 return (val);
467 }
468
469 static uint16_t
pcieadm_cfgspace_extract_u16(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print)470 pcieadm_cfgspace_extract_u16(pcieadm_cfgspace_walk_t *walkp,
471 const pcieadm_cfgspace_print_t *print)
472 {
473 VERIFY(print->pcp_len == 2);
474 return ((uint16_t)pcieadm_cfgspace_extract(walkp, print));
475 }
476
477 static void
pcieadm_cfgspace_print_unit(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)478 pcieadm_cfgspace_print_unit(pcieadm_cfgspace_walk_t *walkp,
479 const pcieadm_cfgspace_print_t *print, const void *arg)
480 {
481 const pcieadm_unitdef_t *unit = arg;
482 uint64_t rawval = pcieadm_cfgspace_extract(walkp, print);
483 uint64_t val = rawval;
484
485 if (unit->pcd_mult > 1) {
486 val *= unit->pcd_mult;
487 }
488 pcieadm_cfgspace_printf(walkp, print, rawval, "0x%" PRIx64 " %s%s\n",
489 val, unit->pcd_unit, val != 1 ? "s" : "");
490 }
491
492 static void
pcieadm_cfgspace_print_regdef(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)493 pcieadm_cfgspace_print_regdef(pcieadm_cfgspace_walk_t *walkp,
494 const pcieadm_cfgspace_print_t *print, const void *arg)
495 {
496 const pcieadm_regdef_t *regdef = arg;
497 uint64_t val = pcieadm_cfgspace_extract(walkp, print);
498
499 pcieadm_cfgspace_printf(walkp, print, val, "0x%" PRIx64 "\n", val);
500
501 pcieadm_indent();
502 pcieadm_strfilt_push(walkp, print->pcp_short);
503
504 for (regdef = arg; regdef->prd_short != NULL; regdef++) {
505 uint32_t nbits = regdef->prd_hibit - regdef->prd_lowbit + 1UL;
506 uint32_t bitmask = (1UL << nbits) - 1UL;
507 uint64_t regval = (val >> regdef->prd_lowbit) & bitmask;
508 const char *strval;
509 uint64_t actval;
510
511 if (!pcieadm_cfgspace_filter(walkp, regdef->prd_short)) {
512 continue;
513 }
514
515 switch (regdef->prd_valtype) {
516 case PRDV_STRVAL:
517 strval = regdef->prd_val.prdv_strval[regval];
518 if (strval == NULL) {
519 strval = "reserved";
520 }
521
522 pcieadm_field_printf(walkp, regdef->prd_short,
523 regdef->prd_human, regval, "%s (0x%" PRIx64 ")\n",
524 strval, regval << regdef->prd_lowbit);
525 break;
526 case PRDV_HEX:
527 actval = regval;
528 if (regdef->prd_val.prdv_hex.pra_shift > 0) {
529 actval <<= regdef->prd_val.prdv_hex.pra_shift;
530 }
531 actval += regdef->prd_val.prdv_hex.pra_addend;
532
533 pcieadm_field_printf(walkp, regdef->prd_short,
534 regdef->prd_human, regval, "0x% " PRIx64 "\n",
535 actval);
536 break;
537 case PRDV_BITFIELD:
538 pcieadm_field_printf(walkp, regdef->prd_short,
539 regdef->prd_human, regval, "0x%" PRIx64 "\n",
540 regval << regdef->prd_lowbit);
541
542 if (walkp->pcw_ofmt == NULL) {
543 pcieadm_indent();
544 for (uint32_t i = 0; i < nbits; i++) {
545 if (((1 << i) & regval) == 0)
546 continue;
547 pcieadm_print("|--> %s (0x%x)\n",
548 regdef->prd_val.prdv_strval[i],
549 1UL << (i + regdef->prd_lowbit));
550 }
551 pcieadm_deindent();
552 }
553 break;
554 case PRDV_CUSTOM:
555 regdef->prd_val.prdv_func(walkp, regdef, regval);
556 break;
557 }
558 }
559
560 pcieadm_strfilt_pop(walkp);
561 pcieadm_deindent();
562 }
563
564 static void
pcieadm_cfgspace_print_strmap(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)565 pcieadm_cfgspace_print_strmap(pcieadm_cfgspace_walk_t *walkp,
566 const pcieadm_cfgspace_print_t *print, const void *arg)
567 {
568 const pcieadm_strmap_t *strmap = arg;
569 uint64_t val = pcieadm_cfgspace_extract(walkp, print);
570 const char *str = "reserved";
571
572 for (uint_t i = 0; strmap[i].psr_str != NULL; i++) {
573 if (strmap[i].psr_val == val) {
574 str = strmap[i].psr_str;
575 break;
576 }
577 }
578
579 pcieadm_cfgspace_printf(walkp, print, val, "0x%x -- %s\n", val, str);
580 }
581
582 static void
pcieadm_cfgspace_print_hex(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)583 pcieadm_cfgspace_print_hex(pcieadm_cfgspace_walk_t *walkp,
584 const pcieadm_cfgspace_print_t *print, const void *arg)
585 {
586 uint64_t val = pcieadm_cfgspace_extract(walkp, print);
587
588 pcieadm_cfgspace_printf(walkp, print, val, "0x%" PRIx64 "\n", val);
589 }
590
591 static void
pcieadm_cfgspace_print_vendor(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)592 pcieadm_cfgspace_print_vendor(pcieadm_cfgspace_walk_t *walkp,
593 const pcieadm_cfgspace_print_t *print, const void *arg)
594 {
595 pcidb_vendor_t *vend;
596 uint16_t vid = pcieadm_cfgspace_extract_u16(walkp, print);
597
598 vend = pcidb_lookup_vendor(walkp->pcw_pcieadm->pia_pcidb, vid);
599 if (vend != NULL) {
600 pcieadm_cfgspace_printf(walkp, print, vid, "0x%x -- %s\n", vid,
601 pcidb_vendor_name(vend));
602 } else {
603 pcieadm_cfgspace_printf(walkp, print, vid, "0x%x\n", vid);
604 }
605 }
606
607 static void
pcieadm_cfgspace_print_device(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)608 pcieadm_cfgspace_print_device(pcieadm_cfgspace_walk_t *walkp,
609 const pcieadm_cfgspace_print_t *print, const void *arg)
610 {
611 pcidb_device_t *dev;
612 uint16_t did = pcieadm_cfgspace_extract_u16(walkp, print);
613 uint16_t vid = walkp->pcw_data->pcb_u8[PCI_CONF_VENID] +
614 (walkp->pcw_data->pcb_u8[PCI_CONF_VENID + 1] << 8);
615
616 dev = pcidb_lookup_device(walkp->pcw_pcieadm->pia_pcidb, vid, did);
617 if (dev != NULL) {
618 pcieadm_cfgspace_printf(walkp, print, did, "0x%x -- %s\n", did,
619 pcidb_device_name(dev));
620 } else {
621 pcieadm_cfgspace_printf(walkp, print, did, "0x%x\n", did);
622 }
623 }
624
625 /*
626 * To print out detailed information about a subsystem vendor or device, we need
627 * all of the information about the vendor and device due to the organization of
628 * the PCI IDs db.
629 */
630 static void
pcieadm_cfgspace_print_subid(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)631 pcieadm_cfgspace_print_subid(pcieadm_cfgspace_walk_t *walkp,
632 const pcieadm_cfgspace_print_t *print, const void *arg)
633 {
634 uint16_t vid = walkp->pcw_data->pcb_u8[PCI_CONF_VENID] +
635 (walkp->pcw_data->pcb_u8[PCI_CONF_VENID + 1] << 8);
636 uint16_t did = walkp->pcw_data->pcb_u8[PCI_CONF_DEVID] +
637 (walkp->pcw_data->pcb_u8[PCI_CONF_DEVID + 1] << 8);
638 uint16_t svid = walkp->pcw_data->pcb_u8[PCI_CONF_SUBVENID] +
639 (walkp->pcw_data->pcb_u8[PCI_CONF_SUBVENID + 1] << 8);
640 uint16_t sdid = walkp->pcw_data->pcb_u8[PCI_CONF_SUBSYSID] +
641 (walkp->pcw_data->pcb_u8[PCI_CONF_SUBSYSID + 1] << 8);
642 uint16_t val = pcieadm_cfgspace_extract_u16(walkp, print);
643 boolean_t isvendor = print->pcp_off == PCI_CONF_SUBVENID;
644
645 if (isvendor) {
646 pcidb_vendor_t *vend;
647 vend = pcidb_lookup_vendor(walkp->pcw_pcieadm->pia_pcidb,
648 svid);
649 if (vend != NULL) {
650 pcieadm_cfgspace_printf(walkp, print, val,
651 "0x%x -- %s\n", val, pcidb_vendor_name(vend));
652 } else {
653 pcieadm_cfgspace_printf(walkp, print, val,
654 "0x%x\n", val);
655 }
656 } else {
657 pcidb_subvd_t *subvd;
658 subvd = pcidb_lookup_subvd(walkp->pcw_pcieadm->pia_pcidb, vid,
659 did, svid, sdid);
660 if (subvd != NULL) {
661 pcieadm_cfgspace_printf(walkp, print, val,
662 "0x%x -- %s\n", val, pcidb_subvd_name(subvd));
663 } else {
664 pcieadm_cfgspace_printf(walkp, print, val, "0x%x\n",
665 val);
666 }
667 }
668 }
669
670 /*
671 * The variable natures of BARs is a pain. This makes printing this out and the
672 * fields all a bit gross.
673 */
674 static void
pcieadm_cfgspace_print_bars(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)675 pcieadm_cfgspace_print_bars(pcieadm_cfgspace_walk_t *walkp,
676 const pcieadm_cfgspace_print_t *print, const void *arg)
677 {
678 uint32_t *barp = &walkp->pcw_data->pcb_u32[(walkp->pcw_capoff +
679 print->pcp_off) / 4];
680 char barname[32];
681 const char *typestrs[2] = { "Memory Space", "I/O Space" };
682
683 for (uint_t i = 0; i < print->pcp_len / 4; i++) {
684 uint_t type;
685 (void) snprintf(barname, sizeof (barname), "%s%u",
686 print->pcp_short, i);
687
688 type = barp[i] & PCI_BASE_SPACE_M;
689
690 if (pcieadm_cfgspace_filter(walkp, barname) &&
691 walkp->pcw_ofmt == NULL) {
692 if ((walkp->pcw_flags & PCIEADM_CFGSPACE_F_SHORT) !=
693 0) {
694 pcieadm_print("%s %u (%s.%s)\n",
695 print->pcp_human, i,
696 walkp->pcw_filt->pstr_curgen, barname);
697 } else {
698 pcieadm_print("%s %u\n", print->pcp_human, i);
699 }
700 }
701
702 pcieadm_strfilt_push(walkp, barname);
703 pcieadm_indent();
704
705 pcieadm_field_printf(walkp, "space", "Space", type,
706 "%s (0x%x)\n", typestrs[type], type);
707
708 if (type == PCI_BASE_SPACE_IO) {
709 uint32_t addr = barp[i] & PCI_BASE_IO_ADDR_M;
710
711 pcieadm_field_printf(walkp, "addr", "Address", addr,
712 "0x%" PRIx32 "\n", addr);
713 } else {
714 uint8_t type, pre;
715 uint64_t addr;
716 const char *locstr;
717
718 type = barp[i] & PCI_BASE_TYPE_M;
719 pre = barp[i] & PCI_BASE_PREF_M;
720 addr = barp[i] & PCI_BASE_M_ADDR_M;
721
722 if (type == PCI_BASE_TYPE_ALL) {
723 addr += (uint64_t)barp[i+1] << 32;
724 i++;
725 }
726
727 pcieadm_field_printf(walkp, "addr", "Address", addr,
728 "0x%" PRIx64 "\n", addr);
729
730 switch (type) {
731 case PCI_BASE_TYPE_MEM:
732 locstr = "32-bit";
733 break;
734 case PCI_BASE_TYPE_LOW:
735 locstr = "Sub-1 MiB";
736 break;
737 case PCI_BASE_TYPE_ALL:
738 locstr = "64-bit";
739 break;
740 case PCI_BASE_TYPE_RES:
741 default:
742 locstr = "Reserved";
743 break;
744 }
745
746 pcieadm_field_printf(walkp, "type", "Memory Type",
747 type >> 1, "%s (0x%x)\n", locstr, type >> 1);
748 pcieadm_field_printf(walkp, "prefetch", "Prefetchable",
749 pre != 0, "%s (0x%x)\n", pre != 0 ? "yes" : "no",
750 pre != 0);
751 }
752
753 pcieadm_deindent();
754 pcieadm_strfilt_pop(walkp);
755 }
756 }
757
758 static void
pcieadm_cfgspace_print_ecv(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)759 pcieadm_cfgspace_print_ecv(pcieadm_cfgspace_walk_t *walkp,
760 const pcieadm_cfgspace_print_t *print, const void *arg)
761 {
762 uint16_t bitlen, nwords;
763
764 if (bitx8(walkp->pcw_data->pcb_u8[walkp->pcw_capoff + 4], 5, 5) == 0) {
765 return;
766 }
767
768 bitlen = walkp->pcw_data->pcb_u8[walkp->pcw_capoff + 5];
769 if (bitlen == 0) {
770 bitlen = 256;
771 }
772
773 nwords = bitlen / 32;
774 if ((bitlen % 8) != 0) {
775 nwords++;
776 }
777
778 for (uint16_t i = 0; i < nwords; i++) {
779 char tshort[32], thuman[128];
780 pcieadm_cfgspace_print_t p;
781
782 (void) snprintf(tshort, sizeof (tshort), "ecv%u", i);
783 (void) snprintf(thuman, sizeof (thuman), "Egress Control "
784 "Vector %u", i);
785 p.pcp_off = print->pcp_off + i * 4;
786 p.pcp_len = 4;
787 p.pcp_short = tshort;
788 p.pcp_human = thuman;
789 p.pcp_print = pcieadm_cfgspace_print_hex;
790 p.pcp_arg = NULL;
791
792 p.pcp_print(walkp, &p, p.pcp_arg);
793 }
794 }
795
796 static void
pcieadm_cfgspace_print_dpa_paa(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)797 pcieadm_cfgspace_print_dpa_paa(pcieadm_cfgspace_walk_t *walkp,
798 const pcieadm_cfgspace_print_t *print, const void *arg)
799 {
800 uint8_t nents;
801
802 nents = bitx8(walkp->pcw_data->pcb_u8[walkp->pcw_capoff + 4], 4, 0) + 1;
803 if (nents == 0) {
804 return;
805 }
806
807 for (uint8_t i = 0; i < nents; i++) {
808 char tshort[32], thuman[128];
809 pcieadm_cfgspace_print_t p;
810
811 (void) snprintf(tshort, sizeof (tshort), "%s%u",
812 print->pcp_short, i);
813 (void) snprintf(thuman, sizeof (thuman), "%s %u",
814 print->pcp_human, i);
815
816 p.pcp_off = print->pcp_off + i;
817 p.pcp_len = 1;
818 p.pcp_short = tshort;
819 p.pcp_human = thuman;
820 p.pcp_print = pcieadm_cfgspace_print_hex;
821 p.pcp_arg = NULL;
822
823 p.pcp_print(walkp, &p, p.pcp_arg);
824 }
825 }
826
827 /*
828 * Config Space Header Table Definitions
829 */
830 static const pcieadm_regdef_t pcieadm_regdef_command[] = {
831 { 0, 0, "io", "I/O Space", PRDV_STRVAL,
832 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
833 { 1, 1, "mem", "Memory Space", PRDV_STRVAL,
834 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
835 { 2, 2, "bus", "Bus Master", PRDV_STRVAL,
836 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
837 { 3, 3, "spec", "Special Cycle", PRDV_STRVAL,
838 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
839 { 4, 4, "mwi", "Memory Write and Invalidate", PRDV_STRVAL,
840 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
841 { 5, 5, "vga", "VGA Palette Snoop", PRDV_STRVAL,
842 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
843 { 6, 6, "per", "Parity Error Response", PRDV_STRVAL,
844 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
845 { 7, 7, "idsel", "IDSEL Stepping/Wait Cycle Control", PRDV_STRVAL,
846 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
847 { 8, 8, "serr", "SERR# Enable", PRDV_STRVAL,
848 .prd_val = { .prdv_strval = { "disabled", "enabled" } }, },
849 { 9, 9, "fbtx", "Fast Back-to-Back Transactions", PRDV_STRVAL,
850 .prd_val = { .prdv_strval = { "disabled", "enabled" } }, },
851 { 10, 10, "intx", "Interrupt X", PRDV_STRVAL,
852 .prd_val = { .prdv_strval = { "enabled", "disabled" } } },
853 { -1, -1, NULL }
854 };
855
856 static const pcieadm_regdef_t pcieadm_regdef_status[] = {
857 { 0, 0, "imm", "Immediate Readiness", PRDV_STRVAL,
858 .prd_val = { .prdv_strval = { "unsupported", "supported" } }, },
859 { 3, 3, "istat", "Interrupt Status", PRDV_STRVAL,
860 .prd_val = { .prdv_strval = { "not pending", "pending" } }, },
861 { 4, 4, "capsup", "Capabilities List", PRDV_STRVAL,
862 .prd_val = { .prdv_strval = { "unsupported", "supported" } }, },
863 { 5, 5, "66mhz", "66 MHz Capable", PRDV_STRVAL,
864 .prd_val = { .prdv_strval = { "unsupported", "supported" } }, },
865 { 7, 7, "fbtxcap", "Fast Back-to-Back Capable", PRDV_STRVAL,
866 .prd_val = { .prdv_strval = { "unsupported", "supported" } }, },
867 { 8, 8, "mdperr", "Master Data Parity Error", PRDV_STRVAL,
868 .prd_val = { .prdv_strval = { "no error", "error detected" } }, },
869 { 9, 10, "devsel", "DEVSEL# Timing", PRDV_STRVAL,
870 .prd_val = { .prdv_strval = { "fast", "medium", "slow",
871 "reserved" } } },
872 { 11, 11, "sta", "Signaled Target Abort", PRDV_STRVAL,
873 .prd_val = { .prdv_strval = { "no", "yes" } } },
874 { 12, 12, "rta", "Received Target Abort", PRDV_STRVAL,
875 .prd_val = { .prdv_strval = { "no", "yes" } } },
876 { 13, 13, "rma", "Received Master Abort", PRDV_STRVAL,
877 .prd_val = { .prdv_strval = { "no", "yes" } } },
878 { 14, 14, "sse", "Signaled System Error", PRDV_STRVAL,
879 .prd_val = { .prdv_strval = { "no", "yes" } } },
880 { 15, 15, "dpe", "Detected Parity Error", PRDV_STRVAL,
881 .prd_val = { .prdv_strval = { "no", "yes" } } },
882 { -1, -1, NULL }
883 };
884
885 /*
886 * It might be interesting to translate these into numbers at a future point.
887 */
888 static const pcieadm_regdef_t pcieadm_regdef_class[] = {
889 { 16, 23, "class", "Class Code", PRDV_HEX },
890 { 8, 15, "sclass", "Sub-Class Code", PRDV_HEX },
891 { 0, 7, "pi", "Programming Interface", PRDV_HEX },
892 { -1, -1, NULL }
893 };
894
895 static const pcieadm_regdef_t pcieadm_regdef_bridge_iobase[] = {
896 { 0, 3, "cap", "Addressing Capability", PRDV_STRVAL,
897 .prd_val = { .prdv_strval = { "16-bit", "32-bit" } } },
898 { 4, 7, "base", "Base", PRDV_HEX,
899 .prd_val = { .prdv_hex = { 12 } } },
900 { -1, -1, NULL }
901 };
902
903 static const pcieadm_regdef_t pcieadm_regdef_bridge_iolim[] = {
904 { 0, 3, "cap", "Addressing Capability", PRDV_STRVAL,
905 .prd_val = { .prdv_strval = { "16-bit", "32-bit" } } },
906 { 4, 7, "limit", "Limit", PRDV_HEX,
907 .prd_val = { .prdv_hex = { 12, 0xfff } } },
908 { -1, -1, NULL }
909 };
910
911
912 static const pcieadm_regdef_t pcieadm_regdef_bridgests[] = {
913 { 5, 5, "66mhz", "66 MHz", PRDV_STRVAL,
914 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
915 { 7, 7, "fastb2b", "Fast Back-to-Back Transactions", PRDV_STRVAL,
916 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
917 { 8, 8, "mdperr", "Master Data Parity Error", PRDV_STRVAL,
918 .prd_val = { .prdv_strval = { "no error", "error detected" } } },
919 { 9, 10, "devsel", "DEVSEL# Timing", PRDV_STRVAL,
920 .prd_val = { .prdv_strval = { "fast", "medium", "slow" } } },
921 { 11, 11, "sta", "Signaled Target Abort", PRDV_STRVAL,
922 .prd_val = { .prdv_strval = { "no abort", "aborted" } } },
923 { 12, 12, "rta", "Received Target Abort", PRDV_STRVAL,
924 .prd_val = { .prdv_strval = { "no abort", "aborted" } } },
925 { 13, 13, "rma", "Received Master Abort", PRDV_STRVAL,
926 .prd_val = { .prdv_strval = { "no abort", "aborted" } } },
927 { 14, 14, "rsyserr", "Received System Error", PRDV_STRVAL,
928 .prd_val = { .prdv_strval = { "no error", "error received" } } },
929 { 15, 15, "dperr", "Detected Parity Error", PRDV_STRVAL,
930 .prd_val = { .prdv_strval = { "no error", "error detected" } } },
931 { -1, -1, NULL }
932 };
933
934 static const pcieadm_regdef_t pcieadm_regdef_bridge_membase[] = {
935 { 4, 16, "base", "Base", PRDV_HEX,
936 .prd_val = { .prdv_hex = { 20 } } },
937 { -1, -1, NULL }
938 };
939
940 static const pcieadm_regdef_t pcieadm_regdef_bridge_memlim[] = {
941 { 4, 16, "limit", "Limit", PRDV_HEX,
942 .prd_val = { .prdv_hex = { 20, 0xfffff } } },
943 { -1, -1, NULL }
944 };
945
946 static const pcieadm_regdef_t pcieadm_regdef_bridge_pfbase[] = {
947 { 0, 3, "cap", "Addressing Capability", PRDV_STRVAL,
948 .prd_val = { .prdv_strval = { "32-bit", "64-bit" } } },
949 { 4, 16, "base", "Base", PRDV_HEX,
950 .prd_val = { .prdv_hex = { 20 } } },
951 { -1, -1, NULL }
952 };
953
954 static const pcieadm_regdef_t pcieadm_regdef_bridge_pflim[] = {
955 { 0, 3, "cap", "Addressing Capability", PRDV_STRVAL,
956 .prd_val = { .prdv_strval = { "32-bit", "64-bit" } } },
957 { 4, 16, "limit", "Limit", PRDV_HEX,
958 .prd_val = { .prdv_hex = { 20, 0xfffff } } },
959 { -1, -1, NULL }
960 };
961
962 static const pcieadm_regdef_t pcieadm_regdef_bridge_ctl[] = {
963 { 0, 0, "perrresp", "Parity Error Response", PRDV_STRVAL,
964 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
965 { 1, 1, "serr", "SERR#", PRDV_STRVAL,
966 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
967 { 2, 2, "isa", "ISA", PRDV_STRVAL,
968 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
969 { 3, 3, "vga", "VGA", PRDV_STRVAL,
970 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
971 { 4, 4, "vgadec", "VGA 16-bit Decode", PRDV_STRVAL,
972 .prd_val = { .prdv_strval = { "10-bit", "16-bit" } } },
973 { 5, 5, "mabort", "Master Abort", PRDV_STRVAL,
974 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
975 { 6, 6, "secrst", "Secondary Bus Reset", PRDV_HEX },
976 { 7, 7, "fastb2b", "Fast Back-to-Back Transactions", PRDV_STRVAL,
977 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
978 { 8, 8, "pridisc", "Primary Discard Timer", PRDV_STRVAL,
979 .prd_val = { .prdv_strval = { "2^15 cycles", "2^10 cycles" } } },
980 { 9, 9, "secdisc", "Secondary Discard Timer", PRDV_STRVAL,
981 .prd_val = { .prdv_strval = { "2^15 cycles", "2^10 cycles" } } },
982 { 10, 10, "disctimer", "Discard Timer Error", PRDV_STRVAL,
983 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
984 { 11, 11, "discserr", "Discard Timer SERR#", PRDV_STRVAL,
985 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
986 { -1, -1, NULL }
987 };
988
989 static pcieadm_unitdef_t pcieadm_unitdef_cache = {
990 "byte", 4
991 };
992
993 static pcieadm_unitdef_t pcieadm_unitdef_latreg = { "cycle" };
994
995 static const pcieadm_regdef_t pcieadm_regdef_header[] = {
996 { 0, 6, "layout", "Header Layout", PRDV_STRVAL,
997 .prd_val = { .prdv_strval = { "Device", "Bridge", "PC Card" } } },
998 { 7, 7, "mfd", "Multi-Function Device", PRDV_STRVAL,
999 .prd_val = { .prdv_strval = { "no", "yes" } } },
1000 { -1, -1, NULL }
1001 };
1002
1003 static const pcieadm_regdef_t pcieadm_regdef_bist[] = {
1004 { 0, 3, "code", "Completion Code", PRDV_HEX },
1005 { 6, 6, "start", "Start BIST", PRDV_HEX },
1006 { 7, 7, "cap", "BIST Capable", PRDV_STRVAL,
1007 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1008 { -1, -1, NULL }
1009 };
1010
1011 static const pcieadm_regdef_t pcieadm_regdef_exprom[] = {
1012 { 0, 0, "enable", "Enable", PRDV_STRVAL,
1013 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1014 { 1, 3, "valsts", "Validation Status", PRDV_STRVAL,
1015 .prd_val = { .prdv_strval = { "not supported", "in progress",
1016 "valid contents, no trust test performed",
1017 "valid and trusted contents",
1018 "invalid contents",
1019 "valid but untrusted contents",
1020 "valid contents with warning, no trust test performed",
1021 "valid and trusted contents with warning" } } },
1022 { 4, 7, "valdet", "Validation Details", PRDV_HEX },
1023 { 11, 31, "addr", "Base Address", PRDV_HEX,
1024 .prd_val = { .prdv_hex = { 11 } } },
1025 { -1, -1, NULL }
1026 };
1027
1028 static pcieadm_strmap_t pcieadm_strmap_ipin[] = {
1029 { "none", 0 },
1030 { "INTA", PCI_INTA },
1031 { "INTB", PCI_INTB },
1032 { "INTC", PCI_INTC },
1033 { "INTD", PCI_INTD },
1034 { NULL }
1035 };
1036
1037
1038 static const pcieadm_cfgspace_print_t pcieadm_cfgspace_type0[] = {
1039 { 0x0, 2, "vendor", "Vendor ID", pcieadm_cfgspace_print_vendor },
1040 { 0x2, 2, "device", "Device ID", pcieadm_cfgspace_print_device },
1041 { 0x4, 2, "command", "Command", pcieadm_cfgspace_print_regdef,
1042 pcieadm_regdef_command },
1043 { 0x6, 2, "status", "Status", pcieadm_cfgspace_print_regdef,
1044 pcieadm_regdef_status },
1045 { 0x8, 1, "revision", "Revision ID", pcieadm_cfgspace_print_hex },
1046 { 0x9, 3, "class", "Class Code", pcieadm_cfgspace_print_regdef,
1047 pcieadm_regdef_class },
1048 { 0xc, 1, "cache", "Cache Line Size", pcieadm_cfgspace_print_unit,
1049 &pcieadm_unitdef_cache },
1050 { 0xd, 1, "latency", "Latency Timer", pcieadm_cfgspace_print_unit,
1051 &pcieadm_unitdef_latreg },
1052 { 0xe, 1, "type", "Header Type", pcieadm_cfgspace_print_regdef,
1053 pcieadm_regdef_header },
1054 { 0xf, 1, "bist", "BIST", pcieadm_cfgspace_print_regdef,
1055 pcieadm_regdef_bist },
1056 { 0x10, 24, "bar", "Base Address Register",
1057 pcieadm_cfgspace_print_bars },
1058 { 0x28, 4, "cis", "Cardbus CIS Pointer", pcieadm_cfgspace_print_hex },
1059 { 0x2c, 2, "subvid", "Subsystem Vendor ID",
1060 pcieadm_cfgspace_print_subid },
1061 { 0x2e, 2, "subdev", "Subsystem Device ID",
1062 pcieadm_cfgspace_print_subid },
1063 { 0x30, 4, "rom", "Expansion ROM", pcieadm_cfgspace_print_regdef,
1064 pcieadm_regdef_exprom },
1065 { 0x34, 1, "cap", "Capabilities Pointer", pcieadm_cfgspace_print_hex },
1066 { 0x3c, 1, "iline", "Interrupt Line", pcieadm_cfgspace_print_hex },
1067 { 0x3d, 1, "ipin", "Interrupt Pin", pcieadm_cfgspace_print_strmap,
1068 pcieadm_strmap_ipin },
1069 { 0x3e, 1, "gnt", "Min_Gnt", pcieadm_cfgspace_print_hex },
1070 { 0x3f, 1, "lat", "Min_Lat", pcieadm_cfgspace_print_hex },
1071 { -1, -1, NULL }
1072 };
1073
1074 static const pcieadm_cfgspace_print_t pcieadm_cfgspace_type1[] = {
1075 { 0x0, 2, "vendor", "Vendor ID", pcieadm_cfgspace_print_vendor },
1076 { 0x2, 2, "device", "Device ID", pcieadm_cfgspace_print_device },
1077 { 0x4, 2, "command", "Command", pcieadm_cfgspace_print_regdef,
1078 pcieadm_regdef_command },
1079 { 0x6, 2, "status", "Status", pcieadm_cfgspace_print_regdef,
1080 pcieadm_regdef_status },
1081 { 0x8, 1, "revision", "Revision ID", pcieadm_cfgspace_print_hex },
1082 { 0x9, 3, "class", "Class Code", pcieadm_cfgspace_print_regdef,
1083 pcieadm_regdef_class },
1084 { 0xc, 1, "cache", "Cache Line Size", pcieadm_cfgspace_print_unit,
1085 &pcieadm_unitdef_cache },
1086 { 0xd, 1, "latency", "Latency Timer", pcieadm_cfgspace_print_unit,
1087 &pcieadm_unitdef_latreg },
1088 { 0xe, 1, "type", "Header Type", pcieadm_cfgspace_print_regdef,
1089 pcieadm_regdef_header },
1090 { 0xf, 1, "bist", "BIST", pcieadm_cfgspace_print_regdef,
1091 pcieadm_regdef_bist },
1092 { 0x10, 8, "bar", "Base Address Register",
1093 pcieadm_cfgspace_print_bars },
1094 { PCI_BCNF_PRIBUS, 1, "pribus", "Primary Bus Number",
1095 pcieadm_cfgspace_print_hex },
1096 { PCI_BCNF_SECBUS, 1, "secbus", "Secondary Bus Number",
1097 pcieadm_cfgspace_print_hex },
1098 { PCI_BCNF_SUBBUS, 1, "subbus", "Subordinate Bus Number",
1099 pcieadm_cfgspace_print_hex },
1100 { PCI_BCNF_LATENCY_TIMER, 1, "latency2", "Secondary Latency timer",
1101 pcieadm_cfgspace_print_unit, &pcieadm_unitdef_latreg },
1102 { PCI_BCNF_IO_BASE_LOW, 1, "iobase", "I/O Base Low",
1103 pcieadm_cfgspace_print_regdef, pcieadm_regdef_bridge_iobase },
1104 { PCI_BCNF_IO_LIMIT_LOW, 1, "iolimit", "I/O Limit Low",
1105 pcieadm_cfgspace_print_regdef, pcieadm_regdef_bridge_iolim },
1106 { PCI_BCNF_SEC_STATUS, 2, "status2", "Secondary Status",
1107 pcieadm_cfgspace_print_regdef, pcieadm_regdef_bridgests },
1108 { PCI_BCNF_MEM_BASE, 2, "membase", "Memory Base",
1109 pcieadm_cfgspace_print_regdef, pcieadm_regdef_bridge_membase },
1110 { PCI_BCNF_MEM_LIMIT, 2, "memlimit", "Memory Limit",
1111 pcieadm_cfgspace_print_regdef, pcieadm_regdef_bridge_memlim },
1112 { PCI_BCNF_PF_BASE_LOW, 2, "pfbase", "Prefetchable Memory Base",
1113 pcieadm_cfgspace_print_regdef, pcieadm_regdef_bridge_pfbase },
1114 { PCI_BCNF_PF_LIMIT_LOW, 2, "pflimit", "Prefetchable Memory Limit",
1115 pcieadm_cfgspace_print_regdef, pcieadm_regdef_bridge_pflim },
1116 { PCI_BCNF_PF_BASE_HIGH, 4, "pfbasehi",
1117 "Prefetchable Base Upper 32 bits",
1118 pcieadm_cfgspace_print_hex },
1119 { PCI_BCNF_PF_LIMIT_HIGH, 4, "pflimihi",
1120 "Prefetchable Limit Upper 32 bits",
1121 pcieadm_cfgspace_print_hex },
1122 { PCI_BCNF_IO_BASE_HI, 2, "iobasehi", "I/O Base Upper 16 bits",
1123 pcieadm_cfgspace_print_hex },
1124 { PCI_BCNF_IO_LIMIT_HI, 2, "iolimithi", "I/O Limit Upper 16 bits",
1125 pcieadm_cfgspace_print_hex },
1126 { PCI_BCNF_CAP_PTR, 1, "cap", "Capabilities Pointer",
1127 pcieadm_cfgspace_print_hex },
1128 { PCI_BCNF_ROM, 4, "rom", "Expansion ROM",
1129 pcieadm_cfgspace_print_regdef, pcieadm_regdef_exprom },
1130 { PCI_BCNF_ILINE, 1, "iline", "Interrupt Line",
1131 pcieadm_cfgspace_print_hex },
1132 { PCI_BCNF_IPIN, 1, "ipin", "Interrupt Pin",
1133 pcieadm_cfgspace_print_strmap, pcieadm_strmap_ipin },
1134 { PCI_BCNF_BCNTRL, 2, "bctl", "Bridge Control",
1135 pcieadm_cfgspace_print_regdef, pcieadm_regdef_bridge_ctl },
1136 { -1, -1, NULL }
1137 };
1138
1139 static const pcieadm_cfgspace_print_t pcieadm_cfgspace_unknown[] = {
1140 { 0x0, 2, "vendor", "Vendor ID", pcieadm_cfgspace_print_vendor },
1141 { 0x2, 2, "device", "Device ID", pcieadm_cfgspace_print_device },
1142 { 0x8, 1, "revision", "Revision ID", pcieadm_cfgspace_print_hex },
1143 { 0xe, 1, "type", "Header Type", pcieadm_cfgspace_print_regdef,
1144 pcieadm_regdef_header },
1145 { -1, -1, NULL }
1146 };
1147
1148 /*
1149 * Power Management Capability Version 3. Note versions two and three seem to be
1150 * the same, but are used to indicate compliance to different revisions of the
1151 * PCI power management specification.
1152 */
1153 static const pcieadm_regdef_t pcieadm_regdef_pmcap[] = {
1154 { 0, 2, "vers", "Version", PRDV_HEX },
1155 { 3, 3, "clock", "PME Clock", PRDV_STRVAL,
1156 .prd_val = { .prdv_strval = { "not required", "required" } } },
1157 { 4, 4, "irrd0", "Immediate Readiness on Return to D0", PRDV_STRVAL,
1158 .prd_val = { .prdv_strval = { "no", "yes" } } },
1159 { 5, 5, "dsi", "Device Specific Initialization", PRDV_STRVAL,
1160 .prd_val = { .prdv_strval = { "no", "yes" } } },
1161 { 6, 8, "auxcur", "Auxiliary Current", PRDV_STRVAL,
1162 .prd_val = { .prdv_strval = { "0", "55 mA", "100 mA", "160 mA",
1163 "220 mA", "270 mA", "320 mA", "375 mA" } } },
1164 { 9, 9, "d1", "D1", PRDV_STRVAL,
1165 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1166 { 10, 10, "d2", "D2", PRDV_STRVAL,
1167 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1168 { 11, 15, "pme", "PME Support", PRDV_BITFIELD,
1169 .prd_val = { .prdv_strval = { "D0", "D1", "D2", "D3hot",
1170 "D3cold" } } },
1171 { -1, -1, NULL }
1172 };
1173
1174
1175 static const pcieadm_cfgspace_print_t pcieadm_cap_pcipm_v3[] = {
1176 { PCI_PMCAP, 2, "pmcap", "Power Management Capabilities",
1177 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pmcap },
1178 { -1, -1, NULL }
1179 };
1180
1181 /*
1182 * PCI Bridge Subsystem Capability
1183 */
1184 static const pcieadm_cfgspace_print_t pcieadm_cap_bridge_subsys[] = {
1185 { 0x4, 2, "subvid", "Subsystem Vendor ID", pcieadm_cfgspace_print_hex },
1186 { 0x6, 2, "subdev", "Subsystem Device ID", pcieadm_cfgspace_print_hex },
1187 { -1, -1, NULL }
1188 };
1189
1190 /*
1191 * MSI Capability
1192 */
1193 static const pcieadm_regdef_t pcieadm_regdef_msictrl[] = {
1194 { 0, 0, "enable", "MSI Enable", PRDV_STRVAL,
1195 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1196 { 1, 3, "mmsgcap", "Multiple Message Capable", PRDV_STRVAL,
1197 .prd_val = { .prdv_strval = { "1 vector", "2 vectors",
1198 "4 vectors", "8 vectors", "16 vectors", "32 vectors" } } },
1199 { 4, 6, "mmsgen", "Multiple Message Enabled", PRDV_STRVAL,
1200 .prd_val = { .prdv_strval = { "1 vector", "2 vectors",
1201 "4 vectors", "8 vectors", "16 vectors", "32 vectors" } } },
1202 { 7, 7, "addr64", "64-bit Address Capable", PRDV_STRVAL,
1203 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1204 { 8, 8, "pvm", "Per-Vector Masking Capable", PRDV_STRVAL,
1205 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1206 { 9, 9, "extmdcap", "Extended Message Data Capable", PRDV_STRVAL,
1207 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1208 { 10, 10, "extmden", "extended Message Data Enable", PRDV_STRVAL,
1209 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1210 { -1, -1, NULL }
1211 };
1212
1213 static const pcieadm_cfgspace_print_t pcieadm_cap_msi_32[] = {
1214 { PCI_MSI_CTRL, 2, "ctrl", "Message Control",
1215 pcieadm_cfgspace_print_regdef, pcieadm_regdef_msictrl },
1216 { PCI_MSI_ADDR_OFFSET, 4, "addr", "Message Address",
1217 pcieadm_cfgspace_print_hex },
1218 { PCI_MSI_32BIT_DATA, 2, "data", "Message Data",
1219 pcieadm_cfgspace_print_hex },
1220 { -1, -1, NULL }
1221 };
1222
1223 static const pcieadm_cfgspace_print_t pcieadm_cap_msi_32ext[] = {
1224 { PCI_MSI_CTRL, 2, "ctrl", "Message Control",
1225 pcieadm_cfgspace_print_regdef, pcieadm_regdef_msictrl },
1226 { PCI_MSI_ADDR_OFFSET, 4, "addr", "Message Address",
1227 pcieadm_cfgspace_print_hex },
1228 { PCI_MSI_32BIT_DATA, 2, "data", "Message Data",
1229 pcieadm_cfgspace_print_hex },
1230 { PCI_MSI_32BIT_EXTDATA, 2, "extdata", "Extended Message Data",
1231 pcieadm_cfgspace_print_hex },
1232 { -1, -1, NULL }
1233 };
1234
1235 static const pcieadm_cfgspace_print_t pcieadm_cap_msi_32pvm[] = {
1236 { PCI_MSI_CTRL, 2, "ctrl", "Message Control",
1237 pcieadm_cfgspace_print_regdef, pcieadm_regdef_msictrl },
1238 { PCI_MSI_ADDR_OFFSET, 4, "addr", "Message Address",
1239 pcieadm_cfgspace_print_hex },
1240 { PCI_MSI_32BIT_DATA, 2, "data", "Message Data",
1241 pcieadm_cfgspace_print_hex },
1242 { PCI_MSI_32BIT_EXTDATA, 2, "extdata", "Extended Message Data",
1243 pcieadm_cfgspace_print_hex },
1244 { PCI_MSI_32BIT_MASK, 4, "mask", "Mask Bits",
1245 pcieadm_cfgspace_print_hex },
1246 { PCI_MSI_32BIT_PENDING, 4, "pend", "Pending Bits",
1247 pcieadm_cfgspace_print_hex },
1248 { -1, -1, NULL }
1249 };
1250
1251 static const pcieadm_cfgspace_print_t pcieadm_cap_msi_64[] = {
1252 { PCI_MSI_CTRL, 2, "ctrl", "Message Control",
1253 pcieadm_cfgspace_print_regdef, pcieadm_regdef_msictrl },
1254 { PCI_MSI_ADDR_OFFSET, 4, "addr", "Message Address",
1255 pcieadm_cfgspace_print_hex },
1256 { PCI_MSI_64BIT_ADDR, 4, "upadd", "Upper Message Address",
1257 pcieadm_cfgspace_print_hex },
1258 { PCI_MSI_64BIT_DATA, 2, "data", "Message Data",
1259 pcieadm_cfgspace_print_hex },
1260 { -1, -1, NULL }
1261 };
1262
1263 static const pcieadm_cfgspace_print_t pcieadm_cap_msi_64ext[] = {
1264 { PCI_MSI_CTRL, 2, "ctrl", "Message Control",
1265 pcieadm_cfgspace_print_regdef, pcieadm_regdef_msictrl },
1266 { PCI_MSI_ADDR_OFFSET, 4, "addr", "Message Address",
1267 pcieadm_cfgspace_print_hex },
1268 { PCI_MSI_64BIT_ADDR, 4, "upadd", "Upper Message Address",
1269 pcieadm_cfgspace_print_hex },
1270 { PCI_MSI_64BIT_DATA, 2, "data", "Message Data",
1271 pcieadm_cfgspace_print_hex },
1272 { PCI_MSI_64BIT_EXTDATA, 2, "extdata", "Extended Message Data",
1273 pcieadm_cfgspace_print_hex },
1274 { -1, -1, NULL }
1275 };
1276
1277 static const pcieadm_cfgspace_print_t pcieadm_cap_msi_64pvm[] = {
1278 { PCI_MSI_CTRL, 2, "ctrl", "Message Control",
1279 pcieadm_cfgspace_print_regdef, pcieadm_regdef_msictrl },
1280 { PCI_MSI_ADDR_OFFSET, 4, "addr", "Message Address",
1281 pcieadm_cfgspace_print_hex },
1282 { PCI_MSI_64BIT_ADDR, 4, "upadd", "Upper Message Address",
1283 pcieadm_cfgspace_print_hex },
1284 { PCI_MSI_64BIT_DATA, 2, "data", "Message Data",
1285 pcieadm_cfgspace_print_hex },
1286 { PCI_MSI_64BIT_EXTDATA, 2, "extdata", "Extended Message Data",
1287 pcieadm_cfgspace_print_hex },
1288 { PCI_MSI_64BIT_MASKBITS, 4, "mask", "Mask Bits",
1289 pcieadm_cfgspace_print_hex },
1290 { PCI_MSI_64BIT_PENDING, 4, "pend", "Pending Bits",
1291 pcieadm_cfgspace_print_hex },
1292 { -1, -1, NULL }
1293 };
1294
1295 /*
1296 * MSI-X Capability
1297 */
1298 static const pcieadm_regdef_t pcieadm_regdef_msixctrl[] = {
1299 { 0, 10, "size", "Table Size", PRDV_HEX,
1300 .prd_val = { .prdv_hex = { 0, 1 } } },
1301 { 14, 14, "mask", "Function Mask", PRDV_STRVAL,
1302 .prd_val = { .prdv_strval = { "unmasked", "masked" } } },
1303 { 15, 15, "enable", "MSI-X Enable", PRDV_STRVAL,
1304 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1305 { -1, -1, NULL }
1306 };
1307
1308 static const pcieadm_regdef_t pcieadm_regdef_msixtable[] = {
1309 { 0, 2, "bir", "Table BIR", PRDV_STRVAL,
1310 .prd_val = { .prdv_strval = { "BAR 0", "BAR 1", "BAR 2", "BAR 3",
1311 "BAR 4", "BAR 5" } } },
1312 { 3, 31, "offset", "Table Offset", PRDV_HEX,
1313 .prd_val = { .prdv_hex = { 3 } } },
1314 { -1, -1, NULL }
1315 };
1316
1317 static const pcieadm_regdef_t pcieadm_regdef_msixpba[] = {
1318 { 0, 2, "bir", "PBA BIR", PRDV_STRVAL,
1319 .prd_val = { .prdv_strval = { "BAR 0", "BAR 1", "BAR 2", "BAR 3",
1320 "BAR 4", "BAR 5" } } },
1321 { 3, 31, "offset", "PBA Offset", PRDV_HEX,
1322 .prd_val = { .prdv_hex = { 3 } } },
1323 { -1, -1, NULL }
1324 };
1325
1326
1327 static const pcieadm_cfgspace_print_t pcieadm_cap_msix[] = {
1328 { PCI_MSIX_CTRL, 2, "ctrl", "Control Register",
1329 pcieadm_cfgspace_print_regdef, pcieadm_regdef_msixctrl },
1330 { PCI_MSIX_TBL_OFFSET, 4, "table", "Table Offset",
1331 pcieadm_cfgspace_print_regdef, pcieadm_regdef_msixtable },
1332 { PCI_MSIX_PBA_OFFSET, 4, "pba", "PBA Offset",
1333 pcieadm_cfgspace_print_regdef, pcieadm_regdef_msixpba },
1334 { -1, -1, NULL }
1335 };
1336
1337 /*
1338 * PCI Express Capability
1339 */
1340 static const pcieadm_regdef_t pcieadm_regdef_pcie_cap[] = {
1341 { 0, 3, "vers", "Version", PRDV_HEX },
1342 { 4, 7, "type", "Device/Port Type", PRDV_STRVAL,
1343 .prd_val = { .prdv_strval = { "PCIe Endpoint",
1344 "Legacy PCIe Endpoint", NULL, NULL,
1345 "Root Port of PCIe Root Complex",
1346 "Upstream Port of PCIe Switch",
1347 "Downstream Port of PCIe Switch",
1348 "PCIe to PCI/PCI-X Bridge",
1349 "PCI/PCI-x to PCIe Bridge",
1350 "RCiEP",
1351 "Root Complex Event Collector" } } },
1352 { 8, 8, "slot", "Slot Implemented", PRDV_STRVAL,
1353 .prd_val = { .prdv_strval = { "No", "Yes" } } },
1354 { 9, 13, "intno", "Interrupt Message Number", PRDV_HEX },
1355 { -1, -1, NULL }
1356 };
1357
1358 static const pcieadm_regdef_t pcieadm_regdef_pcie_devcap[] = {
1359 { 0, 2, "mps", "Max Payload Size Supported", PRDV_STRVAL,
1360 .prd_val = { .prdv_strval = { "128 bytes", "256 bytes",
1361 "512 bytes", "1024 bytes", "2048 bytes", "4096 bytes" } } },
1362 { 3, 4, "pfunc", "Phantom Functions Supported", PRDV_STRVAL,
1363 .prd_val = { .prdv_strval = { "No", "1-bit", "2-bits",
1364 "3-bits" } } },
1365 { 5, 5, "exttag", "Extended Tag Field", PRDV_STRVAL,
1366 .prd_val = { .prdv_strval = { "5-bit", "8-bit" } } },
1367 { 6, 8, "l0slat", "L0s Acceptable Latency", PRDV_STRVAL,
1368 .prd_val = { .prdv_strval = { "64 ns", "128 ns", "256 ns",
1369 "512 ns", "1 us", "2 us", "4 us", "No limit" } } },
1370 { 9, 11, "l1lat", "L1 Acceptable Latency", PRDV_STRVAL,
1371 .prd_val = { .prdv_strval = { "1 us", "2 us", "4 us", "8 us",
1372 "16 us", "32 us", "64 us", "No limit" } } },
1373 { 15, 15, "rber", "Role Based Error Reporting", PRDV_STRVAL,
1374 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1375 { 16, 16, "errcor", "ERR_COR Subclass", PRDV_STRVAL,
1376 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1377 { 18, 25, "csplv", "Captured Slot Power Limit", PRDV_HEX },
1378 { 26, 27, "cspls", "Captured Slot Power Limit Scale", PRDV_STRVAL,
1379 .prd_val = { .prdv_strval = { "1.0x", "0.1x", "0.01x",
1380 "0.001x" } } },
1381 { 28, 28, "flr", "Function Level Reset", PRDV_STRVAL,
1382 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1383 { -1, -1, NULL }
1384 };
1385
1386 static const pcieadm_regdef_t pcieadm_regdef_pcie_devctl[] = {
1387 { 0, 0, "corerr", "Correctable Error Reporting", PRDV_STRVAL,
1388 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1389 { 1, 1, "nferr", "Non-Fatal Error Reporting", PRDV_STRVAL,
1390 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1391 { 2, 2, "ferr", "Fatal Error Reporting", PRDV_STRVAL,
1392 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1393 { 3, 3, "unsupreq", "Unsupported Request Reporting", PRDV_STRVAL,
1394 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1395 { 4, 4, "relord", "Relaxed Ordering", PRDV_STRVAL,
1396 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1397 { 5, 7, "mps", "Max Payload Size", PRDV_STRVAL,
1398 .prd_val = { .prdv_strval = { "128 bytes", "256 bytes",
1399 "512 bytes", "1024 bytes", "2048 bytes", "4096 bytes" } } },
1400 { 8, 8, "exttag", "Extended Tag Field", PRDV_STRVAL,
1401 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1402 { 9, 9, "pfunc", "Phantom Functions", PRDV_STRVAL,
1403 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1404 { 9, 9, "auxpm", "Aux Power PM", PRDV_STRVAL,
1405 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1406 { 11, 11, "nosnoop", "No Snoop", PRDV_STRVAL,
1407 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1408 { 12, 14, "mrrs", "Max Read Request Size", PRDV_STRVAL,
1409 .prd_val = { .prdv_strval = { "128 bytes", "256 bytes",
1410 "512 bytes", "1024 bytes", "2048 bytes", "4096 bytes" } } },
1411 { 15, 15, "bcrflr", "Bridge Configuration Retry / Function Level Reset",
1412 PRDV_HEX },
1413 { -1, -1, NULL }
1414 };
1415
1416 static const pcieadm_regdef_t pcieadm_regdef_pcie_devsts[] = {
1417 { 0, 0, "corerr", "Correctable Error Detected", PRDV_STRVAL,
1418 .prd_val = { .prdv_strval = { "no", "yes" } } },
1419 { 1, 1, "nferr", "Non-Fatal Error Detected", PRDV_STRVAL,
1420 .prd_val = { .prdv_strval = { "no", "yes" } } },
1421 { 2, 2, "ferr", "Fatal Error Detected", PRDV_STRVAL,
1422 .prd_val = { .prdv_strval = { "no", "yes" } } },
1423 { 3, 3, "unsupreq", "Unsupported Request Detected", PRDV_STRVAL,
1424 .prd_val = { .prdv_strval = { "no", "yes" } } },
1425 { 4, 4, "auxpm", "AUX Power Detected", PRDV_STRVAL,
1426 .prd_val = { .prdv_strval = { "no", "yes" } } },
1427 { 5, 5, "txpend", "Transactions Pending", PRDV_STRVAL,
1428 .prd_val = { .prdv_strval = { "no", "yes" } } },
1429 { 6, 6, "eprd", "Emergency Power Reduction Detected", PRDV_STRVAL,
1430 .prd_val = { .prdv_strval = { "no", "yes" } } },
1431 { -1, -1, NULL }
1432 };
1433
1434 static const pcieadm_regdef_t pcieadm_regdef_pcie_linkcap[] = {
1435 { 0, 3, "maxspeed", "Maximum Link Speed", PRDV_STRVAL,
1436 .prd_val = { .prdv_strval = { NULL, "2.5 GT/s", "5.0 GT/s",
1437 "8.0 GT/s", "16.0 GT/s", "32.0 GT/s", "64.0 GT/s" } } },
1438 { 4, 9, "maxwidth", "Maximum Link Width", PRDV_HEX },
1439 { 10, 11, "aspm", "ASPM Support", PRDV_STRVAL,
1440 .prd_val = { .prdv_strval = { "None", "L0s", "L1", "L0s/L1" } } },
1441 { 12, 14, "l0slat", "L0s Exit Latency", PRDV_STRVAL,
1442 .prd_val = { .prdv_strval = { "<64ns", "64-128ns", "128-256ns",
1443 "256-512ns", "512ns-1us", "1-2us", "2-4us", ">4us" } } },
1444 { 15, 17, "l1lat", "L1 Exit Latency", PRDV_STRVAL,
1445 .prd_val = { .prdv_strval = { "<1us", "1-2us", "2-4us", "4-8us",
1446 "8-16us", "16-32us" "32-64us", ">64us" } } },
1447 { 18, 18, "clockpm", "Clock Power Management", PRDV_STRVAL,
1448 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1449 { 19, 19, "supdown", "Surprise Down Error Reporting", PRDV_STRVAL,
1450 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1451 { 20, 20, "dlact", "Data Link Layer Active Reporting", PRDV_STRVAL,
1452 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1453 { 21, 21, "linkbw", "Link Bandwidth Notification Capability",
1454 PRDV_STRVAL,
1455 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1456 { 22, 22, "aspmcomp", "ASPM Optionality Compliance", PRDV_STRVAL,
1457 .prd_val = { .prdv_strval = { "not compliant", "compliant" } } },
1458 { 24, 31, "portno", "Port Number", PRDV_HEX },
1459 { -1, -1, NULL }
1460 };
1461
1462 static const pcieadm_regdef_t pcieadm_regdef_pcie_linkctl[] = {
1463 { 0, 1, "aspmctl", "ASPM Control", PRDV_STRVAL,
1464 .prd_val = { .prdv_strval = { "None", "L0s", "L1", "L0s/L1" } } },
1465 { 3, 3, "rcb", "Read Completion Boundary", PRDV_STRVAL,
1466 .prd_val = { .prdv_strval = { "64 byte", "128 byte" } } },
1467 { 4, 4, "disable", "Link Disable", PRDV_STRVAL,
1468 .prd_val = { .prdv_strval = { "not force disabled",
1469 "force disabled" } } },
1470 { 5, 5, "retrain", "Retrain Link", PRDV_HEX },
1471 { 6, 6, "ccc", "Common Clock Configuration", PRDV_STRVAL,
1472 .prd_val = { .prdv_strval = { "asynchronous", "common" } } },
1473 { 7, 7, "extsync", "Extended Sync", PRDV_STRVAL,
1474 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1475 { 8, 8, "clkpm", "Clock Power Management", PRDV_STRVAL,
1476 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1477 { 9, 9, "hwawd", "Hardware Autonomous Width", PRDV_STRVAL,
1478 .prd_val = { .prdv_strval = { "enabled", "disabled" } } },
1479 { 10, 10, "linkbwint", "Link Bandwidth Management Interrupt",
1480 PRDV_STRVAL, .prd_val = { .prdv_strval = { "disabled",
1481 "enabled" } } },
1482 { 11, 11, "linkabwint", "Link Autonomous Bandwidth Interrupt",
1483 PRDV_STRVAL, .prd_val = { .prdv_strval = { "disabled",
1484 "enabled" } } },
1485 { 14, 15, "drs", "DRS Signaling Control", PRDV_STRVAL,
1486 .prd_val = { .prdv_strval = { "not reported", "Interrupt enabled",
1487 "DRS->FRS enabled" } } },
1488 { -1, -1, NULL }
1489 };
1490
1491 static const pcieadm_regdef_t pcieadm_regdef_pcie_linksts[] = {
1492 { 0, 3, "speed", "Link Speed", PRDV_STRVAL,
1493 .prd_val = { .prdv_strval = { NULL, "2.5 GT/s", "5.0 GT/s",
1494 "8.0 GT/s", "16.0 GT/s", "32.0 GT/s", "64.0 GT/s" } } },
1495 { 4, 9, "width", "Link Width", PRDV_HEX },
1496 { 11, 11, "training", "Link Training", PRDV_STRVAL,
1497 .prd_val = { .prdv_strval = { "no", "yes" } } },
1498 { 12, 12, "slotclk", "Slot Clock Configuration", PRDV_STRVAL,
1499 .prd_val = { .prdv_strval = { "asynchronous", "common" } } },
1500 { 13, 13, "dllact", "Data Link Layer Link Active", PRDV_STRVAL,
1501 .prd_val = { .prdv_strval = { "no", "yes" } } },
1502 { 14, 14, "linkbw", "Link Bandwidth Management Status", PRDV_STRVAL,
1503 .prd_val = { .prdv_strval = { "no change", "change occurred" } } },
1504 { 15, 15, "linkabw", "Link Autonomous Bandwidth Status", PRDV_STRVAL,
1505 .prd_val = { .prdv_strval = { "no change", "change occurred" } } },
1506 { -1, -1, NULL }
1507 };
1508
1509 static const pcieadm_regdef_t pcieadm_regdef_pcie_slotcap[] = {
1510 { 0, 0, "attnbtn", "Attention Button Present", PRDV_STRVAL,
1511 .prd_val = { .prdv_strval = { "no", "yes" } } },
1512 { 1, 1, "pwrctrl", "Power Controller Present", PRDV_STRVAL,
1513 .prd_val = { .prdv_strval = { "no", "yes" } } },
1514 { 2, 2, "mrlsen", "MRL Sensor Present", PRDV_STRVAL,
1515 .prd_val = { .prdv_strval = { "no", "yes" } } },
1516 { 3, 3, "attnind", "Attention Indicator Present", PRDV_STRVAL,
1517 .prd_val = { .prdv_strval = { "no", "yes" } } },
1518 { 4, 4, "pwrind", "Power Indicator Present", PRDV_STRVAL,
1519 .prd_val = { .prdv_strval = { "no", "yes" } } },
1520 { 5, 5, "hpsup", "Hot-Plug Surprise", PRDV_STRVAL,
1521 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1522 { 6, 6, "hpcap", "Hot-Plug Capable ", PRDV_STRVAL,
1523 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1524 { 7, 14, "slotplv", "Slot Power Limit Value", PRDV_HEX },
1525 { 15, 16, "slotpls", "Slot Power Limit Scale", PRDV_HEX },
1526 { 17, 17, "emi", "Electromechanical Interlock Present", PRDV_STRVAL,
1527 .prd_val = { .prdv_strval = { "no", "yes" } } },
1528 { 18, 18, "ncc", "No Command Completed", PRDV_STRVAL,
1529 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1530 { 19, 31, "slotno", "Physical Slot Number", PRDV_HEX },
1531 { -1, -1, NULL }
1532 };
1533
1534 static const pcieadm_regdef_t pcieadm_regdef_pcie_slotctl[] = {
1535 { 0, 0, "attnbtn", "Attention Button Pressed Reporting", PRDV_STRVAL,
1536 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1537 { 1, 1, "pwrflt", "Power Fault Detected Reporting", PRDV_STRVAL,
1538 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1539 { 2, 2, "mrlchg", "MRL Sensor Changed Reporting", PRDV_STRVAL,
1540 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1541 { 3, 3, "preschg", "Presence Detect Changed Reporting", PRDV_STRVAL,
1542 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1543 { 4, 4, "ccmpltint", "Command Complete Interrupt", PRDV_STRVAL,
1544 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1545 { 5, 5, "hpi", "Hot Plug Interrupt Enable", PRDV_STRVAL,
1546 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1547 { 6, 7, "attnind", "Attention Indicator Control", PRDV_STRVAL,
1548 .prd_val = { .prdv_strval = { NULL, "on", "blink", "off" } } },
1549 { 8, 9, "pwrin", "Power Indicator Control", PRDV_STRVAL,
1550 .prd_val = { .prdv_strval = { NULL, "on", "blink", "off" } } },
1551 { 10, 10, "pwrctrl", "Power Controller Control", PRDV_STRVAL,
1552 .prd_val = { .prdv_strval = { "power on", "power off" } } },
1553 { 11, 11, "emi", "Electromechanical Interlock Control", PRDV_HEX },
1554 { 12, 12, "dll", "Data Link Layer State Changed", PRDV_STRVAL,
1555 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1556 { 13, 13, "autopowdis", "Auto Slot Power Limit", PRDV_STRVAL,
1557 .prd_val = { .prdv_strval = { "enabled", "disabled" } } },
1558 { 14, 14, "ibpddis", "In-Band PD", PRDV_STRVAL,
1559 .prd_val = { .prdv_strval = { "enabled", "disabled" } } },
1560 { -1, -1, NULL }
1561 };
1562
1563 static const pcieadm_regdef_t pcieadm_regdef_pcie_slotsts[] = {
1564 { 0, 0, "attnbtn", "Attention Button Pressed", PRDV_STRVAL,
1565 .prd_val = { .prdv_strval = { "no", "yes" } } },
1566 { 1, 1, "pwrflt", "Power Fault Detected", PRDV_STRVAL,
1567 .prd_val = { .prdv_strval = { "no", "yes" } } },
1568 { 2, 2, "mrlchg", "MRL Sensor Changed", PRDV_STRVAL,
1569 .prd_val = { .prdv_strval = { "no", "yes" } } },
1570 { 3, 3, "preschg", "Presence Detect Changed", PRDV_STRVAL,
1571 .prd_val = { .prdv_strval = { "no", "yes" } } },
1572 { 4, 4, "ccmplt", "Command Complete", PRDV_STRVAL,
1573 .prd_val = { .prdv_strval = { "no", "yes" } } },
1574 { 5, 5, "mrlsen", "MRL Sensor State", PRDV_STRVAL,
1575 .prd_val = { .prdv_strval = { "closed", "open" } } },
1576 { 6, 6, "presdet", "Presence Detect State", PRDV_STRVAL,
1577 .prd_val = { .prdv_strval = { "not present", "present" } } },
1578 { 7, 7, "emi", "Electromechanical Interlock", PRDV_STRVAL,
1579 .prd_val = { .prdv_strval = { "disengaged", "engaged" } } },
1580 { 8, 8, "dll", "Data Link Layer State Changed", PRDV_STRVAL,
1581 .prd_val = { .prdv_strval = { "no", "yes" } } },
1582 { -1, -1, NULL }
1583 };
1584
1585 static const pcieadm_regdef_t pcieadm_regdef_pcie_rootcap[] = {
1586 { 0, 0, "syscorerr", "System Error on Correctable Error", PRDV_STRVAL,
1587 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1588 { 1, 1, "sysnonftl", "System Error on Non-Fatal Error", PRDV_STRVAL,
1589 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1590 { 2, 2, "sysfatal", "System Error on Fatal Error", PRDV_STRVAL,
1591 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1592 { 3, 3, "pmeie", "PME Interrupt", PRDV_STRVAL,
1593 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1594 { 4, 4, "crssw", "CRS Software Visibility", PRDV_STRVAL,
1595 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1596 { -1, -1, NULL }
1597 };
1598
1599 static const pcieadm_regdef_t pcieadm_regdef_pcie_rootctl[] = {
1600 { 0, 0, "crssw", "CRS Software Visibility", PRDV_STRVAL,
1601 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1602 { -1, -1, NULL }
1603 };
1604
1605 static const pcieadm_regdef_t pcieadm_regdef_pcie_rootsts[] = {
1606 { 0, 15, "pmereqid", "PME Requester ID", PRDV_HEX },
1607 { 16, 16, "pmests", "PME Status", PRDV_STRVAL,
1608 .prd_val = { .prdv_strval = { "deasserted", "asserted" } } },
1609 { 17, 17, "pmepend", "PME Pending", PRDV_STRVAL,
1610 .prd_val = { .prdv_strval = { "no", "yes" } } },
1611 { -1, -1, NULL }
1612 };
1613
1614 static const pcieadm_regdef_t pcieadm_regdef_pcie_devcap2[] = {
1615 { 0, 3, "cmpto", "Completion Timeout Ranges Supported", PRDV_BITFIELD,
1616 .prd_val = { .prdv_strval = { "50us-10ms", "10ms-250ms",
1617 "250ms-4s", "4s-64s" } } },
1618 { 4, 4, "cmptodis", "Completion Timeout Disable", PRDV_STRVAL,
1619 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1620 { 5, 5, "ari", "ARI Forwarding", PRDV_STRVAL,
1621 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1622 { 6, 6, "atomroute", "AtomicOp Routing", PRDV_STRVAL,
1623 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1624 { 7, 7, "atom32", "32-bit AtomicOp Completer", PRDV_STRVAL,
1625 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1626 { 8, 8, "atom64", "64-bit AtomicOp Completer", PRDV_STRVAL,
1627 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1628 { 9, 9, "cas128", "128-bit CAS Completer", PRDV_STRVAL,
1629 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1630 { 10, 10, "norelord", "No Ro-enabld PR-PR Passing", PRDV_STRVAL,
1631 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1632 { 11, 11, "ltr", "LTR Mechanism", PRDV_STRVAL,
1633 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1634 { 12, 13, "tph", "TPH Completer", PRDV_STRVAL,
1635 .prd_val = { .prdv_strval = { "unsupported", "TPH supported",
1636 NULL, "TPH and Extended TPH supported" } } },
1637 { 14, 15, "lncls", "LN System CLS", PRDV_STRVAL,
1638 .prd_val = { .prdv_strval = { "unsupported",
1639 "LN with 64-byte cachelines", "LN with 128-byte cachelines" } } },
1640 { 16, 16, "tag10comp", "10-bit Tag Completer", PRDV_STRVAL,
1641 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1642 { 17, 17, "tag10req", "10-bit Tag Requester", PRDV_STRVAL,
1643 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1644 { 18, 19, "obff", "OBFF", PRDV_STRVAL,
1645 .prd_val = { .prdv_strval = { "unsupported", "Message Signaling",
1646 "WAKE# Signaling", "WAKE# and Message Signaling" } } },
1647 { 20, 20, "extfmt", "Extended Fmt Field Supported", PRDV_STRVAL,
1648 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1649 { 21, 21, "eetlp", "End-End TLP Prefix Supported", PRDV_STRVAL,
1650 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1651 { 22, 23, "maxeetlp", "Max End-End TLP Prefixes", PRDV_STRVAL,
1652 .prd_val = { .prdv_strval = { "4", "1", "2", "3" } } },
1653 { 24, 25, "empr", "Emergency Power Reduction", PRDV_STRVAL,
1654 .prd_val = { .prdv_strval = { "unsupported",
1655 "supported, device-specific",
1656 "supported, from factor or device-specific" } } },
1657 { 21, 21, "emprinit",
1658 "Emergency Power Reduction Initialization Required", PRDV_STRVAL,
1659 .prd_val = { .prdv_strval = { "no", "yes" } } },
1660 { 31, 31, "frs", "Function Readiness Status", PRDV_STRVAL,
1661 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1662 { -1, -1, NULL }
1663 };
1664
1665 static const pcieadm_regdef_t pcieadm_regdef_pcie_devctl2[] = {
1666 { 0, 3, "cmpto", "Completion Timeout", PRDV_STRVAL,
1667 .prd_val = { .prdv_strval = { "50us-50ms", "50us-100us",
1668 "1ms-10ms", NULL, NULL, "16ms-55ms", "65ms-210ms", NULL, NULL,
1669 "260ms-900ms", "1s-3.5s", NULL, NULL, "4s-13s", "17s-64s" } } },
1670 { 4, 4, "cmptodis", "Completion Timeout Disabled", PRDV_STRVAL,
1671 .prd_val = { .prdv_strval = { "not disabled", "disabled" } } },
1672 { 5, 5, "ari", "ARI Forwarding", PRDV_STRVAL,
1673 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1674 { 6, 6, "atomreq", "AtomicOp Requester", PRDV_STRVAL,
1675 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1676 { 7, 7, "atomblock", "AtomicOp Egress Blocking", PRDV_STRVAL,
1677 .prd_val = { .prdv_strval = { "unblocked", "blocked" } } },
1678 { 8, 8, "idoreq", "ID-Based Ordering Request", PRDV_STRVAL,
1679 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1680 { 9, 9, "idocomp", "ID-Based Ordering Completion", PRDV_STRVAL,
1681 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1682 { 10, 10, "ltr", "LTR Mechanism", PRDV_STRVAL,
1683 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1684 { 11, 11, "empowred", "Emergency Power Reduction", PRDV_STRVAL,
1685 .prd_val = { .prdv_strval = { "not requested", "requested" } } },
1686 { 12, 12, "tag10req", "10-bit Tag Requester", PRDV_STRVAL,
1687 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1688 { 13, 14, "obff", "OBFF", PRDV_STRVAL,
1689 .prd_val = { .prdv_strval = { "disabled", "message signaling - A",
1690 "message signaling - B", "WAKE# signaling" } } },
1691 { 15, 15, "eetlpblk", "End-End TLP Prefix Blocking", PRDV_STRVAL,
1692 .prd_val = { .prdv_strval = { "unblocked", "blocked" } } },
1693 { -1, -1, NULL }
1694 };
1695
1696 static const pcieadm_regdef_t pcieadm_regdef_pcie_devsts2[] = {
1697 { -1, -1, NULL }
1698 };
1699
1700 static const pcieadm_regdef_t pcieadm_regdef_pcie_linkcap2[] = {
1701 { 1, 7, "supspeeds", "Supported Link Speeds", PRDV_BITFIELD,
1702 .prd_val = { .prdv_strval = { "2.5 GT/s", "5.0 GT/s", "8.0 GT/s",
1703 "16.0 GT/s", "32.0 GT/s", "64.0 GT/s" } } },
1704 { 8, 8, "crosslink", "Crosslink", PRDV_STRVAL,
1705 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1706 { 9, 15, "skposgen", "Lower SKP OS Generation Supported Speeds Vector",
1707 PRDV_BITFIELD,
1708 .prd_val = { .prdv_strval = { "2.5 GT/s", "5.0 GT/s", "8.0 GT/s",
1709 "16.0 GT/s", "32.0 GT/s", "64.0 GT/s" } } },
1710 { 16, 22, "skposrecv", "Lower SKP OS Reception Supported Speeds Vector",
1711 PRDV_BITFIELD,
1712 .prd_val = { .prdv_strval = { "2.5 GT/s", "5.0 GT/s", "8.0 GT/s",
1713 "16.0 GT/s", "32.0 GT/s", "64.0 GT/s" } } },
1714 { 23, 23, "retimedet", "Retimer Presence Detect Supported", PRDV_STRVAL,
1715 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1716 { 24, 24, "retime2det", "Two Retimers Presence Detect Supported",
1717 PRDV_STRVAL,
1718 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1719 { 31, 31, "drs", "Device Readiness Status", PRDV_STRVAL,
1720 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1721 { -1, -1, NULL }
1722 };
1723
1724 static const pcieadm_regdef_t pcieadm_regdef_pcie_linkctl2[] = {
1725 { 0, 3, "targspeed", "Target Link Speed", PRDV_STRVAL,
1726 .prd_val = { .prdv_strval = { NULL, "2.5 GT/s", "5.0 GT/s",
1727 "8.0 GT/s", "16.0 GT/s", "32.0 GT/s", "64.0 GT/s" } } },
1728 { 4, 4, "comp", "Enter Compliance", PRDV_STRVAL,
1729 .prd_val = { .prdv_strval = { "no", "yes" } } },
1730 { 5, 5, "hwautosp", "Hardware Autonomous Speed Disable", PRDV_STRVAL,
1731 .prd_val = { .prdv_strval = { "not disabled", "disabled" } } },
1732 { 6, 6, "seldeemph", "Selectable De-emphasis", PRDV_STRVAL,
1733 .prd_val = { .prdv_strval = { "-6 dB", "-3.5 dB" } } },
1734 { 7, 9, "txmarg", "TX Margin", PRDV_HEX },
1735 { 10, 10, "modcomp", "Enter Modified Compliance", PRDV_STRVAL,
1736 .prd_val = { .prdv_strval = { "no", "yes" } } },
1737 { 11, 11, "compsos", "Compliance SOS",
1738 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1739 { 12, 15, "compemph", "Compliance Preset/De-emphasis", PRDV_HEX },
1740 { -1, -1, NULL }
1741 };
1742
1743 static const pcieadm_regdef_t pcieadm_regdef_pcie_linksts2[] = {
1744 { 0, 0, "curdeemph", "Current De-emphasis Level", PRDV_STRVAL,
1745 .prd_val = { .prdv_strval = { "-6 dB", "-3.5 dB" } } },
1746 { 1, 1, "eq8comp", "Equalization 8.0 GT/s Complete", PRDV_STRVAL,
1747 .prd_val = { .prdv_strval = { "no", "yes" } } },
1748 { 2, 2, "eq8p1comp", "Equalization 8.0 GT/s Phase 1", PRDV_STRVAL,
1749 .prd_val = { .prdv_strval = { "unsuccessful", "successful" } } },
1750 { 3, 3, "eq8p2comp", "Equalization 8.0 GT/s Phase 2", PRDV_STRVAL,
1751 .prd_val = { .prdv_strval = { "unsuccessful", "successful" } } },
1752 { 4, 4, "eq8p3comp", "Equalization 8.0 GT/s Phase 3", PRDV_STRVAL,
1753 .prd_val = { .prdv_strval = { "unsuccessful", "successful" } } },
1754 { 5, 5, "linkeq8req", "Link Equalization Request 8.0 GT/s", PRDV_STRVAL,
1755 .prd_val = { .prdv_strval = { "not requested", "requested" } } },
1756 { 6, 6, "retimedet", "Retimer Presence Detected", PRDV_STRVAL,
1757 .prd_val = { .prdv_strval = { "no", "yes" } } },
1758 { 7, 7, "retime2det", "Two Retimers Presence Detected", PRDV_STRVAL,
1759 .prd_val = { .prdv_strval = { "no", "yes" } } },
1760 { 8, 9, "crosslink", "Crosslink Resolution", PRDV_STRVAL,
1761 .prd_val = { .prdv_strval = { "unsupported", "upstream port",
1762 "downstream port", "incomplete" } } },
1763 { 12, 14, "dscomppres", "Downstream Component Presence", PRDV_STRVAL,
1764 .prd_val = { .prdv_strval = { "link down - undetermined",
1765 "link down - not present", "link down - present", NULL,
1766 "link up - present", "link up - present and DRS" } } },
1767 { 15, 15, "drsrx", "DRS Message Received", PRDV_STRVAL,
1768 .prd_val = { .prdv_strval = { "no", "yes" } } },
1769 { -1, -1, NULL }
1770 };
1771
1772 static const pcieadm_regdef_t pcieadm_regdef_pcie_slotcap2[] = {
1773 { 0, 0, "ibpddis", "In-Band PD Disable", PRDV_STRVAL,
1774 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1775 { -1, -1, NULL }
1776 };
1777
1778 static const pcieadm_regdef_t pcieadm_regdef_pcie_slotctl2[] = {
1779 { -1, -1, NULL }
1780 };
1781
1782 static const pcieadm_regdef_t pcieadm_regdef_pcie_slotsts2[] = {
1783 { -1, -1, NULL }
1784 };
1785
1786 static const pcieadm_cfgspace_print_t pcieadm_cap_pcie_v1_dev[] = {
1787 { PCIE_PCIECAP, 2, "cap", "Capability Register",
1788 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_cap },
1789 { PCIE_DEVCAP, 4, "devcap", "Device Capabilities",
1790 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devcap },
1791 { PCIE_DEVSTS, 2, "devsts", "Device Status",
1792 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devsts },
1793 { -1, -1, NULL }
1794 };
1795
1796 static const pcieadm_cfgspace_print_t pcieadm_cap_pcie_v1_link[] = {
1797 { PCIE_PCIECAP, 2, "cap", "Capability Register",
1798 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_cap },
1799 { PCIE_DEVCAP, 4, "devcap", "Device Capabilities",
1800 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devcap },
1801 { PCIE_DEVSTS, 2, "devsts", "Device Status",
1802 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devsts },
1803 { PCIE_LINKCAP, 4, "linkcap", "Link Capabilities",
1804 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkcap },
1805 { PCIE_LINKCTL, 2, "linkctl", "Link Control",
1806 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkctl },
1807 { PCIE_LINKSTS, 2, "linksts", "Link Status",
1808 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linksts },
1809 { -1, -1, NULL }
1810 };
1811
1812 static const pcieadm_cfgspace_print_t pcieadm_cap_pcie_v1_slot[] = {
1813 { PCIE_PCIECAP, 2, "cap", "Capability Register",
1814 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_cap },
1815 { PCIE_DEVCAP, 4, "devcap", "Device Capabilities",
1816 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devcap },
1817 { PCIE_DEVSTS, 2, "devsts", "Device Status",
1818 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devsts },
1819 { PCIE_LINKCAP, 4, "linkcap", "Link Capabilities",
1820 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkcap },
1821 { PCIE_LINKCTL, 2, "linkctl", "Link Control",
1822 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkctl },
1823 { PCIE_LINKSTS, 2, "linksts", "Link Status",
1824 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linksts },
1825 { PCIE_SLOTCAP, 4, "slotcap", "Slot Capabilities",
1826 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotcap },
1827 { PCIE_SLOTCTL, 2, "slotctl", "Slot Control",
1828 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotctl },
1829 { PCIE_SLOTSTS, 2, "slotsts", "Slot Status",
1830 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotsts },
1831 { -1, -1, NULL }
1832 };
1833
1834
1835 static const pcieadm_cfgspace_print_t pcieadm_cap_pcie_v1_all[] = {
1836 { PCIE_PCIECAP, 2, "cap", "Capability Register",
1837 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_cap },
1838 { PCIE_DEVCAP, 4, "devcap", "Device Capabilities",
1839 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devcap },
1840 { PCIE_DEVSTS, 2, "devsts", "Device Status",
1841 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devsts },
1842 { PCIE_LINKCAP, 4, "linkcap", "Link Capabilities",
1843 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkcap },
1844 { PCIE_LINKCTL, 2, "linkctl", "Link Control",
1845 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkctl },
1846 { PCIE_LINKSTS, 2, "linksts", "Link Status",
1847 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linksts },
1848 { PCIE_SLOTCAP, 4, "slotcap", "Slot Capabilities",
1849 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotcap },
1850 { PCIE_SLOTCTL, 2, "slotctl", "Slot Control",
1851 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotctl },
1852 { PCIE_SLOTSTS, 2, "slotsts", "Slot Status",
1853 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotsts },
1854 { PCIE_ROOTCTL, 2, "rootctl", "Root control",
1855 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_rootctl },
1856 { PCIE_ROOTCAP, 2, "rootcap", "Root Capabilities",
1857 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_rootcap },
1858 { PCIE_ROOTSTS, 4, "rootsts", "Root Status",
1859 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_rootsts },
1860 { -1, -1, NULL }
1861 };
1862
1863 static const pcieadm_cfgspace_print_t pcieadm_cap_pcie_v2[] = {
1864 { PCIE_PCIECAP, 2, "cap", "Capability Register",
1865 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_cap },
1866 { PCIE_DEVCAP, 4, "devcap", "Device Capabilities",
1867 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devcap },
1868 { PCIE_DEVCTL, 2, "devctl", "Device Control",
1869 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devctl },
1870 { PCIE_DEVSTS, 2, "devsts", "Device Status",
1871 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devsts },
1872 { PCIE_LINKCAP, 4, "linkcap", "Link Capabilities",
1873 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkcap },
1874 { PCIE_LINKCTL, 2, "linkctl", "Link Control",
1875 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkctl },
1876 { PCIE_LINKSTS, 2, "linksts", "Link Status",
1877 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linksts },
1878 { PCIE_SLOTCAP, 4, "slotcap", "Slot Capabilities",
1879 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotcap },
1880 { PCIE_SLOTCTL, 2, "slotctl", "Slot Control",
1881 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotctl },
1882 { PCIE_SLOTSTS, 2, "slotsts", "Slot Status",
1883 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotsts },
1884 { PCIE_ROOTCTL, 2, "rootctl", "Root Control",
1885 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_rootctl },
1886 { PCIE_ROOTCAP, 2, "rootcap", "Root Capabilities",
1887 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_rootcap },
1888 { PCIE_ROOTSTS, 4, "rootsts", "Root Status",
1889 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_rootsts },
1890 { PCIE_DEVCAP2, 4, "devcap2", "Device Capabilities 2",
1891 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devcap2 },
1892 { PCIE_DEVCTL2, 2, "devctl2", "Device Control 2",
1893 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devctl2 },
1894 { PCIE_DEVSTS2, 2, "devsts2", "Device Status 2",
1895 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devsts2 },
1896 { PCIE_LINKCAP2, 4, "linkcap2", "Link Capabilities 2",
1897 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkcap2 },
1898 { PCIE_LINKCTL2, 2, "linkctl2", "Link Control 2",
1899 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkctl2 },
1900 { PCIE_LINKSTS2, 2, "linksts2", "Link Status 2",
1901 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linksts2 },
1902 { PCIE_SLOTCAP2, 4, "slotcap2", "Slot Capabilities 2",
1903 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotcap2 },
1904 { PCIE_SLOTCTL2, 2, "slotctl2", "Slot Control 2",
1905 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotctl2 },
1906 { PCIE_SLOTSTS2, 2, "slotsts2", "Slot Status 2",
1907 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotsts2 },
1908 { -1, -1, NULL }
1909 };
1910
1911 /*
1912 * PCIe Extended Capability Header
1913 */
1914 static const pcieadm_regdef_t pcieadm_regdef_pcie_caphdr[] = {
1915 { 0, 15, "capid", "Capability ID", PRDV_HEX },
1916 { 16, 19, "version", "Capability Version", PRDV_HEX },
1917 { 20, 32, "offset", "Next Capability Offset", PRDV_HEX },
1918 { -1, -1, NULL }
1919 };
1920
1921 /*
1922 * VPD Capability
1923 */
1924 static const pcieadm_regdef_t pcieadm_regdef_vpd_addr[] = {
1925 { 0, 14, "addr", "VPD Address", PRDV_HEX },
1926 { 15, 15, "flag", "Flag", PRDV_HEX },
1927 { -1, -1, NULL }
1928 };
1929
1930 static const pcieadm_cfgspace_print_t pcieadm_cap_vpd[] = {
1931 { 0x2, 2, "addr", "VPD Address Register",
1932 pcieadm_cfgspace_print_regdef, pcieadm_regdef_vpd_addr },
1933 { 0x4, 4, "data", "VPD Data", pcieadm_cfgspace_print_hex },
1934 { -1, -1, NULL }
1935 };
1936
1937 /*
1938 * SATA Capability per AHCI 1.3.1
1939 */
1940 static const pcieadm_regdef_t pcieadm_regdef_sata_cr0[] = {
1941 { 0, 3, "minrev", "Minor Revision", PRDV_HEX },
1942 { 4, 7, "majrev", "Major Revision", PRDV_HEX },
1943 { -1, -1, NULL }
1944 };
1945
1946 static const pcieadm_regdef_t pcieadm_regdef_sata_cr1[] = {
1947 { 0, 3, "bar", "BAR Location", PRDV_HEX,
1948 .prd_val = { .prdv_hex = { 2 } } },
1949 { 4, 23, "offset", "BAR Offset", PRDV_HEX,
1950 .prd_val = { .prdv_hex = { 2 } } },
1951 { -1, -1, NULL }
1952 };
1953
1954 static const pcieadm_cfgspace_print_t pcieadm_cap_sata[] = {
1955 { 0x2, 2, "satacr0", "SATA Capability Register 0",
1956 pcieadm_cfgspace_print_regdef, pcieadm_regdef_sata_cr0 },
1957 { 0x4, 4, "satacr1", "SATA Capability Register 1",
1958 pcieadm_cfgspace_print_regdef, pcieadm_regdef_sata_cr1 },
1959 { -1, -1, NULL }
1960 };
1961
1962 /*
1963 * Debug Capability per EHCI
1964 */
1965 static const pcieadm_regdef_t pcieadm_regdef_debug[] = {
1966 { 0, 12, "offset", "BAR Offset", PRDV_HEX },
1967 { 13, 15, "bar", "BAR Location ", PRDV_STRVAL,
1968 .prd_val = { .prdv_strval = { NULL, "BAR 0", "BAR 1", "BAR 2",
1969 "BAR 3", "BAR 4", "BAR 5" } } },
1970 { -1, -1, NULL }
1971 };
1972
1973 static const pcieadm_cfgspace_print_t pcieadm_cap_debug[] = {
1974 { 0x2, 2, "port", "Debug Port",
1975 pcieadm_cfgspace_print_regdef, pcieadm_regdef_debug },
1976 { -1, -1, NULL }
1977 };
1978
1979 /*
1980 * AER Capability
1981 */
1982 static const pcieadm_regdef_t pcieadm_regdef_aer_ue[] = {
1983 { 4, 4, "dlp", "Data Link Protocol Error", PRDV_HEX },
1984 { 5, 5, "sde", "Surprise Down Error", PRDV_HEX },
1985 { 12, 12, "ptlp", "Poisoned TLP Received", PRDV_HEX },
1986 { 13, 13, "fcp", "Flow Control Protocol Error", PRDV_HEX },
1987 { 14, 14, "cto", "Completion Timeout", PRDV_HEX },
1988 { 15, 15, "cab", "Completion Abort", PRDV_HEX },
1989 { 16, 16, "unco", "Unexpected Completion", PRDV_HEX },
1990 { 17, 17, "rxov", "Receiver Overflow", PRDV_HEX },
1991 { 18, 18, "maltlp", "Malformed TLP", PRDV_HEX },
1992 { 19, 19, "ecrc", "ECRC Error", PRDV_HEX },
1993 { 20, 20, "usuprx", "Unsupported Request Error", PRDV_HEX },
1994 { 21, 21, "acs", "ACS Violation", PRDV_HEX },
1995 { 22, 22, "ueint", "Uncorrectable Internal Error", PRDV_HEX },
1996 { 23, 23, "mcbtlp", "MC Blocked TLP", PRDV_HEX },
1997 { 24, 24, "atoomeb", "AtomicOp Egress Blocked", PRDV_HEX },
1998 { 25, 25, "tlppb", "TLP Prefix Blocked Error", PRDV_HEX },
1999 { 26, 26, "ptlpeb", "Poisoned TLP Egress Blocked", PRDV_HEX },
2000 { -1, -1, NULL }
2001 };
2002
2003 static const pcieadm_regdef_t pcieadm_regdef_aer_ce[] = {
2004 { 0, 0, "rxerr", "Receiver Error", PRDV_HEX },
2005 { 6, 6, "badtlp", "Bad TLP", PRDV_HEX },
2006 { 7, 7, "baddllp", "Bad DLLP", PRDV_HEX },
2007 { 8, 8, "replayro", "REPLAY_NUM Rollover", PRDV_HEX },
2008 { 12, 12, "rtto", "Replay timer Timeout", PRDV_HEX },
2009 { 13, 13, "advnfe", "Advisory Non-Fatal Error", PRDV_HEX },
2010 { 14, 14, "ceint", "Correctable Internal Error", PRDV_HEX },
2011 { 15, 15, "headlov", "Header Log Overflow", PRDV_HEX },
2012 { -1, -1, NULL }
2013 };
2014
2015 static const pcieadm_regdef_t pcieadm_regdef_aer_ctrl[] = {
2016 { 0, 4, "feptr", "First Error Pointer", PRDV_HEX },
2017 { 5, 5, "ecgencap", "ECRC Generation Capable", PRDV_STRVAL,
2018 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2019 { 6, 6, "ecgenen", "ECRC Generation Enable", PRDV_STRVAL,
2020 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2021 { 7, 7, "ecchkcap", "ECRC Check Capable", PRDV_STRVAL,
2022 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2023 { 8, 8, "ecchken", "ECRC Check Enable", PRDV_STRVAL,
2024 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2025 { -1, -1, NULL }
2026 };
2027
2028 static const pcieadm_regdef_t pcieadm_regdef_aer_rootcom[] = {
2029 { 0, 0, "corerr", "Correctable Error Reporting", PRDV_STRVAL,
2030 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2031 { 1, 1, "nferr", "Non-Fatal Error Reporting", PRDV_STRVAL,
2032 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2033 { 2, 2, "faterr", "Fatal Error Reporting", PRDV_STRVAL,
2034 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2035 { -1, -1, NULL }
2036 };
2037
2038 static const pcieadm_regdef_t pcieadm_regdef_aer_rootsts[] = {
2039 { 0, 0, "errcor", "ERR_COR Received", PRDV_HEX },
2040 { 1, 1, "merrcor", "Multiple ERR_COR Received", PRDV_HEX },
2041 { 2, 2, "errfnf", "ERR_FATAL/NONFATAL Received", PRDV_HEX },
2042 { 3, 3, "merrfnf", "Multiple ERR_FATAL/NONFATAL Received", PRDV_HEX },
2043 { 4, 4, "fuefat", "First Uncorrectable Fatal", PRDV_HEX },
2044 { 5, 5, "nferrrx", "Non-Fatal Error Messages Received", PRDV_HEX },
2045 { 6, 6, "faterrx", "Fatal Error Messages Received", PRDV_HEX },
2046 { 7, 8, "errcorsc", "ERR_COR Subclass", PRDV_STRVAL,
2047 .prd_val = { .prdv_strval = { "ECS Legacy", "ECS SIG_SFW",
2048 "ECS SIG_OS", "ECS Extended" } } },
2049 { 27, 31, "inum", "Advanced Error Interrupt Message", PRDV_HEX },
2050 { -1, -1, NULL }
2051 };
2052
2053 static const pcieadm_regdef_t pcieadm_regdef_aer_esi[] = {
2054 { 0, 15, "errcorr", "ERR_COR Source", PRDV_HEX },
2055 { 16, 31, "errfnf", "ERR_FATAL/NONFATAL Source", PRDV_HEX },
2056 { -1, -1, NULL }
2057 };
2058
2059 static const pcieadm_regdef_t pcieadm_regdef_aer_secue[] = {
2060 { 0, 0, "taosc", "Target-Abort on Split Completion", PRDV_HEX },
2061 { 1, 1, "maosc", "Master-Abort on Split Completion", PRDV_HEX },
2062 { 2, 2, "rxta", "Received Target-Abort", PRDV_HEX },
2063 { 3, 3, "rxma", "Received Master-Abort", PRDV_HEX },
2064 { 5, 5, "unsce", "Unexpected Split Completion Error", PRDV_HEX },
2065 { 6, 6, "uescmd", "Uncorrectable Split Completion Message Data Error",
2066 PRDV_HEX },
2067 { 7, 7, "uede", "Uncorrectable Data Error", PRDV_HEX },
2068 { 8, 8, "ueattre", "Uncorrectable Attribute Error", PRDV_HEX },
2069 { 9, 9, "ueaddre", "Uncorrectable Address Error", PRDV_HEX },
2070 { 10, 10, "dtdte", "Delayed Transaction Discard Timer Expired",
2071 PRDV_HEX },
2072 { 11, 11, "perr", "PERR# Assertion", PRDV_HEX },
2073 { 12, 12, "serr", "SERR# Assertion", PRDV_HEX },
2074 { 13, 13, "internal", "Internal Bridge Error", PRDV_HEX },
2075 { -1, -1, NULL }
2076 };
2077
2078 static const pcieadm_regdef_t pcieadm_regdef_aer_secctl[] = {
2079 { 0, 4, "feptr", "Secondary Uncorrectable First Error Pointer",
2080 PRDV_HEX },
2081 { -1, -1, NULL }
2082 };
2083
2084 static const pcieadm_cfgspace_print_t pcieadm_cap_aer_v1[] = {
2085 { PCIE_AER_CAP, 4, "caphdr", "Capability Header",
2086 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2087 { PCIE_AER_UCE_STS, 4, "uestatus", "Uncorrectable Error Status",
2088 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
2089 { PCIE_AER_UCE_MASK, 4, "uemask", "Uncorrectable Error Mask",
2090 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
2091 { PCIE_AER_UCE_SERV, 4, "ueserv", "Uncorrectable Error Severity",
2092 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
2093 { PCIE_AER_CE_STS, 4, "cestatus", "Correctable Error Status",
2094 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ce },
2095 { PCIE_AER_CE_MASK, 4, "cemask", "Correctable Error Mask",
2096 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ce },
2097 { PCIE_AER_CTL, 4, "ctrl", "Advanced Error Capabilities and Control",
2098 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ctrl },
2099 { PCIE_AER_HDR_LOG + 4, 4, "hl0", "Header Log 0",
2100 pcieadm_cfgspace_print_hex },
2101 { PCIE_AER_HDR_LOG + 8, 4, "hl1", "Header Log 1",
2102 pcieadm_cfgspace_print_hex },
2103 { PCIE_AER_HDR_LOG + 12, 4, "hl2", "Header Log 2",
2104 pcieadm_cfgspace_print_hex },
2105 { PCIE_AER_HDR_LOG + 12, 4, "hl3", "Header Log 3",
2106 pcieadm_cfgspace_print_hex },
2107 { PCIE_AER_RE_CMD, 4, "rootcmd", "Root Error Command",
2108 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_rootcom },
2109 { PCIE_AER_RE_STS, 4, "rootsts", "Root Error Status",
2110 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_rootsts },
2111 { PCIE_AER_CE_SRC_ID, 4, "esi", "Error Source Identification",
2112 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_esi },
2113 { -1, -1, NULL }
2114 };
2115
2116 static const pcieadm_cfgspace_print_t pcieadm_cap_aer_v2[] = {
2117 { PCIE_AER_CAP, 4, "caphdr", "Capability Header",
2118 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2119 { PCIE_AER_UCE_STS, 4, "uestatus", "Uncorrectable Error Status",
2120 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
2121 { PCIE_AER_UCE_MASK, 4, "uemask", "Uncorrectable Error Mask",
2122 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
2123 { PCIE_AER_UCE_SERV, 4, "ueserv", "Uncorrectable Error Severity",
2124 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
2125 { PCIE_AER_CE_STS, 4, "cestatus", "Correctable Error Status",
2126 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ce },
2127 { PCIE_AER_CE_MASK, 4, "cemask", "Correctable Error Mask",
2128 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ce },
2129 { PCIE_AER_CTL, 4, "ctrl", "Advanced Error Capabilities and Control",
2130 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ctrl },
2131 { PCIE_AER_HDR_LOG + 4, 4, "hl0", "Header Log 0",
2132 pcieadm_cfgspace_print_hex },
2133 { PCIE_AER_HDR_LOG + 8, 4, "hl1", "Header Log 1",
2134 pcieadm_cfgspace_print_hex },
2135 { PCIE_AER_HDR_LOG + 12, 4, "hl2", "Header Log 2",
2136 pcieadm_cfgspace_print_hex },
2137 { PCIE_AER_HDR_LOG + 12, 4, "hl3", "Header Log 3",
2138 pcieadm_cfgspace_print_hex },
2139 { PCIE_AER_RE_CMD, 4, "rootcmd", "Root Error Command",
2140 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_rootcom },
2141 { PCIE_AER_RE_STS, 4, "rootsts", "Root Error Status",
2142 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_rootsts },
2143 { PCIE_AER_TLP_PRE_LOG, 4, "tlplog0", "TLP Prefix Log 0",
2144 pcieadm_cfgspace_print_hex },
2145 { PCIE_AER_TLP_PRE_LOG + 4, 4, "tlplog1", "TLP Prefix Log 1",
2146 pcieadm_cfgspace_print_hex },
2147 { PCIE_AER_TLP_PRE_LOG + 8, 4, "tlplog2", "TLP Prefix Log 2",
2148 pcieadm_cfgspace_print_hex },
2149 { PCIE_AER_TLP_PRE_LOG + 12, 4, "tlplog3", "TLP Prefix Log 3",
2150 pcieadm_cfgspace_print_hex },
2151 { -1, -1, NULL }
2152 };
2153
2154 static const pcieadm_cfgspace_print_t pcieadm_cap_aer_bridge[] = {
2155 { PCIE_AER_CAP, 4, "caphdr", "Capability Header",
2156 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2157 { PCIE_AER_UCE_STS, 4, "uestatus", "Uncorrectable Error Status",
2158 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
2159 { PCIE_AER_UCE_MASK, 4, "uemask", "Uncorrectable Error Mask",
2160 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
2161 { PCIE_AER_UCE_SERV, 4, "ueserv", "Uncorrectable Error Severity",
2162 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
2163 { PCIE_AER_CE_STS, 4, "cestatus", "Correctable Error Status",
2164 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ce },
2165 { PCIE_AER_CE_MASK, 4, "cemask", "Correctable Error Mask",
2166 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ce },
2167 { PCIE_AER_CTL, 4, "ctrl", "Advanced Error Capabilities and Control",
2168 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ctrl },
2169 { PCIE_AER_HDR_LOG + 4, 4, "hl0", "Header Log 0",
2170 pcieadm_cfgspace_print_hex },
2171 { PCIE_AER_HDR_LOG + 8, 4, "hl1", "Header Log 1",
2172 pcieadm_cfgspace_print_hex },
2173 { PCIE_AER_HDR_LOG + 12, 4, "hl2", "Header Log 2",
2174 pcieadm_cfgspace_print_hex },
2175 { PCIE_AER_HDR_LOG + 12, 4, "hl3", "Header Log 3",
2176 pcieadm_cfgspace_print_hex },
2177 { PCIE_AER_RE_CMD, 4, "rootcmd", "Root Error Command",
2178 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_rootcom },
2179 { PCIE_AER_RE_STS, 4, "rootsts", "Root Error Status",
2180 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_rootsts },
2181 { PCIE_AER_CE_SRC_ID, 4, "esi", "Error Source Identification",
2182 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_esi },
2183 { PCIE_AER_SUCE_STS, 4, "secuests",
2184 "Secondary Uncorrectable Error Status",
2185 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_secue },
2186 { PCIE_AER_SUCE_MASK, 4, "secuests",
2187 "Secondary Uncorrectable Error Mask",
2188 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_secue },
2189 { PCIE_AER_SUCE_SERV, 4, "secuests",
2190 "Secondary Uncorrectable Error Severity",
2191 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_secue },
2192 { PCIE_AER_SCTL, 4, "secctrl",
2193 "Secondary Error Capabilityes and Control",
2194 pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_secctl },
2195 { PCIE_AER_SHDR_LOG, 4, "shl0", "Secondary Header Log 0",
2196 pcieadm_cfgspace_print_hex },
2197 { PCIE_AER_SHDR_LOG + 4, 4, "shl1", "Secondary Header Log 1",
2198 pcieadm_cfgspace_print_hex },
2199 { PCIE_AER_SHDR_LOG + 8, 4, "shl1", "Secondary Header Log 2",
2200 pcieadm_cfgspace_print_hex },
2201 { PCIE_AER_SHDR_LOG + 12, 4, "shl1", "Secondary Header Log 3",
2202 pcieadm_cfgspace_print_hex },
2203 { -1, -1, NULL }
2204 };
2205
2206 /*
2207 * Secondary PCI Express Extended Capability
2208 */
2209 static const pcieadm_regdef_t pcieadm_regdef_pcie2_linkctl3[] = {
2210 { 0, 0, "peq", "Perform Equalization", PRDV_HEX },
2211 { 1, 1, "leqrie", "Link Equalization Request Interrupt Enable",
2212 PRDV_STRVAL,
2213 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2214 { 9, 15, "elskpos", "Enable Lower SKP OS Generation Vector",
2215 PRDV_BITFIELD,
2216 .prd_val = { .prdv_strval = { "2.5 GT/s", "5.0 GT/s", "8.0 GT/s",
2217 "16.0 GT/s", "32.0 GT/s" } } },
2218 { -1, -1, NULL }
2219 };
2220
2221 static const pcieadm_regdef_t pcieadm_regdef_pcie2_linkeq[] = {
2222 { 0, 3, "dstxpre", "Downstream Port 8.0 GT/s Transmitter Preset",
2223 PRDV_HEX },
2224 { 4, 6, "dstxhint", "Downstream Port 8.0 GT/s Receiver Hint",
2225 PRDV_HEX },
2226 { 8, 11, "ustxpre", "Upstream Port 8.0 GT/s Transmitter Preset",
2227 PRDV_HEX },
2228 { 12, 14, "ustxhint", "Upstream Port 8.0 GT/s Receiver Hint",
2229 PRDV_HEX },
2230 { -1, -1, NULL }
2231 };
2232
2233 static void
pcieadm_cfgspace_print_laneq(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)2234 pcieadm_cfgspace_print_laneq(pcieadm_cfgspace_walk_t *walkp,
2235 const pcieadm_cfgspace_print_t *print, const void *arg)
2236 {
2237 if (walkp->pcw_nlanes == 0) {
2238 warnx("failed to capture lane count, but somehow have "
2239 "secondary PCIe cap");
2240 return;
2241 }
2242
2243 for (uint_t i = 0; i < walkp->pcw_nlanes; i++) {
2244 char eqshort[32], eqhuman[128];
2245 pcieadm_cfgspace_print_t p;
2246
2247 (void) snprintf(eqshort, sizeof (eqshort), "lane%u", i);
2248 (void) snprintf(eqhuman, sizeof (eqhuman), "Lane %u EQ Control",
2249 i);
2250 p.pcp_off = print->pcp_off + i * 2;
2251 p.pcp_len = 2;
2252 p.pcp_short = eqshort;
2253 p.pcp_human = eqhuman;
2254 p.pcp_print = pcieadm_cfgspace_print_regdef;
2255 p.pcp_arg = pcieadm_regdef_pcie2_linkeq;
2256
2257 p.pcp_print(walkp, &p, p.pcp_arg);
2258 }
2259 }
2260
2261 static const pcieadm_cfgspace_print_t pcieadm_cap_pcie2[] = {
2262 { 0x0, 4, "caphdr", "Capability Header",
2263 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2264 { 0x4, 4, "linkctl3", "Link Control 3",
2265 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie2_linkctl3 },
2266 { 0x8, 4, "laneerr", "Lane Error Status", pcieadm_cfgspace_print_hex },
2267 { 0xc, 2, "eqctl", "Lane Equalization Control",
2268 pcieadm_cfgspace_print_laneq },
2269 { -1, -1, NULL }
2270 };
2271
2272 /*
2273 * Access Control Services
2274 */
2275 static const pcieadm_regdef_t pcieadm_regdef_acs_cap[] = {
2276 { 0, 0, "srcvd", "ACS Source Validation", PRDV_STRVAL,
2277 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2278 { 1, 1, "tranblk", "ACS Transaction Blocking", PRDV_STRVAL,
2279 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2280 { 2, 2, "p2prr", "ACS P2P Request Redirect", PRDV_STRVAL,
2281 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2282 { 3, 3, "p2pcr", "ACS P2P Completion Redirect", PRDV_STRVAL,
2283 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2284 { 4, 4, "upfwd", "ACS Upstream Forwarding", PRDV_STRVAL,
2285 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2286 { 5, 5, "p2pegctl", "ACS P2P Egress Control", PRDV_STRVAL,
2287 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2288 { 6, 6, "dtp2p", "ACS Direct Translated P2P", PRDV_STRVAL,
2289 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2290 { 7, 7, "enhcap", "ACS Enhanced Capability", PRDV_STRVAL,
2291 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2292 { 8, 15, "ecvsz", "Egress Control Vector Size", PRDV_HEX },
2293 { -1, -1, NULL }
2294 };
2295
2296 static const pcieadm_regdef_t pcieadm_regdef_acs_ctl[] = {
2297 { 0, 0, "srcvd", "ACS Source Validation", PRDV_STRVAL,
2298 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2299 { 1, 1, "tranblk", "ACS Transaction Blocking", PRDV_STRVAL,
2300 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2301 { 2, 2, "p2prr", "ACS P2P Request Redirect", PRDV_STRVAL,
2302 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2303 { 3, 3, "p2pcr", "ACS P2P Completion Redirect", PRDV_STRVAL,
2304 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2305 { 4, 4, "upfwd", "ACS Upstream Forwarding", PRDV_STRVAL,
2306 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2307 { 5, 5, "p2pegctl", "ACS P2P Egress Control", PRDV_STRVAL,
2308 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2309 { 6, 6, "dtp2p", "ACS Direct Translated P2P", PRDV_STRVAL,
2310 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2311 { 7, 7, "iorb", "ACS I/O Request Blocking", PRDV_STRVAL,
2312 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2313 { 8, 9, "dspmta", "ACS DSP Memory Target Access Control", PRDV_STRVAL,
2314 .prd_val = { .prdv_strval = { "Direct Request access",
2315 "Request blocking", "Request redirect" } } },
2316 { 10, 11, "uspmta", "ACS USP Memory Target Access Control", PRDV_STRVAL,
2317 .prd_val = { .prdv_strval = { "Direct Request access",
2318 "Request blocking", "Request redirect" } } },
2319 { -1, -1, NULL }
2320 };
2321
2322 static const pcieadm_cfgspace_print_t pcieadm_cap_acs[] = {
2323 { 0x0, 4, "caphdr", "Capability Header",
2324 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2325 { 0x4, 2, "cap", "ACS Capability",
2326 pcieadm_cfgspace_print_regdef, pcieadm_regdef_acs_cap },
2327 { 0x6, 2, "ctl", "ACS Control",
2328 pcieadm_cfgspace_print_regdef, pcieadm_regdef_acs_ctl },
2329 { 0x8, 4, "ecv", "Egress Control Vector", pcieadm_cfgspace_print_ecv },
2330 { -1, -1, NULL }
2331 };
2332
2333 /*
2334 * L1 PM Substates
2335 */
2336 static const pcieadm_regdef_t pcieadm_regdef_l1pm_cap[] = {
2337 { 0, 0, "pcil1.2", "PCI-PM L1.2", PRDV_STRVAL,
2338 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2339 { 1, 1, "pcil1.1", "PCI-PM L1.1", PRDV_STRVAL,
2340 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2341 { 2, 2, "aspml1.2", "ASPM L1.2", PRDV_STRVAL,
2342 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2343 { 3, 3, "aspml1.1", "ASPM L1.1", PRDV_STRVAL,
2344 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2345 { 4, 4, "l1pmsub", "L1 PM Substates", PRDV_STRVAL,
2346 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2347 { 5, 5, "linkact", "Link Activation", PRDV_STRVAL,
2348 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2349 { 8, 15, "pcmrt", "Port Common_Mode_Restore_Time", PRDV_HEX },
2350 { 16, 17, "poscale", "Port T_POWER_ON Scale", PRDV_STRVAL,
2351 .prd_val = { .prdv_strval = { "2 us", "10 us", "100 us" } } },
2352 { 19, 23, "portpo", "Port T_POWER_ON Value", PRDV_HEX },
2353 { -1, -1, NULL }
2354 };
2355
2356 static const pcieadm_regdef_t pcieadm_regdef_l1pm_ctl1[] = {
2357 { 0, 0, "pcil1.2", "PCI-PM L1.2", PRDV_STRVAL,
2358 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2359 { 1, 1, "pcil1.1", "PCI-PM L1.1", PRDV_STRVAL,
2360 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2361 { 2, 2, "aspml1.2", "ASPM L1.2", PRDV_STRVAL,
2362 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2363 { 3, 3, "aspml1.1", "ASPM L1.1", PRDV_STRVAL,
2364 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2365 { 4, 4, "laie", "Link Activation Interrupt Enable", PRDV_STRVAL,
2366 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2367 { 5, 5, "lactl", "Link Activation Control", PRDV_STRVAL,
2368 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2369 { 8, 15, "cmrt", "Common_Mode_Restore_Time", PRDV_HEX },
2370 { 16, 25, "ltrl1.2", "LTR L1.2 Threshold Value", PRDV_HEX },
2371 { 29, 31, "ltrl1.2s", "LTR L1.2 Threshold Scale", PRDV_STRVAL,
2372 .prd_val = { .prdv_strval = { "1 ns", "32 ns", "1024 ns",
2373 "32,768 ns", "1,048,576 ns", "33,554,432 ns" } } },
2374 { -1, -1, NULL }
2375 };
2376
2377 static const pcieadm_regdef_t pcieadm_regdef_l1pm_ctl2[] = {
2378 { 0, 1, "poscale", "T_POWER_ON Scale", PRDV_STRVAL,
2379 .prd_val = { .prdv_strval = { "2 us", "10 us", "100 us" } } },
2380 { 3, 7, "portpo", "T_POWER_ON Value", PRDV_HEX },
2381 { -1, -1, NULL }
2382 };
2383
2384 static const pcieadm_regdef_t pcieadm_regdef_l1pm_sts[] = {
2385 { 0, 0, "la", "Link Activation", PRDV_HEX },
2386 { -1, -1, NULL }
2387 };
2388
2389
2390 static const pcieadm_cfgspace_print_t pcieadm_cap_l1pm_v1[] = {
2391 { 0x0, 4, "caphdr", "Capability Header",
2392 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2393 { 0x4, 4, "caps", "L1 PM Substates Capabilities",
2394 pcieadm_cfgspace_print_regdef, pcieadm_regdef_l1pm_cap },
2395 { 0x8, 4, "ctl1", "L1 PM Substates Control 1",
2396 pcieadm_cfgspace_print_regdef, pcieadm_regdef_l1pm_ctl1 },
2397 { 0xc, 4, "ctl2", "L1 PM Substates Control 2",
2398 pcieadm_cfgspace_print_regdef, pcieadm_regdef_l1pm_ctl2 },
2399 { -1, -1, NULL }
2400 };
2401
2402 static const pcieadm_cfgspace_print_t pcieadm_cap_l1pm_v2[] = {
2403 { 0x0, 4, "caphdr", "Capability Header",
2404 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2405 { 0x4, 4, "caps", "L1 PM Substates Capabilities",
2406 pcieadm_cfgspace_print_regdef, pcieadm_regdef_l1pm_cap },
2407 { 0x8, 4, "ctl1", "L1 PM Substates Control 1",
2408 pcieadm_cfgspace_print_regdef, pcieadm_regdef_l1pm_ctl1 },
2409 { 0xc, 4, "ctl2", "L1 PM Substates Control 2",
2410 pcieadm_cfgspace_print_regdef, pcieadm_regdef_l1pm_ctl2 },
2411 { 0x10, 4, "sts", "L1 PM Substates Status",
2412 pcieadm_cfgspace_print_regdef, pcieadm_regdef_l1pm_sts },
2413 { -1, -1, NULL }
2414 };
2415
2416 /*
2417 * Latency Tolerance Reporting (LTR)
2418 */
2419 static const pcieadm_regdef_t pcieadm_regdef_ltr[] = {
2420 { 0, 9, "latval", "Latency Value", PRDV_HEX },
2421 { 10, 12, "latscale", "Latency Scale", PRDV_STRVAL,
2422 .prd_val = { .prdv_strval = { "1 ns", "32 ns", "1024 ns",
2423 "32,768 ns", "1,048,576 ns", "33,554,432 ns" } } },
2424 { -1, -1, NULL }
2425 };
2426
2427 static const pcieadm_cfgspace_print_t pcieadm_cap_ltr[] = {
2428 { 0x0, 4, "caphdr", "Capability Header",
2429 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2430 { 0x4, 2, "snoop", "Max Snoop Latency",
2431 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ltr },
2432 { 0x6, 2, "nosnoop", "Max No-Snoop Latency",
2433 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ltr },
2434 { -1, -1, NULL }
2435 };
2436
2437 /*
2438 * Alternative Routing ID
2439 */
2440 static const pcieadm_regdef_t pcieadm_regdef_ari_cap[] = {
2441 { 0, 0, "mfvcfg", "MFVC Function Groups", PRDV_STRVAL,
2442 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2443 { 1, 1, "acsfg", "ACS Function Groups", PRDV_STRVAL,
2444 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2445 { 8, 15, "nfunc", "Next Function Number", PRDV_HEX },
2446 { -1, -1, NULL }
2447 };
2448
2449 static const pcieadm_regdef_t pcieadm_regdef_ari_ctl[] = {
2450 { 0, 0, "mfvcfg", "MFVC Function Groups", PRDV_STRVAL,
2451 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2452 { 1, 1, "acsfg", "ACS Function Groups", PRDV_STRVAL,
2453 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2454 { 4, 6, "fgrp", "Function Group", PRDV_HEX },
2455 { -1, -1, NULL }
2456 };
2457
2458 static const pcieadm_cfgspace_print_t pcieadm_cap_ari[] = {
2459 { 0x0, 4, "caphdr", "Capability Header",
2460 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2461 { 0x4, 2, "cap", "ARI Capability",
2462 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ari_cap },
2463 { 0x6, 2, "ctl", "ARI Control",
2464 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ari_ctl },
2465 { -1, -1, NULL }
2466 };
2467
2468 /*
2469 * PASID
2470 */
2471 static const pcieadm_regdef_t pcieadm_regdef_pasid_cap[] = {
2472 { 1, 1, "exec", "Execution Permission", PRDV_STRVAL,
2473 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2474 { 2, 2, "priv", "Privileged Mode", PRDV_STRVAL,
2475 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2476 { 8, 12, "width", "Max PASID Width", PRDV_HEX },
2477 { -1, -1, NULL }
2478 };
2479
2480 static const pcieadm_regdef_t pcieadm_regdef_pasid_ctl[] = {
2481 { 0, 0, "pasid", "PASID", PRDV_STRVAL,
2482 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2483 { 1, 1, "exec", "Execution Permission", PRDV_STRVAL,
2484 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2485 { 2, 2, "priv", "Privileged Mode", PRDV_STRVAL,
2486 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2487 { -1, -1, NULL }
2488 };
2489
2490
2491 static const pcieadm_cfgspace_print_t pcieadm_cap_pasid[] = {
2492 { 0x0, 4, "caphdr", "Capability Header",
2493 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2494 { 0x4, 2, "cap", "PASID Capability",
2495 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pasid_cap },
2496 { 0x6, 2, "ctl", "PASID Control",
2497 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pasid_ctl },
2498 { -1, -1, NULL }
2499 };
2500
2501 /*
2502 * "Advanced Features"
2503 */
2504 static const pcieadm_regdef_t pcieadm_regdef_af_cap[] = {
2505 { 0, 0, "tp", "Transactions Pending", PRDV_STRVAL,
2506 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2507 { 1, 1, "flr", "Function Level Reset", PRDV_STRVAL,
2508 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2509 { -1, -1, NULL }
2510 };
2511
2512 static const pcieadm_regdef_t pcieadm_regdef_af_ctl[] = {
2513 { 0, 0, "flr", "Function Level Reset", PRDV_HEX },
2514 { -1, -1, NULL }
2515 };
2516
2517 static const pcieadm_regdef_t pcieadm_regdef_af_sts[] = {
2518 { 0, 0, "tp", "Transactions Pending", PRDV_STRVAL,
2519 .prd_val = { .prdv_strval = { "none pending", "pending" } } },
2520 { -1, -1, NULL }
2521 };
2522
2523 static const pcieadm_cfgspace_print_t pcieadm_cap_af[] = {
2524 { 0x2, 2, "cap", "AF Capabilities",
2525 pcieadm_cfgspace_print_regdef, pcieadm_regdef_af_cap },
2526 { 0x4, 1, "ctl", "AF Control",
2527 pcieadm_cfgspace_print_regdef, pcieadm_regdef_af_ctl },
2528 { 0x5, 1, "sts", "AF Status",
2529 pcieadm_cfgspace_print_regdef, pcieadm_regdef_af_sts },
2530 { -1, -1, NULL }
2531 };
2532
2533 /*
2534 * Multicast
2535 */
2536 static const pcieadm_regdef_t pcieadm_regdef_mcast_cap[] = {
2537 { 0, 5, "maxgrp", "Max Group", PRDV_HEX,
2538 .prd_val = { .prdv_hex = { 0, 1 } } },
2539 { 8, 13, "winsize", "Window Size (raw)", PRDV_HEX },
2540 { 15, 15, "ecrc", "ECRC Regeneration", PRDV_STRVAL,
2541 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2542 { -1, -1, NULL }
2543 };
2544
2545 static const pcieadm_regdef_t pcieadm_regdef_mcast_ctl[] = {
2546 { 0, 5, "numgrp", "Number of Groups", PRDV_HEX,
2547 .prd_val = { .prdv_hex = { 0, 1 } } },
2548 { 15, 15, "enable", "Enable", PRDV_STRVAL,
2549 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2550 { -1, -1, NULL }
2551 };
2552
2553 static const pcieadm_regdef_t pcieadm_regdef_mcast_base[] = {
2554 { 0, 5, "index", "Multicast Index Position", PRDV_HEX },
2555 { 12, 63, "addr", "Base Address", PRDV_HEX,
2556 .prd_val = { .prdv_hex = { 12 } } },
2557 { -1, -1, NULL }
2558 };
2559
2560 static const pcieadm_regdef_t pcieadm_regdef_mcast_overlay[] = {
2561 { 0, 5, "size", "Overlay Size (raw)", PRDV_HEX },
2562 { 6, 63, "addr", "Overlay Base Address", PRDV_HEX,
2563 .prd_val = { .prdv_hex = { 6 } } },
2564 { -1, -1, NULL }
2565 };
2566
2567 static const pcieadm_cfgspace_print_t pcieadm_cap_mcast[] = {
2568 { 0x0, 4, "caphdr", "Capability Header",
2569 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2570 { 0x4, 2, "cap", "Multicast Capability",
2571 pcieadm_cfgspace_print_regdef, pcieadm_regdef_mcast_cap },
2572 { 0x6, 2, "ctl", "Multicast Control",
2573 pcieadm_cfgspace_print_regdef, pcieadm_regdef_mcast_ctl },
2574 { 0x8, 8, "base", "Multicast Base Address",
2575 pcieadm_cfgspace_print_regdef, pcieadm_regdef_mcast_base },
2576 { 0x10, 8, "rx", "Multicast Receive", pcieadm_cfgspace_print_hex },
2577 { 0x18, 8, "block", "Multicast Block All", pcieadm_cfgspace_print_hex },
2578 { 0x20, 8, "blockun", "Multicast Block Untranslated",
2579 pcieadm_cfgspace_print_hex },
2580 { 0x28, 8, "overlay", "Multicast Overlay BAR",
2581 pcieadm_cfgspace_print_regdef, pcieadm_regdef_mcast_overlay },
2582 { -1, -1, NULL }
2583 };
2584
2585 /*
2586 * Various vendor extensions
2587 */
2588 static const pcieadm_regdef_t pcieadm_regdef_vsec[] = {
2589 { 0, 15, "id", "ID", PRDV_HEX },
2590 { 16, 19, "rev", "Revision", PRDV_HEX },
2591 { 20, 31, "len", "Length", PRDV_HEX },
2592 { -1, -1, NULL }
2593 };
2594
2595 static const pcieadm_cfgspace_print_t pcieadm_cap_vs[] = {
2596 { 0x2, 2, "length", "Length", pcieadm_cfgspace_print_hex },
2597 { -1, -1, NULL }
2598 };
2599
2600 static const pcieadm_cfgspace_print_t pcieadm_cap_vsec[] = {
2601 { 0x0, 4, "caphdr", "Capability Header",
2602 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2603 { 0x4, 4, "header", "Vendor-Specific Header",
2604 pcieadm_cfgspace_print_regdef, pcieadm_regdef_vsec },
2605 { -1, -1, NULL }
2606 };
2607
2608 /*
2609 * Data Link Feature
2610 */
2611 static const pcieadm_regdef_t pcieadm_regdef_dlf_cap[] = {
2612 { 0, 0, "lsfc", "Local Scaled Flow Control", PRDV_STRVAL,
2613 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2614 { 31, 31, "dlex", "Data Link Exchange", PRDV_STRVAL,
2615 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2616 { -1, -1, NULL }
2617 };
2618
2619 static const pcieadm_regdef_t pcieadm_regdef_dlf_sts[] = {
2620 { 0, 0, "rsfc", "Remote Scaled Flow Control", PRDV_STRVAL,
2621 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2622 { 31, 31, "valid", "Remote Data Link Feature Valid", PRDV_STRVAL,
2623 .prd_val = { .prdv_strval = { "invalid", "valid" } } },
2624 { -1, -1, NULL }
2625 };
2626
2627 static const pcieadm_cfgspace_print_t pcieadm_cap_dlf[] = {
2628 { 0x0, 4, "caphdr", "Capability Header",
2629 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2630 { 0x4, 4, "cap", "Data Link Feature Capabilities",
2631 pcieadm_cfgspace_print_regdef, pcieadm_regdef_dlf_cap },
2632 { 0x8, 4, "sts", "Data Link Feature Status",
2633 pcieadm_cfgspace_print_regdef, pcieadm_regdef_dlf_sts },
2634 { -1, -1, NULL }
2635 };
2636
2637 /*
2638 * 16.0 GT/s cap
2639 */
2640 static const pcieadm_regdef_t pcieadm_regdef_16g_cap[] = {
2641 { -1, -1, NULL }
2642 };
2643
2644 static const pcieadm_regdef_t pcieadm_regdef_16g_ctl[] = {
2645 { -1, -1, NULL }
2646 };
2647
2648 static const pcieadm_regdef_t pcieadm_regdef_16g_sts[] = {
2649 { 0, 0, "eqcomp", "Equalization 16.0 GT/s Complete", PRDV_STRVAL,
2650 .prd_val = { .prdv_strval = { "incomplete", "complete" } } },
2651 { 1, 1, "eqp1", "Equalization 16.0 GT/s Phase 1", PRDV_STRVAL,
2652 .prd_val = { .prdv_strval = { "incomplete", "complete" } } },
2653 { 2, 2, "eqp2", "Equalization 16.0 GT/s Phase 2", PRDV_STRVAL,
2654 .prd_val = { .prdv_strval = { "incomplete", "complete" } } },
2655 { 3, 3, "eqp3", "Equalization 16.0 GT/s Phase 3", PRDV_STRVAL,
2656 .prd_val = { .prdv_strval = { "incomplete", "complete" } } },
2657 { 4, 4, "req", "Link Equalization Request 16.0 GT/s", PRDV_HEX },
2658 { -1, -1, NULL }
2659 };
2660
2661 static const pcieadm_regdef_t pcieadm_regdef_16g_eq[] = {
2662 { 0, 3, "dstxpre", "Downstream Port 16.0 GT/s Transmitter Preset",
2663 PRDV_HEX },
2664 { 4, 7, "ustxpre", "Upstream Port 16.0 GT/s Transmitter Preset",
2665 PRDV_HEX },
2666 { -1, -1, NULL }
2667 };
2668
2669 static void
pcieadm_cfgspace_print_16geq(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)2670 pcieadm_cfgspace_print_16geq(pcieadm_cfgspace_walk_t *walkp,
2671 const pcieadm_cfgspace_print_t *print, const void *arg)
2672 {
2673 if (walkp->pcw_nlanes == 0) {
2674 warnx("failed to capture lane count, but somehow have "
2675 "Physical Layer 16.0 GT/s cap");
2676 return;
2677 }
2678
2679 for (uint_t i = 0; i < walkp->pcw_nlanes; i++) {
2680 char eqshort[32], eqhuman[128];
2681 pcieadm_cfgspace_print_t p;
2682
2683 (void) snprintf(eqshort, sizeof (eqshort), "lane%u", i);
2684 (void) snprintf(eqhuman, sizeof (eqhuman), "Lane %u EQ Control",
2685 i);
2686 p.pcp_off = print->pcp_off + i * 1;
2687 p.pcp_len = 1;
2688 p.pcp_short = eqshort;
2689 p.pcp_human = eqhuman;
2690 p.pcp_print = pcieadm_cfgspace_print_regdef;
2691 p.pcp_arg = pcieadm_regdef_16g_eq;
2692
2693 p.pcp_print(walkp, &p, p.pcp_arg);
2694 }
2695 }
2696
2697 static const pcieadm_cfgspace_print_t pcieadm_cap_16g[] = {
2698 { 0x0, 4, "caphdr", "Capability Header",
2699 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2700 { 0x4, 4, "cap", "16.0 GT/s Capabilities",
2701 pcieadm_cfgspace_print_regdef, pcieadm_regdef_16g_cap },
2702 { 0x8, 4, "ctl", "16.0 GT/s Control",
2703 pcieadm_cfgspace_print_regdef, pcieadm_regdef_16g_ctl },
2704 { 0xc, 4, "sts", "16.0 GT/s Status",
2705 pcieadm_cfgspace_print_regdef, pcieadm_regdef_16g_sts },
2706 { 0x10, 4, "ldpmis", "16.0 GT/s Local Data Parity Mismatch",
2707 pcieadm_cfgspace_print_hex },
2708 { 0x14, 4, "frpmis", "16.0 GT/s First Retimer Data Parity Mismatch",
2709 pcieadm_cfgspace_print_hex },
2710 { 0x18, 4, "srpmis", "16.0 GT/s Second Retimer Data Parity Mismatch",
2711 pcieadm_cfgspace_print_hex },
2712 { 0x1c, 4, "rsvd", "16.0 GT/s Second Retimer Data Parity Mismatch",
2713 pcieadm_cfgspace_print_hex },
2714 { 0x20, 1, "eqctl", "16.0 GT/s EQ Control",
2715 pcieadm_cfgspace_print_16geq },
2716 { -1, -1, NULL }
2717 };
2718
2719 /*
2720 * Receiver Margining
2721 */
2722 static const pcieadm_regdef_t pcieadm_regdef_margin_cap[] = {
2723 { 0, 0, "sw", "Margining uses Driver Software", PRDV_STRVAL,
2724 .prd_val = { .prdv_strval = { "no", "yes" } } },
2725 { -1, -1, NULL }
2726 };
2727
2728 static const pcieadm_regdef_t pcieadm_regdef_margin_sts[] = {
2729 { 0, 0, "ready", "Margining Ready", PRDV_STRVAL,
2730 .prd_val = { .prdv_strval = { "no", "yes" } } },
2731 { 1, 1, "sw", "Margining Software Ready", PRDV_STRVAL,
2732 .prd_val = { .prdv_strval = { "no", "yes" } } },
2733 { -1, -1, NULL }
2734 };
2735
2736 static const pcieadm_regdef_t pcieadm_regdef_margin_lane[] = {
2737 { 0, 2, "rxno", "Receiver Number", PRDV_HEX },
2738 { 3, 5, "type", "Margin Type", PRDV_HEX },
2739 { 6, 6, "model", "Usage Model", PRDV_HEX },
2740 { 8, 15, "payload", "Margin Payload", PRDV_HEX },
2741 { -1, -1, NULL }
2742 };
2743
2744 static void
pcieadm_cfgspace_print_margin(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)2745 pcieadm_cfgspace_print_margin(pcieadm_cfgspace_walk_t *walkp,
2746 const pcieadm_cfgspace_print_t *print, const void *arg)
2747 {
2748 if (walkp->pcw_nlanes == 0) {
2749 warnx("failed to capture lane count, but somehow have "
2750 "lane margining capability");
2751 return;
2752 }
2753
2754 for (uint_t i = 0; i < walkp->pcw_nlanes; i++) {
2755 char mshort[32], mhuman[128];
2756 pcieadm_cfgspace_print_t p;
2757
2758 (void) snprintf(mshort, sizeof (mshort), "lane%uctl", i);
2759 (void) snprintf(mhuman, sizeof (mhuman), "Lane %u Margining "
2760 "Control", i);
2761 p.pcp_off = print->pcp_off + i * 4;
2762 p.pcp_len = 2;
2763 p.pcp_short = mshort;
2764 p.pcp_human = mhuman;
2765 p.pcp_print = pcieadm_cfgspace_print_regdef;
2766 p.pcp_arg = pcieadm_regdef_margin_lane;
2767
2768 p.pcp_print(walkp, &p, p.pcp_arg);
2769
2770 (void) snprintf(mshort, sizeof (mshort), "lane%usts", i);
2771 (void) snprintf(mhuman, sizeof (mhuman), "Lane %u Margining "
2772 "Status", i);
2773 p.pcp_off = print->pcp_off + 2 + i * 4;
2774 p.pcp_len = 2;
2775 p.pcp_short = mshort;
2776 p.pcp_human = mhuman;
2777 p.pcp_print = pcieadm_cfgspace_print_regdef;
2778 p.pcp_arg = pcieadm_regdef_margin_lane;
2779
2780 p.pcp_print(walkp, &p, p.pcp_arg);
2781 }
2782 }
2783
2784 static const pcieadm_cfgspace_print_t pcieadm_cap_margin[] = {
2785 { 0x0, 4, "caphdr", "Capability Header",
2786 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2787 { 0x4, 2, "cap", "Margining Port Capabilities",
2788 pcieadm_cfgspace_print_regdef, pcieadm_regdef_margin_cap },
2789 { 0x6, 2, "sts", "Margining Port Status",
2790 pcieadm_cfgspace_print_regdef, pcieadm_regdef_margin_sts },
2791 { 0x8, 4, "lane", "Margining Lane", pcieadm_cfgspace_print_margin },
2792 { -1, -1, NULL }
2793 };
2794
2795 /*
2796 * Serial Number Capability
2797 */
2798 static void
pcieadm_cfgspace_print_sn(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)2799 pcieadm_cfgspace_print_sn(pcieadm_cfgspace_walk_t *walkp,
2800 const pcieadm_cfgspace_print_t *print, const void *arg)
2801 {
2802 char sn[64];
2803 uint16_t off = walkp->pcw_capoff + print->pcp_off;
2804
2805 (void) snprintf(sn, sizeof (sn),
2806 "%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x",
2807 walkp->pcw_data->pcb_u8[off + 7], walkp->pcw_data->pcb_u8[off + 6],
2808 walkp->pcw_data->pcb_u8[off + 5], walkp->pcw_data->pcb_u8[off + 4],
2809 walkp->pcw_data->pcb_u8[off + 3], walkp->pcw_data->pcb_u8[off + 2],
2810 walkp->pcw_data->pcb_u8[off + 1], walkp->pcw_data->pcb_u8[off]);
2811
2812 pcieadm_cfgspace_puts(walkp, print, sn);
2813 }
2814
2815 static const pcieadm_cfgspace_print_t pcieadm_cap_sn[] = {
2816 { 0x0, 4, "caphdr", "Capability Header",
2817 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2818 { 0x4, 8, "sn", "Serial Number", pcieadm_cfgspace_print_sn },
2819 { -1, -1, NULL }
2820 };
2821
2822 /*
2823 * TLP Processing Hints (TPH)
2824 */
2825 static const pcieadm_regdef_t pcieadm_regdef_tph_cap[] = {
2826 { 0, 0, "nost", "No ST Mode", PRDV_STRVAL,
2827 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2828 { 1, 1, "ivec", "Interrupt Vector Mode", PRDV_STRVAL,
2829 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2830 { 2, 2, "dev", "Device Specific Mode", PRDV_STRVAL,
2831 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2832 { 8, 8, "exttph", "Extended TPH Requester", PRDV_STRVAL,
2833 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2834 { 9, 10, "loc", "ST Table Location", PRDV_STRVAL,
2835 .prd_val = { .prdv_strval = { "Not Present",
2836 "In Capability Structure", "MSI-X" } } },
2837 { 16, 26, "size", "ST Table Size", PRDV_HEX, { .prdv_hex = { 0, 1 } } },
2838 { -1, -1, NULL }
2839 };
2840
2841 static const pcieadm_regdef_t pcieadm_regdef_tph_ctl[] = {
2842 { 0, 2, "mode", "ST Mode Select", PRDV_STRVAL,
2843 .prd_val = { .prdv_strval = { "No ST", "Interrupt Vector",
2844 "Device Specific" } } },
2845 { 8, 9, "en", "TPH Requester", PRDV_STRVAL,
2846 .prd_val = { .prdv_strval = { "Not Permitted", "TPH", NULL,
2847 "TPH and Extended TPH" } } },
2848 { -1, -1, NULL }
2849 };
2850
2851 static const pcieadm_regdef_t pcieadm_regdef_tph_st[] = {
2852 { 0, 7, "low", "ST Lower", PRDV_HEX },
2853 { 8, 15, "up", "ST Upper", PRDV_HEX },
2854 { -1, -1, NULL }
2855 };
2856
2857 /*
2858 * The TPH ST table is only conditionally present in the capability. So we need
2859 * to read the TPH capability register and then check if the table location and
2860 * size are set here.
2861 */
2862 static void
pcieadm_cfgspace_print_tphst(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)2863 pcieadm_cfgspace_print_tphst(pcieadm_cfgspace_walk_t *walkp,
2864 const pcieadm_cfgspace_print_t *print, const void *arg)
2865 {
2866 uint_t nents;
2867 uint32_t tphcap = pcieadm_cfgspace_getcap32(walkp, 4);
2868
2869 if (bitx32(tphcap, 10, 9) != 1) {
2870 return;
2871 }
2872
2873 nents = bitx32(tphcap, 26, 16) + 1;
2874 for (uint_t i = 0; i < nents; i++) {
2875 char tshort[32], thuman[128];
2876 pcieadm_cfgspace_print_t p;
2877
2878 (void) snprintf(tshort, sizeof (tshort), "st%u", i);
2879 (void) snprintf(thuman, sizeof (thuman), "ST Table %u",
2880 i);
2881 p.pcp_off = print->pcp_off + i * 2;
2882 p.pcp_len = 2;
2883 p.pcp_short = tshort;
2884 p.pcp_human = thuman;
2885 p.pcp_print = pcieadm_cfgspace_print_regdef;
2886 p.pcp_arg = pcieadm_regdef_tph_st;
2887
2888 p.pcp_print(walkp, &p, p.pcp_arg);
2889 }
2890 }
2891
2892 static const pcieadm_cfgspace_print_t pcieadm_cap_tph[] = {
2893 { 0x0, 4, "caphdr", "Capability Header",
2894 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2895 { 0x4, 4, "cap", "TPH Requester Capability",
2896 pcieadm_cfgspace_print_regdef, pcieadm_regdef_tph_cap },
2897 { 0x8, 4, "ctl", "TPH Requester Control",
2898 pcieadm_cfgspace_print_regdef, pcieadm_regdef_tph_ctl },
2899 { 0xc, 2, "table", "ST Table", pcieadm_cfgspace_print_tphst },
2900 { -1, -1, NULL }
2901 };
2902
2903 /*
2904 * SR-IOV
2905 */
2906 static const pcieadm_regdef_t pcieadm_regdef_sriov_cap[] = {
2907 { 0, 0, "migration", "Migration", PRDV_STRVAL,
2908 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2909 { 1, 1, "ari", "ARI Capable Hierarchy Preserved", PRDV_STRVAL,
2910 .prd_val = { .prdv_strval = { "unpreserved", "preserved" } } },
2911 { 2, 2, "vf10b", "VF 10-bit Tag Requester", PRDV_STRVAL,
2912 .prd_val = { .prdv_strval = { "unpreserved", "preserved" } } },
2913 { 21, 31, "inum", "VF Migration Interrupt Message Number", PRDV_HEX },
2914 { -1, -1, NULL }
2915 };
2916
2917 static const pcieadm_regdef_t pcieadm_regdef_sriov_ctl[] = {
2918 { 0, 0, "vf", "VF", PRDV_STRVAL,
2919 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2920 { 1, 1, "vfm", "VF Migration", PRDV_STRVAL,
2921 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2922 { 2, 2, "vfmi", "VF Migration Interrupt", PRDV_STRVAL,
2923 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2924 { 3, 3, "ari", "ARI Capable Hierarchy", PRDV_STRVAL,
2925 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2926 { 4, 4, "vf10b", "VF 10-bit Tag Requester", PRDV_STRVAL,
2927 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2928 { -1, -1, NULL }
2929 };
2930
2931 static const pcieadm_regdef_t pcieadm_regdef_sriov_sts[] = {
2932 { 0, 0, "vfm", "VF Migration", PRDV_STRVAL,
2933 .prd_val = { .prdv_strval = { "none", "requested" } } },
2934 { -1, -1, NULL }
2935 };
2936
2937 static const pcieadm_regdef_t pcieadm_regdef_sriov_pgsup[] = {
2938 { 0, 31, "pgsz", "Supported Page Sizes", PRDV_BITFIELD,
2939 .prd_val = { .prdv_strval = { "4 KB", "8 KB", "16 KB", "32 KB",
2940 "64 KB", "128 KB", "256 KB", "512 KB", "1 MB", "2 MB", "4 MB",
2941 "8 MB", "16 MB", "32 MB", "64 MB", "128 MB", "256 MB", "512 MB",
2942 "1 GB", "2 GB", "4 GB", "8 GB", "16 GB", "32 GB", "64 GB",
2943 "128 GB", "256 GB", "512 GB", "1 TB", "2 TB", "4 TB", "8 TB" } } },
2944 { -1, -1, NULL }
2945 };
2946
2947 static const pcieadm_regdef_t pcieadm_regdef_sriov_pgen[] = {
2948 { 0, 31, "pgsz", "System Page Sizes", PRDV_BITFIELD,
2949 .prd_val = { .prdv_strval = { "4 KB", "8 KB", "16 KB", "32 KB",
2950 "64 KB", "128 KB", "256 KB", "512 KB", "1 MB", "2 MB", "4 MB",
2951 "8 MB", "16 MB", "32 MB", "64 MB", "128 MB", "256 MB", "512 MB",
2952 "1 GB", "2 GB", "4 GB", "8 GB", "16 GB", "32 GB", "64 GB",
2953 "128 GB", "256 GB", "512 GB", "1 TB", "2 TB", "4 TB", "8 TB" } } },
2954 { -1, -1, NULL }
2955 };
2956
2957 static const pcieadm_regdef_t pcieadm_regdef_sriov_mig[] = {
2958 { 0, 2, "bir", "VF Migration State BIR", PRDV_STRVAL,
2959 .prd_val = { .prdv_strval = { "BAR 0", "BAR 1", "BAR 2", "BAR 3",
2960 "BAR 4", "BAR 5" } } },
2961 { 3, 31, "offset", "VF Migration State Offset", PRDV_HEX,
2962 .prd_val = { .prdv_hex = { 3 } } },
2963 { -1, -1, NULL }
2964 };
2965
2966 static const pcieadm_cfgspace_print_t pcieadm_cap_sriov[] = {
2967 { 0x0, 4, "caphdr", "Capability Header",
2968 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2969 { 0x4, 4, "cap", "SR-IOV Capabilities",
2970 pcieadm_cfgspace_print_regdef, pcieadm_regdef_sriov_cap },
2971 { 0x8, 2, "ctl", "SR-IOV Control",
2972 pcieadm_cfgspace_print_regdef, pcieadm_regdef_sriov_ctl },
2973 { 0xa, 2, "sts", "SR-IOV Status",
2974 pcieadm_cfgspace_print_regdef, pcieadm_regdef_sriov_sts },
2975 { 0xc, 2, "initvfs", "Initial VFs", pcieadm_cfgspace_print_hex },
2976 { 0xe, 2, "totvfs", "Total VFs", pcieadm_cfgspace_print_hex },
2977 { 0x10, 2, "numvfs", "Number VFs", pcieadm_cfgspace_print_hex },
2978 { 0x12, 1, "dep", "Function Dependency Link",
2979 pcieadm_cfgspace_print_hex },
2980 { 0x14, 2, "offset", "First VF Offset", pcieadm_cfgspace_print_hex },
2981 { 0x16, 2, "stride", "VF Stride", pcieadm_cfgspace_print_hex },
2982 { 0x1a, 2, "devid", "VF Device ID", pcieadm_cfgspace_print_hex },
2983 { 0x1c, 4, "pgsz", "Supported Page Sizes",
2984 pcieadm_cfgspace_print_regdef, pcieadm_regdef_sriov_pgsup },
2985 { 0x20, 4, "pgsz", "System Page Sizes",
2986 pcieadm_cfgspace_print_regdef, pcieadm_regdef_sriov_pgen },
2987 { 0x24, 24, "vfbar", "Virtual Base Address Register",
2988 pcieadm_cfgspace_print_bars },
2989 { 0x3c, 4, "migration", "VF Migration State Array",
2990 pcieadm_cfgspace_print_regdef, pcieadm_regdef_sriov_mig },
2991 { -1, -1, NULL }
2992 };
2993
2994 /*
2995 * PCI-X
2996 */
2997 static const pcieadm_regdef_t pcieadm_regdef_pcix_dev_ctl[] = {
2998 { 0, 0, "dper", "Data Parity Error Recovery", PRDV_STRVAL,
2999 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3000 { 1, 1, "ro", "Relaxed Ordering", PRDV_STRVAL,
3001 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3002 { 2, 3, "maxread", "Maximum Memory Read Byte Count", PRDV_STRVAL,
3003 .prd_val = { .prdv_strval = { "512 bytes", "1024 bytes",
3004 "2048 bytes", "4096 bytes" } } },
3005 { 4, 6, "maxsplit", "Maximum Outstanding Split Transactions",
3006 PRDV_STRVAL, .prd_val = { .prdv_strval = { "1", "2", "3", "4", "8",
3007 "12", "16", "32" } } },
3008 { -1, -1, NULL }
3009 };
3010
3011 static const pcieadm_regdef_t pcieadm_regdef_pcix_dev_sts[] = {
3012 { 0, 2, "func", "Function Number", PRDV_HEX },
3013 { 3, 7, "dev", "Device Number", PRDV_HEX },
3014 { 8, 15, "bus", "Bus Number", PRDV_HEX },
3015 { 16, 16, "64bit", "64-bit Device", PRDV_STRVAL,
3016 .prd_val = { .prdv_strval = { "unsupported (32-bit)",
3017 "supported" } } },
3018 { 17, 17, "133mhz", "133 MHz Capable", PRDV_STRVAL,
3019 .prd_val = { .prdv_strval = { "unsupported (66 MHz)",
3020 "supported" } } },
3021 { 18, 18, "spcodis", "Split Completion Discarded", PRDV_STRVAL,
3022 .prd_val = { .prdv_strval = { "no", "yes" } } },
3023 { 19, 19, "unspco", "Unexpected Split Completion", PRDV_STRVAL,
3024 .prd_val = { .prdv_strval = { "no", "yes" } } },
3025 { 20, 20, "complex", "Device Complexity", PRDV_STRVAL,
3026 .prd_val = { .prdv_strval = { "simple", "bridge" } } },
3027 { 21, 22, "maxread", "Designed Maximum Memory Read Byte Count",
3028 PRDV_STRVAL, .prd_val = { .prdv_strval = { "512 bytes",
3029 "1024 bytes", "2048 bytes", "4096 bytes" } } },
3030 { 23, 25, "maxsplit", "Designed Maximum Outstanding Split Transactions",
3031 PRDV_STRVAL, .prd_val = { .prdv_strval = { "1", "2", "3", "4", "8",
3032 "12", "16", "32" } } },
3033 { 26, 28, "maxcread", "Designed Maximum Cumulative Read Size",
3034 PRDV_STRVAL, .prd_val = { .prdv_strval = { "8/1KB", "16/2KB",
3035 "32/4KB", "64/8KB", "128/16KB", "256/32KB", "512/64KB",
3036 "1024/128KB" } } },
3037 { 29, 29, "rxspcoer", "Received Split Completion Error Message",
3038 PRDV_STRVAL, .prd_val = { .prdv_strval = { "no", "yes" } } },
3039 { -1, -1, NULL }
3040 };
3041
3042 static const pcieadm_regdef_t pcieadm_regdef_pcix_sec_sts[] = {
3043 { 0, 0, "64bit", "64-bit Device", PRDV_STRVAL,
3044 .prd_val = { .prdv_strval = { "unsupported (32-bit)",
3045 "supported" } } },
3046 { 1, 1, "133mhz", "133 MHz Capable", PRDV_STRVAL,
3047 .prd_val = { .prdv_strval = { "unsupported (66 MHz)",
3048 "supported" } } },
3049 { 2, 2, "spcodis", "Split Completion Discarded", PRDV_STRVAL,
3050 .prd_val = { .prdv_strval = { "no", "yes" } } },
3051 { 3, 3, "unspco", "Unexpected Split Completion", PRDV_STRVAL,
3052 .prd_val = { .prdv_strval = { "no", "yes" } } },
3053 { 4, 4, "spcoor", "Split Completion Overrun", PRDV_STRVAL,
3054 .prd_val = { .prdv_strval = { "no", "yes" } } },
3055 { 5, 5, "sprde", "Split Request Delayed", PRDV_STRVAL,
3056 .prd_val = { .prdv_strval = { "no", "yes" } } },
3057 { 6, 8, "freq", "Secondary Clock Frequency", PRDV_STRVAL,
3058 .prd_val = { .prdv_strval = { "conventional", "66 MHz", "100 Mhz",
3059 "133 MHz" } } },
3060 { -1, -1, NULL }
3061 };
3062
3063 static const pcieadm_regdef_t pcieadm_regdef_pcix_bridge_sts[] = {
3064 { 0, 2, "func", "Function Number", PRDV_HEX },
3065 { 3, 7, "dev", "Device Number", PRDV_HEX },
3066 { 8, 15, "bus", "Bus Number", PRDV_HEX },
3067 { 16, 16, "64bit", "64-bit Device", PRDV_STRVAL,
3068 .prd_val = { .prdv_strval = { "unsupported (32-bit)",
3069 "supported" } } },
3070 { 17, 17, "133mhz", "133 MHz Capable", PRDV_STRVAL,
3071 .prd_val = { .prdv_strval = { "unsupported (66 MHz)",
3072 "supported" } } },
3073 { 18, 18, "spcodis", "Split Completion Discarded", PRDV_STRVAL,
3074 .prd_val = { .prdv_strval = { "no", "yes" } } },
3075 { 19, 19, "unspco", "Unexpected Split Completion", PRDV_STRVAL,
3076 .prd_val = { .prdv_strval = { "no", "yes" } } },
3077 { 20, 20, "spcoor", "Split Completion Overrun", PRDV_STRVAL,
3078 .prd_val = { .prdv_strval = { "no", "yes" } } },
3079 { 21, 21, "sprde", "Split Request Delayed", PRDV_STRVAL,
3080 .prd_val = { .prdv_strval = { "no", "yes" } } },
3081 { -1, -1, NULL }
3082 };
3083
3084 static const pcieadm_regdef_t pcieadm_regdef_pcix_bridge_split[] = {
3085 { 0, 15, "cap", "Split Transaction Capacity", PRDV_HEX },
3086 { 16, 31, "limit", "Split Transaction Commitment Limit", PRDV_HEX },
3087 { -1, -1, NULL }
3088 };
3089
3090 static const pcieadm_cfgspace_print_t pcieadm_cap_pcix_dev[] = {
3091 { 0x2, 2, "ctl", "PCI-X Command",
3092 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcix_dev_ctl },
3093 { 0x4, 4, "sts", "PCI-X Status",
3094 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcix_dev_sts },
3095 { -1, -1, NULL }
3096 };
3097
3098 static const pcieadm_cfgspace_print_t pcieadm_cap_pcix_bridge[] = {
3099 { 0x2, 2, "secsts", "PCI-X Secondary Status",
3100 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcix_sec_sts },
3101 { 0x4, 4, "sts", "PCI-X Bridge Status",
3102 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcix_bridge_sts },
3103 { 0x8, 4, "ussplit", "Upstream Split Transaction",
3104 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcix_bridge_split },
3105 { 0x8, 4, "dssplit", "Downstream Split Transaction",
3106 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcix_bridge_split },
3107 { -1, -1, NULL }
3108 };
3109
3110 /*
3111 * Dynamic Power Allocation
3112 */
3113 static const pcieadm_regdef_t pcieadm_regdef_dpa_cap[] = {
3114 { 0, 4, "substates", "Substate Max", PRDV_HEX,
3115 { .prdv_hex = { 0, 1 } } },
3116 { 8, 9, "tlu", "Transition Latency Unit", PRDV_STRVAL,
3117 .prd_val = { .prdv_strval = { "1 ms", "10 ms", "100 ms" } } },
3118 { 12, 13, "pas", "Power Allocation Scale", PRDV_STRVAL,
3119 .prd_val = { .prdv_strval = { "10.0x", "1.0x", "0.1x",
3120 "0.01x" } } },
3121 { 16, 23, "tlv0", "Transition Latency Value 0", PRDV_HEX },
3122 { 24, 31, "tlv0", "Transition Latency Value 1", PRDV_HEX },
3123 { -1, -1, NULL }
3124 };
3125
3126 static const pcieadm_regdef_t pcieadm_regdef_dpa_sts[] = {
3127 { 0, 4, "substate", "Substate Status", PRDV_HEX },
3128 { 8, 8, "ctlen", "Substate Control Enabled", PRDV_STRVAL,
3129 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3130 { -1, -1, NULL }
3131 };
3132
3133 static const pcieadm_regdef_t pcieadm_regdef_dpa_ctl[] = {
3134 { 0, 4, "substate", "Substate Control", PRDV_HEX },
3135 { -1, -1, NULL }
3136 };
3137
3138 static const pcieadm_cfgspace_print_t pcieadm_cap_dpa[] = {
3139 { 0x0, 4, "caphdr", "Capability Header",
3140 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
3141 { 0x4, 4, "cap", "DPA Capability",
3142 pcieadm_cfgspace_print_regdef, pcieadm_regdef_dpa_cap },
3143 { 0x8, 4, "lat", "DPA Latency Indicator", pcieadm_cfgspace_print_hex },
3144 { 0xc, 2, "sts", "DPA Status",
3145 pcieadm_cfgspace_print_regdef, pcieadm_regdef_dpa_sts },
3146 { 0xe, 2, "sts", "DPA Control",
3147 pcieadm_cfgspace_print_regdef, pcieadm_regdef_dpa_ctl },
3148 { 0x10, 1, "paa", "DPA Power Allocation Array",
3149 pcieadm_cfgspace_print_dpa_paa },
3150 { -1, -1, NULL }
3151 };
3152
3153 /*
3154 * Power Budgeting
3155 */
3156 static const pcieadm_regdef_t pcieadm_regdef_powbudg_data[] = {
3157 { 0, 7, "base", "Base Power", PRDV_HEX },
3158 { 8, 9, "scale", "Data Scale", PRDV_STRVAL,
3159 .prd_val = { .prdv_strval = { "1.0x", "0.1x", "0.01x",
3160 "0.001x" } } },
3161 { 10, 12, "pmsub", "PM Substate", PRDV_STRVAL,
3162 .prd_val = { .prdv_strval = { "Default", "Device Specific",
3163 "Device Specific", "Device Specific", "Device Specific",
3164 "Device Specific", "Device Specific", "Device Specific" } } },
3165 { 13, 14, "pmstate", "PM State", PRDV_STRVAL,
3166 .prd_val = { .prdv_strval = { "D0", "D1", "D2", "D3" } } },
3167 { 15, 17, "type", "Type", PRDV_STRVAL,
3168 .prd_val = { .prdv_strval = { "PME Aux", "Axiliary", "Idle",
3169 "Sustained", "Sustained - EPRS", "Maximum - EPRS", NULL,
3170 "Maximum" } } },
3171 { 18, 20, "rail", "Power Rail", PRDV_STRVAL,
3172 .prd_val = { .prdv_strval = { "Power (12V)", "Power (3.3V)",
3173 "Power (1.5V or 1.8V)", NULL, NULL, NULL, NULL, "Thermal" } } },
3174 { -1, -1, NULL }
3175 };
3176
3177 static const pcieadm_regdef_t pcieadm_regdef_powbudg_cap[] = {
3178 { 0, 0, "sa", "System Allocated", PRDV_STRVAL,
3179 .prd_val = { .prdv_strval = { "no", "yes" } } },
3180 { -1, -1, NULL }
3181 };
3182
3183
3184 static const pcieadm_cfgspace_print_t pcieadm_cap_powbudg[] = {
3185 { 0x0, 4, "caphdr", "Capability Header",
3186 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
3187 { 0x4, 1, "sel", "Data Select", pcieadm_cfgspace_print_hex },
3188 { 0x8, 4, "data", "Data Regiser", pcieadm_cfgspace_print_regdef,
3189 pcieadm_regdef_powbudg_data },
3190 { 0xc, 0x1, "cap", "Power Budget Capability",
3191 pcieadm_cfgspace_print_regdef, pcieadm_regdef_powbudg_cap },
3192 { -1, -1, NULL }
3193 };
3194
3195 /*
3196 * Precision Time Management
3197 */
3198 static const pcieadm_regdef_t pcieadm_regdef_ptm_cap[] = {
3199 { 0, 0, "req", "PTM Requester", PRDV_STRVAL,
3200 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3201 { 1, 1, "resp", "PTM Responder", PRDV_STRVAL,
3202 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3203 { 2, 2, "root", "PTM Root", PRDV_STRVAL,
3204 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3205 { 3, 3, "eptm", "ePTM", PRDV_STRVAL,
3206 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3207 { 8, 15, "gran", "Local Clock Granularity", PRDV_HEX },
3208 { -1, -1, NULL }
3209 };
3210
3211 static const pcieadm_regdef_t pcieadm_regdef_ptm_ctl[] = {
3212 { 0, 0, "en", "PTM Enable", PRDV_STRVAL,
3213 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3214 { 1, 1, "root", "Root Select", PRDV_STRVAL,
3215 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3216 { 8, 15, "gran", "Effective Granularity", PRDV_HEX },
3217 { -1, -1, NULL }
3218 };
3219
3220 static const pcieadm_cfgspace_print_t pcieadm_cap_info_ptm[] = {
3221 { 0x0, 4, "caphdr", "Capability Header",
3222 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
3223 { 0x4, 4, "cap", "PTM Capability",
3224 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ptm_cap },
3225 { 0x8, 4, "cap", "PTM Control",
3226 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ptm_ctl },
3227 { -1, -1, NULL }
3228 };
3229
3230 /*
3231 * Address Translation Services (ATS)
3232 */
3233 static const pcieadm_regdef_t pcieadm_regdef_ats_cap[] = {
3234 { 0, 4, "invqd", "Invalidate Queue Depth", PRDV_HEX },
3235 { 5, 5, "pgalign", "Page Aligned Request", PRDV_STRVAL,
3236 .prd_val = { .prdv_strval = { "not required", "required" } } },
3237 { 6, 6, "glbinv", "Global Invalidate", PRDV_STRVAL,
3238 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3239 { 7, 7, "relo", "Relaxed Ordering", PRDV_STRVAL,
3240 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3241 { -1, -1, NULL }
3242 };
3243
3244 static const pcieadm_regdef_t pcieadm_regdef_ats_ctl[] = {
3245 { 0, 4, "stu", "Smallest Translation Unit", PRDV_HEX },
3246 { 15, 15, "en", "Enable", PRDV_STRVAL,
3247 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3248 { -1, -1, NULL }
3249 };
3250
3251 static const pcieadm_cfgspace_print_t pcieadm_cap_ats[] = {
3252 { 0x0, 4, "caphdr", "Capability Header",
3253 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
3254 { 0x4, 2, "cap", "ATS Capability",
3255 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ats_cap },
3256 { 0x6, 2, "cap", "ATS Control",
3257 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ats_ctl },
3258 { -1, -1, NULL }
3259 };
3260
3261 /*
3262 * Page Request
3263 */
3264 static const pcieadm_regdef_t pcieadm_regdef_pgreq_ctl[] = {
3265 { 0, 0, "en", "Enable", PRDV_STRVAL,
3266 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3267 { 1, 1, "reset", "Reset", PRDV_HEX },
3268 { -1, -1, NULL }
3269 };
3270
3271 static const pcieadm_regdef_t pcieadm_regdef_pgreq_sts[] = {
3272 { 0, 0, "rf", "Response Failure", PRDV_STRVAL,
3273 .prd_val = { .prdv_strval = { "no", "yes" } } },
3274 { 1, 1, "uprgi", "Unexpected Page Request Group Index", PRDV_STRVAL,
3275 .prd_val = { .prdv_strval = { "no", "yes" } } },
3276 { 8, 8, "stopped", "Stopped", PRDV_STRVAL,
3277 .prd_val = { .prdv_strval = { "no", "yes" } } },
3278 { 15, 15, "prgrpreq", "PRG Response PASID", PRDV_STRVAL,
3279 .prd_val = { .prdv_strval = { "not required", "required" } } },
3280 { -1, -1, NULL }
3281 };
3282
3283 static const pcieadm_cfgspace_print_t pcieadm_cap_pgreq[] = {
3284 { 0x0, 4, "caphdr", "Capability Header",
3285 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
3286 { 0x4, 2, "ctl", "Page Request Control",
3287 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pgreq_ctl },
3288 { 0x6, 2, "ctl", "Page Request Status",
3289 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pgreq_sts },
3290 { 0x8, 4, "cap", "Outstanding Page Request Capacity",
3291 pcieadm_cfgspace_print_hex },
3292 { 0xc, 4, "alloc", "Outstanding Page Request Allocation",
3293 pcieadm_cfgspace_print_hex },
3294 { -1, -1, NULL }
3295 };
3296
3297 /*
3298 * NULL Capability
3299 */
3300 static const pcieadm_cfgspace_print_t pcieadm_cap_null[] = {
3301 { 0x0, 4, "caphdr", "Capability Header",
3302 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
3303 { -1, -1, NULL }
3304 };
3305
3306 /*
3307 * Downstream Port Containment
3308 */
3309 static const pcieadm_regdef_t pcieadm_regdef_dpc_cap[] = {
3310 { 0, 4, "inum", "DPC Interrupt Message Number", PRDV_HEX },
3311 { 5, 5, "rpext", "Root Port Extensions", PRDV_STRVAL,
3312 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3313 { 6, 6, "ptlpeb", "Poisoned TLP Egress Blocking", PRDV_STRVAL,
3314 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3315 { 7, 7, "swtrig", "Software Triggering", PRDV_STRVAL,
3316 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3317 { 8, 11, "logsz", "RP PIO Log Size", PRDV_HEX },
3318 { 12, 12, "errcorr", "DL_Active ERR_COR Signaling", PRDV_STRVAL,
3319 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3320 { -1, -1, NULL }
3321 };
3322
3323 static const pcieadm_regdef_t pcieadm_regdef_dpc_ctl[] = {
3324 { 0, 1, "trigger", "DPC Trigger", PRDV_STRVAL,
3325 .prd_val = { .prdv_strval = { "disabled", "enabled, fatal",
3326 "enabled, non-fatal" } } },
3327 { 2, 2, "comp", "Completion Control", PRDV_STRVAL,
3328 .prd_val = { .prdv_strval = { "Completer Abort",
3329 "Unsupported Request" } } },
3330 { 3, 3, "intr", "Interrupt",
3331 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3332 { 4, 4, "errcor", "ERR_COR",
3333 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3334 { 5, 5, "ptlpeb", "Poisoned TLP Egress Blocking", PRDV_STRVAL,
3335 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3336 { 6, 6, "swtrig", "Software Trigger", PRDV_HEX },
3337 { 7, 7, "corerr", "DL_Active ERR_COR",
3338 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3339 { 8, 8, "sigsfw", "SIG_SFW",
3340 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3341 { -1, -1, NULL }
3342 };
3343
3344 static const pcieadm_regdef_t pcieadm_regdef_dpc_sts[] = {
3345 { 0, 0, "trigger", "Trigger Status", PRDV_STRVAL,
3346 .prd_val = { .prdv_strval = { "not triggered", "triggered" } } },
3347 { 1, 2, "reason", "Trigger Reason", PRDV_STRVAL,
3348 .prd_val = { .prdv_strval = { "unmasked uncorrectable",
3349 "ERR_NONFATAL received", "ERR_FATAL received",
3350 "see extension" } } },
3351 { 3, 3, "istatus", "Interrupt Status", PRDV_HEX },
3352 { 4, 4, "rpbusy", "RP Busy", PRDV_STRVAL,
3353 .prd_val = { .prdv_strval = { "no", "yes" } } },
3354 { 5, 6, "extreason", "Trigger Reason Extension", PRDV_STRVAL,
3355 .prd_val = { .prdv_strval = { "RP PIO", "Software Trigger" } } },
3356 { 8, 12, "feptr", "RP PIO, First Error Pointer", PRDV_HEX },
3357 { 13, 13, "sigsfw", "SIG_SFW Status", PRDV_HEX },
3358 { -1, -1, NULL }
3359 };
3360
3361 static const pcieadm_regdef_t pcieadm_regdef_dpc_rppio_bits[] = {
3362 { 0, 0, "cfgur", "Configuration Request UR Completion", PRDV_HEX },
3363 { 1, 1, "cfgca", "Configuration Request CA Completion", PRDV_HEX },
3364 { 2, 2, "cfgcto", "Configuration Request Completion Timeout",
3365 PRDV_HEX },
3366 { 8, 8, "iour", "I/O UR Completion", PRDV_HEX },
3367 { 9, 9, "ioca", "I/O CA Completion", PRDV_HEX },
3368 { 10, 10, "iocto", "I/O Completion Timeout", PRDV_HEX },
3369 { 8, 8, "memur", "Memory UR Completion", PRDV_HEX },
3370 { 9, 9, "memca", "Memory CA Completion", PRDV_HEX },
3371 { 10, 10, "memcto", "Memory Completion Timeout", PRDV_HEX },
3372 { -1, -1, NULL }
3373 };
3374
3375 static void
pcieadm_cfgspace_print_dpc_rppio(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)3376 pcieadm_cfgspace_print_dpc_rppio(pcieadm_cfgspace_walk_t *walkp,
3377 const pcieadm_cfgspace_print_t *print, const void *arg)
3378 {
3379 uint32_t cap = pcieadm_cfgspace_getcap32(walkp, 4);
3380
3381 if (bitx32(cap, 5, 5) == 0) {
3382 return;
3383 }
3384
3385 pcieadm_cfgspace_print_regdef(walkp, print, arg);
3386 }
3387
3388 static void
pcieadm_cfgspace_print_dpc_piohead(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)3389 pcieadm_cfgspace_print_dpc_piohead(pcieadm_cfgspace_walk_t *walkp,
3390 const pcieadm_cfgspace_print_t *print, const void *arg)
3391 {
3392 uint32_t cap = pcieadm_cfgspace_getcap32(walkp, 4);
3393 uint32_t nwords = bitx32(cap, 11, 8);
3394
3395 if (bitx32(cap, 5, 5) == 0 || nwords < 4) {
3396 return;
3397 }
3398
3399 pcieadm_cfgspace_print_hex(walkp, print, NULL);
3400 }
3401
3402 static void
pcieadm_cfgspace_print_dpc_impspec(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)3403 pcieadm_cfgspace_print_dpc_impspec(pcieadm_cfgspace_walk_t *walkp,
3404 const pcieadm_cfgspace_print_t *print, const void *arg)
3405 {
3406 uint32_t cap = pcieadm_cfgspace_getcap32(walkp, 4);
3407 uint32_t nwords = bitx32(cap, 11, 8);
3408
3409 if (bitx32(cap, 5, 5) == 0 || nwords < 5) {
3410 return;
3411 }
3412
3413 pcieadm_cfgspace_print_hex(walkp, print, NULL);
3414 }
3415
3416 static void
pcieadm_cfgspace_print_dpc_tlplog(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)3417 pcieadm_cfgspace_print_dpc_tlplog(pcieadm_cfgspace_walk_t *walkp,
3418 const pcieadm_cfgspace_print_t *print, const void *arg)
3419 {
3420 uint32_t cap = pcieadm_cfgspace_getcap32(walkp, 4);
3421 int32_t nwords = (int32_t)bitx32(cap, 11, 8);
3422
3423 if (nwords == 0 || bitx32(cap, 5, 5) == 0) {
3424 return;
3425 }
3426
3427 if (nwords <= 9) {
3428 nwords -= 5;
3429 } else {
3430 nwords -= 4;
3431 }
3432
3433 for (int32_t i = 0; i < nwords; i++) {
3434 char tlpshort[32], tlphuman[128];
3435 pcieadm_cfgspace_print_t p;
3436
3437 (void) snprintf(tlpshort, sizeof (tlpshort), "%s%u",
3438 print->pcp_short, i);
3439 (void) snprintf(tlphuman, sizeof (tlphuman), "%s %u",
3440 print->pcp_human, i);
3441 p.pcp_off = print->pcp_off + i * 4;
3442 p.pcp_len = 4;
3443 p.pcp_short = tlpshort;
3444 p.pcp_human = tlphuman;
3445 p.pcp_print = pcieadm_cfgspace_print_hex;
3446 p.pcp_arg = NULL;
3447
3448 p.pcp_print(walkp, &p, p.pcp_arg);
3449 }
3450 }
3451
3452 static const pcieadm_cfgspace_print_t pcieadm_cap_dpc[] = {
3453 { 0x0, 4, "caphdr", "Capability Header",
3454 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
3455 { 0x4, 2, "cap", "DPC Capability",
3456 pcieadm_cfgspace_print_regdef, pcieadm_regdef_dpc_cap },
3457 { 0x6, 2, "ctl", "DPC Control",
3458 pcieadm_cfgspace_print_regdef, pcieadm_regdef_dpc_ctl },
3459 { 0x8, 2, "sts", "DPC Status",
3460 pcieadm_cfgspace_print_regdef, pcieadm_regdef_dpc_sts },
3461 { 0xa, 2, "srcid", "DPC Error Source ID",
3462 pcieadm_cfgspace_print_hex },
3463 { 0x10, 4, "rppiosts", "RP PIO Status",
3464 pcieadm_cfgspace_print_dpc_rppio, pcieadm_regdef_dpc_rppio_bits },
3465 { 0x14, 4, "rppiomask", "RP PIO Mask ID",
3466 pcieadm_cfgspace_print_dpc_rppio, pcieadm_regdef_dpc_rppio_bits },
3467 { 0x14, 4, "rppiosev", "RP PIO Severity",
3468 pcieadm_cfgspace_print_dpc_rppio, pcieadm_regdef_dpc_rppio_bits },
3469 { 0x18, 4, "rppiose", "RP PIO SysError",
3470 pcieadm_cfgspace_print_dpc_rppio, pcieadm_regdef_dpc_rppio_bits },
3471 { 0x1c, 4, "rppioex", "RP PIO Exception",
3472 pcieadm_cfgspace_print_dpc_rppio, pcieadm_regdef_dpc_rppio_bits },
3473 { 0x20, 4, "rppiohl0", "RP PIO Header Log 0",
3474 pcieadm_cfgspace_print_dpc_piohead },
3475 { 0x24, 4, "rppiohl1", "RP PIO Header Log 1",
3476 pcieadm_cfgspace_print_dpc_piohead },
3477 { 0x28, 4, "rppiohl2", "RP PIO Header Log 2",
3478 pcieadm_cfgspace_print_dpc_piohead },
3479 { 0x2c, 4, "rppiohl3", "RP PIO Header Log 3",
3480 pcieadm_cfgspace_print_dpc_piohead },
3481 { 0x30, 4, "impspec", "RP PIO ImpSpec Log",
3482 pcieadm_cfgspace_print_dpc_impspec },
3483 { 0x34, 16, "tlplog", "RP PIO TLP Prefix Log",
3484 pcieadm_cfgspace_print_dpc_tlplog },
3485 { -1, -1, NULL }
3486 };
3487
3488 /*
3489 * Virtual Channel Capability
3490 */
3491 static const pcieadm_regdef_t pcieadm_regdef_vc_cap1[] = {
3492 { 0, 2, "count", "Extended VC Count", PRDV_HEX },
3493 { 4, 6, "lpcount", "Low Priority Extended VC Count", PRDV_HEX },
3494 { 8, 9, "refclk", "Reference Clock", PRDV_STRVAL,
3495 .prd_val = { .prdv_strval = { "100ns" } } },
3496 { 10, 11, "patsz", "Port Arbitration Table Size", PRDV_STRVAL,
3497 .prd_val = { .prdv_strval = { "1 bit", "2 bits", "4 bits",
3498 "8 bits" } } },
3499 { -1, -1, NULL }
3500 };
3501
3502 static const pcieadm_regdef_t pcieadm_regdef_vc_cap2[] = {
3503 { 0, 7, "arbcap", "VC Arbitration Capability", PRDV_BITFIELD,
3504 .prd_val = { .prdv_strval = { "hardware fixed",
3505 "32 phase weighted round robin", "64 phase weighted round robin",
3506 "128 phase weighted round robin" } } },
3507 { 24, 31, "offset", "VC Arbitration Table Offset", PRDV_HEX },
3508 { -1, -1, NULL }
3509 };
3510
3511 static const pcieadm_regdef_t pcieadm_regdef_vc_ctl[] = {
3512 { 0, 0, "loadtbl", "Load VC Arbitration Table", PRDV_HEX },
3513 { 1, 3, "arbtype", "VC Arbitration Select", PRDV_STRVAL,
3514 .prd_val = { .prdv_strval = { "hardware fixed",
3515 "32 phase weighted round robin", "64 phase weighted round robin",
3516 "128 phase weighted round robin" } } },
3517 { -1, -1, NULL }
3518 };
3519
3520 static const pcieadm_regdef_t pcieadm_regdef_vc_sts[] = {
3521 { 0, 0, "table", "VC Arbitration Table Status", PRDV_HEX },
3522 { -1, -1, NULL }
3523 };
3524
3525 static const pcieadm_regdef_t pcieadm_regdef_vc_rsrccap[] = {
3526 { 0, 7, "arbcap", "Port Arbitration Capability", PRDV_BITFIELD,
3527 .prd_val = { .prdv_strval = { "hardware fixed",
3528 "32 phase weighted round robin", "64 phase weighted round robin",
3529 "128 phase weighted round robin",
3530 "128 phase time-based weighted round robin",
3531 "256 phase weighted round robin" } } },
3532 { 14, 14, "aps", "Advanced Packet Switching", PRDV_STRVAL,
3533 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3534 { 15, 15, "rstx", "Reject Snoop Transactions", PRDV_STRVAL,
3535 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3536 { 16, 22, "nslots", "Maximum Time Slots", PRDV_HEX,
3537 { .prdv_hex = { 0, 1 } } },
3538 { 24, 31, "offset", "VC Arbitration Table Offset", PRDV_HEX },
3539 { -1, -1, NULL }
3540 };
3541
3542 static const pcieadm_regdef_t pcieadm_regdef_vc_rsrcctl[] = {
3543 { 0, 7, "tcmap", "TC/VC Map", PRDV_HEX },
3544 { 16, 16, "loadtbl", "Load VC Arbitration Table", PRDV_HEX },
3545 { 17, 19, "arbtype", "Port Arbitration Select", PRDV_STRVAL,
3546 .prd_val = { .prdv_strval = { "hardware fixed",
3547 "32 phase weighted round robin", "64 phase weighted round robin",
3548 "128 phase weighted round robin",
3549 "128 phase time-based weighted round robin",
3550 "256 phase weighted round robin" } } },
3551 { 24, 26, "vcid", "VC ID", PRDV_HEX },
3552 { 31, 31, "en", "VC Enable",
3553 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3554 { -1, -1, NULL }
3555 };
3556
3557 static const pcieadm_regdef_t pcieadm_regdef_vc_rsrcsts[] = {
3558 { 0, 0, "table", "Port Arbitration Table Status", PRDV_HEX },
3559 { -1, -1, NULL }
3560 };
3561
3562 static void
pcieadm_cfgspace_print_vc_rsrc(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)3563 pcieadm_cfgspace_print_vc_rsrc(pcieadm_cfgspace_walk_t *walkp,
3564 const pcieadm_cfgspace_print_t *print, const void *arg)
3565 {
3566 uint32_t cap = pcieadm_cfgspace_getcap32(walkp, 4);
3567 uint32_t nents = bitx32(cap, 2, 0) + 1;
3568
3569 for (uint32_t i = 0; i < nents; i++) {
3570 char vcshort[32], vchuman[128];
3571 pcieadm_cfgspace_print_t p;
3572
3573 (void) snprintf(vcshort, sizeof (vcshort), "rsrccap%u", i);
3574 (void) snprintf(vchuman, sizeof (vchuman), "VC Resource %u "
3575 "Capability", i);
3576 p.pcp_off = print->pcp_off + i * 0x10;
3577 p.pcp_len = 4;
3578 p.pcp_short = vcshort;
3579 p.pcp_human = vchuman;
3580 p.pcp_print = pcieadm_cfgspace_print_regdef;
3581 p.pcp_arg = pcieadm_regdef_vc_rsrccap;
3582
3583 p.pcp_print(walkp, &p, p.pcp_arg);
3584
3585 (void) snprintf(vcshort, sizeof (vcshort), "rsrcctl%u", i);
3586 (void) snprintf(vchuman, sizeof (vchuman), "VC Resource %u "
3587 "Control", i);
3588 p.pcp_off = print->pcp_off + i * 0x10 + 4;
3589 p.pcp_len = 4;
3590 p.pcp_short = vcshort;
3591 p.pcp_human = vchuman;
3592 p.pcp_print = pcieadm_cfgspace_print_regdef;
3593 p.pcp_arg = pcieadm_regdef_vc_rsrcctl;
3594
3595 p.pcp_print(walkp, &p, p.pcp_arg);
3596
3597 (void) snprintf(vcshort, sizeof (vcshort), "rsrcsts%u", i);
3598 (void) snprintf(vchuman, sizeof (vchuman), "VC Resource %u "
3599 "Status", i);
3600 p.pcp_off = print->pcp_off + i * 0x10 + 0xa;
3601 p.pcp_len = 2;
3602 p.pcp_short = vcshort;
3603 p.pcp_human = vchuman;
3604 p.pcp_print = pcieadm_cfgspace_print_regdef;
3605 p.pcp_arg = pcieadm_regdef_vc_rsrcsts;
3606
3607 p.pcp_print(walkp, &p, p.pcp_arg);
3608 }
3609 }
3610
3611 static const pcieadm_cfgspace_print_t pcieadm_cap_vc[] = {
3612 { 0x0, 4, "caphdr", "Capability Header",
3613 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
3614 { 0x4, 4, "cap1", "Port VC Capability 1",
3615 pcieadm_cfgspace_print_regdef, pcieadm_regdef_vc_cap1 },
3616 { 0x8, 4, "cap2", "Port VC Capability 2",
3617 pcieadm_cfgspace_print_regdef, pcieadm_regdef_vc_cap2 },
3618 { 0xc, 2, "ctl", "Port VC Control",
3619 pcieadm_cfgspace_print_regdef, pcieadm_regdef_vc_ctl },
3620 { 0xe, 2, "sts", "Port VC Status",
3621 pcieadm_cfgspace_print_regdef, pcieadm_regdef_vc_sts },
3622 { 0x10, 12, "vcrec", "VC Resource", pcieadm_cfgspace_print_vc_rsrc },
3623 { -1, -1, NULL }
3624 };
3625
3626 /*
3627 * HyperTransport
3628 */
3629 static const pcieadm_cfgspace_print_t pcieadm_cap_ht_intr[] = {
3630 { 0x2, 1, "index", "Interrupt Discovery Index",
3631 pcieadm_cfgspace_print_hex },
3632 { 0x4, 4, "dataport", "Interrupt Dataport",
3633 pcieadm_cfgspace_print_hex },
3634 { -1, -1, NULL }
3635 };
3636
3637 static const pcieadm_regdef_t pcieadm_regdef_ht_command_pri[] = {
3638 { 0, 4, "unitid", "Base Unit ID", PRDV_HEX },
3639 { 5, 9, "count", "Unit Count", PRDV_HEX },
3640 { 10, 10, "host", "Master Host", PRDV_HEX },
3641 { 11, 11, "dir", "Default Direction", PRDV_STRVAL,
3642 .prd_val = { .prdv_strval = { "towards host",
3643 "away from host" } } },
3644 { 12, 12, "drop", "Drop on Uninitialized Link", PRDV_HEX },
3645 { 13, 15, "cap", "Capability ID", PRDV_HEX },
3646 { -1, -1, NULL }
3647 };
3648
3649 static const pcieadm_regdef_t pcieadm_regdef_ht_command_sec[] = {
3650 { 0, 0, "reset", "Warm Reset", PRDV_HEX },
3651 { 1, 1, "de", "Double Ended", PRDV_HEX },
3652 { 2, 6, "devno", "Device Number", PRDV_HEX },
3653 { 7, 7, "chain", "Chain Side", PRDV_STRVAL,
3654 .prd_val = { .prdv_strval = { "from host", "from chain" } } },
3655 { 8, 8, "hide", "Host Hide", PRDV_STRVAL,
3656 .prd_val = { .prdv_strval = { "visible", "hidden" } } },
3657 { 10, 10, "target", "Act as Target", PRDV_HEX },
3658 { 11, 11, "eocerr", "Host Inbound End of Chain Error", PRDV_HEX },
3659 { 12, 12, "drop", "Drop on Uninitialized Link", PRDV_HEX },
3660 { 13, 15, "cap", "Capability ID", PRDV_HEX },
3661 { -1, -1, NULL }
3662 };
3663
3664 static const pcieadm_regdef_t pcieadm_regdef_ht_linkctl[] = {
3665 { 0, 0, "srcid", "Source ID", PRDV_STRVAL,
3666 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3667 { 1, 1, "cfl", "CRC Flood", PRDV_STRVAL,
3668 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3669 { 2, 2, "cst", "CRC Start Test", PRDV_HEX },
3670 { 3, 3, "cfer", "CRC Force Error", PRDV_STRVAL,
3671 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3672 { 4, 4, "linkfail", "Link Failure", PRDV_HEX },
3673 { 5, 5, "initcmp", "Initialization Complete", PRDV_HEX },
3674 { 6, 6, "eoc", "End of Chain", PRDV_HEX },
3675 { 7, 7, "txoff", "Transmitter Off", PRDV_STRVAL,
3676 .prd_val = { .prdv_strval = { "transmitter on",
3677 "transmitter off" } } },
3678 { 8, 11, "crcerr", "CRC Error", PRDV_HEX },
3679 { 12, 12, "isoc", "Isochronous Flow Control", PRDV_STRVAL,
3680 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3681 { 13, 13, "ls", "LDTSTOP# Tristate", PRDV_STRVAL,
3682 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3683 { 14, 14, "extctl", "Extended CTL Time", PRDV_HEX },
3684 { 15, 15, "64b", "64-bit Addressing", PRDV_STRVAL,
3685 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3686 { -1, -1, NULL }
3687 };
3688
3689 static const pcieadm_regdef_t pcieadm_regdef_ht_linkcfg[] = {
3690 { 0, 2, "maxin", "Maximum Link Width In", PRDV_STRVAL,
3691 .prd_val = { .prdv_strval = { "8 bits", "16 bits", NULL, "32 bits",
3692 "2 bits", "4 bits", NULL, "not connected" } } },
3693 { 3, 3, "dwfcinsup", "Doubleword Flow Control In", PRDV_STRVAL,
3694 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3695 { 4, 6, "maxout", "Maximum Link Width Out", PRDV_STRVAL,
3696 .prd_val = { .prdv_strval = { "8 bits", "16 bits", NULL, "32 bits",
3697 "2 bits", "4 bits", NULL, "not connected" } } },
3698 { 7, 7, "dwfcoutsup", "Doubleword Flow Control Out", PRDV_STRVAL,
3699 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3700 { 8, 10, "linkin", "Link Width In", PRDV_STRVAL,
3701 .prd_val = { .prdv_strval = { "8 bits", "16 bits", NULL, "32 bits",
3702 "2 bits", "4 bits", NULL, "not connected" } } },
3703 { 11, 11, "dwfcin", "Doubleword Flow Control In", PRDV_STRVAL,
3704 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3705 { 12, 14, "linkout", "Link Width Out", PRDV_STRVAL,
3706 .prd_val = { .prdv_strval = { "8 bits", "16 bits", NULL, "32 bits",
3707 "2 bits", "4 bits", NULL, "not connected" } } },
3708 { 15, 15, "dwfcout", "Doubleword Flow Control Out", PRDV_STRVAL,
3709 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3710 { -1, -1, NULL }
3711 };
3712
3713 static const pcieadm_regdef_t pcieadm_regdef_ht_rev[] = {
3714 { 0, 4, "minor", "Minor Revision", PRDV_HEX },
3715 { 5, 7, "major", "Major Revision", PRDV_HEX },
3716 { -1, -1, NULL }
3717 };
3718
3719 static const pcieadm_regdef_t pcieadm_regdef_ht_linkfreq[] = {
3720 { 0, 4, "freq", "Link Frequency", PRDV_STRVAL,
3721 .prd_val = { .prdv_strval = { "200 MHz", "300 MHz", "400 MHz",
3722 "500 MHz", "600 MHz", "800 MHz", "1000 MHz", "1200 MHz", "1400 MHz",
3723 "1600 MHz", "1800 MHz", "2000 MHz", "2200 MHz", "2400 MHz",
3724 "2600 MHz", "Vendor Specfic" } } },
3725 { -1, -1, NULL }
3726 };
3727
3728 static const pcieadm_regdef_t pcieadm_regdef_ht_linkerr[] = {
3729 { 4, 4, "prot", "Protocol Error", PRDV_HEX },
3730 { 5, 5, "over", "Overflow Error", PRDV_HEX },
3731 { 6, 6, "eoc", "End of Chain Error", PRDV_HEX },
3732 { 7, 7, "ctl", "CTL Timeout", PRDV_HEX },
3733 { -1, -1, NULL }
3734 };
3735
3736 static const pcieadm_regdef_t pcieadm_regdef_ht_linkcap[] = {
3737 { 0, 15, "freq", "Link Frequency", PRDV_BITFIELD,
3738 .prd_val = { .prdv_strval = { "200 MHz", "300 MHz", "400 MHz",
3739 "500 MHz", "600 MHz", "800 MHz", "1000 MHz", "1200 MHz", "1400 MHz",
3740 "1600 MHz", "1800 MHz", "2000 MHz", "2200 MHz", "2400 MHz",
3741 "2600 MHz", "Vendor Specfic" } } },
3742 { -1, -1, NULL }
3743 };
3744
3745 static const pcieadm_regdef_t pcieadm_regdef_ht_feature[] = {
3746 { 0, 0, "isofc", "Isochronous Flow Control", PRDV_STRVAL,
3747 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3748 { 1, 1, "ls", "LDTSTOP#", PRDV_STRVAL,
3749 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3750 { 2, 2, "crct", "CRC Test Mode", PRDV_STRVAL,
3751 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3752 { 3, 3, "ectl", "Extended CTL Time", PRDV_STRVAL,
3753 .prd_val = { .prdv_strval = { "not required", "required" } } },
3754 { 4, 4, "64b", "64-bit Addressing", PRDV_STRVAL,
3755 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3756 { 5, 5, "unitid", "UnitID Reorder", PRDV_STRVAL,
3757 .prd_val = { .prdv_strval = { "enabled", "disabled" } } },
3758 { 6, 6, "srcid", "Source Identification Extension", PRDV_STRVAL,
3759 .prd_val = { .prdv_strval = { "not required", "required" } } },
3760 { 8, 8, "extreg", "Extended Register Set", PRDV_STRVAL,
3761 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3762 { 9, 9, "uscfg", "Upstream Configuration", PRDV_STRVAL,
3763 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3764 { -1, -1, NULL }
3765 };
3766
3767 static const pcieadm_regdef_t pcieadm_regdef_ht_error[] = {
3768 { 0, 0, "protfl", "Protocol Error Flood", PRDV_STRVAL,
3769 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3770 { 1, 1, "ovfl", "Overflow Error Flood", PRDV_STRVAL,
3771 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3772 { 2, 2, "protf", "Protocol Error Fatal", PRDV_STRVAL,
3773 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3774 { 3, 3, "ovf", "Overflow Error Fatal", PRDV_STRVAL,
3775 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3776 { 4, 4, "eocf", "End of Chain Fatal Error", PRDV_STRVAL,
3777 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3778 { 5, 5, "respf", "Response Error Fatal", PRDV_STRVAL,
3779 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3780 { 6, 6, "crcf", "CRC Error Fatal", PRDV_STRVAL,
3781 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3782 { 7, 7, "sysf", "System Error Fatal", PRDV_STRVAL,
3783 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3784 { 8, 8, "chain", "Chain Fail", PRDV_HEX },
3785 { 9, 9, "resp", "Response Error", PRDV_HEX },
3786 { 10, 10, "protnf", "Protocol Error Non-Fatal", PRDV_STRVAL,
3787 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3788 { 11, 11, "ovfnf", "Overflow Error Non-Fatal", PRDV_STRVAL,
3789 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3790 { 12, 12, "eocnf", "End of Chain Error Non-Fatal", PRDV_STRVAL,
3791 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3792 { 13, 13, "respnf", "Response Error Non-Fatal", PRDV_STRVAL,
3793 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3794 { 14, 14, "crcnf", "CRC Error Non-Fatal", PRDV_STRVAL,
3795 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3796 { 15, 15, "sysnf", "System Error Non-Fatal", PRDV_STRVAL,
3797 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3798 { -1, -1, NULL }
3799 };
3800
3801 static const pcieadm_regdef_t pcieadm_regdef_ht_memory[] = {
3802 { 0, 8, "base", "Memory Base Upper 8 Bits", PRDV_HEX,
3803 .prd_val = { .prdv_hex = { 32 } } },
3804 { 9, 15, "limit", "Memory Limit Upper 8 Bits", PRDV_HEX,
3805 .prd_val = { .prdv_hex = { 32 } } },
3806 { -1, -1, NULL }
3807 };
3808
3809 static const pcieadm_cfgspace_print_t pcieadm_cap_ht_pri[] = {
3810 { 0x2, 2, "command", "Command",
3811 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_command_pri },
3812 { 0x4, 2, "linkctl0", "Link Control 0",
3813 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkctl },
3814 { 0x6, 2, "linkcfg0", "Link Configuration 0",
3815 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkcfg },
3816 { 0x8, 2, "linkctl1", "Link Control 1",
3817 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkctl },
3818 { 0xa, 2, "linkcfg1", "Link Configuration 1",
3819 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkcfg },
3820 { 0xc, 1, "rev", "Revision",
3821 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_rev },
3822 { 0xd, 1, "linkfreq0", "Link Frequency 0",
3823 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkfreq },
3824 { 0xd, 1, "linkerr0", "Link Error 0",
3825 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkerr },
3826 { 0xe, 2, "linkfcap0", "Link Frequency Cap 0",
3827 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkcap },
3828 { 0x10, 1, "feature", "Feature Capability",
3829 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_feature },
3830 { 0x11, 1, "linkfreq1", "Link Frequency 1",
3831 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkfreq },
3832 { 0x11, 1, "linkerr1", "Link Error 1",
3833 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkerr },
3834 { 0x12, 2, "linkfcap1", "Link Frequency Cap 1",
3835 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkcap },
3836 { 0x14, 2, "scratch", "Enumeration Scratchpad",
3837 pcieadm_cfgspace_print_hex },
3838 { 0x16, 2, "error", "Error Handling",
3839 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_error },
3840 { 0x18, 2, "memory", "Memory",
3841 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_memory },
3842 { 0x1a, 1, "bus", "Bus Number", pcieadm_cfgspace_print_hex },
3843 { -1, -1, NULL }
3844 };
3845
3846 static const pcieadm_cfgspace_print_t pcieadm_cap_ht_sec[] = {
3847 { 0x2, 2, "command", "Command",
3848 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_command_sec },
3849 { 0x4, 2, "linkctl", "Link Control",
3850 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkctl },
3851 { 0x6, 2, "linkcfg", "Link Configuration",
3852 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkcfg },
3853 { 0x8, 1, "rev", "Revision",
3854 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_rev },
3855 { 0x9, 1, "linkfreq", "Link Frequency 0",
3856 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkfreq },
3857 { 0x9, 1, "linkerr", "Link Error 0",
3858 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkerr },
3859 { 0xa, 2, "linkfcap", "Link Frequency Cap 0",
3860 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkcap },
3861 { 0xc, 2, "feature", "Feature Capability",
3862 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_feature },
3863 { 0x10, 2, "scratch", "Enumeration Scratchpad",
3864 pcieadm_cfgspace_print_hex },
3865 { 0x12, 2, "error", "Error Handling",
3866 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_error },
3867 { 0x14, 2, "memory", "Memory",
3868 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_memory },
3869 { -1, -1, NULL }
3870 };
3871
3872 static const pcieadm_regdef_t pcieadm_regdef_ht_msi[] = {
3873 { 0, 0, "en", "Enable", PRDV_STRVAL,
3874 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3875 { 1, 1, "fixed", "Fixed", PRDV_STRVAL,
3876 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3877 { -1, -1, NULL }
3878 };
3879
3880 static void
pcieadm_cfgspace_print_ht_msi_addr(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)3881 pcieadm_cfgspace_print_ht_msi_addr(pcieadm_cfgspace_walk_t *walkp,
3882 const pcieadm_cfgspace_print_t *print, const void *arg)
3883 {
3884 uint8_t fixed = walkp->pcw_data->pcb_u8[walkp->pcw_capoff + 2];
3885
3886 if (bitx8(fixed, 1, 1) != 0)
3887 return;
3888
3889 pcieadm_cfgspace_print_hex(walkp, print, arg);
3890 }
3891
3892 static const pcieadm_cfgspace_print_t pcieadm_cap_ht_msi[] = {
3893 { 0x2, 2, "command", "Command",
3894 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_msi },
3895 { 0x4, 8, "address", "MSI Address",
3896 pcieadm_cfgspace_print_ht_msi_addr },
3897 { -1, -1, NULL }
3898 };
3899
3900 /*
3901 * Capability related tables
3902 */
3903 typedef struct pcieadm_cap_vers {
3904 uint32_t ppr_vers;
3905 uint32_t ppr_len;
3906 const pcieadm_cfgspace_print_t *ppr_print;
3907 } pcieadm_cap_vers_t;
3908
3909 typedef struct pcieadm_subcap {
3910 const char *psub_short;
3911 const char *psub_human;
3912 } pcieadm_subcap_t;
3913
3914 typedef struct pcieadm_pci_cap pcieadm_pci_cap_t;
3915
3916 typedef void (*pcieadm_cap_info_f)(pcieadm_cfgspace_walk_t *,
3917 const pcieadm_pci_cap_t *, uint32_t, const pcieadm_cap_vers_t **,
3918 uint32_t *, const pcieadm_subcap_t **);
3919
3920 struct pcieadm_pci_cap {
3921 uint32_t ppc_id;
3922 const char *ppc_short;
3923 const char *ppc_human;
3924 pcieadm_cap_info_f ppc_info;
3925 const pcieadm_cap_vers_t ppc_vers[4];
3926 };
3927
3928 /*
3929 * Capability version determinations.
3930 */
3931
3932 static void
pcieadm_cap_info_fixed(pcieadm_cfgspace_walk_t * walkp,const pcieadm_pci_cap_t * cap,uint32_t off,const pcieadm_cap_vers_t ** versp,uint32_t * lenp,const pcieadm_subcap_t ** subcap)3933 pcieadm_cap_info_fixed(pcieadm_cfgspace_walk_t *walkp,
3934 const pcieadm_pci_cap_t *cap, uint32_t off,
3935 const pcieadm_cap_vers_t **versp, uint32_t *lenp,
3936 const pcieadm_subcap_t **subcap)
3937 {
3938 *versp = &cap->ppc_vers[0];
3939 *lenp = cap->ppc_vers[0].ppr_len;
3940 *subcap = NULL;
3941 }
3942
3943 static void
pcieadm_cap_info_vers(pcieadm_cfgspace_walk_t * walkp,const pcieadm_pci_cap_t * cap,uint32_t off,const pcieadm_cap_vers_t ** versp,uint32_t * lenp,const pcieadm_subcap_t ** subcap)3944 pcieadm_cap_info_vers(pcieadm_cfgspace_walk_t *walkp,
3945 const pcieadm_pci_cap_t *cap, uint32_t off,
3946 const pcieadm_cap_vers_t **versp, uint32_t *lenp,
3947 const pcieadm_subcap_t **subcap)
3948 {
3949 uint8_t vers;
3950
3951 *subcap = NULL;
3952 vers = walkp->pcw_data->pcb_u8[off + 2] & 0xf;
3953 for (uint32_t i = 0; i < ARRAY_SIZE(cap->ppc_vers); i++) {
3954 if (vers == cap->ppc_vers[i].ppr_vers &&
3955 cap->ppc_vers[i].ppr_vers != 0) {
3956 *versp = &cap->ppc_vers[i];
3957 *lenp = cap->ppc_vers[i].ppr_len;
3958 return;
3959 }
3960 }
3961
3962 *versp = NULL;
3963 *lenp = 0;
3964 }
3965
3966 /*
3967 * The PCI Power Management capability uses a 3-bit version ID as opposed to the
3968 * standard 4-bit version.
3969 */
3970 static void
pcieadm_cap_info_pcipm(pcieadm_cfgspace_walk_t * walkp,const pcieadm_pci_cap_t * cap,uint32_t off,const pcieadm_cap_vers_t ** versp,uint32_t * lenp,const pcieadm_subcap_t ** subcap)3971 pcieadm_cap_info_pcipm(pcieadm_cfgspace_walk_t *walkp,
3972 const pcieadm_pci_cap_t *cap, uint32_t off,
3973 const pcieadm_cap_vers_t **versp, uint32_t *lenp,
3974 const pcieadm_subcap_t **subcap)
3975 {
3976 uint8_t vers;
3977
3978 *subcap = NULL;
3979 vers = walkp->pcw_data->pcb_u8[off + 2] & 0x7;
3980 for (uint32_t i = 0; i < ARRAY_SIZE(cap->ppc_vers); i++) {
3981 if (vers == cap->ppc_vers[i].ppr_vers) {
3982 *versp = &cap->ppc_vers[i];
3983 *lenp = cap->ppc_vers[i].ppr_len;
3984 return;
3985 }
3986 }
3987
3988 *versp = NULL;
3989 *lenp = 0;
3990 }
3991
3992 /*
3993 * The PCIe capability underwent a few changes. In version 1 of the capability,
3994 * devices were not required to implement the entire capability. In particular,
3995 * endpoints did not need to implement anything more than the link status
3996 * register. In the v2 capability, this was changed such that all devices had to
3997 * implement the entire capbility, but otherwise hardcode registers to zero. As
3998 * such we get to play guess the length based on the device type.
3999 */
4000 static const pcieadm_cap_vers_t pcieadm_cap_vers_pcie_v1_dev = {
4001 1, 0x0c, pcieadm_cap_pcie_v1_dev
4002 };
4003
4004 static const pcieadm_cap_vers_t pcieadm_cap_vers_pcie_v1_link = {
4005 1, 0x14, pcieadm_cap_pcie_v1_link
4006 };
4007
4008 static const pcieadm_cap_vers_t pcieadm_cap_vers_pcie_v1_slot = {
4009 1, 0x1c, pcieadm_cap_pcie_v1_slot
4010 };
4011
4012 static const pcieadm_cap_vers_t pcieadm_cap_vers_pcie_v1_all = {
4013 1, 0x24, pcieadm_cap_pcie_v1_all
4014 };
4015
4016 static const pcieadm_cap_vers_t pcieadm_cap_vers_pcie_v2 = {
4017 2, 0x4c, pcieadm_cap_pcie_v2
4018 };
4019
4020 static void
pcieadm_cap_info_pcie(pcieadm_cfgspace_walk_t * walkp,const pcieadm_pci_cap_t * cap,uint32_t off,const pcieadm_cap_vers_t ** versp,uint32_t * lenp,const pcieadm_subcap_t ** subcap)4021 pcieadm_cap_info_pcie(pcieadm_cfgspace_walk_t *walkp,
4022 const pcieadm_pci_cap_t *cap, uint32_t off,
4023 const pcieadm_cap_vers_t **versp, uint32_t *lenp,
4024 const pcieadm_subcap_t **subcap)
4025 {
4026 uint8_t vers = walkp->pcw_data->pcb_u8[off + 2] & 0xf;
4027 uint16_t pcie = walkp->pcw_data->pcb_u8[off + 2] |
4028 (walkp->pcw_data->pcb_u8[off + 3] << 8);
4029
4030 /*
4031 * Version 2 is simple. There's only one thing to do, so we do it. For
4032 * version 1 we need to look at the device type.
4033 */
4034 *subcap = NULL;
4035 if (vers == 2) {
4036 *versp = &pcieadm_cap_vers_pcie_v2;
4037 *lenp = (*versp)->ppr_len;
4038 return;
4039 } else if (vers != 1) {
4040 *versp = NULL;
4041 *lenp = 0;
4042 return;
4043 }
4044
4045 switch (pcie & PCIE_PCIECAP_DEV_TYPE_MASK) {
4046 case PCIE_PCIECAP_DEV_TYPE_PCIE_DEV:
4047 case PCIE_PCIECAP_DEV_TYPE_PCI_DEV:
4048 *versp = &pcieadm_cap_vers_pcie_v1_link;
4049 break;
4050 case PCIE_PCIECAP_DEV_TYPE_RC_IEP:
4051 *versp = &pcieadm_cap_vers_pcie_v1_dev;
4052 break;
4053 case PCIE_PCIECAP_DEV_TYPE_UP:
4054 case PCIE_PCIECAP_DEV_TYPE_DOWN:
4055 case PCIE_PCIECAP_DEV_TYPE_PCIE2PCI:
4056 case PCIE_PCIECAP_DEV_TYPE_PCI2PCIE:
4057 if ((pcie & PCIE_PCIECAP_SLOT_IMPL) != 0) {
4058 *versp = &pcieadm_cap_vers_pcie_v1_slot;
4059 } else {
4060 *versp = &pcieadm_cap_vers_pcie_v1_link;
4061 }
4062 break;
4063 case PCIE_PCIECAP_DEV_TYPE_ROOT:
4064 case PCIE_PCIECAP_DEV_TYPE_RC_EC:
4065 *versp = &pcieadm_cap_vers_pcie_v1_all;
4066 break;
4067 default:
4068 *versp = NULL;
4069 *lenp = 0;
4070 return;
4071 }
4072
4073 *lenp = (*versp)->ppr_len;
4074 }
4075
4076 /*
4077 * The length of the MSI capability depends on bits in its control field. As
4078 * such we use a custom function to extract the length and treat each of these
4079 * variants as thought it were a different version.
4080 */
4081 static pcieadm_cap_vers_t pcieadm_cap_vers_msi_32 = {
4082 0, 0xa, pcieadm_cap_msi_32
4083 };
4084
4085 static pcieadm_cap_vers_t pcieadm_cap_vers_msi_32ext = {
4086 0, 0xc, pcieadm_cap_msi_32ext
4087 };
4088
4089 static pcieadm_cap_vers_t pcieadm_cap_vers_msi_64 = {
4090 0, 0xe, pcieadm_cap_msi_64
4091 };
4092
4093 static pcieadm_cap_vers_t pcieadm_cap_vers_msi_64ext = {
4094 0, 0x10, pcieadm_cap_msi_64ext
4095 };
4096
4097 static pcieadm_cap_vers_t pcieadm_cap_vers_msi_32pvm = {
4098 0, 0x14, pcieadm_cap_msi_32pvm
4099 };
4100
4101 static pcieadm_cap_vers_t pcieadm_cap_vers_msi_64pvm = {
4102 0, 0x18, pcieadm_cap_msi_64pvm
4103 };
4104
4105 static void
pcieadm_cap_info_msi(pcieadm_cfgspace_walk_t * walkp,const pcieadm_pci_cap_t * cap,uint32_t off,const pcieadm_cap_vers_t ** versp,uint32_t * lenp,const pcieadm_subcap_t ** subcap)4106 pcieadm_cap_info_msi(pcieadm_cfgspace_walk_t *walkp,
4107 const pcieadm_pci_cap_t *cap, uint32_t off,
4108 const pcieadm_cap_vers_t **versp, uint32_t *lenp,
4109 const pcieadm_subcap_t **subcap)
4110 {
4111 uint16_t ctrl;
4112 boolean_t addr64, pvm, ext;
4113
4114 *subcap = NULL;
4115 ctrl = walkp->pcw_data->pcb_u8[off + 2] |
4116 (walkp->pcw_data->pcb_u8[off + 3] << 8);
4117 if (ctrl == PCI_EINVAL16) {
4118 warnx("failed to read MSI Message Control register");
4119 *lenp = 0;
4120 *versp = NULL;
4121 return;
4122 }
4123
4124 /*
4125 * The MSI capability has three main things that control its size.
4126 * 64-bit addressing adds 4 bytes. Per-Vector Masking adds 8 bytes and
4127 * causes the Extended data addressing piece to always be present.
4128 * Therefore we check first for pvm as it implies evt, effectively.
4129 */
4130 addr64 = (ctrl & PCI_MSI_64BIT_MASK) != 0;
4131 pvm = (ctrl & PCI_MSI_PVM_MASK) != 0;
4132 ext = (ctrl & PCI_MSI_EMD_MASK) != 0;
4133
4134 if (pvm && addr64) {
4135 *versp = &pcieadm_cap_vers_msi_64pvm;
4136 } else if (pvm) {
4137 *versp = &pcieadm_cap_vers_msi_32pvm;
4138 } else if (addr64 && ext) {
4139 *versp = &pcieadm_cap_vers_msi_64ext;
4140 } else if (addr64) {
4141 *versp = &pcieadm_cap_vers_msi_64;
4142 } else if (ext) {
4143 *versp = &pcieadm_cap_vers_msi_32ext;
4144 } else {
4145 *versp = &pcieadm_cap_vers_msi_32;
4146 }
4147
4148 *lenp = (*versp)->ppr_len;
4149 }
4150
4151 /*
4152 * The AER Capability is technically different for PCIe-PCI bridges. If we find
4153 * that device type here, then we need to use a different version information
4154 * rather than the actual set defined with the device (which have changed over
4155 * time).
4156 */
4157 static const pcieadm_cap_vers_t pcieadm_cap_vers_aer_bridge = {
4158 1, 0x4c, pcieadm_cap_aer_bridge
4159 };
4160
4161 static void
pcieadm_cap_info_aer(pcieadm_cfgspace_walk_t * walkp,const pcieadm_pci_cap_t * cap,uint32_t off,const pcieadm_cap_vers_t ** versp,uint32_t * lenp,const pcieadm_subcap_t ** subcap)4162 pcieadm_cap_info_aer(pcieadm_cfgspace_walk_t *walkp,
4163 const pcieadm_pci_cap_t *cap, uint32_t off,
4164 const pcieadm_cap_vers_t **versp, uint32_t *lenp,
4165 const pcieadm_subcap_t **subcap)
4166 {
4167 if (walkp->pcw_pcietype == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) {
4168 uint8_t vers;
4169
4170 *subcap = NULL;
4171 vers = walkp->pcw_data->pcb_u8[off + 2] & 0xf;
4172 if (vers != pcieadm_cap_vers_aer_bridge.ppr_vers) {
4173 warnx("encountered PCIe to PCI bridge with unknown "
4174 "AER capability version: %u", vers);
4175 *lenp = 0;
4176 *versp = NULL;
4177 return;
4178 }
4179 *lenp = pcieadm_cap_vers_aer_bridge.ppr_len;
4180 *versp = &pcieadm_cap_vers_aer_bridge;
4181 }
4182
4183 return (pcieadm_cap_info_vers(walkp, cap, off, versp, lenp, subcap));
4184 }
4185
4186 /*
4187 * The PCI-X capability varies depending on the header type of the device.
4188 * Therefore we simply use the device type to figure out what to do.
4189 */
4190 static pcieadm_cap_vers_t pcieadm_cap_vers_pcix_dev = {
4191 0, 0x8, pcieadm_cap_pcix_dev
4192 };
4193
4194 static pcieadm_cap_vers_t pcieadm_cap_vers_pcix_bridge = {
4195 0, 0x10, pcieadm_cap_pcix_bridge
4196 };
4197
4198 static void
pcieadm_cap_info_pcix(pcieadm_cfgspace_walk_t * walkp,const pcieadm_pci_cap_t * cap,uint32_t off,const pcieadm_cap_vers_t ** versp,uint32_t * lenp,const pcieadm_subcap_t ** subcap)4199 pcieadm_cap_info_pcix(pcieadm_cfgspace_walk_t *walkp,
4200 const pcieadm_pci_cap_t *cap, uint32_t off,
4201 const pcieadm_cap_vers_t **versp, uint32_t *lenp,
4202 const pcieadm_subcap_t **subcap)
4203 {
4204
4205 *subcap = NULL;
4206 switch (walkp->pcw_dtype) {
4207 case PCI_HEADER_ZERO:
4208 *versp = &pcieadm_cap_vers_pcix_dev;
4209 break;
4210 case PCI_HEADER_ONE:
4211 *versp = &pcieadm_cap_vers_pcix_bridge;
4212 break;
4213 default:
4214 warnx("encountered PCI-X capability with unsupported device "
4215 "type: 0x%x\n", walkp->pcw_dtype);
4216 *lenp = 0;
4217 *versp = NULL;
4218 return;
4219 }
4220
4221 *lenp = (*versp)->ppr_len;
4222 }
4223
4224 typedef struct pcieadm_cap_ht {
4225 uint32_t pch_capid;
4226 pcieadm_subcap_t pch_subcap;
4227 pcieadm_cap_vers_t pch_vers;
4228 } pcieadm_cap_ht_t;
4229
4230 static pcieadm_cap_ht_t pcieadm_ht_cap_pri = {
4231 0x00, { "pri", "Primary" }, { 0, 0x1c, pcieadm_cap_ht_pri }
4232 };
4233
4234 static pcieadm_cap_ht_t pcieadm_ht_cap_sec = {
4235 0x01, { "sec", "Secondary" }, { 0, 0x18, pcieadm_cap_ht_sec }
4236 };
4237
4238 static pcieadm_cap_ht_t pcieadm_ht_caps[] = {
4239 { 0x08, { "switch", "Switch" } },
4240 { 0x10, { "intr", "Interrupt Discovery and Configuration" },
4241 { 0, 8, pcieadm_cap_ht_intr } },
4242 { 0x11, { "rev", "Revision ID" } },
4243 { 0x12, { "unitid", "UnitID Clumping" } },
4244 { 0x13, { "extcfg", "Extended Configuration Space Access" } },
4245 { 0x14, { "addrmap", "Address Mapping" } },
4246 { 0x15, { "msi", "MSI Mapping" },
4247 { 0, 4, pcieadm_cap_ht_msi } },
4248 { 0x16, { "dir", "DirectRoute" } },
4249 { 0x17, { "vcset", "VCSet" } },
4250 { 0x18, { "retry", "Retry Mode" } },
4251 { 0x19, { "x86", "X86 Encoding" } },
4252 { 0x1a, { "gen3", "Gen3" } },
4253 { 0x1b, { "fle", "Function-Level Extension" } },
4254 { 0x1c, { "pm", "Power Management" } },
4255 { UINT32_MAX, NULL },
4256 };
4257
4258 static void
pcieadm_cap_info_ht(pcieadm_cfgspace_walk_t * walkp,const pcieadm_pci_cap_t * cap,uint32_t off,const pcieadm_cap_vers_t ** versp,uint32_t * lenp,const pcieadm_subcap_t ** subcap)4259 pcieadm_cap_info_ht(pcieadm_cfgspace_walk_t *walkp,
4260 const pcieadm_pci_cap_t *cap, uint32_t off,
4261 const pcieadm_cap_vers_t **versp, uint32_t *lenp,
4262 const pcieadm_subcap_t **subcap)
4263 {
4264 uint32_t base = walkp->pcw_data->pcb_u32[off / 4];
4265 uint32_t caplo = bitx32(base, 31, 29);
4266 pcieadm_cap_ht_t *htcap = NULL;
4267
4268 *versp = NULL;
4269 *lenp = 0;
4270 *subcap = NULL;
4271
4272 if (caplo > 1) {
4273 uint32_t capid = bitx32(base, 31, 27);
4274
4275 for (uint32_t i = 0; pcieadm_ht_caps[i].pch_capid != UINT32_MAX;
4276 i++) {
4277 if (capid == pcieadm_ht_caps[i].pch_capid) {
4278 htcap = &pcieadm_ht_caps[i];
4279 break;
4280 }
4281 }
4282 } else if (caplo == 0) {
4283 htcap = &pcieadm_ht_cap_pri;
4284 } else if (caplo == 1) {
4285 htcap = &pcieadm_ht_cap_sec;
4286 }
4287
4288 if (htcap == NULL) {
4289 warnx("encountered unknown HyperTransport Capability 0x%x",
4290 bitx32(base, 31, 27));
4291 return;
4292 }
4293
4294 *subcap = &htcap->pch_subcap;
4295 if (htcap->pch_vers.ppr_print != NULL) {
4296 *versp = &htcap->pch_vers;
4297 *lenp = htcap->pch_vers.ppr_len;
4298 }
4299 }
4300
4301 /*
4302 * Root Complex Link Declaration
4303 */
4304 static const pcieadm_regdef_t pcieadm_regdef_rcld_desc[] = {
4305 { 0, 3, "type", "Element Type", PRDV_STRVAL,
4306 .prd_val = { .prdv_strval = { "Configuration Space Element",
4307 "System Egress Port or internal sink",
4308 "Internal Root Complex Link" } } },
4309 { 8, 15, "num", "Number of Entries", PRDV_HEX },
4310 { 16, 23, "id", "Component ID", PRDV_HEX },
4311 { 24, 31, "port", "Port Number", PRDV_HEX },
4312 { -1, -1, NULL }
4313 };
4314
4315 static const pcieadm_regdef_t pcieadm_regdef_rcld_link[] = {
4316 { 0, 0, "valid", "Link Valid", PRDV_STRVAL,
4317 .prd_val = { .prdv_strval = { "no", "yes" } } },
4318 { 1, 1, "type", "Link Type", PRDV_STRVAL,
4319 .prd_val = { .prdv_strval = { "RCRB", "Configuration Space" } } },
4320 { 2, 2, "rcrb", "Assosciate RCRB", PRDV_STRVAL,
4321 .prd_val = { .prdv_strval = { "no", "yes" } } },
4322 { 16, 23, "tid", "Target Component ID", PRDV_HEX },
4323 { 24, 31, "tport", "Target Port Number", PRDV_HEX },
4324 { -1, -1, NULL }
4325 };
4326
4327 /*
4328 * Print a variable number of Root Complex Links.
4329 */
4330 static void
pcieadm_cfgspace_print_rcld(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)4331 pcieadm_cfgspace_print_rcld(pcieadm_cfgspace_walk_t *walkp,
4332 const pcieadm_cfgspace_print_t *print, const void *arg)
4333 {
4334 uint_t nlinks = walkp->pcw_data->pcb_u8[walkp->pcw_capoff + 5];
4335
4336 for (uint_t i = 0; i < nlinks; i++) {
4337 char mshort[32], mhuman[128];
4338 pcieadm_cfgspace_print_t p;
4339 uint16_t off = print->pcp_off + i * 0x10;
4340 uint8_t type = walkp->pcw_data->pcb_u8[walkp->pcw_capoff + off];
4341
4342 (void) snprintf(mshort, sizeof (mshort), "link%udesc", i);
4343 (void) snprintf(mhuman, sizeof (mhuman), "Link %u Description");
4344
4345 p.pcp_off = off;
4346 p.pcp_len = 4;
4347 p.pcp_short = mshort;
4348 p.pcp_human = mhuman;
4349 p.pcp_print = pcieadm_cfgspace_print_regdef;
4350 p.pcp_arg = pcieadm_regdef_rcld_link;
4351
4352 p.pcp_print(walkp, &p, p.pcp_arg);
4353
4354 /*
4355 * The way that we print the link depends on the actual type of
4356 * link which is in bit 2 of the link description.
4357 */
4358 p.pcp_off += 8;
4359
4360 if ((type & (1 << 1)) == 0) {
4361 (void) snprintf(mshort, sizeof (mshort),
4362 "link%uaddr", i);
4363 (void) snprintf(mhuman, sizeof (mhuman),
4364 "Link %u Address");
4365 p.pcp_len = 8;
4366 p.pcp_print = pcieadm_cfgspace_print_hex;
4367 p.pcp_arg = NULL;
4368
4369 p.pcp_print(walkp, &p, p.pcp_arg);
4370 } else {
4371 warnx("encountered unsupported RCLD Link Address");
4372 }
4373 }
4374 }
4375
4376 static const pcieadm_cfgspace_print_t pcieadm_cap_rcld[] = {
4377 { 0x0, 4, "caphdr", "Capability Header",
4378 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
4379 { 0x4, 4, "desc", "Self Description",
4380 pcieadm_cfgspace_print_regdef, pcieadm_regdef_rcld_desc },
4381 { 0x10, 0x10, "link", "Link Entry", pcieadm_cfgspace_print_rcld },
4382 { -1, -1, NULL }
4383 };
4384
4385
4386 /*
4387 * Physical Layer 32.0 GT/s Capability
4388 */
4389 static const pcieadm_regdef_t pcieadm_regdef_32g_cap[] = {
4390 { 0, 0, "eqbyp", "Equalization Bypass to Highest Rate", PRDV_STRVAL,
4391 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
4392 { 1, 1, "noeq", "No Equalization Needed", PRDV_STRVAL,
4393 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
4394 { 8, 8, "mts0", "Modified TS Usage Mode 0 - PCI Express", PRDV_STRVAL,
4395 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
4396 { 9, 9, "mts1", "Modified TS Usage Mode 1 - Training Set", PRDV_STRVAL,
4397 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
4398 { 10, 10, "mts2", "Modified TS Usage Mode 2 - Alternate Protocol",
4399 PRDV_STRVAL, .prd_val = { .prdv_strval = { "unsupported",
4400 "supported" } } },
4401 /*
4402 * Bits 11 to 15 are defined as reserved for future use here as
4403 * read-only bits. Add them here once they have actual definitions.
4404 */
4405 { -1, -1, NULL }
4406 };
4407
4408 static const pcieadm_regdef_t pcieadm_regdef_32g_ctl[] = {
4409 { 0, 0, "eqbyp", "Equalization Bypass to Highest Rate", PRDV_STRVAL,
4410 .prd_val = { .prdv_strval = { "enabled", "disabled" } } },
4411 { 1, 1, "noeq", "No Equalization Needed", PRDV_STRVAL,
4412 .prd_val = { .prdv_strval = { "enabled", "disabled" } } },
4413 { 8, 10, "mts", "Modified TS Usage Mode Selected", PRDV_STRVAL,
4414 .prd_val = { .prdv_strval = { "PCIe", "training set messages",
4415 "alternate protocol negotiation" } } },
4416 { -1, -1, NULL }
4417 };
4418
4419 static const pcieadm_regdef_t pcieadm_regdef_32g_sts[] = {
4420 { 0, 0, "eqcomp", "Equalization 32.0 GT/s Complete", PRDV_STRVAL,
4421 .prd_val = { .prdv_strval = { "incomplete", "complete" } } },
4422 { 1, 1, "eqp1", "Equalization 32.0 GT/s Phase 1", PRDV_STRVAL,
4423 .prd_val = { .prdv_strval = { "incomplete", "complete" } } },
4424 { 2, 2, "eqp2", "Equalization 32.0 GT/s Phase 2", PRDV_STRVAL,
4425 .prd_val = { .prdv_strval = { "incomplete", "complete" } } },
4426 { 3, 3, "eqp3", "Equalization 32.0 GT/s Phase 3", PRDV_STRVAL,
4427 .prd_val = { .prdv_strval = { "incomplete", "complete" } } },
4428 { 4, 4, "req", "Link Equalization Request 32.0 GT/s", PRDV_HEX },
4429 { 5, 5, "mts", "Modified TS Received", PRDV_STRVAL,
4430 .prd_val = { .prdv_strval = { "no", "yes" } } },
4431 { 6, 7, "rxelbc", "Received Enhanced Link Behavior Control",
4432 PRDV_STRVAL, .prd_val = { .prdv_strval = {
4433 "full equalization required", "equalization bypass to highest rate",
4434 "no equalization needed", "modified TS1/TS2 ordered sets" } } },
4435 { 8, 8, "txpre", "Transmitter Precoding", PRDV_STRVAL,
4436 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
4437 { 9, 9, "prereq", "Transmitter Precoding Request", PRDV_STRVAL,
4438 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
4439 { 10, 10, "noeqrx", "No Equalization Needed Received", PRDV_STRVAL,
4440 .prd_val = { .prdv_strval = { "no", "yes" } } },
4441 { -1, -1, NULL }
4442 };
4443
4444 static const pcieadm_regdef_t pcieadm_regdef_32g_rxts1[] = {
4445 { 0, 2, "mts", "Modified TS Usage Mode Selected", PRDV_STRVAL,
4446 .prd_val = { .prdv_strval = { "PCIe", "training set messages",
4447 "alternate protocol negotiation" } } },
4448 { 3, 15, "info", "Received Modified TS Information 1", PRDV_HEX },
4449 { 16, 31, "vendor", "Received Modified TS Vendor ID", PRDV_HEX },
4450 { -1, -1, NULL }
4451 };
4452
4453 static const pcieadm_regdef_t pcieadm_regdef_32g_rxts2[] = {
4454 { 0, 23, "info", "Received Modified TS Information 2", PRDV_HEX },
4455 { 24, 25, "apnsts", "Alternate Protocol Negotiation Status",
4456 PRDV_STRVAL, .prd_val = { .prdv_strval = { "not supported",
4457 "disabled", "failed", "succeeded" } } },
4458 { -1, -1, NULL }
4459 };
4460
4461 static const pcieadm_regdef_t pcieadm_regdef_32g_txts1[] = {
4462 { 0, 2, "mts", "Transmitted Modified TS Usage Mode", PRDV_STRVAL,
4463 .prd_val = { .prdv_strval = { "PCIe", "training set messages",
4464 "alternate protocol negotiation" } } },
4465 { 3, 15, "info", "Transmitted Modified TS Information 1", PRDV_HEX },
4466 { 16, 31, "vendor", "Transmitted Modified TS Vendor ID", PRDV_HEX },
4467 { -1, -1, NULL }
4468 };
4469
4470 static const pcieadm_regdef_t pcieadm_regdef_32g_txts2[] = {
4471 { 0, 23, "info", "Transmitted Modified TS Information 2", PRDV_HEX },
4472 { 24, 25, "apnsts", "Alternate Protocol Negotiation Status",
4473 PRDV_STRVAL, .prd_val = { .prdv_strval = { "not supported",
4474 "disabled", "failed", "succeeded" } } },
4475 { -1, -1, NULL }
4476 };
4477
4478 static const pcieadm_regdef_t pcieadm_regdef_32g_eq[] = {
4479 { 0, 3, "dstxpre", "Downstream Port 32.0 GT/s Transmitter Preset",
4480 PRDV_HEX },
4481 { 4, 7, "ustxpre", "Upstream Port 32.0 GT/s Transmitter Preset",
4482 PRDV_HEX },
4483 { -1, -1, NULL }
4484 };
4485
4486 static void
pcieadm_cfgspace_print_32geq(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)4487 pcieadm_cfgspace_print_32geq(pcieadm_cfgspace_walk_t *walkp,
4488 const pcieadm_cfgspace_print_t *print, const void *arg)
4489 {
4490 if (walkp->pcw_nlanes == 0) {
4491 warnx("failed to capture lane count, but somehow have "
4492 "Physical Layer 32.0 GT/s cap");
4493 return;
4494 }
4495
4496 for (uint_t i = 0; i < walkp->pcw_nlanes; i++) {
4497 char eqshort[32], eqhuman[128];
4498 pcieadm_cfgspace_print_t p;
4499
4500 (void) snprintf(eqshort, sizeof (eqshort), "lane%u", i);
4501 (void) snprintf(eqhuman, sizeof (eqhuman), "Lane %u EQ Control",
4502 i);
4503 p.pcp_off = print->pcp_off + i * 1;
4504 p.pcp_len = 1;
4505 p.pcp_short = eqshort;
4506 p.pcp_human = eqhuman;
4507 p.pcp_print = pcieadm_cfgspace_print_regdef;
4508 p.pcp_arg = pcieadm_regdef_32g_eq;
4509
4510 p.pcp_print(walkp, &p, p.pcp_arg);
4511 }
4512 }
4513
4514 static const pcieadm_cfgspace_print_t pcieadm_cap_32g[] = {
4515 { 0x0, 4, "caphdr", "Capability Header",
4516 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
4517 { 0x4, 4, "cap", "32.0 GT/s Capabilities",
4518 pcieadm_cfgspace_print_regdef, pcieadm_regdef_32g_cap },
4519 { 0x8, 4, "ctl", "32.0 GT/s Control",
4520 pcieadm_cfgspace_print_regdef, pcieadm_regdef_32g_ctl },
4521 { 0xc, 4, "sts", "32.0 GT/s Status",
4522 pcieadm_cfgspace_print_regdef, pcieadm_regdef_32g_sts },
4523 { 0x10, 4, "rxts1", "Received Modified TS Data 1",
4524 pcieadm_cfgspace_print_regdef, pcieadm_regdef_32g_rxts1 },
4525 { 0x14, 4, "rxts2", "Received Modified TS Data 2",
4526 pcieadm_cfgspace_print_regdef, pcieadm_regdef_32g_rxts2 },
4527 { 0x18, 4, "txts1", "Transmitted Modified TS Data 1",
4528 pcieadm_cfgspace_print_regdef, pcieadm_regdef_32g_txts1 },
4529 { 0x1c, 4, "txts2", "Transmitted Modified TS Data 2",
4530 pcieadm_cfgspace_print_regdef, pcieadm_regdef_32g_txts2 },
4531 { 0x20, 1, "eqctl", "32.0 GT/s EQ Control",
4532 pcieadm_cfgspace_print_32geq },
4533 { -1, -1, NULL }
4534 };
4535
4536 /*
4537 * Native PCIe Enclosure Management
4538 */
4539 static const pcieadm_regdef_t pcieadm_regdef_npem_cap[] = {
4540 { 0, 0, "npem", "NPEM", PRDV_STRVAL,
4541 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
4542 { 1, 1, "reset", "NPEM Reset", PRDV_STRVAL,
4543 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
4544 { 2, 2, "ok", "NPEM OK", PRDV_STRVAL,
4545 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
4546 { 3, 3, "loc", "NPEM Locate", PRDV_STRVAL,
4547 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
4548 { 4, 4, "fail", "NPEM Fail", PRDV_STRVAL,
4549 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
4550 { 5, 5, "rb", "NPEM Rebuild", PRDV_STRVAL,
4551 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
4552 { 6, 6, "pfa", "NPEM PFA", PRDV_STRVAL,
4553 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
4554 { 7, 7, "hs", "NPEM Hot Spare", PRDV_STRVAL,
4555 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
4556 { 8, 8, "crit", "NPEM In a Critical Array", PRDV_STRVAL,
4557 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
4558 { 9, 9, "fail", "NPEM In a Failed Array", PRDV_STRVAL,
4559 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
4560 { 10, 10, "invdt", "NPEM Invalid Device type", PRDV_STRVAL,
4561 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
4562 { 11, 11, "dis", "NPEM Disabled", PRDV_STRVAL,
4563 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
4564 { 24, 31, "es", "Enclosure-specific Capabilities", PRDV_HEX },
4565 { -1, -1, NULL }
4566 };
4567
4568 static const pcieadm_regdef_t pcieadm_regdef_npem_ctl[] = {
4569 { 0, 0, "npem", "NPEM", PRDV_STRVAL,
4570 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
4571 { 1, 1, "reset", "NPEM Initiate Reset", PRDV_STRVAL,
4572 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
4573 { 2, 2, "ok", "NPEM OK", PRDV_STRVAL,
4574 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
4575 { 3, 3, "loc", "NPEM Locate", PRDV_STRVAL,
4576 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
4577 { 4, 4, "fail", "NPEM Fail", PRDV_STRVAL,
4578 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
4579 { 5, 5, "rb", "NPEM Rebuild", PRDV_STRVAL,
4580 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
4581 { 6, 6, "pfa", "NPEM PFA", PRDV_STRVAL,
4582 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
4583 { 7, 7, "hs", "NPEM Hot Spare", PRDV_STRVAL,
4584 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
4585 { 8, 8, "crit", "NPEM In a Critical Array", PRDV_STRVAL,
4586 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
4587 { 9, 9, "fail", "NPEM In a Failed Array", PRDV_STRVAL,
4588 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
4589 { 10, 10, "invdt", "NPEM Invalid Device type", PRDV_STRVAL,
4590 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
4591 { 11, 11, "dis", "NPEM Disabled", PRDV_STRVAL,
4592 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
4593 { 24, 31, "es", "Enclosure-specific Control", PRDV_HEX },
4594 { -1, -1, NULL }
4595 };
4596
4597 static const pcieadm_regdef_t pcieadm_regdef_npem_sts[] = {
4598 { 0, 0, "ccmplt", "NPEM Command Complete", PRDV_STRVAL,
4599 .prd_val = { .prdv_strval = { "no", "yes" } } },
4600 { 24, 31, "es", "Enclosure-specific Status", PRDV_HEX },
4601 { -1, -1, NULL }
4602 };
4603
4604 static const pcieadm_cfgspace_print_t pcieadm_cap_npem[] = {
4605 { 0x0, 4, "caphdr", "Capability Header",
4606 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
4607 { 0x4, 4, "cap", "NPEM Capability",
4608 pcieadm_cfgspace_print_regdef, pcieadm_regdef_npem_cap },
4609 { 0x8, 4, "ctl", "NPEM Control",
4610 pcieadm_cfgspace_print_regdef, pcieadm_regdef_npem_ctl },
4611 { 0xc, 4, "sts", "NPEM Status",
4612 pcieadm_cfgspace_print_regdef, pcieadm_regdef_npem_sts },
4613 { -1, -1, NULL }
4614 };
4615
4616 /*
4617 * Alternate Protocol Capability
4618 */
4619 static const pcieadm_regdef_t pcieadm_regdef_ap_cap[] = {
4620 { 0, 7, "count", "Alternate Protocol Count", PRDV_HEX },
4621 { 8, 8, "sen", "Alternate Protocol Select Enable", PRDV_STRVAL,
4622 .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
4623 { -1, -1, NULL }
4624 };
4625
4626 static const pcieadm_regdef_t pcieadm_regdef_ap_ctl[] = {
4627 { 0, 7, "index", "Alternate Protocol Index Select", PRDV_HEX },
4628 { 8, 8, "apngen", "Alternate Protocol Negotiation Global Enable",
4629 PRDV_STRVAL, .prd_val = { .prdv_strval = { "disabled",
4630 "enabled" } } },
4631 { -1, -1, NULL }
4632 };
4633
4634 static const pcieadm_regdef_t pcieadm_regdef_ap_data1[] = {
4635 { 0, 2, "use", "Alternate Protocol Usage Information", PRDV_HEX },
4636 { 5, 15, "detail", "Alternate Protocol Details", PRDV_HEX },
4637 { 16, 31, "vendor", "Alternate Protocol Vendor ID", PRDV_HEX },
4638 { -1, -1, NULL }
4639 };
4640
4641 static const pcieadm_regdef_t pcieadm_regdef_ap_data2[] = {
4642 { 0, 23, "mts2", "Modified TS 2 Information", PRDV_HEX },
4643 { -1, -1, NULL }
4644 };
4645
4646 static const pcieadm_regdef_t pcieadm_regdef_ap_sen[] = {
4647 { 0, 0, "pcie", "Selective Enable Mask - PCIe", PRDV_STRVAL,
4648 .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
4649 { 1, 31, "other", "Selective Enable Mask - Other", PRDV_HEX },
4650 { -1, -1, NULL }
4651 };
4652
4653 /*
4654 * The Advanced Protocol Selective Enable Mask register is only present if a bit
4655 * in the capabilities register is present. As such, we need to check if it is
4656 * here before we try to read and print it.
4657 */
4658 static void
pcieadm_cfgspace_print_ap_sen(pcieadm_cfgspace_walk_t * walkp,const pcieadm_cfgspace_print_t * print,const void * arg)4659 pcieadm_cfgspace_print_ap_sen(pcieadm_cfgspace_walk_t *walkp,
4660 const pcieadm_cfgspace_print_t *print, const void *arg)
4661 {
4662 uint32_t ap_cap = pcieadm_cfgspace_getcap32(walkp, 4);
4663 pcieadm_cfgspace_print_t p;
4664
4665 if (bitx32(ap_cap, 8, 8) == 0)
4666 return;
4667
4668 (void) memcpy(&p, print, sizeof (*print));
4669 p.pcp_print = pcieadm_cfgspace_print_regdef;
4670 p.pcp_arg = pcieadm_regdef_ap_sen;
4671
4672 p.pcp_print(walkp, &p, p.pcp_arg);
4673 }
4674
4675 static const pcieadm_cfgspace_print_t pcieadm_cap_ap[] = {
4676 { 0x0, 4, "caphdr", "Capability Header",
4677 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
4678 { 0x4, 4, "cap", "Alternate Protocol Capabilities",
4679 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ap_cap },
4680 { 0x8, 4, "ctl", "Alternate Protocol Control",
4681 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ap_ctl },
4682 { 0xc, 4, "data1", "Alternate Protocol Data 1",
4683 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ap_data1 },
4684 { 0x10, 4, "data2", "Alternate Protocol Data 2",
4685 pcieadm_cfgspace_print_regdef, pcieadm_regdef_ap_data2 },
4686 { 0x14, 4, "sen", "Alternate Protocol Select Enable Mask",
4687 pcieadm_cfgspace_print_ap_sen },
4688 { -1, -1, NULL }
4689 };
4690
4691 /*
4692 * Root Complex Event Collector Endpoint Association
4693 */
4694 static const pcieadm_regdef_t pcieadm_regdef_rcecea_bus[] = {
4695 { 8, 15, "next", "RCEC Next Bus", PRDV_HEX },
4696 { 16, 23, "last", "RCEC Last Bus", PRDV_HEX },
4697 { -1, -1, NULL }
4698 };
4699
4700 static const pcieadm_cfgspace_print_t pcieadm_cap_rcecea_v1[] = {
4701 { 0x0, 4, "caphdr", "Capability Header",
4702 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
4703 { 0x4, 4, "bitmap", "Association Bitmap for RCiEPs",
4704 pcieadm_cfgspace_print_hex },
4705 { -1, -1, NULL }
4706 };
4707
4708 static const pcieadm_cfgspace_print_t pcieadm_cap_rcecea_v2[] = {
4709 { 0x0, 4, "caphdr", "Capability Header",
4710 pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
4711 { 0x4, 4, "bitmap", "Association Bitmap for RCiEPs",
4712 pcieadm_cfgspace_print_hex },
4713 { 0x8, 4, "bus", "RCEC Associated Bus Numbers",
4714 pcieadm_cfgspace_print_regdef, pcieadm_regdef_rcecea_bus },
4715 { -1, -1, NULL }
4716 };
4717
4718 /*
4719 * Readiness Time Reporting
4720 */
4721
4722 /*
4723 * A single readiness time constitutes a 9 bit value and 3 bit scale. The actual
4724 * register contains a value in nanosconds which is calculated as value *
4725 * 32^scale. We take advantage of the fact that this is a power of 2 and
4726 * therefore we can calculate 32^scale by taking advantage that 32 is 2^5 and
4727 * that this is really 2^(scale * 5) which becomes a simple bit shift.
4728 */
4729 static void
pcieadm_regdef_print_rtr(pcieadm_cfgspace_walk_t * walkp,const pcieadm_regdef_t * regdef,uint64_t reg)4730 pcieadm_regdef_print_rtr(pcieadm_cfgspace_walk_t *walkp,
4731 const pcieadm_regdef_t *regdef, uint64_t reg)
4732 {
4733 uint64_t scale = bitx64(reg, 11, 9);
4734 uint64_t time = bitx64(reg, 8, 0);
4735
4736 time *= 1ULL << (scale * 5);
4737 pcieadm_field_printf(walkp, regdef->prd_short, regdef->prd_human,
4738 reg, "%" PRIu64 " ns\n", time);
4739 }
4740
4741 static const pcieadm_regdef_t pcieadm_regdef_rtr1[] = {
4742 { 0, 11, "reset", "Reset Time", PRDV_CUSTOM,
4743 .prd_val = { .prdv_func = pcieadm_regdef_print_rtr } },
4744 { 12, 23, "dlup", "DL_Up Time", PRDV_CUSTOM,
4745 .prd_val = { .prdv_func = pcieadm_regdef_print_rtr } },
4746 { 31, 31, "valid", "Valid", PRDV_STRVAL,
4747 .prd_val = { .prdv_strval = { "invalid", "valid" } } },
4748 { -1, -1, NULL }
4749 };
4750
4751 static const pcieadm_regdef_t pcieadm_regdef_rtr2[] = {
4752 { 0, 11, "flr", "FLR Time", PRDV_CUSTOM,
4753 .prd_val = { .prdv_func = pcieadm_regdef_print_rtr } },
4754 { 12, 23, "d3d0", "D3_HOT to D0 Time", PRDV_CUSTOM,
4755 .prd_val = { .prdv_func = pcieadm_regdef_print_rtr } },
4756 { -1, -1, NULL }
4757 };
4758
4759 static const pcieadm_cfgspace_print_t pcieadm_cap_rtr[] = {
4760 { 0x0, 4, "caphdr", "Capability Header", pcieadm_cfgspace_print_regdef,
4761 pcieadm_regdef_pcie_caphdr },
4762 { 0x4, 4, "rtr1", "Readiness Time Reporting Register 1",
4763 pcieadm_cfgspace_print_regdef, pcieadm_regdef_rtr1 },
4764 { 0x8, 4, "rtr2", "Readiness Time Reporting Register 2",
4765 pcieadm_cfgspace_print_regdef, pcieadm_regdef_rtr2 },
4766 { -1, -1, NULL }
4767 };
4768
4769 static const pcieadm_pci_cap_t pcieadm_pci_caps[] = {
4770 { PCI_CAP_ID_PM, "pcipm", "PCI Power Management",
4771 pcieadm_cap_info_pcipm, { { 2, 8, pcieadm_cap_pcipm_v3 },
4772 { 3, 8, pcieadm_cap_pcipm_v3 } } },
4773 { PCI_CAP_ID_AGP, "agp", "Accelerated Graphics Port" },
4774 { PCI_CAP_ID_VPD, "vpd", "Vital Product Data", pcieadm_cap_info_fixed,
4775 { { 0, 8, pcieadm_cap_vpd } } },
4776 { PCI_CAP_ID_SLOT_ID, "slot", "Slot Identification" },
4777 { PCI_CAP_ID_MSI, "msi", "Message Signaled Interrupts",
4778 pcieadm_cap_info_msi },
4779 { PCI_CAP_ID_cPCI_HS, "cpci", "CompactPCI Hot Swap" },
4780 { PCI_CAP_ID_PCIX, "pcix", "PCI-X", pcieadm_cap_info_pcix },
4781 { PCI_CAP_ID_HT, "ht", "HyperTransport", pcieadm_cap_info_ht },
4782 { PCI_CAP_ID_VS, "vs", "Vendor Specific", pcieadm_cap_info_fixed,
4783 { { 0, 3, pcieadm_cap_vs } } },
4784 { PCI_CAP_ID_DEBUG_PORT, "dbg", "Debug Port", pcieadm_cap_info_fixed,
4785 { { 0, 4, pcieadm_cap_debug } } },
4786 { PCI_CAP_ID_cPCI_CRC, "cpcicrc",
4787 "CompactPCI Central Resource Control" },
4788 { PCI_CAP_ID_PCI_HOTPLUG, "pcihp", "PCI Hot-Plug" },
4789 { PCI_CAP_ID_P2P_SUBSYS, "bdgsub", "PCI Bridge Subsystem Vendor ID",
4790 pcieadm_cap_info_fixed, { 0, 8, pcieadm_cap_bridge_subsys } },
4791 { PCI_CAP_ID_AGP_8X, "agp8x", "AGP 8x" },
4792 { PCI_CAP_ID_SECURE_DEV, "secdev", "Secure Device" },
4793 { PCI_CAP_ID_PCI_E, "pcie", "PCI Express", pcieadm_cap_info_pcie },
4794 { PCI_CAP_ID_MSI_X, "msix", "MSI-X", pcieadm_cap_info_fixed,
4795 { { 0, 12, pcieadm_cap_msix } } },
4796 { PCI_CAP_ID_SATA, "sata", "Serial ATA Configuration",
4797 pcieadm_cap_info_fixed, { { 0, 8, pcieadm_cap_sata } } },
4798 /*
4799 * Note, the AF feature doesn't have a version but encodes a length in
4800 * the version field, so we cheat and use that.
4801 */
4802 { PCI_CAP_ID_FLR, "af", "Advanced Features", pcieadm_cap_info_vers,
4803 { { 6, 6, pcieadm_cap_af } } },
4804 { PCI_CAP_ID_EA, "ea", "Enhanced Allocation" },
4805 { PCI_CAP_ID_FPB, "fpb", "Flattening Portal Bridge" }
4806 };
4807
4808 static const pcieadm_pci_cap_t pcieadm_pcie_caps[] = {
4809 { 0, "null", "NULL Capability", pcieadm_cap_info_fixed,
4810 { { 0, 0x4, pcieadm_cap_null } } },
4811 { PCIE_EXT_CAP_ID_AER, "aer", "Advanced Error Reporting",
4812 pcieadm_cap_info_aer, { { 1, 0x38, pcieadm_cap_aer_v1 },
4813 { 2, 0x48, pcieadm_cap_aer_v2 } } },
4814 { PCIE_EXT_CAP_ID_VC, "vc", "Virtual Channel", pcieadm_cap_info_vers,
4815 { { 0x1, 0x1c, pcieadm_cap_vc } } },
4816 { PCIE_EXT_CAP_ID_SER, "sn", "Serial Number", pcieadm_cap_info_vers,
4817 { { 1, 0xc, pcieadm_cap_sn } } },
4818 { PCIE_EXT_CAP_ID_PWR_BUDGET, "pwrbudg", "Power Budgeting",
4819 pcieadm_cap_info_vers, { { 1, 0x10, pcieadm_cap_powbudg } } },
4820 { PCIE_EXT_CAP_ID_RC_LINK_DECL, "rcld",
4821 "Root Complex Link Declaration", pcieadm_cap_info_vers,
4822 { { 1, 0x1c, pcieadm_cap_rcld } } },
4823 { PCIE_EXT_CAP_ID_RC_INT_LINKCTRL, "rcilc",
4824 "Root Complex Internal Link Control" },
4825 { PCIE_EXT_CAP_ID_RC_EVNT_CEA, "rcecea",
4826 "Root Complex Event Collector Endpoint Association",
4827 pcieadm_cap_info_vers, { { 1, 0x8, pcieadm_cap_rcecea_v1 },
4828 { 2, 0xc, pcieadm_cap_rcecea_v2 } } },
4829 { PCIE_EXT_CAP_ID_MFVC, "mfvc", "Multi-Function Virtual Channel" },
4830 { PCIE_EXT_CAP_ID_VC_WITH_MFVC, "vcwmfvc", "Virtual Channel with MFVC",
4831 pcieadm_cap_info_vers, { { 0x1, 0x1c, pcieadm_cap_vc } } },
4832 { PCIE_EXT_CAP_ID_RCRB, "rcrb", "Root Complex Register Block" },
4833 { PCIE_EXT_CAP_ID_VS, "vsec", "Vendor Specific Extended Capability",
4834 pcieadm_cap_info_vers, { { 1, 0x8, pcieadm_cap_vsec } } },
4835 { PCIE_EXT_CAP_ID_CAC, "cac", "Configuration Access Correlation" },
4836 { PCIE_EXT_CAP_ID_ACS, "acs", "Access Control Services",
4837 pcieadm_cap_info_vers, { { 1, 0x8, pcieadm_cap_acs } } },
4838 { PCIE_EXT_CAP_ID_ARI, "ari", "Alternative Routing-ID Interpretation",
4839 pcieadm_cap_info_vers, { { 1, 0x8, pcieadm_cap_ari } } },
4840 { PCIE_EXT_CAP_ID_ATS, "ats", "Access Translation Services",
4841 pcieadm_cap_info_vers, { { 1, 0x8, pcieadm_cap_ats } } },
4842 { PCIE_EXT_CAP_ID_SRIOV, "sriov", "Single Root I/O Virtualization",
4843 pcieadm_cap_info_vers, { { 1, 0x40, pcieadm_cap_sriov } } },
4844 { PCIE_EXT_CAP_ID_MRIOV, "mriov", "Multi-Root I/O Virtualization" },
4845 { PCIE_EXT_CAP_ID_MULTICAST, "mcast", "Multicast",
4846 pcieadm_cap_info_vers, { { 1, 0x30, pcieadm_cap_mcast } } },
4847 { PCIE_EXT_CAP_ID_PGREQ, "pgreq", "Page Request",
4848 pcieadm_cap_info_vers, { { 1, 0x10, pcieadm_cap_pgreq } } },
4849 { PCIE_EXT_CAP_ID_EA, "ea", "Enhanced Allocation" },
4850 { PCIE_EXT_CAP_ID_RESIZE_BAR, "rbar", "Resizable Bar" },
4851 { PCIE_EXT_CAP_ID_DPA, "dpa", "Dynamic Power Allocation",
4852 pcieadm_cap_info_vers, { { 1, 0x10, pcieadm_cap_dpa } } },
4853 { PCIE_EXT_CAP_ID_TPH_REQ, "tph", "TPH Requester",
4854 pcieadm_cap_info_vers, { { 1, 0xc, pcieadm_cap_tph } } },
4855 { PCIE_EXT_CAP_ID_LTR, "ltr", "Latency Tolerance Reporting",
4856 pcieadm_cap_info_vers, { { 1, 0x8, pcieadm_cap_ltr } } },
4857 { PCIE_EXT_CAP_ID_PCIE2, "pcie2", "Secondary PCI Express",
4858 pcieadm_cap_info_vers, { { 1, 0xc, pcieadm_cap_pcie2 } } },
4859 { PCIE_EXT_CAP_ID_PASID, "pasid", "Process Address Space ID",
4860 pcieadm_cap_info_vers, { { 1, 0x8, pcieadm_cap_pasid } } },
4861 { PCIE_EXT_CAP_ID_LNR, "lnr", "LN Requester" },
4862 { PCIE_EXT_CAP_ID_DPC, "dpc", "Downstream Port Containment",
4863 pcieadm_cap_info_vers, { { 1, 0x30, pcieadm_cap_dpc } } },
4864 { PCIE_EXT_CAP_ID_L1PM, "l1pm", "L1 PM Substates",
4865 pcieadm_cap_info_vers, { { 1, 0x10, pcieadm_cap_l1pm_v1 },
4866 { 2, 0x14, pcieadm_cap_l1pm_v2 } } },
4867 { PCIE_EXT_CAP_ID_PTM, "ptm", "Precision Time Management",
4868 pcieadm_cap_info_vers, { { 1, 0xc, pcieadm_cap_info_ptm } } },
4869 { PCIE_EXT_CAP_ID_FRS, "frs", "FRS Queueing" },
4870 { PCIE_EXT_CAP_ID_RTR, "rtr", "Readiness Time Reporting",
4871 pcieadm_cap_info_vers, { { 1, 0xc, pcieadm_cap_rtr } } },
4872 /*
4873 * When we encounter a designated vendor specification, in particular,
4874 * for CXL, we'll want to set ppc_subcap so we can use reasonable
4875 * filtering.
4876 */
4877 { PCIE_EXT_CAP_ID_DVS, "dvsec",
4878 "Designated Vendor-Specific Extended Capability" },
4879 { PCIE_EXT_CAP_ID_VFRBAR, "vfrbar", "Virtual Function Resizable BAR" },
4880 { PCIE_EXT_CAP_ID_DLF, "dlf", "Data Link Feature",
4881 pcieadm_cap_info_vers, { { 1, 0xc, pcieadm_cap_dlf } } },
4882 { PCIE_EXT_CAP_ID_PL16GT, "pl16g", "Physical Layer 16.0 GT/s",
4883 pcieadm_cap_info_vers, { { 1, 0x22, pcieadm_cap_16g } } },
4884 { PCIE_EXT_CAP_ID_LANE_MARGIN, "margin",
4885 "Lane Margining at the Receiver", pcieadm_cap_info_vers,
4886 { { 1, 0x8, pcieadm_cap_margin } } },
4887 { PCIE_EXT_CAP_ID_HIEARCHY_ID, "hierid", "Hierarchy ID" },
4888 { PCIE_EXT_CAP_ID_NPEM, "npem", "Native PCIe Enclosure Management",
4889 pcieadm_cap_info_vers, { { 1, 0x10, pcieadm_cap_npem } } },
4890 /*
4891 * The sizing of the 32.0 GT/s physical layer requires that there's at
4892 * least one lane's worth of information and the device is required to
4893 * pad that out to 4-byte alignment.
4894 */
4895 { PCIE_EXT_CAP_ID_PL32GT, "pl32g", "Physical Layer 32.0 GT/s",
4896 pcieadm_cap_info_vers, { { 1, 0x24, pcieadm_cap_32g } } },
4897 { PCIE_EXT_CAP_ID_AP, "ap", "Alternative Protocol",
4898 pcieadm_cap_info_vers, { { 1, 0x14, pcieadm_cap_ap } } },
4899 { PCIE_EXT_CAP_ID_SFI, "sfi", "System Firmware Intermediary" },
4900 { PCIE_EXT_CAP_ID_SHDW_FUNC, "sfunc", "Shadow Functions" },
4901 { PCIE_EXT_CAP_ID_DOE, "doe", "Data Object Exchange" },
4902 { PCIE_EXT_CAP_ID_DEV3, "dev3", "Device 3" },
4903 { PCIE_EXT_CAP_ID_IDE, "ide", "Integrity and Data Encryption" },
4904 { PCIE_EXT_CAP_ID_PL64GT, "pl64g", "Physical Layer 64.0 GT/s" },
4905 { PCIE_EXT_CAP_ID_FLIT_LOG, "fltlog", "Flit Logging" },
4906 { PCIE_EXT_CAP_ID_FLIT_PERF, "fltperf",
4907 "Flit Performance Measurement" },
4908 { PCIE_EXT_CAP_ID_FLIT_ERR, "flterr", "Flit Error Injection" },
4909 { PCIE_EXT_CAP_ID_SVC, "svc", "Streamlined Virtual Channel" },
4910 { PCIE_EXT_CAP_ID_MMIO_RBL, "mrbl", "MMIO Register Block Locator" },
4911 { PCIE_EXT_CAP_ID_NOP_FLIT, "nop", "NOP Flit" },
4912 { PCIE_EXT_CAP_ID_SIOV, "siov", "Scalable I/O Virtualization" },
4913 { PCIE_EXT_CAP_ID_PL128GT, "pl128g", "Physical Layer 128.0 GT/s" },
4914 { PCIE_EXT_CAP_ID_CAP_DATA, "cdata", "Captured Data" }
4915 };
4916
4917 static const pcieadm_pci_cap_t *
pcieadm_cfgspace_match_cap(uint32_t capid,boolean_t pcie)4918 pcieadm_cfgspace_match_cap(uint32_t capid, boolean_t pcie)
4919 {
4920 uint_t ncaps;
4921 const pcieadm_pci_cap_t *caps;
4922
4923 if (pcie) {
4924 ncaps = ARRAY_SIZE(pcieadm_pcie_caps);
4925 caps = pcieadm_pcie_caps;
4926 } else {
4927 ncaps = ARRAY_SIZE(pcieadm_pci_caps);
4928 caps = pcieadm_pci_caps;
4929 }
4930
4931 for (uint_t i = 0; i < ncaps; i++) {
4932 if (caps[i].ppc_id == capid) {
4933 return (&caps[i]);
4934 }
4935 }
4936
4937 return (NULL);
4938 }
4939
4940 static void
pcieadm_cfgspace_print_cap(pcieadm_cfgspace_walk_t * walkp,uint_t capid,const pcieadm_pci_cap_t * cap_info,const pcieadm_cap_vers_t * vers_info,const pcieadm_subcap_t * subcap)4941 pcieadm_cfgspace_print_cap(pcieadm_cfgspace_walk_t *walkp, uint_t capid,
4942 const pcieadm_pci_cap_t *cap_info, const pcieadm_cap_vers_t *vers_info,
4943 const pcieadm_subcap_t *subcap)
4944 {
4945 boolean_t filter = B_FALSE;
4946
4947 /*
4948 * If we don't recognize the capability, print out the ID if we're not
4949 * filtering and not in parsable mode.
4950 */
4951 if (cap_info == NULL) {
4952 if (walkp->pcw_ofmt == NULL &&
4953 pcieadm_cfgspace_filter(walkp, NULL)) {
4954 warnx("encountered unknown capability ID 0x%x "
4955 "unable to print or list", capid);
4956 pcieadm_print("Unknown Capability (0x%x)\n", capid);
4957 }
4958 return;
4959 }
4960
4961 /*
4962 * Check to see if we should print this and in particular, if there's
4963 * both a capability or subcapability, we need to try and match both.
4964 * The reason that the calls to check the filters are conditioned on
4965 * pcw_ofmt is that when we're in parsable mode, we cannot match a
4966 * top-level capability since it's an arbitrary number of fields.
4967 */
4968 if (walkp->pcw_ofmt == NULL) {
4969 filter = pcieadm_cfgspace_filter(walkp, cap_info->ppc_short);
4970 }
4971 pcieadm_strfilt_push(walkp, cap_info->ppc_short);
4972 if (subcap != NULL) {
4973 if (walkp->pcw_ofmt == NULL) {
4974 boolean_t subfilt = pcieadm_cfgspace_filter(walkp,
4975 subcap->psub_short);
4976 filter = subfilt || filter;
4977 }
4978 pcieadm_strfilt_push(walkp, subcap->psub_short);
4979 }
4980
4981
4982 if (walkp->pcw_ofmt == NULL && filter) {
4983 if ((walkp->pcw_flags & PCIEADM_CFGSPACE_F_SHORT) != 0) {
4984 if (subcap != NULL) {
4985 pcieadm_print("%s Capability - %s (%s) "
4986 "(0x%x)\n", cap_info->ppc_human,
4987 subcap->psub_human,
4988 walkp->pcw_filt->pstr_curgen, capid);
4989 } else {
4990 pcieadm_print("%s Capability (%s) (0x%x)\n",
4991 cap_info->ppc_human,
4992 walkp->pcw_filt->pstr_curgen, capid);
4993 }
4994 } else {
4995 if (subcap != NULL) {
4996 pcieadm_print("%s Capability - %s (0x%x)\n",
4997 cap_info->ppc_human, subcap->psub_human,
4998 capid);
4999 } else {
5000 pcieadm_print("%s Capability (0x%x)\n",
5001 cap_info->ppc_human, capid);
5002 }
5003 }
5004 }
5005
5006 if (vers_info != NULL) {
5007 const pcieadm_cfgspace_print_t *print;
5008
5009 pcieadm_indent();
5010 for (print = vers_info->ppr_print;
5011 print->pcp_short != NULL; print++) {
5012 VERIFY3P(print->pcp_print, !=, NULL);
5013 print->pcp_print(walkp, print,
5014 print->pcp_arg);
5015 }
5016 pcieadm_deindent();
5017 } else {
5018 if (subcap != NULL) {
5019 warnx("Unable to print or list %s - %s (no support or "
5020 "missing version info)", cap_info->ppc_human,
5021 subcap->psub_human);
5022 } else {
5023 warnx("Unable to print or list %s (no support or "
5024 "missing version info)", cap_info->ppc_human);
5025 }
5026 }
5027
5028 if (subcap != NULL) {
5029 pcieadm_strfilt_pop(walkp);
5030 }
5031 pcieadm_strfilt_pop(walkp);
5032 }
5033
5034 static void
pcieadm_cfgspace_write(int fd,const uint8_t * source,size_t len)5035 pcieadm_cfgspace_write(int fd, const uint8_t *source, size_t len)
5036 {
5037 size_t off = 0;
5038
5039 while (len > 0) {
5040 ssize_t ret = write(fd, source + off, len - off);
5041 if (ret < 0) {
5042 err(EXIT_FAILURE, "failed to write config space to "
5043 "output file");
5044 }
5045
5046 off += ret;
5047 len -= ret;
5048 }
5049 }
5050
5051 void
pcieadm_cfgspace(pcieadm_t * pcip,pcieadm_cfgspace_op_t op,pcieadm_cfgspace_f readf,int fd,void * readarg,uint_t nfilts,pcieadm_cfgspace_filter_t * filters,pcieadm_cfgspace_flags_t flags,ofmt_handle_t ofmt)5052 pcieadm_cfgspace(pcieadm_t *pcip, pcieadm_cfgspace_op_t op,
5053 pcieadm_cfgspace_f readf, int fd, void *readarg, uint_t nfilts,
5054 pcieadm_cfgspace_filter_t *filters, pcieadm_cfgspace_flags_t flags,
5055 ofmt_handle_t ofmt)
5056 {
5057 uint_t type;
5058 uint16_t cap;
5059 pcieadm_cfgspace_data_t data;
5060 pcieadm_cfgspace_walk_t walk;
5061 const char *headstr, *headshort;
5062 const pcieadm_cfgspace_print_t *header;
5063 boolean_t capsup = B_FALSE, extcfg = B_FALSE;
5064 uint_t ncaps;
5065
5066 walk.pcw_pcieadm = pcip;
5067 walk.pcw_op = op;
5068 walk.pcw_data = &data;
5069 walk.pcw_outfd = fd;
5070 walk.pcw_capoff = 0;
5071 walk.pcw_nlanes = 0;
5072 walk.pcw_nfilters = nfilts;
5073 walk.pcw_filters = filters;
5074 walk.pcw_flags = flags;
5075 walk.pcw_ofmt = ofmt;
5076 walk.pcw_filt = NULL;
5077
5078 /*
5079 * Start by reading all of the basic 40-byte config space header in one
5080 * fell swoop.
5081 */
5082 for (uint32_t i = 0; i < PCI_CAP_PTR_OFF / 4; i++) {
5083 if (!readf(i * 4, 4, &data.pcb_u32[i], readarg)) {
5084 errx(EXIT_FAILURE, "failed to read offset %u from "
5085 "configuration space", i * 4);
5086 }
5087 }
5088 walk.pcw_valid = PCI_CAP_PTR_OFF;
5089 walk.pcw_caplen = PCI_CAP_PTR_OFF;
5090
5091 /*
5092 * Grab the information from the header that we need to figure out what
5093 * kind of device this is, how to print it, if there are any
5094 * capabilities, and go from there.
5095 */
5096 type = data.pcb_u8[PCI_CONF_HEADER] & PCI_HEADER_TYPE_M;
5097 switch (type) {
5098 case PCI_HEADER_ZERO:
5099 headstr = "Type 0 Header";
5100 headshort = "header0";
5101 header = pcieadm_cfgspace_type0;
5102 capsup = (data.pcb_u8[PCI_CONF_STAT] & PCI_STAT_CAP) != 0;
5103 break;
5104 case PCI_HEADER_ONE:
5105 headstr = "Type 1 Header";
5106 headshort = "header1";
5107 header = pcieadm_cfgspace_type1;
5108 capsup = (data.pcb_u8[PCI_CONF_STAT] & PCI_STAT_CAP) != 0;
5109 break;
5110 case PCI_HEADER_TWO:
5111 default:
5112 headstr = "Unknown Header";
5113 headshort = "headerX";
5114 header = pcieadm_cfgspace_unknown;
5115 warnx("unsupported PCI header type: 0x%x, output limited to "
5116 "data configuration space", type);
5117 }
5118
5119 walk.pcw_dtype = type;
5120
5121 if (op == PCIEADM_CFGSPACE_OP_WRITE) {
5122 pcieadm_cfgspace_write(fd, &data.pcb_u8[0], PCI_CAP_PTR_OFF);
5123 } else if (op == PCIEADM_CFGSPACE_OP_PRINT) {
5124 const pcieadm_cfgspace_print_t *print;
5125
5126 if (walk.pcw_ofmt == NULL &&
5127 pcieadm_cfgspace_filter(&walk, headshort)) {
5128 if ((flags & PCIEADM_CFGSPACE_F_SHORT) != 0) {
5129 pcieadm_print("Device %s -- %s (%s)\n",
5130 pcip->pia_devstr, headstr, headshort);
5131 } else {
5132 pcieadm_print("Device %s -- %s\n",
5133 pcip->pia_devstr, headstr);
5134 }
5135 }
5136
5137 pcieadm_strfilt_push(&walk, headshort);
5138 pcieadm_indent();
5139 for (print = header; print->pcp_short != NULL; print++) {
5140 print->pcp_print(&walk, print, print->pcp_arg);
5141 }
5142 pcieadm_deindent();
5143 pcieadm_strfilt_pop(&walk);
5144 }
5145
5146
5147 if (!capsup) {
5148 return;
5149 }
5150
5151 for (uint32_t i = PCI_CAP_PTR_OFF / 4; i < PCI_CONF_HDR_SIZE / 4; i++) {
5152 if (!readf(i * 4, 4, &data.pcb_u32[i], readarg)) {
5153 errx(EXIT_FAILURE, "failed to read offset %u from "
5154 "configuration space", i * 4);
5155 }
5156 }
5157 walk.pcw_valid = PCIE_EXT_CAP;
5158 VERIFY3P(walk.pcw_filt, ==, NULL);
5159
5160 if (op == PCIEADM_CFGSPACE_OP_WRITE) {
5161 pcieadm_cfgspace_write(fd, &data.pcb_u8[PCI_CAP_PTR_OFF],
5162 PCI_CONF_HDR_SIZE - PCI_CAP_PTR_OFF);
5163 }
5164
5165 ncaps = 0;
5166 cap = data.pcb_u8[PCI_CONF_CAP_PTR];
5167 while (cap != 0 && cap != PCI_EINVAL8) {
5168 const pcieadm_pci_cap_t *cap_info;
5169 const pcieadm_cap_vers_t *vers_info = NULL;
5170 const pcieadm_subcap_t *subcap = NULL;
5171 uint8_t cap_id, nextcap;
5172 uint32_t read_len = 0;
5173
5174 /*
5175 * The PCI specification requires that the caller mask off the
5176 * bottom two bits. Always check for an invalid value (all 1s)
5177 * before this.
5178 */
5179 cap &= PCI_CAP_PTR_MASK;
5180 cap_id = data.pcb_u8[cap + PCI_CAP_ID];
5181 nextcap = data.pcb_u8[cap + PCI_CAP_NEXT_PTR];
5182 cap_info = pcieadm_cfgspace_match_cap(cap_id, B_FALSE);
5183 if (cap_info != NULL && cap_info->ppc_info != NULL) {
5184 cap_info->ppc_info(&walk, cap_info, cap, &vers_info,
5185 &read_len, &subcap);
5186 }
5187
5188 walk.pcw_caplen = read_len;
5189 walk.pcw_capoff = cap;
5190
5191 if (cap_id == PCI_CAP_ID_PCI_E) {
5192 extcfg = B_TRUE;
5193 if (walk.pcw_valid != 0) {
5194 walk.pcw_pcietype = data.pcb_u8[cap +
5195 PCIE_PCIECAP] & PCIE_PCIECAP_DEV_TYPE_MASK;
5196 walk.pcw_nlanes = (data.pcb_u8[cap +
5197 PCIE_LINKCAP] & 0xf0) >> 4;
5198 walk.pcw_nlanes |= (data.pcb_u8[cap +
5199 PCIE_LINKCAP + 1] & 0x01) << 4;
5200 } else {
5201 walk.pcw_pcietype = UINT_MAX;
5202 }
5203 }
5204
5205 if (op == PCIEADM_CFGSPACE_OP_PRINT) {
5206 pcieadm_cfgspace_print_cap(&walk, cap_id, cap_info,
5207 vers_info, subcap);
5208 }
5209
5210 cap = nextcap;
5211 ncaps++;
5212 if (ncaps >= PCI_CAP_MAX_PTR) {
5213 errx(EXIT_FAILURE, "encountered more PCI capabilities "
5214 "than fit in configuration space");
5215 }
5216 }
5217
5218 if (!extcfg) {
5219 return;
5220 }
5221
5222 for (uint_t i = PCIE_EXT_CAP / 4; i < PCIE_CONF_HDR_SIZE / 4; i++) {
5223 if (!readf(i * 4, 4, &data.pcb_u32[i], readarg)) {
5224 errx(EXIT_FAILURE, "failed to read offset %u from "
5225 "configuration space", i * 4);
5226 }
5227 }
5228 walk.pcw_valid = PCIE_CONF_HDR_SIZE;
5229
5230 if (op == PCIEADM_CFGSPACE_OP_WRITE) {
5231 pcieadm_cfgspace_write(fd, &data.pcb_u8[PCIE_EXT_CAP],
5232 PCIE_CONF_HDR_SIZE - PCIE_EXT_CAP);
5233 return;
5234 }
5235
5236 cap = PCIE_EXT_CAP;
5237 ncaps = 0;
5238 while (cap != 0 && cap != PCI_EINVAL16) {
5239 uint16_t cap_id, nextcap;
5240 const pcieadm_pci_cap_t *cap_info;
5241 const pcieadm_cap_vers_t *vers_info = NULL;
5242 const pcieadm_subcap_t *subcap = NULL;
5243 uint32_t read_len = 0;
5244
5245 /*
5246 * PCIe has the same masking as PCI. Note, sys/pcie.h currently
5247 * has PCIE_EXT_CAP_NEXT_PTR_MASK as 0xfff, instead of the
5248 * below. This should be switched to PCIE_EXT_CAP_NEXT_PTR_MASK
5249 * when the kernel headers are fixed.
5250 */
5251 cap &= 0xffc;
5252
5253 /*
5254 * While this seems duplicative of the loop condition, a device
5255 * without capabilities indicates it with a zero for the first
5256 * cap.
5257 */
5258 if (data.pcb_u32[cap / 4] == 0 ||
5259 data.pcb_u32[cap / 4] == PCI_EINVAL32)
5260 break;
5261
5262 cap_id = data.pcb_u32[cap / 4] & PCIE_EXT_CAP_ID_MASK;
5263 nextcap = (data.pcb_u32[cap / 4] >>
5264 PCIE_EXT_CAP_NEXT_PTR_SHIFT) & PCIE_EXT_CAP_NEXT_PTR_MASK;
5265
5266 cap_info = pcieadm_cfgspace_match_cap(cap_id, B_TRUE);
5267 if (cap_info != NULL && cap_info->ppc_info != NULL) {
5268 cap_info->ppc_info(&walk, cap_info, cap, &vers_info,
5269 &read_len, &subcap);
5270 }
5271
5272 walk.pcw_caplen = read_len;
5273 walk.pcw_capoff = cap;
5274
5275 if (op == PCIEADM_CFGSPACE_OP_PRINT) {
5276 pcieadm_cfgspace_print_cap(&walk, cap_id, cap_info,
5277 vers_info, subcap);
5278 }
5279
5280 cap = nextcap;
5281 ncaps++;
5282 if (ncaps >= PCIE_EXT_CAP_MAX_PTR) {
5283 errx(EXIT_FAILURE, "encountered more PCI capabilities "
5284 "than fit in configuration space");
5285 }
5286 }
5287 }
5288
5289 void
pcieadm_show_cfgspace_usage(FILE * f)5290 pcieadm_show_cfgspace_usage(FILE *f)
5291 {
5292 (void) fprintf(f, "\tshow-cfgspace\t[-L] [-n] [-H] -d device | -f file "
5293 "[filter...]\n");
5294 (void) fprintf(f, "\tshow-cfgspace\t-p -o field[,...] [-H] -d device | "
5295 "-f file [filter...]\n");
5296 }
5297
5298 static void
pcieadm_show_cfgspace_help(const char * fmt,...)5299 pcieadm_show_cfgspace_help(const char *fmt, ...)
5300 {
5301 if (fmt != NULL) {
5302 va_list ap;
5303
5304 va_start(ap, fmt);
5305 vwarnx(fmt, ap);
5306 va_end(ap);
5307 (void) fprintf(stderr, "\n");
5308 }
5309
5310 (void) fprintf(stderr, "Usage: %s show-cfgspace [-L] [-n] [-H] -d "
5311 "device | -f file [filter...]\n", pcieadm_progname);
5312 (void) fprintf(stderr, " %s show-cfgspace -p -o field[,...] "
5313 "[-H] -d device | -f file\n\t\t\t [filter...]\n",
5314 pcieadm_progname);
5315
5316 (void) fprintf(stderr, "\nPrint and decode PCI configuration space "
5317 "data from a device or file. Each\n<filter> selects a given "
5318 "capability, sub-capability, register, or field to print.\n\n"
5319 "\t-d device\tread data from the specified device (driver instance,"
5320 "\n\t\t\t/devices path, or b/d/f)\n"
5321 "\t-f file\t\tread data from the specified file\n"
5322 "\t-L\t\tlist printable fields\n"
5323 "\t-n\t\tshow printable short names\n"
5324 "\t-H\t\tomit the column header (for -L and -p)\n"
5325 "\t-p\t\tparsable output (requires -o)\n"
5326 "\t-o field\toutput fields to print (required for -p)\n\n"
5327 "The following fields are supported:\n"
5328 "\thuman\t\ta human-readable description of the specific output\n"
5329 "\tshort\t\tthe short name of the value used for filters\n"
5330 "\tvalue\t\tthe value of a the given capability, register, etc.\n");
5331 }
5332
5333 int
pcieadm_show_cfgspace(pcieadm_t * pcip,int argc,char * argv[])5334 pcieadm_show_cfgspace(pcieadm_t *pcip, int argc, char *argv[])
5335 {
5336 int c, ret;
5337 pcieadm_cfgspace_f readf;
5338 void *readarg;
5339 boolean_t list = B_FALSE, parse = B_FALSE;
5340 const char *device = NULL, *file = NULL, *fields = NULL;
5341 uint_t nfilts = 0;
5342 pcieadm_cfgspace_filter_t *filts = NULL;
5343 pcieadm_cfgspace_flags_t flags = 0;
5344 uint_t oflags = 0;
5345 ofmt_handle_t ofmt = NULL;
5346
5347 while ((c = getopt(argc, argv, ":HLd:f:o:np")) != -1) {
5348 switch (c) {
5349 case 'd':
5350 device = optarg;
5351 break;
5352 case 'L':
5353 list = B_TRUE;
5354 break;
5355 case 'f':
5356 file = optarg;
5357 break;
5358 case 'p':
5359 parse = B_TRUE;
5360 flags |= PCIEADM_CFGSPACE_F_PARSE;
5361 oflags |= OFMT_PARSABLE;
5362 break;
5363 case 'n':
5364 flags |= PCIEADM_CFGSPACE_F_SHORT;
5365 break;
5366 case 'H':
5367 oflags |= OFMT_NOHEADER;
5368 break;
5369 case 'o':
5370 fields = optarg;
5371 break;
5372 case ':':
5373 pcieadm_show_cfgspace_help("Option -%c requires an "
5374 "argument", optopt);
5375 exit(EXIT_USAGE);
5376 case '?':
5377 default:
5378 pcieadm_show_cfgspace_help("unknown option: -%c",
5379 optopt);
5380 exit(EXIT_USAGE);
5381 }
5382 }
5383
5384 argc -= optind;
5385 argv += optind;
5386
5387 if (device == NULL && file == NULL) {
5388 pcieadm_show_cfgspace_help("one of -d or -f must be specified");
5389 exit(EXIT_USAGE);
5390 }
5391
5392 if (device != NULL && file != NULL) {
5393 pcieadm_show_cfgspace_help("only one of -d and -f must be "
5394 "specified");
5395 exit(EXIT_USAGE);
5396 }
5397
5398 if (parse && fields == NULL) {
5399 pcieadm_show_cfgspace_help("-p requires fields specified with "
5400 "-o");
5401 exit(EXIT_USAGE);
5402 }
5403
5404 if (!parse && fields != NULL) {
5405 pcieadm_show_cfgspace_help("-o can only be used with -p");
5406 exit(EXIT_USAGE);
5407 }
5408
5409 if ((oflags & OFMT_NOHEADER) && !(list || parse)) {
5410 pcieadm_show_cfgspace_help("-H must be used with either -L or "
5411 "-p");
5412 exit(EXIT_USAGE);
5413 }
5414
5415 if ((flags & PCIEADM_CFGSPACE_F_SHORT) && (list || parse)) {
5416 pcieadm_show_cfgspace_help("-n cannot be used with either -L "
5417 "or -p");
5418 exit(EXIT_USAGE);
5419 }
5420
5421 if (list && parse != 0) {
5422 pcieadm_show_cfgspace_help("-L and -p cannot be used together");
5423 exit(EXIT_USAGE);
5424 }
5425
5426 if (list && fields != NULL) {
5427 pcieadm_show_cfgspace_help("-L and -o cannot be used together");
5428 exit(EXIT_USAGE);
5429 }
5430
5431 if (list) {
5432 fields = "short,human";
5433 }
5434
5435 if (argc > 0) {
5436 nfilts = argc;
5437 filts = calloc(nfilts, sizeof (pcieadm_cfgspace_filter_t));
5438
5439 for (int i = 0; i < argc; i++) {
5440 filts[i].pcf_string = argv[i];
5441 filts[i].pcf_len = strlen(argv[i]);
5442 }
5443 }
5444
5445 if (list || parse) {
5446 ofmt_status_t oferr;
5447 oferr = ofmt_open(fields, pcieadm_cfgspace_ofmt, oflags, 0,
5448 &ofmt);
5449 ofmt_check(oferr, parse, ofmt, pcieadm_ofmt_errx, warnx);
5450 }
5451
5452 /*
5453 * Initialize privileges that we require. For reading from the kernel
5454 * we require all privileges. For a file, we just intersect with things
5455 * that would allow someone to read from any file.
5456 */
5457 if (device != NULL) {
5458 /*
5459 * We need full privileges if reading from a device,
5460 * unfortunately.
5461 */
5462 priv_fillset(pcip->pia_priv_eff);
5463 } else {
5464 VERIFY0(priv_addset(pcip->pia_priv_eff, PRIV_FILE_DAC_READ));
5465 VERIFY0(priv_addset(pcip->pia_priv_eff, PRIV_FILE_DAC_SEARCH));
5466 }
5467 pcieadm_init_privs(pcip);
5468
5469 if (device != NULL) {
5470 pcieadm_find_dip(pcip, device);
5471 pcieadm_init_cfgspace_kernel(pcip, &readf, &readarg);
5472 } else {
5473 pcip->pia_devstr = file;
5474 pcieadm_init_cfgspace_file(pcip, file, &readf, &readarg);
5475 }
5476 pcieadm_cfgspace(pcip, PCIEADM_CFGSPACE_OP_PRINT, readf, -1, readarg,
5477 nfilts, filts, flags, ofmt);
5478 if (device != NULL) {
5479 pcieadm_fini_cfgspace_kernel(readarg);
5480 } else {
5481 pcieadm_fini_cfgspace_file(readarg);
5482 }
5483
5484 ofmt_close(ofmt);
5485 ret = EXIT_SUCCESS;
5486 for (uint_t i = 0; i < nfilts; i++) {
5487 if (!filts[i].pcf_used) {
5488 warnx("filter '%s' did not match any fields",
5489 filts[i].pcf_string);
5490 ret = EXIT_FAILURE;
5491 }
5492 }
5493
5494 return (ret);
5495 }
5496
5497 typedef struct pcieadm_save_cfgspace {
5498 pcieadm_t *psc_pci;
5499 int psc_dirfd;
5500 uint_t psc_nsaved;
5501 int psc_ret;
5502 } pcieadm_save_cfgspace_t;
5503
5504 static int
pcieadm_save_cfgspace_cb(di_node_t devi,void * arg)5505 pcieadm_save_cfgspace_cb(di_node_t devi, void *arg)
5506 {
5507 int fd, nregs, *regs;
5508 pcieadm_save_cfgspace_t *psc = arg;
5509 pcieadm_cfgspace_f readf;
5510 void *readarg;
5511 char fname[128];
5512
5513 psc->psc_pci->pia_devstr = di_node_name(devi);
5514 psc->psc_pci->pia_devi = devi;
5515 psc->psc_pci->pia_nexus = DI_NODE_NIL;
5516 pcieadm_find_nexus(psc->psc_pci);
5517 if (psc->psc_pci->pia_nexus == DI_NODE_NIL) {
5518 warnx("failed to find nexus for %s", di_node_name(devi));
5519 psc->psc_ret = EXIT_FAILURE;
5520 return (DI_WALK_CONTINUE);
5521 }
5522
5523 nregs = di_prop_lookup_ints(DDI_DEV_T_ANY, devi, "reg", ®s);
5524 if (nregs <= 0) {
5525 warnx("failed to lookup regs array for %s",
5526 psc->psc_pci->pia_devstr);
5527 psc->psc_ret = EXIT_FAILURE;
5528 return (DI_WALK_CONTINUE);
5529 }
5530
5531 (void) snprintf(fname, sizeof (fname), "%02x-%02x-%02x.pci",
5532 PCI_REG_BUS_G(regs[0]), PCI_REG_DEV_G(regs[0]),
5533 PCI_REG_FUNC_G(regs[0]));
5534
5535 if (setppriv(PRIV_SET, PRIV_EFFECTIVE, psc->psc_pci->pia_priv_eff) !=
5536 0) {
5537 err(EXIT_FAILURE, "failed to raise privileges");
5538 }
5539 fd = openat(psc->psc_dirfd, fname, O_WRONLY | O_TRUNC | O_CREAT, 0666);
5540 if (setppriv(PRIV_SET, PRIV_EFFECTIVE, psc->psc_pci->pia_priv_min) !=
5541 0) {
5542 err(EXIT_FAILURE, "failed to reduce privileges");
5543 }
5544
5545 if (fd < 0) {
5546 warn("failed to create output file %s", fname);
5547 psc->psc_ret = EXIT_FAILURE;
5548 return (DI_WALK_CONTINUE);
5549 }
5550
5551 pcieadm_init_cfgspace_kernel(psc->psc_pci, &readf, &readarg);
5552 pcieadm_cfgspace(psc->psc_pci, PCIEADM_CFGSPACE_OP_WRITE, readf, fd,
5553 readarg, 0, NULL, 0, NULL);
5554 pcieadm_fini_cfgspace_kernel(readarg);
5555
5556 if (close(fd) != 0) {
5557 warn("failed to close output fd for %s", fname);
5558 psc->psc_ret = EXIT_FAILURE;
5559 } else {
5560 psc->psc_nsaved++;
5561 }
5562
5563 return (DI_WALK_CONTINUE);
5564 }
5565
5566 void
pcieadm_save_cfgspace_usage(FILE * f)5567 pcieadm_save_cfgspace_usage(FILE *f)
5568 {
5569 (void) fprintf(f, "\tsave-cfgspace\t-d device output-file\n");
5570 (void) fprintf(f, "\tsave-cfgspace\t-a output-directory\n");
5571 }
5572
5573 static void
pcieadm_save_cfgspace_help(const char * fmt,...)5574 pcieadm_save_cfgspace_help(const char *fmt, ...)
5575 {
5576 if (fmt != NULL) {
5577 va_list ap;
5578
5579 va_start(ap, fmt);
5580 vwarnx(fmt, ap);
5581 va_end(ap);
5582 (void) fprintf(stderr, "\n");
5583 }
5584
5585 (void) fprintf(stderr, "Usage: %s save-cfgspace -d device "
5586 "output-file\n", pcieadm_progname);
5587 (void) fprintf(stderr, " %s save-cfgspace -a "
5588 "output-directory\n", pcieadm_progname);
5589
5590 (void) fprintf(stderr, "\nSave PCI configuration space data from a "
5591 "device to a file or\nsave all devices to a specified directory."
5592 "\n\n"
5593 "\t-a\t\tsave data from all devices\n"
5594 "\t-d device\tread data from the specified device (driver instance,"
5595 "\n\t\t\t/devices path, or b/d/f)\n");
5596 }
5597
5598 int
pcieadm_save_cfgspace(pcieadm_t * pcip,int argc,char * argv[])5599 pcieadm_save_cfgspace(pcieadm_t *pcip, int argc, char *argv[])
5600 {
5601 int c;
5602 pcieadm_cfgspace_f readf;
5603 void *readarg;
5604 const char *device = NULL;
5605 boolean_t do_all = B_FALSE;
5606
5607 while ((c = getopt(argc, argv, ":ad:")) != -1) {
5608 switch (c) {
5609 case 'a':
5610 do_all = B_TRUE;
5611 break;
5612 case 'd':
5613 device = optarg;
5614 break;
5615 case ':':
5616 pcieadm_save_cfgspace_help("Option -%c requires an "
5617 "argument", optopt);
5618 exit(EXIT_USAGE);
5619 case '?':
5620 default:
5621 pcieadm_save_cfgspace_help("unknown option: -%c",
5622 optopt);
5623 exit(EXIT_USAGE);
5624 }
5625 }
5626
5627 argc -= optind;
5628 argv += optind;
5629
5630 if (device == NULL && !do_all) {
5631 pcieadm_save_cfgspace_help("missing required -d option to "
5632 "indicate device to dump");
5633 exit(EXIT_USAGE);
5634 }
5635
5636 if (argc != 1) {
5637 pcieadm_save_cfgspace_help("missing required output path");
5638 exit(EXIT_USAGE);
5639 }
5640
5641 /*
5642 * For reading from devices, we need to full privileges, unfortunately.
5643 */
5644 priv_fillset(pcip->pia_priv_eff);
5645 pcieadm_init_privs(pcip);
5646
5647 if (!do_all) {
5648 int fd;
5649
5650 pcieadm_find_dip(pcip, device);
5651
5652 if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_eff) !=
5653 0) {
5654 err(EXIT_FAILURE, "failed to raise privileges");
5655 }
5656
5657 if ((fd = open(argv[0], O_WRONLY | O_CREAT | O_TRUNC, 0666)) <
5658 0) {
5659 err(EXIT_FAILURE, "failed to open output file %s",
5660 argv[0]);
5661 }
5662
5663 if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_min) !=
5664 0) {
5665 err(EXIT_FAILURE, "failed to reduce privileges");
5666 }
5667
5668 pcieadm_init_cfgspace_kernel(pcip, &readf, &readarg);
5669 pcieadm_cfgspace(pcip, PCIEADM_CFGSPACE_OP_WRITE, readf, fd,
5670 readarg, 0, NULL, 0, NULL);
5671 pcieadm_fini_cfgspace_kernel(readarg);
5672
5673 if (close(fd) != 0) {
5674 err(EXIT_FAILURE, "failed to close output file "
5675 "descriptor");
5676 }
5677
5678 return (EXIT_SUCCESS);
5679 } else {
5680 pcieadm_save_cfgspace_t psc;
5681 pcieadm_di_walk_t walk;
5682
5683 if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_eff) !=
5684 0) {
5685 err(EXIT_FAILURE, "failed to raise privileges");
5686 }
5687
5688 if ((psc.psc_dirfd = open(argv[0], O_RDONLY | O_DIRECTORY)) <
5689 0) {
5690 err(EXIT_FAILURE, "failed to open output directory %s",
5691 argv[0]);
5692 }
5693
5694 if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_min) !=
5695 0) {
5696 err(EXIT_FAILURE, "failed to reduce privileges");
5697 }
5698
5699 psc.psc_nsaved = 0;
5700 psc.psc_ret = EXIT_SUCCESS;
5701 psc.psc_pci = pcip;
5702
5703 walk.pdw_arg = &psc;
5704 walk.pdw_func = pcieadm_save_cfgspace_cb;
5705 pcieadm_di_walk(pcip, &walk);
5706
5707 VERIFY0(close(psc.psc_dirfd));
5708
5709 if (psc.psc_nsaved == 0) {
5710 warnx("failed to save any PCI devices");
5711 return (EXIT_FAILURE);
5712 }
5713
5714 pcieadm_print("successfully saved %u devices to %s\n",
5715 psc.psc_nsaved, argv[0]);
5716 return (psc.psc_ret);
5717 }
5718 }
5719