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