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