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