18866f04eSJohn Baldwin /*- 28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 38a16b7a1SPedro F. Giffuni * 4cbf96402SJohn Baldwin * Copyright (c) 2007 Yahoo!, Inc. 58866f04eSJohn Baldwin * All rights reserved. 6cbf96402SJohn Baldwin * Written by: John Baldwin <jhb@FreeBSD.org> 78866f04eSJohn Baldwin * 88866f04eSJohn Baldwin * Redistribution and use in source and binary forms, with or without 98866f04eSJohn Baldwin * modification, are permitted provided that the following conditions 108866f04eSJohn Baldwin * are met: 118866f04eSJohn Baldwin * 1. Redistributions of source code must retain the above copyright 128866f04eSJohn Baldwin * notice, this list of conditions and the following disclaimer. 138866f04eSJohn Baldwin * 2. Redistributions in binary form must reproduce the above copyright 148866f04eSJohn Baldwin * notice, this list of conditions and the following disclaimer in the 158866f04eSJohn Baldwin * documentation and/or other materials provided with the distribution. 168866f04eSJohn Baldwin * 3. Neither the name of the author nor the names of any co-contributors 178866f04eSJohn Baldwin * may be used to endorse or promote products derived from this software 188866f04eSJohn Baldwin * without specific prior written permission. 198866f04eSJohn Baldwin * 208866f04eSJohn Baldwin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 218866f04eSJohn Baldwin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 228866f04eSJohn Baldwin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 238866f04eSJohn Baldwin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 248866f04eSJohn Baldwin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 258866f04eSJohn Baldwin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 268866f04eSJohn Baldwin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 278866f04eSJohn Baldwin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 288866f04eSJohn Baldwin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 298866f04eSJohn Baldwin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 308866f04eSJohn Baldwin * SUCH DAMAGE. 318866f04eSJohn Baldwin */ 328866f04eSJohn Baldwin 338866f04eSJohn Baldwin #include <sys/types.h> 348866f04eSJohn Baldwin 358866f04eSJohn Baldwin #include <err.h> 368866f04eSJohn Baldwin #include <stdio.h> 377fdbba5eSRyan Stone #include <strings.h> 388866f04eSJohn Baldwin #include <sys/agpio.h> 398866f04eSJohn Baldwin #include <sys/pciio.h> 408866f04eSJohn Baldwin 41305274ceSJohn Birrell #include <dev/agp/agpreg.h> 428866f04eSJohn Baldwin #include <dev/pci/pcireg.h> 438866f04eSJohn Baldwin 448866f04eSJohn Baldwin #include "pciconf.h" 458866f04eSJohn Baldwin 4679c2de35SJohn Baldwin static void list_ecaps(int fd, struct pci_conf *p); 4779c2de35SJohn Baldwin 4897faa4c4SScott Long static int cap_level; 4997faa4c4SScott Long 508866f04eSJohn Baldwin static void 518866f04eSJohn Baldwin cap_power(int fd, struct pci_conf *p, uint8_t ptr) 528866f04eSJohn Baldwin { 538866f04eSJohn Baldwin uint16_t cap, status; 548866f04eSJohn Baldwin 558866f04eSJohn Baldwin cap = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_CAP, 2); 568866f04eSJohn Baldwin status = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_STATUS, 2); 578866f04eSJohn Baldwin printf("powerspec %d supports D0%s%s D3 current D%d", 588866f04eSJohn Baldwin cap & PCIM_PCAP_SPEC, 598866f04eSJohn Baldwin cap & PCIM_PCAP_D1SUPP ? " D1" : "", 608866f04eSJohn Baldwin cap & PCIM_PCAP_D2SUPP ? " D2" : "", 618866f04eSJohn Baldwin status & PCIM_PSTAT_DMASK); 628866f04eSJohn Baldwin } 638866f04eSJohn Baldwin 648866f04eSJohn Baldwin static void 658866f04eSJohn Baldwin cap_agp(int fd, struct pci_conf *p, uint8_t ptr) 668866f04eSJohn Baldwin { 678866f04eSJohn Baldwin uint32_t status, command; 688866f04eSJohn Baldwin 698866f04eSJohn Baldwin status = read_config(fd, &p->pc_sel, ptr + AGP_STATUS, 4); 708866f04eSJohn Baldwin command = read_config(fd, &p->pc_sel, ptr + AGP_CAPID, 4); 718866f04eSJohn Baldwin printf("AGP "); 728866f04eSJohn Baldwin if (AGP_MODE_GET_MODE_3(status)) { 738866f04eSJohn Baldwin printf("v3 "); 748866f04eSJohn Baldwin if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_8x) 758866f04eSJohn Baldwin printf("8x "); 768866f04eSJohn Baldwin if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_4x) 778866f04eSJohn Baldwin printf("4x "); 788866f04eSJohn Baldwin } else { 798866f04eSJohn Baldwin if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_4x) 808866f04eSJohn Baldwin printf("4x "); 818866f04eSJohn Baldwin if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_2x) 828866f04eSJohn Baldwin printf("2x "); 838866f04eSJohn Baldwin if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_1x) 848866f04eSJohn Baldwin printf("1x "); 858866f04eSJohn Baldwin } 868866f04eSJohn Baldwin if (AGP_MODE_GET_SBA(status)) 878866f04eSJohn Baldwin printf("SBA "); 888866f04eSJohn Baldwin if (AGP_MODE_GET_AGP(command)) { 898866f04eSJohn Baldwin printf("enabled at "); 908866f04eSJohn Baldwin if (AGP_MODE_GET_MODE_3(command)) { 918866f04eSJohn Baldwin printf("v3 "); 928866f04eSJohn Baldwin switch (AGP_MODE_GET_RATE(command)) { 938866f04eSJohn Baldwin case AGP_MODE_V3_RATE_8x: 948866f04eSJohn Baldwin printf("8x "); 958866f04eSJohn Baldwin break; 968866f04eSJohn Baldwin case AGP_MODE_V3_RATE_4x: 978866f04eSJohn Baldwin printf("4x "); 988866f04eSJohn Baldwin break; 998866f04eSJohn Baldwin } 1008866f04eSJohn Baldwin } else 1018866f04eSJohn Baldwin switch (AGP_MODE_GET_RATE(command)) { 1028866f04eSJohn Baldwin case AGP_MODE_V2_RATE_4x: 1038866f04eSJohn Baldwin printf("4x "); 1048866f04eSJohn Baldwin break; 1058866f04eSJohn Baldwin case AGP_MODE_V2_RATE_2x: 1068866f04eSJohn Baldwin printf("2x "); 1078866f04eSJohn Baldwin break; 1088866f04eSJohn Baldwin case AGP_MODE_V2_RATE_1x: 1098866f04eSJohn Baldwin printf("1x "); 1108866f04eSJohn Baldwin break; 1118866f04eSJohn Baldwin } 1128866f04eSJohn Baldwin if (AGP_MODE_GET_SBA(command)) 1138866f04eSJohn Baldwin printf("SBA "); 1148866f04eSJohn Baldwin } else 1158866f04eSJohn Baldwin printf("disabled"); 1168866f04eSJohn Baldwin } 1178866f04eSJohn Baldwin 1188866f04eSJohn Baldwin static void 119873e155cSStefan Eßer cap_vpd(int fd __unused, struct pci_conf *p __unused, uint8_t ptr __unused) 1208866f04eSJohn Baldwin { 1218866f04eSJohn Baldwin 1228866f04eSJohn Baldwin printf("VPD"); 1238866f04eSJohn Baldwin } 1248866f04eSJohn Baldwin 1258866f04eSJohn Baldwin static void 1268866f04eSJohn Baldwin cap_msi(int fd, struct pci_conf *p, uint8_t ptr) 1278866f04eSJohn Baldwin { 1288866f04eSJohn Baldwin uint16_t ctrl; 1298866f04eSJohn Baldwin int msgnum; 1308866f04eSJohn Baldwin 1318866f04eSJohn Baldwin ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSI_CTRL, 2); 1328866f04eSJohn Baldwin msgnum = 1 << ((ctrl & PCIM_MSICTRL_MMC_MASK) >> 1); 1338866f04eSJohn Baldwin printf("MSI supports %d message%s%s%s ", msgnum, 1348866f04eSJohn Baldwin (msgnum == 1) ? "" : "s", 1358866f04eSJohn Baldwin (ctrl & PCIM_MSICTRL_64BIT) ? ", 64 bit" : "", 1368866f04eSJohn Baldwin (ctrl & PCIM_MSICTRL_VECTOR) ? ", vector masks" : ""); 1378866f04eSJohn Baldwin if (ctrl & PCIM_MSICTRL_MSI_ENABLE) { 1388866f04eSJohn Baldwin msgnum = 1 << ((ctrl & PCIM_MSICTRL_MME_MASK) >> 4); 1398866f04eSJohn Baldwin printf("enabled with %d message%s", msgnum, 1408866f04eSJohn Baldwin (msgnum == 1) ? "" : "s"); 1418866f04eSJohn Baldwin } 1428866f04eSJohn Baldwin } 1438866f04eSJohn Baldwin 1448866f04eSJohn Baldwin static void 1458866f04eSJohn Baldwin cap_pcix(int fd, struct pci_conf *p, uint8_t ptr) 1468866f04eSJohn Baldwin { 1478866f04eSJohn Baldwin uint32_t status; 1488866f04eSJohn Baldwin int comma, max_splits, max_burst_read; 1498866f04eSJohn Baldwin 1508866f04eSJohn Baldwin status = read_config(fd, &p->pc_sel, ptr + PCIXR_STATUS, 4); 1518866f04eSJohn Baldwin printf("PCI-X "); 1528866f04eSJohn Baldwin if (status & PCIXM_STATUS_64BIT) 1538866f04eSJohn Baldwin printf("64-bit "); 1548866f04eSJohn Baldwin if ((p->pc_hdr & PCIM_HDRTYPE) == 1) 1558866f04eSJohn Baldwin printf("bridge "); 156a28b3fc7SJohn Baldwin if ((p->pc_hdr & PCIM_HDRTYPE) != 1 || (status & (PCIXM_STATUS_133CAP | 157a28b3fc7SJohn Baldwin PCIXM_STATUS_266CAP | PCIXM_STATUS_533CAP)) != 0) 1588866f04eSJohn Baldwin printf("supports"); 1598866f04eSJohn Baldwin comma = 0; 1608866f04eSJohn Baldwin if (status & PCIXM_STATUS_133CAP) { 161e96d5d7bSWarner Losh printf(" 133MHz"); 1628866f04eSJohn Baldwin comma = 1; 1638866f04eSJohn Baldwin } 1648866f04eSJohn Baldwin if (status & PCIXM_STATUS_266CAP) { 1658866f04eSJohn Baldwin printf("%s 266MHz", comma ? "," : ""); 1668866f04eSJohn Baldwin comma = 1; 1678866f04eSJohn Baldwin } 1688866f04eSJohn Baldwin if (status & PCIXM_STATUS_533CAP) { 1698866f04eSJohn Baldwin printf("%s 533MHz", comma ? "," : ""); 1708866f04eSJohn Baldwin comma = 1; 1718866f04eSJohn Baldwin } 1728866f04eSJohn Baldwin if ((p->pc_hdr & PCIM_HDRTYPE) == 1) 1738866f04eSJohn Baldwin return; 174a4ed9e4fSStefan Eßer max_burst_read = 0; 1758866f04eSJohn Baldwin switch (status & PCIXM_STATUS_MAX_READ) { 1768866f04eSJohn Baldwin case PCIXM_STATUS_MAX_READ_512: 1778866f04eSJohn Baldwin max_burst_read = 512; 1788866f04eSJohn Baldwin break; 1798866f04eSJohn Baldwin case PCIXM_STATUS_MAX_READ_1024: 1808866f04eSJohn Baldwin max_burst_read = 1024; 1818866f04eSJohn Baldwin break; 1828866f04eSJohn Baldwin case PCIXM_STATUS_MAX_READ_2048: 1838866f04eSJohn Baldwin max_burst_read = 2048; 1848866f04eSJohn Baldwin break; 1858866f04eSJohn Baldwin case PCIXM_STATUS_MAX_READ_4096: 1868866f04eSJohn Baldwin max_burst_read = 4096; 1878866f04eSJohn Baldwin break; 1888866f04eSJohn Baldwin } 189a4ed9e4fSStefan Eßer max_splits = 0; 1908866f04eSJohn Baldwin switch (status & PCIXM_STATUS_MAX_SPLITS) { 1918866f04eSJohn Baldwin case PCIXM_STATUS_MAX_SPLITS_1: 1928866f04eSJohn Baldwin max_splits = 1; 1938866f04eSJohn Baldwin break; 1948866f04eSJohn Baldwin case PCIXM_STATUS_MAX_SPLITS_2: 1958866f04eSJohn Baldwin max_splits = 2; 1968866f04eSJohn Baldwin break; 1978866f04eSJohn Baldwin case PCIXM_STATUS_MAX_SPLITS_3: 1988866f04eSJohn Baldwin max_splits = 3; 1998866f04eSJohn Baldwin break; 2008866f04eSJohn Baldwin case PCIXM_STATUS_MAX_SPLITS_4: 2018866f04eSJohn Baldwin max_splits = 4; 2028866f04eSJohn Baldwin break; 2038866f04eSJohn Baldwin case PCIXM_STATUS_MAX_SPLITS_8: 2048866f04eSJohn Baldwin max_splits = 8; 2058866f04eSJohn Baldwin break; 2068866f04eSJohn Baldwin case PCIXM_STATUS_MAX_SPLITS_12: 2078866f04eSJohn Baldwin max_splits = 12; 2088866f04eSJohn Baldwin break; 2098866f04eSJohn Baldwin case PCIXM_STATUS_MAX_SPLITS_16: 2108866f04eSJohn Baldwin max_splits = 16; 2118866f04eSJohn Baldwin break; 2128866f04eSJohn Baldwin case PCIXM_STATUS_MAX_SPLITS_32: 2138866f04eSJohn Baldwin max_splits = 32; 2148866f04eSJohn Baldwin break; 2158866f04eSJohn Baldwin } 2168866f04eSJohn Baldwin printf("%s %d burst read, %d split transaction%s", comma ? "," : "", 2178866f04eSJohn Baldwin max_burst_read, max_splits, max_splits == 1 ? "" : "s"); 2188866f04eSJohn Baldwin } 2198866f04eSJohn Baldwin 2208866f04eSJohn Baldwin static void 2218866f04eSJohn Baldwin cap_ht(int fd, struct pci_conf *p, uint8_t ptr) 2228866f04eSJohn Baldwin { 2238866f04eSJohn Baldwin uint32_t reg; 2248866f04eSJohn Baldwin uint16_t command; 2258866f04eSJohn Baldwin 2268866f04eSJohn Baldwin command = read_config(fd, &p->pc_sel, ptr + PCIR_HT_COMMAND, 2); 2278866f04eSJohn Baldwin printf("HT "); 2288866f04eSJohn Baldwin if ((command & 0xe000) == PCIM_HTCAP_SLAVE) 2298866f04eSJohn Baldwin printf("slave"); 2308866f04eSJohn Baldwin else if ((command & 0xe000) == PCIM_HTCAP_HOST) 2318866f04eSJohn Baldwin printf("host"); 2328866f04eSJohn Baldwin else 2338866f04eSJohn Baldwin switch (command & PCIM_HTCMD_CAP_MASK) { 2348866f04eSJohn Baldwin case PCIM_HTCAP_SWITCH: 2358866f04eSJohn Baldwin printf("switch"); 2368866f04eSJohn Baldwin break; 2378866f04eSJohn Baldwin case PCIM_HTCAP_INTERRUPT: 2388866f04eSJohn Baldwin printf("interrupt"); 2398866f04eSJohn Baldwin break; 2408866f04eSJohn Baldwin case PCIM_HTCAP_REVISION_ID: 2418866f04eSJohn Baldwin printf("revision ID"); 2428866f04eSJohn Baldwin break; 2438866f04eSJohn Baldwin case PCIM_HTCAP_UNITID_CLUMPING: 2448866f04eSJohn Baldwin printf("unit ID clumping"); 2458866f04eSJohn Baldwin break; 2468866f04eSJohn Baldwin case PCIM_HTCAP_EXT_CONFIG_SPACE: 2478866f04eSJohn Baldwin printf("extended config space"); 2488866f04eSJohn Baldwin break; 2498866f04eSJohn Baldwin case PCIM_HTCAP_ADDRESS_MAPPING: 2508866f04eSJohn Baldwin printf("address mapping"); 2518866f04eSJohn Baldwin break; 2528866f04eSJohn Baldwin case PCIM_HTCAP_MSI_MAPPING: 253d68b1825SJohn Baldwin printf("MSI %saddress window %s at 0x", 254d68b1825SJohn Baldwin command & PCIM_HTCMD_MSI_FIXED ? "fixed " : "", 2558866f04eSJohn Baldwin command & PCIM_HTCMD_MSI_ENABLE ? "enabled" : 2568866f04eSJohn Baldwin "disabled"); 257d68b1825SJohn Baldwin if (command & PCIM_HTCMD_MSI_FIXED) 258d68b1825SJohn Baldwin printf("fee00000"); 259d68b1825SJohn Baldwin else { 2608866f04eSJohn Baldwin reg = read_config(fd, &p->pc_sel, 2618866f04eSJohn Baldwin ptr + PCIR_HTMSI_ADDRESS_HI, 4); 2628866f04eSJohn Baldwin if (reg != 0) 2638866f04eSJohn Baldwin printf("%08x", reg); 2648866f04eSJohn Baldwin reg = read_config(fd, &p->pc_sel, 2658866f04eSJohn Baldwin ptr + PCIR_HTMSI_ADDRESS_LO, 4); 2668866f04eSJohn Baldwin printf("%08x", reg); 267d68b1825SJohn Baldwin } 2688866f04eSJohn Baldwin break; 2698866f04eSJohn Baldwin case PCIM_HTCAP_DIRECT_ROUTE: 2708866f04eSJohn Baldwin printf("direct route"); 2718866f04eSJohn Baldwin break; 2728866f04eSJohn Baldwin case PCIM_HTCAP_VCSET: 2738866f04eSJohn Baldwin printf("VC set"); 2748866f04eSJohn Baldwin break; 2758866f04eSJohn Baldwin case PCIM_HTCAP_RETRY_MODE: 2768866f04eSJohn Baldwin printf("retry mode"); 2778866f04eSJohn Baldwin break; 2784d6c5befSJohn Baldwin case PCIM_HTCAP_X86_ENCODING: 2794d6c5befSJohn Baldwin printf("X86 encoding"); 2804d6c5befSJohn Baldwin break; 2815d6787cfSKonstantin Belousov case PCIM_HTCAP_GEN3: 2825d6787cfSKonstantin Belousov printf("Gen3"); 2835d6787cfSKonstantin Belousov break; 2845d6787cfSKonstantin Belousov case PCIM_HTCAP_FLE: 2855d6787cfSKonstantin Belousov printf("function-level extension"); 2865d6787cfSKonstantin Belousov break; 2875d6787cfSKonstantin Belousov case PCIM_HTCAP_PM: 2885d6787cfSKonstantin Belousov printf("power management"); 2895d6787cfSKonstantin Belousov break; 2905d6787cfSKonstantin Belousov case PCIM_HTCAP_HIGH_NODE_COUNT: 2915d6787cfSKonstantin Belousov printf("high node count"); 2925d6787cfSKonstantin Belousov break; 2938866f04eSJohn Baldwin default: 2948866f04eSJohn Baldwin printf("unknown %02x", command); 2958866f04eSJohn Baldwin break; 2968866f04eSJohn Baldwin } 2978866f04eSJohn Baldwin } 2988866f04eSJohn Baldwin 2998866f04eSJohn Baldwin static void 3008866f04eSJohn Baldwin cap_vendor(int fd, struct pci_conf *p, uint8_t ptr) 3018866f04eSJohn Baldwin { 3028866f04eSJohn Baldwin uint8_t length; 3038866f04eSJohn Baldwin 3048866f04eSJohn Baldwin length = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_LENGTH, 1); 3058866f04eSJohn Baldwin printf("vendor (length %d)", length); 3068866f04eSJohn Baldwin if (p->pc_vendor == 0x8086) { 3078866f04eSJohn Baldwin /* Intel */ 3088866f04eSJohn Baldwin uint8_t version; 3098866f04eSJohn Baldwin 3108866f04eSJohn Baldwin version = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_DATA, 3118866f04eSJohn Baldwin 1); 3128866f04eSJohn Baldwin printf(" Intel cap %d version %d", version >> 4, version & 0xf); 3138866f04eSJohn Baldwin if (version >> 4 == 1 && length == 12) { 3148866f04eSJohn Baldwin /* Feature Detection */ 3158866f04eSJohn Baldwin uint32_t fvec; 3168866f04eSJohn Baldwin int comma; 3178866f04eSJohn Baldwin 3188866f04eSJohn Baldwin comma = 0; 3198866f04eSJohn Baldwin fvec = read_config(fd, &p->pc_sel, ptr + 3208866f04eSJohn Baldwin PCIR_VENDOR_DATA + 5, 4); 3218866f04eSJohn Baldwin printf("\n\t\t features:"); 3228866f04eSJohn Baldwin if (fvec & (1 << 0)) { 3238866f04eSJohn Baldwin printf(" AMT"); 3248866f04eSJohn Baldwin comma = 1; 3258866f04eSJohn Baldwin } 3268866f04eSJohn Baldwin fvec = read_config(fd, &p->pc_sel, ptr + 3278866f04eSJohn Baldwin PCIR_VENDOR_DATA + 1, 4); 3288866f04eSJohn Baldwin if (fvec & (1 << 21)) { 3298866f04eSJohn Baldwin printf("%s Quick Resume", comma ? "," : ""); 3308866f04eSJohn Baldwin comma = 1; 3318866f04eSJohn Baldwin } 3328866f04eSJohn Baldwin if (fvec & (1 << 18)) { 3338866f04eSJohn Baldwin printf("%s SATA RAID-5", comma ? "," : ""); 3348866f04eSJohn Baldwin comma = 1; 3358866f04eSJohn Baldwin } 3368866f04eSJohn Baldwin if (fvec & (1 << 9)) { 3378866f04eSJohn Baldwin printf("%s Mobile", comma ? "," : ""); 3388866f04eSJohn Baldwin comma = 1; 3398866f04eSJohn Baldwin } 3408866f04eSJohn Baldwin if (fvec & (1 << 7)) { 3418866f04eSJohn Baldwin printf("%s 6 PCI-e x1 slots", comma ? "," : ""); 3428866f04eSJohn Baldwin comma = 1; 3438866f04eSJohn Baldwin } else { 3448866f04eSJohn Baldwin printf("%s 4 PCI-e x1 slots", comma ? "," : ""); 3458866f04eSJohn Baldwin comma = 1; 3468866f04eSJohn Baldwin } 3478866f04eSJohn Baldwin if (fvec & (1 << 5)) { 3488866f04eSJohn Baldwin printf("%s SATA RAID-0/1/10", comma ? "," : ""); 3498866f04eSJohn Baldwin comma = 1; 3508866f04eSJohn Baldwin } 351e96d5d7bSWarner Losh if (fvec & (1 << 3)) 352e96d5d7bSWarner Losh printf(", SATA AHCI"); 3538866f04eSJohn Baldwin } 3548866f04eSJohn Baldwin } 3558866f04eSJohn Baldwin } 3568866f04eSJohn Baldwin 3578866f04eSJohn Baldwin static void 3588866f04eSJohn Baldwin cap_debug(int fd, struct pci_conf *p, uint8_t ptr) 3598866f04eSJohn Baldwin { 3608866f04eSJohn Baldwin uint16_t debug_port; 3618866f04eSJohn Baldwin 3628866f04eSJohn Baldwin debug_port = read_config(fd, &p->pc_sel, ptr + PCIR_DEBUG_PORT, 2); 3638866f04eSJohn Baldwin printf("EHCI Debug Port at offset 0x%x in map 0x%x", debug_port & 3648866f04eSJohn Baldwin PCIM_DEBUG_PORT_OFFSET, PCIR_BAR(debug_port >> 13)); 3658866f04eSJohn Baldwin } 3668866f04eSJohn Baldwin 3678866f04eSJohn Baldwin static void 3688866f04eSJohn Baldwin cap_subvendor(int fd, struct pci_conf *p, uint8_t ptr) 3698866f04eSJohn Baldwin { 3708866f04eSJohn Baldwin uint32_t id; 371fe1c3596SScott Long uint16_t ssid, ssvid; 3728866f04eSJohn Baldwin 3738866f04eSJohn Baldwin id = read_config(fd, &p->pc_sel, ptr + PCIR_SUBVENDCAP_ID, 4); 374fe1c3596SScott Long ssid = id >> 16; 375fe1c3596SScott Long ssvid = id & 0xffff; 376fe1c3596SScott Long printf("PCI Bridge subvendor=0x%04x subdevice=0x%04x", ssvid, ssid); 3778866f04eSJohn Baldwin } 3788866f04eSJohn Baldwin 379*1e6db7beSKonstantin Belousov static const char * 380*1e6db7beSKonstantin Belousov cap_secdev_amdiommu_decode_vasize(uint32_t misc0) 381*1e6db7beSKonstantin Belousov { 382*1e6db7beSKonstantin Belousov switch (misc0 & PCIM_AMDIOMMU_MISC0_VASIZE_MASK) { 383*1e6db7beSKonstantin Belousov case PCIM_AMDIOMMU_MISC0_VASIZE_32: 384*1e6db7beSKonstantin Belousov return ("32bit"); 385*1e6db7beSKonstantin Belousov case PCIM_AMDIOMMU_MISC0_VASIZE_40: 386*1e6db7beSKonstantin Belousov return ("40bit"); 387*1e6db7beSKonstantin Belousov case PCIM_AMDIOMMU_MISC0_VASIZE_48: 388*1e6db7beSKonstantin Belousov return ("48bit"); 389*1e6db7beSKonstantin Belousov case PCIM_AMDIOMMU_MISC0_VASIZE_64: 390*1e6db7beSKonstantin Belousov return ("64bit"); 391*1e6db7beSKonstantin Belousov default: 392*1e6db7beSKonstantin Belousov return ("unknown"); 393*1e6db7beSKonstantin Belousov } 394*1e6db7beSKonstantin Belousov } 395*1e6db7beSKonstantin Belousov 396*1e6db7beSKonstantin Belousov static const char * 397*1e6db7beSKonstantin Belousov cap_secdev_amdiommu_decode_pasize(uint32_t misc0) 398*1e6db7beSKonstantin Belousov { 399*1e6db7beSKonstantin Belousov switch (misc0 & PCIM_AMDIOMMU_MISC0_PASIZE_MASK) { 400*1e6db7beSKonstantin Belousov case PCIM_AMDIOMMU_MISC0_PASIZE_40: 401*1e6db7beSKonstantin Belousov return ("40bit"); 402*1e6db7beSKonstantin Belousov case PCIM_AMDIOMMU_MISC0_PASIZE_48: 403*1e6db7beSKonstantin Belousov return ("48bit"); 404*1e6db7beSKonstantin Belousov case PCIM_AMDIOMMU_MISC0_PASIZE_52: 405*1e6db7beSKonstantin Belousov return ("52bit"); 406*1e6db7beSKonstantin Belousov default: 407*1e6db7beSKonstantin Belousov return ("unknown"); 408*1e6db7beSKonstantin Belousov } 409*1e6db7beSKonstantin Belousov } 410*1e6db7beSKonstantin Belousov 411*1e6db7beSKonstantin Belousov static const char * 412*1e6db7beSKonstantin Belousov cap_secdev_amdiommu_decode_gvasize(uint32_t misc0) 413*1e6db7beSKonstantin Belousov { 414*1e6db7beSKonstantin Belousov switch (misc0 & PCIM_AMDIOMMU_MISC0_GVASIZE_MASK) { 415*1e6db7beSKonstantin Belousov case PCIM_AMDIOMMU_MISC0_GVASIZE_48: 416*1e6db7beSKonstantin Belousov return ("48bit"); 417*1e6db7beSKonstantin Belousov case PCIM_AMDIOMMU_MISC0_GVASIZE_57: 418*1e6db7beSKonstantin Belousov return ("57bit"); 419*1e6db7beSKonstantin Belousov default: 420*1e6db7beSKonstantin Belousov return ("unknown"); 421*1e6db7beSKonstantin Belousov } 422*1e6db7beSKonstantin Belousov } 423*1e6db7beSKonstantin Belousov 424*1e6db7beSKonstantin Belousov static void 425*1e6db7beSKonstantin Belousov cap_secdev(int fd, struct pci_conf *p, uint8_t ptr) 426*1e6db7beSKonstantin Belousov { 427*1e6db7beSKonstantin Belousov uint32_t cap_h; 428*1e6db7beSKonstantin Belousov uint32_t cap_type, cap_rev; 429*1e6db7beSKonstantin Belousov uint32_t base_low, base_high; 430*1e6db7beSKonstantin Belousov uint32_t range; 431*1e6db7beSKonstantin Belousov uint32_t misc0, misc1; 432*1e6db7beSKonstantin Belousov const char *delim; 433*1e6db7beSKonstantin Belousov 434*1e6db7beSKonstantin Belousov cap_h = read_config(fd, &p->pc_sel, ptr + PCIR_AMDIOMMU_CAP_HEADER, 4); 435*1e6db7beSKonstantin Belousov cap_type = cap_h & PCIM_AMDIOMMU_CAP_TYPE_MASK; 436*1e6db7beSKonstantin Belousov cap_rev = cap_h & PCIM_AMDIOMMU_CAP_REV_MASK; 437*1e6db7beSKonstantin Belousov if (cap_type != PCIM_AMDIOMMU_CAP_TYPE_VAL || 438*1e6db7beSKonstantin Belousov cap_rev != PCIM_AMDIOMMU_CAP_REV_VAL) { 439*1e6db7beSKonstantin Belousov printf("Secure Device Type=0x%1x Rev=0x%02x\n", 440*1e6db7beSKonstantin Belousov cap_type >> 16, cap_rev >> 19); 441*1e6db7beSKonstantin Belousov return; 442*1e6db7beSKonstantin Belousov } 443*1e6db7beSKonstantin Belousov base_low = read_config(fd, &p->pc_sel, ptr + PCIR_AMDIOMMU_BASE_LOW, 444*1e6db7beSKonstantin Belousov 4); 445*1e6db7beSKonstantin Belousov base_high = read_config(fd, &p->pc_sel, ptr + PCIR_AMDIOMMU_BASE_HIGH, 446*1e6db7beSKonstantin Belousov 4); 447*1e6db7beSKonstantin Belousov printf("AMD IOMMU Base Capability Base=%#018jx/%sabled", 448*1e6db7beSKonstantin Belousov (uintmax_t)(base_low & PCIM_AMDIOMMU_BASE_LOW_ADDRM) + 449*1e6db7beSKonstantin Belousov ((uintmax_t)base_high << 32), 450*1e6db7beSKonstantin Belousov (base_low & PCIM_AMDIOMMU_BASE_LOW_EN) != 0 ? "En" : "Dis"); 451*1e6db7beSKonstantin Belousov 452*1e6db7beSKonstantin Belousov delim = "\n\t\t"; 453*1e6db7beSKonstantin Belousov #define PRINTCAP(bit, name) \ 454*1e6db7beSKonstantin Belousov if ((cap_h & PCIM_AMDIOMMU_CAP_ ##bit) != 0) { \ 455*1e6db7beSKonstantin Belousov printf("%s%s", delim, #name); \ 456*1e6db7beSKonstantin Belousov delim = ","; \ 457*1e6db7beSKonstantin Belousov } 458*1e6db7beSKonstantin Belousov PRINTCAP(CAPEXT, CapExt); 459*1e6db7beSKonstantin Belousov PRINTCAP(EFR, EFRSup); 460*1e6db7beSKonstantin Belousov PRINTCAP(NPCACHE, NpCache); 461*1e6db7beSKonstantin Belousov PRINTCAP(HTTUN, HtTunnel); 462*1e6db7beSKonstantin Belousov PRINTCAP(IOTLB, IotlbSup); 463*1e6db7beSKonstantin Belousov #undef PRINTCAP 464*1e6db7beSKonstantin Belousov 465*1e6db7beSKonstantin Belousov range = read_config(fd, &p->pc_sel, ptr + PCIR_AMDIOMMU_RANGE, 4); 466*1e6db7beSKonstantin Belousov printf("\n\t\tUnitId=%d", range & PCIM_AMDIOMMU_RANGE_UNITID_MASK); 467*1e6db7beSKonstantin Belousov if ((range & PCIM_AMDIOMMU_RANGE_RNGVALID) != 0) { 468*1e6db7beSKonstantin Belousov printf(" BusNum=%#06x FirstDev=%#06x LastDev=%#06x", 469*1e6db7beSKonstantin Belousov (range & PCIM_AMDIOMMU_RANGE_BUSNUM_MASK) >> 8, 470*1e6db7beSKonstantin Belousov (range & PCIM_AMDIOMMU_RANGE_FIRSTDEV_MASK) >> 16, 471*1e6db7beSKonstantin Belousov (range & PCIM_AMDIOMMU_RANGE_LASTDEV_MASK) >> 24); 472*1e6db7beSKonstantin Belousov } 473*1e6db7beSKonstantin Belousov 474*1e6db7beSKonstantin Belousov misc0 = read_config(fd, &p->pc_sel, ptr + PCIR_AMDIOMMU_MISC0, 4); 475*1e6db7beSKonstantin Belousov printf("\n\t\tMsiNum=%d MsiNumPPR=%d HtAtsResv=%d", 476*1e6db7beSKonstantin Belousov misc0 & PCIM_AMDIOMMU_MISC0_MSINUM_MASK, 477*1e6db7beSKonstantin Belousov (misc0 & PCIM_AMDIOMMU_MISC0_MSINUMPPR_MASK) >> 27, 478*1e6db7beSKonstantin Belousov (misc0 & PCIM_AMDIOMMU_MISC0_HTATSRESV) != 0); 479*1e6db7beSKonstantin Belousov if ((cap_h & PCIM_AMDIOMMU_CAP_CAPEXT) != 0) { 480*1e6db7beSKonstantin Belousov misc1 = read_config(fd, &p->pc_sel, 481*1e6db7beSKonstantin Belousov ptr + PCIR_AMDIOMMU_MISC1, 4); 482*1e6db7beSKonstantin Belousov printf(" MsiNumGA=%d", 483*1e6db7beSKonstantin Belousov misc1 & PCIM_AMDIOMMU_MISC1_MSINUMGA_MASK); 484*1e6db7beSKonstantin Belousov } 485*1e6db7beSKonstantin Belousov printf("\n\t\tVAsize=%s PAsize=%s GVAsize=%s", 486*1e6db7beSKonstantin Belousov cap_secdev_amdiommu_decode_vasize(misc0), 487*1e6db7beSKonstantin Belousov cap_secdev_amdiommu_decode_pasize(misc0), 488*1e6db7beSKonstantin Belousov cap_secdev_amdiommu_decode_gvasize(misc0)); 489*1e6db7beSKonstantin Belousov } 490*1e6db7beSKonstantin Belousov 491a28b3fc7SJohn Baldwin #define MAX_PAYLOAD(field) (128 << (field)) 492a28b3fc7SJohn Baldwin 493ff473561SJim Harris static const char * 494ff473561SJim Harris link_speed_string(uint8_t speed) 495ff473561SJim Harris { 496ff473561SJim Harris 497ff473561SJim Harris switch (speed) { 498ff473561SJim Harris case 1: 499ff473561SJim Harris return ("2.5"); 500ff473561SJim Harris case 2: 501ff473561SJim Harris return ("5.0"); 502ff473561SJim Harris case 3: 503ff473561SJim Harris return ("8.0"); 504e1d8b631SAndrew Gallatin case 4: 505e1d8b631SAndrew Gallatin return ("16.0"); 506e0a63d87SEd Maste case 5: 507e0a63d87SEd Maste return ("32.0"); 508e0a63d87SEd Maste case 6: 509e0a63d87SEd Maste return ("64.0"); 510ff473561SJim Harris default: 511ff473561SJim Harris return ("undef"); 512ff473561SJim Harris } 513ff473561SJim Harris } 514ff473561SJim Harris 51543a716a6SJung-uk Kim static const char * 51696128185SKonstantin Belousov max_read_string(u_int max_read) 51796128185SKonstantin Belousov { 51896128185SKonstantin Belousov 51996128185SKonstantin Belousov switch (max_read) { 52096128185SKonstantin Belousov case 0x0: 52196128185SKonstantin Belousov return ("128"); 52296128185SKonstantin Belousov case 0x1: 52396128185SKonstantin Belousov return ("256"); 52496128185SKonstantin Belousov case 0x2: 52596128185SKonstantin Belousov return ("512"); 52696128185SKonstantin Belousov case 0x3: 52796128185SKonstantin Belousov return ("1024"); 52896128185SKonstantin Belousov case 0x4: 52996128185SKonstantin Belousov return ("2048"); 53096128185SKonstantin Belousov case 0x5: 53196128185SKonstantin Belousov return ("4096"); 53296128185SKonstantin Belousov default: 53396128185SKonstantin Belousov return ("undef"); 53496128185SKonstantin Belousov } 53596128185SKonstantin Belousov } 53696128185SKonstantin Belousov 53796128185SKonstantin Belousov static const char * 53843a716a6SJung-uk Kim aspm_string(uint8_t aspm) 53943a716a6SJung-uk Kim { 54043a716a6SJung-uk Kim 54143a716a6SJung-uk Kim switch (aspm) { 54243a716a6SJung-uk Kim case 1: 54343a716a6SJung-uk Kim return ("L0s"); 54443a716a6SJung-uk Kim case 2: 54543a716a6SJung-uk Kim return ("L1"); 54643a716a6SJung-uk Kim case 3: 54743a716a6SJung-uk Kim return ("L0s/L1"); 54843a716a6SJung-uk Kim default: 54943a716a6SJung-uk Kim return ("disabled"); 55043a716a6SJung-uk Kim } 55143a716a6SJung-uk Kim } 55243a716a6SJung-uk Kim 5530b035149SJohn Baldwin static int 5540b035149SJohn Baldwin slot_power(uint32_t cap) 5550b035149SJohn Baldwin { 5560b035149SJohn Baldwin int mwatts; 5570b035149SJohn Baldwin 5580b035149SJohn Baldwin mwatts = (cap & PCIEM_SLOT_CAP_SPLV) >> 7; 5590b035149SJohn Baldwin switch (cap & PCIEM_SLOT_CAP_SPLS) { 5600b035149SJohn Baldwin case 0x0: 5610b035149SJohn Baldwin mwatts *= 1000; 5620b035149SJohn Baldwin break; 5630b035149SJohn Baldwin case 0x1: 5640b035149SJohn Baldwin mwatts *= 100; 5650b035149SJohn Baldwin break; 5660b035149SJohn Baldwin case 0x2: 5670b035149SJohn Baldwin mwatts *= 10; 5680b035149SJohn Baldwin break; 5690b035149SJohn Baldwin default: 5700b035149SJohn Baldwin break; 5710b035149SJohn Baldwin } 5720b035149SJohn Baldwin return (mwatts); 5730b035149SJohn Baldwin } 5740b035149SJohn Baldwin 5758866f04eSJohn Baldwin static void 5768866f04eSJohn Baldwin cap_express(int fd, struct pci_conf *p, uint8_t ptr) 5778866f04eSJohn Baldwin { 578c36c6e72SJohn Baldwin uint32_t cap; 57943a716a6SJung-uk Kim uint16_t ctl, flags, sta; 580c36c6e72SJohn Baldwin unsigned int version; 5818866f04eSJohn Baldwin 582389c8bd5SGavin Atkinson flags = read_config(fd, &p->pc_sel, ptr + PCIER_FLAGS, 2); 583c36c6e72SJohn Baldwin version = flags & PCIEM_FLAGS_VERSION; 584c36c6e72SJohn Baldwin printf("PCI-Express %u ", version); 585389c8bd5SGavin Atkinson switch (flags & PCIEM_FLAGS_TYPE) { 586389c8bd5SGavin Atkinson case PCIEM_TYPE_ENDPOINT: 5878866f04eSJohn Baldwin printf("endpoint"); 5888866f04eSJohn Baldwin break; 589389c8bd5SGavin Atkinson case PCIEM_TYPE_LEGACY_ENDPOINT: 5908866f04eSJohn Baldwin printf("legacy endpoint"); 5918866f04eSJohn Baldwin break; 592389c8bd5SGavin Atkinson case PCIEM_TYPE_ROOT_PORT: 5938866f04eSJohn Baldwin printf("root port"); 5948866f04eSJohn Baldwin break; 595389c8bd5SGavin Atkinson case PCIEM_TYPE_UPSTREAM_PORT: 5968866f04eSJohn Baldwin printf("upstream port"); 5978866f04eSJohn Baldwin break; 598389c8bd5SGavin Atkinson case PCIEM_TYPE_DOWNSTREAM_PORT: 5998866f04eSJohn Baldwin printf("downstream port"); 6008866f04eSJohn Baldwin break; 601389c8bd5SGavin Atkinson case PCIEM_TYPE_PCI_BRIDGE: 6028866f04eSJohn Baldwin printf("PCI bridge"); 6038866f04eSJohn Baldwin break; 604389c8bd5SGavin Atkinson case PCIEM_TYPE_PCIE_BRIDGE: 605a28b3fc7SJohn Baldwin printf("PCI to PCIe bridge"); 606a28b3fc7SJohn Baldwin break; 607389c8bd5SGavin Atkinson case PCIEM_TYPE_ROOT_INT_EP: 608a28b3fc7SJohn Baldwin printf("root endpoint"); 609a28b3fc7SJohn Baldwin break; 610389c8bd5SGavin Atkinson case PCIEM_TYPE_ROOT_EC: 611a28b3fc7SJohn Baldwin printf("event collector"); 612a28b3fc7SJohn Baldwin break; 6138866f04eSJohn Baldwin default: 614389c8bd5SGavin Atkinson printf("type %d", (flags & PCIEM_FLAGS_TYPE) >> 4); 6158866f04eSJohn Baldwin break; 6168866f04eSJohn Baldwin } 617389c8bd5SGavin Atkinson if (flags & PCIEM_FLAGS_IRQ) 618c36c6e72SJohn Baldwin printf(" MSI %d", (flags & PCIEM_FLAGS_IRQ) >> 9); 61943a716a6SJung-uk Kim cap = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CAP, 4); 62043a716a6SJung-uk Kim ctl = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CTL, 2); 621a28b3fc7SJohn Baldwin printf(" max data %d(%d)", 62243a716a6SJung-uk Kim MAX_PAYLOAD((ctl & PCIEM_CTL_MAX_PAYLOAD) >> 5), 62343a716a6SJung-uk Kim MAX_PAYLOAD(cap & PCIEM_CAP_MAX_PAYLOAD)); 62443a716a6SJung-uk Kim if ((cap & PCIEM_CAP_FLR) != 0) 62560149b5cSJohn Baldwin printf(" FLR"); 62634f2f73cSJohn Baldwin if (ctl & PCIEM_CTL_RELAXED_ORD_ENABLE) 62734f2f73cSJohn Baldwin printf(" RO"); 62834f2f73cSJohn Baldwin if (ctl & PCIEM_CTL_NOSNOOP_ENABLE) 62934f2f73cSJohn Baldwin printf(" NS"); 630c36c6e72SJohn Baldwin if (version >= 2) { 631c36c6e72SJohn Baldwin cap = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CAP2, 4); 632c36c6e72SJohn Baldwin if ((cap & PCIEM_CAP2_ARI) != 0) { 633c36c6e72SJohn Baldwin ctl = read_config(fd, &p->pc_sel, 634c36c6e72SJohn Baldwin ptr + PCIER_DEVICE_CTL2, 4); 635c36c6e72SJohn Baldwin printf(" ARI %s", 636c36c6e72SJohn Baldwin (ctl & PCIEM_CTL2_ARI) ? "enabled" : "disabled"); 637c36c6e72SJohn Baldwin } 638c36c6e72SJohn Baldwin } 63996128185SKonstantin Belousov printf("\n max read %s", max_read_string((ctl & 64096128185SKonstantin Belousov PCIEM_CTL_MAX_READ_REQUEST) >> 12)); 64143a716a6SJung-uk Kim cap = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_CAP, 4); 64243a716a6SJung-uk Kim sta = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_STA, 2); 643c36c6e72SJohn Baldwin if (cap == 0 && sta == 0) 644c36c6e72SJohn Baldwin return; 645c36c6e72SJohn Baldwin printf("\n "); 64643a716a6SJung-uk Kim printf(" link x%d(x%d)", (sta & PCIEM_LINK_STA_WIDTH) >> 4, 64743a716a6SJung-uk Kim (cap & PCIEM_LINK_CAP_MAX_WIDTH) >> 4); 64843a716a6SJung-uk Kim if ((cap & PCIEM_LINK_CAP_MAX_WIDTH) != 0) { 64943a716a6SJung-uk Kim printf(" speed %s(%s)", (sta & PCIEM_LINK_STA_WIDTH) == 0 ? 65043a716a6SJung-uk Kim "0.0" : link_speed_string(sta & PCIEM_LINK_STA_SPEED), 65143a716a6SJung-uk Kim link_speed_string(cap & PCIEM_LINK_CAP_MAX_SPEED)); 65243a716a6SJung-uk Kim } 65343a716a6SJung-uk Kim if ((cap & PCIEM_LINK_CAP_ASPM) != 0) { 65443a716a6SJung-uk Kim ctl = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_CTL, 2); 65543a716a6SJung-uk Kim printf(" ASPM %s(%s)", aspm_string(ctl & PCIEM_LINK_CTL_ASPMC), 65643a716a6SJung-uk Kim aspm_string((cap & PCIEM_LINK_CAP_ASPM) >> 10)); 657ff473561SJim Harris } 6585469a751SAlexander Motin if ((cap & PCIEM_LINK_CAP_CLOCK_PM) != 0) { 6595469a751SAlexander Motin ctl = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_CTL, 2); 6605469a751SAlexander Motin printf(" ClockPM %s", (ctl & PCIEM_LINK_CTL_ECPM) ? 6615469a751SAlexander Motin "enabled" : "disabled"); 6625469a751SAlexander Motin } 6630b035149SJohn Baldwin if (!(flags & PCIEM_FLAGS_SLOT)) 6640b035149SJohn Baldwin return; 6650b035149SJohn Baldwin cap = read_config(fd, &p->pc_sel, ptr + PCIER_SLOT_CAP, 4); 6660b035149SJohn Baldwin sta = read_config(fd, &p->pc_sel, ptr + PCIER_SLOT_STA, 2); 6670b035149SJohn Baldwin ctl = read_config(fd, &p->pc_sel, ptr + PCIER_SLOT_CTL, 2); 6680b035149SJohn Baldwin printf("\n "); 6690b035149SJohn Baldwin printf(" slot %d", (cap & PCIEM_SLOT_CAP_PSN) >> 19); 6700b035149SJohn Baldwin printf(" power limit %d mW", slot_power(cap)); 6710b035149SJohn Baldwin if (cap & PCIEM_SLOT_CAP_HPC) 6720b035149SJohn Baldwin printf(" HotPlug(%s)", sta & PCIEM_SLOT_STA_PDS ? "present" : 6730b035149SJohn Baldwin "empty"); 6740b035149SJohn Baldwin if (cap & PCIEM_SLOT_CAP_HPS) 6750b035149SJohn Baldwin printf(" surprise"); 6760b035149SJohn Baldwin if (cap & PCIEM_SLOT_CAP_APB) 6770b035149SJohn Baldwin printf(" Attn Button"); 6780b035149SJohn Baldwin if (cap & PCIEM_SLOT_CAP_PCP) 679a1566487SEric van Gyzen printf(" PC(%s)", ctl & PCIEM_SLOT_CTL_PCC ? "off" : "on"); 6800b035149SJohn Baldwin if (cap & PCIEM_SLOT_CAP_MRLSP) 6810b035149SJohn Baldwin printf(" MRL(%s)", sta & PCIEM_SLOT_STA_MRLSS ? "open" : 6820b035149SJohn Baldwin "closed"); 683a1566487SEric van Gyzen if (cap & PCIEM_SLOT_CAP_EIP) 684a1566487SEric van Gyzen printf(" EI(%s)", sta & PCIEM_SLOT_STA_EIS ? "engaged" : 685a1566487SEric van Gyzen "disengaged"); 6868866f04eSJohn Baldwin } 6878866f04eSJohn Baldwin 6888866f04eSJohn Baldwin static void 6898866f04eSJohn Baldwin cap_msix(int fd, struct pci_conf *p, uint8_t ptr) 6908866f04eSJohn Baldwin { 691609933c6SNeel Natu uint32_t pba_offset, table_offset, val; 692609933c6SNeel Natu int msgnum, pba_bar, table_bar; 6938866f04eSJohn Baldwin uint16_t ctrl; 6948866f04eSJohn Baldwin 6958866f04eSJohn Baldwin ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_CTRL, 2); 6968866f04eSJohn Baldwin msgnum = (ctrl & PCIM_MSIXCTRL_TABLE_SIZE) + 1; 697609933c6SNeel Natu 6988866f04eSJohn Baldwin val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_TABLE, 4); 6998866f04eSJohn Baldwin table_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); 700609933c6SNeel Natu table_offset = val & ~PCIM_MSIX_BIR_MASK; 701609933c6SNeel Natu 7028866f04eSJohn Baldwin val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_PBA, 4); 7038866f04eSJohn Baldwin pba_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); 704609933c6SNeel Natu pba_offset = val & ~PCIM_MSIX_BIR_MASK; 705609933c6SNeel Natu 706609933c6SNeel Natu printf("MSI-X supports %d message%s%s\n", msgnum, 707609933c6SNeel Natu (msgnum == 1) ? "" : "s", 708609933c6SNeel Natu (ctrl & PCIM_MSIXCTRL_MSIX_ENABLE) ? ", enabled" : ""); 709609933c6SNeel Natu 710609933c6SNeel Natu printf(" "); 711609933c6SNeel Natu printf("Table in map 0x%x[0x%x], PBA in map 0x%x[0x%x]", 712609933c6SNeel Natu table_bar, table_offset, pba_bar, pba_offset); 7138866f04eSJohn Baldwin } 7148866f04eSJohn Baldwin 7158e6f99f6SAlexander Motin static void 716873e155cSStefan Eßer cap_sata(int fd __unused, struct pci_conf *p __unused, uint8_t ptr __unused) 7178e6f99f6SAlexander Motin { 7188e6f99f6SAlexander Motin 7198e6f99f6SAlexander Motin printf("SATA Index-Data Pair"); 7208e6f99f6SAlexander Motin } 7218e6f99f6SAlexander Motin 7228e6f99f6SAlexander Motin static void 7238e6f99f6SAlexander Motin cap_pciaf(int fd, struct pci_conf *p, uint8_t ptr) 7248e6f99f6SAlexander Motin { 7258e6f99f6SAlexander Motin uint8_t cap; 7268e6f99f6SAlexander Motin 7278e6f99f6SAlexander Motin cap = read_config(fd, &p->pc_sel, ptr + PCIR_PCIAF_CAP, 1); 7288e6f99f6SAlexander Motin printf("PCI Advanced Features:%s%s", 729f8dacb04SAlexander Motin cap & PCIM_PCIAFCAP_FLR ? " FLR" : "", 730f8dacb04SAlexander Motin cap & PCIM_PCIAFCAP_TP ? " TP" : ""); 7318e6f99f6SAlexander Motin } 7328e6f99f6SAlexander Motin 733a2862b11SWojciech Macek static const char * 734733191a5SPedro F. Giffuni ea_bei_to_name(int bei) 735a2862b11SWojciech Macek { 736a2862b11SWojciech Macek static const char *barstr[] = { 737a2862b11SWojciech Macek "BAR0", "BAR1", "BAR2", "BAR3", "BAR4", "BAR5" 738a2862b11SWojciech Macek }; 739a2862b11SWojciech Macek static const char *vfbarstr[] = { 740a2862b11SWojciech Macek "VFBAR0", "VFBAR1", "VFBAR2", "VFBAR3", "VFBAR4", "VFBAR5" 741a2862b11SWojciech Macek }; 742a2862b11SWojciech Macek 743a2862b11SWojciech Macek if ((bei >= PCIM_EA_BEI_BAR_0) && (bei <= PCIM_EA_BEI_BAR_5)) 744a2862b11SWojciech Macek return (barstr[bei - PCIM_EA_BEI_BAR_0]); 745a2862b11SWojciech Macek if ((bei >= PCIM_EA_BEI_VF_BAR_0) && (bei <= PCIM_EA_BEI_VF_BAR_5)) 746a2862b11SWojciech Macek return (vfbarstr[bei - PCIM_EA_BEI_VF_BAR_0]); 747a2862b11SWojciech Macek 748a2862b11SWojciech Macek switch (bei) { 749a2862b11SWojciech Macek case PCIM_EA_BEI_BRIDGE: 750a2862b11SWojciech Macek return "BRIDGE"; 751a2862b11SWojciech Macek case PCIM_EA_BEI_ENI: 752a2862b11SWojciech Macek return "ENI"; 753a2862b11SWojciech Macek case PCIM_EA_BEI_ROM: 754a2862b11SWojciech Macek return "ROM"; 755a2862b11SWojciech Macek case PCIM_EA_BEI_RESERVED: 756a2862b11SWojciech Macek default: 757a2862b11SWojciech Macek return "RSVD"; 758a2862b11SWojciech Macek } 759a2862b11SWojciech Macek } 760a2862b11SWojciech Macek 761a2862b11SWojciech Macek static const char * 762a2862b11SWojciech Macek ea_prop_to_name(uint8_t prop) 763a2862b11SWojciech Macek { 764a2862b11SWojciech Macek 765a2862b11SWojciech Macek switch (prop) { 766a2862b11SWojciech Macek case PCIM_EA_P_MEM: 767a2862b11SWojciech Macek return "Non-Prefetchable Memory"; 768a2862b11SWojciech Macek case PCIM_EA_P_MEM_PREFETCH: 769a2862b11SWojciech Macek return "Prefetchable Memory"; 770a2862b11SWojciech Macek case PCIM_EA_P_IO: 771a2862b11SWojciech Macek return "I/O Space"; 772a2862b11SWojciech Macek case PCIM_EA_P_VF_MEM_PREFETCH: 773a2862b11SWojciech Macek return "VF Prefetchable Memory"; 774a2862b11SWojciech Macek case PCIM_EA_P_VF_MEM: 775a2862b11SWojciech Macek return "VF Non-Prefetchable Memory"; 776a2862b11SWojciech Macek case PCIM_EA_P_BRIDGE_MEM: 777a2862b11SWojciech Macek return "Bridge Non-Prefetchable Memory"; 778a2862b11SWojciech Macek case PCIM_EA_P_BRIDGE_MEM_PREFETCH: 779a2862b11SWojciech Macek return "Bridge Prefetchable Memory"; 780a2862b11SWojciech Macek case PCIM_EA_P_BRIDGE_IO: 781a2862b11SWojciech Macek return "Bridge I/O Space"; 782a2862b11SWojciech Macek case PCIM_EA_P_MEM_RESERVED: 783a2862b11SWojciech Macek return "Reserved Memory"; 784a2862b11SWojciech Macek case PCIM_EA_P_IO_RESERVED: 785a2862b11SWojciech Macek return "Reserved I/O Space"; 786a2862b11SWojciech Macek case PCIM_EA_P_UNAVAILABLE: 787a2862b11SWojciech Macek return "Unavailable"; 788a2862b11SWojciech Macek default: 789a2862b11SWojciech Macek return "Reserved"; 790a2862b11SWojciech Macek } 791a2862b11SWojciech Macek } 792a2862b11SWojciech Macek 793a2862b11SWojciech Macek static void 794a2862b11SWojciech Macek cap_ea(int fd, struct pci_conf *p, uint8_t ptr) 795a2862b11SWojciech Macek { 796a2862b11SWojciech Macek int num_ent; 797a2862b11SWojciech Macek int a, b; 798a2862b11SWojciech Macek uint32_t bei; 799a2862b11SWojciech Macek uint32_t val; 800a2862b11SWojciech Macek int ent_size; 801a2862b11SWojciech Macek uint32_t dw[4]; 802a2862b11SWojciech Macek uint32_t flags, flags_pp, flags_sp; 803a2862b11SWojciech Macek uint64_t base, max_offset; 804a2862b11SWojciech Macek uint8_t fixed_sub_bus_nr, fixed_sec_bus_nr; 805a2862b11SWojciech Macek 806a2862b11SWojciech Macek /* Determine the number of entries */ 807a2862b11SWojciech Macek num_ent = read_config(fd, &p->pc_sel, ptr + PCIR_EA_NUM_ENT, 2); 808a2862b11SWojciech Macek num_ent &= PCIM_EA_NUM_ENT_MASK; 809a2862b11SWojciech Macek 810a2862b11SWojciech Macek printf("PCI Enhanced Allocation (%d entries)", num_ent); 811a2862b11SWojciech Macek 812a2862b11SWojciech Macek /* Find the first entry to care of */ 813a2862b11SWojciech Macek ptr += PCIR_EA_FIRST_ENT; 814a2862b11SWojciech Macek 815a2862b11SWojciech Macek /* Print BUS numbers for bridges */ 816a2862b11SWojciech Macek if ((p->pc_hdr & PCIM_HDRTYPE) == PCIM_HDRTYPE_BRIDGE) { 817a2862b11SWojciech Macek val = read_config(fd, &p->pc_sel, ptr, 4); 818a2862b11SWojciech Macek 819a2862b11SWojciech Macek fixed_sec_bus_nr = PCIM_EA_SEC_NR(val); 820a2862b11SWojciech Macek fixed_sub_bus_nr = PCIM_EA_SUB_NR(val); 821a2862b11SWojciech Macek 822a2862b11SWojciech Macek printf("\n\t\t BRIDGE, sec bus [%d], sub bus [%d]", 823a2862b11SWojciech Macek fixed_sec_bus_nr, fixed_sub_bus_nr); 824a2862b11SWojciech Macek ptr += 4; 825a2862b11SWojciech Macek } 826a2862b11SWojciech Macek 827a2862b11SWojciech Macek for (a = 0; a < num_ent; a++) { 828a2862b11SWojciech Macek /* Read a number of dwords in the entry */ 829a2862b11SWojciech Macek val = read_config(fd, &p->pc_sel, ptr, 4); 830a2862b11SWojciech Macek ptr += 4; 831a2862b11SWojciech Macek ent_size = (val & PCIM_EA_ES); 832a2862b11SWojciech Macek 833a2862b11SWojciech Macek for (b = 0; b < ent_size; b++) { 834a2862b11SWojciech Macek dw[b] = read_config(fd, &p->pc_sel, ptr, 4); 835a2862b11SWojciech Macek ptr += 4; 836a2862b11SWojciech Macek } 837a2862b11SWojciech Macek 838a2862b11SWojciech Macek flags = val; 839a2862b11SWojciech Macek flags_pp = (flags & PCIM_EA_PP) >> PCIM_EA_PP_OFFSET; 840a2862b11SWojciech Macek flags_sp = (flags & PCIM_EA_SP) >> PCIM_EA_SP_OFFSET; 841a2862b11SWojciech Macek bei = (PCIM_EA_BEI & val) >> PCIM_EA_BEI_OFFSET; 842a2862b11SWojciech Macek 843a2862b11SWojciech Macek base = dw[0] & PCIM_EA_FIELD_MASK; 844a2862b11SWojciech Macek max_offset = dw[1] | ~PCIM_EA_FIELD_MASK; 845a2862b11SWojciech Macek b = 2; 846a2862b11SWojciech Macek if (((dw[0] & PCIM_EA_IS_64) != 0) && (b < ent_size)) { 847a2862b11SWojciech Macek base |= (uint64_t)dw[b] << 32UL; 848a2862b11SWojciech Macek b++; 849a2862b11SWojciech Macek } 850a2862b11SWojciech Macek if (((dw[1] & PCIM_EA_IS_64) != 0) 851a2862b11SWojciech Macek && (b < ent_size)) { 852a2862b11SWojciech Macek max_offset |= (uint64_t)dw[b] << 32UL; 853a2862b11SWojciech Macek b++; 854a2862b11SWojciech Macek } 855a2862b11SWojciech Macek 85698179b62SWojciech Macek printf("\n\t\t [%d] %s, %s, %s, base [0x%jx], size [0x%jx]" 857a2862b11SWojciech Macek "\n\t\t\tPrimary properties [0x%x] (%s)" 858a2862b11SWojciech Macek "\n\t\t\tSecondary properties [0x%x] (%s)", 859a2862b11SWojciech Macek bei, ea_bei_to_name(bei), 860a2862b11SWojciech Macek (flags & PCIM_EA_ENABLE ? "Enabled" : "Disabled"), 861a2862b11SWojciech Macek (flags & PCIM_EA_WRITABLE ? "Writable" : "Read-only"), 86298179b62SWojciech Macek (uintmax_t)base, (uintmax_t)(max_offset + 1), 863a2862b11SWojciech Macek flags_pp, ea_prop_to_name(flags_pp), 864a2862b11SWojciech Macek flags_sp, ea_prop_to_name(flags_sp)); 865a2862b11SWojciech Macek } 866a2862b11SWojciech Macek } 867a2862b11SWojciech Macek 8688866f04eSJohn Baldwin void 86997faa4c4SScott Long list_caps(int fd, struct pci_conf *p, int level) 8708866f04eSJohn Baldwin { 871770e4c5bSJohn Baldwin int express; 87264393db3SJohn Baldwin uint16_t sta; 8738866f04eSJohn Baldwin uint8_t ptr, cap; 8748866f04eSJohn Baldwin 8758866f04eSJohn Baldwin /* Are capabilities present for this device? */ 87664393db3SJohn Baldwin sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); 87764393db3SJohn Baldwin if (!(sta & PCIM_STATUS_CAPPRESENT)) 8788866f04eSJohn Baldwin return; 8798866f04eSJohn Baldwin 88097faa4c4SScott Long cap_level = level; 88197faa4c4SScott Long 8828866f04eSJohn Baldwin switch (p->pc_hdr & PCIM_HDRTYPE) { 88364393db3SJohn Baldwin case PCIM_HDRTYPE_NORMAL: 88464393db3SJohn Baldwin case PCIM_HDRTYPE_BRIDGE: 8858866f04eSJohn Baldwin ptr = PCIR_CAP_PTR; 8868866f04eSJohn Baldwin break; 88764393db3SJohn Baldwin case PCIM_HDRTYPE_CARDBUS: 8888866f04eSJohn Baldwin ptr = PCIR_CAP_PTR_2; 8898866f04eSJohn Baldwin break; 8908866f04eSJohn Baldwin default: 8918866f04eSJohn Baldwin errx(1, "list_caps: bad header type"); 8928866f04eSJohn Baldwin } 8938866f04eSJohn Baldwin 8948866f04eSJohn Baldwin /* Walk the capability list. */ 895770e4c5bSJohn Baldwin express = 0; 8968866f04eSJohn Baldwin ptr = read_config(fd, &p->pc_sel, ptr, 1); 8978866f04eSJohn Baldwin while (ptr != 0 && ptr != 0xff) { 8988866f04eSJohn Baldwin cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1); 8998866f04eSJohn Baldwin printf(" cap %02x[%02x] = ", cap, ptr); 9008866f04eSJohn Baldwin switch (cap) { 9018866f04eSJohn Baldwin case PCIY_PMG: 9028866f04eSJohn Baldwin cap_power(fd, p, ptr); 9038866f04eSJohn Baldwin break; 9048866f04eSJohn Baldwin case PCIY_AGP: 9058866f04eSJohn Baldwin cap_agp(fd, p, ptr); 9068866f04eSJohn Baldwin break; 9078866f04eSJohn Baldwin case PCIY_VPD: 9088866f04eSJohn Baldwin cap_vpd(fd, p, ptr); 9098866f04eSJohn Baldwin break; 9108866f04eSJohn Baldwin case PCIY_MSI: 9118866f04eSJohn Baldwin cap_msi(fd, p, ptr); 9128866f04eSJohn Baldwin break; 9138866f04eSJohn Baldwin case PCIY_PCIX: 9148866f04eSJohn Baldwin cap_pcix(fd, p, ptr); 9158866f04eSJohn Baldwin break; 9168866f04eSJohn Baldwin case PCIY_HT: 9178866f04eSJohn Baldwin cap_ht(fd, p, ptr); 9188866f04eSJohn Baldwin break; 9198866f04eSJohn Baldwin case PCIY_VENDOR: 9208866f04eSJohn Baldwin cap_vendor(fd, p, ptr); 9218866f04eSJohn Baldwin break; 9228866f04eSJohn Baldwin case PCIY_DEBUG: 9238866f04eSJohn Baldwin cap_debug(fd, p, ptr); 9248866f04eSJohn Baldwin break; 9258866f04eSJohn Baldwin case PCIY_SUBVENDOR: 9268866f04eSJohn Baldwin cap_subvendor(fd, p, ptr); 9278866f04eSJohn Baldwin break; 928*1e6db7beSKonstantin Belousov case PCIY_SECDEV: 929*1e6db7beSKonstantin Belousov cap_secdev(fd, p, ptr); 930*1e6db7beSKonstantin Belousov break; 9318866f04eSJohn Baldwin case PCIY_EXPRESS: 932770e4c5bSJohn Baldwin express = 1; 9338866f04eSJohn Baldwin cap_express(fd, p, ptr); 9348866f04eSJohn Baldwin break; 9358866f04eSJohn Baldwin case PCIY_MSIX: 9368866f04eSJohn Baldwin cap_msix(fd, p, ptr); 9378866f04eSJohn Baldwin break; 9388e6f99f6SAlexander Motin case PCIY_SATA: 9398e6f99f6SAlexander Motin cap_sata(fd, p, ptr); 9408e6f99f6SAlexander Motin break; 9418e6f99f6SAlexander Motin case PCIY_PCIAF: 9428e6f99f6SAlexander Motin cap_pciaf(fd, p, ptr); 9438e6f99f6SAlexander Motin break; 944a2862b11SWojciech Macek case PCIY_EA: 945a2862b11SWojciech Macek cap_ea(fd, p, ptr); 946a2862b11SWojciech Macek break; 9478866f04eSJohn Baldwin default: 9488866f04eSJohn Baldwin printf("unknown"); 9498866f04eSJohn Baldwin break; 9508866f04eSJohn Baldwin } 9518866f04eSJohn Baldwin printf("\n"); 9528866f04eSJohn Baldwin ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1); 9538866f04eSJohn Baldwin } 95479c2de35SJohn Baldwin 955770e4c5bSJohn Baldwin if (express) 95679c2de35SJohn Baldwin list_ecaps(fd, p); 95779c2de35SJohn Baldwin } 95879c2de35SJohn Baldwin 95979c2de35SJohn Baldwin /* From <sys/systm.h>. */ 96079c2de35SJohn Baldwin static __inline uint32_t 96179c2de35SJohn Baldwin bitcount32(uint32_t x) 96279c2de35SJohn Baldwin { 96379c2de35SJohn Baldwin 96479c2de35SJohn Baldwin x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1); 96579c2de35SJohn Baldwin x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2); 96679c2de35SJohn Baldwin x = (x + (x >> 4)) & 0x0f0f0f0f; 96779c2de35SJohn Baldwin x = (x + (x >> 8)); 96879c2de35SJohn Baldwin x = (x + (x >> 16)) & 0x000000ff; 96979c2de35SJohn Baldwin return (x); 97079c2de35SJohn Baldwin } 97179c2de35SJohn Baldwin 97279c2de35SJohn Baldwin static void 97379c2de35SJohn Baldwin ecap_aer(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 97479c2de35SJohn Baldwin { 97579c2de35SJohn Baldwin uint32_t sta, mask; 97679c2de35SJohn Baldwin 97779c2de35SJohn Baldwin printf("AER %d", ver); 9782f176a2bSDavid Bright if (ver < 1) { 9792f176a2bSDavid Bright printf("\n"); 98079c2de35SJohn Baldwin return; 9812f176a2bSDavid Bright } 98279c2de35SJohn Baldwin sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_STATUS, 4); 98379c2de35SJohn Baldwin mask = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_SEVERITY, 4); 98479c2de35SJohn Baldwin printf(" %d fatal", bitcount32(sta & mask)); 98579c2de35SJohn Baldwin printf(" %d non-fatal", bitcount32(sta & ~mask)); 98679c2de35SJohn Baldwin sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_COR_STATUS, 4); 9877fdbba5eSRyan Stone printf(" %d corrected\n", bitcount32(sta)); 98879c2de35SJohn Baldwin } 98979c2de35SJohn Baldwin 99079c2de35SJohn Baldwin static void 99179c2de35SJohn Baldwin ecap_vc(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 99279c2de35SJohn Baldwin { 99379c2de35SJohn Baldwin uint32_t cap1; 99479c2de35SJohn Baldwin 99579c2de35SJohn Baldwin printf("VC %d", ver); 9962f176a2bSDavid Bright if (ver < 1) { 9972f176a2bSDavid Bright printf("\n"); 99879c2de35SJohn Baldwin return; 9992f176a2bSDavid Bright } 100079c2de35SJohn Baldwin cap1 = read_config(fd, &p->pc_sel, ptr + PCIR_VC_CAP1, 4); 100179c2de35SJohn Baldwin printf(" max VC%d", cap1 & PCIM_VC_CAP1_EXT_COUNT); 100279c2de35SJohn Baldwin if ((cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) != 0) 100379c2de35SJohn Baldwin printf(" lowpri VC0-VC%d", 100479c2de35SJohn Baldwin (cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) >> 4); 10057fdbba5eSRyan Stone printf("\n"); 100679c2de35SJohn Baldwin } 100779c2de35SJohn Baldwin 100879c2de35SJohn Baldwin static void 100979c2de35SJohn Baldwin ecap_sernum(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 101079c2de35SJohn Baldwin { 101179c2de35SJohn Baldwin uint32_t high, low; 101279c2de35SJohn Baldwin 101379c2de35SJohn Baldwin printf("Serial %d", ver); 10142f176a2bSDavid Bright if (ver < 1) { 10152f176a2bSDavid Bright printf("\n"); 101679c2de35SJohn Baldwin return; 10172f176a2bSDavid Bright } 101879c2de35SJohn Baldwin low = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_LOW, 4); 101979c2de35SJohn Baldwin high = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_HIGH, 4); 10207fdbba5eSRyan Stone printf(" %08x%08x\n", high, low); 102179c2de35SJohn Baldwin } 102279c2de35SJohn Baldwin 102379c2de35SJohn Baldwin static void 102460149b5cSJohn Baldwin ecap_vendor(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 102560149b5cSJohn Baldwin { 102697faa4c4SScott Long uint32_t val, hdr; 102797faa4c4SScott Long uint16_t nextptr, len; 102897faa4c4SScott Long int i; 102960149b5cSJohn Baldwin 103097faa4c4SScott Long val = read_config(fd, &p->pc_sel, ptr, 4); 103197faa4c4SScott Long nextptr = PCI_EXTCAP_NEXTPTR(val); 103297faa4c4SScott Long hdr = read_config(fd, &p->pc_sel, ptr + PCIR_VSEC_HEADER, 4); 103397faa4c4SScott Long len = PCIR_VSEC_LENGTH(hdr); 103497faa4c4SScott Long if (len == 0) { 103597faa4c4SScott Long if (nextptr == 0) 103697faa4c4SScott Long nextptr = 0x1000; 103797faa4c4SScott Long len = nextptr - ptr; 103897faa4c4SScott Long } 103997faa4c4SScott Long 104097faa4c4SScott Long printf("Vendor [%d] ID %04x Rev %d Length %d\n", ver, 104197faa4c4SScott Long PCIR_VSEC_ID(hdr), PCIR_VSEC_REV(hdr), len); 104297faa4c4SScott Long if ((ver < 1) || (cap_level <= 1)) 104360149b5cSJohn Baldwin return; 104497faa4c4SScott Long for (i = 0; i < len; i += 4) { 1045e1ae0ee1SScott Long val = read_config(fd, &p->pc_sel, ptr + i, 4); 104697faa4c4SScott Long if ((i % 16) == 0) 104797faa4c4SScott Long printf(" "); 104897faa4c4SScott Long printf("%02x %02x %02x %02x", val & 0xff, (val >> 8) & 0xff, 104997faa4c4SScott Long (val >> 16) & 0xff, (val >> 24) & 0xff); 105097faa4c4SScott Long if ((((i + 4) % 16) == 0 ) || ((i + 4) >= len)) 105197faa4c4SScott Long printf("\n"); 1052e1ae0ee1SScott Long else 1053e1ae0ee1SScott Long printf(" "); 105497faa4c4SScott Long } 105560149b5cSJohn Baldwin } 105660149b5cSJohn Baldwin 105760149b5cSJohn Baldwin static void 105860149b5cSJohn Baldwin ecap_sec_pcie(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 105960149b5cSJohn Baldwin { 106060149b5cSJohn Baldwin uint32_t val; 106160149b5cSJohn Baldwin 106260149b5cSJohn Baldwin printf("PCIe Sec %d", ver); 10632f176a2bSDavid Bright if (ver < 1) { 10642f176a2bSDavid Bright printf("\n"); 106560149b5cSJohn Baldwin return; 10662f176a2bSDavid Bright } 106760149b5cSJohn Baldwin val = read_config(fd, &p->pc_sel, ptr + 8, 4); 10687fdbba5eSRyan Stone printf(" lane errors %#x\n", val); 10697fdbba5eSRyan Stone } 10707fdbba5eSRyan Stone 10717fdbba5eSRyan Stone static const char * 10727fdbba5eSRyan Stone check_enabled(int value) 10737fdbba5eSRyan Stone { 10747fdbba5eSRyan Stone 10757fdbba5eSRyan Stone return (value ? "enabled" : "disabled"); 10767fdbba5eSRyan Stone } 10777fdbba5eSRyan Stone 10787fdbba5eSRyan Stone static void 10797fdbba5eSRyan Stone ecap_sriov(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 10807fdbba5eSRyan Stone { 10817fdbba5eSRyan Stone const char *comma, *enabled; 10827fdbba5eSRyan Stone uint16_t iov_ctl, total_vfs, num_vfs, vf_offset, vf_stride, vf_did; 10837fdbba5eSRyan Stone uint32_t page_caps, page_size, page_shift, size; 10847fdbba5eSRyan Stone int i; 10857fdbba5eSRyan Stone 10867fdbba5eSRyan Stone printf("SR-IOV %d ", ver); 10877fdbba5eSRyan Stone 10887fdbba5eSRyan Stone iov_ctl = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_CTL, 2); 10897fdbba5eSRyan Stone printf("IOV %s, Memory Space %s, ARI %s\n", 10907fdbba5eSRyan Stone check_enabled(iov_ctl & PCIM_SRIOV_VF_EN), 10917fdbba5eSRyan Stone check_enabled(iov_ctl & PCIM_SRIOV_VF_MSE), 10927fdbba5eSRyan Stone check_enabled(iov_ctl & PCIM_SRIOV_ARI_EN)); 10937fdbba5eSRyan Stone 10947fdbba5eSRyan Stone total_vfs = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_TOTAL_VFS, 2); 10957fdbba5eSRyan Stone num_vfs = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_NUM_VFS, 2); 10967fdbba5eSRyan Stone printf(" "); 10977fdbba5eSRyan Stone printf("%d VFs configured out of %d supported\n", num_vfs, total_vfs); 10987fdbba5eSRyan Stone 10997fdbba5eSRyan Stone vf_offset = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_VF_OFF, 2); 11007fdbba5eSRyan Stone vf_stride = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_VF_STRIDE, 2); 11017fdbba5eSRyan Stone printf(" "); 11027fdbba5eSRyan Stone printf("First VF RID Offset 0x%04x, VF RID Stride 0x%04x\n", vf_offset, 11037fdbba5eSRyan Stone vf_stride); 11047fdbba5eSRyan Stone 11057fdbba5eSRyan Stone vf_did = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_VF_DID, 2); 11067fdbba5eSRyan Stone printf(" VF Device ID 0x%04x\n", vf_did); 11077fdbba5eSRyan Stone 11087fdbba5eSRyan Stone page_caps = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_PAGE_CAP, 4); 11097fdbba5eSRyan Stone page_size = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_PAGE_SIZE, 4); 11107fdbba5eSRyan Stone printf(" "); 11117fdbba5eSRyan Stone printf("Page Sizes: "); 11127fdbba5eSRyan Stone comma = ""; 11137fdbba5eSRyan Stone while (page_caps != 0) { 11147fdbba5eSRyan Stone page_shift = ffs(page_caps) - 1; 11157fdbba5eSRyan Stone 11167fdbba5eSRyan Stone if (page_caps & page_size) 11177fdbba5eSRyan Stone enabled = " (enabled)"; 11187fdbba5eSRyan Stone else 11197fdbba5eSRyan Stone enabled = ""; 11207fdbba5eSRyan Stone 11217fdbba5eSRyan Stone size = (1 << (page_shift + PCI_SRIOV_BASE_PAGE_SHIFT)); 11227fdbba5eSRyan Stone printf("%s%d%s", comma, size, enabled); 11237fdbba5eSRyan Stone comma = ", "; 11247fdbba5eSRyan Stone 11257fdbba5eSRyan Stone page_caps &= ~(1 << page_shift); 11267fdbba5eSRyan Stone } 11277fdbba5eSRyan Stone printf("\n"); 11287fdbba5eSRyan Stone 11297fdbba5eSRyan Stone for (i = 0; i <= PCIR_MAX_BAR_0; i++) 11307fdbba5eSRyan Stone print_bar(fd, p, "iov bar ", ptr + PCIR_SRIOV_BAR(i)); 113160149b5cSJohn Baldwin } 113260149b5cSJohn Baldwin 1133118cfb82SNavdeep Parhar static const char * 1134118cfb82SNavdeep Parhar check_avail_and_state(u_int cap, u_int capbit, u_int ctl, u_int ctlbit) 1135118cfb82SNavdeep Parhar { 1136118cfb82SNavdeep Parhar 1137118cfb82SNavdeep Parhar if (cap & capbit) 1138118cfb82SNavdeep Parhar return (ctl & ctlbit ? "enabled" : "disabled"); 1139118cfb82SNavdeep Parhar else 1140118cfb82SNavdeep Parhar return "unavailable"; 1141118cfb82SNavdeep Parhar } 1142118cfb82SNavdeep Parhar 1143118cfb82SNavdeep Parhar static void 1144118cfb82SNavdeep Parhar ecap_acs(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 1145118cfb82SNavdeep Parhar { 1146118cfb82SNavdeep Parhar uint16_t acs_cap, acs_ctl; 1147118cfb82SNavdeep Parhar static const char *const acc[] = { "access enabled", "blocking enabled", 1148118cfb82SNavdeep Parhar "redirect enabled", "reserved" }; 1149118cfb82SNavdeep Parhar 1150118cfb82SNavdeep Parhar printf("ACS %d ", ver); 1151118cfb82SNavdeep Parhar if (ver != 1) { 1152118cfb82SNavdeep Parhar printf("\n"); 1153118cfb82SNavdeep Parhar return; 1154118cfb82SNavdeep Parhar } 1155118cfb82SNavdeep Parhar 1156118cfb82SNavdeep Parhar #define CHECK_AVAIL_STATE(bit) \ 1157118cfb82SNavdeep Parhar check_avail_and_state(acs_cap, bit, acs_ctl, bit##_ENABLE) 1158118cfb82SNavdeep Parhar 1159118cfb82SNavdeep Parhar acs_cap = read_config(fd, &p->pc_sel, ptr + PCIR_ACS_CAP, 2); 1160118cfb82SNavdeep Parhar acs_ctl = read_config(fd, &p->pc_sel, ptr + PCIR_ACS_CTL, 2); 1161118cfb82SNavdeep Parhar printf("Source Validation %s, Translation Blocking %s\n", 1162118cfb82SNavdeep Parhar CHECK_AVAIL_STATE(PCIM_ACS_SOURCE_VALIDATION), 1163118cfb82SNavdeep Parhar CHECK_AVAIL_STATE(PCIM_ACS_TRANSLATION_BLOCKING)); 1164118cfb82SNavdeep Parhar 1165118cfb82SNavdeep Parhar printf(" "); 1166118cfb82SNavdeep Parhar printf("P2P Req Redirect %s, P2P Cmpl Redirect %s\n", 1167118cfb82SNavdeep Parhar CHECK_AVAIL_STATE(PCIM_ACS_P2P_REQ_REDIRECT), 1168118cfb82SNavdeep Parhar CHECK_AVAIL_STATE(PCIM_ACS_P2P_CMP_REDIRECT)); 1169118cfb82SNavdeep Parhar printf(" "); 1170118cfb82SNavdeep Parhar printf("P2P Upstream Forwarding %s, P2P Egress Control %s\n", 1171118cfb82SNavdeep Parhar CHECK_AVAIL_STATE(PCIM_ACS_P2P_UPSTREAM_FORWARDING), 1172118cfb82SNavdeep Parhar CHECK_AVAIL_STATE(PCIM_ACS_P2P_EGRESS_CTL)); 1173118cfb82SNavdeep Parhar printf(" "); 1174118cfb82SNavdeep Parhar printf("P2P Direct Translated %s, Enhanced Capability %s\n", 1175118cfb82SNavdeep Parhar CHECK_AVAIL_STATE(PCIM_ACS_P2P_DIRECT_TRANSLATED), 1176118cfb82SNavdeep Parhar acs_ctl & PCIM_ACS_ENHANCED_CAP ? "available" : "unavailable"); 1177118cfb82SNavdeep Parhar #undef CHECK_AVAIL_STATE 1178118cfb82SNavdeep Parhar 1179118cfb82SNavdeep Parhar if (acs_cap & PCIM_ACS_ENHANCED_CAP) { 1180118cfb82SNavdeep Parhar printf(" "); 1181118cfb82SNavdeep Parhar printf("I/O Req Blocking %s, Unclaimed Req Redirect Control %s\n", 1182118cfb82SNavdeep Parhar check_enabled(acs_ctl & PCIM_ACS_IO_REQ_BLOCKING_ENABLE), 1183118cfb82SNavdeep Parhar check_enabled(acs_ctl & PCIM_ACS_UNCLAIMED_REQ_REDIRECT_CTL)); 1184118cfb82SNavdeep Parhar printf(" "); 1185118cfb82SNavdeep Parhar printf("DSP BAR %s, USP BAR %s\n", 1186118cfb82SNavdeep Parhar acc[(acs_cap & PCIM_ACS_DSP_MEM_TGT_ACC_CTL) >> 8], 1187118cfb82SNavdeep Parhar acc[(acs_cap & PCIM_ACS_USP_MEM_TGT_ACC_CTL) >> 10]); 1188118cfb82SNavdeep Parhar } 1189118cfb82SNavdeep Parhar } 1190118cfb82SNavdeep Parhar 1191a4ed9e4fSStefan Eßer static struct { 119260149b5cSJohn Baldwin uint16_t id; 119360149b5cSJohn Baldwin const char *name; 119460149b5cSJohn Baldwin } ecap_names[] = { 11953b7a70d9SKonstantin Belousov { PCIZ_AER, "AER" }, 11963b7a70d9SKonstantin Belousov { PCIZ_VC, "Virtual Channel" }, 11973b7a70d9SKonstantin Belousov { PCIZ_SERNUM, "Device Serial Number" }, 119860149b5cSJohn Baldwin { PCIZ_PWRBDGT, "Power Budgeting" }, 119960149b5cSJohn Baldwin { PCIZ_RCLINK_DCL, "Root Complex Link Declaration" }, 120060149b5cSJohn Baldwin { PCIZ_RCLINK_CTL, "Root Complex Internal Link Control" }, 120160149b5cSJohn Baldwin { PCIZ_RCEC_ASSOC, "Root Complex Event Collector ASsociation" }, 120260149b5cSJohn Baldwin { PCIZ_MFVC, "MFVC" }, 12033b7a70d9SKonstantin Belousov { PCIZ_VC2, "Virtual Channel 2" }, 120460149b5cSJohn Baldwin { PCIZ_RCRB, "RCRB" }, 12053b7a70d9SKonstantin Belousov { PCIZ_CAC, "Configuration Access Correction" }, 120660149b5cSJohn Baldwin { PCIZ_ACS, "ACS" }, 120760149b5cSJohn Baldwin { PCIZ_ARI, "ARI" }, 120860149b5cSJohn Baldwin { PCIZ_ATS, "ATS" }, 12093b7a70d9SKonstantin Belousov { PCIZ_SRIOV, "SRIOV" }, 12103b7a70d9SKonstantin Belousov { PCIZ_MRIOV, "MRIOV" }, 121160149b5cSJohn Baldwin { PCIZ_MULTICAST, "Multicast" }, 12123b7a70d9SKonstantin Belousov { PCIZ_PAGE_REQ, "Page Page Request" }, 12133b7a70d9SKonstantin Belousov { PCIZ_AMD, "AMD proprietary "}, 121460149b5cSJohn Baldwin { PCIZ_RESIZE_BAR, "Resizable BAR" }, 121560149b5cSJohn Baldwin { PCIZ_DPA, "DPA" }, 121660149b5cSJohn Baldwin { PCIZ_TPH_REQ, "TPH Requester" }, 121760149b5cSJohn Baldwin { PCIZ_LTR, "LTR" }, 12183b7a70d9SKonstantin Belousov { PCIZ_SEC_PCIE, "Secondary PCI Express" }, 12193b7a70d9SKonstantin Belousov { PCIZ_PMUX, "Protocol Multiplexing" }, 12203b7a70d9SKonstantin Belousov { PCIZ_PASID, "Process Address Space ID" }, 12213b7a70d9SKonstantin Belousov { PCIZ_LN_REQ, "LN Requester" }, 12223b7a70d9SKonstantin Belousov { PCIZ_DPC, "Downstream Port Containment" }, 12233b7a70d9SKonstantin Belousov { PCIZ_L1PM, "L1 PM Substates" }, 1224f1bbdf87SKonstantin Belousov { PCIZ_PTM, "Precision Time Measurement" }, 1225f1bbdf87SKonstantin Belousov { PCIZ_M_PCIE, "PCIe over M-PHY" }, 1226f1bbdf87SKonstantin Belousov { PCIZ_FRS, "FRS Queuing" }, 1227f1bbdf87SKonstantin Belousov { PCIZ_RTR, "Readiness Time Reporting" }, 1228f1bbdf87SKonstantin Belousov { PCIZ_DVSEC, "Designated Vendor-Specific" }, 1229f1bbdf87SKonstantin Belousov { PCIZ_VF_REBAR, "VF Resizable BAR" }, 1230f1bbdf87SKonstantin Belousov { PCIZ_DLNK, "Data Link Feature" }, 1231f1bbdf87SKonstantin Belousov { PCIZ_16GT, "Physical Layer 16.0 GT/s" }, 1232f1bbdf87SKonstantin Belousov { PCIZ_LMR, "Lane Margining at Receiver" }, 1233f1bbdf87SKonstantin Belousov { PCIZ_HIER_ID, "Hierarchy ID" }, 1234f1bbdf87SKonstantin Belousov { PCIZ_NPEM, "Native PCIe Enclosure Management" }, 1235f1bbdf87SKonstantin Belousov { PCIZ_PL32, "Physical Layer 32.0 GT/s" }, 1236f1bbdf87SKonstantin Belousov { PCIZ_AP, "Alternate Protocol" }, 1237f1bbdf87SKonstantin Belousov { PCIZ_SFI, "System Firmware Intermediary" }, 123860149b5cSJohn Baldwin { 0, NULL } 123960149b5cSJohn Baldwin }; 124060149b5cSJohn Baldwin 124160149b5cSJohn Baldwin static void 124279c2de35SJohn Baldwin list_ecaps(int fd, struct pci_conf *p) 124379c2de35SJohn Baldwin { 124460149b5cSJohn Baldwin const char *name; 124579c2de35SJohn Baldwin uint32_t ecap; 124679c2de35SJohn Baldwin uint16_t ptr; 124760149b5cSJohn Baldwin int i; 124879c2de35SJohn Baldwin 124979c2de35SJohn Baldwin ptr = PCIR_EXTCAP; 125079c2de35SJohn Baldwin ecap = read_config(fd, &p->pc_sel, ptr, 4); 125179c2de35SJohn Baldwin if (ecap == 0xffffffff || ecap == 0) 125279c2de35SJohn Baldwin return; 125379c2de35SJohn Baldwin for (;;) { 125479c2de35SJohn Baldwin printf(" ecap %04x[%03x] = ", PCI_EXTCAP_ID(ecap), ptr); 125579c2de35SJohn Baldwin switch (PCI_EXTCAP_ID(ecap)) { 125679c2de35SJohn Baldwin case PCIZ_AER: 125779c2de35SJohn Baldwin ecap_aer(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 125879c2de35SJohn Baldwin break; 125979c2de35SJohn Baldwin case PCIZ_VC: 126079c2de35SJohn Baldwin ecap_vc(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 126179c2de35SJohn Baldwin break; 126279c2de35SJohn Baldwin case PCIZ_SERNUM: 126379c2de35SJohn Baldwin ecap_sernum(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 126479c2de35SJohn Baldwin break; 126560149b5cSJohn Baldwin case PCIZ_VENDOR: 126660149b5cSJohn Baldwin ecap_vendor(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 126760149b5cSJohn Baldwin break; 126860149b5cSJohn Baldwin case PCIZ_SEC_PCIE: 126960149b5cSJohn Baldwin ecap_sec_pcie(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 127060149b5cSJohn Baldwin break; 12717fdbba5eSRyan Stone case PCIZ_SRIOV: 12727fdbba5eSRyan Stone ecap_sriov(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 12737fdbba5eSRyan Stone break; 1274118cfb82SNavdeep Parhar case PCIZ_ACS: 1275118cfb82SNavdeep Parhar ecap_acs(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 1276118cfb82SNavdeep Parhar break; 127779c2de35SJohn Baldwin default: 127860149b5cSJohn Baldwin name = "unknown"; 127960149b5cSJohn Baldwin for (i = 0; ecap_names[i].name != NULL; i++) 128060149b5cSJohn Baldwin if (ecap_names[i].id == PCI_EXTCAP_ID(ecap)) { 128160149b5cSJohn Baldwin name = ecap_names[i].name; 128260149b5cSJohn Baldwin break; 128360149b5cSJohn Baldwin } 12847fdbba5eSRyan Stone printf("%s %d\n", name, PCI_EXTCAP_VER(ecap)); 128579c2de35SJohn Baldwin break; 128679c2de35SJohn Baldwin } 128779c2de35SJohn Baldwin ptr = PCI_EXTCAP_NEXTPTR(ecap); 128879c2de35SJohn Baldwin if (ptr == 0) 128979c2de35SJohn Baldwin break; 129079c2de35SJohn Baldwin ecap = read_config(fd, &p->pc_sel, ptr, 4); 129179c2de35SJohn Baldwin } 12928866f04eSJohn Baldwin } 1293b6de0055SJohn Baldwin 1294b6de0055SJohn Baldwin /* Find offset of a specific capability. Returns 0 on failure. */ 1295b6de0055SJohn Baldwin uint8_t 1296b6de0055SJohn Baldwin pci_find_cap(int fd, struct pci_conf *p, uint8_t id) 1297b6de0055SJohn Baldwin { 1298b6de0055SJohn Baldwin uint16_t sta; 1299b6de0055SJohn Baldwin uint8_t ptr, cap; 1300b6de0055SJohn Baldwin 1301b6de0055SJohn Baldwin /* Are capabilities present for this device? */ 1302b6de0055SJohn Baldwin sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); 1303b6de0055SJohn Baldwin if (!(sta & PCIM_STATUS_CAPPRESENT)) 1304b6de0055SJohn Baldwin return (0); 1305b6de0055SJohn Baldwin 1306b6de0055SJohn Baldwin switch (p->pc_hdr & PCIM_HDRTYPE) { 1307b6de0055SJohn Baldwin case PCIM_HDRTYPE_NORMAL: 1308b6de0055SJohn Baldwin case PCIM_HDRTYPE_BRIDGE: 1309b6de0055SJohn Baldwin ptr = PCIR_CAP_PTR; 1310b6de0055SJohn Baldwin break; 1311b6de0055SJohn Baldwin case PCIM_HDRTYPE_CARDBUS: 1312b6de0055SJohn Baldwin ptr = PCIR_CAP_PTR_2; 1313b6de0055SJohn Baldwin break; 1314b6de0055SJohn Baldwin default: 1315b6de0055SJohn Baldwin return (0); 1316b6de0055SJohn Baldwin } 1317b6de0055SJohn Baldwin 1318b6de0055SJohn Baldwin ptr = read_config(fd, &p->pc_sel, ptr, 1); 1319b6de0055SJohn Baldwin while (ptr != 0 && ptr != 0xff) { 1320b6de0055SJohn Baldwin cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1); 1321b6de0055SJohn Baldwin if (cap == id) 1322b6de0055SJohn Baldwin return (ptr); 1323b6de0055SJohn Baldwin ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1); 1324b6de0055SJohn Baldwin } 1325b6de0055SJohn Baldwin return (0); 1326b6de0055SJohn Baldwin } 1327b6de0055SJohn Baldwin 1328b6de0055SJohn Baldwin /* Find offset of a specific extended capability. Returns 0 on failure. */ 1329b6de0055SJohn Baldwin uint16_t 1330b6de0055SJohn Baldwin pcie_find_cap(int fd, struct pci_conf *p, uint16_t id) 1331b6de0055SJohn Baldwin { 1332b6de0055SJohn Baldwin uint32_t ecap; 1333b6de0055SJohn Baldwin uint16_t ptr; 1334b6de0055SJohn Baldwin 1335b6de0055SJohn Baldwin ptr = PCIR_EXTCAP; 1336b6de0055SJohn Baldwin ecap = read_config(fd, &p->pc_sel, ptr, 4); 1337b6de0055SJohn Baldwin if (ecap == 0xffffffff || ecap == 0) 1338b6de0055SJohn Baldwin return (0); 1339b6de0055SJohn Baldwin for (;;) { 1340b6de0055SJohn Baldwin if (PCI_EXTCAP_ID(ecap) == id) 1341b6de0055SJohn Baldwin return (ptr); 1342b6de0055SJohn Baldwin ptr = PCI_EXTCAP_NEXTPTR(ecap); 1343b6de0055SJohn Baldwin if (ptr == 0) 1344b6de0055SJohn Baldwin break; 1345b6de0055SJohn Baldwin ecap = read_config(fd, &p->pc_sel, ptr, 4); 1346b6de0055SJohn Baldwin } 1347b6de0055SJohn Baldwin return (0); 1348b6de0055SJohn Baldwin } 1349