cap.c revision 212749
1169691Skan/*-
2169691Skan * Copyright (c) 2007 Yahoo!, Inc.
3169691Skan * All rights reserved.
4169691Skan * Written by: John Baldwin <jhb@FreeBSD.org>
5169691Skan *
6169691Skan * Redistribution and use in source and binary forms, with or without
7169691Skan * modification, are permitted provided that the following conditions
8169691Skan * are met:
9169691Skan * 1. Redistributions of source code must retain the above copyright
10169691Skan *    notice, this list of conditions and the following disclaimer.
11169691Skan * 2. Redistributions in binary form must reproduce the above copyright
12169691Skan *    notice, this list of conditions and the following disclaimer in the
13169691Skan *    documentation and/or other materials provided with the distribution.
14169691Skan * 3. Neither the name of the author nor the names of any co-contributors
15169691Skan *    may be used to endorse or promote products derived from this software
16169691Skan *    without specific prior written permission.
17169691Skan *
18169691Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19169691Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20169691Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21169691Skan * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22169691Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23169691Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24169691Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25169691Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26169691Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27169691Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28169691Skan * SUCH DAMAGE.
29169691Skan */
30169691Skan
31169691Skan#ifndef lint
32169691Skanstatic const char rcsid[] =
33169691Skan  "$FreeBSD: head/usr.sbin/pciconf/cap.c 212749 2010-09-16 16:03:12Z jhb $";
34169691Skan#endif /* not lint */
35169691Skan
36169691Skan#include <sys/types.h>
37169691Skan
38169691Skan#include <err.h>
39169691Skan#include <stdio.h>
40169691Skan#include <sys/agpio.h>
41169691Skan#include <sys/pciio.h>
42169691Skan
43169691Skan#include <dev/agp/agpreg.h>
44169691Skan#include <dev/pci/pcireg.h>
45169691Skan
46169691Skan#include "pciconf.h"
47169691Skan
48169691Skanstatic void	list_ecaps(int fd, struct pci_conf *p);
49169691Skan
50169691Skanstatic void
51169691Skancap_power(int fd, struct pci_conf *p, uint8_t ptr)
52169691Skan{
53169691Skan	uint16_t cap, status;
54169691Skan
55169691Skan	cap = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_CAP, 2);
56169691Skan	status = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_STATUS, 2);
57169691Skan	printf("powerspec %d  supports D0%s%s D3  current D%d",
58169691Skan	    cap & PCIM_PCAP_SPEC,
59169691Skan	    cap & PCIM_PCAP_D1SUPP ? " D1" : "",
60169691Skan	    cap & PCIM_PCAP_D2SUPP ? " D2" : "",
61169691Skan	    status & PCIM_PSTAT_DMASK);
62169691Skan}
63169691Skan
64169691Skanstatic void
65169691Skancap_agp(int fd, struct pci_conf *p, uint8_t ptr)
66169691Skan{
67169691Skan	uint32_t status, command;
68169691Skan
69169691Skan	status = read_config(fd, &p->pc_sel, ptr + AGP_STATUS, 4);
70169691Skan	command = read_config(fd, &p->pc_sel, ptr + AGP_CAPID, 4);
71169691Skan	printf("AGP ");
72169691Skan	if (AGP_MODE_GET_MODE_3(status)) {
73169691Skan		printf("v3 ");
74169691Skan		if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_8x)
75169691Skan			printf("8x ");
76169691Skan		if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_4x)
77169691Skan			printf("4x ");
78169691Skan	} else {
79169691Skan		if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_4x)
80169691Skan			printf("4x ");
81169691Skan		if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_2x)
82169691Skan			printf("2x ");
83169691Skan		if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_1x)
84169691Skan			printf("1x ");
85169691Skan	}
86169691Skan	if (AGP_MODE_GET_SBA(status))
87169691Skan		printf("SBA ");
88169691Skan	if (AGP_MODE_GET_AGP(command)) {
89169691Skan		printf("enabled at ");
90169691Skan		if (AGP_MODE_GET_MODE_3(command)) {
91169691Skan			printf("v3 ");
92169691Skan			switch (AGP_MODE_GET_RATE(command)) {
93169691Skan			case AGP_MODE_V3_RATE_8x:
94169691Skan				printf("8x ");
95169691Skan				break;
96169691Skan			case AGP_MODE_V3_RATE_4x:
97169691Skan				printf("4x ");
98169691Skan				break;
99169691Skan			}
100169691Skan		} else
101169691Skan			switch (AGP_MODE_GET_RATE(command)) {
102169691Skan			case AGP_MODE_V2_RATE_4x:
103169691Skan				printf("4x ");
104169691Skan				break;
105169691Skan			case AGP_MODE_V2_RATE_2x:
106169691Skan				printf("2x ");
107169691Skan				break;
108169691Skan			case AGP_MODE_V2_RATE_1x:
109169691Skan				printf("1x ");
110169691Skan				break;
111169691Skan			}
112169691Skan		if (AGP_MODE_GET_SBA(command))
113169691Skan			printf("SBA ");
114169691Skan	} else
115169691Skan		printf("disabled");
116169691Skan}
117169691Skan
118169691Skanstatic void
119169691Skancap_vpd(int fd, struct pci_conf *p, uint8_t ptr)
120169691Skan{
121169691Skan
122169691Skan	printf("VPD");
123169691Skan}
124169691Skan
125169691Skanstatic void
126169691Skancap_msi(int fd, struct pci_conf *p, uint8_t ptr)
127169691Skan{
128169691Skan	uint16_t ctrl;
129169691Skan	int msgnum;
130169691Skan
131169691Skan	ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSI_CTRL, 2);
132169691Skan	msgnum = 1 << ((ctrl & PCIM_MSICTRL_MMC_MASK) >> 1);
133169691Skan	printf("MSI supports %d message%s%s%s ", msgnum,
134169691Skan	    (msgnum == 1) ? "" : "s",
135169691Skan	    (ctrl & PCIM_MSICTRL_64BIT) ? ", 64 bit" : "",
136169691Skan	    (ctrl & PCIM_MSICTRL_VECTOR) ? ", vector masks" : "");
137169691Skan	if (ctrl & PCIM_MSICTRL_MSI_ENABLE) {
138169691Skan		msgnum = 1 << ((ctrl & PCIM_MSICTRL_MME_MASK) >> 4);
139169691Skan		printf("enabled with %d message%s", msgnum,
140169691Skan		    (msgnum == 1) ? "" : "s");
141169691Skan	}
142169691Skan}
143169691Skan
144169691Skanstatic void
145169691Skancap_pcix(int fd, struct pci_conf *p, uint8_t ptr)
146169691Skan{
147169691Skan	uint32_t status;
148169691Skan	int comma, max_splits, max_burst_read;
149169691Skan
150169691Skan	status = read_config(fd, &p->pc_sel, ptr + PCIXR_STATUS, 4);
151169691Skan	printf("PCI-X ");
152169691Skan	if (status & PCIXM_STATUS_64BIT)
153169691Skan		printf("64-bit ");
154169691Skan	if ((p->pc_hdr & PCIM_HDRTYPE) == 1)
155169691Skan		printf("bridge ");
156169691Skan	if ((p->pc_hdr & PCIM_HDRTYPE) != 1 || (status & (PCIXM_STATUS_133CAP |
157169691Skan	    PCIXM_STATUS_266CAP | PCIXM_STATUS_533CAP)) != 0)
158169691Skan		printf("supports");
159169691Skan	comma = 0;
160169691Skan	if (status & PCIXM_STATUS_133CAP) {
161169691Skan		printf("%s 133MHz", comma ? "," : "");
162169691Skan		comma = 1;
163169691Skan	}
164169691Skan	if (status & PCIXM_STATUS_266CAP) {
165169691Skan		printf("%s 266MHz", comma ? "," : "");
166169691Skan		comma = 1;
167169691Skan	}
168169691Skan	if (status & PCIXM_STATUS_533CAP) {
169169691Skan		printf("%s 533MHz", comma ? "," : "");
170169691Skan		comma = 1;
171169691Skan	}
172169691Skan	if ((p->pc_hdr & PCIM_HDRTYPE) == 1)
173169691Skan		return;
174169691Skan	switch (status & PCIXM_STATUS_MAX_READ) {
175169691Skan	case PCIXM_STATUS_MAX_READ_512:
176169691Skan		max_burst_read = 512;
177169691Skan		break;
178169691Skan	case PCIXM_STATUS_MAX_READ_1024:
179169691Skan		max_burst_read = 1024;
180169691Skan		break;
181169691Skan	case PCIXM_STATUS_MAX_READ_2048:
182169691Skan		max_burst_read = 2048;
183169691Skan		break;
184169691Skan	case PCIXM_STATUS_MAX_READ_4096:
185169691Skan		max_burst_read = 4096;
186169691Skan		break;
187169691Skan	}
188169691Skan	switch (status & PCIXM_STATUS_MAX_SPLITS) {
189169691Skan	case PCIXM_STATUS_MAX_SPLITS_1:
190169691Skan		max_splits = 1;
191169691Skan		break;
192169691Skan	case PCIXM_STATUS_MAX_SPLITS_2:
193169691Skan		max_splits = 2;
194169691Skan		break;
195169691Skan	case PCIXM_STATUS_MAX_SPLITS_3:
196169691Skan		max_splits = 3;
197169691Skan		break;
198169691Skan	case PCIXM_STATUS_MAX_SPLITS_4:
199169691Skan		max_splits = 4;
200169691Skan		break;
201169691Skan	case PCIXM_STATUS_MAX_SPLITS_8:
202169691Skan		max_splits = 8;
203169691Skan		break;
204169691Skan	case PCIXM_STATUS_MAX_SPLITS_12:
205169691Skan		max_splits = 12;
206169691Skan		break;
207169691Skan	case PCIXM_STATUS_MAX_SPLITS_16:
208169691Skan		max_splits = 16;
209169691Skan		break;
210169691Skan	case PCIXM_STATUS_MAX_SPLITS_32:
211169691Skan		max_splits = 32;
212169691Skan		break;
213169691Skan	}
214169691Skan	printf("%s %d burst read, %d split transaction%s", comma ? "," : "",
215169691Skan	    max_burst_read, max_splits, max_splits == 1 ? "" : "s");
216169691Skan}
217169691Skan
218169691Skanstatic void
219169691Skancap_ht(int fd, struct pci_conf *p, uint8_t ptr)
220169691Skan{
221169691Skan	uint32_t reg;
222169691Skan	uint16_t command;
223169691Skan
224169691Skan	command = read_config(fd, &p->pc_sel, ptr + PCIR_HT_COMMAND, 2);
225169691Skan	printf("HT ");
226169691Skan	if ((command & 0xe000) == PCIM_HTCAP_SLAVE)
227169691Skan		printf("slave");
228169691Skan	else if ((command & 0xe000) == PCIM_HTCAP_HOST)
229169691Skan		printf("host");
230169691Skan	else
231169691Skan		switch (command & PCIM_HTCMD_CAP_MASK) {
232169691Skan		case PCIM_HTCAP_SWITCH:
233169691Skan			printf("switch");
234169691Skan			break;
235169691Skan		case PCIM_HTCAP_INTERRUPT:
236169691Skan			printf("interrupt");
237169691Skan			break;
238169691Skan		case PCIM_HTCAP_REVISION_ID:
239169691Skan			printf("revision ID");
240169691Skan			break;
241169691Skan		case PCIM_HTCAP_UNITID_CLUMPING:
242169691Skan			printf("unit ID clumping");
243169691Skan			break;
244169691Skan		case PCIM_HTCAP_EXT_CONFIG_SPACE:
245169691Skan			printf("extended config space");
246169691Skan			break;
247169691Skan		case PCIM_HTCAP_ADDRESS_MAPPING:
248169691Skan			printf("address mapping");
249169691Skan			break;
250169691Skan		case PCIM_HTCAP_MSI_MAPPING:
251169691Skan			printf("MSI %saddress window %s at 0x",
252169691Skan			    command & PCIM_HTCMD_MSI_FIXED ? "fixed " : "",
253169691Skan			    command & PCIM_HTCMD_MSI_ENABLE ? "enabled" :
254169691Skan			    "disabled");
255169691Skan			if (command & PCIM_HTCMD_MSI_FIXED)
256169691Skan				printf("fee00000");
257169691Skan			else {
258169691Skan				reg = read_config(fd, &p->pc_sel,
259169691Skan				    ptr + PCIR_HTMSI_ADDRESS_HI, 4);
260169691Skan				if (reg != 0)
261169691Skan					printf("%08x", reg);
262169691Skan				reg = read_config(fd, &p->pc_sel,
263169691Skan				    ptr + PCIR_HTMSI_ADDRESS_LO, 4);
264169691Skan				printf("%08x", reg);
265169691Skan			}
266169691Skan			break;
267169691Skan		case PCIM_HTCAP_DIRECT_ROUTE:
268169691Skan			printf("direct route");
269169691Skan			break;
270169691Skan		case PCIM_HTCAP_VCSET:
271169691Skan			printf("VC set");
272169691Skan			break;
273169691Skan		case PCIM_HTCAP_RETRY_MODE:
274169691Skan			printf("retry mode");
275169691Skan			break;
276169691Skan		case PCIM_HTCAP_X86_ENCODING:
277169691Skan			printf("X86 encoding");
278169691Skan			break;
279169691Skan		default:
280169691Skan			printf("unknown %02x", command);
281169691Skan			break;
282169691Skan		}
283169691Skan}
284169691Skan
285169691Skanstatic void
286169691Skancap_vendor(int fd, struct pci_conf *p, uint8_t ptr)
287169691Skan{
288169691Skan	uint8_t length;
289169691Skan
290169691Skan	length = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_LENGTH, 1);
291169691Skan	printf("vendor (length %d)", length);
292169691Skan	if (p->pc_vendor == 0x8086) {
293169691Skan		/* Intel */
294169691Skan		uint8_t version;
295169691Skan
296169691Skan		version = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_DATA,
297169691Skan		    1);
298169691Skan		printf(" Intel cap %d version %d", version >> 4, version & 0xf);
299169691Skan		if (version >> 4 == 1 && length == 12) {
300169691Skan			/* Feature Detection */
301169691Skan			uint32_t fvec;
302169691Skan			int comma;
303169691Skan
304169691Skan			comma = 0;
305169691Skan			fvec = read_config(fd, &p->pc_sel, ptr +
306169691Skan			    PCIR_VENDOR_DATA + 5, 4);
307169691Skan			printf("\n\t\t features:");
308169691Skan			if (fvec & (1 << 0)) {
309169691Skan				printf(" AMT");
310169691Skan				comma = 1;
311169691Skan			}
312169691Skan			fvec = read_config(fd, &p->pc_sel, ptr +
313169691Skan			    PCIR_VENDOR_DATA + 1, 4);
314169691Skan			if (fvec & (1 << 21)) {
315169691Skan				printf("%s Quick Resume", comma ? "," : "");
316169691Skan				comma = 1;
317169691Skan			}
318169691Skan			if (fvec & (1 << 18)) {
319169691Skan				printf("%s SATA RAID-5", comma ? "," : "");
320169691Skan				comma = 1;
321169691Skan			}
322169691Skan			if (fvec & (1 << 9)) {
323169691Skan				printf("%s Mobile", comma ? "," : "");
324169691Skan				comma = 1;
325169691Skan			}
326169691Skan			if (fvec & (1 << 7)) {
327169691Skan				printf("%s 6 PCI-e x1 slots", comma ? "," : "");
328169691Skan				comma = 1;
329169691Skan			} else {
330169691Skan				printf("%s 4 PCI-e x1 slots", comma ? "," : "");
331169691Skan				comma = 1;
332169691Skan			}
333169691Skan			if (fvec & (1 << 5)) {
334169691Skan				printf("%s SATA RAID-0/1/10", comma ? "," : "");
335169691Skan				comma = 1;
336169691Skan			}
337169691Skan			if (fvec & (1 << 3)) {
338169691Skan				printf("%s SATA AHCI", comma ? "," : "");
339169691Skan				comma = 1;
340169691Skan			}
341169691Skan		}
342169691Skan	}
343169691Skan}
344169691Skan
345169691Skanstatic void
346169691Skancap_debug(int fd, struct pci_conf *p, uint8_t ptr)
347169691Skan{
348169691Skan	uint16_t debug_port;
349169691Skan
350169691Skan	debug_port = read_config(fd, &p->pc_sel, ptr + PCIR_DEBUG_PORT, 2);
351169691Skan	printf("EHCI Debug Port at offset 0x%x in map 0x%x", debug_port &
352169691Skan	    PCIM_DEBUG_PORT_OFFSET, PCIR_BAR(debug_port >> 13));
353169691Skan}
354169691Skan
355169691Skanstatic void
356169691Skancap_subvendor(int fd, struct pci_conf *p, uint8_t ptr)
357169691Skan{
358169691Skan	uint32_t id;
359169691Skan
360169691Skan	id = read_config(fd, &p->pc_sel, ptr + PCIR_SUBVENDCAP_ID, 4);
361169691Skan	printf("PCI Bridge card=0x%08x", id);
362169691Skan}
363169691Skan
364169691Skan#define	MAX_PAYLOAD(field)		(128 << (field))
365169691Skan
366169691Skanstatic void
367169691Skancap_express(int fd, struct pci_conf *p, uint8_t ptr)
368169691Skan{
369169691Skan	uint32_t val;
370169691Skan	uint16_t flags;
371169691Skan
372169691Skan	flags = read_config(fd, &p->pc_sel, ptr + PCIR_EXPRESS_FLAGS, 2);
373169691Skan	printf("PCI-Express %d ", flags & PCIM_EXP_FLAGS_VERSION);
374169691Skan	switch (flags & PCIM_EXP_FLAGS_TYPE) {
375169691Skan	case PCIM_EXP_TYPE_ENDPOINT:
376169691Skan		printf("endpoint");
377169691Skan		break;
378169691Skan	case PCIM_EXP_TYPE_LEGACY_ENDPOINT:
379169691Skan		printf("legacy endpoint");
380169691Skan		break;
381169691Skan	case PCIM_EXP_TYPE_ROOT_PORT:
382169691Skan		printf("root port");
383169691Skan		break;
384169691Skan	case PCIM_EXP_TYPE_UPSTREAM_PORT:
385169691Skan		printf("upstream port");
386169691Skan		break;
387169691Skan	case PCIM_EXP_TYPE_DOWNSTREAM_PORT:
388169691Skan		printf("downstream port");
389169691Skan		break;
390169691Skan	case PCIM_EXP_TYPE_PCI_BRIDGE:
391169691Skan		printf("PCI bridge");
392169691Skan		break;
393169691Skan	case PCIM_EXP_TYPE_PCIE_BRIDGE:
394169691Skan		printf("PCI to PCIe bridge");
395169691Skan		break;
396169691Skan	case PCIM_EXP_TYPE_ROOT_INT_EP:
397169691Skan		printf("root endpoint");
398169691Skan		break;
399169691Skan	case PCIM_EXP_TYPE_ROOT_EC:
400169691Skan		printf("event collector");
401169691Skan		break;
402169691Skan	default:
403169691Skan		printf("type %d", (flags & PCIM_EXP_FLAGS_TYPE) >> 4);
404169691Skan		break;
405169691Skan	}
406169691Skan	if (flags & PCIM_EXP_FLAGS_IRQ)
407169691Skan		printf(" IRQ %d", (flags & PCIM_EXP_FLAGS_IRQ) >> 8);
408169691Skan	val = read_config(fd, &p->pc_sel, ptr + PCIR_EXPRESS_DEVICE_CAP, 4);
409169691Skan	flags = read_config(fd, &p->pc_sel, ptr + PCIR_EXPRESS_DEVICE_CTL, 2);
410169691Skan	printf(" max data %d(%d)",
411169691Skan	    MAX_PAYLOAD((flags & PCIM_EXP_CTL_MAX_PAYLOAD) >> 5),
412169691Skan	    MAX_PAYLOAD(val & PCIM_EXP_CAP_MAX_PAYLOAD));
413169691Skan	val = read_config(fd, &p->pc_sel, ptr + PCIR_EXPRESS_LINK_CAP, 4);
414169691Skan	flags = read_config(fd, &p->pc_sel, ptr+ PCIR_EXPRESS_LINK_STA, 2);
415169691Skan	printf(" link x%d(x%d)", (flags & PCIM_LINK_STA_WIDTH) >> 4,
416169691Skan	    (val & PCIM_LINK_CAP_MAX_WIDTH) >> 4);
417169691Skan}
418169691Skan
419169691Skanstatic void
420169691Skancap_msix(int fd, struct pci_conf *p, uint8_t ptr)
421169691Skan{
422169691Skan	uint32_t val;
423169691Skan	uint16_t ctrl;
424169691Skan	int msgnum, table_bar, pba_bar;
425169691Skan
426169691Skan	ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_CTRL, 2);
427169691Skan	msgnum = (ctrl & PCIM_MSIXCTRL_TABLE_SIZE) + 1;
428169691Skan	val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_TABLE, 4);
429169691Skan	table_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK);
430169691Skan	val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_PBA, 4);
431169691Skan	pba_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK);
432169691Skan	printf("MSI-X supports %d message%s ", msgnum,
433169691Skan	    (msgnum == 1) ? "" : "s");
434169691Skan	if (table_bar == pba_bar)
435169691Skan		printf("in map 0x%x", table_bar);
436169691Skan	else
437169691Skan		printf("in maps 0x%x and 0x%x", table_bar, pba_bar);
438169691Skan	if (ctrl & PCIM_MSIXCTRL_MSIX_ENABLE)
439169691Skan		printf(" enabled");
440169691Skan}
441169691Skan
442169691Skanstatic void
443169691Skancap_sata(int fd, struct pci_conf *p, uint8_t ptr)
444169691Skan{
445169691Skan
446169691Skan	printf("SATA Index-Data Pair");
447169691Skan}
448169691Skan
449169691Skanstatic void
450169691Skancap_pciaf(int fd, struct pci_conf *p, uint8_t ptr)
451169691Skan{
452169691Skan	uint8_t cap;
453169691Skan
454169691Skan	cap = read_config(fd, &p->pc_sel, ptr + PCIR_PCIAF_CAP, 1);
455169691Skan	printf("PCI Advanced Features:%s%s",
456169691Skan	    cap & PCIM_PCIAFCAP_FLR ? " FLR" : "",
457169691Skan	    cap & PCIM_PCIAFCAP_TP  ? " TP"  : "");
458169691Skan}
459169691Skan
460169691Skanvoid
461169691Skanlist_caps(int fd, struct pci_conf *p)
462169691Skan{
463169691Skan	int express;
464169691Skan	uint16_t sta;
465169691Skan	uint8_t ptr, cap;
466169691Skan
467169691Skan	/* Are capabilities present for this device? */
468169691Skan	sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2);
469169691Skan	if (!(sta & PCIM_STATUS_CAPPRESENT))
470169691Skan		return;
471169691Skan
472169691Skan	switch (p->pc_hdr & PCIM_HDRTYPE) {
473169691Skan	case PCIM_HDRTYPE_NORMAL:
474169691Skan	case PCIM_HDRTYPE_BRIDGE:
475169691Skan		ptr = PCIR_CAP_PTR;
476169691Skan		break;
477169691Skan	case PCIM_HDRTYPE_CARDBUS:
478169691Skan		ptr = PCIR_CAP_PTR_2;
479169691Skan		break;
480169691Skan	default:
481169691Skan		errx(1, "list_caps: bad header type");
482169691Skan	}
483169691Skan
484169691Skan	/* Walk the capability list. */
485169691Skan	express = 0;
486169691Skan	ptr = read_config(fd, &p->pc_sel, ptr, 1);
487169691Skan	while (ptr != 0 && ptr != 0xff) {
488169691Skan		cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1);
489169691Skan		printf("    cap %02x[%02x] = ", cap, ptr);
490169691Skan		switch (cap) {
491169691Skan		case PCIY_PMG:
492169691Skan			cap_power(fd, p, ptr);
493169691Skan			break;
494169691Skan		case PCIY_AGP:
495169691Skan			cap_agp(fd, p, ptr);
496169691Skan			break;
497169691Skan		case PCIY_VPD:
498169691Skan			cap_vpd(fd, p, ptr);
499169691Skan			break;
500169691Skan		case PCIY_MSI:
501169691Skan			cap_msi(fd, p, ptr);
502169691Skan			break;
503169691Skan		case PCIY_PCIX:
504169691Skan			cap_pcix(fd, p, ptr);
505169691Skan			break;
506169691Skan		case PCIY_HT:
507169691Skan			cap_ht(fd, p, ptr);
508169691Skan			break;
509169691Skan		case PCIY_VENDOR:
510169691Skan			cap_vendor(fd, p, ptr);
511169691Skan			break;
512169691Skan		case PCIY_DEBUG:
513169691Skan			cap_debug(fd, p, ptr);
514169691Skan			break;
515169691Skan		case PCIY_SUBVENDOR:
516169691Skan			cap_subvendor(fd, p, ptr);
517169691Skan			break;
518169691Skan		case PCIY_EXPRESS:
519169691Skan			express = 1;
520169691Skan			cap_express(fd, p, ptr);
521169691Skan			break;
522169691Skan		case PCIY_MSIX:
523169691Skan			cap_msix(fd, p, ptr);
524169691Skan			break;
525169691Skan		case PCIY_SATA:
526169691Skan			cap_sata(fd, p, ptr);
527169691Skan			break;
528169691Skan		case PCIY_PCIAF:
529169691Skan			cap_pciaf(fd, p, ptr);
530169691Skan			break;
531169691Skan		default:
532169691Skan			printf("unknown");
533169691Skan			break;
534169691Skan		}
535169691Skan		printf("\n");
536169691Skan		ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1);
537169691Skan	}
538169691Skan
539169691Skan	if (express)
540169691Skan		list_ecaps(fd, p);
541169691Skan}
542169691Skan
543169691Skan/* From <sys/systm.h>. */
544169691Skanstatic __inline uint32_t
545169691Skanbitcount32(uint32_t x)
546169691Skan{
547169691Skan
548169691Skan	x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1);
549169691Skan	x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2);
550169691Skan	x = (x + (x >> 4)) & 0x0f0f0f0f;
551169691Skan	x = (x + (x >> 8));
552169691Skan	x = (x + (x >> 16)) & 0x000000ff;
553169691Skan	return (x);
554169691Skan}
555169691Skan
556169691Skanstatic void
557169691Skanecap_aer(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
558169691Skan{
559169691Skan	uint32_t sta, mask;
560169691Skan
561169691Skan	printf("AER %d", ver);
562169691Skan	if (ver != 1)
563169691Skan		return;
564169691Skan	sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_STATUS, 4);
565169691Skan	mask = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_SEVERITY, 4);
566169691Skan	printf(" %d fatal", bitcount32(sta & mask));
567169691Skan	printf(" %d non-fatal", bitcount32(sta & ~mask));
568169691Skan	sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_COR_STATUS, 4);
569169691Skan	printf(" %d corrected", bitcount32(sta));
570169691Skan}
571169691Skan
572169691Skanstatic void
573169691Skanecap_vc(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
574169691Skan{
575169691Skan	uint32_t cap1;
576169691Skan
577169691Skan	printf("VC %d", ver);
578169691Skan	if (ver != 1)
579169691Skan		return;
580169691Skan	cap1 = read_config(fd, &p->pc_sel, ptr + PCIR_VC_CAP1, 4);
581169691Skan	printf(" max VC%d", cap1 & PCIM_VC_CAP1_EXT_COUNT);
582169691Skan	if ((cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) != 0)
583169691Skan		printf(" lowpri VC0-VC%d",
584169691Skan		    (cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) >> 4);
585169691Skan}
586169691Skan
587169691Skanstatic void
588169691Skanecap_sernum(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
589169691Skan{
590169691Skan	uint32_t high, low;
591169691Skan
592169691Skan	printf("Serial %d", ver);
593169691Skan	if (ver != 1)
594169691Skan		return;
595169691Skan	low = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_LOW, 4);
596169691Skan	high = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_HIGH, 4);
597169691Skan	printf(" %08x%08x", high, low);
598169691Skan}
599169691Skan
600169691Skanstatic void
601169691Skanlist_ecaps(int fd, struct pci_conf *p)
602169691Skan{
603169691Skan	uint32_t ecap;
604169691Skan	uint16_t ptr;
605169691Skan
606169691Skan	ptr = PCIR_EXTCAP;
607169691Skan	ecap = read_config(fd, &p->pc_sel, ptr, 4);
608169691Skan	if (ecap == 0xffffffff || ecap == 0)
609169691Skan		return;
610169691Skan	for (;;) {
611169691Skan		printf("ecap %04x[%03x] = ", PCI_EXTCAP_ID(ecap), ptr);
612169691Skan		switch (PCI_EXTCAP_ID(ecap)) {
613169691Skan		case PCIZ_AER:
614169691Skan			ecap_aer(fd, p, ptr, PCI_EXTCAP_VER(ecap));
615169691Skan			break;
616169691Skan		case PCIZ_VC:
617169691Skan			ecap_vc(fd, p, ptr, PCI_EXTCAP_VER(ecap));
618169691Skan			break;
619169691Skan		case PCIZ_SERNUM:
620169691Skan			ecap_sernum(fd, p, ptr, PCI_EXTCAP_VER(ecap));
621169691Skan			break;
622169691Skan		default:
623169691Skan			printf("unknown %d", PCI_EXTCAP_VER(ecap));
624169691Skan			break;
625169691Skan		}
626169691Skan		printf("\n");
627169691Skan		ptr = PCI_EXTCAP_NEXTPTR(ecap);
628169691Skan		if (ptr == 0)
629169691Skan			break;
630169691Skan		ecap = read_config(fd, &p->pc_sel, ptr, 4);
631169691Skan	}
632169691Skan}
633169691Skan