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