xref: /freebsd/usr.sbin/pciconf/cap.c (revision 1da7f3f6f72b2245e458fc7195733268ae4a1136)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 2007 Yahoo!, Inc.
5  * All rights reserved.
6  * Written by: John Baldwin <jhb@FreeBSD.org>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <sys/types.h>
34 
35 #include <err.h>
36 #include <stdio.h>
37 #include <strings.h>
38 #include <sys/agpio.h>
39 #include <sys/pciio.h>
40 
41 #include <dev/agp/agpreg.h>
42 #include <dev/pci/pcireg.h>
43 
44 #include "pciconf.h"
45 
46 static void	list_ecaps(int fd, struct pci_conf *p);
47 
48 static int cap_level;
49 
50 static void
51 cap_power(int fd, struct pci_conf *p, uint8_t ptr)
52 {
53 	uint16_t cap, status;
54 
55 	cap = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_CAP, 2);
56 	status = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_STATUS, 2);
57 	printf("powerspec %d  supports D0%s%s D3  current D%d",
58 	    cap & PCIM_PCAP_SPEC,
59 	    cap & PCIM_PCAP_D1SUPP ? " D1" : "",
60 	    cap & PCIM_PCAP_D2SUPP ? " D2" : "",
61 	    status & PCIM_PSTAT_DMASK);
62 }
63 
64 static void
65 cap_agp(int fd, struct pci_conf *p, uint8_t ptr)
66 {
67 	uint32_t status, command;
68 
69 	status = read_config(fd, &p->pc_sel, ptr + AGP_STATUS, 4);
70 	command = read_config(fd, &p->pc_sel, ptr + AGP_CAPID, 4);
71 	printf("AGP ");
72 	if (AGP_MODE_GET_MODE_3(status)) {
73 		printf("v3 ");
74 		if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_8x)
75 			printf("8x ");
76 		if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_4x)
77 			printf("4x ");
78 	} else {
79 		if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_4x)
80 			printf("4x ");
81 		if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_2x)
82 			printf("2x ");
83 		if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_1x)
84 			printf("1x ");
85 	}
86 	if (AGP_MODE_GET_SBA(status))
87 		printf("SBA ");
88 	if (AGP_MODE_GET_AGP(command)) {
89 		printf("enabled at ");
90 		if (AGP_MODE_GET_MODE_3(command)) {
91 			printf("v3 ");
92 			switch (AGP_MODE_GET_RATE(command)) {
93 			case AGP_MODE_V3_RATE_8x:
94 				printf("8x ");
95 				break;
96 			case AGP_MODE_V3_RATE_4x:
97 				printf("4x ");
98 				break;
99 			}
100 		} else
101 			switch (AGP_MODE_GET_RATE(command)) {
102 			case AGP_MODE_V2_RATE_4x:
103 				printf("4x ");
104 				break;
105 			case AGP_MODE_V2_RATE_2x:
106 				printf("2x ");
107 				break;
108 			case AGP_MODE_V2_RATE_1x:
109 				printf("1x ");
110 				break;
111 			}
112 		if (AGP_MODE_GET_SBA(command))
113 			printf("SBA ");
114 	} else
115 		printf("disabled");
116 }
117 
118 static void
119 cap_vpd(int fd __unused, struct pci_conf *p __unused, uint8_t ptr __unused)
120 {
121 
122 	printf("VPD");
123 }
124 
125 static void
126 cap_msi(int fd, struct pci_conf *p, uint8_t ptr)
127 {
128 	uint16_t ctrl;
129 	int msgnum;
130 
131 	ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSI_CTRL, 2);
132 	msgnum = 1 << ((ctrl & PCIM_MSICTRL_MMC_MASK) >> 1);
133 	printf("MSI supports %d message%s%s%s ", msgnum,
134 	    (msgnum == 1) ? "" : "s",
135 	    (ctrl & PCIM_MSICTRL_64BIT) ? ", 64 bit" : "",
136 	    (ctrl & PCIM_MSICTRL_VECTOR) ? ", vector masks" : "");
137 	if (ctrl & PCIM_MSICTRL_MSI_ENABLE) {
138 		msgnum = 1 << ((ctrl & PCIM_MSICTRL_MME_MASK) >> 4);
139 		printf("enabled with %d message%s", msgnum,
140 		    (msgnum == 1) ? "" : "s");
141 	}
142 }
143 
144 static void
145 cap_pcix(int fd, struct pci_conf *p, uint8_t ptr)
146 {
147 	uint32_t status;
148 	int comma, max_splits, max_burst_read;
149 
150 	status = read_config(fd, &p->pc_sel, ptr + PCIXR_STATUS, 4);
151 	printf("PCI-X ");
152 	if (status & PCIXM_STATUS_64BIT)
153 		printf("64-bit ");
154 	if ((p->pc_hdr & PCIM_HDRTYPE) == 1)
155 		printf("bridge ");
156 	if ((p->pc_hdr & PCIM_HDRTYPE) != 1 || (status & (PCIXM_STATUS_133CAP |
157 	    PCIXM_STATUS_266CAP | PCIXM_STATUS_533CAP)) != 0)
158 		printf("supports");
159 	comma = 0;
160 	if (status & PCIXM_STATUS_133CAP) {
161 		printf(" 133MHz");
162 		comma = 1;
163 	}
164 	if (status & PCIXM_STATUS_266CAP) {
165 		printf("%s 266MHz", comma ? "," : "");
166 		comma = 1;
167 	}
168 	if (status & PCIXM_STATUS_533CAP) {
169 		printf("%s 533MHz", comma ? "," : "");
170 		comma = 1;
171 	}
172 	if ((p->pc_hdr & PCIM_HDRTYPE) == 1)
173 		return;
174 	max_burst_read = 0;
175 	switch (status & PCIXM_STATUS_MAX_READ) {
176 	case PCIXM_STATUS_MAX_READ_512:
177 		max_burst_read = 512;
178 		break;
179 	case PCIXM_STATUS_MAX_READ_1024:
180 		max_burst_read = 1024;
181 		break;
182 	case PCIXM_STATUS_MAX_READ_2048:
183 		max_burst_read = 2048;
184 		break;
185 	case PCIXM_STATUS_MAX_READ_4096:
186 		max_burst_read = 4096;
187 		break;
188 	}
189 	max_splits = 0;
190 	switch (status & PCIXM_STATUS_MAX_SPLITS) {
191 	case PCIXM_STATUS_MAX_SPLITS_1:
192 		max_splits = 1;
193 		break;
194 	case PCIXM_STATUS_MAX_SPLITS_2:
195 		max_splits = 2;
196 		break;
197 	case PCIXM_STATUS_MAX_SPLITS_3:
198 		max_splits = 3;
199 		break;
200 	case PCIXM_STATUS_MAX_SPLITS_4:
201 		max_splits = 4;
202 		break;
203 	case PCIXM_STATUS_MAX_SPLITS_8:
204 		max_splits = 8;
205 		break;
206 	case PCIXM_STATUS_MAX_SPLITS_12:
207 		max_splits = 12;
208 		break;
209 	case PCIXM_STATUS_MAX_SPLITS_16:
210 		max_splits = 16;
211 		break;
212 	case PCIXM_STATUS_MAX_SPLITS_32:
213 		max_splits = 32;
214 		break;
215 	}
216 	printf("%s %d burst read, %d split transaction%s", comma ? "," : "",
217 	    max_burst_read, max_splits, max_splits == 1 ? "" : "s");
218 }
219 
220 static void
221 cap_ht(int fd, struct pci_conf *p, uint8_t ptr)
222 {
223 	uint32_t reg;
224 	uint16_t command;
225 
226 	command = read_config(fd, &p->pc_sel, ptr + PCIR_HT_COMMAND, 2);
227 	printf("HT ");
228 	if ((command & 0xe000) == PCIM_HTCAP_SLAVE)
229 		printf("slave");
230 	else if ((command & 0xe000) == PCIM_HTCAP_HOST)
231 		printf("host");
232 	else
233 		switch (command & PCIM_HTCMD_CAP_MASK) {
234 		case PCIM_HTCAP_SWITCH:
235 			printf("switch");
236 			break;
237 		case PCIM_HTCAP_INTERRUPT:
238 			printf("interrupt");
239 			break;
240 		case PCIM_HTCAP_REVISION_ID:
241 			printf("revision ID");
242 			break;
243 		case PCIM_HTCAP_UNITID_CLUMPING:
244 			printf("unit ID clumping");
245 			break;
246 		case PCIM_HTCAP_EXT_CONFIG_SPACE:
247 			printf("extended config space");
248 			break;
249 		case PCIM_HTCAP_ADDRESS_MAPPING:
250 			printf("address mapping");
251 			break;
252 		case PCIM_HTCAP_MSI_MAPPING:
253 			printf("MSI %saddress window %s at 0x",
254 			    command & PCIM_HTCMD_MSI_FIXED ? "fixed " : "",
255 			    command & PCIM_HTCMD_MSI_ENABLE ? "enabled" :
256 			    "disabled");
257 			if (command & PCIM_HTCMD_MSI_FIXED)
258 				printf("fee00000");
259 			else {
260 				reg = read_config(fd, &p->pc_sel,
261 				    ptr + PCIR_HTMSI_ADDRESS_HI, 4);
262 				if (reg != 0)
263 					printf("%08x", reg);
264 				reg = read_config(fd, &p->pc_sel,
265 				    ptr + PCIR_HTMSI_ADDRESS_LO, 4);
266 				printf("%08x", reg);
267 			}
268 			break;
269 		case PCIM_HTCAP_DIRECT_ROUTE:
270 			printf("direct route");
271 			break;
272 		case PCIM_HTCAP_VCSET:
273 			printf("VC set");
274 			break;
275 		case PCIM_HTCAP_RETRY_MODE:
276 			printf("retry mode");
277 			break;
278 		case PCIM_HTCAP_X86_ENCODING:
279 			printf("X86 encoding");
280 			break;
281 		case PCIM_HTCAP_GEN3:
282 			printf("Gen3");
283 			break;
284 		case PCIM_HTCAP_FLE:
285 			printf("function-level extension");
286 			break;
287 		case PCIM_HTCAP_PM:
288 			printf("power management");
289 			break;
290 		case PCIM_HTCAP_HIGH_NODE_COUNT:
291 			printf("high node count");
292 			break;
293 		default:
294 			printf("unknown %02x", command);
295 			break;
296 		}
297 }
298 
299 static void
300 cap_vendor(int fd, struct pci_conf *p, uint8_t ptr)
301 {
302 	uint8_t length;
303 
304 	length = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_LENGTH, 1);
305 	printf("vendor (length %d)", length);
306 	if (p->pc_vendor == 0x8086) {
307 		/* Intel */
308 		uint8_t version;
309 
310 		version = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_DATA,
311 		    1);
312 		printf(" Intel cap %d version %d", version >> 4, version & 0xf);
313 		if (version >> 4 == 1 && length == 12) {
314 			/* Feature Detection */
315 			uint32_t fvec;
316 			int comma;
317 
318 			comma = 0;
319 			fvec = read_config(fd, &p->pc_sel, ptr +
320 			    PCIR_VENDOR_DATA + 5, 4);
321 			printf("\n\t\t features:");
322 			if (fvec & (1 << 0)) {
323 				printf(" AMT");
324 				comma = 1;
325 			}
326 			fvec = read_config(fd, &p->pc_sel, ptr +
327 			    PCIR_VENDOR_DATA + 1, 4);
328 			if (fvec & (1 << 21)) {
329 				printf("%s Quick Resume", comma ? "," : "");
330 				comma = 1;
331 			}
332 			if (fvec & (1 << 18)) {
333 				printf("%s SATA RAID-5", comma ? "," : "");
334 				comma = 1;
335 			}
336 			if (fvec & (1 << 9)) {
337 				printf("%s Mobile", comma ? "," : "");
338 				comma = 1;
339 			}
340 			if (fvec & (1 << 7)) {
341 				printf("%s 6 PCI-e x1 slots", comma ? "," : "");
342 				comma = 1;
343 			} else {
344 				printf("%s 4 PCI-e x1 slots", comma ? "," : "");
345 				comma = 1;
346 			}
347 			if (fvec & (1 << 5)) {
348 				printf("%s SATA RAID-0/1/10", comma ? "," : "");
349 				comma = 1;
350 			}
351 			if (fvec & (1 << 3))
352 				printf(", SATA AHCI");
353 		}
354 	}
355 }
356 
357 static void
358 cap_debug(int fd, struct pci_conf *p, uint8_t ptr)
359 {
360 	uint16_t debug_port;
361 
362 	debug_port = read_config(fd, &p->pc_sel, ptr + PCIR_DEBUG_PORT, 2);
363 	printf("EHCI Debug Port at offset 0x%x in map 0x%x", debug_port &
364 	    PCIM_DEBUG_PORT_OFFSET, PCIR_BAR(debug_port >> 13));
365 }
366 
367 static void
368 cap_subvendor(int fd, struct pci_conf *p, uint8_t ptr)
369 {
370 	uint32_t id;
371 	uint16_t ssid, ssvid;
372 
373 	id = read_config(fd, &p->pc_sel, ptr + PCIR_SUBVENDCAP_ID, 4);
374 	ssid = id >> 16;
375 	ssvid = id & 0xffff;
376 	printf("PCI Bridge subvendor=0x%04x subdevice=0x%04x", ssvid, ssid);
377 }
378 
379 #define	MAX_PAYLOAD(field)		(128 << (field))
380 
381 static const char *
382 link_speed_string(uint8_t speed)
383 {
384 
385 	switch (speed) {
386 	case 1:
387 		return ("2.5");
388 	case 2:
389 		return ("5.0");
390 	case 3:
391 		return ("8.0");
392 	case 4:
393 		return ("16.0");
394 	case 5:
395 		return ("32.0");
396 	case 6:
397 		return ("64.0");
398 	default:
399 		return ("undef");
400 	}
401 }
402 
403 static const char *
404 max_read_string(u_int max_read)
405 {
406 
407 	switch (max_read) {
408 	case 0x0:
409 		return ("128");
410 	case 0x1:
411 		return ("256");
412 	case 0x2:
413 		return ("512");
414 	case 0x3:
415 		return ("1024");
416 	case 0x4:
417 		return ("2048");
418 	case 0x5:
419 		return ("4096");
420 	default:
421 		return ("undef");
422 	}
423 }
424 
425 static const char *
426 aspm_string(uint8_t aspm)
427 {
428 
429 	switch (aspm) {
430 	case 1:
431 		return ("L0s");
432 	case 2:
433 		return ("L1");
434 	case 3:
435 		return ("L0s/L1");
436 	default:
437 		return ("disabled");
438 	}
439 }
440 
441 static int
442 slot_power(uint32_t cap)
443 {
444 	int mwatts;
445 
446 	mwatts = (cap & PCIEM_SLOT_CAP_SPLV) >> 7;
447 	switch (cap & PCIEM_SLOT_CAP_SPLS) {
448 	case 0x0:
449 		mwatts *= 1000;
450 		break;
451 	case 0x1:
452 		mwatts *= 100;
453 		break;
454 	case 0x2:
455 		mwatts *= 10;
456 		break;
457 	default:
458 		break;
459 	}
460 	return (mwatts);
461 }
462 
463 static void
464 cap_express(int fd, struct pci_conf *p, uint8_t ptr)
465 {
466 	uint32_t cap;
467 	uint16_t ctl, flags, sta;
468 	unsigned int version;
469 
470 	flags = read_config(fd, &p->pc_sel, ptr + PCIER_FLAGS, 2);
471 	version = flags & PCIEM_FLAGS_VERSION;
472 	printf("PCI-Express %u ", version);
473 	switch (flags & PCIEM_FLAGS_TYPE) {
474 	case PCIEM_TYPE_ENDPOINT:
475 		printf("endpoint");
476 		break;
477 	case PCIEM_TYPE_LEGACY_ENDPOINT:
478 		printf("legacy endpoint");
479 		break;
480 	case PCIEM_TYPE_ROOT_PORT:
481 		printf("root port");
482 		break;
483 	case PCIEM_TYPE_UPSTREAM_PORT:
484 		printf("upstream port");
485 		break;
486 	case PCIEM_TYPE_DOWNSTREAM_PORT:
487 		printf("downstream port");
488 		break;
489 	case PCIEM_TYPE_PCI_BRIDGE:
490 		printf("PCI bridge");
491 		break;
492 	case PCIEM_TYPE_PCIE_BRIDGE:
493 		printf("PCI to PCIe bridge");
494 		break;
495 	case PCIEM_TYPE_ROOT_INT_EP:
496 		printf("root endpoint");
497 		break;
498 	case PCIEM_TYPE_ROOT_EC:
499 		printf("event collector");
500 		break;
501 	default:
502 		printf("type %d", (flags & PCIEM_FLAGS_TYPE) >> 4);
503 		break;
504 	}
505 	if (flags & PCIEM_FLAGS_IRQ)
506 		printf(" MSI %d", (flags & PCIEM_FLAGS_IRQ) >> 9);
507 	cap = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CAP, 4);
508 	ctl = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CTL, 2);
509 	printf(" max data %d(%d)",
510 	    MAX_PAYLOAD((ctl & PCIEM_CTL_MAX_PAYLOAD) >> 5),
511 	    MAX_PAYLOAD(cap & PCIEM_CAP_MAX_PAYLOAD));
512 	if ((cap & PCIEM_CAP_FLR) != 0)
513 		printf(" FLR");
514 	if (ctl & PCIEM_CTL_RELAXED_ORD_ENABLE)
515 		printf(" RO");
516 	if (ctl & PCIEM_CTL_NOSNOOP_ENABLE)
517 		printf(" NS");
518 	if (version >= 2) {
519 		cap = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CAP2, 4);
520 		if ((cap & PCIEM_CAP2_ARI) != 0) {
521 			ctl = read_config(fd, &p->pc_sel,
522 			    ptr + PCIER_DEVICE_CTL2, 4);
523 			printf(" ARI %s",
524 			    (ctl & PCIEM_CTL2_ARI) ? "enabled" : "disabled");
525 		}
526 	}
527 	printf("\n                 max read %s", max_read_string((ctl &
528 	    PCIEM_CTL_MAX_READ_REQUEST) >> 12));
529 	cap = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_CAP, 4);
530 	sta = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_STA, 2);
531 	if (cap == 0 && sta == 0)
532 		return;
533 	printf("\n                ");
534 	printf(" link x%d(x%d)", (sta & PCIEM_LINK_STA_WIDTH) >> 4,
535 	    (cap & PCIEM_LINK_CAP_MAX_WIDTH) >> 4);
536 	if ((cap & PCIEM_LINK_CAP_MAX_WIDTH) != 0) {
537 		printf(" speed %s(%s)", (sta & PCIEM_LINK_STA_WIDTH) == 0 ?
538 		    "0.0" : link_speed_string(sta & PCIEM_LINK_STA_SPEED),
539 	    	    link_speed_string(cap & PCIEM_LINK_CAP_MAX_SPEED));
540 	}
541 	if ((cap & PCIEM_LINK_CAP_ASPM) != 0) {
542 		ctl = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_CTL, 2);
543 		printf(" ASPM %s(%s)", aspm_string(ctl & PCIEM_LINK_CTL_ASPMC),
544 		    aspm_string((cap & PCIEM_LINK_CAP_ASPM) >> 10));
545 	}
546 	if ((cap & PCIEM_LINK_CAP_CLOCK_PM) != 0) {
547 		ctl = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_CTL, 2);
548 		printf(" ClockPM %s", (ctl & PCIEM_LINK_CTL_ECPM) ?
549 		    "enabled" : "disabled");
550 	}
551 	if (!(flags & PCIEM_FLAGS_SLOT))
552 		return;
553 	cap = read_config(fd, &p->pc_sel, ptr + PCIER_SLOT_CAP, 4);
554 	sta = read_config(fd, &p->pc_sel, ptr + PCIER_SLOT_STA, 2);
555 	ctl = read_config(fd, &p->pc_sel, ptr + PCIER_SLOT_CTL, 2);
556 	printf("\n                ");
557 	printf(" slot %d", (cap & PCIEM_SLOT_CAP_PSN) >> 19);
558 	printf(" power limit %d mW", slot_power(cap));
559 	if (cap & PCIEM_SLOT_CAP_HPC)
560 		printf(" HotPlug(%s)", sta & PCIEM_SLOT_STA_PDS ? "present" :
561 		    "empty");
562 	if (cap & PCIEM_SLOT_CAP_HPS)
563 		printf(" surprise");
564 	if (cap & PCIEM_SLOT_CAP_APB)
565 		printf(" Attn Button");
566 	if (cap & PCIEM_SLOT_CAP_PCP)
567 		printf(" PC(%s)", ctl & PCIEM_SLOT_CTL_PCC ? "off" : "on");
568 	if (cap & PCIEM_SLOT_CAP_MRLSP)
569 		printf(" MRL(%s)", sta & PCIEM_SLOT_STA_MRLSS ? "open" :
570 		    "closed");
571 	if (cap & PCIEM_SLOT_CAP_EIP)
572 		printf(" EI(%s)", sta & PCIEM_SLOT_STA_EIS ? "engaged" :
573 		    "disengaged");
574 }
575 
576 static void
577 cap_msix(int fd, struct pci_conf *p, uint8_t ptr)
578 {
579 	uint32_t pba_offset, table_offset, val;
580 	int msgnum, pba_bar, table_bar;
581 	uint16_t ctrl;
582 
583 	ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_CTRL, 2);
584 	msgnum = (ctrl & PCIM_MSIXCTRL_TABLE_SIZE) + 1;
585 
586 	val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_TABLE, 4);
587 	table_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK);
588 	table_offset = val & ~PCIM_MSIX_BIR_MASK;
589 
590 	val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_PBA, 4);
591 	pba_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK);
592 	pba_offset = val & ~PCIM_MSIX_BIR_MASK;
593 
594 	printf("MSI-X supports %d message%s%s\n", msgnum,
595 	    (msgnum == 1) ? "" : "s",
596 	    (ctrl & PCIM_MSIXCTRL_MSIX_ENABLE) ? ", enabled" : "");
597 
598 	printf("                 ");
599 	printf("Table in map 0x%x[0x%x], PBA in map 0x%x[0x%x]",
600 	    table_bar, table_offset, pba_bar, pba_offset);
601 }
602 
603 static void
604 cap_sata(int fd __unused, struct pci_conf *p __unused, uint8_t ptr __unused)
605 {
606 
607 	printf("SATA Index-Data Pair");
608 }
609 
610 static void
611 cap_pciaf(int fd, struct pci_conf *p, uint8_t ptr)
612 {
613 	uint8_t cap;
614 
615 	cap = read_config(fd, &p->pc_sel, ptr + PCIR_PCIAF_CAP, 1);
616 	printf("PCI Advanced Features:%s%s",
617 	    cap & PCIM_PCIAFCAP_FLR ? " FLR" : "",
618 	    cap & PCIM_PCIAFCAP_TP  ? " TP"  : "");
619 }
620 
621 static const char *
622 ea_bei_to_name(int bei)
623 {
624 	static const char *barstr[] = {
625 		"BAR0", "BAR1", "BAR2", "BAR3", "BAR4", "BAR5"
626 	};
627 	static const char *vfbarstr[] = {
628 		"VFBAR0", "VFBAR1", "VFBAR2", "VFBAR3", "VFBAR4", "VFBAR5"
629 	};
630 
631 	if ((bei >= PCIM_EA_BEI_BAR_0) && (bei <= PCIM_EA_BEI_BAR_5))
632 		return (barstr[bei - PCIM_EA_BEI_BAR_0]);
633 	if ((bei >= PCIM_EA_BEI_VF_BAR_0) && (bei <= PCIM_EA_BEI_VF_BAR_5))
634 		return (vfbarstr[bei - PCIM_EA_BEI_VF_BAR_0]);
635 
636 	switch (bei) {
637 	case PCIM_EA_BEI_BRIDGE:
638 		return "BRIDGE";
639 	case PCIM_EA_BEI_ENI:
640 		return "ENI";
641 	case PCIM_EA_BEI_ROM:
642 		return "ROM";
643 	case PCIM_EA_BEI_RESERVED:
644 	default:
645 		return "RSVD";
646 	}
647 }
648 
649 static const char *
650 ea_prop_to_name(uint8_t prop)
651 {
652 
653 	switch (prop) {
654 	case PCIM_EA_P_MEM:
655 		return "Non-Prefetchable Memory";
656 	case PCIM_EA_P_MEM_PREFETCH:
657 		return "Prefetchable Memory";
658 	case PCIM_EA_P_IO:
659 		return "I/O Space";
660 	case PCIM_EA_P_VF_MEM_PREFETCH:
661 		return "VF Prefetchable Memory";
662 	case PCIM_EA_P_VF_MEM:
663 		return "VF Non-Prefetchable Memory";
664 	case PCIM_EA_P_BRIDGE_MEM:
665 		return "Bridge Non-Prefetchable Memory";
666 	case PCIM_EA_P_BRIDGE_MEM_PREFETCH:
667 		return "Bridge Prefetchable Memory";
668 	case PCIM_EA_P_BRIDGE_IO:
669 		return "Bridge I/O Space";
670 	case PCIM_EA_P_MEM_RESERVED:
671 		return "Reserved Memory";
672 	case PCIM_EA_P_IO_RESERVED:
673 		return "Reserved I/O Space";
674 	case PCIM_EA_P_UNAVAILABLE:
675 		return "Unavailable";
676 	default:
677 		return "Reserved";
678 	}
679 }
680 
681 static void
682 cap_ea(int fd, struct pci_conf *p, uint8_t ptr)
683 {
684 	int num_ent;
685 	int a, b;
686 	uint32_t bei;
687 	uint32_t val;
688 	int ent_size;
689 	uint32_t dw[4];
690 	uint32_t flags, flags_pp, flags_sp;
691 	uint64_t base, max_offset;
692 	uint8_t fixed_sub_bus_nr, fixed_sec_bus_nr;
693 
694 	/* Determine the number of entries */
695 	num_ent = read_config(fd, &p->pc_sel, ptr + PCIR_EA_NUM_ENT, 2);
696 	num_ent &= PCIM_EA_NUM_ENT_MASK;
697 
698 	printf("PCI Enhanced Allocation (%d entries)", num_ent);
699 
700 	/* Find the first entry to care of */
701 	ptr += PCIR_EA_FIRST_ENT;
702 
703 	/* Print BUS numbers for bridges */
704 	if ((p->pc_hdr & PCIM_HDRTYPE) == PCIM_HDRTYPE_BRIDGE) {
705 		val = read_config(fd, &p->pc_sel, ptr, 4);
706 
707 		fixed_sec_bus_nr = PCIM_EA_SEC_NR(val);
708 		fixed_sub_bus_nr = PCIM_EA_SUB_NR(val);
709 
710 		printf("\n\t\t BRIDGE, sec bus [%d], sub bus [%d]",
711 		    fixed_sec_bus_nr, fixed_sub_bus_nr);
712 		ptr += 4;
713 	}
714 
715 	for (a = 0; a < num_ent; a++) {
716 		/* Read a number of dwords in the entry */
717 		val = read_config(fd, &p->pc_sel, ptr, 4);
718 		ptr += 4;
719 		ent_size = (val & PCIM_EA_ES);
720 
721 		for (b = 0; b < ent_size; b++) {
722 			dw[b] = read_config(fd, &p->pc_sel, ptr, 4);
723 			ptr += 4;
724 		}
725 
726 		flags = val;
727 		flags_pp = (flags & PCIM_EA_PP) >> PCIM_EA_PP_OFFSET;
728 		flags_sp = (flags & PCIM_EA_SP) >> PCIM_EA_SP_OFFSET;
729 		bei = (PCIM_EA_BEI & val) >> PCIM_EA_BEI_OFFSET;
730 
731 		base = dw[0] & PCIM_EA_FIELD_MASK;
732 		max_offset = dw[1] | ~PCIM_EA_FIELD_MASK;
733 		b = 2;
734 		if (((dw[0] & PCIM_EA_IS_64) != 0) && (b < ent_size)) {
735 			base |= (uint64_t)dw[b] << 32UL;
736 			b++;
737 		}
738 		if (((dw[1] & PCIM_EA_IS_64) != 0)
739 			&& (b < ent_size)) {
740 			max_offset |= (uint64_t)dw[b] << 32UL;
741 			b++;
742 		}
743 
744 		printf("\n\t\t [%d] %s, %s, %s, base [0x%jx], size [0x%jx]"
745 		    "\n\t\t\tPrimary properties [0x%x] (%s)"
746 		    "\n\t\t\tSecondary properties [0x%x] (%s)",
747 		    bei, ea_bei_to_name(bei),
748 		    (flags & PCIM_EA_ENABLE ? "Enabled" : "Disabled"),
749 		    (flags & PCIM_EA_WRITABLE ? "Writable" : "Read-only"),
750 		    (uintmax_t)base, (uintmax_t)(max_offset + 1),
751 		    flags_pp, ea_prop_to_name(flags_pp),
752 		    flags_sp, ea_prop_to_name(flags_sp));
753 	}
754 }
755 
756 void
757 list_caps(int fd, struct pci_conf *p, int level)
758 {
759 	int express;
760 	uint16_t sta;
761 	uint8_t ptr, cap;
762 
763 	/* Are capabilities present for this device? */
764 	sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2);
765 	if (!(sta & PCIM_STATUS_CAPPRESENT))
766 		return;
767 
768 	cap_level = level;
769 
770 	switch (p->pc_hdr & PCIM_HDRTYPE) {
771 	case PCIM_HDRTYPE_NORMAL:
772 	case PCIM_HDRTYPE_BRIDGE:
773 		ptr = PCIR_CAP_PTR;
774 		break;
775 	case PCIM_HDRTYPE_CARDBUS:
776 		ptr = PCIR_CAP_PTR_2;
777 		break;
778 	default:
779 		errx(1, "list_caps: bad header type");
780 	}
781 
782 	/* Walk the capability list. */
783 	express = 0;
784 	ptr = read_config(fd, &p->pc_sel, ptr, 1);
785 	while (ptr != 0 && ptr != 0xff) {
786 		cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1);
787 		printf("    cap %02x[%02x] = ", cap, ptr);
788 		switch (cap) {
789 		case PCIY_PMG:
790 			cap_power(fd, p, ptr);
791 			break;
792 		case PCIY_AGP:
793 			cap_agp(fd, p, ptr);
794 			break;
795 		case PCIY_VPD:
796 			cap_vpd(fd, p, ptr);
797 			break;
798 		case PCIY_MSI:
799 			cap_msi(fd, p, ptr);
800 			break;
801 		case PCIY_PCIX:
802 			cap_pcix(fd, p, ptr);
803 			break;
804 		case PCIY_HT:
805 			cap_ht(fd, p, ptr);
806 			break;
807 		case PCIY_VENDOR:
808 			cap_vendor(fd, p, ptr);
809 			break;
810 		case PCIY_DEBUG:
811 			cap_debug(fd, p, ptr);
812 			break;
813 		case PCIY_SUBVENDOR:
814 			cap_subvendor(fd, p, ptr);
815 			break;
816 		case PCIY_EXPRESS:
817 			express = 1;
818 			cap_express(fd, p, ptr);
819 			break;
820 		case PCIY_MSIX:
821 			cap_msix(fd, p, ptr);
822 			break;
823 		case PCIY_SATA:
824 			cap_sata(fd, p, ptr);
825 			break;
826 		case PCIY_PCIAF:
827 			cap_pciaf(fd, p, ptr);
828 			break;
829 		case PCIY_EA:
830 			cap_ea(fd, p, ptr);
831 			break;
832 		default:
833 			printf("unknown");
834 			break;
835 		}
836 		printf("\n");
837 		ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1);
838 	}
839 
840 	if (express)
841 		list_ecaps(fd, p);
842 }
843 
844 /* From <sys/systm.h>. */
845 static __inline uint32_t
846 bitcount32(uint32_t x)
847 {
848 
849 	x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1);
850 	x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2);
851 	x = (x + (x >> 4)) & 0x0f0f0f0f;
852 	x = (x + (x >> 8));
853 	x = (x + (x >> 16)) & 0x000000ff;
854 	return (x);
855 }
856 
857 static void
858 ecap_aer(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
859 {
860 	uint32_t sta, mask;
861 
862 	printf("AER %d", ver);
863 	if (ver < 1) {
864 		printf("\n");
865 		return;
866 	}
867 	sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_STATUS, 4);
868 	mask = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_SEVERITY, 4);
869 	printf(" %d fatal", bitcount32(sta & mask));
870 	printf(" %d non-fatal", bitcount32(sta & ~mask));
871 	sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_COR_STATUS, 4);
872 	printf(" %d corrected\n", bitcount32(sta));
873 }
874 
875 static void
876 ecap_vc(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
877 {
878 	uint32_t cap1;
879 
880 	printf("VC %d", ver);
881 	if (ver < 1) {
882 		printf("\n");
883 		return;
884 	}
885 	cap1 = read_config(fd, &p->pc_sel, ptr + PCIR_VC_CAP1, 4);
886 	printf(" max VC%d", cap1 & PCIM_VC_CAP1_EXT_COUNT);
887 	if ((cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) != 0)
888 		printf(" lowpri VC0-VC%d",
889 		    (cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) >> 4);
890 	printf("\n");
891 }
892 
893 static void
894 ecap_sernum(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
895 {
896 	uint32_t high, low;
897 
898 	printf("Serial %d", ver);
899 	if (ver < 1) {
900 		printf("\n");
901 		return;
902 	}
903 	low = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_LOW, 4);
904 	high = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_HIGH, 4);
905 	printf(" %08x%08x\n", high, low);
906 }
907 
908 static void
909 ecap_vendor(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
910 {
911 	uint32_t val, hdr;
912 	uint16_t nextptr, len;
913 	int i;
914 
915 	val = read_config(fd, &p->pc_sel, ptr, 4);
916 	nextptr = PCI_EXTCAP_NEXTPTR(val);
917 	hdr = read_config(fd, &p->pc_sel, ptr + PCIR_VSEC_HEADER, 4);
918 	len = PCIR_VSEC_LENGTH(hdr);
919 	if (len == 0) {
920 		if (nextptr == 0)
921 			nextptr = 0x1000;
922 		len = nextptr - ptr;
923 	}
924 
925 	printf("Vendor [%d] ID %04x Rev %d Length %d\n", ver,
926 	    PCIR_VSEC_ID(hdr), PCIR_VSEC_REV(hdr), len);
927 	if ((ver < 1) || (cap_level <= 1))
928 		return;
929 	for (i = 0; i < len; i += 4) {
930 		val = read_config(fd, &p->pc_sel, ptr + i, 4);
931 		if ((i % 16) == 0)
932 			printf("                 ");
933 		printf("%02x %02x %02x %02x", val & 0xff, (val >> 8) & 0xff,
934 		    (val >> 16) & 0xff, (val >> 24) & 0xff);
935 		if ((((i + 4) % 16) == 0 ) || ((i + 4) >= len))
936 			printf("\n");
937 		else
938 			printf(" ");
939 	}
940 }
941 
942 static void
943 ecap_sec_pcie(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
944 {
945 	uint32_t val;
946 
947 	printf("PCIe Sec %d", ver);
948 	if (ver < 1) {
949 		printf("\n");
950 		return;
951 	}
952 	val = read_config(fd, &p->pc_sel, ptr + 8, 4);
953 	printf(" lane errors %#x\n", val);
954 }
955 
956 static const char *
957 check_enabled(int value)
958 {
959 
960 	return (value ? "enabled" : "disabled");
961 }
962 
963 static void
964 ecap_sriov(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
965 {
966 	const char *comma, *enabled;
967 	uint16_t iov_ctl, total_vfs, num_vfs, vf_offset, vf_stride, vf_did;
968 	uint32_t page_caps, page_size, page_shift, size;
969 	int i;
970 
971 	printf("SR-IOV %d ", ver);
972 
973 	iov_ctl = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_CTL, 2);
974 	printf("IOV %s, Memory Space %s, ARI %s\n",
975 	    check_enabled(iov_ctl & PCIM_SRIOV_VF_EN),
976 	    check_enabled(iov_ctl & PCIM_SRIOV_VF_MSE),
977 	    check_enabled(iov_ctl & PCIM_SRIOV_ARI_EN));
978 
979 	total_vfs = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_TOTAL_VFS, 2);
980 	num_vfs = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_NUM_VFS, 2);
981 	printf("                     ");
982 	printf("%d VFs configured out of %d supported\n", num_vfs, total_vfs);
983 
984 	vf_offset = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_VF_OFF, 2);
985 	vf_stride = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_VF_STRIDE, 2);
986 	printf("                     ");
987 	printf("First VF RID Offset 0x%04x, VF RID Stride 0x%04x\n", vf_offset,
988 	    vf_stride);
989 
990 	vf_did = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_VF_DID, 2);
991 	printf("                     VF Device ID 0x%04x\n", vf_did);
992 
993 	page_caps = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_PAGE_CAP, 4);
994 	page_size = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_PAGE_SIZE, 4);
995 	printf("                     ");
996 	printf("Page Sizes: ");
997 	comma = "";
998 	while (page_caps != 0) {
999 		page_shift = ffs(page_caps) - 1;
1000 
1001 		if (page_caps & page_size)
1002 			enabled = " (enabled)";
1003 		else
1004 			enabled = "";
1005 
1006 		size = (1 << (page_shift + PCI_SRIOV_BASE_PAGE_SHIFT));
1007 		printf("%s%d%s", comma, size, enabled);
1008 		comma = ", ";
1009 
1010 		page_caps &= ~(1 << page_shift);
1011 	}
1012 	printf("\n");
1013 
1014 	for (i = 0; i <= PCIR_MAX_BAR_0; i++)
1015 		print_bar(fd, p, "iov bar  ", ptr + PCIR_SRIOV_BAR(i));
1016 }
1017 
1018 static const char *
1019 check_avail_and_state(u_int cap, u_int capbit, u_int ctl, u_int ctlbit)
1020 {
1021 
1022 	if (cap & capbit)
1023 		return (ctl & ctlbit ? "enabled" : "disabled");
1024 	else
1025 		return "unavailable";
1026 }
1027 
1028 static void
1029 ecap_acs(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
1030 {
1031 	uint16_t acs_cap, acs_ctl;
1032 	static const char *const acc[] = { "access enabled", "blocking enabled",
1033 		"redirect enabled", "reserved" };
1034 
1035 	printf("ACS %d ", ver);
1036 	if (ver != 1) {
1037 		printf("\n");
1038 		return;
1039 	}
1040 
1041 #define	CHECK_AVAIL_STATE(bit) \
1042 	check_avail_and_state(acs_cap, bit, acs_ctl, bit##_ENABLE)
1043 
1044 	acs_cap = read_config(fd, &p->pc_sel, ptr + PCIR_ACS_CAP, 2);
1045 	acs_ctl = read_config(fd, &p->pc_sel, ptr + PCIR_ACS_CTL, 2);
1046 	printf("Source Validation %s, Translation Blocking %s\n",
1047 	    CHECK_AVAIL_STATE(PCIM_ACS_SOURCE_VALIDATION),
1048 	    CHECK_AVAIL_STATE(PCIM_ACS_TRANSLATION_BLOCKING));
1049 
1050 	printf("                     ");
1051 	printf("P2P Req Redirect %s, P2P Cmpl Redirect %s\n",
1052 	    CHECK_AVAIL_STATE(PCIM_ACS_P2P_REQ_REDIRECT),
1053 	    CHECK_AVAIL_STATE(PCIM_ACS_P2P_CMP_REDIRECT));
1054 	printf("                     ");
1055 	printf("P2P Upstream Forwarding %s, P2P Egress Control %s\n",
1056 	    CHECK_AVAIL_STATE(PCIM_ACS_P2P_UPSTREAM_FORWARDING),
1057 	    CHECK_AVAIL_STATE(PCIM_ACS_P2P_EGRESS_CTL));
1058 	printf("                     ");
1059 	printf("P2P Direct Translated %s, Enhanced Capability %s\n",
1060 	    CHECK_AVAIL_STATE(PCIM_ACS_P2P_DIRECT_TRANSLATED),
1061 	    acs_ctl & PCIM_ACS_ENHANCED_CAP ? "available" : "unavailable");
1062 #undef	CHECK_AVAIL_STATE
1063 
1064 	if (acs_cap & PCIM_ACS_ENHANCED_CAP) {
1065 		printf("                     ");
1066 		printf("I/O Req Blocking %s, Unclaimed Req Redirect Control %s\n",
1067 		    check_enabled(acs_ctl & PCIM_ACS_IO_REQ_BLOCKING_ENABLE),
1068 		    check_enabled(acs_ctl & PCIM_ACS_UNCLAIMED_REQ_REDIRECT_CTL));
1069 		printf("                     ");
1070 		printf("DSP BAR %s, USP BAR %s\n",
1071 		    acc[(acs_cap & PCIM_ACS_DSP_MEM_TGT_ACC_CTL) >> 8],
1072 		    acc[(acs_cap & PCIM_ACS_USP_MEM_TGT_ACC_CTL) >> 10]);
1073 	}
1074 }
1075 
1076 static struct {
1077 	uint16_t id;
1078 	const char *name;
1079 } ecap_names[] = {
1080 	{ PCIZ_AER, "AER" },
1081 	{ PCIZ_VC, "Virtual Channel" },
1082 	{ PCIZ_SERNUM, "Device Serial Number" },
1083 	{ PCIZ_PWRBDGT, "Power Budgeting" },
1084 	{ PCIZ_RCLINK_DCL, "Root Complex Link Declaration" },
1085 	{ PCIZ_RCLINK_CTL, "Root Complex Internal Link Control" },
1086 	{ PCIZ_RCEC_ASSOC, "Root Complex Event Collector ASsociation" },
1087 	{ PCIZ_MFVC, "MFVC" },
1088 	{ PCIZ_VC2, "Virtual Channel 2" },
1089 	{ PCIZ_RCRB, "RCRB" },
1090 	{ PCIZ_CAC, "Configuration Access Correction" },
1091 	{ PCIZ_ACS, "ACS" },
1092 	{ PCIZ_ARI, "ARI" },
1093 	{ PCIZ_ATS, "ATS" },
1094 	{ PCIZ_SRIOV, "SRIOV" },
1095 	{ PCIZ_MRIOV, "MRIOV" },
1096 	{ PCIZ_MULTICAST, "Multicast" },
1097 	{ PCIZ_PAGE_REQ, "Page Page Request" },
1098 	{ PCIZ_AMD, "AMD proprietary "},
1099 	{ PCIZ_RESIZE_BAR, "Resizable BAR" },
1100 	{ PCIZ_DPA, "DPA" },
1101 	{ PCIZ_TPH_REQ, "TPH Requester" },
1102 	{ PCIZ_LTR, "LTR" },
1103 	{ PCIZ_SEC_PCIE, "Secondary PCI Express" },
1104 	{ PCIZ_PMUX, "Protocol Multiplexing" },
1105 	{ PCIZ_PASID, "Process Address Space ID" },
1106 	{ PCIZ_LN_REQ, "LN Requester" },
1107 	{ PCIZ_DPC, "Downstream Port Containment" },
1108 	{ PCIZ_L1PM, "L1 PM Substates" },
1109 	{ PCIZ_PTM, "Precision Time Measurement" },
1110 	{ PCIZ_M_PCIE, "PCIe over M-PHY" },
1111 	{ PCIZ_FRS, "FRS Queuing" },
1112 	{ PCIZ_RTR, "Readiness Time Reporting" },
1113 	{ PCIZ_DVSEC, "Designated Vendor-Specific" },
1114 	{ PCIZ_VF_REBAR, "VF Resizable BAR" },
1115 	{ PCIZ_DLNK, "Data Link Feature" },
1116 	{ PCIZ_16GT, "Physical Layer 16.0 GT/s" },
1117 	{ PCIZ_LMR, "Lane Margining at Receiver" },
1118 	{ PCIZ_HIER_ID, "Hierarchy ID" },
1119 	{ PCIZ_NPEM, "Native PCIe Enclosure Management" },
1120 	{ PCIZ_PL32, "Physical Layer 32.0 GT/s" },
1121 	{ PCIZ_AP, "Alternate Protocol" },
1122 	{ PCIZ_SFI, "System Firmware Intermediary" },
1123 	{ 0, NULL }
1124 };
1125 
1126 static void
1127 list_ecaps(int fd, struct pci_conf *p)
1128 {
1129 	const char *name;
1130 	uint32_t ecap;
1131 	uint16_t ptr;
1132 	int i;
1133 
1134 	ptr = PCIR_EXTCAP;
1135 	ecap = read_config(fd, &p->pc_sel, ptr, 4);
1136 	if (ecap == 0xffffffff || ecap == 0)
1137 		return;
1138 	for (;;) {
1139 		printf("    ecap %04x[%03x] = ", PCI_EXTCAP_ID(ecap), ptr);
1140 		switch (PCI_EXTCAP_ID(ecap)) {
1141 		case PCIZ_AER:
1142 			ecap_aer(fd, p, ptr, PCI_EXTCAP_VER(ecap));
1143 			break;
1144 		case PCIZ_VC:
1145 			ecap_vc(fd, p, ptr, PCI_EXTCAP_VER(ecap));
1146 			break;
1147 		case PCIZ_SERNUM:
1148 			ecap_sernum(fd, p, ptr, PCI_EXTCAP_VER(ecap));
1149 			break;
1150 		case PCIZ_VENDOR:
1151 			ecap_vendor(fd, p, ptr, PCI_EXTCAP_VER(ecap));
1152 			break;
1153 		case PCIZ_SEC_PCIE:
1154 			ecap_sec_pcie(fd, p, ptr, PCI_EXTCAP_VER(ecap));
1155 			break;
1156 		case PCIZ_SRIOV:
1157 			ecap_sriov(fd, p, ptr, PCI_EXTCAP_VER(ecap));
1158 			break;
1159 		case PCIZ_ACS:
1160 			ecap_acs(fd, p, ptr, PCI_EXTCAP_VER(ecap));
1161 			break;
1162 		default:
1163 			name = "unknown";
1164 			for (i = 0; ecap_names[i].name != NULL; i++)
1165 				if (ecap_names[i].id == PCI_EXTCAP_ID(ecap)) {
1166 					name = ecap_names[i].name;
1167 					break;
1168 				}
1169 			printf("%s %d\n", name, PCI_EXTCAP_VER(ecap));
1170 			break;
1171 		}
1172 		ptr = PCI_EXTCAP_NEXTPTR(ecap);
1173 		if (ptr == 0)
1174 			break;
1175 		ecap = read_config(fd, &p->pc_sel, ptr, 4);
1176 	}
1177 }
1178 
1179 /* Find offset of a specific capability.  Returns 0 on failure. */
1180 uint8_t
1181 pci_find_cap(int fd, struct pci_conf *p, uint8_t id)
1182 {
1183 	uint16_t sta;
1184 	uint8_t ptr, cap;
1185 
1186 	/* Are capabilities present for this device? */
1187 	sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2);
1188 	if (!(sta & PCIM_STATUS_CAPPRESENT))
1189 		return (0);
1190 
1191 	switch (p->pc_hdr & PCIM_HDRTYPE) {
1192 	case PCIM_HDRTYPE_NORMAL:
1193 	case PCIM_HDRTYPE_BRIDGE:
1194 		ptr = PCIR_CAP_PTR;
1195 		break;
1196 	case PCIM_HDRTYPE_CARDBUS:
1197 		ptr = PCIR_CAP_PTR_2;
1198 		break;
1199 	default:
1200 		return (0);
1201 	}
1202 
1203 	ptr = read_config(fd, &p->pc_sel, ptr, 1);
1204 	while (ptr != 0 && ptr != 0xff) {
1205 		cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1);
1206 		if (cap == id)
1207 			return (ptr);
1208 		ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1);
1209 	}
1210 	return (0);
1211 }
1212 
1213 /* Find offset of a specific extended capability.  Returns 0 on failure. */
1214 uint16_t
1215 pcie_find_cap(int fd, struct pci_conf *p, uint16_t id)
1216 {
1217 	uint32_t ecap;
1218 	uint16_t ptr;
1219 
1220 	ptr = PCIR_EXTCAP;
1221 	ecap = read_config(fd, &p->pc_sel, ptr, 4);
1222 	if (ecap == 0xffffffff || ecap == 0)
1223 		return (0);
1224 	for (;;) {
1225 		if (PCI_EXTCAP_ID(ecap) == id)
1226 			return (ptr);
1227 		ptr = PCI_EXTCAP_NEXTPTR(ecap);
1228 		if (ptr == 0)
1229 			break;
1230 		ecap = read_config(fd, &p->pc_sel, ptr, 4);
1231 	}
1232 	return (0);
1233 }
1234