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