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