1166435Sjhb/*- 2173228Sjhb * Copyright (c) 2007 Yahoo!, Inc. 3166435Sjhb * All rights reserved. 4173228Sjhb * Written by: John Baldwin <jhb@FreeBSD.org> 5166435Sjhb * 6166435Sjhb * Redistribution and use in source and binary forms, with or without 7166435Sjhb * modification, are permitted provided that the following conditions 8166435Sjhb * are met: 9166435Sjhb * 1. Redistributions of source code must retain the above copyright 10166435Sjhb * notice, this list of conditions and the following disclaimer. 11166435Sjhb * 2. Redistributions in binary form must reproduce the above copyright 12166435Sjhb * notice, this list of conditions and the following disclaimer in the 13166435Sjhb * documentation and/or other materials provided with the distribution. 14166435Sjhb * 3. Neither the name of the author nor the names of any co-contributors 15166435Sjhb * may be used to endorse or promote products derived from this software 16166435Sjhb * without specific prior written permission. 17166435Sjhb * 18166435Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19166435Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20166435Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21166435Sjhb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22166435Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23166435Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24166435Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25166435Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26166435Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27166435Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28166435Sjhb * SUCH DAMAGE. 29166435Sjhb */ 30166435Sjhb 31166435Sjhb#ifndef lint 32166435Sjhbstatic const char rcsid[] = 33166435Sjhb "$FreeBSD: releng/11.0/usr.sbin/pciconf/cap.c 303835 2016-08-08 15:07:38Z vangyzen $"; 34166435Sjhb#endif /* not lint */ 35166435Sjhb 36166435Sjhb#include <sys/types.h> 37166435Sjhb 38166435Sjhb#include <err.h> 39166435Sjhb#include <stdio.h> 40279466Srstone#include <strings.h> 41166435Sjhb#include <sys/agpio.h> 42166435Sjhb#include <sys/pciio.h> 43166435Sjhb 44173576Sjb#include <dev/agp/agpreg.h> 45166435Sjhb#include <dev/pci/pcireg.h> 46166435Sjhb 47166435Sjhb#include "pciconf.h" 48166435Sjhb 49212326Sjhbstatic void list_ecaps(int fd, struct pci_conf *p); 50212326Sjhb 51166435Sjhbstatic void 52166435Sjhbcap_power(int fd, struct pci_conf *p, uint8_t ptr) 53166435Sjhb{ 54166435Sjhb uint16_t cap, status; 55166435Sjhb 56166435Sjhb cap = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_CAP, 2); 57166435Sjhb status = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_STATUS, 2); 58166435Sjhb printf("powerspec %d supports D0%s%s D3 current D%d", 59166435Sjhb cap & PCIM_PCAP_SPEC, 60166435Sjhb cap & PCIM_PCAP_D1SUPP ? " D1" : "", 61166435Sjhb cap & PCIM_PCAP_D2SUPP ? " D2" : "", 62166435Sjhb status & PCIM_PSTAT_DMASK); 63166435Sjhb} 64166435Sjhb 65166435Sjhbstatic void 66166435Sjhbcap_agp(int fd, struct pci_conf *p, uint8_t ptr) 67166435Sjhb{ 68166435Sjhb uint32_t status, command; 69166435Sjhb 70166435Sjhb status = read_config(fd, &p->pc_sel, ptr + AGP_STATUS, 4); 71166435Sjhb command = read_config(fd, &p->pc_sel, ptr + AGP_CAPID, 4); 72166435Sjhb printf("AGP "); 73166435Sjhb if (AGP_MODE_GET_MODE_3(status)) { 74166435Sjhb printf("v3 "); 75166435Sjhb if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_8x) 76166435Sjhb printf("8x "); 77166435Sjhb if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_4x) 78166435Sjhb printf("4x "); 79166435Sjhb } else { 80166435Sjhb if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_4x) 81166435Sjhb printf("4x "); 82166435Sjhb if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_2x) 83166435Sjhb printf("2x "); 84166435Sjhb if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_1x) 85166435Sjhb printf("1x "); 86166435Sjhb } 87166435Sjhb if (AGP_MODE_GET_SBA(status)) 88166435Sjhb printf("SBA "); 89166435Sjhb if (AGP_MODE_GET_AGP(command)) { 90166435Sjhb printf("enabled at "); 91166435Sjhb if (AGP_MODE_GET_MODE_3(command)) { 92166435Sjhb printf("v3 "); 93166435Sjhb switch (AGP_MODE_GET_RATE(command)) { 94166435Sjhb case AGP_MODE_V3_RATE_8x: 95166435Sjhb printf("8x "); 96166435Sjhb break; 97166435Sjhb case AGP_MODE_V3_RATE_4x: 98166435Sjhb printf("4x "); 99166435Sjhb break; 100166435Sjhb } 101166435Sjhb } else 102166435Sjhb switch (AGP_MODE_GET_RATE(command)) { 103166435Sjhb case AGP_MODE_V2_RATE_4x: 104166435Sjhb printf("4x "); 105166435Sjhb break; 106166435Sjhb case AGP_MODE_V2_RATE_2x: 107166435Sjhb printf("2x "); 108166435Sjhb break; 109166435Sjhb case AGP_MODE_V2_RATE_1x: 110166435Sjhb printf("1x "); 111166435Sjhb break; 112166435Sjhb } 113166435Sjhb if (AGP_MODE_GET_SBA(command)) 114166435Sjhb printf("SBA "); 115166435Sjhb } else 116166435Sjhb printf("disabled"); 117166435Sjhb} 118166435Sjhb 119166435Sjhbstatic void 120295769Ssecap_vpd(int fd __unused, struct pci_conf *p __unused, uint8_t ptr __unused) 121166435Sjhb{ 122166435Sjhb 123166435Sjhb printf("VPD"); 124166435Sjhb} 125166435Sjhb 126166435Sjhbstatic void 127166435Sjhbcap_msi(int fd, struct pci_conf *p, uint8_t ptr) 128166435Sjhb{ 129166435Sjhb uint16_t ctrl; 130166435Sjhb int msgnum; 131166435Sjhb 132166435Sjhb ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSI_CTRL, 2); 133166435Sjhb msgnum = 1 << ((ctrl & PCIM_MSICTRL_MMC_MASK) >> 1); 134166435Sjhb printf("MSI supports %d message%s%s%s ", msgnum, 135166435Sjhb (msgnum == 1) ? "" : "s", 136166435Sjhb (ctrl & PCIM_MSICTRL_64BIT) ? ", 64 bit" : "", 137166435Sjhb (ctrl & PCIM_MSICTRL_VECTOR) ? ", vector masks" : ""); 138166435Sjhb if (ctrl & PCIM_MSICTRL_MSI_ENABLE) { 139166435Sjhb msgnum = 1 << ((ctrl & PCIM_MSICTRL_MME_MASK) >> 4); 140166435Sjhb printf("enabled with %d message%s", msgnum, 141166435Sjhb (msgnum == 1) ? "" : "s"); 142166435Sjhb } 143166435Sjhb} 144166435Sjhb 145166435Sjhbstatic void 146166435Sjhbcap_pcix(int fd, struct pci_conf *p, uint8_t ptr) 147166435Sjhb{ 148166435Sjhb uint32_t status; 149166435Sjhb int comma, max_splits, max_burst_read; 150166435Sjhb 151166435Sjhb status = read_config(fd, &p->pc_sel, ptr + PCIXR_STATUS, 4); 152166435Sjhb printf("PCI-X "); 153166435Sjhb if (status & PCIXM_STATUS_64BIT) 154166435Sjhb printf("64-bit "); 155166435Sjhb if ((p->pc_hdr & PCIM_HDRTYPE) == 1) 156166435Sjhb printf("bridge "); 157191222Sjhb if ((p->pc_hdr & PCIM_HDRTYPE) != 1 || (status & (PCIXM_STATUS_133CAP | 158191222Sjhb PCIXM_STATUS_266CAP | PCIXM_STATUS_533CAP)) != 0) 159191222Sjhb printf("supports"); 160166435Sjhb comma = 0; 161166435Sjhb if (status & PCIXM_STATUS_133CAP) { 162166435Sjhb printf("%s 133MHz", comma ? "," : ""); 163166435Sjhb comma = 1; 164166435Sjhb } 165166435Sjhb if (status & PCIXM_STATUS_266CAP) { 166166435Sjhb printf("%s 266MHz", comma ? "," : ""); 167166435Sjhb comma = 1; 168166435Sjhb } 169166435Sjhb if (status & PCIXM_STATUS_533CAP) { 170166435Sjhb printf("%s 533MHz", comma ? "," : ""); 171166435Sjhb comma = 1; 172166435Sjhb } 173166435Sjhb if ((p->pc_hdr & PCIM_HDRTYPE) == 1) 174166435Sjhb return; 175295760Sse max_burst_read = 0; 176166435Sjhb switch (status & PCIXM_STATUS_MAX_READ) { 177166435Sjhb case PCIXM_STATUS_MAX_READ_512: 178166435Sjhb max_burst_read = 512; 179166435Sjhb break; 180166435Sjhb case PCIXM_STATUS_MAX_READ_1024: 181166435Sjhb max_burst_read = 1024; 182166435Sjhb break; 183166435Sjhb case PCIXM_STATUS_MAX_READ_2048: 184166435Sjhb max_burst_read = 2048; 185166435Sjhb break; 186166435Sjhb case PCIXM_STATUS_MAX_READ_4096: 187166435Sjhb max_burst_read = 4096; 188166435Sjhb break; 189166435Sjhb } 190295760Sse max_splits = 0; 191166435Sjhb switch (status & PCIXM_STATUS_MAX_SPLITS) { 192166435Sjhb case PCIXM_STATUS_MAX_SPLITS_1: 193166435Sjhb max_splits = 1; 194166435Sjhb break; 195166435Sjhb case PCIXM_STATUS_MAX_SPLITS_2: 196166435Sjhb max_splits = 2; 197166435Sjhb break; 198166435Sjhb case PCIXM_STATUS_MAX_SPLITS_3: 199166435Sjhb max_splits = 3; 200166435Sjhb break; 201166435Sjhb case PCIXM_STATUS_MAX_SPLITS_4: 202166435Sjhb max_splits = 4; 203166435Sjhb break; 204166435Sjhb case PCIXM_STATUS_MAX_SPLITS_8: 205166435Sjhb max_splits = 8; 206166435Sjhb break; 207166435Sjhb case PCIXM_STATUS_MAX_SPLITS_12: 208166435Sjhb max_splits = 12; 209166435Sjhb break; 210166435Sjhb case PCIXM_STATUS_MAX_SPLITS_16: 211166435Sjhb max_splits = 16; 212166435Sjhb break; 213166435Sjhb case PCIXM_STATUS_MAX_SPLITS_32: 214166435Sjhb max_splits = 32; 215166435Sjhb break; 216166435Sjhb } 217166435Sjhb printf("%s %d burst read, %d split transaction%s", comma ? "," : "", 218166435Sjhb max_burst_read, max_splits, max_splits == 1 ? "" : "s"); 219166435Sjhb} 220166435Sjhb 221166435Sjhbstatic void 222166435Sjhbcap_ht(int fd, struct pci_conf *p, uint8_t ptr) 223166435Sjhb{ 224166435Sjhb uint32_t reg; 225166435Sjhb uint16_t command; 226166435Sjhb 227166435Sjhb command = read_config(fd, &p->pc_sel, ptr + PCIR_HT_COMMAND, 2); 228166435Sjhb printf("HT "); 229166435Sjhb if ((command & 0xe000) == PCIM_HTCAP_SLAVE) 230166435Sjhb printf("slave"); 231166435Sjhb else if ((command & 0xe000) == PCIM_HTCAP_HOST) 232166435Sjhb printf("host"); 233166435Sjhb else 234166435Sjhb switch (command & PCIM_HTCMD_CAP_MASK) { 235166435Sjhb case PCIM_HTCAP_SWITCH: 236166435Sjhb printf("switch"); 237166435Sjhb break; 238166435Sjhb case PCIM_HTCAP_INTERRUPT: 239166435Sjhb printf("interrupt"); 240166435Sjhb break; 241166435Sjhb case PCIM_HTCAP_REVISION_ID: 242166435Sjhb printf("revision ID"); 243166435Sjhb break; 244166435Sjhb case PCIM_HTCAP_UNITID_CLUMPING: 245166435Sjhb printf("unit ID clumping"); 246166435Sjhb break; 247166435Sjhb case PCIM_HTCAP_EXT_CONFIG_SPACE: 248166435Sjhb printf("extended config space"); 249166435Sjhb break; 250166435Sjhb case PCIM_HTCAP_ADDRESS_MAPPING: 251166435Sjhb printf("address mapping"); 252166435Sjhb break; 253166435Sjhb case PCIM_HTCAP_MSI_MAPPING: 254169037Sjhb printf("MSI %saddress window %s at 0x", 255169037Sjhb command & PCIM_HTCMD_MSI_FIXED ? "fixed " : "", 256166435Sjhb command & PCIM_HTCMD_MSI_ENABLE ? "enabled" : 257166435Sjhb "disabled"); 258169037Sjhb if (command & PCIM_HTCMD_MSI_FIXED) 259169037Sjhb printf("fee00000"); 260169037Sjhb else { 261169037Sjhb reg = read_config(fd, &p->pc_sel, 262169037Sjhb ptr + PCIR_HTMSI_ADDRESS_HI, 4); 263169037Sjhb if (reg != 0) 264169037Sjhb printf("%08x", reg); 265169037Sjhb reg = read_config(fd, &p->pc_sel, 266169037Sjhb ptr + PCIR_HTMSI_ADDRESS_LO, 4); 267166435Sjhb printf("%08x", reg); 268169037Sjhb } 269166435Sjhb break; 270166435Sjhb case PCIM_HTCAP_DIRECT_ROUTE: 271166435Sjhb printf("direct route"); 272166435Sjhb break; 273166435Sjhb case PCIM_HTCAP_VCSET: 274166435Sjhb printf("VC set"); 275166435Sjhb break; 276166435Sjhb case PCIM_HTCAP_RETRY_MODE: 277166435Sjhb printf("retry mode"); 278166435Sjhb break; 279173059Sjhb case PCIM_HTCAP_X86_ENCODING: 280173059Sjhb printf("X86 encoding"); 281173059Sjhb break; 282250741Skib case PCIM_HTCAP_GEN3: 283250741Skib printf("Gen3"); 284250741Skib break; 285250741Skib case PCIM_HTCAP_FLE: 286250741Skib printf("function-level extension"); 287250741Skib break; 288250741Skib case PCIM_HTCAP_PM: 289250741Skib printf("power management"); 290250741Skib break; 291250741Skib case PCIM_HTCAP_HIGH_NODE_COUNT: 292250741Skib printf("high node count"); 293250741Skib break; 294166435Sjhb default: 295166435Sjhb printf("unknown %02x", command); 296166435Sjhb break; 297166435Sjhb } 298166435Sjhb} 299166435Sjhb 300166435Sjhbstatic void 301166435Sjhbcap_vendor(int fd, struct pci_conf *p, uint8_t ptr) 302166435Sjhb{ 303166435Sjhb uint8_t length; 304166435Sjhb 305166435Sjhb length = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_LENGTH, 1); 306166435Sjhb printf("vendor (length %d)", length); 307166435Sjhb if (p->pc_vendor == 0x8086) { 308166435Sjhb /* Intel */ 309166435Sjhb uint8_t version; 310166435Sjhb 311166435Sjhb version = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_DATA, 312166435Sjhb 1); 313166435Sjhb printf(" Intel cap %d version %d", version >> 4, version & 0xf); 314166435Sjhb if (version >> 4 == 1 && length == 12) { 315166435Sjhb /* Feature Detection */ 316166435Sjhb uint32_t fvec; 317166435Sjhb int comma; 318166435Sjhb 319166435Sjhb comma = 0; 320166435Sjhb fvec = read_config(fd, &p->pc_sel, ptr + 321166435Sjhb PCIR_VENDOR_DATA + 5, 4); 322166435Sjhb printf("\n\t\t features:"); 323166435Sjhb if (fvec & (1 << 0)) { 324166435Sjhb printf(" AMT"); 325166435Sjhb comma = 1; 326166435Sjhb } 327166435Sjhb fvec = read_config(fd, &p->pc_sel, ptr + 328166435Sjhb PCIR_VENDOR_DATA + 1, 4); 329166435Sjhb if (fvec & (1 << 21)) { 330166435Sjhb printf("%s Quick Resume", comma ? "," : ""); 331166435Sjhb comma = 1; 332166435Sjhb } 333166435Sjhb if (fvec & (1 << 18)) { 334166435Sjhb printf("%s SATA RAID-5", comma ? "," : ""); 335166435Sjhb comma = 1; 336166435Sjhb } 337166435Sjhb if (fvec & (1 << 9)) { 338166435Sjhb printf("%s Mobile", comma ? "," : ""); 339166435Sjhb comma = 1; 340166435Sjhb } 341166435Sjhb if (fvec & (1 << 7)) { 342166435Sjhb printf("%s 6 PCI-e x1 slots", comma ? "," : ""); 343166435Sjhb comma = 1; 344166435Sjhb } else { 345166435Sjhb printf("%s 4 PCI-e x1 slots", comma ? "," : ""); 346166435Sjhb comma = 1; 347166435Sjhb } 348166435Sjhb if (fvec & (1 << 5)) { 349166435Sjhb printf("%s SATA RAID-0/1/10", comma ? "," : ""); 350166435Sjhb comma = 1; 351166435Sjhb } 352166435Sjhb if (fvec & (1 << 3)) { 353166435Sjhb printf("%s SATA AHCI", comma ? "," : ""); 354166435Sjhb comma = 1; 355166435Sjhb } 356166435Sjhb } 357166435Sjhb } 358166435Sjhb} 359166435Sjhb 360166435Sjhbstatic void 361166435Sjhbcap_debug(int fd, struct pci_conf *p, uint8_t ptr) 362166435Sjhb{ 363166435Sjhb uint16_t debug_port; 364166435Sjhb 365166435Sjhb debug_port = read_config(fd, &p->pc_sel, ptr + PCIR_DEBUG_PORT, 2); 366166435Sjhb printf("EHCI Debug Port at offset 0x%x in map 0x%x", debug_port & 367166435Sjhb PCIM_DEBUG_PORT_OFFSET, PCIR_BAR(debug_port >> 13)); 368166435Sjhb} 369166435Sjhb 370166435Sjhbstatic void 371166435Sjhbcap_subvendor(int fd, struct pci_conf *p, uint8_t ptr) 372166435Sjhb{ 373166435Sjhb uint32_t id; 374166435Sjhb 375166435Sjhb id = read_config(fd, &p->pc_sel, ptr + PCIR_SUBVENDCAP_ID, 4); 376166435Sjhb printf("PCI Bridge card=0x%08x", id); 377166435Sjhb} 378166435Sjhb 379191222Sjhb#define MAX_PAYLOAD(field) (128 << (field)) 380191222Sjhb 381242085Sjimharrisstatic const char * 382242085Sjimharrislink_speed_string(uint8_t speed) 383242085Sjimharris{ 384242085Sjimharris 385242085Sjimharris switch (speed) { 386242085Sjimharris case 1: 387242085Sjimharris return ("2.5"); 388242085Sjimharris case 2: 389242085Sjimharris return ("5.0"); 390242085Sjimharris case 3: 391242085Sjimharris return ("8.0"); 392242085Sjimharris default: 393242085Sjimharris return ("undef"); 394242085Sjimharris } 395242085Sjimharris} 396242085Sjimharris 397253455Sjkimstatic const char * 398253455Sjkimaspm_string(uint8_t aspm) 399253455Sjkim{ 400253455Sjkim 401253455Sjkim switch (aspm) { 402253455Sjkim case 1: 403253455Sjkim return ("L0s"); 404253455Sjkim case 2: 405253455Sjkim return ("L1"); 406253455Sjkim case 3: 407253455Sjkim return ("L0s/L1"); 408253455Sjkim default: 409253455Sjkim return ("disabled"); 410253455Sjkim } 411253455Sjkim} 412253455Sjkim 413297501Sjhbstatic int 414297501Sjhbslot_power(uint32_t cap) 415297501Sjhb{ 416297501Sjhb int mwatts; 417297501Sjhb 418297501Sjhb mwatts = (cap & PCIEM_SLOT_CAP_SPLV) >> 7; 419297501Sjhb switch (cap & PCIEM_SLOT_CAP_SPLS) { 420297501Sjhb case 0x0: 421297501Sjhb mwatts *= 1000; 422297501Sjhb break; 423297501Sjhb case 0x1: 424297501Sjhb mwatts *= 100; 425297501Sjhb break; 426297501Sjhb case 0x2: 427297501Sjhb mwatts *= 10; 428297501Sjhb break; 429297501Sjhb default: 430297501Sjhb break; 431297501Sjhb } 432297501Sjhb return (mwatts); 433297501Sjhb} 434297501Sjhb 435166435Sjhbstatic void 436166435Sjhbcap_express(int fd, struct pci_conf *p, uint8_t ptr) 437166435Sjhb{ 438297500Sjhb uint32_t cap; 439253455Sjkim uint16_t ctl, flags, sta; 440297500Sjhb unsigned int version; 441166435Sjhb 442240680Sgavin flags = read_config(fd, &p->pc_sel, ptr + PCIER_FLAGS, 2); 443297500Sjhb version = flags & PCIEM_FLAGS_VERSION; 444297500Sjhb printf("PCI-Express %u ", version); 445240680Sgavin switch (flags & PCIEM_FLAGS_TYPE) { 446240680Sgavin case PCIEM_TYPE_ENDPOINT: 447166435Sjhb printf("endpoint"); 448166435Sjhb break; 449240680Sgavin case PCIEM_TYPE_LEGACY_ENDPOINT: 450166435Sjhb printf("legacy endpoint"); 451166435Sjhb break; 452240680Sgavin case PCIEM_TYPE_ROOT_PORT: 453166435Sjhb printf("root port"); 454166435Sjhb break; 455240680Sgavin case PCIEM_TYPE_UPSTREAM_PORT: 456166435Sjhb printf("upstream port"); 457166435Sjhb break; 458240680Sgavin case PCIEM_TYPE_DOWNSTREAM_PORT: 459166435Sjhb printf("downstream port"); 460166435Sjhb break; 461240680Sgavin case PCIEM_TYPE_PCI_BRIDGE: 462166435Sjhb printf("PCI bridge"); 463166435Sjhb break; 464240680Sgavin case PCIEM_TYPE_PCIE_BRIDGE: 465191222Sjhb printf("PCI to PCIe bridge"); 466191222Sjhb break; 467240680Sgavin case PCIEM_TYPE_ROOT_INT_EP: 468191222Sjhb printf("root endpoint"); 469191222Sjhb break; 470240680Sgavin case PCIEM_TYPE_ROOT_EC: 471191222Sjhb printf("event collector"); 472191222Sjhb break; 473166435Sjhb default: 474240680Sgavin printf("type %d", (flags & PCIEM_FLAGS_TYPE) >> 4); 475166435Sjhb break; 476166435Sjhb } 477240680Sgavin if (flags & PCIEM_FLAGS_IRQ) 478297500Sjhb printf(" MSI %d", (flags & PCIEM_FLAGS_IRQ) >> 9); 479253455Sjkim cap = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CAP, 4); 480253455Sjkim ctl = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CTL, 2); 481191222Sjhb printf(" max data %d(%d)", 482253455Sjkim MAX_PAYLOAD((ctl & PCIEM_CTL_MAX_PAYLOAD) >> 5), 483253455Sjkim MAX_PAYLOAD(cap & PCIEM_CAP_MAX_PAYLOAD)); 484253455Sjkim if ((cap & PCIEM_CAP_FLR) != 0) 485240474Sjhb printf(" FLR"); 486290412Sjhb if (ctl & PCIEM_CTL_RELAXED_ORD_ENABLE) 487290412Sjhb printf(" RO"); 488290412Sjhb if (ctl & PCIEM_CTL_NOSNOOP_ENABLE) 489290412Sjhb printf(" NS"); 490297500Sjhb if (version >= 2) { 491297500Sjhb cap = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CAP2, 4); 492297500Sjhb if ((cap & PCIEM_CAP2_ARI) != 0) { 493297500Sjhb ctl = read_config(fd, &p->pc_sel, 494297500Sjhb ptr + PCIER_DEVICE_CTL2, 4); 495297500Sjhb printf(" ARI %s", 496297500Sjhb (ctl & PCIEM_CTL2_ARI) ? "enabled" : "disabled"); 497297500Sjhb } 498297500Sjhb } 499253455Sjkim cap = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_CAP, 4); 500253455Sjkim sta = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_STA, 2); 501297500Sjhb if (cap == 0 && sta == 0) 502297500Sjhb return; 503297500Sjhb printf("\n "); 504253455Sjkim printf(" link x%d(x%d)", (sta & PCIEM_LINK_STA_WIDTH) >> 4, 505253455Sjkim (cap & PCIEM_LINK_CAP_MAX_WIDTH) >> 4); 506253455Sjkim if ((cap & PCIEM_LINK_CAP_MAX_WIDTH) != 0) { 507253455Sjkim printf(" speed %s(%s)", (sta & PCIEM_LINK_STA_WIDTH) == 0 ? 508253455Sjkim "0.0" : link_speed_string(sta & PCIEM_LINK_STA_SPEED), 509253455Sjkim link_speed_string(cap & PCIEM_LINK_CAP_MAX_SPEED)); 510242085Sjimharris } 511253455Sjkim if ((cap & PCIEM_LINK_CAP_ASPM) != 0) { 512253455Sjkim ctl = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_CTL, 2); 513253455Sjkim printf(" ASPM %s(%s)", aspm_string(ctl & PCIEM_LINK_CTL_ASPMC), 514253455Sjkim aspm_string((cap & PCIEM_LINK_CAP_ASPM) >> 10)); 515253455Sjkim } 516297501Sjhb if (!(flags & PCIEM_FLAGS_SLOT)) 517297501Sjhb return; 518297501Sjhb cap = read_config(fd, &p->pc_sel, ptr + PCIER_SLOT_CAP, 4); 519297501Sjhb sta = read_config(fd, &p->pc_sel, ptr + PCIER_SLOT_STA, 2); 520297501Sjhb ctl = read_config(fd, &p->pc_sel, ptr + PCIER_SLOT_CTL, 2); 521297501Sjhb printf("\n "); 522297501Sjhb printf(" slot %d", (cap & PCIEM_SLOT_CAP_PSN) >> 19); 523297501Sjhb printf(" power limit %d mW", slot_power(cap)); 524297501Sjhb if (cap & PCIEM_SLOT_CAP_HPC) 525297501Sjhb printf(" HotPlug(%s)", sta & PCIEM_SLOT_STA_PDS ? "present" : 526297501Sjhb "empty"); 527297501Sjhb if (cap & PCIEM_SLOT_CAP_HPS) 528297501Sjhb printf(" surprise"); 529297501Sjhb if (cap & PCIEM_SLOT_CAP_APB) 530297501Sjhb printf(" Attn Button"); 531297501Sjhb if (cap & PCIEM_SLOT_CAP_PCP) 532303835Svangyzen printf(" PC(%s)", ctl & PCIEM_SLOT_CTL_PCC ? "off" : "on"); 533297501Sjhb if (cap & PCIEM_SLOT_CAP_MRLSP) 534297501Sjhb printf(" MRL(%s)", sta & PCIEM_SLOT_STA_MRLSS ? "open" : 535297501Sjhb "closed"); 536303835Svangyzen if (cap & PCIEM_SLOT_CAP_EIP) 537303835Svangyzen printf(" EI(%s)", sta & PCIEM_SLOT_STA_EIS ? "engaged" : 538303835Svangyzen "disengaged"); 539166435Sjhb} 540166435Sjhb 541166435Sjhbstatic void 542166435Sjhbcap_msix(int fd, struct pci_conf *p, uint8_t ptr) 543166435Sjhb{ 544246221Sneel uint32_t pba_offset, table_offset, val; 545246221Sneel int msgnum, pba_bar, table_bar; 546166435Sjhb uint16_t ctrl; 547166435Sjhb 548166435Sjhb ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_CTRL, 2); 549166435Sjhb msgnum = (ctrl & PCIM_MSIXCTRL_TABLE_SIZE) + 1; 550246221Sneel 551166435Sjhb val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_TABLE, 4); 552166435Sjhb table_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); 553246221Sneel table_offset = val & ~PCIM_MSIX_BIR_MASK; 554246221Sneel 555166435Sjhb val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_PBA, 4); 556246221Sneel pba_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); 557246221Sneel pba_offset = val & ~PCIM_MSIX_BIR_MASK; 558246221Sneel 559246221Sneel printf("MSI-X supports %d message%s%s\n", msgnum, 560246221Sneel (msgnum == 1) ? "" : "s", 561246221Sneel (ctrl & PCIM_MSIXCTRL_MSIX_ENABLE) ? ", enabled" : ""); 562246221Sneel 563246221Sneel printf(" "); 564246221Sneel printf("Table in map 0x%x[0x%x], PBA in map 0x%x[0x%x]", 565246221Sneel table_bar, table_offset, pba_bar, pba_offset); 566166435Sjhb} 567166435Sjhb 568188640Smavstatic void 569295769Ssecap_sata(int fd __unused, struct pci_conf *p __unused, uint8_t ptr __unused) 570188640Smav{ 571188640Smav 572188640Smav printf("SATA Index-Data Pair"); 573188640Smav} 574188640Smav 575188640Smavstatic void 576188640Smavcap_pciaf(int fd, struct pci_conf *p, uint8_t ptr) 577188640Smav{ 578188640Smav uint8_t cap; 579188640Smav 580188640Smav cap = read_config(fd, &p->pc_sel, ptr + PCIR_PCIAF_CAP, 1); 581188641Smav printf("PCI Advanced Features:%s%s", 582188641Smav cap & PCIM_PCIAFCAP_FLR ? " FLR" : "", 583188641Smav cap & PCIM_PCIAFCAP_TP ? " TP" : ""); 584188640Smav} 585188640Smav 586296081Swmastatic const char * 587296132Spfgea_bei_to_name(int bei) 588296081Swma{ 589296081Swma static const char *barstr[] = { 590296081Swma "BAR0", "BAR1", "BAR2", "BAR3", "BAR4", "BAR5" 591296081Swma }; 592296081Swma static const char *vfbarstr[] = { 593296081Swma "VFBAR0", "VFBAR1", "VFBAR2", "VFBAR3", "VFBAR4", "VFBAR5" 594296081Swma }; 595296081Swma 596296081Swma if ((bei >= PCIM_EA_BEI_BAR_0) && (bei <= PCIM_EA_BEI_BAR_5)) 597296081Swma return (barstr[bei - PCIM_EA_BEI_BAR_0]); 598296081Swma if ((bei >= PCIM_EA_BEI_VF_BAR_0) && (bei <= PCIM_EA_BEI_VF_BAR_5)) 599296081Swma return (vfbarstr[bei - PCIM_EA_BEI_VF_BAR_0]); 600296081Swma 601296081Swma switch (bei) { 602296081Swma case PCIM_EA_BEI_BRIDGE: 603296081Swma return "BRIDGE"; 604296081Swma case PCIM_EA_BEI_ENI: 605296081Swma return "ENI"; 606296081Swma case PCIM_EA_BEI_ROM: 607296081Swma return "ROM"; 608296081Swma case PCIM_EA_BEI_RESERVED: 609296081Swma default: 610296081Swma return "RSVD"; 611296081Swma } 612296081Swma} 613296081Swma 614296081Swmastatic const char * 615296081Swmaea_prop_to_name(uint8_t prop) 616296081Swma{ 617296081Swma 618296081Swma switch (prop) { 619296081Swma case PCIM_EA_P_MEM: 620296081Swma return "Non-Prefetchable Memory"; 621296081Swma case PCIM_EA_P_MEM_PREFETCH: 622296081Swma return "Prefetchable Memory"; 623296081Swma case PCIM_EA_P_IO: 624296081Swma return "I/O Space"; 625296081Swma case PCIM_EA_P_VF_MEM_PREFETCH: 626296081Swma return "VF Prefetchable Memory"; 627296081Swma case PCIM_EA_P_VF_MEM: 628296081Swma return "VF Non-Prefetchable Memory"; 629296081Swma case PCIM_EA_P_BRIDGE_MEM: 630296081Swma return "Bridge Non-Prefetchable Memory"; 631296081Swma case PCIM_EA_P_BRIDGE_MEM_PREFETCH: 632296081Swma return "Bridge Prefetchable Memory"; 633296081Swma case PCIM_EA_P_BRIDGE_IO: 634296081Swma return "Bridge I/O Space"; 635296081Swma case PCIM_EA_P_MEM_RESERVED: 636296081Swma return "Reserved Memory"; 637296081Swma case PCIM_EA_P_IO_RESERVED: 638296081Swma return "Reserved I/O Space"; 639296081Swma case PCIM_EA_P_UNAVAILABLE: 640296081Swma return "Unavailable"; 641296081Swma default: 642296081Swma return "Reserved"; 643296081Swma } 644296081Swma} 645296081Swma 646296081Swmastatic void 647296081Swmacap_ea(int fd, struct pci_conf *p, uint8_t ptr) 648296081Swma{ 649296081Swma int num_ent; 650296081Swma int a, b; 651296081Swma uint32_t bei; 652296081Swma uint32_t val; 653296081Swma int ent_size; 654296081Swma uint32_t dw[4]; 655296081Swma uint32_t flags, flags_pp, flags_sp; 656296081Swma uint64_t base, max_offset; 657296081Swma uint8_t fixed_sub_bus_nr, fixed_sec_bus_nr; 658296081Swma 659296081Swma /* Determine the number of entries */ 660296081Swma num_ent = read_config(fd, &p->pc_sel, ptr + PCIR_EA_NUM_ENT, 2); 661296081Swma num_ent &= PCIM_EA_NUM_ENT_MASK; 662296081Swma 663296081Swma printf("PCI Enhanced Allocation (%d entries)", num_ent); 664296081Swma 665296081Swma /* Find the first entry to care of */ 666296081Swma ptr += PCIR_EA_FIRST_ENT; 667296081Swma 668296081Swma /* Print BUS numbers for bridges */ 669296081Swma if ((p->pc_hdr & PCIM_HDRTYPE) == PCIM_HDRTYPE_BRIDGE) { 670296081Swma val = read_config(fd, &p->pc_sel, ptr, 4); 671296081Swma 672296081Swma fixed_sec_bus_nr = PCIM_EA_SEC_NR(val); 673296081Swma fixed_sub_bus_nr = PCIM_EA_SUB_NR(val); 674296081Swma 675296081Swma printf("\n\t\t BRIDGE, sec bus [%d], sub bus [%d]", 676296081Swma fixed_sec_bus_nr, fixed_sub_bus_nr); 677296081Swma ptr += 4; 678296081Swma } 679296081Swma 680296081Swma for (a = 0; a < num_ent; a++) { 681296081Swma /* Read a number of dwords in the entry */ 682296081Swma val = read_config(fd, &p->pc_sel, ptr, 4); 683296081Swma ptr += 4; 684296081Swma ent_size = (val & PCIM_EA_ES); 685296081Swma 686296081Swma for (b = 0; b < ent_size; b++) { 687296081Swma dw[b] = read_config(fd, &p->pc_sel, ptr, 4); 688296081Swma ptr += 4; 689296081Swma } 690296081Swma 691296081Swma flags = val; 692296081Swma flags_pp = (flags & PCIM_EA_PP) >> PCIM_EA_PP_OFFSET; 693296081Swma flags_sp = (flags & PCIM_EA_SP) >> PCIM_EA_SP_OFFSET; 694296081Swma bei = (PCIM_EA_BEI & val) >> PCIM_EA_BEI_OFFSET; 695296081Swma 696296081Swma base = dw[0] & PCIM_EA_FIELD_MASK; 697296081Swma max_offset = dw[1] | ~PCIM_EA_FIELD_MASK; 698296081Swma b = 2; 699296081Swma if (((dw[0] & PCIM_EA_IS_64) != 0) && (b < ent_size)) { 700296081Swma base |= (uint64_t)dw[b] << 32UL; 701296081Swma b++; 702296081Swma } 703296081Swma if (((dw[1] & PCIM_EA_IS_64) != 0) 704296081Swma && (b < ent_size)) { 705296081Swma max_offset |= (uint64_t)dw[b] << 32UL; 706296081Swma b++; 707296081Swma } 708296081Swma 709296090Swma printf("\n\t\t [%d] %s, %s, %s, base [0x%jx], size [0x%jx]" 710296081Swma "\n\t\t\tPrimary properties [0x%x] (%s)" 711296081Swma "\n\t\t\tSecondary properties [0x%x] (%s)", 712296081Swma bei, ea_bei_to_name(bei), 713296081Swma (flags & PCIM_EA_ENABLE ? "Enabled" : "Disabled"), 714296090Swma (flags & PCIM_EA_WRITABLE ? "Writable" : "Read-only"), 715296090Swma (uintmax_t)base, (uintmax_t)(max_offset + 1), 716296081Swma flags_pp, ea_prop_to_name(flags_pp), 717296081Swma flags_sp, ea_prop_to_name(flags_sp)); 718296081Swma } 719296081Swma} 720296081Swma 721166435Sjhbvoid 722166435Sjhblist_caps(int fd, struct pci_conf *p) 723166435Sjhb{ 724212749Sjhb int express; 725212369Sjhb uint16_t sta; 726166435Sjhb uint8_t ptr, cap; 727166435Sjhb 728166435Sjhb /* Are capabilities present for this device? */ 729212369Sjhb sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); 730212369Sjhb if (!(sta & PCIM_STATUS_CAPPRESENT)) 731166435Sjhb return; 732166435Sjhb 733166435Sjhb switch (p->pc_hdr & PCIM_HDRTYPE) { 734212369Sjhb case PCIM_HDRTYPE_NORMAL: 735212369Sjhb case PCIM_HDRTYPE_BRIDGE: 736166435Sjhb ptr = PCIR_CAP_PTR; 737166435Sjhb break; 738212369Sjhb case PCIM_HDRTYPE_CARDBUS: 739166435Sjhb ptr = PCIR_CAP_PTR_2; 740166435Sjhb break; 741166435Sjhb default: 742166435Sjhb errx(1, "list_caps: bad header type"); 743166435Sjhb } 744166435Sjhb 745166435Sjhb /* Walk the capability list. */ 746212749Sjhb express = 0; 747166435Sjhb ptr = read_config(fd, &p->pc_sel, ptr, 1); 748166435Sjhb while (ptr != 0 && ptr != 0xff) { 749166435Sjhb cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1); 750166435Sjhb printf(" cap %02x[%02x] = ", cap, ptr); 751166435Sjhb switch (cap) { 752166435Sjhb case PCIY_PMG: 753166435Sjhb cap_power(fd, p, ptr); 754166435Sjhb break; 755166435Sjhb case PCIY_AGP: 756166435Sjhb cap_agp(fd, p, ptr); 757166435Sjhb break; 758166435Sjhb case PCIY_VPD: 759166435Sjhb cap_vpd(fd, p, ptr); 760166435Sjhb break; 761166435Sjhb case PCIY_MSI: 762166435Sjhb cap_msi(fd, p, ptr); 763166435Sjhb break; 764166435Sjhb case PCIY_PCIX: 765166435Sjhb cap_pcix(fd, p, ptr); 766166435Sjhb break; 767166435Sjhb case PCIY_HT: 768166435Sjhb cap_ht(fd, p, ptr); 769166435Sjhb break; 770166435Sjhb case PCIY_VENDOR: 771166435Sjhb cap_vendor(fd, p, ptr); 772166435Sjhb break; 773166435Sjhb case PCIY_DEBUG: 774166435Sjhb cap_debug(fd, p, ptr); 775166435Sjhb break; 776166435Sjhb case PCIY_SUBVENDOR: 777166435Sjhb cap_subvendor(fd, p, ptr); 778166435Sjhb break; 779166435Sjhb case PCIY_EXPRESS: 780212749Sjhb express = 1; 781166435Sjhb cap_express(fd, p, ptr); 782166435Sjhb break; 783166435Sjhb case PCIY_MSIX: 784166435Sjhb cap_msix(fd, p, ptr); 785166435Sjhb break; 786188640Smav case PCIY_SATA: 787188640Smav cap_sata(fd, p, ptr); 788188640Smav break; 789188640Smav case PCIY_PCIAF: 790188640Smav cap_pciaf(fd, p, ptr); 791188640Smav break; 792296081Swma case PCIY_EA: 793296081Swma cap_ea(fd, p, ptr); 794296081Swma break; 795166435Sjhb default: 796166435Sjhb printf("unknown"); 797166435Sjhb break; 798166435Sjhb } 799166435Sjhb printf("\n"); 800166435Sjhb ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1); 801166435Sjhb } 802212326Sjhb 803212749Sjhb if (express) 804212749Sjhb list_ecaps(fd, p); 805166435Sjhb} 806212326Sjhb 807212326Sjhb/* From <sys/systm.h>. */ 808212326Sjhbstatic __inline uint32_t 809212326Sjhbbitcount32(uint32_t x) 810212326Sjhb{ 811212326Sjhb 812212326Sjhb x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1); 813212326Sjhb x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2); 814212326Sjhb x = (x + (x >> 4)) & 0x0f0f0f0f; 815212326Sjhb x = (x + (x >> 8)); 816212326Sjhb x = (x + (x >> 16)) & 0x000000ff; 817212326Sjhb return (x); 818212326Sjhb} 819212326Sjhb 820212326Sjhbstatic void 821212326Sjhbecap_aer(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 822212326Sjhb{ 823212326Sjhb uint32_t sta, mask; 824212326Sjhb 825212326Sjhb printf("AER %d", ver); 826240474Sjhb if (ver < 1) 827212326Sjhb return; 828212326Sjhb sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_STATUS, 4); 829212326Sjhb mask = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_SEVERITY, 4); 830212326Sjhb printf(" %d fatal", bitcount32(sta & mask)); 831212326Sjhb printf(" %d non-fatal", bitcount32(sta & ~mask)); 832212326Sjhb sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_COR_STATUS, 4); 833279466Srstone printf(" %d corrected\n", bitcount32(sta)); 834212326Sjhb} 835212326Sjhb 836212326Sjhbstatic void 837212326Sjhbecap_vc(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 838212326Sjhb{ 839212326Sjhb uint32_t cap1; 840212326Sjhb 841212326Sjhb printf("VC %d", ver); 842240474Sjhb if (ver < 1) 843212326Sjhb return; 844212326Sjhb cap1 = read_config(fd, &p->pc_sel, ptr + PCIR_VC_CAP1, 4); 845212326Sjhb printf(" max VC%d", cap1 & PCIM_VC_CAP1_EXT_COUNT); 846212326Sjhb if ((cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) != 0) 847212326Sjhb printf(" lowpri VC0-VC%d", 848212326Sjhb (cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) >> 4); 849279466Srstone printf("\n"); 850212326Sjhb} 851212326Sjhb 852212326Sjhbstatic void 853212326Sjhbecap_sernum(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 854212326Sjhb{ 855212326Sjhb uint32_t high, low; 856212326Sjhb 857212326Sjhb printf("Serial %d", ver); 858240474Sjhb if (ver < 1) 859212326Sjhb return; 860212326Sjhb low = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_LOW, 4); 861212326Sjhb high = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_HIGH, 4); 862279466Srstone printf(" %08x%08x\n", high, low); 863212326Sjhb} 864212326Sjhb 865212326Sjhbstatic void 866240474Sjhbecap_vendor(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 867240474Sjhb{ 868240474Sjhb uint32_t val; 869240474Sjhb 870240474Sjhb printf("Vendor %d", ver); 871240474Sjhb if (ver < 1) 872240474Sjhb return; 873240474Sjhb val = read_config(fd, &p->pc_sel, ptr + 4, 4); 874279466Srstone printf(" ID %d\n", val & 0xffff); 875240474Sjhb} 876240474Sjhb 877240474Sjhbstatic void 878240474Sjhbecap_sec_pcie(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 879240474Sjhb{ 880240474Sjhb uint32_t val; 881240474Sjhb 882240474Sjhb printf("PCIe Sec %d", ver); 883240474Sjhb if (ver < 1) 884240474Sjhb return; 885240474Sjhb val = read_config(fd, &p->pc_sel, ptr + 8, 4); 886279466Srstone printf(" lane errors %#x\n", val); 887240474Sjhb} 888240474Sjhb 889279466Srstonestatic const char * 890279466Srstonecheck_enabled(int value) 891279466Srstone{ 892279466Srstone 893279466Srstone return (value ? "enabled" : "disabled"); 894279466Srstone} 895279466Srstone 896279466Srstonestatic void 897279466Srstoneecap_sriov(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 898279466Srstone{ 899279466Srstone const char *comma, *enabled; 900279466Srstone uint16_t iov_ctl, total_vfs, num_vfs, vf_offset, vf_stride, vf_did; 901279466Srstone uint32_t page_caps, page_size, page_shift, size; 902279466Srstone int i; 903279466Srstone 904279466Srstone printf("SR-IOV %d ", ver); 905279466Srstone 906279466Srstone iov_ctl = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_CTL, 2); 907279466Srstone printf("IOV %s, Memory Space %s, ARI %s\n", 908279466Srstone check_enabled(iov_ctl & PCIM_SRIOV_VF_EN), 909279466Srstone check_enabled(iov_ctl & PCIM_SRIOV_VF_MSE), 910279466Srstone check_enabled(iov_ctl & PCIM_SRIOV_ARI_EN)); 911279466Srstone 912279466Srstone total_vfs = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_TOTAL_VFS, 2); 913279466Srstone num_vfs = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_NUM_VFS, 2); 914279466Srstone printf(" "); 915279466Srstone printf("%d VFs configured out of %d supported\n", num_vfs, total_vfs); 916279466Srstone 917279466Srstone vf_offset = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_VF_OFF, 2); 918279466Srstone vf_stride = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_VF_STRIDE, 2); 919279466Srstone printf(" "); 920279466Srstone printf("First VF RID Offset 0x%04x, VF RID Stride 0x%04x\n", vf_offset, 921279466Srstone vf_stride); 922279466Srstone 923279466Srstone vf_did = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_VF_DID, 2); 924279466Srstone printf(" VF Device ID 0x%04x\n", vf_did); 925279466Srstone 926279466Srstone page_caps = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_PAGE_CAP, 4); 927279466Srstone page_size = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_PAGE_SIZE, 4); 928279466Srstone printf(" "); 929279466Srstone printf("Page Sizes: "); 930279466Srstone comma = ""; 931279466Srstone while (page_caps != 0) { 932279466Srstone page_shift = ffs(page_caps) - 1; 933279466Srstone 934279466Srstone if (page_caps & page_size) 935279466Srstone enabled = " (enabled)"; 936279466Srstone else 937279466Srstone enabled = ""; 938279466Srstone 939279466Srstone size = (1 << (page_shift + PCI_SRIOV_BASE_PAGE_SHIFT)); 940279466Srstone printf("%s%d%s", comma, size, enabled); 941279466Srstone comma = ", "; 942279466Srstone 943279466Srstone page_caps &= ~(1 << page_shift); 944279466Srstone } 945279466Srstone printf("\n"); 946279466Srstone 947279466Srstone for (i = 0; i <= PCIR_MAX_BAR_0; i++) 948279466Srstone print_bar(fd, p, "iov bar ", ptr + PCIR_SRIOV_BAR(i)); 949279466Srstone} 950279466Srstone 951295760Ssestatic struct { 952240474Sjhb uint16_t id; 953240474Sjhb const char *name; 954240474Sjhb} ecap_names[] = { 955240474Sjhb { PCIZ_PWRBDGT, "Power Budgeting" }, 956240474Sjhb { PCIZ_RCLINK_DCL, "Root Complex Link Declaration" }, 957240474Sjhb { PCIZ_RCLINK_CTL, "Root Complex Internal Link Control" }, 958240474Sjhb { PCIZ_RCEC_ASSOC, "Root Complex Event Collector ASsociation" }, 959240474Sjhb { PCIZ_MFVC, "MFVC" }, 960240474Sjhb { PCIZ_RCRB, "RCRB" }, 961240474Sjhb { PCIZ_ACS, "ACS" }, 962240474Sjhb { PCIZ_ARI, "ARI" }, 963240474Sjhb { PCIZ_ATS, "ATS" }, 964240474Sjhb { PCIZ_MULTICAST, "Multicast" }, 965240474Sjhb { PCIZ_RESIZE_BAR, "Resizable BAR" }, 966240474Sjhb { PCIZ_DPA, "DPA" }, 967240474Sjhb { PCIZ_TPH_REQ, "TPH Requester" }, 968240474Sjhb { PCIZ_LTR, "LTR" }, 969240474Sjhb { 0, NULL } 970240474Sjhb}; 971240474Sjhb 972240474Sjhbstatic void 973212326Sjhblist_ecaps(int fd, struct pci_conf *p) 974212326Sjhb{ 975240474Sjhb const char *name; 976212326Sjhb uint32_t ecap; 977212326Sjhb uint16_t ptr; 978240474Sjhb int i; 979212326Sjhb 980212326Sjhb ptr = PCIR_EXTCAP; 981212326Sjhb ecap = read_config(fd, &p->pc_sel, ptr, 4); 982212326Sjhb if (ecap == 0xffffffff || ecap == 0) 983212326Sjhb return; 984212326Sjhb for (;;) { 985241757Simp printf(" ecap %04x[%03x] = ", PCI_EXTCAP_ID(ecap), ptr); 986212326Sjhb switch (PCI_EXTCAP_ID(ecap)) { 987212326Sjhb case PCIZ_AER: 988212326Sjhb ecap_aer(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 989212326Sjhb break; 990212326Sjhb case PCIZ_VC: 991212326Sjhb ecap_vc(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 992212326Sjhb break; 993212326Sjhb case PCIZ_SERNUM: 994212326Sjhb ecap_sernum(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 995212326Sjhb break; 996240474Sjhb case PCIZ_VENDOR: 997240474Sjhb ecap_vendor(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 998240474Sjhb break; 999240474Sjhb case PCIZ_SEC_PCIE: 1000240474Sjhb ecap_sec_pcie(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 1001240474Sjhb break; 1002279466Srstone case PCIZ_SRIOV: 1003279466Srstone ecap_sriov(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 1004279466Srstone break; 1005212326Sjhb default: 1006240474Sjhb name = "unknown"; 1007240474Sjhb for (i = 0; ecap_names[i].name != NULL; i++) 1008240474Sjhb if (ecap_names[i].id == PCI_EXTCAP_ID(ecap)) { 1009240474Sjhb name = ecap_names[i].name; 1010240474Sjhb break; 1011240474Sjhb } 1012279466Srstone printf("%s %d\n", name, PCI_EXTCAP_VER(ecap)); 1013212326Sjhb break; 1014212326Sjhb } 1015212326Sjhb ptr = PCI_EXTCAP_NEXTPTR(ecap); 1016212326Sjhb if (ptr == 0) 1017212326Sjhb break; 1018212326Sjhb ecap = read_config(fd, &p->pc_sel, ptr, 4); 1019212326Sjhb } 1020212326Sjhb} 1021236415Sjhb 1022236415Sjhb/* Find offset of a specific capability. Returns 0 on failure. */ 1023236415Sjhbuint8_t 1024236415Sjhbpci_find_cap(int fd, struct pci_conf *p, uint8_t id) 1025236415Sjhb{ 1026236415Sjhb uint16_t sta; 1027236415Sjhb uint8_t ptr, cap; 1028236415Sjhb 1029236415Sjhb /* Are capabilities present for this device? */ 1030236415Sjhb sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); 1031236415Sjhb if (!(sta & PCIM_STATUS_CAPPRESENT)) 1032236415Sjhb return (0); 1033236415Sjhb 1034236415Sjhb switch (p->pc_hdr & PCIM_HDRTYPE) { 1035236415Sjhb case PCIM_HDRTYPE_NORMAL: 1036236415Sjhb case PCIM_HDRTYPE_BRIDGE: 1037236415Sjhb ptr = PCIR_CAP_PTR; 1038236415Sjhb break; 1039236415Sjhb case PCIM_HDRTYPE_CARDBUS: 1040236415Sjhb ptr = PCIR_CAP_PTR_2; 1041236415Sjhb break; 1042236415Sjhb default: 1043236415Sjhb return (0); 1044236415Sjhb } 1045236415Sjhb 1046236415Sjhb ptr = read_config(fd, &p->pc_sel, ptr, 1); 1047236415Sjhb while (ptr != 0 && ptr != 0xff) { 1048236415Sjhb cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1); 1049236415Sjhb if (cap == id) 1050236415Sjhb return (ptr); 1051236415Sjhb ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1); 1052236415Sjhb } 1053236415Sjhb return (0); 1054236415Sjhb} 1055236415Sjhb 1056236415Sjhb/* Find offset of a specific extended capability. Returns 0 on failure. */ 1057236415Sjhbuint16_t 1058236415Sjhbpcie_find_cap(int fd, struct pci_conf *p, uint16_t id) 1059236415Sjhb{ 1060236415Sjhb uint32_t ecap; 1061236415Sjhb uint16_t ptr; 1062236415Sjhb 1063236415Sjhb ptr = PCIR_EXTCAP; 1064236415Sjhb ecap = read_config(fd, &p->pc_sel, ptr, 4); 1065236415Sjhb if (ecap == 0xffffffff || ecap == 0) 1066236415Sjhb return (0); 1067236415Sjhb for (;;) { 1068236415Sjhb if (PCI_EXTCAP_ID(ecap) == id) 1069236415Sjhb return (ptr); 1070236415Sjhb ptr = PCI_EXTCAP_NEXTPTR(ecap); 1071236415Sjhb if (ptr == 0) 1072236415Sjhb break; 1073236415Sjhb ecap = read_config(fd, &p->pc_sel, ptr, 4); 1074236415Sjhb } 1075236415Sjhb return (0); 1076236415Sjhb} 1077