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