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