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 static pcieadm_cfgspace_print_t pcieadm_cap_pcie_v1_dev[] = {
1753 	{ PCIE_PCIECAP, 2, "cap", "Capability Register",
1754 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_cap },
1755 	{ PCIE_DEVCAP, 4, "devcap", "Device Capabilities",
1756 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devcap },
1757 	{ PCIE_DEVSTS, 2, "devsts", "Device Status",
1758 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devsts },
1759 	{ -1, -1, NULL }
1760 };
1761 
1762 static pcieadm_cfgspace_print_t pcieadm_cap_pcie_v1_link[] = {
1763 	{ PCIE_PCIECAP, 2, "cap", "Capability Register",
1764 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_cap },
1765 	{ PCIE_DEVCAP, 4, "devcap", "Device Capabilities",
1766 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devcap },
1767 	{ PCIE_DEVSTS, 2, "devsts", "Device Status",
1768 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devsts },
1769 	{ PCIE_LINKCAP, 4, "linkcap", "Link Capabilities",
1770 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkcap },
1771 	{ PCIE_LINKCTL, 2, "linkctl", "Link Control",
1772 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkctl },
1773 	{ PCIE_LINKSTS, 2, "linksts", "Link Status",
1774 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linksts },
1775 	{ -1, -1, NULL }
1776 };
1777 
1778 static pcieadm_cfgspace_print_t pcieadm_cap_pcie_v1_slot[] = {
1779 	{ PCIE_PCIECAP, 2, "cap", "Capability Register",
1780 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_cap },
1781 	{ PCIE_DEVCAP, 4, "devcap", "Device Capabilities",
1782 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devcap },
1783 	{ PCIE_DEVSTS, 2, "devsts", "Device Status",
1784 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devsts },
1785 	{ PCIE_LINKCAP, 4, "linkcap", "Link Capabilities",
1786 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkcap },
1787 	{ PCIE_LINKCTL, 2, "linkctl", "Link Control",
1788 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkctl },
1789 	{ PCIE_LINKSTS, 2, "linksts", "Link Status",
1790 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linksts },
1791 	{ PCIE_SLOTCAP, 4, "slotcap", "Slot Capabilities",
1792 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotcap },
1793 	{ PCIE_SLOTCTL, 2, "slotctl", "Slot Control",
1794 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotctl },
1795 	{ PCIE_SLOTSTS, 2, "slotsts", "Slot Status",
1796 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotsts },
1797 	{ -1, -1, NULL }
1798 };
1799 
1800 
1801 static pcieadm_cfgspace_print_t pcieadm_cap_pcie_v1_all[] = {
1802 	{ PCIE_PCIECAP, 2, "cap", "Capability Register",
1803 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_cap },
1804 	{ PCIE_DEVCAP, 4, "devcap", "Device Capabilities",
1805 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devcap },
1806 	{ PCIE_DEVSTS, 2, "devsts", "Device Status",
1807 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devsts },
1808 	{ PCIE_LINKCAP, 4, "linkcap", "Link Capabilities",
1809 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkcap },
1810 	{ PCIE_LINKCTL, 2, "linkctl", "Link Control",
1811 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkctl },
1812 	{ PCIE_LINKSTS, 2, "linksts", "Link Status",
1813 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linksts },
1814 	{ PCIE_SLOTCAP, 4, "slotcap", "Slot Capabilities",
1815 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotcap },
1816 	{ PCIE_SLOTCTL, 2, "slotctl", "Slot Control",
1817 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotctl },
1818 	{ PCIE_SLOTSTS, 2, "slotsts", "Slot Status",
1819 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotsts },
1820 	{ PCIE_ROOTCTL, 2, "rootctl", "Root control",
1821 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_rootctl },
1822 	{ PCIE_ROOTCAP, 2, "rootcap", "Root Capabilities",
1823 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_rootcap },
1824 	{ PCIE_ROOTSTS, 4, "rootsts", "Root Status",
1825 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_rootsts },
1826 	{ -1, -1, NULL }
1827 };
1828 
1829 static pcieadm_cfgspace_print_t pcieadm_cap_pcie_v2[] = {
1830 	{ PCIE_PCIECAP, 2, "cap", "Capability Register",
1831 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_cap },
1832 	{ PCIE_DEVCAP, 4, "devcap", "Device Capabilities",
1833 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devcap },
1834 	{ PCIE_DEVCTL, 2, "devctl", "Device Control",
1835 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devctl },
1836 	{ PCIE_DEVSTS, 2, "devsts", "Device Status",
1837 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devsts },
1838 	{ PCIE_LINKCAP, 4, "linkcap", "Link Capabilities",
1839 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkcap },
1840 	{ PCIE_LINKCTL, 2, "linkctl", "Link Control",
1841 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkctl },
1842 	{ PCIE_LINKSTS, 2, "linksts", "Link Status",
1843 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linksts },
1844 	{ PCIE_SLOTCAP, 4, "slotcap", "Slot Capabilities",
1845 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotcap },
1846 	{ PCIE_SLOTCTL, 2, "slotctl", "Slot Control",
1847 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotctl },
1848 	{ PCIE_SLOTSTS, 2, "slotsts", "Slot Status",
1849 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotsts },
1850 	{ PCIE_ROOTCTL, 2, "rootctl", "Root Control",
1851 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_rootctl },
1852 	{ PCIE_ROOTCAP, 2, "rootcap", "Root Capabilities",
1853 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_rootcap },
1854 	{ PCIE_ROOTSTS, 4, "rootsts", "Root Status",
1855 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_rootsts },
1856 	{ PCIE_DEVCAP2, 4, "devcap2", "Device Capabilities 2",
1857 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devcap2 },
1858 	{ PCIE_DEVCTL2, 2, "devctl2", "Device Control 2",
1859 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devctl2 },
1860 	{ PCIE_DEVSTS2, 2, "devsts2", "Device Status 2",
1861 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_devsts2 },
1862 	{ PCIE_LINKCAP2, 4, "linkcap2", "Link Capabilities 2",
1863 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkcap2 },
1864 	{ PCIE_LINKCTL2, 2, "linkctl2", "Link Control 2",
1865 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linkctl2 },
1866 	{ PCIE_LINKSTS2, 2, "linksts2", "Link Status 2",
1867 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_linksts2 },
1868 	{ PCIE_SLOTCAP2, 4, "slotcap2", "Slot Capabilities 2",
1869 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotcap2 },
1870 	{ PCIE_SLOTCTL2, 2, "slotctl2", "Slot Control 2",
1871 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotctl2 },
1872 	{ PCIE_SLOTSTS2, 2, "slotsts2", "Slot Status 2",
1873 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_slotsts2 },
1874 	{ -1, -1, NULL }
1875 };
1876 
1877 /*
1878  * PCIe Extended Capability Header
1879  */
1880 static pcieadm_regdef_t pcieadm_regdef_pcie_caphdr[] = {
1881 	{ 0, 15, "capid", "Capability ID", PRDV_HEX },
1882 	{ 16, 19, "version", "Capability Version", PRDV_HEX },
1883 	{ 20, 32, "offset", "Next Capability Offset", PRDV_HEX },
1884 	{ -1, -1, NULL }
1885 };
1886 
1887 /*
1888  * VPD Capability
1889  */
1890 static pcieadm_regdef_t pcieadm_regdef_vpd_addr[] = {
1891 	{ 0, 14, "addr", "VPD Address", PRDV_HEX },
1892 	{ 15, 15, "flag", "Flag", PRDV_HEX },
1893 	{ -1, -1, NULL }
1894 };
1895 
1896 static pcieadm_cfgspace_print_t pcieadm_cap_vpd[] = {
1897 	{ 0x2, 2, "addr", "VPD Address Register",
1898 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_vpd_addr },
1899 	{ 0x4, 4, "data", "VPD Data", pcieadm_cfgspace_print_hex },
1900 	{ -1, -1, NULL }
1901 };
1902 
1903 /*
1904  * SATA Capability per AHCI 1.3.1
1905  */
1906 static pcieadm_regdef_t pcieadm_regdef_sata_cr0[] = {
1907 	{ 0, 3, "minrev", "Minor Revision", PRDV_HEX },
1908 	{ 4, 7, "majrev", "Major Revision", PRDV_HEX },
1909 	{ -1, -1, NULL }
1910 };
1911 
1912 static pcieadm_regdef_t pcieadm_regdef_sata_cr1[] = {
1913 	{ 0, 3, "bar", "BAR Location", PRDV_HEX,
1914 	    .prd_val = { .prdv_hex = { 2 } } },
1915 	{ 4, 23, "offset", "BAR Offset", PRDV_HEX,
1916 	    .prd_val = { .prdv_hex = { 2 } } },
1917 	{ -1, -1, NULL }
1918 };
1919 
1920 static pcieadm_cfgspace_print_t pcieadm_cap_sata[] = {
1921 	{ 0x2, 2, "satacr0", "SATA Capability Register 0",
1922 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_sata_cr0 },
1923 	{ 0x4, 4, "satacr1", "SATA Capability Register 1",
1924 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_sata_cr1 },
1925 	{ -1, -1, NULL }
1926 };
1927 
1928 /*
1929  * Debug Capability per EHCI
1930  */
1931 static pcieadm_regdef_t pcieadm_regdef_debug[] = {
1932 	{ 0, 12, "offset", "BAR Offset", PRDV_HEX },
1933 	{ 13, 15, "bar", "BAR Location ", PRDV_STRVAL,
1934 	    .prd_val = { .prdv_strval = { NULL, "BAR 0", "BAR 1", "BAR 2",
1935 	    "BAR 3", "BAR 4", "BAR 5" } } },
1936 	{ -1, -1, NULL }
1937 };
1938 
1939 static pcieadm_cfgspace_print_t pcieadm_cap_debug[] = {
1940 	{ 0x2, 2, "port", "Debug Port",
1941 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_debug },
1942 	{ -1, -1, NULL }
1943 };
1944 
1945 /*
1946  * AER Capability
1947  */
1948 static pcieadm_regdef_t pcieadm_regdef_aer_ue[] = {
1949 	{ 4, 4, "dlp", "Data Link Protocol Error", PRDV_HEX },
1950 	{ 5, 5, "sde", "Surprise Down Error", PRDV_HEX },
1951 	{ 12, 12, "ptlp", "Poisoned TLP Received", PRDV_HEX },
1952 	{ 13, 13, "fcp", "Flow Control Protocol Error", PRDV_HEX },
1953 	{ 14, 14, "cto", "Completion Timeout", PRDV_HEX },
1954 	{ 15, 15, "cab", "Completion Abort", PRDV_HEX },
1955 	{ 16, 16, "unco", "Unexpected Completion", PRDV_HEX },
1956 	{ 17, 17, "rxov", "Receiver Overflow", PRDV_HEX },
1957 	{ 18, 18, "maltlp", "Malformed TLP", PRDV_HEX },
1958 	{ 19, 19, "ecrc", "ECRC Error", PRDV_HEX },
1959 	{ 20, 20, "usuprx", "Unsupported Request Error", PRDV_HEX },
1960 	{ 21, 21, "acs", "ACS Violation", PRDV_HEX },
1961 	{ 22, 22, "ueint", "Uncorrectable Internal Error", PRDV_HEX },
1962 	{ 23, 23, "mcbtlp", "MC Blocked TLP", PRDV_HEX },
1963 	{ 24, 24, "atoomeb", "AtomicOp Egress Blocked", PRDV_HEX },
1964 	{ 25, 25, "tlppb", "TLP Prefix Blocked Error", PRDV_HEX },
1965 	{ 26, 26, "ptlpeb", "Poisoned TLP Egress Blocked", PRDV_HEX },
1966 	{ -1, -1, NULL }
1967 };
1968 
1969 static pcieadm_regdef_t pcieadm_regdef_aer_ce[] = {
1970 	{ 0, 0, "rxerr", "Receiver Error", PRDV_HEX },
1971 	{ 6, 6, "badtlp", "Bad TLP", PRDV_HEX },
1972 	{ 7, 7, "baddllp", "Bad DLLP", PRDV_HEX },
1973 	{ 8, 8, "replayro", "REPLAY_NUM Rollover", PRDV_HEX },
1974 	{ 12, 12, "rtto", "Replay timer Timeout", PRDV_HEX },
1975 	{ 13, 13, "advnfe", "Advisory Non-Fatal Error", PRDV_HEX },
1976 	{ 14, 14, "ceint", "Correctable Internal Error", PRDV_HEX },
1977 	{ 15, 15, "headlov", "Header Log Overflow", PRDV_HEX },
1978 	{ -1, -1, NULL }
1979 };
1980 
1981 static pcieadm_regdef_t pcieadm_regdef_aer_ctrl[] = {
1982 	{ 0, 4, "feptr", "First Error Pointer", PRDV_HEX },
1983 	{ 5, 5, "ecgencap", "ECRC Generation Capable", PRDV_STRVAL,
1984 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1985 	{ 6, 6, "ecgenen", "ECRC Generation Enable", PRDV_STRVAL,
1986 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1987 	{ 7, 7, "ecchkcap", "ECRC Check Capable", PRDV_STRVAL,
1988 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
1989 	{ 8, 8, "ecchken", "ECRC Check Enable", PRDV_STRVAL,
1990 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1991 	{ -1, -1, NULL }
1992 };
1993 
1994 static pcieadm_regdef_t pcieadm_regdef_aer_rootcom[] = {
1995 	{ 0, 0, "corerr", "Correctable Error Reporting", PRDV_STRVAL,
1996 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1997 	{ 1, 1, "nferr", "Non-Fatal Error Reporting", PRDV_STRVAL,
1998 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
1999 	{ 2, 2, "faterr", "Fatal Error Reporting", PRDV_STRVAL,
2000 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2001 	{ -1, -1, NULL }
2002 };
2003 
2004 static pcieadm_regdef_t pcieadm_regdef_aer_rootsts[] = {
2005 	{ 0, 0, "errcor", "ERR_COR Received", PRDV_HEX },
2006 	{ 1, 1, "merrcor", "Multiple ERR_COR Received", PRDV_HEX },
2007 	{ 2, 2, "errfnf", "ERR_FATAL/NONFATAL Received", PRDV_HEX },
2008 	{ 3, 3, "merrfnf", "Multiple ERR_FATAL/NONFATAL Received", PRDV_HEX },
2009 	{ 4, 4, "fuefat", "First Uncorrectable Fatal", PRDV_HEX },
2010 	{ 5, 5, "nferrrx", "Non-Fatal Error Messages Received", PRDV_HEX },
2011 	{ 6, 6, "faterrx", "Fatal Error Messages Received", PRDV_HEX },
2012 	{ 7, 8, "errcorsc", "ERR_COR Subclass", PRDV_STRVAL,
2013 	    .prd_val = { .prdv_strval = { "ECS Legacy", "ECS SIG_SFW",
2014 	    "ECS SIG_OS", "ECS Extended" } } },
2015 	{ 27, 31, "inum", "Advanced Error Interrupt Message", PRDV_HEX },
2016 	{ -1, -1, NULL }
2017 };
2018 
2019 static pcieadm_regdef_t pcieadm_regdef_aer_esi[] = {
2020 	{ 0, 15, "errcorr", "ERR_COR Source", PRDV_HEX },
2021 	{ 16, 31, "errfnf", "ERR_FATAL/NONFATAL Source", PRDV_HEX },
2022 	{ -1, -1, NULL }
2023 };
2024 
2025 static pcieadm_regdef_t pcieadm_regdef_aer_secue[] = {
2026 	{ 0, 0, "taosc", "Target-Abort on Split Completion", PRDV_HEX },
2027 	{ 1, 1, "maosc", "Master-Abort on Split Completion", PRDV_HEX },
2028 	{ 2, 2, "rxta", "Received Target-Abort", PRDV_HEX },
2029 	{ 3, 3, "rxma", "Received Master-Abort", PRDV_HEX },
2030 	{ 5, 5, "unsce", "Unexpected Split Completion Error", PRDV_HEX },
2031 	{ 6, 6, "uescmd", "Uncorrectable Split Completion Message Data Error",
2032 	    PRDV_HEX },
2033 	{ 7, 7, "uede", "Uncorrectable Data Error", PRDV_HEX },
2034 	{ 8, 8, "ueattre", "Uncorrectable Attribute Error", PRDV_HEX },
2035 	{ 9, 9, "ueaddre", "Uncorrectable Address Error", PRDV_HEX },
2036 	{ 10, 10, "dtdte", "Delayed Transaction Discard Timer Expired",
2037 	    PRDV_HEX },
2038 	{ 11, 11, "perr", "PERR# Assertion", PRDV_HEX },
2039 	{ 12, 12, "serr", "SERR# Assertion", PRDV_HEX },
2040 	{ 13, 13, "internal", "Internal Bridge Error", PRDV_HEX },
2041 	{ -1, -1, NULL }
2042 };
2043 
2044 static pcieadm_regdef_t pcieadm_regdef_aer_secctl[] = {
2045 	{ 0, 4, "feptr", "Secondary Uncorrectable First Error Pointer",
2046 	    PRDV_HEX },
2047 	{ -1, -1, NULL }
2048 };
2049 
2050 static pcieadm_cfgspace_print_t pcieadm_cap_aer_v1[] = {
2051 	{ PCIE_AER_CAP, 4, "caphdr", "Capability Header",
2052 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2053 	{ PCIE_AER_UCE_STS, 4, "uestatus", "Uncorrectable Error Status",
2054 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
2055 	{ PCIE_AER_UCE_MASK, 4, "uemask", "Uncorrectable Error Mask",
2056 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
2057 	{ PCIE_AER_UCE_SERV, 4, "ueserv", "Uncorrectable Error Severity",
2058 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
2059 	{ PCIE_AER_CE_STS, 4, "cestatus", "Correctable Error Status",
2060 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ce },
2061 	{ PCIE_AER_CE_MASK, 4, "cemask", "Correctable Error Mask",
2062 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ce },
2063 	{ PCIE_AER_CTL, 4, "ctrl", "Advanced Error Capabilities and Control",
2064 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ctrl },
2065 	{ PCIE_AER_HDR_LOG + 4, 4, "hl0", "Header Log 0",
2066 	    pcieadm_cfgspace_print_hex },
2067 	{ PCIE_AER_HDR_LOG + 8, 4, "hl1", "Header Log 1",
2068 	    pcieadm_cfgspace_print_hex },
2069 	{ PCIE_AER_HDR_LOG + 12, 4, "hl2", "Header Log 2",
2070 	    pcieadm_cfgspace_print_hex },
2071 	{ PCIE_AER_HDR_LOG + 12, 4, "hl3", "Header Log 3",
2072 	    pcieadm_cfgspace_print_hex },
2073 	{ PCIE_AER_CTL, 4, "rootcmd", "Root Error Command",
2074 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_rootcom },
2075 	{ PCIE_AER_RE_STS, 4, "rootsts", "Root Error Status",
2076 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_rootsts },
2077 	{ PCIE_AER_CE_SRC_ID, 4, "esi", "Error Source Identification",
2078 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_esi },
2079 	{ -1, -1, NULL }
2080 };
2081 
2082 static pcieadm_cfgspace_print_t pcieadm_cap_aer_v2[] = {
2083 	{ PCIE_AER_CAP, 4, "caphdr", "Capability Header",
2084 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2085 	{ PCIE_AER_UCE_STS, 4, "uestatus", "Uncorrectable Error Status",
2086 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
2087 	{ PCIE_AER_UCE_MASK, 4, "uemask", "Uncorrectable Error Mask",
2088 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
2089 	{ PCIE_AER_UCE_SERV, 4, "ueserv", "Uncorrectable Error Severity",
2090 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
2091 	{ PCIE_AER_CE_STS, 4, "cestatus", "Correctable Error Status",
2092 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ce },
2093 	{ PCIE_AER_CE_MASK, 4, "cemask", "Correctable Error Mask",
2094 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ce },
2095 	{ PCIE_AER_CTL, 4, "ctrl", "Advanced Error Capabilities and Control",
2096 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ctrl },
2097 	{ PCIE_AER_HDR_LOG + 4, 4, "hl0", "Header Log 0",
2098 	    pcieadm_cfgspace_print_hex },
2099 	{ PCIE_AER_HDR_LOG + 8, 4, "hl1", "Header Log 1",
2100 	    pcieadm_cfgspace_print_hex },
2101 	{ PCIE_AER_HDR_LOG + 12, 4, "hl2", "Header Log 2",
2102 	    pcieadm_cfgspace_print_hex },
2103 	{ PCIE_AER_HDR_LOG + 12, 4, "hl3", "Header Log 3",
2104 	    pcieadm_cfgspace_print_hex },
2105 	{ PCIE_AER_CTL, 4, "rootcmd", "Root Error Command",
2106 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_rootcom },
2107 	{ PCIE_AER_RE_STS, 4, "rootsts", "Root Error Status",
2108 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_rootsts },
2109 	{ PCIE_AER_TLP_PRE_LOG, 4, "tlplog0", "TLP Prefix Log 0",
2110 	    pcieadm_cfgspace_print_hex },
2111 	{ PCIE_AER_TLP_PRE_LOG + 4, 4, "tlplog1", "TLP Prefix Log 1",
2112 	    pcieadm_cfgspace_print_hex },
2113 	{ PCIE_AER_TLP_PRE_LOG + 8, 4, "tlplog2", "TLP Prefix Log 2",
2114 	    pcieadm_cfgspace_print_hex },
2115 	{ PCIE_AER_TLP_PRE_LOG + 12, 4, "tlplog3", "TLP Prefix Log 3",
2116 	    pcieadm_cfgspace_print_hex },
2117 	{ -1, -1, NULL }
2118 };
2119 
2120 static pcieadm_cfgspace_print_t pcieadm_cap_aer_bridge[] = {
2121 	{ PCIE_AER_CAP, 4, "caphdr", "Capability Header",
2122 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2123 	{ PCIE_AER_UCE_STS, 4, "uestatus", "Uncorrectable Error Status",
2124 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
2125 	{ PCIE_AER_UCE_MASK, 4, "uemask", "Uncorrectable Error Mask",
2126 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
2127 	{ PCIE_AER_UCE_SERV, 4, "ueserv", "Uncorrectable Error Severity",
2128 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ue },
2129 	{ PCIE_AER_CE_STS, 4, "cestatus", "Correctable Error Status",
2130 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ce },
2131 	{ PCIE_AER_CE_MASK, 4, "cemask", "Correctable Error Mask",
2132 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ce },
2133 	{ PCIE_AER_CTL, 4, "ctrl", "Advanced Error Capabilities and Control",
2134 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_ctrl },
2135 	{ PCIE_AER_HDR_LOG + 4, 4, "hl0", "Header Log 0",
2136 	    pcieadm_cfgspace_print_hex },
2137 	{ PCIE_AER_HDR_LOG + 8, 4, "hl1", "Header Log 1",
2138 	    pcieadm_cfgspace_print_hex },
2139 	{ PCIE_AER_HDR_LOG + 12, 4, "hl2", "Header Log 2",
2140 	    pcieadm_cfgspace_print_hex },
2141 	{ PCIE_AER_HDR_LOG + 12, 4, "hl3", "Header Log 3",
2142 	    pcieadm_cfgspace_print_hex },
2143 	{ PCIE_AER_CTL, 4, "rootcmd", "Root Error Command",
2144 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_rootcom },
2145 	{ PCIE_AER_RE_STS, 4, "rootsts", "Root Error Status",
2146 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_rootsts },
2147 	{ PCIE_AER_CE_SRC_ID, 4, "esi", "Error Source Identification",
2148 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_esi },
2149 	{ PCIE_AER_SUCE_STS, 4, "secuests",
2150 	    "Secondary Uncorrectable Error Status",
2151 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_secue },
2152 	{ PCIE_AER_SUCE_MASK, 4, "secuests",
2153 	    "Secondary Uncorrectable Error Mask",
2154 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_secue },
2155 	{ PCIE_AER_SUCE_SERV, 4, "secuests",
2156 	    "Secondary Uncorrectable Error Severity",
2157 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_secue },
2158 	{ PCIE_AER_SCTL, 4, "secctrl",
2159 	    "Secondary Error Capabilityes and Control",
2160 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_aer_secctl },
2161 	{ PCIE_AER_SHDR_LOG, 4, "shl0", "Secondary Header Log 0",
2162 	    pcieadm_cfgspace_print_hex },
2163 	{ PCIE_AER_SHDR_LOG + 4, 4, "shl1", "Secondary Header Log 1",
2164 	    pcieadm_cfgspace_print_hex },
2165 	{ PCIE_AER_SHDR_LOG + 8, 4, "shl1", "Secondary Header Log 2",
2166 	    pcieadm_cfgspace_print_hex },
2167 	{ PCIE_AER_SHDR_LOG + 12, 4, "shl1", "Secondary Header Log 3",
2168 	    pcieadm_cfgspace_print_hex },
2169 	{ -1, -1, NULL }
2170 };
2171 
2172 /*
2173  * Secondary PCI Express Extended Capability
2174  */
2175 static pcieadm_regdef_t pcieadm_regdef_pcie2_linkctl3[] = {
2176 	{ 0, 0, "peq", "Perform Equalization", PRDV_HEX },
2177 	{ 1, 1, "leqrie", "Link Equalization Request Interrupt Enable",
2178 	    PRDV_STRVAL,
2179 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2180 	{ 9, 15, "elskpos", "Enable Lower SKP OS Generation Vector",
2181 	    PRDV_BITFIELD,
2182 	    .prd_val = { .prdv_strval = { "2.5 GT/s", "5.0 GT/s", "8.0 GT/s",
2183 	    "16.0 GT/s", "32.0 GT/s" } } },
2184 	{ -1, -1, NULL }
2185 };
2186 
2187 static pcieadm_regdef_t pcieadm_regdef_pcie2_linkeq[] = {
2188 	{ 0, 3, "dstxpre", "Downstream Port 8.0 GT/s Transmitter Preset",
2189 	    PRDV_HEX },
2190 	{ 4, 6, "dstxhint", "Downstream Port 8.0 GT/s Receiver Hint",
2191 	    PRDV_HEX },
2192 	{ 8, 11, "ustxpre", "Upstream Port 8.0 GT/s Transmitter Preset",
2193 	    PRDV_HEX },
2194 	{ 12, 14, "ustxhint", "Upstream Port 8.0 GT/s Receiver Hint",
2195 	    PRDV_HEX },
2196 	{ -1, -1, NULL }
2197 };
2198 
2199 static void
2200 pcieadm_cfgspace_print_laneq(pcieadm_cfgspace_walk_t *walkp,
2201     pcieadm_cfgspace_print_t *print, void *arg)
2202 {
2203 	if (walkp->pcw_nlanes == 0) {
2204 		warnx("failed to capture lane count, but somehow have "
2205 		    "secondary PCIe cap");
2206 		return;
2207 	}
2208 
2209 	for (uint_t i = 0; i < walkp->pcw_nlanes; i++) {
2210 		char eqshort[32], eqhuman[128];
2211 		pcieadm_cfgspace_print_t p;
2212 
2213 		(void) snprintf(eqshort, sizeof (eqshort), "lane%u", i);
2214 		(void) snprintf(eqhuman, sizeof (eqhuman), "Lane %u EQ Control",
2215 		    i);
2216 		p.pcp_off = print->pcp_off + i * 2;
2217 		p.pcp_len = 2;
2218 		p.pcp_short = eqshort;
2219 		p.pcp_human = eqhuman;
2220 		p.pcp_print = pcieadm_cfgspace_print_regdef;
2221 		p.pcp_arg = pcieadm_regdef_pcie2_linkeq;
2222 
2223 		p.pcp_print(walkp, &p, p.pcp_arg);
2224 	}
2225 }
2226 
2227 static pcieadm_cfgspace_print_t pcieadm_cap_pcie2[] = {
2228 	{ 0x0, 4, "caphdr", "Capability Header",
2229 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2230 	{ 0x4, 4, "linkctl3", "Link Control 3",
2231 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie2_linkctl3 },
2232 	{ 0x8, 4, "laneerr", "Lane Error Status", pcieadm_cfgspace_print_hex },
2233 	{ 0xc, 2, "eqctl", "Lane Equalization Control",
2234 	    pcieadm_cfgspace_print_laneq },
2235 	{ -1, -1, NULL }
2236 };
2237 
2238 /*
2239  * Access Control Services
2240  */
2241 static pcieadm_regdef_t pcieadm_regdef_acs_cap[] = {
2242 	{ 0, 0, "srcvd", "ACS Source Validation", PRDV_STRVAL,
2243 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2244 	{ 1, 1, "tranblk", "ACS Transaction Blocking", PRDV_STRVAL,
2245 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2246 	{ 2, 2, "p2prr", "ACS P2P Request Redirect", PRDV_STRVAL,
2247 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2248 	{ 3, 3, "p2pcr", "ACS P2P Completion Redirect", PRDV_STRVAL,
2249 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2250 	{ 4, 4, "upfwd", "ACS Upstream Forwarding", PRDV_STRVAL,
2251 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2252 	{ 5, 5, "p2pegctl", "ACS P2P Egress Control", PRDV_STRVAL,
2253 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2254 	{ 6, 6, "dtp2p", "ACS Direct Translated P2P", PRDV_STRVAL,
2255 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2256 	{ 7, 7, "enhcap", "ACS Enhanced Capability", PRDV_STRVAL,
2257 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2258 	{ 8, 15, "ecvsz", "Egress Control Vector Size", PRDV_HEX },
2259 	{ -1, -1, NULL }
2260 };
2261 
2262 static pcieadm_regdef_t pcieadm_regdef_acs_ctl[] = {
2263 	{ 0, 0, "srcvd", "ACS Source Validation", PRDV_STRVAL,
2264 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2265 	{ 1, 1, "tranblk", "ACS Transaction Blocking", PRDV_STRVAL,
2266 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2267 	{ 2, 2, "p2prr", "ACS P2P Request Redirect", PRDV_STRVAL,
2268 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2269 	{ 3, 3, "p2pcr", "ACS P2P Completion Redirect", PRDV_STRVAL,
2270 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2271 	{ 4, 4, "upfwd", "ACS Upstream Forwarding", PRDV_STRVAL,
2272 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2273 	{ 5, 5, "p2pegctl", "ACS P2P Egress Control", PRDV_STRVAL,
2274 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2275 	{ 6, 6, "dtp2p", "ACS Direct Translated P2P", PRDV_STRVAL,
2276 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2277 	{ 7, 7, "iorb", "ACS I/O Request Blocking", PRDV_STRVAL,
2278 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2279 	{ 8, 9, "dspmta", "ACS DSP Memory Target Access Control", PRDV_STRVAL,
2280 	    .prd_val = { .prdv_strval = { "Direct Request access",
2281 	    "Request blocking", "Request redirect" } } },
2282 	{ 10, 11, "uspmta", "ACS USP Memory Target Access Control", PRDV_STRVAL,
2283 	    .prd_val = { .prdv_strval = { "Direct Request access",
2284 	    "Request blocking", "Request redirect" } } },
2285 	{ -1, -1, NULL }
2286 };
2287 
2288 static pcieadm_cfgspace_print_t pcieadm_cap_acs[] = {
2289 	{ 0x0, 4, "caphdr", "Capability Header",
2290 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2291 	{ 0x4, 2, "cap", "ACS Capability",
2292 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_acs_cap },
2293 	{ 0x6, 2, "ctl", "ACS Control",
2294 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_acs_ctl },
2295 	{ 0x8, 4, "ecv", "Egress Control Vector", pcieadm_cfgspace_print_ecv },
2296 	{ -1, -1, NULL }
2297 };
2298 
2299 /*
2300  * L1 PM Substates
2301  */
2302 static pcieadm_regdef_t pcieadm_regdef_l1pm_cap[] = {
2303 	{ 0, 0, "pcil1.2", "PCI-PM L1.2", PRDV_STRVAL,
2304 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2305 	{ 1, 1, "pcil1.1", "PCI-PM L1.1", PRDV_STRVAL,
2306 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2307 	{ 2, 2, "aspml1.2", "ASPM L1.2", PRDV_STRVAL,
2308 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2309 	{ 3, 3, "aspml1.1", "ASPM L1.1", PRDV_STRVAL,
2310 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2311 	{ 4, 4, "l1pmsub", "L1 PM Substates", PRDV_STRVAL,
2312 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2313 	{ 5, 5, "linkact", "Link Activation", PRDV_STRVAL,
2314 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2315 	{ 8, 15, "pcmrt", "Port Common_Mode_Restore_Time", PRDV_HEX },
2316 	{ 16, 17, "poscale", "Port T_POWER_ON Scale", PRDV_STRVAL,
2317 	    .prd_val = { .prdv_strval = { "2 us", "10 us", "100 us" } } },
2318 	{ 19, 23, "portpo", "Port T_POWER_ON Value", PRDV_HEX },
2319 	{ -1, -1, NULL }
2320 };
2321 
2322 static pcieadm_regdef_t pcieadm_regdef_l1pm_ctl1[] = {
2323 	{ 0, 0, "pcil1.2", "PCI-PM L1.2", PRDV_STRVAL,
2324 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2325 	{ 1, 1, "pcil1.1", "PCI-PM L1.1", PRDV_STRVAL,
2326 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2327 	{ 2, 2, "aspml1.2", "ASPM L1.2", PRDV_STRVAL,
2328 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2329 	{ 3, 3, "aspml1.1", "ASPM L1.1", PRDV_STRVAL,
2330 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2331 	{ 4, 4, "laie", "Link Activation Interrupt Enable", PRDV_STRVAL,
2332 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2333 	{ 5, 5, "lactl", "Link Activation Control", PRDV_STRVAL,
2334 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2335 	{ 8, 15, "cmrt", "Common_Mode_Restore_Time", PRDV_HEX },
2336 	{ 16, 25, "ltrl1.2", "LTR L1.2 Threshold Value", PRDV_HEX },
2337 	{ 29, 31, "ltrl1.2s", "LTR L1.2 Threshold Scale", PRDV_STRVAL,
2338 	    .prd_val = { .prdv_strval = { "1 ns", "32 ns", "1024 ns",
2339 	    "32,768 ns", "1,048,576 ns", "33,554,432 ns" } } },
2340 	{ -1, -1, NULL }
2341 };
2342 
2343 static pcieadm_regdef_t pcieadm_regdef_l1pm_ctl2[] = {
2344 	{ 0, 1, "poscale", "T_POWER_ON Scale", PRDV_STRVAL,
2345 	    .prd_val = { .prdv_strval = { "2 us", "10 us", "100 us" } } },
2346 	{ 3, 7, "portpo", "T_POWER_ON Value", PRDV_HEX },
2347 	{ -1, -1, NULL }
2348 };
2349 
2350 static pcieadm_regdef_t pcieadm_regdef_l1pm_sts[] = {
2351 	{ 0, 0, "la", "Link Activation", PRDV_HEX },
2352 	{ -1, -1, NULL }
2353 };
2354 
2355 
2356 static pcieadm_cfgspace_print_t pcieadm_cap_l1pm_v1[] = {
2357 	{ 0x0, 4, "caphdr", "Capability Header",
2358 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2359 	{ 0x4, 4, "caps", "L1 PM Substates Capabilities",
2360 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_l1pm_cap },
2361 	{ 0x8, 4, "ctl1", "L1 PM Substates Control 1",
2362 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_l1pm_ctl1 },
2363 	{ 0xc, 4, "ctl1", "L1 PM Substates Control 2",
2364 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_l1pm_ctl2 },
2365 	{ -1, -1, NULL }
2366 };
2367 
2368 static pcieadm_cfgspace_print_t pcieadm_cap_l1pm_v2[] = {
2369 	{ 0x0, 4, "caphdr", "Capability Header",
2370 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2371 	{ 0x4, 4, "caps", "L1 PM Substates Capabilities",
2372 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_l1pm_cap },
2373 	{ 0x8, 4, "ctl1", "L1 PM Substates Control 1",
2374 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_l1pm_ctl1 },
2375 	{ 0xc, 4, "ctl1", "L1 PM Substates Control 2",
2376 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_l1pm_ctl2 },
2377 	{ 0x10, 4, "sts", "L1 PM Substates Status",
2378 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_l1pm_sts },
2379 	{ -1, -1, NULL }
2380 };
2381 
2382 /*
2383  * Latency Tolerance Reporting (LTR)
2384  */
2385 static pcieadm_regdef_t pcieadm_regdef_ltr[] = {
2386 	{ 0, 9, "latval", "Latency Value", PRDV_HEX },
2387 	{ 10, 12, "latscale", "Latency Scale", PRDV_STRVAL,
2388 	    .prd_val = { .prdv_strval = { "1 ns", "32 ns", "1024 ns",
2389 	    "32,768 ns", "1,048,576 ns", "33,554,432 ns" } } },
2390 	{ -1, -1, NULL }
2391 };
2392 
2393 static pcieadm_cfgspace_print_t pcieadm_cap_ltr[] = {
2394 	{ 0x0, 4, "caphdr", "Capability Header",
2395 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2396 	{ 0x4, 2, "snoop", "Max Snoop Latency",
2397 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ltr },
2398 	{ 0x6, 2, "snoop", "Max No-Snoop Latency",
2399 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ltr },
2400 	{ -1, -1, NULL }
2401 };
2402 
2403 /*
2404  * Alternative Routing ID
2405  */
2406 static pcieadm_regdef_t pcieadm_regdef_ari_cap[] = {
2407 	{ 0, 0, "mfvcfg", "MFVC Function Groups", PRDV_STRVAL,
2408 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2409 	{ 1, 1, "acsfg", "ACS Function Groups", PRDV_STRVAL,
2410 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2411 	{ 8, 15, "nfunc", "Next Function Number", PRDV_HEX },
2412 	{ -1, -1, NULL }
2413 };
2414 
2415 static pcieadm_regdef_t pcieadm_regdef_ari_ctl[] = {
2416 	{ 0, 0, "mfvcfg", "MFVC Function Groups", PRDV_STRVAL,
2417 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2418 	{ 1, 1, "acsfg", "ACS Function Groups", PRDV_STRVAL,
2419 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2420 	{ 4, 6, "fgrp", "Function Group", PRDV_HEX },
2421 	{ -1, -1, NULL }
2422 };
2423 
2424 static pcieadm_cfgspace_print_t pcieadm_cap_ari[] = {
2425 	{ 0x0, 4, "caphdr", "Capability Header",
2426 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2427 	{ 0x4, 2, "cap", "ARI Capability",
2428 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ari_cap },
2429 	{ 0x6, 2, "ctl", "ARI Control",
2430 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ari_ctl },
2431 	{ -1, -1, NULL }
2432 };
2433 
2434 /*
2435  * PASID
2436  */
2437 static pcieadm_regdef_t pcieadm_regdef_pasid_cap[] = {
2438 	{ 1, 1, "exec", "Execution Permission", PRDV_STRVAL,
2439 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2440 	{ 2, 2, "priv", "Privileged Mode", PRDV_STRVAL,
2441 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2442 	{ 8, 12, "width", "Max PASID Width", PRDV_HEX },
2443 	{ -1, -1, NULL }
2444 };
2445 
2446 static pcieadm_regdef_t pcieadm_regdef_pasid_ctl[] = {
2447 	{ 0, 0, "pasid", "PASID", PRDV_STRVAL,
2448 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2449 	{ 1, 1, "exec", "Execution Permission", PRDV_STRVAL,
2450 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2451 	{ 2, 2, "priv", "Privileged Mode", PRDV_STRVAL,
2452 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2453 	{ -1, -1, NULL }
2454 };
2455 
2456 
2457 static pcieadm_cfgspace_print_t pcieadm_cap_pasid[] = {
2458 	{ 0x0, 4, "caphdr", "Capability Header",
2459 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2460 	{ 0x4, 2, "cap", "PASID Capability",
2461 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pasid_cap },
2462 	{ 0x6, 2, "ctl", "PASID Control",
2463 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pasid_ctl },
2464 	{ -1, -1, NULL }
2465 };
2466 
2467 /*
2468  * "Advanced Features"
2469  */
2470 static pcieadm_regdef_t pcieadm_regdef_af_cap[] = {
2471 	{ 0, 0, "tp", "Transactions Pending", PRDV_STRVAL,
2472 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2473 	{ 1, 1, "flr", "Function Level Reset", PRDV_STRVAL,
2474 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2475 	{ -1, -1, NULL }
2476 };
2477 
2478 static pcieadm_regdef_t pcieadm_regdef_af_ctl[] = {
2479 	{ 0, 0, "flr", "Function Level Reset", PRDV_HEX },
2480 	{ -1, -1, NULL }
2481 };
2482 
2483 static pcieadm_regdef_t pcieadm_regdef_af_sts[] = {
2484 	{ 0, 0, "tp", "Transactions Pending", PRDV_STRVAL,
2485 	    .prd_val = { .prdv_strval = { "none pending", "pending" } } },
2486 	{ -1, -1, NULL }
2487 };
2488 
2489 static pcieadm_cfgspace_print_t pcieadm_cap_af[] = {
2490 	{ 0x2, 2, "cap", "AF Capabilities",
2491 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_af_cap },
2492 	{ 0x4, 1, "ctl", "AF Control",
2493 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_af_ctl },
2494 	{ 0x5, 1, "sts", "AF Status",
2495 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_af_sts },
2496 	{ -1, -1, NULL }
2497 };
2498 
2499 /*
2500  * Multicast
2501  */
2502 static pcieadm_regdef_t pcieadm_regdef_mcast_cap[] = {
2503 	{ 0, 5, "maxgrp", "Max Group", PRDV_HEX,
2504 	    .prd_val = { .prdv_hex = { 0, 1 } } },
2505 	{ 8, 13, "winsize", "Window Size (raw)", PRDV_HEX },
2506 	{ 15, 15, "ecrc", "ECRC Regeneration", PRDV_STRVAL,
2507 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2508 	{ -1, -1, NULL }
2509 };
2510 
2511 static pcieadm_regdef_t pcieadm_regdef_mcast_ctl[] = {
2512 	{ 0, 5, "numgrp", "Number of Groups", PRDV_HEX,
2513 	    .prd_val = { .prdv_hex = { 0, 1 } } },
2514 	{ 15, 15, "enable", "Enable", PRDV_STRVAL,
2515 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2516 	{ -1, -1, NULL }
2517 };
2518 
2519 static pcieadm_regdef_t pcieadm_regdef_mcast_base[] = {
2520 	{ 0, 5, "index", "Multicast Index Position", PRDV_HEX },
2521 	{ 12, 63, "addr", "Base Address", PRDV_HEX,
2522 	    .prd_val = { .prdv_hex = { 12 } } },
2523 	{ -1, -1, NULL }
2524 };
2525 
2526 static pcieadm_regdef_t pcieadm_regdef_mcast_overlay[] = {
2527 	{ 0, 5, "size", "Overlay Size (raw)", PRDV_HEX },
2528 	{ 6, 63, "addr", "Overlay Base Address", PRDV_HEX,
2529 	    .prd_val = { .prdv_hex = { 6 } } },
2530 	{ -1, -1, NULL }
2531 };
2532 
2533 static pcieadm_cfgspace_print_t pcieadm_cap_mcast[] = {
2534 	{ 0x0, 4, "caphdr", "Capability Header",
2535 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2536 	{ 0x4, 2, "cap", "Multicast Capability",
2537 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_mcast_cap },
2538 	{ 0x6, 2, "ctl", "Multicast Control",
2539 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_mcast_ctl },
2540 	{ 0x8, 8, "base", "Multicast Base Address",
2541 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_mcast_base },
2542 	{ 0x10, 8, "rx", "Multicast Receive", pcieadm_cfgspace_print_hex },
2543 	{ 0x18, 8, "block", "Multicast Block All", pcieadm_cfgspace_print_hex },
2544 	{ 0x20, 8, "blockun", "Multicast Block Untranslated",
2545 	    pcieadm_cfgspace_print_hex },
2546 	{ 0x28, 8, "overlay", "Multicast Overlay BAR",
2547 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_mcast_overlay },
2548 	{ -1, -1, NULL }
2549 };
2550 
2551 /*
2552  * Various vendor extensions
2553  */
2554 static pcieadm_regdef_t pcieadm_regdef_vsec[] = {
2555 	{ 0, 15, "id", "ID", PRDV_HEX },
2556 	{ 16, 19, "rev", "Revision", PRDV_HEX },
2557 	{ 20, 31, "len", "Length", PRDV_HEX },
2558 	{ -1, -1, NULL }
2559 };
2560 
2561 static pcieadm_cfgspace_print_t pcieadm_cap_vs[] = {
2562 	{ 0x2, 2, "length", "Length", pcieadm_cfgspace_print_hex },
2563 	{ -1, -1, NULL }
2564 };
2565 
2566 static pcieadm_cfgspace_print_t pcieadm_cap_vsec[] = {
2567 	{ 0x0, 4, "caphdr", "Capability Header",
2568 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2569 	{ 0x4, 4, "header", "Vendor-Specific Header",
2570 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_vsec },
2571 	{ -1, -1, NULL }
2572 };
2573 
2574 /*
2575  * Data Link Feature
2576  */
2577 static pcieadm_regdef_t pcieadm_regdef_dlf_cap[] = {
2578 	{ 0, 0, "lsfc", "Local Scaled Flow Control", PRDV_STRVAL,
2579 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2580 	{ 31, 31, "dlex", "Data Link Exchange", PRDV_STRVAL,
2581 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2582 	{ -1, -1, NULL }
2583 };
2584 
2585 static pcieadm_regdef_t pcieadm_regdef_dlf_sts[] = {
2586 	{ 0, 0, "rsfc", "Remote Scaled Flow Control", PRDV_STRVAL,
2587 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2588 	{ 31, 31, "valid", "Remote Data Link Feature Valid", PRDV_STRVAL,
2589 	    .prd_val = { .prdv_strval = { "invalid", "valid" } } },
2590 	{ -1, -1, NULL }
2591 };
2592 
2593 static pcieadm_cfgspace_print_t pcieadm_cap_dlf[] = {
2594 	{ 0x0, 4, "caphdr", "Capability Header",
2595 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2596 	{ 0x4, 4, "cap", "Data Link Feature Capabilities",
2597 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_dlf_cap },
2598 	{ 0x8, 4, "sts", "Data Link Feature Status",
2599 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_dlf_sts },
2600 	{ -1, -1, NULL }
2601 };
2602 
2603 /*
2604  * 16.0 GT/s cap
2605  */
2606 static pcieadm_regdef_t pcieadm_regdef_16g_cap[] = {
2607 	{ -1, -1, NULL }
2608 };
2609 
2610 static pcieadm_regdef_t pcieadm_regdef_16g_ctl[] = {
2611 	{ -1, -1, NULL }
2612 };
2613 
2614 static pcieadm_regdef_t pcieadm_regdef_16g_sts[] = {
2615 	{ 0, 0, "eqcomp", "Equalization 16.0 GT/s Complete", PRDV_STRVAL,
2616 	    .prd_val = { .prdv_strval = { "incomplete", "complete" } } },
2617 	{ 1, 1, "eqp1", "Equalization 16.0 GT/s Phase 1", PRDV_STRVAL,
2618 	    .prd_val = { .prdv_strval = { "incomplete", "complete" } } },
2619 	{ 2, 2, "eqp2", "Equalization 16.0 GT/s Phase 2", PRDV_STRVAL,
2620 	    .prd_val = { .prdv_strval = { "incomplete", "complete" } } },
2621 	{ 3, 3, "eqp3", "Equalization 16.0 GT/s Phase 3", PRDV_STRVAL,
2622 	    .prd_val = { .prdv_strval = { "incomplete", "complete" } } },
2623 	{ 4, 4, "req", "Link Equalization Request 16.0 GT/s", PRDV_HEX },
2624 	{ -1, -1, NULL }
2625 };
2626 
2627 static pcieadm_regdef_t pcieadm_regdef_16g_eq[] = {
2628 	{ 0, 3, "dstxpre", "Downstream Port 16.0 GT/s Transmitter Preset",
2629 	    PRDV_HEX },
2630 	{ 4, 7, "ustxpre", "Upstream Port 16.0 GT/s Transmitter Preset",
2631 	    PRDV_HEX },
2632 	{ -1, -1, NULL }
2633 };
2634 
2635 static void
2636 pcieadm_cfgspace_print_16geq(pcieadm_cfgspace_walk_t *walkp,
2637     pcieadm_cfgspace_print_t *print, void *arg)
2638 {
2639 	if (walkp->pcw_nlanes == 0) {
2640 		warnx("failed to capture lane count, but somehow have "
2641 		    "secondary PCIe cap");
2642 		return;
2643 	}
2644 
2645 	for (uint_t i = 0; i < walkp->pcw_nlanes; i++) {
2646 		char eqshort[32], eqhuman[128];
2647 		pcieadm_cfgspace_print_t p;
2648 
2649 		(void) snprintf(eqshort, sizeof (eqshort), "lane%u", i);
2650 		(void) snprintf(eqhuman, sizeof (eqhuman), "Lane %u EQ Control",
2651 		    i);
2652 		p.pcp_off = print->pcp_off + i * 1;
2653 		p.pcp_len = 1;
2654 		p.pcp_short = eqshort;
2655 		p.pcp_human = eqhuman;
2656 		p.pcp_print = pcieadm_cfgspace_print_regdef;
2657 		p.pcp_arg = pcieadm_regdef_16g_eq;
2658 
2659 		p.pcp_print(walkp, &p, p.pcp_arg);
2660 	}
2661 }
2662 
2663 static pcieadm_cfgspace_print_t pcieadm_cap_16g[] = {
2664 	{ 0x0, 4, "caphdr", "Capability Header",
2665 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2666 	{ 0x4, 4, "cap", "16.0 GT/s Capabilities",
2667 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_16g_cap },
2668 	{ 0x8, 4, "ctl", "16.0 GT/s Control",
2669 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_16g_ctl },
2670 	{ 0xc, 4, "sts", "16.0 GT/s Status",
2671 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_16g_sts },
2672 	{ 0x10, 4, "ldpmis", "16.0 GT/s Local Data Parity Mismatch",
2673 	    pcieadm_cfgspace_print_hex },
2674 	{ 0x14, 4, "frpmis", "16.0 GT/s First Retimer Data Parity Mismatch",
2675 	    pcieadm_cfgspace_print_hex },
2676 	{ 0x18, 4, "srpmis", "16.0 GT/s Second Retimer Data Parity Mismatch",
2677 	    pcieadm_cfgspace_print_hex },
2678 	{ 0x1c, 4, "rsvd", "16.0 GT/s Second Retimer Data Parity Mismatch",
2679 	    pcieadm_cfgspace_print_hex },
2680 	{ 0x20, 1, "eqctl", "16.0 GT/s EQ Control",
2681 	    pcieadm_cfgspace_print_16geq },
2682 	{ -1, -1, NULL }
2683 };
2684 
2685 /*
2686  * Receiver Margining
2687  */
2688 static pcieadm_regdef_t pcieadm_regdef_margin_cap[] = {
2689 	{ 0, 0, "sw", "Margining uses Driver Software", PRDV_STRVAL,
2690 	    .prd_val = { .prdv_strval = { "no", "yes" } } },
2691 	{ -1, -1, NULL }
2692 };
2693 
2694 static pcieadm_regdef_t pcieadm_regdef_margin_sts[] = {
2695 	{ 0, 0, "ready", "Margining Ready", PRDV_STRVAL,
2696 	    .prd_val = { .prdv_strval = { "no", "yes" } } },
2697 	{ 1, 1, "sw", "Margining Software Ready", PRDV_STRVAL,
2698 	    .prd_val = { .prdv_strval = { "no", "yes" } } },
2699 	{ -1, -1, NULL }
2700 };
2701 
2702 static pcieadm_regdef_t pcieadm_regdef_margin_lane[] = {
2703 	{ 0, 2, "rxno", "Receiver Number", PRDV_HEX },
2704 	{ 3, 5, "type", "Margin Type", PRDV_HEX },
2705 	{ 6, 6, "model", "Usage Model", PRDV_HEX },
2706 	{ 8, 15, "payload", "Margin Payload", PRDV_HEX },
2707 	{ -1, -1, NULL }
2708 };
2709 
2710 static void
2711 pcieadm_cfgspace_print_margin(pcieadm_cfgspace_walk_t *walkp,
2712     pcieadm_cfgspace_print_t *print, void *arg)
2713 {
2714 	if (walkp->pcw_nlanes == 0) {
2715 		warnx("failed to capture lane count, but somehow have "
2716 		    "lane margining capability");
2717 		return;
2718 	}
2719 
2720 	for (uint_t i = 0; i < walkp->pcw_nlanes; i++) {
2721 		char mshort[32], mhuman[128];
2722 		pcieadm_cfgspace_print_t p;
2723 
2724 		(void) snprintf(mshort, sizeof (mshort), "lane%uctl", i);
2725 		(void) snprintf(mhuman, sizeof (mhuman), "Lane %u Margining "
2726 		    "Control", i);
2727 		p.pcp_off = print->pcp_off + i * 4;
2728 		p.pcp_len = 2;
2729 		p.pcp_short = mshort;
2730 		p.pcp_human = mhuman;
2731 		p.pcp_print = pcieadm_cfgspace_print_regdef;
2732 		p.pcp_arg = pcieadm_regdef_margin_lane;
2733 
2734 		p.pcp_print(walkp, &p, p.pcp_arg);
2735 
2736 		(void) snprintf(mshort, sizeof (mshort), "lane%usts", i);
2737 		(void) snprintf(mhuman, sizeof (mhuman), "Lane %u Margining "
2738 		    "Status", i);
2739 		p.pcp_off = print->pcp_off + 2 + i * 4;
2740 		p.pcp_len = 2;
2741 		p.pcp_short = mshort;
2742 		p.pcp_human = mhuman;
2743 		p.pcp_print = pcieadm_cfgspace_print_regdef;
2744 		p.pcp_arg = pcieadm_regdef_margin_lane;
2745 
2746 		p.pcp_print(walkp, &p, p.pcp_arg);
2747 	}
2748 }
2749 
2750 static pcieadm_cfgspace_print_t pcieadm_cap_margin[] = {
2751 	{ 0x0, 4, "caphdr", "Capability Header",
2752 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2753 	{ 0x4, 2, "cap", "Margining Port Capabilities",
2754 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_margin_cap },
2755 	{ 0x6, 2, "sts", "Margining Port Status",
2756 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_margin_sts },
2757 	{ 0x8, 4, "lane", "Margining Lane", pcieadm_cfgspace_print_margin },
2758 	{ -1, -1, NULL }
2759 };
2760 
2761 /*
2762  * Serial Number Capability
2763  */
2764 static void
2765 pcieadm_cfgspace_print_sn(pcieadm_cfgspace_walk_t *walkp,
2766     pcieadm_cfgspace_print_t *print, void *arg)
2767 {
2768 	char sn[64];
2769 	uint16_t off = walkp->pcw_capoff + print->pcp_off;
2770 
2771 	(void) snprintf(sn, sizeof (sn),
2772 	    "%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x",
2773 	    walkp->pcw_data->pcb_u8[off + 7], walkp->pcw_data->pcb_u8[off + 6],
2774 	    walkp->pcw_data->pcb_u8[off + 5], walkp->pcw_data->pcb_u8[off + 4],
2775 	    walkp->pcw_data->pcb_u8[off + 3], walkp->pcw_data->pcb_u8[off + 2],
2776 	    walkp->pcw_data->pcb_u8[off + 1], walkp->pcw_data->pcb_u8[off]);
2777 
2778 	pcieadm_cfgspace_puts(walkp, print, sn);
2779 }
2780 
2781 static pcieadm_cfgspace_print_t pcieadm_cap_sn[] = {
2782 	{ 0x0, 4, "caphdr", "Capability Header",
2783 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2784 	{ 0x4, 8, "sn", "Serial Number", pcieadm_cfgspace_print_sn },
2785 	{ -1, -1, NULL }
2786 };
2787 
2788 /*
2789  * TLP Processing Hints (TPH)
2790  */
2791 static pcieadm_regdef_t pcieadm_regdef_tph_cap[] = {
2792 	{ 0, 0, "nost", "No ST Mode", PRDV_STRVAL,
2793 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2794 	{ 1, 1, "ivec", "Interrupt Vector Mode", PRDV_STRVAL,
2795 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2796 	{ 2, 2, "dev", "Device Specific Mode", PRDV_STRVAL,
2797 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2798 	{ 8, 8, "exttph", "Extended TPH Requester", PRDV_STRVAL,
2799 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2800 	{ 9, 10, "loc", "ST Table Location", PRDV_STRVAL,
2801 	    .prd_val = { .prdv_strval = { "Not Present",
2802 	    "In Capability Structure", "MSI-X" } } },
2803 	{ 16, 26, "size", "ST Table Size", PRDV_HEX, { .prdv_hex = { 0, 1 } } },
2804 	{ -1, -1, NULL }
2805 };
2806 
2807 static pcieadm_regdef_t pcieadm_regdef_tph_ctl[] = {
2808 	{ 0, 2, "mode", "ST Mode Select", PRDV_STRVAL,
2809 	    .prd_val = { .prdv_strval = { "No ST", "Interrupt Vector",
2810 	    "Device Specific" } } },
2811 	{ 8, 9, "en", "TPH Requester", PRDV_STRVAL,
2812 	    .prd_val = { .prdv_strval = { "Not Permitted", "TPH", NULL,
2813 	    "TPH and Extended TPH" } } },
2814 	{ -1, -1, NULL }
2815 };
2816 
2817 static pcieadm_regdef_t pcieadm_regdef_tph_st[] = {
2818 	{ 0, 7, "low", "ST Lower", PRDV_HEX },
2819 	{ 8, 15, "up", "ST Upper", PRDV_HEX },
2820 	{ -1, -1, NULL }
2821 };
2822 
2823 /*
2824  * The TPH ST table is only conditionally present in the capability. So we need
2825  * to read the TPH capability register and then check if the table location and
2826  * size are set here.
2827  */
2828 static void
2829 pcieadm_cfgspace_print_tphst(pcieadm_cfgspace_walk_t *walkp,
2830     pcieadm_cfgspace_print_t *print, void *arg)
2831 {
2832 	uint_t nents;
2833 	uint32_t tphcap = walkp->pcw_data->pcb_u32[(walkp->pcw_capoff + 4) / 4];
2834 
2835 	if (BITX(tphcap, 10, 9) != 1) {
2836 		return;
2837 	}
2838 
2839 	nents = BITX(tphcap, 26, 16) + 1;
2840 	for (uint_t i = 0; i < nents; i++) {
2841 		char tshort[32], thuman[128];
2842 		pcieadm_cfgspace_print_t p;
2843 
2844 		(void) snprintf(tshort, sizeof (tshort), "st%u", i);
2845 		(void) snprintf(thuman, sizeof (thuman), "ST Table %u",
2846 		    i);
2847 		p.pcp_off = print->pcp_off + i * 2;
2848 		p.pcp_len = 2;
2849 		p.pcp_short = tshort;
2850 		p.pcp_human = thuman;
2851 		p.pcp_print = pcieadm_cfgspace_print_regdef;
2852 		p.pcp_arg = pcieadm_regdef_tph_st;
2853 
2854 		p.pcp_print(walkp, &p, p.pcp_arg);
2855 	}
2856 }
2857 
2858 static pcieadm_cfgspace_print_t pcieadm_cap_tph[] = {
2859 	{ 0x0, 4, "caphdr", "Capability Header",
2860 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2861 	{ 0x4, 4, "cap", "TPH Requester Capability",
2862 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_tph_cap },
2863 	{ 0x8, 4, "ctl", "TPH Requester Control",
2864 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_tph_ctl },
2865 	{ 0xc, 2, "table", "ST Table", pcieadm_cfgspace_print_tphst },
2866 	{ -1, -1, NULL }
2867 };
2868 
2869 /*
2870  * SR-IOV
2871  */
2872 static pcieadm_regdef_t pcieadm_regdef_sriov_cap[] = {
2873 	{ 0, 0, "migration", "Migration", PRDV_STRVAL,
2874 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
2875 	{ 1, 1, "ari", "ARI Capable Hierarchy Preserved", PRDV_STRVAL,
2876 	    .prd_val = { .prdv_strval = { "unpreserved", "preserved" } } },
2877 	{ 2, 2, "vf10b", "VF 10-bit Tag Requester", PRDV_STRVAL,
2878 	    .prd_val = { .prdv_strval = { "unpreserved", "preserved" } } },
2879 	{ 21, 31, "inum", "VF Migration Interrupt Message Number", PRDV_HEX },
2880 	{ -1, -1, NULL }
2881 };
2882 
2883 static pcieadm_regdef_t pcieadm_regdef_sriov_ctl[] = {
2884 	{ 0, 0, "vf", "VF", PRDV_STRVAL,
2885 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2886 	{ 1, 1, "vfm", "VF Migration", PRDV_STRVAL,
2887 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2888 	{ 2, 2, "vfmi", "VF Migration Interrupt", PRDV_STRVAL,
2889 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2890 	{ 3, 3, "ari", "ARI Capable Hierarchy", PRDV_STRVAL,
2891 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2892 	{ 4, 4, "vf10b", "VF 10-bit Tag Requester", PRDV_STRVAL,
2893 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2894 	{ -1, -1, NULL }
2895 };
2896 
2897 static pcieadm_regdef_t pcieadm_regdef_sriov_sts[] = {
2898 	{ 0, 0, "vfm", "VF Migration", PRDV_STRVAL,
2899 	    .prd_val = { .prdv_strval = { "none", "requested" } } },
2900 	{ -1, -1, NULL }
2901 };
2902 
2903 static pcieadm_regdef_t pcieadm_regdef_sriov_pgsup[] = {
2904 	{ 0, 31, "pgsz", "Supported Page Sizes", PRDV_BITFIELD,
2905 	    .prd_val = { .prdv_strval = { "4 KB", "8 KB", "16 KB", "32 KB",
2906 	    "64 KB", "128 KB", "256 KB", "512 KB", "1 MB", "2 MB", "4 MB",
2907 	    "8 MB", "16 MB", "32 MB", "64 MB", "128 MB", "256 MB", "512 MB",
2908 	    "1 GB", "2 GB", "4 GB", "8 GB", "16 GB", "32 GB", "64 GB",
2909 	    "128 GB", "256 GB", "512 GB", "1 TB", "2 TB", "4 TB", "8 TB" } } },
2910 	{ -1, -1, NULL }
2911 };
2912 
2913 static pcieadm_regdef_t pcieadm_regdef_sriov_pgen[] = {
2914 	{ 0, 31, "pgsz", "System Page Sizes", PRDV_BITFIELD,
2915 	    .prd_val = { .prdv_strval = { "4 KB", "8 KB", "16 KB", "32 KB",
2916 	    "64 KB", "128 KB", "256 KB", "512 KB", "1 MB", "2 MB", "4 MB",
2917 	    "8 MB", "16 MB", "32 MB", "64 MB", "128 MB", "256 MB", "512 MB",
2918 	    "1 GB", "2 GB", "4 GB", "8 GB", "16 GB", "32 GB", "64 GB",
2919 	    "128 GB", "256 GB", "512 GB", "1 TB", "2 TB", "4 TB", "8 TB" } } },
2920 	{ -1, -1, NULL }
2921 };
2922 
2923 static pcieadm_regdef_t pcieadm_regdef_sriov_mig[] = {
2924 	{ 0, 2, "bir", "VF Migration State BIR", PRDV_STRVAL,
2925 	    .prd_val = { .prdv_strval = { "BAR 0", "BAR 1", "BAR 2", "BAR 3",
2926 	    "BAR 4", "BAR 5" } } },
2927 	{ 3, 31, "offset", "VF Migration State Offset", PRDV_HEX,
2928 	    .prd_val = { .prdv_hex = { 3 } } },
2929 	{ -1, -1, NULL }
2930 };
2931 
2932 static pcieadm_cfgspace_print_t pcieadm_cap_sriov[] = {
2933 	{ 0x0, 4, "caphdr", "Capability Header",
2934 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
2935 	{ 0x4, 4, "cap", "SR-IOV Capabilities",
2936 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_sriov_cap },
2937 	{ 0x8, 2, "ctl", "SR-IOV Control",
2938 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_sriov_ctl },
2939 	{ 0xa, 2, "sts", "SR-IOV Status",
2940 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_sriov_sts },
2941 	{ 0xc, 2, "initvfs", "Initial VFs", pcieadm_cfgspace_print_hex },
2942 	{ 0xe, 2, "totvfs", "Total VFs", pcieadm_cfgspace_print_hex },
2943 	{ 0x10, 2, "numvfs", "Number VFs", pcieadm_cfgspace_print_hex },
2944 	{ 0x12, 1, "dep", "Function Dependency Link",
2945 	    pcieadm_cfgspace_print_hex },
2946 	{ 0x14, 2, "offset", "First VF Offset", pcieadm_cfgspace_print_hex },
2947 	{ 0x16, 2, "stride", "VF Stride", pcieadm_cfgspace_print_hex },
2948 	{ 0x1a, 2, "devid", "VF Device ID", pcieadm_cfgspace_print_hex },
2949 	{ 0x1c, 4, "pgsz", "Supported Page Sizes",
2950 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_sriov_pgsup },
2951 	{ 0x20, 4, "pgsz", "System Page Sizes",
2952 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_sriov_pgen },
2953 	{ 0x24, 24, "vfbar", "Virtual Base Address Register",
2954 	    pcieadm_cfgspace_print_bars },
2955 	{ 0x3c, 4, "migration", "VF Migration State Array",
2956 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_sriov_mig },
2957 	{ -1, -1, NULL }
2958 };
2959 
2960 /*
2961  * PCI-X
2962  */
2963 static pcieadm_regdef_t pcieadm_regdef_pcix_dev_ctl[] = {
2964 	{ 0, 0, "dper", "Data Parity Error Recovery", PRDV_STRVAL,
2965 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2966 	{ 1, 1, "ro", "Relaxed Ordering", PRDV_STRVAL,
2967 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
2968 	{ 2, 3, "maxread", "Maximum Memory Read Byte Count", PRDV_STRVAL,
2969 	    .prd_val = { .prdv_strval = { "512 bytes", "1024 bytes",
2970 	    "2048 byes", "4096 bytes" } } },
2971 	{ 4, 6, "maxsplit", "Maximum Outstanding Split Transactions",
2972 	    PRDV_STRVAL, .prd_val = { .prdv_strval = { "1", "2", "3", "4", "8",
2973 	    "12", "16", "32" } } },
2974 	{ -1, -1, NULL }
2975 };
2976 
2977 static pcieadm_regdef_t pcieadm_regdef_pcix_dev_sts[] = {
2978 	{ 0, 2, "func", "Function Number", PRDV_HEX },
2979 	{ 3, 7, "dev", "Device Number", PRDV_HEX },
2980 	{ 8, 15, "bus", "Bus Number", PRDV_HEX },
2981 	{ 16, 16, "64bit", "64-bit Device", PRDV_STRVAL,
2982 	    .prd_val = { .prdv_strval = { "unsupported (32-bit)",
2983 	    "supported" } } },
2984 	{ 17, 17, "133mhz", "133 MHz Capable", PRDV_STRVAL,
2985 	    .prd_val = { .prdv_strval = { "unsupported (66 MHz)",
2986 	    "supported" } } },
2987 	{ 18, 18, "spcodis", "Split Completion Discarded", PRDV_STRVAL,
2988 	    .prd_val = { .prdv_strval = { "no", "yes" } } },
2989 	{ 19, 19, "unspco", "Unexpected Split Completion", PRDV_STRVAL,
2990 	    .prd_val = { .prdv_strval = { "no", "yes" } } },
2991 	{ 20, 20, "complex", "Device Complexity", PRDV_STRVAL,
2992 	    .prd_val = { .prdv_strval = { "simple", "bridge" } } },
2993 	{ 21, 22, "maxread", "Designed Maximum Memory Read Byte Count",
2994 	    PRDV_STRVAL, .prd_val = { .prdv_strval = { "512 bytes",
2995 	    "1024 bytes", "2048 byes", "4096 bytes" } } },
2996 	{ 23, 25, "maxsplit", "Designed Maximum Outstanding Split Transactions",
2997 	    PRDV_STRVAL, .prd_val = { .prdv_strval = { "1", "2", "3", "4", "8",
2998 	    "12", "16", "32" } } },
2999 	{ 26, 28, "maxcread", "Designed Maximum Cumulative Read Size",
3000 	    PRDV_STRVAL, .prd_val = { .prdv_strval = { "8/1KB", "16/2KB",
3001 	    "32/4KB", "64/8KB", "128/16KB", "256/32KB", "512/64KB",
3002 	    "1024/128KB" } } },
3003 	{ 29, 29, "rxspcoer", "Received Split Completion Error Message",
3004 	    PRDV_STRVAL, .prd_val = { .prdv_strval = { "no", "yes" } } },
3005 	{ -1, -1, NULL }
3006 };
3007 
3008 static pcieadm_regdef_t pcieadm_regdef_pcix_sec_sts[] = {
3009 	{ 0, 0, "64bit", "64-bit Device", PRDV_STRVAL,
3010 	    .prd_val = { .prdv_strval = { "unsupported (32-bit)",
3011 	    "supported" } } },
3012 	{ 1, 1, "133mhz", "133 MHz Capable", PRDV_STRVAL,
3013 	    .prd_val = { .prdv_strval = { "unsupported (66 MHz)",
3014 	    "supported" } } },
3015 	{ 2, 2, "spcodis", "Split Completion Discarded", PRDV_STRVAL,
3016 	    .prd_val = { .prdv_strval = { "no", "yes" } } },
3017 	{ 3, 3, "unspco", "Unexpected Split Completion", PRDV_STRVAL,
3018 	    .prd_val = { .prdv_strval = { "no", "yes" } } },
3019 	{ 4, 4, "spcoor", "Split Completion Overrun", PRDV_STRVAL,
3020 	    .prd_val = { .prdv_strval = { "no", "yes" } } },
3021 	{ 5, 5, "sprde", "Split Request Delayed", PRDV_STRVAL,
3022 	    .prd_val = { .prdv_strval = { "no", "yes" } } },
3023 	{ 6, 8, "freq", "Secondary Clock Frequency", PRDV_STRVAL,
3024 	    .prd_val = { .prdv_strval = { "conventional", "66 MHz", "100 Mhz",
3025 	    "133 MHz" } } },
3026 	{ -1, -1, NULL }
3027 };
3028 
3029 static pcieadm_regdef_t pcieadm_regdef_pcix_bridge_sts[] = {
3030 	{ 0, 2, "func", "Function Number", PRDV_HEX },
3031 	{ 3, 7, "dev", "Device Number", PRDV_HEX },
3032 	{ 8, 15, "bus", "Bus Number", PRDV_HEX },
3033 	{ 16, 16, "64bit", "64-bit Device", PRDV_STRVAL,
3034 	    .prd_val = { .prdv_strval = { "unsupported (32-bit)",
3035 	    "supported" } } },
3036 	{ 17, 17, "133mhz", "133 MHz Capable", PRDV_STRVAL,
3037 	    .prd_val = { .prdv_strval = { "unsupported (66 MHz)",
3038 	    "supported" } } },
3039 	{ 18, 18, "spcodis", "Split Completion Discarded", PRDV_STRVAL,
3040 	    .prd_val = { .prdv_strval = { "no", "yes" } } },
3041 	{ 19, 19, "unspco", "Unexpected Split Completion", PRDV_STRVAL,
3042 	    .prd_val = { .prdv_strval = { "no", "yes" } } },
3043 	{ 20, 20, "spcoor", "Split Completion Overrun", PRDV_STRVAL,
3044 	    .prd_val = { .prdv_strval = { "no", "yes" } } },
3045 	{ 21, 21, "sprde", "Split Request Delayed", PRDV_STRVAL,
3046 	    .prd_val = { .prdv_strval = { "no", "yes" } } },
3047 	{ -1, -1, NULL }
3048 };
3049 
3050 static pcieadm_regdef_t pcieadm_regdef_pcix_bridge_split[] = {
3051 	{ 0, 15, "cap", "Split Transaction Capacity", PRDV_HEX },
3052 	{ 16, 31, "limit", "Split Transaction Commitment Limit", PRDV_HEX },
3053 	{ -1, -1, NULL }
3054 };
3055 
3056 static pcieadm_cfgspace_print_t pcieadm_cap_pcix_dev[] = {
3057 	{ 0x2, 2, "ctl", "PCI-X Command",
3058 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcix_dev_ctl },
3059 	{ 0x4, 4, "sts", "PCI-X Status",
3060 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcix_dev_sts },
3061 	{ -1, -1, NULL }
3062 };
3063 
3064 static pcieadm_cfgspace_print_t pcieadm_cap_pcix_bridge[] = {
3065 	{ 0x2, 2, "secsts", "PCI-X Secondary Status",
3066 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcix_sec_sts },
3067 	{ 0x4, 4, "sts", "PCI-X Bridge Status",
3068 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcix_bridge_sts },
3069 	{ 0x8, 4, "ussplit", "Upstream Split Transaction",
3070 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcix_bridge_split },
3071 	{ 0x8, 4, "dssplit", "Downstream Split Transaction",
3072 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcix_bridge_split },
3073 	{ -1, -1, NULL }
3074 };
3075 
3076 /*
3077  * Dynamic Power Allocation
3078  */
3079 static pcieadm_regdef_t pcieadm_regdef_dpa_cap[] = {
3080 	{ 0, 4, "substates", "Substate Max", PRDV_HEX,
3081 	    { .prdv_hex = { 0, 1 } } },
3082 	{ 8, 9, "tlu", "Transition Latency Unit", PRDV_STRVAL,
3083 	    .prd_val = { .prdv_strval = { "1 ms", "10 ms", "100 ms" } } },
3084 	{ 12, 13, "pas", "Power Allocation Scale", PRDV_STRVAL,
3085 	    .prd_val = { .prdv_strval = { "10.0x", "1.0x", "0.1x",
3086 	    "0.01x" } } },
3087 	{ 16, 23, "tlv0", "Transition Latency Value 0", PRDV_HEX },
3088 	{ 24, 31, "tlv0", "Transition Latency Value 1", PRDV_HEX },
3089 	{ -1, -1, NULL }
3090 };
3091 
3092 static pcieadm_regdef_t pcieadm_regdef_dpa_sts[] = {
3093 	{ 0, 4, "substate", "Substate Status", PRDV_HEX },
3094 	{ 8, 8, "ctlen", "Substate Control Enabled", PRDV_STRVAL,
3095 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3096 	{ -1, -1, NULL }
3097 };
3098 
3099 static pcieadm_regdef_t pcieadm_regdef_dpa_ctl[] = {
3100 	{ 0, 4, "substate", "Substate Control", PRDV_HEX },
3101 	{ -1, -1, NULL }
3102 };
3103 
3104 static pcieadm_cfgspace_print_t pcieadm_cap_dpa[] = {
3105 	{ 0x0, 4, "caphdr", "Capability Header",
3106 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
3107 	{ 0x4, 4, "cap", "DPA Capability",
3108 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_dpa_cap },
3109 	{ 0x8, 4, "lat", "DPA Latency Indicator", pcieadm_cfgspace_print_hex },
3110 	{ 0xc, 2, "sts", "DPA Status",
3111 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_dpa_sts },
3112 	{ 0xe, 2, "sts", "DPA Control",
3113 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_dpa_ctl },
3114 	{ 0x10, 1, "paa", "DPA Power Allocation Array",
3115 	    pcieadm_cfgspace_print_dpa_paa },
3116 	{ -1, -1, NULL }
3117 };
3118 
3119 /*
3120  * Power Budgeting
3121  */
3122 static pcieadm_regdef_t pcieadm_regdef_powbudg_data[] = {
3123 	{ 0, 7, "base", "Base Power", PRDV_HEX },
3124 	{ 8, 9, "scale", "Data Scale", PRDV_STRVAL,
3125 	    .prd_val = { .prdv_strval = { "1.0x", "0.1x", "0.01x",
3126 	    "0.001x" } } },
3127 	{ 10, 12, "pmsub", "PM Substate", PRDV_STRVAL,
3128 	    .prd_val = { .prdv_strval = { "Default", "Device Specific",
3129 	    "Device Specific", "Device Specific", "Device Specific",
3130 	    "Device Specific", "Device Specific", "Device Specific" } } },
3131 	{ 13, 14, "pmstate", "PM State", PRDV_STRVAL,
3132 	    .prd_val = { .prdv_strval = { "D0", "D1", "D2", "D3" } } },
3133 	{ 15, 17, "type", "Type", PRDV_STRVAL,
3134 	    .prd_val = { .prdv_strval = { "PME Aux", "Axiliary", "Idle",
3135 	    "Sustained", "Sustained - EPRS", "Maximum - EPRS", NULL,
3136 	    "Maximum" } } },
3137 	{ 18, 20, "rail", "Power Rail", PRDV_STRVAL,
3138 	    .prd_val = { .prdv_strval = { "Power (12V)", "Power (3.3V)",
3139 	    "Power (1.5V or 1.8V)", NULL, NULL, NULL, NULL, "Thermal" } } },
3140 	{ -1, -1, NULL }
3141 };
3142 
3143 static pcieadm_regdef_t pcieadm_regdef_powbudg_cap[] = {
3144 	{ 0, 0, "sa", "System Allocated", PRDV_STRVAL,
3145 	    .prd_val = { .prdv_strval = { "no", "yes" } } },
3146 	{ -1, -1, NULL }
3147 };
3148 
3149 
3150 static pcieadm_cfgspace_print_t pcieadm_cap_powbudg[] = {
3151 	{ 0x0, 4, "caphdr", "Capability Header",
3152 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
3153 	{ 0x4, 1, "sel", "Data Select", pcieadm_cfgspace_print_hex },
3154 	{ 0x8, 4, "data", "Data Regiser", pcieadm_cfgspace_print_regdef,
3155 	    pcieadm_regdef_powbudg_data },
3156 	{ 0xc, 0x1, "cap", "Power Budget Capability",
3157 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_powbudg_cap },
3158 	{ -1, -1, NULL }
3159 };
3160 
3161 /*
3162  * Precision Time Management
3163  */
3164 static pcieadm_regdef_t pcieadm_regdef_ptm_cap[] = {
3165 	{ 0, 0, "req", "PTM Requester", PRDV_STRVAL,
3166 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3167 	{ 1, 1, "resp", "PTM Responder", PRDV_STRVAL,
3168 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3169 	{ 2, 2, "root", "PTM Root", PRDV_STRVAL,
3170 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3171 	{ 3, 3, "eptm", "ePTM", PRDV_STRVAL,
3172 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3173 	{ 8, 15, "gran", "Local Clock Granularity", PRDV_HEX },
3174 	{ -1, -1, NULL }
3175 };
3176 
3177 static pcieadm_regdef_t pcieadm_regdef_ptm_ctl[] = {
3178 	{ 0, 0, "en", "PTM Enable", PRDV_STRVAL,
3179 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3180 	{ 1, 1, "root", "Root Select", PRDV_STRVAL,
3181 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3182 	{ 8, 15, "gran", "Effective Granularity", PRDV_HEX },
3183 	{ -1, -1, NULL }
3184 };
3185 
3186 static pcieadm_cfgspace_print_t pcieadm_cap_info_ptm[] = {
3187 	{ 0x0, 4, "caphdr", "Capability Header",
3188 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
3189 	{ 0x4, 4, "cap", "PTM Capability",
3190 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ptm_cap },
3191 	{ 0x8, 4, "cap", "PTM Control",
3192 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ptm_ctl },
3193 	{ -1, -1, NULL }
3194 };
3195 
3196 /*
3197  * Address Translation Services (ATS)
3198  */
3199 static pcieadm_regdef_t pcieadm_regdef_ats_cap[] = {
3200 	{ 0, 4, "invqd", "Invalidate Queue Depth", PRDV_HEX },
3201 	{ 5, 5, "pgalign", "Page Aligned Request", PRDV_STRVAL,
3202 	    .prd_val = { .prdv_strval = { "not required", "required" } } },
3203 	{ 6, 6, "glbinv", "Global Invalidate", PRDV_STRVAL,
3204 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3205 	{ 7, 7, "relo", "Relaxed Ordering", PRDV_STRVAL,
3206 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3207 	{ -1, -1, NULL }
3208 };
3209 
3210 static pcieadm_regdef_t pcieadm_regdef_ats_ctl[] = {
3211 	{ 0, 4, "stu", "Smallest Translation Unit", PRDV_HEX },
3212 	{ 15, 15, "en", "Enable", PRDV_STRVAL,
3213 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3214 	{ -1, -1, NULL }
3215 };
3216 
3217 static pcieadm_cfgspace_print_t pcieadm_cap_ats[] = {
3218 	{ 0x0, 4, "caphdr", "Capability Header",
3219 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
3220 	{ 0x4, 2, "cap", "ATS Capability",
3221 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ats_cap },
3222 	{ 0x6, 2, "cap", "ATS Control",
3223 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ats_ctl },
3224 	{ -1, -1, NULL }
3225 };
3226 
3227 /*
3228  * Page Request
3229  */
3230 static pcieadm_regdef_t pcieadm_regdef_pgreq_ctl[] = {
3231 	{ 0, 0, "en", "Enable", PRDV_STRVAL,
3232 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3233 	{ 1, 1, "reset", "Reset", PRDV_HEX },
3234 	{ -1, -1, NULL }
3235 };
3236 
3237 static pcieadm_regdef_t pcieadm_regdef_pgreq_sts[] = {
3238 	{ 0, 0, "rf", "Response Failure", PRDV_STRVAL,
3239 	    .prd_val = { .prdv_strval = { "no", "yes" } } },
3240 	{ 1, 1, "uprgi", "Unexpected Page Request Group Index", PRDV_STRVAL,
3241 	    .prd_val = { .prdv_strval = { "no", "yes" } } },
3242 	{ 8, 8, "stopped", "Stopped", PRDV_STRVAL,
3243 	    .prd_val = { .prdv_strval = { "no", "yes" } } },
3244 	{ 15, 15, "prgrpreq", "PRG Response PASID", PRDV_STRVAL,
3245 	    .prd_val = { .prdv_strval = { "not required", "required" } } },
3246 	{ -1, -1, NULL }
3247 };
3248 
3249 static pcieadm_cfgspace_print_t pcieadm_cap_pgreq[] = {
3250 	{ 0x0, 4, "caphdr", "Capability Header",
3251 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
3252 	{ 0x4, 2, "ctl", "Page Request Control",
3253 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pgreq_ctl },
3254 	{ 0x6, 2, "ctl", "Page Request Status",
3255 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pgreq_sts },
3256 	{ 0x8, 4, "cap", "Outstanding Page Request Capacity",
3257 	    pcieadm_cfgspace_print_hex },
3258 	{ 0xc, 4, "alloc", "Outstanding Page Request Allocation",
3259 	    pcieadm_cfgspace_print_hex },
3260 	{ -1, -1, NULL }
3261 };
3262 
3263 /*
3264  * NULL Capability
3265  */
3266 static pcieadm_cfgspace_print_t pcieadm_cap_null[] = {
3267 	{ 0x0, 4, "caphdr", "Capability Header",
3268 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
3269 	{ -1, -1, NULL }
3270 };
3271 
3272 /*
3273  * Downstream Port Containment
3274  */
3275 static pcieadm_regdef_t pcieadm_regdef_dpc_cap[] = {
3276 	{ 0, 4, "inum", "DPC Interrupt Message Number", PRDV_HEX },
3277 	{ 5, 5, "rpext", "Root Port Extensions", PRDV_STRVAL,
3278 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3279 	{ 6, 6, "ptlpeb", "Poisoned TLP Egress Blocking", PRDV_STRVAL,
3280 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3281 	{ 7, 7, "swtrig", "Software Triggering", PRDV_STRVAL,
3282 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3283 	{ 8, 11, "logsz", "RP PIO Log Size", PRDV_HEX },
3284 	{ 12, 12, "errcorr", "DL_Active ERR_COR Signaling", PRDV_STRVAL,
3285 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3286 	{ -1, -1, NULL }
3287 };
3288 
3289 static pcieadm_regdef_t pcieadm_regdef_dpc_ctl[] = {
3290 	{ 0, 1, "trigger", "DPC Trigger", PRDV_STRVAL,
3291 	    .prd_val = { .prdv_strval = { "disabled", "enabled, fatal",
3292 	    "enabled, non-fatal" } } },
3293 	{ 2, 2, "comp", "Completion Control", PRDV_STRVAL,
3294 	    .prd_val = { .prdv_strval = { "Completer Abort",
3295 	    "Unsupported Request" } } },
3296 	{ 3, 3, "intr", "Interrupt",
3297 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3298 	{ 4, 4, "errcor", "ERR_COR",
3299 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3300 	{ 5, 5, "ptlpeb", "Poisoned TLP Egress Blocking", PRDV_STRVAL,
3301 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3302 	{ 6, 6, "swtrig", "Software Trigger", PRDV_HEX },
3303 	{ 7, 7, "corerr", "DL_Active ERR_COR",
3304 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3305 	{ 8, 8, "sigsfw", "SIG_SFW",
3306 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3307 	{ -1, -1, NULL }
3308 };
3309 
3310 static pcieadm_regdef_t pcieadm_regdef_dpc_sts[] = {
3311 	{ 0, 0, "trigger", "Trigger Status", PRDV_STRVAL,
3312 	    .prd_val = { .prdv_strval = { "not triggered", "triggered" } } },
3313 	{ 1, 2, "reason", "Trigger Reason", PRDV_STRVAL,
3314 	    .prd_val = { .prdv_strval = { "unmasked uncorrectable",
3315 	    "ERR_NONFATAL received", "ERR_FATAL received",
3316 	    "see extension" } } },
3317 	{ 3, 3, "istatus", "Interrupt Status", PRDV_HEX },
3318 	{ 4, 4, "rpbusy", "RP Busy", PRDV_STRVAL,
3319 	    .prd_val = { .prdv_strval = { "no", "yes" } } },
3320 	{ 5, 6, "extreason", "Trigger Reason Extension", PRDV_STRVAL,
3321 	    .prd_val = { .prdv_strval = { "RP PIO", "Software Trigger" } } },
3322 	{ 8, 12, "feptr", "RP PIO, First Error Pointer", PRDV_HEX },
3323 	{ 13, 13, "sigsfw", "SIG_SFW Status", PRDV_HEX },
3324 	{ -1, -1, NULL }
3325 };
3326 
3327 static pcieadm_regdef_t pcieadm_regdef_dpc_rppio_bits[] = {
3328 	{ 0, 0, "cfgur", "Configuration Request UR Completion", PRDV_HEX },
3329 	{ 1, 1, "cfgca", "Configuration Request CA Completion", PRDV_HEX },
3330 	{ 2, 2, "cfgcto", "Configuration Request Completion Timeout",
3331 	    PRDV_HEX },
3332 	{ 8, 8, "iour", "I/O UR Completion", PRDV_HEX },
3333 	{ 9, 9, "ioca", "I/O CA Completion", PRDV_HEX },
3334 	{ 10, 10, "iocto", "I/O Completion Timeout", PRDV_HEX },
3335 	{ 8, 8, "memur", "Memory UR Completion", PRDV_HEX },
3336 	{ 9, 9, "memca", "Memory CA Completion", PRDV_HEX },
3337 	{ 10, 10, "memcto", "Memory Completion Timeout", PRDV_HEX },
3338 	{ -1, -1, NULL }
3339 };
3340 
3341 static void
3342 pcieadm_cfgspace_print_dpc_rppio(pcieadm_cfgspace_walk_t *walkp,
3343     pcieadm_cfgspace_print_t *print, void *arg)
3344 {
3345 	uint32_t cap = walkp->pcw_data->pcb_u32[(walkp->pcw_capoff + 4) / 4];
3346 
3347 	if (BITX(cap, 5, 5) == 0) {
3348 		return;
3349 	}
3350 
3351 	pcieadm_cfgspace_print_regdef(walkp, print, arg);
3352 }
3353 
3354 static void
3355 pcieadm_cfgspace_print_dpc_piohead(pcieadm_cfgspace_walk_t *walkp,
3356     pcieadm_cfgspace_print_t *print, void *arg)
3357 {
3358 	uint32_t cap = walkp->pcw_data->pcb_u32[(walkp->pcw_capoff + 4) / 4];
3359 	uint32_t nwords = BITX(cap, 11, 8);
3360 
3361 	if (BITX(cap, 5, 5) == 0 || nwords < 4) {
3362 		return;
3363 	}
3364 
3365 	pcieadm_cfgspace_print_hex(walkp, print, NULL);
3366 }
3367 
3368 static void
3369 pcieadm_cfgspace_print_dpc_impspec(pcieadm_cfgspace_walk_t *walkp,
3370     pcieadm_cfgspace_print_t *print, void *arg)
3371 {
3372 	uint32_t cap = walkp->pcw_data->pcb_u32[(walkp->pcw_capoff + 4) / 4];
3373 	uint32_t nwords = BITX(cap, 11, 8);
3374 
3375 	if (BITX(cap, 5, 5) == 0 || nwords < 5) {
3376 		return;
3377 	}
3378 
3379 	pcieadm_cfgspace_print_hex(walkp, print, NULL);
3380 }
3381 
3382 static void
3383 pcieadm_cfgspace_print_dpc_tlplog(pcieadm_cfgspace_walk_t *walkp,
3384     pcieadm_cfgspace_print_t *print, void *arg)
3385 {
3386 	uint32_t cap = walkp->pcw_data->pcb_u32[(walkp->pcw_capoff + 4) / 4];
3387 	int32_t nwords = BITX(cap, 11, 8);
3388 
3389 	if (nwords == 0 || BITX(cap, 5, 5) == 0) {
3390 		return;
3391 	}
3392 
3393 	if (nwords <= 9) {
3394 		nwords -= 5;
3395 	} else {
3396 		nwords -= 4;
3397 	}
3398 
3399 	for (int32_t i = 0; i < nwords; i++) {
3400 		char tlpshort[32], tlphuman[128];
3401 		pcieadm_cfgspace_print_t p;
3402 
3403 		(void) snprintf(tlpshort, sizeof (tlpshort), "%s%u",
3404 		    print->pcp_short, i);
3405 		(void) snprintf(tlphuman, sizeof (tlphuman), "%s %u",
3406 		    print->pcp_human, i);
3407 		p.pcp_off = print->pcp_off + i * 4;
3408 		p.pcp_len = 4;
3409 		p.pcp_short = tlpshort;
3410 		p.pcp_human = tlphuman;
3411 		p.pcp_print = pcieadm_cfgspace_print_hex;
3412 		p.pcp_arg = NULL;
3413 
3414 		p.pcp_print(walkp, &p, p.pcp_arg);
3415 	}
3416 }
3417 
3418 static pcieadm_cfgspace_print_t pcieadm_cap_dpc[] = {
3419 	{ 0x0, 4, "caphdr", "Capability Header",
3420 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
3421 	{ 0x4, 2, "cap", "DPC Capability",
3422 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_dpc_cap },
3423 	{ 0x6, 2, "ctl", "DPC Control",
3424 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_dpc_ctl },
3425 	{ 0x8, 2, "sts", "DPC Status",
3426 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_dpc_sts },
3427 	{ 0xa, 2, "srcid", "DPC Error Source ID",
3428 	    pcieadm_cfgspace_print_hex },
3429 	{ 0x10, 4, "rppiosts", "RP PIO Status",
3430 	    pcieadm_cfgspace_print_dpc_rppio, pcieadm_regdef_dpc_rppio_bits },
3431 	{ 0x14, 4, "rppiomask", "RP PIO Mask ID",
3432 	    pcieadm_cfgspace_print_dpc_rppio, pcieadm_regdef_dpc_rppio_bits },
3433 	{ 0x14, 4, "rppiosev", "RP PIO Severity",
3434 	    pcieadm_cfgspace_print_dpc_rppio, pcieadm_regdef_dpc_rppio_bits },
3435 	{ 0x18, 4, "rppiose", "RP PIO SysError",
3436 	    pcieadm_cfgspace_print_dpc_rppio, pcieadm_regdef_dpc_rppio_bits },
3437 	{ 0x1c, 4, "rppioex", "RP PIO Exception",
3438 	    pcieadm_cfgspace_print_dpc_rppio, pcieadm_regdef_dpc_rppio_bits },
3439 	{ 0x20, 4, "rppiohl0", "RP PIO Header Log 0",
3440 	    pcieadm_cfgspace_print_dpc_piohead },
3441 	{ 0x24, 4, "rppiohl1", "RP PIO Header Log 1",
3442 	    pcieadm_cfgspace_print_dpc_piohead },
3443 	{ 0x28, 4, "rppiohl2", "RP PIO Header Log 2",
3444 	    pcieadm_cfgspace_print_dpc_piohead },
3445 	{ 0x2c, 4, "rppiohl3", "RP PIO Header Log 3",
3446 	    pcieadm_cfgspace_print_dpc_piohead },
3447 	{ 0x30, 4, "impspec", "RP PIO ImpSpec Log",
3448 	    pcieadm_cfgspace_print_dpc_impspec },
3449 	{ 0x34, 16, "tlplog", "RP PIO TLP Prefix Log",
3450 	    pcieadm_cfgspace_print_dpc_tlplog },
3451 	{ -1, -1, NULL }
3452 };
3453 
3454 /*
3455  * Virtual Channel Capability
3456  */
3457 static pcieadm_regdef_t pcieadm_regdef_vc_cap1[] = {
3458 	{ 0, 2, "count", "Extended VC Count", PRDV_HEX },
3459 	{ 4, 6, "lpcount", "Low Priority Extended VC Count", PRDV_HEX },
3460 	{ 8, 9, "refclk", "Reference Clock", PRDV_STRVAL,
3461 	    .prd_val = { .prdv_strval = { "100ns" } } },
3462 	{ 10, 11, "patsz", "Port Arbitration Table Size", PRDV_STRVAL,
3463 	    .prd_val = { .prdv_strval = { "1 bit", "2 bits", "4 bits",
3464 	    "8 bits" } } },
3465 	{ -1, -1, NULL }
3466 };
3467 
3468 static pcieadm_regdef_t pcieadm_regdef_vc_cap2[] = {
3469 	{ 0, 7, "arbcap", "VC Arbitration Capability", PRDV_BITFIELD,
3470 	    .prd_val = { .prdv_strval = { "hardware fixed",
3471 	    "32 phase weighted round robin", "64 phase weighted round robin",
3472 	    "128 phase weighted round robin" } } },
3473 	{ 24, 31, "offset", "VC Arbitration Table Offset", PRDV_HEX },
3474 	{ -1, -1, NULL }
3475 };
3476 
3477 static pcieadm_regdef_t pcieadm_regdef_vc_ctl[] = {
3478 	{ 0, 0, "loadtbl", "Load VC Arbitration Table", PRDV_HEX },
3479 	{ 1, 3, "arbtype", "VC Arbitration Select", PRDV_STRVAL,
3480 	    .prd_val = { .prdv_strval = { "hardware fixed",
3481 	    "32 phase weighted round robin", "64 phase weighted round robin",
3482 	    "128 phase weighted round robin" } } },
3483 	{ -1, -1, NULL }
3484 };
3485 
3486 static pcieadm_regdef_t pcieadm_regdef_vc_sts[] = {
3487 	{ 0, 0, "table", "VC Arbitration Table Status", PRDV_HEX },
3488 	{ -1, -1, NULL }
3489 };
3490 
3491 static pcieadm_regdef_t pcieadm_regdef_vc_rsrccap[] = {
3492 	{ 0, 7, "arbcap", "Port Arbitration Capability", PRDV_BITFIELD,
3493 	    .prd_val = { .prdv_strval = { "hardware fixed",
3494 	    "32 phase weighted round robin", "64 phase weighted round robin",
3495 	    "128 phase weighted round robin",
3496 	    "128 phase time-based weighted round robin",
3497 	    "256 phase weighted round robin" } } },
3498 	{ 14, 14, "aps", "Advanced Packet Switching", PRDV_STRVAL,
3499 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3500 	{ 15, 15, "rstx", "Reject Snoop Transactions", PRDV_STRVAL,
3501 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3502 	{ 16, 22, "nslots", "Maximum Time Slots", PRDV_HEX,
3503 	    { .prdv_hex = { 0, 1 } } },
3504 	{ 24, 31, "offset", "VC Arbitration Table Offset", PRDV_HEX },
3505 	{ -1, -1, NULL }
3506 };
3507 
3508 static pcieadm_regdef_t pcieadm_regdef_vc_rsrcctl[] = {
3509 	{ 0, 7, "tcmap", "TC/VC Map", PRDV_HEX },
3510 	{ 16, 16, "loadtbl", "Load VC Arbitration Table", PRDV_HEX },
3511 	{ 17, 19, "arbtype", "Port Arbitration Select", PRDV_STRVAL,
3512 	    .prd_val = { .prdv_strval = { "hardware fixed",
3513 	    "32 phase weighted round robin", "64 phase weighted round robin",
3514 	    "128 phase weighted round robin",
3515 	    "128 phase time-based weighted round robin",
3516 	    "256 phase weighted round robin" } } },
3517 	{ 24, 26, "vcid", "VC ID", PRDV_HEX },
3518 	{ 31, 31, "en", "VC Enable",
3519 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3520 	{ -1, -1, NULL }
3521 };
3522 
3523 static pcieadm_regdef_t pcieadm_regdef_vc_rsrcsts[] = {
3524 	{ 0, 0, "table", "Port Arbitration Table Status", PRDV_HEX },
3525 	{ -1, -1, NULL }
3526 };
3527 
3528 static void
3529 pcieadm_cfgspace_print_vc_rsrc(pcieadm_cfgspace_walk_t *walkp,
3530     pcieadm_cfgspace_print_t *print, void *arg)
3531 {
3532 	uint32_t cap = walkp->pcw_data->pcb_u32[(walkp->pcw_capoff + 4) / 4];
3533 	uint32_t nents = BITX(cap, 2, 0) + 1;
3534 
3535 	for (uint32_t i = 0; i < nents; i++) {
3536 		char vcshort[32], vchuman[128];
3537 		pcieadm_cfgspace_print_t p;
3538 
3539 		(void) snprintf(vcshort, sizeof (vcshort), "rsrccap%u", i);
3540 		(void) snprintf(vchuman, sizeof (vchuman), "VC Resource %u "
3541 		    "Capability", i);
3542 		p.pcp_off = print->pcp_off + i * 0x10;
3543 		p.pcp_len = 4;
3544 		p.pcp_short = vcshort;
3545 		p.pcp_human = vchuman;
3546 		p.pcp_print = pcieadm_cfgspace_print_regdef;
3547 		p.pcp_arg = pcieadm_regdef_vc_rsrccap;
3548 
3549 		p.pcp_print(walkp, &p, p.pcp_arg);
3550 
3551 		(void) snprintf(vcshort, sizeof (vcshort), "rsrcctl%u", i);
3552 		(void) snprintf(vchuman, sizeof (vchuman), "VC Resource %u "
3553 		    "Control", i);
3554 		p.pcp_off = print->pcp_off + i * 0x10 + 4;
3555 		p.pcp_len = 4;
3556 		p.pcp_short = vcshort;
3557 		p.pcp_human = vchuman;
3558 		p.pcp_print = pcieadm_cfgspace_print_regdef;
3559 		p.pcp_arg = pcieadm_regdef_vc_rsrcctl;
3560 
3561 		p.pcp_print(walkp, &p, p.pcp_arg);
3562 
3563 		(void) snprintf(vcshort, sizeof (vcshort), "rsrcsts%u", i);
3564 		(void) snprintf(vchuman, sizeof (vchuman), "VC Resource %u "
3565 		    "Status", i);
3566 		p.pcp_off = print->pcp_off + i * 0x10 + 0xa;
3567 		p.pcp_len = 2;
3568 		p.pcp_short = vcshort;
3569 		p.pcp_human = vchuman;
3570 		p.pcp_print = pcieadm_cfgspace_print_regdef;
3571 		p.pcp_arg = pcieadm_regdef_vc_rsrcsts;
3572 
3573 		p.pcp_print(walkp, &p, p.pcp_arg);
3574 	}
3575 }
3576 
3577 static pcieadm_cfgspace_print_t pcieadm_cap_vc[] = {
3578 	{ 0x0, 4, "caphdr", "Capability Header",
3579 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_pcie_caphdr },
3580 	{ 0x4, 4, "cap1", "Port VC Capability 1",
3581 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_vc_cap1 },
3582 	{ 0x8, 4, "cap2", "Port VC Capability 2",
3583 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_vc_cap2 },
3584 	{ 0xc, 2, "ctl", "Port VC Control",
3585 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_vc_ctl },
3586 	{ 0xe, 2, "sts", "Port VC Status",
3587 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_vc_sts },
3588 	{ 0x10, 12, "vcrec", "VC Resource", pcieadm_cfgspace_print_vc_rsrc },
3589 	{ -1, -1, NULL }
3590 };
3591 
3592 /*
3593  * HyperTransport
3594  */
3595 static pcieadm_cfgspace_print_t pcieadm_cap_ht_intr[] = {
3596 	{ 0x2, 1, "index", "Interrupt Discovery Index",
3597 	    pcieadm_cfgspace_print_hex },
3598 	{ 0x4, 4, "dataport", "Interrupt Dataport",
3599 	    pcieadm_cfgspace_print_hex },
3600 	{ -1, -1, NULL }
3601 };
3602 
3603 static pcieadm_regdef_t pcieadm_regdef_ht_command_pri[] = {
3604 	{ 0, 4, "unitid", "Base Unit ID", PRDV_HEX },
3605 	{ 5, 9, "count", "Unit Count", PRDV_HEX },
3606 	{ 10, 10, "host", "Master Host", PRDV_HEX },
3607 	{ 11, 11, "dir", "Default Direction", PRDV_STRVAL,
3608 	    .prd_val = { .prdv_strval = { "towards host",
3609 	    "away from host" } } },
3610 	{ 12, 12, "drop", "Drop on Uninitialized Link", PRDV_HEX },
3611 	{ 13, 15, "cap", "Capability ID", PRDV_HEX },
3612 	{ -1, -1, NULL }
3613 };
3614 
3615 static pcieadm_regdef_t pcieadm_regdef_ht_command_sec[] = {
3616 	{ 0, 0, "reset", "Warm Reset", PRDV_HEX },
3617 	{ 1, 1, "de", "Double Ended", PRDV_HEX },
3618 	{ 2, 6, "devno", "Device Number", PRDV_HEX },
3619 	{ 7, 7, "chain", "Chain Side", PRDV_STRVAL,
3620 	    .prd_val = { .prdv_strval = { "from host", "from chain" } } },
3621 	{ 8, 8, "hide", "Host Hide", PRDV_STRVAL,
3622 	    .prd_val = { .prdv_strval = { "visible", "hidden" } } },
3623 	{ 10, 10, "target", "Act as Target", PRDV_HEX },
3624 	{ 11, 11, "eocerr", "Host Inbound End of Chain Error", PRDV_HEX },
3625 	{ 12, 12, "drop", "Drop on Uninitialized Link", PRDV_HEX },
3626 	{ 13, 15, "cap", "Capability ID", PRDV_HEX },
3627 	{ -1, -1, NULL }
3628 };
3629 
3630 static pcieadm_regdef_t pcieadm_regdef_ht_linkctl[] = {
3631 	{ 0, 0, "srcid", "Source ID", PRDV_STRVAL,
3632 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3633 	{ 1, 1, "cfl", "CRC Flood", PRDV_STRVAL,
3634 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3635 	{ 2, 2, "cst", "CRC Start Test", PRDV_HEX },
3636 	{ 3, 3, "cfer", "CRC Force Error", PRDV_STRVAL,
3637 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3638 	{ 4, 4, "linkfail", "Link Failure", PRDV_HEX },
3639 	{ 5, 5, "initcmp", "Initialization Complete", PRDV_HEX },
3640 	{ 6, 6, "eoc", "End of Chain", PRDV_HEX },
3641 	{ 7, 7, "txoff", "Transmitter Off", PRDV_STRVAL,
3642 	    .prd_val = { .prdv_strval = { "transmitter on",
3643 	    "transmitter off" } } },
3644 	{ 8, 11, "crcerr", "CRC Error", PRDV_HEX },
3645 	{ 12, 12, "isoc", "Isochronous Flow Control", PRDV_STRVAL,
3646 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3647 	{ 13, 13, "ls", "LDTSTOP# Tristate", PRDV_STRVAL,
3648 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3649 	{ 14, 14, "extctl", "Extended CTL Time", PRDV_HEX },
3650 	{ 15, 15, "64b", "64-bit Addressing", PRDV_STRVAL,
3651 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3652 	{ -1, -1, NULL }
3653 };
3654 
3655 static pcieadm_regdef_t pcieadm_regdef_ht_linkcfg[] = {
3656 	{ 0, 2, "maxin", "Maximum Link Width In", PRDV_STRVAL,
3657 	    .prd_val = { .prdv_strval = { "8 bits", "16 bits", NULL, "32 bits",
3658 	    "2 bits", "4 bits", NULL, "not connected" } } },
3659 	{ 3, 3, "dwfcinsup", "Doubleword Flow Control In", PRDV_STRVAL,
3660 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3661 	{ 4, 6, "maxout", "Maximum Link Width Out", PRDV_STRVAL,
3662 	    .prd_val = { .prdv_strval = { "8 bits", "16 bits", NULL, "32 bits",
3663 	    "2 bits", "4 bits", NULL, "not connected" } } },
3664 	{ 7, 7, "dwfcoutsup", "Doubleword Flow Control Out", PRDV_STRVAL,
3665 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3666 	{ 8, 10, "linkin", "Link Width In", PRDV_STRVAL,
3667 	    .prd_val = { .prdv_strval = { "8 bits", "16 bits", NULL, "32 bits",
3668 	    "2 bits", "4 bits", NULL, "not connected" } } },
3669 	{ 11, 11, "dwfcin", "Doubleword Flow Control In", PRDV_STRVAL,
3670 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3671 	{ 12, 14, "linkout", "Link Width Out", PRDV_STRVAL,
3672 	    .prd_val = { .prdv_strval = { "8 bits", "16 bits", NULL, "32 bits",
3673 	    "2 bits", "4 bits", NULL, "not connected" } } },
3674 	{ 15, 15, "dwfcout", "Doubleword Flow Control Out", PRDV_STRVAL,
3675 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3676 	{ -1, -1, NULL }
3677 };
3678 
3679 static pcieadm_regdef_t pcieadm_regdef_ht_rev[] = {
3680 	{ 0, 4, "minor", "Minor Revision", PRDV_HEX },
3681 	{ 5, 7, "major", "Major Revision", PRDV_HEX },
3682 	{ -1, -1, NULL }
3683 };
3684 
3685 static pcieadm_regdef_t pcieadm_regdef_ht_linkfreq[] = {
3686 	{ 0, 4, "freq", "Link Frequency", PRDV_STRVAL,
3687 	    .prd_val = { .prdv_strval = { "200 MHz", "300 MHz", "400 MHz",
3688 	    "500 MHz", "600 MHz", "800 MHz", "1000 MHz", "1200 MHz", "1400 MHz",
3689 	    "1600 MHz", "1800 MHz", "2000 MHz", "2200 MHz", "2400 MHz",
3690 	    "2600 MHz", "Vendor Specfic" } } },
3691 	{ -1, -1, NULL }
3692 };
3693 
3694 static pcieadm_regdef_t pcieadm_regdef_ht_linkerr[] = {
3695 	{ 4, 4, "prot", "Protocol Error", PRDV_HEX },
3696 	{ 5, 5, "over", "Overflow Error", PRDV_HEX },
3697 	{ 6, 6, "eoc", "End of Chain Error", PRDV_HEX },
3698 	{ 7, 7, "ctl", "CTL Timeout", PRDV_HEX },
3699 	{ -1, -1, NULL }
3700 };
3701 
3702 static pcieadm_regdef_t pcieadm_regdef_ht_linkcap[] = {
3703 	{ 0, 15, "freq", "Link Frequency", PRDV_BITFIELD,
3704 	    .prd_val = { .prdv_strval = { "200 MHz", "300 MHz", "400 MHz",
3705 	    "500 MHz", "600 MHz", "800 MHz", "1000 MHz", "1200 MHz", "1400 MHz",
3706 	    "1600 MHz", "1800 MHz", "2000 MHz", "2200 MHz", "2400 MHz",
3707 	    "2600 MHz", "Vendor Specfic" } } },
3708 	{ -1, -1, NULL }
3709 };
3710 
3711 static pcieadm_regdef_t pcieadm_regdef_ht_feature[] = {
3712 	{ 0, 0, "isofc", "Isochronous Flow Control", PRDV_STRVAL,
3713 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3714 	{ 1, 1, "ls", "LDTSTOP#", PRDV_STRVAL,
3715 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3716 	{ 2, 2, "crct", "CRC Test Mode", PRDV_STRVAL,
3717 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3718 	{ 3, 3, "ectl", "Extended CTL Time", PRDV_STRVAL,
3719 	    .prd_val = { .prdv_strval = { "not required", "required" } } },
3720 	{ 4, 4, "64b", "64-bit Addressing", PRDV_STRVAL,
3721 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3722 	{ 5, 5, "unitid", "UnitID Reorder", PRDV_STRVAL,
3723 	    .prd_val = { .prdv_strval = { "enabled", "disabled" } } },
3724 	{ 6, 6, "srcid", "Source Identification Extension", PRDV_STRVAL,
3725 	    .prd_val = { .prdv_strval = { "not required", "required" } } },
3726 	{ 8, 8, "extreg", "Extended Register Set", PRDV_STRVAL,
3727 	    .prd_val = { .prdv_strval = { "unsupported", "supported" } } },
3728 	{ 9, 9, "uscfg", "Upstream Configuration", PRDV_STRVAL,
3729 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3730 	{ -1, -1, NULL }
3731 };
3732 
3733 static pcieadm_regdef_t pcieadm_regdef_ht_error[] = {
3734 	{ 0, 0, "protfl", "Protocol Error Flood", PRDV_STRVAL,
3735 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3736 	{ 1, 1, "ovfl", "Overflow Error Flood", PRDV_STRVAL,
3737 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3738 	{ 2, 2, "protf", "Protocol Error Fatal", PRDV_STRVAL,
3739 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3740 	{ 3, 3, "ovf", "Overflow Error Fatal", PRDV_STRVAL,
3741 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3742 	{ 4, 4, "eocf", "End of Chain Fatal Error", PRDV_STRVAL,
3743 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3744 	{ 5, 5, "respf", "Response Error Fatal", PRDV_STRVAL,
3745 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3746 	{ 6, 6, "crcf", "CRC Error Fatal", PRDV_STRVAL,
3747 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3748 	{ 7, 7, "sysf", "System Error Fatal", PRDV_STRVAL,
3749 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3750 	{ 8, 8, "chain", "Chain Fail", PRDV_HEX },
3751 	{ 9, 9, "resp", "Response Error", PRDV_HEX },
3752 	{ 10, 10, "protnf", "Protocol Error Non-Fatal", PRDV_STRVAL,
3753 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3754 	{ 11, 11, "ovfnf", "Overflow Error Non-Fatal", PRDV_STRVAL,
3755 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3756 	{ 12, 12, "eocnf", "End of Chain Error Non-Fatal", PRDV_STRVAL,
3757 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3758 	{ 13, 13, "respnf", "Response Error Non-Fatal", PRDV_STRVAL,
3759 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3760 	{ 14, 14, "crcnf", "CRC Error Non-Fatal", PRDV_STRVAL,
3761 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3762 	{ 15, 15, "sysnf", "System Error Non-Fatal", PRDV_STRVAL,
3763 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3764 	{ -1, -1, NULL }
3765 };
3766 
3767 static pcieadm_regdef_t pcieadm_regdef_ht_memory[] = {
3768 	{ 0, 8, "base", "Memory Base Upper 8 Bits", PRDV_HEX,
3769 	    .prd_val = { .prdv_hex = { 32 } } },
3770 	{ 9, 15, "limit", "Memory Limit Upper 8 Bits", PRDV_HEX,
3771 	    .prd_val = { .prdv_hex = { 32 } } },
3772 	{ -1, -1, NULL }
3773 };
3774 
3775 static pcieadm_cfgspace_print_t pcieadm_cap_ht_pri[] = {
3776 	{ 0x2, 2, "command", "Command",
3777 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_command_pri },
3778 	{ 0x4, 2, "linkctl0", "Link Control 0",
3779 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkctl },
3780 	{ 0x6, 2, "linkcfg0", "Link Configuration 0",
3781 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkcfg },
3782 	{ 0x8, 2, "linkctl1", "Link Control 1",
3783 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkctl },
3784 	{ 0xa, 2, "linkcfg1", "Link Configuration 1",
3785 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkcfg },
3786 	{ 0xc, 1, "rev", "Revision",
3787 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_rev },
3788 	{ 0xd, 1, "linkfreq0", "Link Frequency 0",
3789 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkfreq },
3790 	{ 0xd, 1, "linkerr0", "Link Error 0",
3791 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkerr },
3792 	{ 0xe, 2, "linkfcap0", "Link Frequency Cap 0",
3793 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkcap },
3794 	{ 0x10, 1, "feature", "Feature Capability",
3795 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_feature },
3796 	{ 0x11, 1, "linkfreq1", "Link Frequency 1",
3797 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkfreq },
3798 	{ 0x11, 1, "linkerr1", "Link Error 1",
3799 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkerr },
3800 	{ 0x12, 2, "linkfcap1", "Link Frequency Cap 1",
3801 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkcap },
3802 	{ 0x14, 2, "scratch", "Enumeration Scratchpad",
3803 	    pcieadm_cfgspace_print_hex },
3804 	{ 0x16, 2, "error", "Error Handling",
3805 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_error },
3806 	{ 0x18, 2, "memory", "Memory",
3807 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_memory },
3808 	{ 0x1a, 1, "bus", "Bus Number", pcieadm_cfgspace_print_hex },
3809 	{ -1, -1, NULL }
3810 };
3811 
3812 static pcieadm_cfgspace_print_t pcieadm_cap_ht_sec[] = {
3813 	{ 0x2, 2, "command", "Command",
3814 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_command_sec },
3815 	{ 0x4, 2, "linkctl", "Link Control",
3816 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkctl },
3817 	{ 0x6, 2, "linkcfg", "Link Configuration",
3818 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkcfg },
3819 	{ 0x8, 1, "rev", "Revision",
3820 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_rev },
3821 	{ 0x9, 1, "linkfreq", "Link Frequency 0",
3822 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkfreq },
3823 	{ 0x9, 1, "linkerr", "Link Error 0",
3824 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkerr },
3825 	{ 0xa, 2, "linkfcap", "Link Frequency Cap 0",
3826 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_linkcap },
3827 	{ 0xc, 2, "feature", "Feature Capability",
3828 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_feature },
3829 	{ 0x10, 2, "scratch", "Enumeration Scratchpad",
3830 	    pcieadm_cfgspace_print_hex },
3831 	{ 0x12, 2, "error", "Error Handling",
3832 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_error },
3833 	{ 0x14, 2, "memory", "Memory",
3834 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_memory },
3835 	{ -1, -1, NULL }
3836 };
3837 
3838 static pcieadm_regdef_t pcieadm_regdef_ht_msi[] = {
3839 	{ 0, 0, "en", "Enable", PRDV_STRVAL,
3840 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3841 	{ 1, 1, "fixed", "Fixed", PRDV_STRVAL,
3842 	    .prd_val = { .prdv_strval = { "disabled", "enabled" } } },
3843 	{ -1, -1, NULL }
3844 };
3845 
3846 static void
3847 pcieadm_cfgspace_print_ht_msi_addr(pcieadm_cfgspace_walk_t *walkp,
3848     pcieadm_cfgspace_print_t *print, void *arg)
3849 {
3850 	uint8_t fixed = walkp->pcw_data->pcb_u8[walkp->pcw_capoff + 2];
3851 
3852 	if (BITX(fixed, 1, 1) != 0)
3853 		return;
3854 
3855 	pcieadm_cfgspace_print_hex(walkp, print, arg);
3856 }
3857 
3858 static pcieadm_cfgspace_print_t pcieadm_cap_ht_msi[] = {
3859 	{ 0x2, 2, "command", "Command",
3860 	    pcieadm_cfgspace_print_regdef, pcieadm_regdef_ht_msi },
3861 	{ 0x4, 8, "address", "MSI Address",
3862 	    pcieadm_cfgspace_print_ht_msi_addr },
3863 	{ -1, -1, NULL }
3864 };
3865 
3866 /*
3867  * Capability related tables
3868  */
3869 typedef struct pcieadm_cap_vers {
3870 	uint32_t ppr_vers;
3871 	uint32_t ppr_len;
3872 	pcieadm_cfgspace_print_t *ppr_print;
3873 } pcieadm_cap_vers_t;
3874 
3875 typedef struct pcieadm_subcap {
3876 	const char *psub_short;
3877 	const char *psub_human;
3878 } pcieadm_subcap_t;
3879 
3880 typedef struct pcieadm_pci_cap pcieadm_pci_cap_t;
3881 
3882 typedef void (*pcieadm_cap_info_f)(pcieadm_cfgspace_walk_t *,
3883     const pcieadm_pci_cap_t *, uint32_t, const pcieadm_cap_vers_t **,
3884     uint32_t *, const pcieadm_subcap_t **);
3885 
3886 struct pcieadm_pci_cap {
3887 	uint32_t ppc_id;
3888 	const char *ppc_short;
3889 	const char *ppc_human;
3890 	pcieadm_cap_info_f ppc_info;
3891 	pcieadm_cap_vers_t ppc_vers[4];
3892 };
3893 
3894 /*
3895  * Capability version determinations.
3896  */
3897 
3898 static void
3899 pcieadm_cap_info_fixed(pcieadm_cfgspace_walk_t *walkp,
3900     const pcieadm_pci_cap_t *cap, uint32_t off,
3901     const pcieadm_cap_vers_t **versp, uint32_t *lenp,
3902     const pcieadm_subcap_t **subcap)
3903 {
3904 	*versp = &cap->ppc_vers[0];
3905 	*lenp = cap->ppc_vers[0].ppr_len;
3906 	*subcap = NULL;
3907 }
3908 
3909 static void
3910 pcieadm_cap_info_vers(pcieadm_cfgspace_walk_t *walkp,
3911     const pcieadm_pci_cap_t *cap, uint32_t off,
3912     const pcieadm_cap_vers_t **versp, uint32_t *lenp,
3913     const pcieadm_subcap_t **subcap)
3914 {
3915 	uint8_t vers;
3916 
3917 	*subcap = NULL;
3918 	vers = walkp->pcw_data->pcb_u8[off + 2] & 0xf;
3919 	for (uint32_t i = 0; i < ARRAY_SIZE(cap->ppc_vers); i++) {
3920 		if (vers == cap->ppc_vers[i].ppr_vers &&
3921 		    cap->ppc_vers[i].ppr_vers != 0) {
3922 			*versp = &cap->ppc_vers[i];
3923 			*lenp = cap->ppc_vers[i].ppr_len;
3924 			return;
3925 		}
3926 	}
3927 
3928 	*versp = NULL;
3929 	*lenp = 0;
3930 }
3931 
3932 /*
3933  * The PCI Power Management capability uses a 3-bit version ID as opposed to the
3934  * standard 4-bit version.
3935  */
3936 static void
3937 pcieadm_cap_info_pcipm(pcieadm_cfgspace_walk_t *walkp,
3938     const pcieadm_pci_cap_t *cap, uint32_t off,
3939     const pcieadm_cap_vers_t **versp, uint32_t *lenp,
3940     const pcieadm_subcap_t **subcap)
3941 {
3942 	uint8_t vers;
3943 
3944 	*subcap = NULL;
3945 	vers = walkp->pcw_data->pcb_u8[off + 2] & 0x7;
3946 	for (uint32_t i = 0; i < ARRAY_SIZE(cap->ppc_vers); i++) {
3947 		if (vers == cap->ppc_vers[i].ppr_vers) {
3948 			*versp = &cap->ppc_vers[i];
3949 			*lenp = cap->ppc_vers[i].ppr_len;
3950 			return;
3951 		}
3952 	}
3953 
3954 	*versp = NULL;
3955 	*lenp = 0;
3956 }
3957 
3958 /*
3959  * The PCIe capability underwent a few changes. In version 1 of the capability,
3960  * devices were not required to implement the entire capability. In particular,
3961  * endpoints did not need to implement anything more than the link status
3962  * register. In the v2 capability, this was changed such that all devices had to
3963  * implement the entire capbility, but otherwise hardcode registers to zero. As
3964  * such we get to play guess the length based on the device type.
3965  */
3966 static pcieadm_cap_vers_t pcieadm_cap_vers_pcie_v1_dev = {
3967 	1, 0x0c, pcieadm_cap_pcie_v1_dev
3968 };
3969 
3970 static pcieadm_cap_vers_t pcieadm_cap_vers_pcie_v1_link = {
3971 	1, 0x14, pcieadm_cap_pcie_v1_link
3972 };
3973 
3974 static pcieadm_cap_vers_t pcieadm_cap_vers_pcie_v1_slot = {
3975 	1, 0x1c, pcieadm_cap_pcie_v1_slot
3976 };
3977 
3978 static pcieadm_cap_vers_t pcieadm_cap_vers_pcie_v1_all = {
3979 	1, 0x24, pcieadm_cap_pcie_v1_all
3980 };
3981 
3982 static pcieadm_cap_vers_t pcieadm_cap_vers_pcie_v2 = {
3983 	2, 0x4c, pcieadm_cap_pcie_v2
3984 };
3985 
3986 static void
3987 pcieadm_cap_info_pcie(pcieadm_cfgspace_walk_t *walkp,
3988     const pcieadm_pci_cap_t *cap, uint32_t off,
3989     const pcieadm_cap_vers_t **versp, uint32_t *lenp,
3990     const pcieadm_subcap_t **subcap)
3991 {
3992 	uint8_t vers = walkp->pcw_data->pcb_u8[off + 2] & 0xf;
3993 	uint16_t pcie = walkp->pcw_data->pcb_u8[off + 2] |
3994 	    (walkp->pcw_data->pcb_u8[off + 3] << 8);
3995 
3996 	/*
3997 	 * Version 2 is simple. There's only one thing to do, so we do it. For
3998 	 * version 1 we need to look at the device type.
3999 	 */
4000 	*subcap = NULL;
4001 	if (vers == 2) {
4002 		*versp = &pcieadm_cap_vers_pcie_v2;
4003 		*lenp = (*versp)->ppr_len;
4004 		return;
4005 	} else if (vers != 1) {
4006 		*versp = NULL;
4007 		*lenp = 0;
4008 		return;
4009 	}
4010 
4011 	switch (pcie & PCIE_PCIECAP_DEV_TYPE_MASK) {
4012 	case PCIE_PCIECAP_DEV_TYPE_PCIE_DEV:
4013 	case PCIE_PCIECAP_DEV_TYPE_PCI_DEV:
4014 		*versp = &pcieadm_cap_vers_pcie_v1_link;
4015 		break;
4016 	case PCIE_PCIECAP_DEV_TYPE_RC_IEP:
4017 		*versp = &pcieadm_cap_vers_pcie_v1_dev;
4018 		break;
4019 	case PCIE_PCIECAP_DEV_TYPE_UP:
4020 	case PCIE_PCIECAP_DEV_TYPE_DOWN:
4021 	case PCIE_PCIECAP_DEV_TYPE_PCIE2PCI:
4022 	case PCIE_PCIECAP_DEV_TYPE_PCI2PCIE:
4023 		if ((pcie & PCIE_PCIECAP_SLOT_IMPL) != 0) {
4024 			*versp = &pcieadm_cap_vers_pcie_v1_slot;
4025 		} else {
4026 			*versp = &pcieadm_cap_vers_pcie_v1_link;
4027 		}
4028 		break;
4029 	case PCIE_PCIECAP_DEV_TYPE_ROOT:
4030 	case PCIE_PCIECAP_DEV_TYPE_RC_EC:
4031 		*versp = &pcieadm_cap_vers_pcie_v1_all;
4032 		break;
4033 	default:
4034 		*versp = NULL;
4035 		*lenp = 0;
4036 		return;
4037 	}
4038 
4039 	*lenp = (*versp)->ppr_len;
4040 }
4041 
4042 /*
4043  * The length of the MSI capability depends on bits in its control field. As
4044  * such we use a custom function to extract the length and treat each of these
4045  * variants as thought it were a different version.
4046  */
4047 static pcieadm_cap_vers_t pcieadm_cap_vers_msi_32 = {
4048 	0, 0xa, pcieadm_cap_msi_32
4049 };
4050 
4051 static pcieadm_cap_vers_t pcieadm_cap_vers_msi_32ext = {
4052 	0, 0xc, pcieadm_cap_msi_32ext
4053 };
4054 
4055 static pcieadm_cap_vers_t pcieadm_cap_vers_msi_64 = {
4056 	0, 0xe, pcieadm_cap_msi_64
4057 };
4058 
4059 static pcieadm_cap_vers_t pcieadm_cap_vers_msi_64ext = {
4060 	0, 0x10, pcieadm_cap_msi_64ext
4061 };
4062 
4063 static pcieadm_cap_vers_t pcieadm_cap_vers_msi_32pvm = {
4064 	0, 0x14, pcieadm_cap_msi_32pvm
4065 };
4066 
4067 static pcieadm_cap_vers_t pcieadm_cap_vers_msi_64pvm = {
4068 	0, 0x18, pcieadm_cap_msi_64pvm
4069 };
4070 
4071 static void
4072 pcieadm_cap_info_msi(pcieadm_cfgspace_walk_t *walkp,
4073     const pcieadm_pci_cap_t *cap, uint32_t off,
4074     const pcieadm_cap_vers_t **versp, uint32_t *lenp,
4075     const pcieadm_subcap_t **subcap)
4076 {
4077 	uint16_t ctrl;
4078 	boolean_t addr64, pvm, ext;
4079 
4080 	*subcap = NULL;
4081 	ctrl = walkp->pcw_data->pcb_u8[off + 2] |
4082 	    (walkp->pcw_data->pcb_u8[off + 3] << 8);
4083 	if (ctrl == PCI_EINVAL16) {
4084 		warnx("failed to read MSI Message Control register");
4085 		*lenp = 0;
4086 		*versp = NULL;
4087 		return;
4088 	}
4089 
4090 	/*
4091 	 * The MSI capability has three main things that control its size.
4092 	 * 64-bit addressing adds 4 bytes. Per-Vector Masking adds 8 bytes and
4093 	 * causes the Extended data addressing piece to always be present.
4094 	 * Therefore we check first for pvm as it implies evt, effectively.
4095 	 */
4096 	addr64 = (ctrl & PCI_MSI_64BIT_MASK) != 0;
4097 	pvm = (ctrl & PCI_MSI_PVM_MASK) != 0;
4098 	ext = (ctrl & PCI_MSI_EMD_MASK) != 0;
4099 
4100 	if (pvm && addr64) {
4101 		*versp = &pcieadm_cap_vers_msi_64pvm;
4102 	} else if (pvm) {
4103 		*versp = &pcieadm_cap_vers_msi_32pvm;
4104 	} else if (addr64 && ext) {
4105 		*versp = &pcieadm_cap_vers_msi_64ext;
4106 	} else if (addr64) {
4107 		*versp = &pcieadm_cap_vers_msi_64;
4108 	} else if (ext) {
4109 		*versp = &pcieadm_cap_vers_msi_32ext;
4110 	} else {
4111 		*versp = &pcieadm_cap_vers_msi_32;
4112 	}
4113 
4114 	*lenp = (*versp)->ppr_len;
4115 }
4116 
4117 /*
4118  * The AER Capability is technically different for PCIe-PCI bridges. If we find
4119  * that device type here, then we need to use a different version information
4120  * rather than the actual set defined with the device (which have changed over
4121  * time).
4122  */
4123 static const pcieadm_cap_vers_t pcieadm_cap_vers_aer_bridge = {
4124 	1, 0x4c, pcieadm_cap_aer_bridge
4125 };
4126 
4127 static void
4128 pcieadm_cap_info_aer(pcieadm_cfgspace_walk_t *walkp,
4129     const pcieadm_pci_cap_t *cap, uint32_t off,
4130     const pcieadm_cap_vers_t **versp, uint32_t *lenp,
4131     const pcieadm_subcap_t **subcap)
4132 {
4133 	if (walkp->pcw_pcietype == PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) {
4134 		uint8_t vers;
4135 
4136 		*subcap = NULL;
4137 		vers = walkp->pcw_data->pcb_u8[off + 2] & 0xf;
4138 		if (vers != pcieadm_cap_vers_aer_bridge.ppr_vers) {
4139 			warnx("encountered PCIe to PCI bridge with unknown "
4140 			    "AER capability version: %u", vers);
4141 			*lenp = 0;
4142 			*versp = NULL;
4143 			return;
4144 		}
4145 		*lenp = pcieadm_cap_vers_aer_bridge.ppr_len;
4146 		*versp = &pcieadm_cap_vers_aer_bridge;
4147 	}
4148 
4149 	return (pcieadm_cap_info_vers(walkp, cap, off, versp, lenp, subcap));
4150 }
4151 
4152 /*
4153  * The PCI-X capability varies depending on the header type of the device.
4154  * Therefore we simply use the device type to figure out what to do.
4155  */
4156 static pcieadm_cap_vers_t pcieadm_cap_vers_pcix_dev = {
4157 	0, 0x8, pcieadm_cap_pcix_dev
4158 };
4159 
4160 static pcieadm_cap_vers_t pcieadm_cap_vers_pcix_bridge = {
4161 	0, 0x10, pcieadm_cap_pcix_bridge
4162 };
4163 
4164 static void
4165 pcieadm_cap_info_pcix(pcieadm_cfgspace_walk_t *walkp,
4166     const pcieadm_pci_cap_t *cap, uint32_t off,
4167     const pcieadm_cap_vers_t **versp, uint32_t *lenp,
4168     const pcieadm_subcap_t **subcap)
4169 {
4170 
4171 	*subcap = NULL;
4172 	switch (walkp->pcw_dtype) {
4173 	case PCI_HEADER_ZERO:
4174 		*versp = &pcieadm_cap_vers_pcix_dev;
4175 		break;
4176 	case PCI_HEADER_ONE:
4177 		*versp = &pcieadm_cap_vers_pcix_bridge;
4178 		break;
4179 	default:
4180 		warnx("encountered PCI-X capability with unsupported device "
4181 		    "type: 0x%x\n", walkp->pcw_dtype);
4182 		*lenp = 0;
4183 		*versp = NULL;
4184 		return;
4185 	}
4186 
4187 	*lenp = (*versp)->ppr_len;
4188 }
4189 
4190 typedef struct pcieadm_cap_ht {
4191 	uint32_t pch_capid;
4192 	pcieadm_subcap_t pch_subcap;
4193 	pcieadm_cap_vers_t pch_vers;
4194 } pcieadm_cap_ht_t;
4195 
4196 static pcieadm_cap_ht_t pcieadm_ht_cap_pri = {
4197 	0x00, { "pri", "Primary" }, { 0, 0x1c, pcieadm_cap_ht_pri }
4198 };
4199 
4200 static pcieadm_cap_ht_t pcieadm_ht_cap_sec = {
4201 	0x01, { "sec", "Secondary" }, { 0, 0x18, pcieadm_cap_ht_sec }
4202 };
4203 
4204 static pcieadm_cap_ht_t pcieadm_ht_caps[] = {
4205 	{ 0x08, { "switch", "Switch" } },
4206 	{ 0x10, { "intr", "Interrupt Discovery and Configuration" },
4207 	    { 0, 8, pcieadm_cap_ht_intr } },
4208 	{ 0x11, { "rev", "Revision ID" } },
4209 	{ 0x12, { "unitid", "UnitID Clumping" } },
4210 	{ 0x13, { "extcfg", "Extended Configuration Space Access" } },
4211 	{ 0x14, { "addrmap", "Address Mapping" } },
4212 	{ 0x15, { "msi", "MSI Mapping" },
4213 	    { 0, 4, pcieadm_cap_ht_msi } },
4214 	{ 0x16, { "dir", "DirectRoute" } },
4215 	{ 0x17, { "vcset", "VCSet" } },
4216 	{ 0x18, { "retry", "Retry Mode" } },
4217 	{ 0x19, { "x86", "X86 Encoding" } },
4218 	{ 0x1a, { "gen3", "Gen3" } },
4219 	{ 0x1b, { "fle", "Function-Level Extension" } },
4220 	{ 0x1c, { "pm", "Power Management" } },
4221 	{ UINT32_MAX, NULL },
4222 };
4223 
4224 static void
4225 pcieadm_cap_info_ht(pcieadm_cfgspace_walk_t *walkp,
4226     const pcieadm_pci_cap_t *cap, uint32_t off,
4227     const pcieadm_cap_vers_t **versp, uint32_t *lenp,
4228     const pcieadm_subcap_t **subcap)
4229 {
4230 	uint32_t base = walkp->pcw_data->pcb_u32[off / 4];
4231 	uint32_t caplo = BITX(base, 31, 29);
4232 	pcieadm_cap_ht_t *htcap = NULL;
4233 
4234 	*versp = NULL;
4235 	*lenp = 0;
4236 	*subcap = NULL;
4237 
4238 	if (caplo > 1) {
4239 		uint32_t capid = BITX(base, 31, 27);
4240 
4241 		for (uint32_t i = 0; pcieadm_ht_caps[i].pch_capid != UINT32_MAX;
4242 		    i++) {
4243 			if (capid == pcieadm_ht_caps[i].pch_capid) {
4244 				htcap = &pcieadm_ht_caps[i];
4245 				break;
4246 			}
4247 		}
4248 	} else if (caplo == 0) {
4249 		htcap = &pcieadm_ht_cap_pri;
4250 	} else if (caplo == 1) {
4251 		htcap = &pcieadm_ht_cap_sec;
4252 	}
4253 
4254 	if (htcap == NULL) {
4255 		warnx("encountered unknown HyperTransport Capability 0x%x",
4256 		    BITX(base, 31, 27));
4257 		return;
4258 	}
4259 
4260 	*subcap = &htcap->pch_subcap;
4261 	if (htcap->pch_vers.ppr_print != NULL) {
4262 		*versp = &htcap->pch_vers;
4263 		*lenp = htcap->pch_vers.ppr_len;
4264 	}
4265 }
4266 
4267 pcieadm_pci_cap_t pcieadm_pci_caps[] = {
4268 	{ PCI_CAP_ID_PM, "pcipm", "PCI Power Management",
4269 	    pcieadm_cap_info_pcipm, { { 2, 8, pcieadm_cap_pcipm_v3 },
4270 	    { 3, 8, pcieadm_cap_pcipm_v3 } } },
4271 	{ PCI_CAP_ID_AGP, "agp", "Accelerated Graphics Port" },
4272 	{ PCI_CAP_ID_VPD, "vpd", "Vital Product Data", pcieadm_cap_info_fixed,
4273 	    { { 0, 8, pcieadm_cap_vpd } } },
4274 	{ PCI_CAP_ID_SLOT_ID, "slot", "Slot Identification" },
4275 	{ PCI_CAP_ID_MSI, "msi", "Message Signaled Interrupts",
4276 	    pcieadm_cap_info_msi },
4277 	{ PCI_CAP_ID_cPCI_HS, "cpci", "CompactPCI Hot Swap" },
4278 	{ PCI_CAP_ID_PCIX, "pcix", "PCI-X", pcieadm_cap_info_pcix },
4279 	{ PCI_CAP_ID_HT, "ht", "HyperTransport", pcieadm_cap_info_ht },
4280 	{ PCI_CAP_ID_VS, "vs", "Vendor Specific", pcieadm_cap_info_fixed,
4281 	    { { 0, 3, pcieadm_cap_vs } } },
4282 	{ PCI_CAP_ID_DEBUG_PORT, "dbg", "Debug Port", pcieadm_cap_info_fixed,
4283 	    { { 0, 4, pcieadm_cap_debug } } },
4284 	{ PCI_CAP_ID_cPCI_CRC, "cpcicrc",
4285 	    "CompactPCI Central Resource Control" },
4286 	{ PCI_CAP_ID_PCI_HOTPLUG, "pcihp", "PCI Hot-Plug" },
4287 	{ PCI_CAP_ID_P2P_SUBSYS, "bdgsub", "PCI Bridge Subsystem Vendor ID",
4288 	    pcieadm_cap_info_fixed, { 0, 8, pcieadm_cap_bridge_subsys } },
4289 	{ PCI_CAP_ID_AGP_8X, "agp8x", "AGP 8x" },
4290 	{ PCI_CAP_ID_SECURE_DEV, "secdev", "Secure Device" },
4291 	{ PCI_CAP_ID_PCI_E, "pcie", "PCI Express", pcieadm_cap_info_pcie },
4292 	{ PCI_CAP_ID_MSI_X, "msix", "MSI-X", pcieadm_cap_info_fixed,
4293 	    { { 0, 12, pcieadm_cap_msix } } },
4294 	{ PCI_CAP_ID_SATA, "sata", "Serial ATA Configuration",
4295 	    pcieadm_cap_info_fixed, { { 0, 8, pcieadm_cap_sata } } },
4296 	/*
4297 	 * Note, the AF feature doesn't have a version but encodes a length in
4298 	 * the version field, so we cheat and use that.
4299 	 */
4300 	{ PCI_CAP_ID_FLR, "af", "Advanced Features", pcieadm_cap_info_vers,
4301 	    { { 6, 6, pcieadm_cap_af } } },
4302 	{ PCI_CAP_ID_EA, "ea", "Enhanced Allocation" },
4303 	{ PCI_CAP_ID_FPB, "fpb", "Flattening Portal Bridge" }
4304 };
4305 
4306 pcieadm_pci_cap_t pcieadm_pcie_caps[] = {
4307 	{ 0, "null", "NULL Capability", pcieadm_cap_info_fixed,
4308 	    { { 0, 0x4, pcieadm_cap_null } } },
4309 	{ PCIE_EXT_CAP_ID_AER, "aer", "Advanced Error Reporting",
4310 	    pcieadm_cap_info_aer, { { 1, 0x38, pcieadm_cap_aer_v1 },
4311 	    { 2, 0x48, pcieadm_cap_aer_v2 } } },
4312 	{ PCIE_EXT_CAP_ID_VC, "vc", "Virtual Channel", pcieadm_cap_info_vers,
4313 	    { { 0x1, 0x1c, pcieadm_cap_vc } } },
4314 	{ PCIE_EXT_CAP_ID_SER, "sn", "Serial Number", pcieadm_cap_info_vers,
4315 	    { { 1, 0xc, pcieadm_cap_sn } } },
4316 	{ PCIE_EXT_CAP_ID_PWR_BUDGET, "powbudg", "Power Budgeting",
4317 	    pcieadm_cap_info_vers, { { 1, 0x10, pcieadm_cap_powbudg } } },
4318 	{ PCIE_EXT_CAP_ID_RC_LINK_DECL, "rcld",
4319 	    "Root Complex Link Declaration" },
4320 	{ PCIE_EXT_CAP_ID_RC_INT_LINKCTRL, "rcilc",
4321 	    "Root Complex Internal Link Control" },
4322 	{ PCIE_EXT_CAP_ID_RC_EVNT_CEA, "rcecea",
4323 	    "Root Complex Event Collector Endpoint Aggregation" },
4324 	{ PCIE_EXT_CAP_ID_MFVC, "mfvc", "Multi-Function Virtual Channel" },
4325 	{ PCIE_EXT_CAP_ID_VC_WITH_MFVC, "vcwmfvc", "Virtual Channel with MFVC",
4326 	    pcieadm_cap_info_vers, { { 0x1, 0x1c, pcieadm_cap_vc } } },
4327 	{ PCIE_EXT_CAP_ID_RCRB, "rcrb", "Root Complex Register Block" },
4328 	{ PCIE_EXT_CAP_ID_VS, "vsec", "Vendor Specific Extended Capability",
4329 	    pcieadm_cap_info_vers, { { 1, 0x8, pcieadm_cap_vsec } } },
4330 	{ PCIE_EXT_CAP_ID_CAC, "cac", "Configuration Access Correlation" },
4331 	{ PCIE_EXT_CAP_ID_ACS, "acs", "Access Control Services",
4332 	    pcieadm_cap_info_vers, { { 1, 0x8, pcieadm_cap_acs } } },
4333 	{ PCIE_EXT_CAP_ID_ARI, "ari", "Alternative Routing-ID Interpretation",
4334 	    pcieadm_cap_info_vers, { { 1, 0x8, pcieadm_cap_ari } } },
4335 	{ PCIE_EXT_CAP_ID_ATS, "ats", "Access Translation Services",
4336 	    pcieadm_cap_info_vers, { { 1, 0x8, pcieadm_cap_ats } } },
4337 	{ PCIE_EXT_CAP_ID_SRIOV, "sriov", "Single Root I/O Virtualization",
4338 	    pcieadm_cap_info_vers, { { 1, 0x40, pcieadm_cap_sriov } } },
4339 	{ PCIE_EXT_CAP_ID_MRIOV, "mriov", "Multi-Root I/O Virtualization" },
4340 	{ PCIE_EXT_CAP_ID_MULTICAST, "mcast", "Multicast",
4341 	    pcieadm_cap_info_vers, { { 1, 0x30, pcieadm_cap_mcast } } },
4342 	{ PCIE_EXT_CAP_ID_PGREQ, "pgreq", "Page Request",
4343 	    pcieadm_cap_info_vers, { { 1, 0x10, pcieadm_cap_pgreq } } },
4344 	{ PCIE_EXT_CAP_ID_EA, "ea", "Enhanced Allocation" },
4345 	{ PCIE_EXT_CAP_ID_RESIZE_BAR, "rbar", "Resizable Bar" },
4346 	{ PCIE_EXT_CAP_ID_DPA, "dpa", "Dynamic Power Allocation",
4347 	    pcieadm_cap_info_vers, { { 1, 0x10, pcieadm_cap_dpa } } },
4348 	{ PCIE_EXT_CAP_ID_TPH_REQ, "tph", "TPH Requester",
4349 	    pcieadm_cap_info_vers, { { 1, 0xc, pcieadm_cap_tph } } },
4350 	{ PCIE_EXT_CAP_ID_LTR, "ltr", "Latency Tolerance Reporting",
4351 	    pcieadm_cap_info_vers, { { 1, 0x8, pcieadm_cap_ltr } } },
4352 	{ PCIE_EXT_CAP_ID_PCIE2, "pcie2", "Secondary PCI Express",
4353 	    pcieadm_cap_info_vers, { { 1, 0xc, pcieadm_cap_pcie2 } } },
4354 	{ PCIE_EXT_CAP_ID_PASID, "pasid", "Process Address Space ID",
4355 	    pcieadm_cap_info_vers, { { 1, 0x8, pcieadm_cap_pasid } } },
4356 	{ PCIE_EXT_CAP_ID_LNR, "lnr", "LN Requester" },
4357 	{ PCIE_EXT_CAP_ID_DPC, "dpc", "Downstream Port Containment",
4358 	    pcieadm_cap_info_vers, { { 1, 0x30, pcieadm_cap_dpc } } },
4359 	{ PCIE_EXT_CAP_ID_L1PM, "l1pm", "L1 PM Substates",
4360 	    pcieadm_cap_info_vers, { { 1, 0x10, pcieadm_cap_l1pm_v1 },
4361 	    { 2, 0x14, pcieadm_cap_l1pm_v2 } } },
4362 	{ PCIE_EXT_CAP_ID_PTM, "ptm", "Precision Time Management",
4363 	    pcieadm_cap_info_vers, { { 1, 0xc, pcieadm_cap_info_ptm } } },
4364 	{ PCIE_EXT_CAP_ID_FRS, "frs", "FRS Queueing" },
4365 	{ PCIE_EXT_CAP_ID_RTR, "trt", "Readiness Time Reporting" },
4366 	/*
4367 	 * When we encounter a designated vendor specificaiton, in particular,
4368 	 * for CXL, we'll want to set ppc_subcap so we can use reasonable
4369 	 * filtering.
4370 	 */
4371 	{ PCIE_EXT_CAP_ID_DVS, "dvsec",
4372 	    "Designated Vendor-Specific Extended Capability" },
4373 	{ PCIE_EXT_CAP_ID_VFRBAR, "vfrbar", "Virtual Function Resizable BAR" },
4374 	{ PCIE_EXT_CAP_ID_DLF, "dlf", "Data Link Feature",
4375 	    pcieadm_cap_info_vers, { { 1, 0xc, pcieadm_cap_dlf } } },
4376 	{ PCIE_EXT_CAP_ID_PL16GT, "pl16g", "Physical Layer 16.0 GT/s",
4377 	    pcieadm_cap_info_vers, { { 1, 0x22, pcieadm_cap_16g } } },
4378 	{ PCIE_EXT_CAP_ID_LANE_MARGIN, "margin",
4379 	    "Lane Margining at the Receiver", pcieadm_cap_info_vers,
4380 	    { { 1, 0x8, pcieadm_cap_margin } } },
4381 	{ PCIE_EXT_CAP_ID_HIEARCHY_ID, "hierid", "Hierarchy ID" },
4382 	{ PCIE_EXT_CAP_ID_NPEM, "npem", "Native PCIe Enclosure Management" },
4383 	{ PCIE_EXT_CAP_ID_PL32GT, "pl32g", "Physical Layer 32.0 GT/s" },
4384 	{ PCIE_EXT_CAP_ID_AP, "ap", "Alternative Protocol" },
4385 	{ PCIE_EXT_CAP_ID_SFI, "sfi", "System Firmware Intermediary" }
4386 };
4387 
4388 static const pcieadm_pci_cap_t *
4389 pcieadm_cfgspace_match_cap(uint32_t capid, boolean_t pcie)
4390 {
4391 	uint_t ncaps;
4392 	pcieadm_pci_cap_t *caps;
4393 
4394 	if (pcie) {
4395 		ncaps = ARRAY_SIZE(pcieadm_pcie_caps);
4396 		caps = pcieadm_pcie_caps;
4397 	} else {
4398 		ncaps = ARRAY_SIZE(pcieadm_pci_caps);
4399 		caps = pcieadm_pci_caps;
4400 	}
4401 
4402 	for (uint_t i = 0; i < ncaps; i++) {
4403 		if (caps[i].ppc_id == capid) {
4404 			return (&caps[i]);
4405 		}
4406 	}
4407 
4408 	return (NULL);
4409 }
4410 
4411 static void
4412 pcieadm_cfgspace_print_cap(pcieadm_cfgspace_walk_t *walkp, uint_t capid,
4413     const pcieadm_pci_cap_t *cap_info, const pcieadm_cap_vers_t *vers_info,
4414     const pcieadm_subcap_t *subcap)
4415 {
4416 	boolean_t filter = B_FALSE;
4417 
4418 	/*
4419 	 * If we don't recognize the capability, print out the ID if we're not
4420 	 * filtering and not in parsable mode.
4421 	 */
4422 	if (cap_info == NULL) {
4423 		if (walkp->pcw_ofmt == NULL &&
4424 		    pcieadm_cfgspace_filter(walkp, NULL)) {
4425 			warnx("encountered unknown capability ID 0x%x "
4426 			    "unable to print or list", capid);
4427 			pcieadm_print("Unknown Capability (0x%x)\n", capid);
4428 		}
4429 		return;
4430 	}
4431 
4432 	/*
4433 	 * Check to see if we should print this and in particular, if there's
4434 	 * both a capability or subcapability, we need to try and match both.
4435 	 * The reason that the calls to check the filters are conditioned on
4436 	 * pcw_ofmt is that when we're in parsable mode, we cannot match a
4437 	 * top-level capability since it's an arbitrary number of fields.
4438 	 */
4439 	if (walkp->pcw_ofmt == NULL) {
4440 		filter = pcieadm_cfgspace_filter(walkp, cap_info->ppc_short);
4441 	}
4442 	pcieadm_strfilt_push(walkp, cap_info->ppc_short);
4443 	if (subcap != NULL) {
4444 		if (walkp->pcw_ofmt == NULL) {
4445 			boolean_t subfilt = pcieadm_cfgspace_filter(walkp,
4446 			    subcap->psub_short);
4447 			filter = subfilt || filter;
4448 		}
4449 		pcieadm_strfilt_push(walkp, subcap->psub_short);
4450 	}
4451 
4452 
4453 	if (walkp->pcw_ofmt == NULL && filter) {
4454 		if ((walkp->pcw_flags & PCIEADM_CFGSPACE_F_SHORT) != 0) {
4455 			if (subcap != NULL) {
4456 				pcieadm_print("%s Capability - %s (%s) "
4457 				    "(0x%x)\n", cap_info->ppc_human,
4458 				    subcap->psub_human,
4459 				    walkp->pcw_filt->pstr_curgen, capid);
4460 			} else {
4461 				pcieadm_print("%s Capability (%s) (0x%x)\n",
4462 				    cap_info->ppc_human,
4463 				    walkp->pcw_filt->pstr_curgen, capid);
4464 			}
4465 		} else {
4466 			if (subcap != NULL) {
4467 				pcieadm_print("%s Capability - %s (0x%x)\n",
4468 				    cap_info->ppc_human, subcap->psub_human,
4469 				    capid);
4470 			} else {
4471 				pcieadm_print("%s Capability (0x%x)\n",
4472 				    cap_info->ppc_human, capid);
4473 			}
4474 		}
4475 	}
4476 
4477 	if (vers_info != NULL) {
4478 		pcieadm_cfgspace_print_t *print;
4479 
4480 		pcieadm_indent();
4481 		for (print = vers_info->ppr_print;
4482 		    print->pcp_short != NULL; print++) {
4483 			VERIFY3P(print->pcp_print, !=, NULL);
4484 			print->pcp_print(walkp, print,
4485 			    print->pcp_arg);
4486 		}
4487 		pcieadm_deindent();
4488 	} else {
4489 		if (subcap != NULL) {
4490 			warnx("Unable to print or list %s - %s (no support or "
4491 			    "missing version info)", cap_info->ppc_human,
4492 			    subcap->psub_human);
4493 		} else {
4494 			warnx("Unable to print or list %s (no support or "
4495 			    "missing version info)", cap_info->ppc_human);
4496 		}
4497 	}
4498 
4499 	if (subcap != NULL) {
4500 		pcieadm_strfilt_pop(walkp);
4501 	}
4502 	pcieadm_strfilt_pop(walkp);
4503 }
4504 
4505 static void
4506 pcieadm_cfgspace_write(int fd, const uint8_t *source, size_t len)
4507 {
4508 	size_t off = 0;
4509 
4510 	while (len > 0) {
4511 		ssize_t ret = write(fd, source + off, len - off);
4512 		if (ret < 0) {
4513 			err(EXIT_FAILURE, "failed to write config space to "
4514 			    "output file");
4515 		}
4516 
4517 		off += ret;
4518 		len -= ret;
4519 	}
4520 }
4521 
4522 void
4523 pcieadm_cfgspace(pcieadm_t *pcip, pcieadm_cfgspace_op_t op,
4524     pcieadm_cfgspace_f readf, int fd, void *readarg, uint_t nfilts,
4525     pcieadm_cfgspace_filter_t *filters, pcieadm_cfgspace_flags_t flags,
4526     ofmt_handle_t ofmt)
4527 {
4528 	uint_t type;
4529 	uint16_t cap;
4530 	pcieadm_cfgspace_data_t data;
4531 	pcieadm_cfgspace_walk_t walk;
4532 	const char *headstr, *headshort;
4533 	pcieadm_cfgspace_print_t *header;
4534 	boolean_t capsup = B_FALSE, extcfg = B_FALSE;
4535 	uint_t ncaps;
4536 
4537 	walk.pcw_pcieadm = pcip;
4538 	walk.pcw_op = op;
4539 	walk.pcw_data = &data;
4540 	walk.pcw_outfd = fd;
4541 	walk.pcw_capoff = 0;
4542 	walk.pcw_nlanes = 0;
4543 	walk.pcw_nfilters = nfilts;
4544 	walk.pcw_filters = filters;
4545 	walk.pcw_flags = flags;
4546 	walk.pcw_ofmt = ofmt;
4547 	walk.pcw_filt = NULL;
4548 
4549 	/*
4550 	 * Start by reading all of the basic 40-byte config space header in one
4551 	 * fell swoop.
4552 	 */
4553 	for (uint32_t i = 0; i < PCI_CAP_PTR_OFF / 4; i++) {
4554 		if (!readf(i * 4, 4, &data.pcb_u32[i], readarg)) {
4555 			errx(EXIT_FAILURE, "failed to read offset %u from "
4556 			    "configuration space", i * 4);
4557 		}
4558 	}
4559 	walk.pcw_valid = PCI_CAP_PTR_OFF;
4560 	walk.pcw_caplen = PCI_CAP_PTR_OFF;
4561 
4562 	/*
4563 	 * Grab the information from the header that we need to figure out what
4564 	 * kind of device this is, how to print it, if there are any
4565 	 * capabilities, and go from there.
4566 	 */
4567 	type = data.pcb_u8[PCI_CONF_HEADER] & PCI_HEADER_TYPE_M;
4568 	switch (type) {
4569 	case PCI_HEADER_ZERO:
4570 		headstr = "Type 0 Header";
4571 		headshort = "header0";
4572 		header = pcieadm_cfgspace_type0;
4573 		capsup = (data.pcb_u8[PCI_CONF_STAT] & PCI_STAT_CAP) != 0;
4574 		break;
4575 	case PCI_HEADER_ONE:
4576 		headstr = "Type 1 Header";
4577 		headshort = "header1";
4578 		header = pcieadm_cfgspace_type1;
4579 		capsup = (data.pcb_u8[PCI_CONF_STAT] & PCI_STAT_CAP) != 0;
4580 		break;
4581 	case PCI_HEADER_TWO:
4582 	default:
4583 		headstr = "Unknown Header";
4584 		headshort = "headerX";
4585 		header = pcieadm_cfgspace_unknown;
4586 		warnx("unsupported PCI header type: 0x%x, output limited to "
4587 		    "data configuration space");
4588 	}
4589 
4590 	walk.pcw_dtype = type;
4591 
4592 	if (op == PCIEADM_CFGSPACE_OP_WRITE) {
4593 		pcieadm_cfgspace_write(fd, &data.pcb_u8[0], PCI_CAP_PTR_OFF);
4594 	} else if (op == PCIEADM_CFGSPACE_OP_PRINT) {
4595 		pcieadm_cfgspace_print_t *print;
4596 
4597 		if (walk.pcw_ofmt == NULL &&
4598 		    pcieadm_cfgspace_filter(&walk, headshort)) {
4599 			if ((flags & PCIEADM_CFGSPACE_F_SHORT) != 0) {
4600 				pcieadm_print("Device %s -- %s (%s)\n",
4601 				    pcip->pia_devstr, headstr, headshort);
4602 			} else {
4603 				pcieadm_print("Device %s -- %s\n",
4604 				    pcip->pia_devstr, headstr);
4605 			}
4606 		}
4607 
4608 		pcieadm_strfilt_push(&walk, headshort);
4609 		pcieadm_indent();
4610 		for (print = header; print->pcp_short != NULL; print++) {
4611 			print->pcp_print(&walk, print, print->pcp_arg);
4612 		}
4613 		pcieadm_deindent();
4614 		pcieadm_strfilt_pop(&walk);
4615 	}
4616 
4617 
4618 	if (!capsup) {
4619 		return;
4620 	}
4621 
4622 	for (uint32_t i = PCI_CAP_PTR_OFF / 4; i < PCI_CONF_HDR_SIZE / 4; i++) {
4623 		if (!readf(i * 4, 4, &data.pcb_u32[i], readarg)) {
4624 			errx(EXIT_FAILURE, "failed to read offset %u from "
4625 			    "configuration space", i * 4);
4626 		}
4627 	}
4628 	walk.pcw_valid = PCIE_EXT_CAP;
4629 	VERIFY3P(walk.pcw_filt, ==, NULL);
4630 
4631 	if (op == PCIEADM_CFGSPACE_OP_WRITE) {
4632 		pcieadm_cfgspace_write(fd, &data.pcb_u8[PCI_CAP_PTR_OFF],
4633 		    PCI_CONF_HDR_SIZE - PCI_CAP_PTR_OFF);
4634 	}
4635 
4636 	ncaps = 0;
4637 	cap = data.pcb_u8[PCI_CONF_CAP_PTR];
4638 	while (cap != 0 && cap != PCI_EINVAL8) {
4639 		const pcieadm_pci_cap_t *cap_info;
4640 		const pcieadm_cap_vers_t *vers_info = NULL;
4641 		const pcieadm_subcap_t *subcap = NULL;
4642 		uint8_t cap_id, nextcap;
4643 		uint32_t read_len = 0;
4644 
4645 		/*
4646 		 * The PCI specification requires that the caller mask off the
4647 		 * bottom two bits. Always check for an invalid value (all 1s)
4648 		 * before this.
4649 		 */
4650 		cap &= PCI_CAP_PTR_MASK;
4651 		cap_id = data.pcb_u8[cap + PCI_CAP_ID];
4652 		nextcap = data.pcb_u8[cap + PCI_CAP_NEXT_PTR];
4653 		cap_info = pcieadm_cfgspace_match_cap(cap_id, B_FALSE);
4654 		if (cap_info != NULL && cap_info->ppc_info != NULL) {
4655 			cap_info->ppc_info(&walk, cap_info, cap, &vers_info,
4656 			    &read_len, &subcap);
4657 		}
4658 
4659 		walk.pcw_caplen = read_len;
4660 		walk.pcw_capoff = cap;
4661 
4662 		if (cap_id == PCI_CAP_ID_PCI_E) {
4663 			extcfg = B_TRUE;
4664 			if (walk.pcw_valid != 0) {
4665 				walk.pcw_pcietype = data.pcb_u8[cap +
4666 				    PCIE_PCIECAP] & PCIE_PCIECAP_DEV_TYPE_MASK;
4667 				walk.pcw_nlanes = (data.pcb_u8[cap +
4668 				    PCIE_LINKCAP] & 0xf0) >> 4;
4669 				walk.pcw_nlanes |= (data.pcb_u8[cap +
4670 				    PCIE_LINKCAP + 1] & 0x01) << 4;
4671 			} else {
4672 				walk.pcw_pcietype = UINT_MAX;
4673 			}
4674 		}
4675 
4676 		if (op == PCIEADM_CFGSPACE_OP_PRINT) {
4677 			pcieadm_cfgspace_print_cap(&walk, cap_id, cap_info,
4678 			    vers_info, subcap);
4679 		}
4680 
4681 		cap = nextcap;
4682 		ncaps++;
4683 		if (ncaps >= PCI_CAP_MAX_PTR) {
4684 			errx(EXIT_FAILURE, "encountered more PCI capabilities "
4685 			    "than fit in configuration space");
4686 		}
4687 	}
4688 
4689 	if (!extcfg) {
4690 		return;
4691 	}
4692 
4693 	for (uint_t i = PCIE_EXT_CAP / 4; i < PCIE_CONF_HDR_SIZE / 4; i++) {
4694 		if (!readf(i * 4, 4, &data.pcb_u32[i], readarg)) {
4695 			errx(EXIT_FAILURE, "failed to read offset %u from "
4696 			    "configuration space", i * 4);
4697 		}
4698 	}
4699 	walk.pcw_valid = PCIE_CONF_HDR_SIZE;
4700 
4701 	if (op == PCIEADM_CFGSPACE_OP_WRITE) {
4702 		pcieadm_cfgspace_write(fd, &data.pcb_u8[PCIE_EXT_CAP],
4703 		    PCIE_CONF_HDR_SIZE - PCIE_EXT_CAP);
4704 		return;
4705 	}
4706 
4707 	cap = PCIE_EXT_CAP;
4708 	ncaps = 0;
4709 	while (cap != 0 && cap != PCI_EINVAL16) {
4710 		uint16_t cap_id, nextcap;
4711 		const pcieadm_pci_cap_t *cap_info;
4712 		const pcieadm_cap_vers_t *vers_info = NULL;
4713 		const pcieadm_subcap_t *subcap = NULL;
4714 		uint32_t read_len = 0;
4715 
4716 		/*
4717 		 * PCIe has the same masking as PCI. Note, sys/pcie.h currently
4718 		 * has PCIE_EXT_CAP_NEXT_PTR_MASK as 0xfff, instead of the
4719 		 * below. This should be switched to PCIE_EXT_CAP_NEXT_PTR_MASK
4720 		 * when the kernel headers are fixed.
4721 		 */
4722 		cap &= 0xffc;
4723 
4724 		/*
4725 		 * While this seems duplicative of the loop condition, a device
4726 		 * without capabilities indicates it with a zero for the first
4727 		 * cap.
4728 		 */
4729 		if (data.pcb_u32[cap / 4] == 0 ||
4730 		    data.pcb_u32[cap / 4] == PCI_EINVAL32)
4731 			break;
4732 
4733 		cap_id = data.pcb_u32[cap / 4] & PCIE_EXT_CAP_ID_MASK;
4734 		nextcap = (data.pcb_u32[cap / 4] >>
4735 		    PCIE_EXT_CAP_NEXT_PTR_SHIFT) & PCIE_EXT_CAP_NEXT_PTR_MASK;
4736 
4737 		cap_info = pcieadm_cfgspace_match_cap(cap_id, B_TRUE);
4738 		if (cap_info != NULL && cap_info->ppc_info != NULL) {
4739 			cap_info->ppc_info(&walk, cap_info, cap, &vers_info,
4740 			    &read_len, &subcap);
4741 		}
4742 
4743 		walk.pcw_caplen = read_len;
4744 		walk.pcw_capoff = cap;
4745 
4746 		if (op == PCIEADM_CFGSPACE_OP_PRINT) {
4747 			pcieadm_cfgspace_print_cap(&walk, cap_id, cap_info,
4748 			    vers_info, subcap);
4749 		}
4750 
4751 		cap = nextcap;
4752 		ncaps++;
4753 		if (ncaps >= PCIE_EXT_CAP_MAX_PTR) {
4754 			errx(EXIT_FAILURE, "encountered more PCI capabilities "
4755 			    "than fit in configuration space");
4756 		}
4757 	}
4758 }
4759 
4760 void
4761 pcieadm_show_cfgspace_usage(FILE *f)
4762 {
4763 	(void) fprintf(f, "\tshow-cfgspace\t[-L] [-n] [-H] -d device | -f file "
4764 	    "[filter...]\n");
4765 	(void) fprintf(f, "\tshow-cfgspace\t-p -o field[,...] [-H] -d device | "
4766 	    "-f file [filter...]\n");
4767 }
4768 
4769 static void
4770 pcieadm_show_cfgspace_help(const char *fmt, ...)
4771 {
4772 	if (fmt != NULL) {
4773 		va_list ap;
4774 
4775 		va_start(ap, fmt);
4776 		vwarnx(fmt, ap);
4777 		va_end(ap);
4778 		(void) fprintf(stderr, "\n");
4779 	}
4780 
4781 	(void) fprintf(stderr, "Usage:  %s show-cfgspace [-L] [-n] [-H] -d "
4782 	    "device | -f file [filter...]\n", pcieadm_progname);
4783 	(void) fprintf(stderr, "        %s show-cfgspace -p -o field[,...] "
4784 	    "[-H] -d device | -f file\n\t\t\t      [filter...]\n",
4785 	    pcieadm_progname);
4786 
4787 	(void) fprintf(stderr, "\nPrint and decode PCI configuration space "
4788 	    "data from a device or file. Each\n<filter> selects a given "
4789 	    "capability, sub-capability, register, or field to print.\n\n"
4790 	    "\t-d device\tread data from the specified device (driver instance,"
4791 	    "\n\t\t\t/devices path, or b/d/f)\n"
4792 	    "\t-f file\t\tread data from the specified file\n"
4793 	    "\t-L\t\tlist printable fields\n"
4794 	    "\t-n\t\tshow printable short names\n"
4795 	    "\t-H\t\tomit the column header (for -L and -p)\n"
4796 	    "\t-p\t\tparsable output (requires -o)\n"
4797 	    "\t-o field\toutput fields to print (required for -p)\n");
4798 }
4799 
4800 int
4801 pcieadm_show_cfgspace(pcieadm_t *pcip, int argc, char *argv[])
4802 {
4803 	int c, ret;
4804 	pcieadm_cfgspace_f readf;
4805 	void *readarg;
4806 	boolean_t list = B_FALSE, parse = B_FALSE;
4807 	const char *device = NULL, *file = NULL, *fields = NULL;
4808 	uint_t nfilts = 0;
4809 	pcieadm_cfgspace_filter_t *filts = NULL;
4810 	pcieadm_cfgspace_flags_t flags = 0;
4811 	uint_t oflags = 0;
4812 	ofmt_handle_t ofmt = NULL;
4813 
4814 	while ((c = getopt(argc, argv, ":HLd:f:o:np")) != -1) {
4815 		switch (c) {
4816 		case 'd':
4817 			device = optarg;
4818 			break;
4819 		case 'L':
4820 			list = B_TRUE;
4821 			break;
4822 		case 'f':
4823 			file = optarg;
4824 			break;
4825 		case 'p':
4826 			parse = B_TRUE;
4827 			flags |= PCIEADM_CFGSPACE_F_PARSE;
4828 			oflags |= OFMT_PARSABLE;
4829 			break;
4830 		case 'n':
4831 			flags |= PCIEADM_CFGSPACE_F_SHORT;
4832 			break;
4833 		case 'H':
4834 			oflags |= OFMT_NOHEADER;
4835 			break;
4836 		case 'o':
4837 			fields = optarg;
4838 			break;
4839 		case ':':
4840 			pcieadm_show_cfgspace_help("Option -%c requires an "
4841 			    "argument", optopt);
4842 			exit(EXIT_USAGE);
4843 		case '?':
4844 		default:
4845 			pcieadm_show_cfgspace_help("unknown option: -%c",
4846 			    optopt);
4847 			exit(EXIT_USAGE);
4848 		}
4849 	}
4850 
4851 	argc -= optind;
4852 	argv += optind;
4853 
4854 	if (device == NULL && file == NULL) {
4855 		pcieadm_show_cfgspace_help("one of -d or -f must be specified");
4856 		exit(EXIT_USAGE);
4857 	}
4858 
4859 	if (device != NULL && file != NULL) {
4860 		pcieadm_show_cfgspace_help("only one of -d and -f must be "
4861 		    "specified");
4862 		exit(EXIT_USAGE);
4863 	}
4864 
4865 	if (parse && fields == NULL) {
4866 		pcieadm_show_cfgspace_help("-p requires fields specified with "
4867 		    "-o");
4868 		exit(EXIT_USAGE);
4869 	}
4870 
4871 	if (!parse && fields != NULL) {
4872 		pcieadm_show_cfgspace_help("-o can only be used with -p");
4873 		exit(EXIT_USAGE);
4874 	}
4875 
4876 	if ((oflags & OFMT_NOHEADER) && !(list || parse)) {
4877 		pcieadm_show_cfgspace_help("-H must be used with either -L or "
4878 		    "-p");
4879 		exit(EXIT_USAGE);
4880 	}
4881 
4882 	if ((flags & PCIEADM_CFGSPACE_F_SHORT) && (list || parse)) {
4883 		pcieadm_show_cfgspace_help("-n cannot be used with either -L "
4884 		    "or -p");
4885 		exit(EXIT_USAGE);
4886 	}
4887 
4888 	if (list && parse != 0) {
4889 		pcieadm_show_cfgspace_help("-L and -p cannot be used together");
4890 		exit(EXIT_USAGE);
4891 	}
4892 
4893 	if (list && fields != NULL) {
4894 		pcieadm_show_cfgspace_help("-L and -o cannot be used together");
4895 		exit(EXIT_USAGE);
4896 	}
4897 
4898 	if (list) {
4899 		fields = "short,human";
4900 	}
4901 
4902 	if (argc > 0) {
4903 		nfilts = argc;
4904 		filts = calloc(nfilts, sizeof (pcieadm_cfgspace_filter_t));
4905 
4906 		for (int i = 0; i < argc; i++) {
4907 			filts[i].pcf_string = argv[i];
4908 			filts[i].pcf_len = strlen(argv[i]);
4909 		}
4910 	}
4911 
4912 	if (list || parse) {
4913 		ofmt_status_t oferr;
4914 		oferr = ofmt_open(fields, pcieadm_cfgspace_ofmt, oflags, 0,
4915 		    &ofmt);
4916 		ofmt_check(oferr, parse, ofmt, pcieadm_ofmt_errx, warnx);
4917 	}
4918 
4919 	/*
4920 	 * Initialize privileges that we require. For reading from the kernel
4921 	 * we require all privileges. For a file, we just intersect with things
4922 	 * that would allow someone to read from any file.
4923 	 */
4924 	if (device != NULL) {
4925 		/*
4926 		 * We need full privileges if reading from a device,
4927 		 * unfortunately.
4928 		 */
4929 		priv_fillset(pcip->pia_priv_eff);
4930 	} else {
4931 		VERIFY0(priv_addset(pcip->pia_priv_eff, PRIV_FILE_DAC_READ));
4932 		VERIFY0(priv_addset(pcip->pia_priv_eff, PRIV_FILE_DAC_SEARCH));
4933 	}
4934 	pcieadm_init_privs(pcip);
4935 
4936 	if (device != NULL) {
4937 		pcieadm_find_dip(pcip, device);
4938 		pcieadm_init_cfgspace_kernel(pcip, &readf, &readarg);
4939 	} else {
4940 		pcip->pia_devstr = file;
4941 		pcieadm_init_cfgspace_file(pcip, file, &readf, &readarg);
4942 	}
4943 	pcieadm_cfgspace(pcip, PCIEADM_CFGSPACE_OP_PRINT, readf, -1, readarg,
4944 	    nfilts, filts, flags, ofmt);
4945 	if (device != NULL) {
4946 		pcieadm_fini_cfgspace_kernel(readarg);
4947 	} else {
4948 		pcieadm_fini_cfgspace_file(readarg);
4949 	}
4950 
4951 	ofmt_close(ofmt);
4952 	ret = EXIT_SUCCESS;
4953 	for (uint_t i = 0; i < nfilts; i++) {
4954 		if (!filts[i].pcf_used) {
4955 			warnx("filter '%s' did not match any fields",
4956 			    filts[i].pcf_string);
4957 			ret = EXIT_FAILURE;
4958 		}
4959 	}
4960 
4961 	return (ret);
4962 }
4963 
4964 typedef struct pcieadm_save_cfgspace {
4965 	pcieadm_t *psc_pci;
4966 	int psc_dirfd;
4967 	uint_t psc_nsaved;
4968 	int psc_ret;
4969 } pcieadm_save_cfgspace_t;
4970 
4971 static int
4972 pcieadm_save_cfgspace_cb(di_node_t devi, void *arg)
4973 {
4974 	int fd, nregs, *regs;
4975 	pcieadm_save_cfgspace_t *psc = arg;
4976 	pcieadm_cfgspace_f readf;
4977 	void *readarg;
4978 	char fname[128];
4979 
4980 	psc->psc_pci->pia_devstr = di_node_name(devi);
4981 	psc->psc_pci->pia_devi = devi;
4982 	psc->psc_pci->pia_nexus = DI_NODE_NIL;
4983 	pcieadm_find_nexus(psc->psc_pci);
4984 	if (psc->psc_pci->pia_nexus == DI_NODE_NIL) {
4985 		warnx("failed to find nexus for %s", di_node_name(devi));
4986 		psc->psc_ret = EXIT_FAILURE;
4987 		return (DI_WALK_CONTINUE);
4988 	}
4989 
4990 	nregs = di_prop_lookup_ints(DDI_DEV_T_ANY, devi, "reg", &regs);
4991 	if (nregs <= 0) {
4992 		warnx("failed to lookup regs array for %s",
4993 		    psc->psc_pci->pia_devstr);
4994 		psc->psc_ret = EXIT_FAILURE;
4995 		return (DI_WALK_CONTINUE);
4996 	}
4997 
4998 	(void) snprintf(fname, sizeof (fname), "%02x-%02x-%02x.pci",
4999 	    PCI_REG_BUS_G(regs[0]), PCI_REG_DEV_G(regs[0]),
5000 	    PCI_REG_FUNC_G(regs[0]));
5001 
5002 	if (setppriv(PRIV_SET, PRIV_EFFECTIVE, psc->psc_pci->pia_priv_eff) !=
5003 	    0) {
5004 		err(EXIT_FAILURE, "failed to raise privileges");
5005 	}
5006 	fd = openat(psc->psc_dirfd, fname, O_WRONLY | O_TRUNC | O_CREAT, 0666);
5007 	if (setppriv(PRIV_SET, PRIV_EFFECTIVE, psc->psc_pci->pia_priv_min) !=
5008 	    0) {
5009 		err(EXIT_FAILURE, "failed to reduce privileges");
5010 	}
5011 
5012 	if (fd < 0) {
5013 		warn("failed to create output file %s", fname);
5014 		psc->psc_ret = EXIT_FAILURE;
5015 		return (DI_WALK_CONTINUE);
5016 	}
5017 
5018 	pcieadm_init_cfgspace_kernel(psc->psc_pci, &readf, &readarg);
5019 	pcieadm_cfgspace(psc->psc_pci, PCIEADM_CFGSPACE_OP_WRITE, readf, fd,
5020 	    readarg, 0, NULL, 0, NULL);
5021 	pcieadm_fini_cfgspace_kernel(readarg);
5022 
5023 	if (close(fd) != 0) {
5024 		warn("failed to close output fd for %s", fname);
5025 		psc->psc_ret = EXIT_FAILURE;
5026 	} else {
5027 		psc->psc_nsaved++;
5028 	}
5029 
5030 	return (DI_WALK_CONTINUE);
5031 }
5032 
5033 void
5034 pcieadm_save_cfgspace_usage(FILE *f)
5035 {
5036 	(void) fprintf(f, "\tsave-cfgspace\t-d device output-file\n");
5037 	(void) fprintf(f, "\tsave-cfgspace\t-a output-directory\n");
5038 }
5039 
5040 static void
5041 pcieadm_save_cfgspace_help(const char *fmt, ...)
5042 {
5043 	if (fmt != NULL) {
5044 		va_list ap;
5045 
5046 		va_start(ap, fmt);
5047 		vwarnx(fmt, ap);
5048 		va_end(ap);
5049 		(void) fprintf(stderr, "\n");
5050 	}
5051 
5052 	(void) fprintf(stderr, "Usage:  %s save-cfgspace -d device "
5053 	    "output-file\n", pcieadm_progname);
5054 	(void) fprintf(stderr, "        %s save-cfgspace -a "
5055 	    "output-directory\n", pcieadm_progname);
5056 
5057 	(void) fprintf(stderr, "\nSave PCI configuration space data from a "
5058 	    "device to a file or\nsave all devices to a specified directory."
5059 	    "\n\n"
5060 	    "\t-a\t\tsave data from all devices\n"
5061 	    "\t-d device\tread data from the specified device (driver instance,"
5062 	    "\n\t\t\t/devices path, or b/d/f)\n");
5063 }
5064 
5065 int
5066 pcieadm_save_cfgspace(pcieadm_t *pcip, int argc, char *argv[])
5067 {
5068 	int c;
5069 	pcieadm_cfgspace_f readf;
5070 	void *readarg;
5071 	const char *device = NULL;
5072 	boolean_t do_all = B_FALSE;
5073 
5074 	while ((c = getopt(argc, argv, ":ad:")) != -1) {
5075 		switch (c) {
5076 		case 'a':
5077 			do_all = B_TRUE;
5078 			break;
5079 		case 'd':
5080 			device = optarg;
5081 			break;
5082 		case ':':
5083 			pcieadm_save_cfgspace_help("Option -%c requires an "
5084 			    "argument", optopt);
5085 			exit(EXIT_USAGE);
5086 		case '?':
5087 		default:
5088 			pcieadm_save_cfgspace_help("unknown option: -%c",
5089 			    optopt);
5090 			exit(EXIT_USAGE);
5091 		}
5092 	}
5093 
5094 	argc -= optind;
5095 	argv += optind;
5096 
5097 	if (device == NULL && !do_all) {
5098 		pcieadm_save_cfgspace_help("missing required -d option to "
5099 		    "indicate device to dump");
5100 		exit(EXIT_USAGE);
5101 	}
5102 
5103 	if (argc != 1) {
5104 		pcieadm_save_cfgspace_help("missing required output path");
5105 		exit(EXIT_USAGE);
5106 	}
5107 
5108 	/*
5109 	 * For reading from devices, we need to full privileges, unfortunately.
5110 	 */
5111 	priv_fillset(pcip->pia_priv_eff);
5112 	pcieadm_init_privs(pcip);
5113 
5114 	if (!do_all) {
5115 		int fd;
5116 
5117 		pcieadm_find_dip(pcip, device);
5118 
5119 		if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_eff) !=
5120 		    0) {
5121 			err(EXIT_FAILURE, "failed to raise privileges");
5122 		}
5123 
5124 		if ((fd = open(argv[0], O_WRONLY | O_CREAT | O_TRUNC, 0666)) <
5125 		    0) {
5126 			err(EXIT_FAILURE, "failed to open output file %s",
5127 			    argv[0]);
5128 		}
5129 
5130 		if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_min) !=
5131 		    0) {
5132 			err(EXIT_FAILURE, "failed to reduce privileges");
5133 		}
5134 
5135 		pcieadm_init_cfgspace_kernel(pcip, &readf, &readarg);
5136 		pcieadm_cfgspace(pcip, PCIEADM_CFGSPACE_OP_WRITE, readf, fd,
5137 		    readarg, 0, NULL, 0, NULL);
5138 		pcieadm_fini_cfgspace_kernel(readarg);
5139 
5140 		if (close(fd) != 0) {
5141 			err(EXIT_FAILURE, "failed to close output file "
5142 			    "descriptor");
5143 		}
5144 
5145 		return (EXIT_SUCCESS);
5146 	} else {
5147 		pcieadm_save_cfgspace_t psc;
5148 		pcieadm_di_walk_t walk;
5149 
5150 		if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_eff) !=
5151 		    0) {
5152 			err(EXIT_FAILURE, "failed to raise privileges");
5153 		}
5154 
5155 		if ((psc.psc_dirfd = open(argv[0], O_RDONLY | O_DIRECTORY)) <
5156 		    0) {
5157 			err(EXIT_FAILURE, "failed to open output directory %s",
5158 			    argv[0]);
5159 		}
5160 
5161 		if (setppriv(PRIV_SET, PRIV_EFFECTIVE, pcip->pia_priv_min) !=
5162 		    0) {
5163 			err(EXIT_FAILURE, "failed to reduce privileges");
5164 		}
5165 
5166 		psc.psc_nsaved = 0;
5167 		psc.psc_ret = EXIT_SUCCESS;
5168 		psc.psc_pci = pcip;
5169 
5170 		walk.pdw_arg = &psc;
5171 		walk.pdw_func = pcieadm_save_cfgspace_cb;
5172 		pcieadm_di_walk(pcip, &walk);
5173 
5174 		VERIFY0(close(psc.psc_dirfd));
5175 
5176 		if (psc.psc_nsaved == 0) {
5177 			warnx("failed to save any PCI devices");
5178 			return (EXIT_FAILURE);
5179 		}
5180 
5181 		pcieadm_print("successfully saved %u devices to %s\n",
5182 		    psc.psc_nsaved, argv[0]);
5183 		return (psc.psc_ret);
5184 	}
5185 }
5186