xref: /freebsd/usr.sbin/pciconf/cap.c (revision 1e6db7be)
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
cap_power(int fd,struct pci_conf * p,uint8_t ptr)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
cap_agp(int fd,struct pci_conf * p,uint8_t ptr)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
cap_vpd(int fd __unused,struct pci_conf * p __unused,uint8_t ptr __unused)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
cap_msi(int fd,struct pci_conf * p,uint8_t ptr)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
cap_pcix(int fd,struct pci_conf * p,uint8_t ptr)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
cap_ht(int fd,struct pci_conf * p,uint8_t ptr)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
cap_vendor(int fd,struct pci_conf * p,uint8_t ptr)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
cap_debug(int fd,struct pci_conf * p,uint8_t ptr)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
cap_subvendor(int fd,struct pci_conf * p,uint8_t ptr)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 static const char *
cap_secdev_amdiommu_decode_vasize(uint32_t misc0)380 cap_secdev_amdiommu_decode_vasize(uint32_t misc0)
381 {
382 	switch (misc0 & PCIM_AMDIOMMU_MISC0_VASIZE_MASK) {
383 	case PCIM_AMDIOMMU_MISC0_VASIZE_32:
384 		return ("32bit");
385 	case PCIM_AMDIOMMU_MISC0_VASIZE_40:
386 		return ("40bit");
387 	case PCIM_AMDIOMMU_MISC0_VASIZE_48:
388 		return ("48bit");
389 	case PCIM_AMDIOMMU_MISC0_VASIZE_64:
390 		return ("64bit");
391 	default:
392 		return ("unknown");
393 	}
394 }
395 
396 static const char *
cap_secdev_amdiommu_decode_pasize(uint32_t misc0)397 cap_secdev_amdiommu_decode_pasize(uint32_t misc0)
398 {
399 	switch (misc0 & PCIM_AMDIOMMU_MISC0_PASIZE_MASK) {
400 	case PCIM_AMDIOMMU_MISC0_PASIZE_40:
401 		return ("40bit");
402 	case PCIM_AMDIOMMU_MISC0_PASIZE_48:
403 		return ("48bit");
404 	case PCIM_AMDIOMMU_MISC0_PASIZE_52:
405 		return ("52bit");
406 	default:
407 		return ("unknown");
408 	}
409 }
410 
411 static const char *
cap_secdev_amdiommu_decode_gvasize(uint32_t misc0)412 cap_secdev_amdiommu_decode_gvasize(uint32_t misc0)
413 {
414 	switch (misc0 & PCIM_AMDIOMMU_MISC0_GVASIZE_MASK) {
415 	case PCIM_AMDIOMMU_MISC0_GVASIZE_48:
416 		return ("48bit");
417 	case PCIM_AMDIOMMU_MISC0_GVASIZE_57:
418 		return ("57bit");
419 	default:
420 		return ("unknown");
421 	}
422 }
423 
424 static void
cap_secdev(int fd,struct pci_conf * p,uint8_t ptr)425 cap_secdev(int fd, struct pci_conf *p, uint8_t ptr)
426 {
427 	uint32_t cap_h;
428 	uint32_t cap_type, cap_rev;
429 	uint32_t base_low, base_high;
430 	uint32_t range;
431 	uint32_t misc0, misc1;
432 	const char *delim;
433 
434 	cap_h = read_config(fd, &p->pc_sel, ptr + PCIR_AMDIOMMU_CAP_HEADER, 4);
435 	cap_type = cap_h & PCIM_AMDIOMMU_CAP_TYPE_MASK;
436 	cap_rev = cap_h & PCIM_AMDIOMMU_CAP_REV_MASK;
437 	if (cap_type != PCIM_AMDIOMMU_CAP_TYPE_VAL ||
438 	    cap_rev != PCIM_AMDIOMMU_CAP_REV_VAL) {
439 		printf("Secure Device Type=0x%1x Rev=0x%02x\n",
440 		    cap_type >> 16, cap_rev >> 19);
441 		return;
442 	}
443 	base_low = read_config(fd, &p->pc_sel, ptr + PCIR_AMDIOMMU_BASE_LOW,
444 	    4);
445 	base_high = read_config(fd, &p->pc_sel, ptr + PCIR_AMDIOMMU_BASE_HIGH,
446 	    4);
447 	printf("AMD IOMMU Base Capability Base=%#018jx/%sabled",
448 	    (uintmax_t)(base_low & PCIM_AMDIOMMU_BASE_LOW_ADDRM) +
449 	    ((uintmax_t)base_high << 32),
450 	    (base_low & PCIM_AMDIOMMU_BASE_LOW_EN) != 0 ? "En" : "Dis");
451 
452 	delim = "\n\t\t";
453 #define	PRINTCAP(bit, name)				\
454 	if ((cap_h & PCIM_AMDIOMMU_CAP_ ##bit) != 0) {	\
455 		printf("%s%s", delim, #name);		\
456 		delim = ",";				\
457 	}
458 	PRINTCAP(CAPEXT, CapExt);
459 	PRINTCAP(EFR, EFRSup);
460 	PRINTCAP(NPCACHE, NpCache);
461 	PRINTCAP(HTTUN, HtTunnel);
462 	PRINTCAP(IOTLB, IotlbSup);
463 #undef PRINTCAP
464 
465 	range = read_config(fd, &p->pc_sel, ptr + PCIR_AMDIOMMU_RANGE, 4);
466 	printf("\n\t\tUnitId=%d", range & PCIM_AMDIOMMU_RANGE_UNITID_MASK);
467 	if ((range & PCIM_AMDIOMMU_RANGE_RNGVALID) != 0) {
468 		printf(" BusNum=%#06x FirstDev=%#06x LastDev=%#06x",
469 		    (range & PCIM_AMDIOMMU_RANGE_BUSNUM_MASK) >> 8,
470 		    (range & PCIM_AMDIOMMU_RANGE_FIRSTDEV_MASK) >> 16,
471 		    (range & PCIM_AMDIOMMU_RANGE_LASTDEV_MASK) >> 24);
472 	}
473 
474 	misc0 = read_config(fd, &p->pc_sel, ptr + PCIR_AMDIOMMU_MISC0, 4);
475 	printf("\n\t\tMsiNum=%d MsiNumPPR=%d HtAtsResv=%d",
476 	    misc0 & PCIM_AMDIOMMU_MISC0_MSINUM_MASK,
477 	    (misc0 & PCIM_AMDIOMMU_MISC0_MSINUMPPR_MASK) >> 27,
478 	    (misc0 & PCIM_AMDIOMMU_MISC0_HTATSRESV) != 0);
479 	if ((cap_h & PCIM_AMDIOMMU_CAP_CAPEXT) != 0) {
480 		misc1 = read_config(fd, &p->pc_sel,
481 		    ptr + PCIR_AMDIOMMU_MISC1, 4);
482 		printf(" MsiNumGA=%d",
483 		    misc1 & PCIM_AMDIOMMU_MISC1_MSINUMGA_MASK);
484 	}
485 	printf("\n\t\tVAsize=%s PAsize=%s GVAsize=%s",
486 	    cap_secdev_amdiommu_decode_vasize(misc0),
487 	    cap_secdev_amdiommu_decode_pasize(misc0),
488 	    cap_secdev_amdiommu_decode_gvasize(misc0));
489 }
490 
491 #define	MAX_PAYLOAD(field)		(128 << (field))
492 
493 static const char *
link_speed_string(uint8_t speed)494 link_speed_string(uint8_t speed)
495 {
496 
497 	switch (speed) {
498 	case 1:
499 		return ("2.5");
500 	case 2:
501 		return ("5.0");
502 	case 3:
503 		return ("8.0");
504 	case 4:
505 		return ("16.0");
506 	case 5:
507 		return ("32.0");
508 	case 6:
509 		return ("64.0");
510 	default:
511 		return ("undef");
512 	}
513 }
514 
515 static const char *
max_read_string(u_int max_read)516 max_read_string(u_int max_read)
517 {
518 
519 	switch (max_read) {
520 	case 0x0:
521 		return ("128");
522 	case 0x1:
523 		return ("256");
524 	case 0x2:
525 		return ("512");
526 	case 0x3:
527 		return ("1024");
528 	case 0x4:
529 		return ("2048");
530 	case 0x5:
531 		return ("4096");
532 	default:
533 		return ("undef");
534 	}
535 }
536 
537 static const char *
aspm_string(uint8_t aspm)538 aspm_string(uint8_t aspm)
539 {
540 
541 	switch (aspm) {
542 	case 1:
543 		return ("L0s");
544 	case 2:
545 		return ("L1");
546 	case 3:
547 		return ("L0s/L1");
548 	default:
549 		return ("disabled");
550 	}
551 }
552 
553 static int
slot_power(uint32_t cap)554 slot_power(uint32_t cap)
555 {
556 	int mwatts;
557 
558 	mwatts = (cap & PCIEM_SLOT_CAP_SPLV) >> 7;
559 	switch (cap & PCIEM_SLOT_CAP_SPLS) {
560 	case 0x0:
561 		mwatts *= 1000;
562 		break;
563 	case 0x1:
564 		mwatts *= 100;
565 		break;
566 	case 0x2:
567 		mwatts *= 10;
568 		break;
569 	default:
570 		break;
571 	}
572 	return (mwatts);
573 }
574 
575 static void
cap_express(int fd,struct pci_conf * p,uint8_t ptr)576 cap_express(int fd, struct pci_conf *p, uint8_t ptr)
577 {
578 	uint32_t cap;
579 	uint16_t ctl, flags, sta;
580 	unsigned int version;
581 
582 	flags = read_config(fd, &p->pc_sel, ptr + PCIER_FLAGS, 2);
583 	version = flags & PCIEM_FLAGS_VERSION;
584 	printf("PCI-Express %u ", version);
585 	switch (flags & PCIEM_FLAGS_TYPE) {
586 	case PCIEM_TYPE_ENDPOINT:
587 		printf("endpoint");
588 		break;
589 	case PCIEM_TYPE_LEGACY_ENDPOINT:
590 		printf("legacy endpoint");
591 		break;
592 	case PCIEM_TYPE_ROOT_PORT:
593 		printf("root port");
594 		break;
595 	case PCIEM_TYPE_UPSTREAM_PORT:
596 		printf("upstream port");
597 		break;
598 	case PCIEM_TYPE_DOWNSTREAM_PORT:
599 		printf("downstream port");
600 		break;
601 	case PCIEM_TYPE_PCI_BRIDGE:
602 		printf("PCI bridge");
603 		break;
604 	case PCIEM_TYPE_PCIE_BRIDGE:
605 		printf("PCI to PCIe bridge");
606 		break;
607 	case PCIEM_TYPE_ROOT_INT_EP:
608 		printf("root endpoint");
609 		break;
610 	case PCIEM_TYPE_ROOT_EC:
611 		printf("event collector");
612 		break;
613 	default:
614 		printf("type %d", (flags & PCIEM_FLAGS_TYPE) >> 4);
615 		break;
616 	}
617 	if (flags & PCIEM_FLAGS_IRQ)
618 		printf(" MSI %d", (flags & PCIEM_FLAGS_IRQ) >> 9);
619 	cap = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CAP, 4);
620 	ctl = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CTL, 2);
621 	printf(" max data %d(%d)",
622 	    MAX_PAYLOAD((ctl & PCIEM_CTL_MAX_PAYLOAD) >> 5),
623 	    MAX_PAYLOAD(cap & PCIEM_CAP_MAX_PAYLOAD));
624 	if ((cap & PCIEM_CAP_FLR) != 0)
625 		printf(" FLR");
626 	if (ctl & PCIEM_CTL_RELAXED_ORD_ENABLE)
627 		printf(" RO");
628 	if (ctl & PCIEM_CTL_NOSNOOP_ENABLE)
629 		printf(" NS");
630 	if (version >= 2) {
631 		cap = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CAP2, 4);
632 		if ((cap & PCIEM_CAP2_ARI) != 0) {
633 			ctl = read_config(fd, &p->pc_sel,
634 			    ptr + PCIER_DEVICE_CTL2, 4);
635 			printf(" ARI %s",
636 			    (ctl & PCIEM_CTL2_ARI) ? "enabled" : "disabled");
637 		}
638 	}
639 	printf("\n                 max read %s", max_read_string((ctl &
640 	    PCIEM_CTL_MAX_READ_REQUEST) >> 12));
641 	cap = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_CAP, 4);
642 	sta = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_STA, 2);
643 	if (cap == 0 && sta == 0)
644 		return;
645 	printf("\n                ");
646 	printf(" link x%d(x%d)", (sta & PCIEM_LINK_STA_WIDTH) >> 4,
647 	    (cap & PCIEM_LINK_CAP_MAX_WIDTH) >> 4);
648 	if ((cap & PCIEM_LINK_CAP_MAX_WIDTH) != 0) {
649 		printf(" speed %s(%s)", (sta & PCIEM_LINK_STA_WIDTH) == 0 ?
650 		    "0.0" : link_speed_string(sta & PCIEM_LINK_STA_SPEED),
651 	    	    link_speed_string(cap & PCIEM_LINK_CAP_MAX_SPEED));
652 	}
653 	if ((cap & PCIEM_LINK_CAP_ASPM) != 0) {
654 		ctl = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_CTL, 2);
655 		printf(" ASPM %s(%s)", aspm_string(ctl & PCIEM_LINK_CTL_ASPMC),
656 		    aspm_string((cap & PCIEM_LINK_CAP_ASPM) >> 10));
657 	}
658 	if ((cap & PCIEM_LINK_CAP_CLOCK_PM) != 0) {
659 		ctl = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_CTL, 2);
660 		printf(" ClockPM %s", (ctl & PCIEM_LINK_CTL_ECPM) ?
661 		    "enabled" : "disabled");
662 	}
663 	if (!(flags & PCIEM_FLAGS_SLOT))
664 		return;
665 	cap = read_config(fd, &p->pc_sel, ptr + PCIER_SLOT_CAP, 4);
666 	sta = read_config(fd, &p->pc_sel, ptr + PCIER_SLOT_STA, 2);
667 	ctl = read_config(fd, &p->pc_sel, ptr + PCIER_SLOT_CTL, 2);
668 	printf("\n                ");
669 	printf(" slot %d", (cap & PCIEM_SLOT_CAP_PSN) >> 19);
670 	printf(" power limit %d mW", slot_power(cap));
671 	if (cap & PCIEM_SLOT_CAP_HPC)
672 		printf(" HotPlug(%s)", sta & PCIEM_SLOT_STA_PDS ? "present" :
673 		    "empty");
674 	if (cap & PCIEM_SLOT_CAP_HPS)
675 		printf(" surprise");
676 	if (cap & PCIEM_SLOT_CAP_APB)
677 		printf(" Attn Button");
678 	if (cap & PCIEM_SLOT_CAP_PCP)
679 		printf(" PC(%s)", ctl & PCIEM_SLOT_CTL_PCC ? "off" : "on");
680 	if (cap & PCIEM_SLOT_CAP_MRLSP)
681 		printf(" MRL(%s)", sta & PCIEM_SLOT_STA_MRLSS ? "open" :
682 		    "closed");
683 	if (cap & PCIEM_SLOT_CAP_EIP)
684 		printf(" EI(%s)", sta & PCIEM_SLOT_STA_EIS ? "engaged" :
685 		    "disengaged");
686 }
687 
688 static void
cap_msix(int fd,struct pci_conf * p,uint8_t ptr)689 cap_msix(int fd, struct pci_conf *p, uint8_t ptr)
690 {
691 	uint32_t pba_offset, table_offset, val;
692 	int msgnum, pba_bar, table_bar;
693 	uint16_t ctrl;
694 
695 	ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_CTRL, 2);
696 	msgnum = (ctrl & PCIM_MSIXCTRL_TABLE_SIZE) + 1;
697 
698 	val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_TABLE, 4);
699 	table_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK);
700 	table_offset = val & ~PCIM_MSIX_BIR_MASK;
701 
702 	val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_PBA, 4);
703 	pba_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK);
704 	pba_offset = val & ~PCIM_MSIX_BIR_MASK;
705 
706 	printf("MSI-X supports %d message%s%s\n", msgnum,
707 	    (msgnum == 1) ? "" : "s",
708 	    (ctrl & PCIM_MSIXCTRL_MSIX_ENABLE) ? ", enabled" : "");
709 
710 	printf("                 ");
711 	printf("Table in map 0x%x[0x%x], PBA in map 0x%x[0x%x]",
712 	    table_bar, table_offset, pba_bar, pba_offset);
713 }
714 
715 static void
cap_sata(int fd __unused,struct pci_conf * p __unused,uint8_t ptr __unused)716 cap_sata(int fd __unused, struct pci_conf *p __unused, uint8_t ptr __unused)
717 {
718 
719 	printf("SATA Index-Data Pair");
720 }
721 
722 static void
cap_pciaf(int fd,struct pci_conf * p,uint8_t ptr)723 cap_pciaf(int fd, struct pci_conf *p, uint8_t ptr)
724 {
725 	uint8_t cap;
726 
727 	cap = read_config(fd, &p->pc_sel, ptr + PCIR_PCIAF_CAP, 1);
728 	printf("PCI Advanced Features:%s%s",
729 	    cap & PCIM_PCIAFCAP_FLR ? " FLR" : "",
730 	    cap & PCIM_PCIAFCAP_TP  ? " TP"  : "");
731 }
732 
733 static const char *
ea_bei_to_name(int bei)734 ea_bei_to_name(int bei)
735 {
736 	static const char *barstr[] = {
737 		"BAR0", "BAR1", "BAR2", "BAR3", "BAR4", "BAR5"
738 	};
739 	static const char *vfbarstr[] = {
740 		"VFBAR0", "VFBAR1", "VFBAR2", "VFBAR3", "VFBAR4", "VFBAR5"
741 	};
742 
743 	if ((bei >= PCIM_EA_BEI_BAR_0) && (bei <= PCIM_EA_BEI_BAR_5))
744 		return (barstr[bei - PCIM_EA_BEI_BAR_0]);
745 	if ((bei >= PCIM_EA_BEI_VF_BAR_0) && (bei <= PCIM_EA_BEI_VF_BAR_5))
746 		return (vfbarstr[bei - PCIM_EA_BEI_VF_BAR_0]);
747 
748 	switch (bei) {
749 	case PCIM_EA_BEI_BRIDGE:
750 		return "BRIDGE";
751 	case PCIM_EA_BEI_ENI:
752 		return "ENI";
753 	case PCIM_EA_BEI_ROM:
754 		return "ROM";
755 	case PCIM_EA_BEI_RESERVED:
756 	default:
757 		return "RSVD";
758 	}
759 }
760 
761 static const char *
ea_prop_to_name(uint8_t prop)762 ea_prop_to_name(uint8_t prop)
763 {
764 
765 	switch (prop) {
766 	case PCIM_EA_P_MEM:
767 		return "Non-Prefetchable Memory";
768 	case PCIM_EA_P_MEM_PREFETCH:
769 		return "Prefetchable Memory";
770 	case PCIM_EA_P_IO:
771 		return "I/O Space";
772 	case PCIM_EA_P_VF_MEM_PREFETCH:
773 		return "VF Prefetchable Memory";
774 	case PCIM_EA_P_VF_MEM:
775 		return "VF Non-Prefetchable Memory";
776 	case PCIM_EA_P_BRIDGE_MEM:
777 		return "Bridge Non-Prefetchable Memory";
778 	case PCIM_EA_P_BRIDGE_MEM_PREFETCH:
779 		return "Bridge Prefetchable Memory";
780 	case PCIM_EA_P_BRIDGE_IO:
781 		return "Bridge I/O Space";
782 	case PCIM_EA_P_MEM_RESERVED:
783 		return "Reserved Memory";
784 	case PCIM_EA_P_IO_RESERVED:
785 		return "Reserved I/O Space";
786 	case PCIM_EA_P_UNAVAILABLE:
787 		return "Unavailable";
788 	default:
789 		return "Reserved";
790 	}
791 }
792 
793 static void
cap_ea(int fd,struct pci_conf * p,uint8_t ptr)794 cap_ea(int fd, struct pci_conf *p, uint8_t ptr)
795 {
796 	int num_ent;
797 	int a, b;
798 	uint32_t bei;
799 	uint32_t val;
800 	int ent_size;
801 	uint32_t dw[4];
802 	uint32_t flags, flags_pp, flags_sp;
803 	uint64_t base, max_offset;
804 	uint8_t fixed_sub_bus_nr, fixed_sec_bus_nr;
805 
806 	/* Determine the number of entries */
807 	num_ent = read_config(fd, &p->pc_sel, ptr + PCIR_EA_NUM_ENT, 2);
808 	num_ent &= PCIM_EA_NUM_ENT_MASK;
809 
810 	printf("PCI Enhanced Allocation (%d entries)", num_ent);
811 
812 	/* Find the first entry to care of */
813 	ptr += PCIR_EA_FIRST_ENT;
814 
815 	/* Print BUS numbers for bridges */
816 	if ((p->pc_hdr & PCIM_HDRTYPE) == PCIM_HDRTYPE_BRIDGE) {
817 		val = read_config(fd, &p->pc_sel, ptr, 4);
818 
819 		fixed_sec_bus_nr = PCIM_EA_SEC_NR(val);
820 		fixed_sub_bus_nr = PCIM_EA_SUB_NR(val);
821 
822 		printf("\n\t\t BRIDGE, sec bus [%d], sub bus [%d]",
823 		    fixed_sec_bus_nr, fixed_sub_bus_nr);
824 		ptr += 4;
825 	}
826 
827 	for (a = 0; a < num_ent; a++) {
828 		/* Read a number of dwords in the entry */
829 		val = read_config(fd, &p->pc_sel, ptr, 4);
830 		ptr += 4;
831 		ent_size = (val & PCIM_EA_ES);
832 
833 		for (b = 0; b < ent_size; b++) {
834 			dw[b] = read_config(fd, &p->pc_sel, ptr, 4);
835 			ptr += 4;
836 		}
837 
838 		flags = val;
839 		flags_pp = (flags & PCIM_EA_PP) >> PCIM_EA_PP_OFFSET;
840 		flags_sp = (flags & PCIM_EA_SP) >> PCIM_EA_SP_OFFSET;
841 		bei = (PCIM_EA_BEI & val) >> PCIM_EA_BEI_OFFSET;
842 
843 		base = dw[0] & PCIM_EA_FIELD_MASK;
844 		max_offset = dw[1] | ~PCIM_EA_FIELD_MASK;
845 		b = 2;
846 		if (((dw[0] & PCIM_EA_IS_64) != 0) && (b < ent_size)) {
847 			base |= (uint64_t)dw[b] << 32UL;
848 			b++;
849 		}
850 		if (((dw[1] & PCIM_EA_IS_64) != 0)
851 			&& (b < ent_size)) {
852 			max_offset |= (uint64_t)dw[b] << 32UL;
853 			b++;
854 		}
855 
856 		printf("\n\t\t [%d] %s, %s, %s, base [0x%jx], size [0x%jx]"
857 		    "\n\t\t\tPrimary properties [0x%x] (%s)"
858 		    "\n\t\t\tSecondary properties [0x%x] (%s)",
859 		    bei, ea_bei_to_name(bei),
860 		    (flags & PCIM_EA_ENABLE ? "Enabled" : "Disabled"),
861 		    (flags & PCIM_EA_WRITABLE ? "Writable" : "Read-only"),
862 		    (uintmax_t)base, (uintmax_t)(max_offset + 1),
863 		    flags_pp, ea_prop_to_name(flags_pp),
864 		    flags_sp, ea_prop_to_name(flags_sp));
865 	}
866 }
867 
868 void
list_caps(int fd,struct pci_conf * p,int level)869 list_caps(int fd, struct pci_conf *p, int level)
870 {
871 	int express;
872 	uint16_t sta;
873 	uint8_t ptr, cap;
874 
875 	/* Are capabilities present for this device? */
876 	sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2);
877 	if (!(sta & PCIM_STATUS_CAPPRESENT))
878 		return;
879 
880 	cap_level = level;
881 
882 	switch (p->pc_hdr & PCIM_HDRTYPE) {
883 	case PCIM_HDRTYPE_NORMAL:
884 	case PCIM_HDRTYPE_BRIDGE:
885 		ptr = PCIR_CAP_PTR;
886 		break;
887 	case PCIM_HDRTYPE_CARDBUS:
888 		ptr = PCIR_CAP_PTR_2;
889 		break;
890 	default:
891 		errx(1, "list_caps: bad header type");
892 	}
893 
894 	/* Walk the capability list. */
895 	express = 0;
896 	ptr = read_config(fd, &p->pc_sel, ptr, 1);
897 	while (ptr != 0 && ptr != 0xff) {
898 		cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1);
899 		printf("    cap %02x[%02x] = ", cap, ptr);
900 		switch (cap) {
901 		case PCIY_PMG:
902 			cap_power(fd, p, ptr);
903 			break;
904 		case PCIY_AGP:
905 			cap_agp(fd, p, ptr);
906 			break;
907 		case PCIY_VPD:
908 			cap_vpd(fd, p, ptr);
909 			break;
910 		case PCIY_MSI:
911 			cap_msi(fd, p, ptr);
912 			break;
913 		case PCIY_PCIX:
914 			cap_pcix(fd, p, ptr);
915 			break;
916 		case PCIY_HT:
917 			cap_ht(fd, p, ptr);
918 			break;
919 		case PCIY_VENDOR:
920 			cap_vendor(fd, p, ptr);
921 			break;
922 		case PCIY_DEBUG:
923 			cap_debug(fd, p, ptr);
924 			break;
925 		case PCIY_SUBVENDOR:
926 			cap_subvendor(fd, p, ptr);
927 			break;
928 		case PCIY_SECDEV:
929 			cap_secdev(fd, p, ptr);
930 			break;
931 		case PCIY_EXPRESS:
932 			express = 1;
933 			cap_express(fd, p, ptr);
934 			break;
935 		case PCIY_MSIX:
936 			cap_msix(fd, p, ptr);
937 			break;
938 		case PCIY_SATA:
939 			cap_sata(fd, p, ptr);
940 			break;
941 		case PCIY_PCIAF:
942 			cap_pciaf(fd, p, ptr);
943 			break;
944 		case PCIY_EA:
945 			cap_ea(fd, p, ptr);
946 			break;
947 		default:
948 			printf("unknown");
949 			break;
950 		}
951 		printf("\n");
952 		ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1);
953 	}
954 
955 	if (express)
956 		list_ecaps(fd, p);
957 }
958 
959 /* From <sys/systm.h>. */
960 static __inline uint32_t
bitcount32(uint32_t x)961 bitcount32(uint32_t x)
962 {
963 
964 	x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1);
965 	x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2);
966 	x = (x + (x >> 4)) & 0x0f0f0f0f;
967 	x = (x + (x >> 8));
968 	x = (x + (x >> 16)) & 0x000000ff;
969 	return (x);
970 }
971 
972 static void
ecap_aer(int fd,struct pci_conf * p,uint16_t ptr,uint8_t ver)973 ecap_aer(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
974 {
975 	uint32_t sta, mask;
976 
977 	printf("AER %d", ver);
978 	if (ver < 1) {
979 		printf("\n");
980 		return;
981 	}
982 	sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_STATUS, 4);
983 	mask = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_SEVERITY, 4);
984 	printf(" %d fatal", bitcount32(sta & mask));
985 	printf(" %d non-fatal", bitcount32(sta & ~mask));
986 	sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_COR_STATUS, 4);
987 	printf(" %d corrected\n", bitcount32(sta));
988 }
989 
990 static void
ecap_vc(int fd,struct pci_conf * p,uint16_t ptr,uint8_t ver)991 ecap_vc(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
992 {
993 	uint32_t cap1;
994 
995 	printf("VC %d", ver);
996 	if (ver < 1) {
997 		printf("\n");
998 		return;
999 	}
1000 	cap1 = read_config(fd, &p->pc_sel, ptr + PCIR_VC_CAP1, 4);
1001 	printf(" max VC%d", cap1 & PCIM_VC_CAP1_EXT_COUNT);
1002 	if ((cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) != 0)
1003 		printf(" lowpri VC0-VC%d",
1004 		    (cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) >> 4);
1005 	printf("\n");
1006 }
1007 
1008 static void
ecap_sernum(int fd,struct pci_conf * p,uint16_t ptr,uint8_t ver)1009 ecap_sernum(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
1010 {
1011 	uint32_t high, low;
1012 
1013 	printf("Serial %d", ver);
1014 	if (ver < 1) {
1015 		printf("\n");
1016 		return;
1017 	}
1018 	low = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_LOW, 4);
1019 	high = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_HIGH, 4);
1020 	printf(" %08x%08x\n", high, low);
1021 }
1022 
1023 static void
ecap_vendor(int fd,struct pci_conf * p,uint16_t ptr,uint8_t ver)1024 ecap_vendor(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
1025 {
1026 	uint32_t val, hdr;
1027 	uint16_t nextptr, len;
1028 	int i;
1029 
1030 	val = read_config(fd, &p->pc_sel, ptr, 4);
1031 	nextptr = PCI_EXTCAP_NEXTPTR(val);
1032 	hdr = read_config(fd, &p->pc_sel, ptr + PCIR_VSEC_HEADER, 4);
1033 	len = PCIR_VSEC_LENGTH(hdr);
1034 	if (len == 0) {
1035 		if (nextptr == 0)
1036 			nextptr = 0x1000;
1037 		len = nextptr - ptr;
1038 	}
1039 
1040 	printf("Vendor [%d] ID %04x Rev %d Length %d\n", ver,
1041 	    PCIR_VSEC_ID(hdr), PCIR_VSEC_REV(hdr), len);
1042 	if ((ver < 1) || (cap_level <= 1))
1043 		return;
1044 	for (i = 0; i < len; i += 4) {
1045 		val = read_config(fd, &p->pc_sel, ptr + i, 4);
1046 		if ((i % 16) == 0)
1047 			printf("                 ");
1048 		printf("%02x %02x %02x %02x", val & 0xff, (val >> 8) & 0xff,
1049 		    (val >> 16) & 0xff, (val >> 24) & 0xff);
1050 		if ((((i + 4) % 16) == 0 ) || ((i + 4) >= len))
1051 			printf("\n");
1052 		else
1053 			printf(" ");
1054 	}
1055 }
1056 
1057 static void
ecap_sec_pcie(int fd,struct pci_conf * p,uint16_t ptr,uint8_t ver)1058 ecap_sec_pcie(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
1059 {
1060 	uint32_t val;
1061 
1062 	printf("PCIe Sec %d", ver);
1063 	if (ver < 1) {
1064 		printf("\n");
1065 		return;
1066 	}
1067 	val = read_config(fd, &p->pc_sel, ptr + 8, 4);
1068 	printf(" lane errors %#x\n", val);
1069 }
1070 
1071 static const char *
check_enabled(int value)1072 check_enabled(int value)
1073 {
1074 
1075 	return (value ? "enabled" : "disabled");
1076 }
1077 
1078 static void
ecap_sriov(int fd,struct pci_conf * p,uint16_t ptr,uint8_t ver)1079 ecap_sriov(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
1080 {
1081 	const char *comma, *enabled;
1082 	uint16_t iov_ctl, total_vfs, num_vfs, vf_offset, vf_stride, vf_did;
1083 	uint32_t page_caps, page_size, page_shift, size;
1084 	int i;
1085 
1086 	printf("SR-IOV %d ", ver);
1087 
1088 	iov_ctl = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_CTL, 2);
1089 	printf("IOV %s, Memory Space %s, ARI %s\n",
1090 	    check_enabled(iov_ctl & PCIM_SRIOV_VF_EN),
1091 	    check_enabled(iov_ctl & PCIM_SRIOV_VF_MSE),
1092 	    check_enabled(iov_ctl & PCIM_SRIOV_ARI_EN));
1093 
1094 	total_vfs = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_TOTAL_VFS, 2);
1095 	num_vfs = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_NUM_VFS, 2);
1096 	printf("                     ");
1097 	printf("%d VFs configured out of %d supported\n", num_vfs, total_vfs);
1098 
1099 	vf_offset = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_VF_OFF, 2);
1100 	vf_stride = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_VF_STRIDE, 2);
1101 	printf("                     ");
1102 	printf("First VF RID Offset 0x%04x, VF RID Stride 0x%04x\n", vf_offset,
1103 	    vf_stride);
1104 
1105 	vf_did = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_VF_DID, 2);
1106 	printf("                     VF Device ID 0x%04x\n", vf_did);
1107 
1108 	page_caps = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_PAGE_CAP, 4);
1109 	page_size = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_PAGE_SIZE, 4);
1110 	printf("                     ");
1111 	printf("Page Sizes: ");
1112 	comma = "";
1113 	while (page_caps != 0) {
1114 		page_shift = ffs(page_caps) - 1;
1115 
1116 		if (page_caps & page_size)
1117 			enabled = " (enabled)";
1118 		else
1119 			enabled = "";
1120 
1121 		size = (1 << (page_shift + PCI_SRIOV_BASE_PAGE_SHIFT));
1122 		printf("%s%d%s", comma, size, enabled);
1123 		comma = ", ";
1124 
1125 		page_caps &= ~(1 << page_shift);
1126 	}
1127 	printf("\n");
1128 
1129 	for (i = 0; i <= PCIR_MAX_BAR_0; i++)
1130 		print_bar(fd, p, "iov bar  ", ptr + PCIR_SRIOV_BAR(i));
1131 }
1132 
1133 static const char *
check_avail_and_state(u_int cap,u_int capbit,u_int ctl,u_int ctlbit)1134 check_avail_and_state(u_int cap, u_int capbit, u_int ctl, u_int ctlbit)
1135 {
1136 
1137 	if (cap & capbit)
1138 		return (ctl & ctlbit ? "enabled" : "disabled");
1139 	else
1140 		return "unavailable";
1141 }
1142 
1143 static void
ecap_acs(int fd,struct pci_conf * p,uint16_t ptr,uint8_t ver)1144 ecap_acs(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
1145 {
1146 	uint16_t acs_cap, acs_ctl;
1147 	static const char *const acc[] = { "access enabled", "blocking enabled",
1148 		"redirect enabled", "reserved" };
1149 
1150 	printf("ACS %d ", ver);
1151 	if (ver != 1) {
1152 		printf("\n");
1153 		return;
1154 	}
1155 
1156 #define	CHECK_AVAIL_STATE(bit) \
1157 	check_avail_and_state(acs_cap, bit, acs_ctl, bit##_ENABLE)
1158 
1159 	acs_cap = read_config(fd, &p->pc_sel, ptr + PCIR_ACS_CAP, 2);
1160 	acs_ctl = read_config(fd, &p->pc_sel, ptr + PCIR_ACS_CTL, 2);
1161 	printf("Source Validation %s, Translation Blocking %s\n",
1162 	    CHECK_AVAIL_STATE(PCIM_ACS_SOURCE_VALIDATION),
1163 	    CHECK_AVAIL_STATE(PCIM_ACS_TRANSLATION_BLOCKING));
1164 
1165 	printf("                     ");
1166 	printf("P2P Req Redirect %s, P2P Cmpl Redirect %s\n",
1167 	    CHECK_AVAIL_STATE(PCIM_ACS_P2P_REQ_REDIRECT),
1168 	    CHECK_AVAIL_STATE(PCIM_ACS_P2P_CMP_REDIRECT));
1169 	printf("                     ");
1170 	printf("P2P Upstream Forwarding %s, P2P Egress Control %s\n",
1171 	    CHECK_AVAIL_STATE(PCIM_ACS_P2P_UPSTREAM_FORWARDING),
1172 	    CHECK_AVAIL_STATE(PCIM_ACS_P2P_EGRESS_CTL));
1173 	printf("                     ");
1174 	printf("P2P Direct Translated %s, Enhanced Capability %s\n",
1175 	    CHECK_AVAIL_STATE(PCIM_ACS_P2P_DIRECT_TRANSLATED),
1176 	    acs_ctl & PCIM_ACS_ENHANCED_CAP ? "available" : "unavailable");
1177 #undef	CHECK_AVAIL_STATE
1178 
1179 	if (acs_cap & PCIM_ACS_ENHANCED_CAP) {
1180 		printf("                     ");
1181 		printf("I/O Req Blocking %s, Unclaimed Req Redirect Control %s\n",
1182 		    check_enabled(acs_ctl & PCIM_ACS_IO_REQ_BLOCKING_ENABLE),
1183 		    check_enabled(acs_ctl & PCIM_ACS_UNCLAIMED_REQ_REDIRECT_CTL));
1184 		printf("                     ");
1185 		printf("DSP BAR %s, USP BAR %s\n",
1186 		    acc[(acs_cap & PCIM_ACS_DSP_MEM_TGT_ACC_CTL) >> 8],
1187 		    acc[(acs_cap & PCIM_ACS_USP_MEM_TGT_ACC_CTL) >> 10]);
1188 	}
1189 }
1190 
1191 static struct {
1192 	uint16_t id;
1193 	const char *name;
1194 } ecap_names[] = {
1195 	{ PCIZ_AER, "AER" },
1196 	{ PCIZ_VC, "Virtual Channel" },
1197 	{ PCIZ_SERNUM, "Device Serial Number" },
1198 	{ PCIZ_PWRBDGT, "Power Budgeting" },
1199 	{ PCIZ_RCLINK_DCL, "Root Complex Link Declaration" },
1200 	{ PCIZ_RCLINK_CTL, "Root Complex Internal Link Control" },
1201 	{ PCIZ_RCEC_ASSOC, "Root Complex Event Collector ASsociation" },
1202 	{ PCIZ_MFVC, "MFVC" },
1203 	{ PCIZ_VC2, "Virtual Channel 2" },
1204 	{ PCIZ_RCRB, "RCRB" },
1205 	{ PCIZ_CAC, "Configuration Access Correction" },
1206 	{ PCIZ_ACS, "ACS" },
1207 	{ PCIZ_ARI, "ARI" },
1208 	{ PCIZ_ATS, "ATS" },
1209 	{ PCIZ_SRIOV, "SRIOV" },
1210 	{ PCIZ_MRIOV, "MRIOV" },
1211 	{ PCIZ_MULTICAST, "Multicast" },
1212 	{ PCIZ_PAGE_REQ, "Page Page Request" },
1213 	{ PCIZ_AMD, "AMD proprietary "},
1214 	{ PCIZ_RESIZE_BAR, "Resizable BAR" },
1215 	{ PCIZ_DPA, "DPA" },
1216 	{ PCIZ_TPH_REQ, "TPH Requester" },
1217 	{ PCIZ_LTR, "LTR" },
1218 	{ PCIZ_SEC_PCIE, "Secondary PCI Express" },
1219 	{ PCIZ_PMUX, "Protocol Multiplexing" },
1220 	{ PCIZ_PASID, "Process Address Space ID" },
1221 	{ PCIZ_LN_REQ, "LN Requester" },
1222 	{ PCIZ_DPC, "Downstream Port Containment" },
1223 	{ PCIZ_L1PM, "L1 PM Substates" },
1224 	{ PCIZ_PTM, "Precision Time Measurement" },
1225 	{ PCIZ_M_PCIE, "PCIe over M-PHY" },
1226 	{ PCIZ_FRS, "FRS Queuing" },
1227 	{ PCIZ_RTR, "Readiness Time Reporting" },
1228 	{ PCIZ_DVSEC, "Designated Vendor-Specific" },
1229 	{ PCIZ_VF_REBAR, "VF Resizable BAR" },
1230 	{ PCIZ_DLNK, "Data Link Feature" },
1231 	{ PCIZ_16GT, "Physical Layer 16.0 GT/s" },
1232 	{ PCIZ_LMR, "Lane Margining at Receiver" },
1233 	{ PCIZ_HIER_ID, "Hierarchy ID" },
1234 	{ PCIZ_NPEM, "Native PCIe Enclosure Management" },
1235 	{ PCIZ_PL32, "Physical Layer 32.0 GT/s" },
1236 	{ PCIZ_AP, "Alternate Protocol" },
1237 	{ PCIZ_SFI, "System Firmware Intermediary" },
1238 	{ 0, NULL }
1239 };
1240 
1241 static void
list_ecaps(int fd,struct pci_conf * p)1242 list_ecaps(int fd, struct pci_conf *p)
1243 {
1244 	const char *name;
1245 	uint32_t ecap;
1246 	uint16_t ptr;
1247 	int i;
1248 
1249 	ptr = PCIR_EXTCAP;
1250 	ecap = read_config(fd, &p->pc_sel, ptr, 4);
1251 	if (ecap == 0xffffffff || ecap == 0)
1252 		return;
1253 	for (;;) {
1254 		printf("    ecap %04x[%03x] = ", PCI_EXTCAP_ID(ecap), ptr);
1255 		switch (PCI_EXTCAP_ID(ecap)) {
1256 		case PCIZ_AER:
1257 			ecap_aer(fd, p, ptr, PCI_EXTCAP_VER(ecap));
1258 			break;
1259 		case PCIZ_VC:
1260 			ecap_vc(fd, p, ptr, PCI_EXTCAP_VER(ecap));
1261 			break;
1262 		case PCIZ_SERNUM:
1263 			ecap_sernum(fd, p, ptr, PCI_EXTCAP_VER(ecap));
1264 			break;
1265 		case PCIZ_VENDOR:
1266 			ecap_vendor(fd, p, ptr, PCI_EXTCAP_VER(ecap));
1267 			break;
1268 		case PCIZ_SEC_PCIE:
1269 			ecap_sec_pcie(fd, p, ptr, PCI_EXTCAP_VER(ecap));
1270 			break;
1271 		case PCIZ_SRIOV:
1272 			ecap_sriov(fd, p, ptr, PCI_EXTCAP_VER(ecap));
1273 			break;
1274 		case PCIZ_ACS:
1275 			ecap_acs(fd, p, ptr, PCI_EXTCAP_VER(ecap));
1276 			break;
1277 		default:
1278 			name = "unknown";
1279 			for (i = 0; ecap_names[i].name != NULL; i++)
1280 				if (ecap_names[i].id == PCI_EXTCAP_ID(ecap)) {
1281 					name = ecap_names[i].name;
1282 					break;
1283 				}
1284 			printf("%s %d\n", name, PCI_EXTCAP_VER(ecap));
1285 			break;
1286 		}
1287 		ptr = PCI_EXTCAP_NEXTPTR(ecap);
1288 		if (ptr == 0)
1289 			break;
1290 		ecap = read_config(fd, &p->pc_sel, ptr, 4);
1291 	}
1292 }
1293 
1294 /* Find offset of a specific capability.  Returns 0 on failure. */
1295 uint8_t
pci_find_cap(int fd,struct pci_conf * p,uint8_t id)1296 pci_find_cap(int fd, struct pci_conf *p, uint8_t id)
1297 {
1298 	uint16_t sta;
1299 	uint8_t ptr, cap;
1300 
1301 	/* Are capabilities present for this device? */
1302 	sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2);
1303 	if (!(sta & PCIM_STATUS_CAPPRESENT))
1304 		return (0);
1305 
1306 	switch (p->pc_hdr & PCIM_HDRTYPE) {
1307 	case PCIM_HDRTYPE_NORMAL:
1308 	case PCIM_HDRTYPE_BRIDGE:
1309 		ptr = PCIR_CAP_PTR;
1310 		break;
1311 	case PCIM_HDRTYPE_CARDBUS:
1312 		ptr = PCIR_CAP_PTR_2;
1313 		break;
1314 	default:
1315 		return (0);
1316 	}
1317 
1318 	ptr = read_config(fd, &p->pc_sel, ptr, 1);
1319 	while (ptr != 0 && ptr != 0xff) {
1320 		cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1);
1321 		if (cap == id)
1322 			return (ptr);
1323 		ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1);
1324 	}
1325 	return (0);
1326 }
1327 
1328 /* Find offset of a specific extended capability.  Returns 0 on failure. */
1329 uint16_t
pcie_find_cap(int fd,struct pci_conf * p,uint16_t id)1330 pcie_find_cap(int fd, struct pci_conf *p, uint16_t id)
1331 {
1332 	uint32_t ecap;
1333 	uint16_t ptr;
1334 
1335 	ptr = PCIR_EXTCAP;
1336 	ecap = read_config(fd, &p->pc_sel, ptr, 4);
1337 	if (ecap == 0xffffffff || ecap == 0)
1338 		return (0);
1339 	for (;;) {
1340 		if (PCI_EXTCAP_ID(ecap) == id)
1341 			return (ptr);
1342 		ptr = PCI_EXTCAP_NEXTPTR(ecap);
1343 		if (ptr == 0)
1344 			break;
1345 		ecap = read_config(fd, &p->pc_sel, ptr, 4);
1346 	}
1347 	return (0);
1348 }
1349