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