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$"; 34166435Sjhb#endif /* not lint */ 35166435Sjhb 36166435Sjhb#include <sys/types.h> 37166435Sjhb 38166435Sjhb#include <err.h> 39166435Sjhb#include <stdio.h> 40166435Sjhb#include <sys/agpio.h> 41166435Sjhb#include <sys/pciio.h> 42166435Sjhb 43173576Sjb#include <dev/agp/agpreg.h> 44166435Sjhb#include <dev/pci/pcireg.h> 45166435Sjhb 46166435Sjhb#include "pciconf.h" 47166435Sjhb 48212326Sjhbstatic void list_ecaps(int fd, struct pci_conf *p); 49212326Sjhb 50166435Sjhbstatic void 51166435Sjhbcap_power(int fd, struct pci_conf *p, uint8_t ptr) 52166435Sjhb{ 53166435Sjhb uint16_t cap, status; 54166435Sjhb 55166435Sjhb cap = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_CAP, 2); 56166435Sjhb status = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_STATUS, 2); 57166435Sjhb printf("powerspec %d supports D0%s%s D3 current D%d", 58166435Sjhb cap & PCIM_PCAP_SPEC, 59166435Sjhb cap & PCIM_PCAP_D1SUPP ? " D1" : "", 60166435Sjhb cap & PCIM_PCAP_D2SUPP ? " D2" : "", 61166435Sjhb status & PCIM_PSTAT_DMASK); 62166435Sjhb} 63166435Sjhb 64166435Sjhbstatic void 65166435Sjhbcap_agp(int fd, struct pci_conf *p, uint8_t ptr) 66166435Sjhb{ 67166435Sjhb uint32_t status, command; 68166435Sjhb 69166435Sjhb status = read_config(fd, &p->pc_sel, ptr + AGP_STATUS, 4); 70166435Sjhb command = read_config(fd, &p->pc_sel, ptr + AGP_CAPID, 4); 71166435Sjhb printf("AGP "); 72166435Sjhb if (AGP_MODE_GET_MODE_3(status)) { 73166435Sjhb printf("v3 "); 74166435Sjhb if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_8x) 75166435Sjhb printf("8x "); 76166435Sjhb if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_4x) 77166435Sjhb printf("4x "); 78166435Sjhb } else { 79166435Sjhb if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_4x) 80166435Sjhb printf("4x "); 81166435Sjhb if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_2x) 82166435Sjhb printf("2x "); 83166435Sjhb if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_1x) 84166435Sjhb printf("1x "); 85166435Sjhb } 86166435Sjhb if (AGP_MODE_GET_SBA(status)) 87166435Sjhb printf("SBA "); 88166435Sjhb if (AGP_MODE_GET_AGP(command)) { 89166435Sjhb printf("enabled at "); 90166435Sjhb if (AGP_MODE_GET_MODE_3(command)) { 91166435Sjhb printf("v3 "); 92166435Sjhb switch (AGP_MODE_GET_RATE(command)) { 93166435Sjhb case AGP_MODE_V3_RATE_8x: 94166435Sjhb printf("8x "); 95166435Sjhb break; 96166435Sjhb case AGP_MODE_V3_RATE_4x: 97166435Sjhb printf("4x "); 98166435Sjhb break; 99166435Sjhb } 100166435Sjhb } else 101166435Sjhb switch (AGP_MODE_GET_RATE(command)) { 102166435Sjhb case AGP_MODE_V2_RATE_4x: 103166435Sjhb printf("4x "); 104166435Sjhb break; 105166435Sjhb case AGP_MODE_V2_RATE_2x: 106166435Sjhb printf("2x "); 107166435Sjhb break; 108166435Sjhb case AGP_MODE_V2_RATE_1x: 109166435Sjhb printf("1x "); 110166435Sjhb break; 111166435Sjhb } 112166435Sjhb if (AGP_MODE_GET_SBA(command)) 113166435Sjhb printf("SBA "); 114166435Sjhb } else 115166435Sjhb printf("disabled"); 116166435Sjhb} 117166435Sjhb 118166435Sjhbstatic void 119166435Sjhbcap_vpd(int fd, struct pci_conf *p, uint8_t ptr) 120166435Sjhb{ 121166435Sjhb 122166435Sjhb printf("VPD"); 123166435Sjhb} 124166435Sjhb 125166435Sjhbstatic void 126166435Sjhbcap_msi(int fd, struct pci_conf *p, uint8_t ptr) 127166435Sjhb{ 128166435Sjhb uint16_t ctrl; 129166435Sjhb int msgnum; 130166435Sjhb 131166435Sjhb ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSI_CTRL, 2); 132166435Sjhb msgnum = 1 << ((ctrl & PCIM_MSICTRL_MMC_MASK) >> 1); 133166435Sjhb printf("MSI supports %d message%s%s%s ", msgnum, 134166435Sjhb (msgnum == 1) ? "" : "s", 135166435Sjhb (ctrl & PCIM_MSICTRL_64BIT) ? ", 64 bit" : "", 136166435Sjhb (ctrl & PCIM_MSICTRL_VECTOR) ? ", vector masks" : ""); 137166435Sjhb if (ctrl & PCIM_MSICTRL_MSI_ENABLE) { 138166435Sjhb msgnum = 1 << ((ctrl & PCIM_MSICTRL_MME_MASK) >> 4); 139166435Sjhb printf("enabled with %d message%s", msgnum, 140166435Sjhb (msgnum == 1) ? "" : "s"); 141166435Sjhb } 142166435Sjhb} 143166435Sjhb 144166435Sjhbstatic void 145166435Sjhbcap_pcix(int fd, struct pci_conf *p, uint8_t ptr) 146166435Sjhb{ 147166435Sjhb uint32_t status; 148166435Sjhb int comma, max_splits, max_burst_read; 149166435Sjhb 150166435Sjhb status = read_config(fd, &p->pc_sel, ptr + PCIXR_STATUS, 4); 151166435Sjhb printf("PCI-X "); 152166435Sjhb if (status & PCIXM_STATUS_64BIT) 153166435Sjhb printf("64-bit "); 154166435Sjhb if ((p->pc_hdr & PCIM_HDRTYPE) == 1) 155166435Sjhb printf("bridge "); 156191222Sjhb if ((p->pc_hdr & PCIM_HDRTYPE) != 1 || (status & (PCIXM_STATUS_133CAP | 157191222Sjhb PCIXM_STATUS_266CAP | PCIXM_STATUS_533CAP)) != 0) 158191222Sjhb printf("supports"); 159166435Sjhb comma = 0; 160166435Sjhb if (status & PCIXM_STATUS_133CAP) { 161166435Sjhb printf("%s 133MHz", comma ? "," : ""); 162166435Sjhb comma = 1; 163166435Sjhb } 164166435Sjhb if (status & PCIXM_STATUS_266CAP) { 165166435Sjhb printf("%s 266MHz", comma ? "," : ""); 166166435Sjhb comma = 1; 167166435Sjhb } 168166435Sjhb if (status & PCIXM_STATUS_533CAP) { 169166435Sjhb printf("%s 533MHz", comma ? "," : ""); 170166435Sjhb comma = 1; 171166435Sjhb } 172166435Sjhb if ((p->pc_hdr & PCIM_HDRTYPE) == 1) 173166435Sjhb return; 174166435Sjhb switch (status & PCIXM_STATUS_MAX_READ) { 175166435Sjhb case PCIXM_STATUS_MAX_READ_512: 176166435Sjhb max_burst_read = 512; 177166435Sjhb break; 178166435Sjhb case PCIXM_STATUS_MAX_READ_1024: 179166435Sjhb max_burst_read = 1024; 180166435Sjhb break; 181166435Sjhb case PCIXM_STATUS_MAX_READ_2048: 182166435Sjhb max_burst_read = 2048; 183166435Sjhb break; 184166435Sjhb case PCIXM_STATUS_MAX_READ_4096: 185166435Sjhb max_burst_read = 4096; 186166435Sjhb break; 187166435Sjhb } 188166435Sjhb switch (status & PCIXM_STATUS_MAX_SPLITS) { 189166435Sjhb case PCIXM_STATUS_MAX_SPLITS_1: 190166435Sjhb max_splits = 1; 191166435Sjhb break; 192166435Sjhb case PCIXM_STATUS_MAX_SPLITS_2: 193166435Sjhb max_splits = 2; 194166435Sjhb break; 195166435Sjhb case PCIXM_STATUS_MAX_SPLITS_3: 196166435Sjhb max_splits = 3; 197166435Sjhb break; 198166435Sjhb case PCIXM_STATUS_MAX_SPLITS_4: 199166435Sjhb max_splits = 4; 200166435Sjhb break; 201166435Sjhb case PCIXM_STATUS_MAX_SPLITS_8: 202166435Sjhb max_splits = 8; 203166435Sjhb break; 204166435Sjhb case PCIXM_STATUS_MAX_SPLITS_12: 205166435Sjhb max_splits = 12; 206166435Sjhb break; 207166435Sjhb case PCIXM_STATUS_MAX_SPLITS_16: 208166435Sjhb max_splits = 16; 209166435Sjhb break; 210166435Sjhb case PCIXM_STATUS_MAX_SPLITS_32: 211166435Sjhb max_splits = 32; 212166435Sjhb break; 213166435Sjhb } 214166435Sjhb printf("%s %d burst read, %d split transaction%s", comma ? "," : "", 215166435Sjhb max_burst_read, max_splits, max_splits == 1 ? "" : "s"); 216166435Sjhb} 217166435Sjhb 218166435Sjhbstatic void 219166435Sjhbcap_ht(int fd, struct pci_conf *p, uint8_t ptr) 220166435Sjhb{ 221166435Sjhb uint32_t reg; 222166435Sjhb uint16_t command; 223166435Sjhb 224166435Sjhb command = read_config(fd, &p->pc_sel, ptr + PCIR_HT_COMMAND, 2); 225166435Sjhb printf("HT "); 226166435Sjhb if ((command & 0xe000) == PCIM_HTCAP_SLAVE) 227166435Sjhb printf("slave"); 228166435Sjhb else if ((command & 0xe000) == PCIM_HTCAP_HOST) 229166435Sjhb printf("host"); 230166435Sjhb else 231166435Sjhb switch (command & PCIM_HTCMD_CAP_MASK) { 232166435Sjhb case PCIM_HTCAP_SWITCH: 233166435Sjhb printf("switch"); 234166435Sjhb break; 235166435Sjhb case PCIM_HTCAP_INTERRUPT: 236166435Sjhb printf("interrupt"); 237166435Sjhb break; 238166435Sjhb case PCIM_HTCAP_REVISION_ID: 239166435Sjhb printf("revision ID"); 240166435Sjhb break; 241166435Sjhb case PCIM_HTCAP_UNITID_CLUMPING: 242166435Sjhb printf("unit ID clumping"); 243166435Sjhb break; 244166435Sjhb case PCIM_HTCAP_EXT_CONFIG_SPACE: 245166435Sjhb printf("extended config space"); 246166435Sjhb break; 247166435Sjhb case PCIM_HTCAP_ADDRESS_MAPPING: 248166435Sjhb printf("address mapping"); 249166435Sjhb break; 250166435Sjhb case PCIM_HTCAP_MSI_MAPPING: 251169037Sjhb printf("MSI %saddress window %s at 0x", 252169037Sjhb command & PCIM_HTCMD_MSI_FIXED ? "fixed " : "", 253166435Sjhb command & PCIM_HTCMD_MSI_ENABLE ? "enabled" : 254166435Sjhb "disabled"); 255169037Sjhb if (command & PCIM_HTCMD_MSI_FIXED) 256169037Sjhb printf("fee00000"); 257169037Sjhb else { 258169037Sjhb reg = read_config(fd, &p->pc_sel, 259169037Sjhb ptr + PCIR_HTMSI_ADDRESS_HI, 4); 260169037Sjhb if (reg != 0) 261169037Sjhb printf("%08x", reg); 262169037Sjhb reg = read_config(fd, &p->pc_sel, 263169037Sjhb ptr + PCIR_HTMSI_ADDRESS_LO, 4); 264166435Sjhb printf("%08x", reg); 265169037Sjhb } 266166435Sjhb break; 267166435Sjhb case PCIM_HTCAP_DIRECT_ROUTE: 268166435Sjhb printf("direct route"); 269166435Sjhb break; 270166435Sjhb case PCIM_HTCAP_VCSET: 271166435Sjhb printf("VC set"); 272166435Sjhb break; 273166435Sjhb case PCIM_HTCAP_RETRY_MODE: 274166435Sjhb printf("retry mode"); 275166435Sjhb break; 276173059Sjhb case PCIM_HTCAP_X86_ENCODING: 277173059Sjhb printf("X86 encoding"); 278173059Sjhb break; 279250741Skib case PCIM_HTCAP_GEN3: 280250741Skib printf("Gen3"); 281250741Skib break; 282250741Skib case PCIM_HTCAP_FLE: 283250741Skib printf("function-level extension"); 284250741Skib break; 285250741Skib case PCIM_HTCAP_PM: 286250741Skib printf("power management"); 287250741Skib break; 288250741Skib case PCIM_HTCAP_HIGH_NODE_COUNT: 289250741Skib printf("high node count"); 290250741Skib break; 291166435Sjhb default: 292166435Sjhb printf("unknown %02x", command); 293166435Sjhb break; 294166435Sjhb } 295166435Sjhb} 296166435Sjhb 297166435Sjhbstatic void 298166435Sjhbcap_vendor(int fd, struct pci_conf *p, uint8_t ptr) 299166435Sjhb{ 300166435Sjhb uint8_t length; 301166435Sjhb 302166435Sjhb length = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_LENGTH, 1); 303166435Sjhb printf("vendor (length %d)", length); 304166435Sjhb if (p->pc_vendor == 0x8086) { 305166435Sjhb /* Intel */ 306166435Sjhb uint8_t version; 307166435Sjhb 308166435Sjhb version = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_DATA, 309166435Sjhb 1); 310166435Sjhb printf(" Intel cap %d version %d", version >> 4, version & 0xf); 311166435Sjhb if (version >> 4 == 1 && length == 12) { 312166435Sjhb /* Feature Detection */ 313166435Sjhb uint32_t fvec; 314166435Sjhb int comma; 315166435Sjhb 316166435Sjhb comma = 0; 317166435Sjhb fvec = read_config(fd, &p->pc_sel, ptr + 318166435Sjhb PCIR_VENDOR_DATA + 5, 4); 319166435Sjhb printf("\n\t\t features:"); 320166435Sjhb if (fvec & (1 << 0)) { 321166435Sjhb printf(" AMT"); 322166435Sjhb comma = 1; 323166435Sjhb } 324166435Sjhb fvec = read_config(fd, &p->pc_sel, ptr + 325166435Sjhb PCIR_VENDOR_DATA + 1, 4); 326166435Sjhb if (fvec & (1 << 21)) { 327166435Sjhb printf("%s Quick Resume", comma ? "," : ""); 328166435Sjhb comma = 1; 329166435Sjhb } 330166435Sjhb if (fvec & (1 << 18)) { 331166435Sjhb printf("%s SATA RAID-5", comma ? "," : ""); 332166435Sjhb comma = 1; 333166435Sjhb } 334166435Sjhb if (fvec & (1 << 9)) { 335166435Sjhb printf("%s Mobile", comma ? "," : ""); 336166435Sjhb comma = 1; 337166435Sjhb } 338166435Sjhb if (fvec & (1 << 7)) { 339166435Sjhb printf("%s 6 PCI-e x1 slots", comma ? "," : ""); 340166435Sjhb comma = 1; 341166435Sjhb } else { 342166435Sjhb printf("%s 4 PCI-e x1 slots", comma ? "," : ""); 343166435Sjhb comma = 1; 344166435Sjhb } 345166435Sjhb if (fvec & (1 << 5)) { 346166435Sjhb printf("%s SATA RAID-0/1/10", comma ? "," : ""); 347166435Sjhb comma = 1; 348166435Sjhb } 349166435Sjhb if (fvec & (1 << 3)) { 350166435Sjhb printf("%s SATA AHCI", comma ? "," : ""); 351166435Sjhb comma = 1; 352166435Sjhb } 353166435Sjhb } 354166435Sjhb } 355166435Sjhb} 356166435Sjhb 357166435Sjhbstatic void 358166435Sjhbcap_debug(int fd, struct pci_conf *p, uint8_t ptr) 359166435Sjhb{ 360166435Sjhb uint16_t debug_port; 361166435Sjhb 362166435Sjhb debug_port = read_config(fd, &p->pc_sel, ptr + PCIR_DEBUG_PORT, 2); 363166435Sjhb printf("EHCI Debug Port at offset 0x%x in map 0x%x", debug_port & 364166435Sjhb PCIM_DEBUG_PORT_OFFSET, PCIR_BAR(debug_port >> 13)); 365166435Sjhb} 366166435Sjhb 367166435Sjhbstatic void 368166435Sjhbcap_subvendor(int fd, struct pci_conf *p, uint8_t ptr) 369166435Sjhb{ 370166435Sjhb uint32_t id; 371166435Sjhb 372166435Sjhb id = read_config(fd, &p->pc_sel, ptr + PCIR_SUBVENDCAP_ID, 4); 373166435Sjhb printf("PCI Bridge card=0x%08x", id); 374166435Sjhb} 375166435Sjhb 376191222Sjhb#define MAX_PAYLOAD(field) (128 << (field)) 377191222Sjhb 378242085Sjimharrisstatic const char * 379242085Sjimharrislink_speed_string(uint8_t speed) 380242085Sjimharris{ 381242085Sjimharris 382242085Sjimharris switch (speed) { 383242085Sjimharris case 1: 384242085Sjimharris return ("2.5"); 385242085Sjimharris case 2: 386242085Sjimharris return ("5.0"); 387242085Sjimharris case 3: 388242085Sjimharris return ("8.0"); 389242085Sjimharris default: 390242085Sjimharris return ("undef"); 391242085Sjimharris } 392242085Sjimharris} 393242085Sjimharris 394253455Sjkimstatic const char * 395253455Sjkimaspm_string(uint8_t aspm) 396253455Sjkim{ 397253455Sjkim 398253455Sjkim switch (aspm) { 399253455Sjkim case 1: 400253455Sjkim return ("L0s"); 401253455Sjkim case 2: 402253455Sjkim return ("L1"); 403253455Sjkim case 3: 404253455Sjkim return ("L0s/L1"); 405253455Sjkim default: 406253455Sjkim return ("disabled"); 407253455Sjkim } 408253455Sjkim} 409253455Sjkim 410166435Sjhbstatic void 411166435Sjhbcap_express(int fd, struct pci_conf *p, uint8_t ptr) 412166435Sjhb{ 413279470Srstone uint32_t cap, cap2; 414253455Sjkim uint16_t ctl, flags, sta; 415166435Sjhb 416240680Sgavin flags = read_config(fd, &p->pc_sel, ptr + PCIER_FLAGS, 2); 417240680Sgavin printf("PCI-Express %d ", flags & PCIEM_FLAGS_VERSION); 418240680Sgavin switch (flags & PCIEM_FLAGS_TYPE) { 419240680Sgavin case PCIEM_TYPE_ENDPOINT: 420166435Sjhb printf("endpoint"); 421166435Sjhb break; 422240680Sgavin case PCIEM_TYPE_LEGACY_ENDPOINT: 423166435Sjhb printf("legacy endpoint"); 424166435Sjhb break; 425240680Sgavin case PCIEM_TYPE_ROOT_PORT: 426166435Sjhb printf("root port"); 427166435Sjhb break; 428240680Sgavin case PCIEM_TYPE_UPSTREAM_PORT: 429166435Sjhb printf("upstream port"); 430166435Sjhb break; 431240680Sgavin case PCIEM_TYPE_DOWNSTREAM_PORT: 432166435Sjhb printf("downstream port"); 433166435Sjhb break; 434240680Sgavin case PCIEM_TYPE_PCI_BRIDGE: 435166435Sjhb printf("PCI bridge"); 436166435Sjhb break; 437240680Sgavin case PCIEM_TYPE_PCIE_BRIDGE: 438191222Sjhb printf("PCI to PCIe bridge"); 439191222Sjhb break; 440240680Sgavin case PCIEM_TYPE_ROOT_INT_EP: 441191222Sjhb printf("root endpoint"); 442191222Sjhb break; 443240680Sgavin case PCIEM_TYPE_ROOT_EC: 444191222Sjhb printf("event collector"); 445191222Sjhb break; 446166435Sjhb default: 447240680Sgavin printf("type %d", (flags & PCIEM_FLAGS_TYPE) >> 4); 448166435Sjhb break; 449166435Sjhb } 450240680Sgavin if (flags & PCIEM_FLAGS_SLOT) 451240146Sgavin printf(" slot"); 452240680Sgavin if (flags & PCIEM_FLAGS_IRQ) 453240680Sgavin printf(" IRQ %d", (flags & PCIEM_FLAGS_IRQ) >> 9); 454253455Sjkim cap = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CAP, 4); 455279470Srstone cap2 = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CAP2, 4); 456253455Sjkim ctl = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CTL, 2); 457191222Sjhb printf(" max data %d(%d)", 458253455Sjkim MAX_PAYLOAD((ctl & PCIEM_CTL_MAX_PAYLOAD) >> 5), 459253455Sjkim MAX_PAYLOAD(cap & PCIEM_CAP_MAX_PAYLOAD)); 460253455Sjkim if ((cap & PCIEM_CAP_FLR) != 0) 461240474Sjhb printf(" FLR"); 462290804Sjhb if (ctl & PCIEM_CTL_RELAXED_ORD_ENABLE) 463290804Sjhb printf(" RO"); 464290804Sjhb if (ctl & PCIEM_CTL_NOSNOOP_ENABLE) 465290804Sjhb printf(" NS"); 466253455Sjkim cap = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_CAP, 4); 467253455Sjkim sta = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_STA, 2); 468253455Sjkim printf(" link x%d(x%d)", (sta & PCIEM_LINK_STA_WIDTH) >> 4, 469253455Sjkim (cap & PCIEM_LINK_CAP_MAX_WIDTH) >> 4); 470253455Sjkim if ((cap & (PCIEM_LINK_CAP_MAX_WIDTH | PCIEM_LINK_CAP_ASPM)) != 0) 471253455Sjkim printf("\n "); 472253455Sjkim if ((cap & PCIEM_LINK_CAP_MAX_WIDTH) != 0) { 473253455Sjkim printf(" speed %s(%s)", (sta & PCIEM_LINK_STA_WIDTH) == 0 ? 474253455Sjkim "0.0" : link_speed_string(sta & PCIEM_LINK_STA_SPEED), 475253455Sjkim link_speed_string(cap & PCIEM_LINK_CAP_MAX_SPEED)); 476242085Sjimharris } 477253455Sjkim if ((cap & PCIEM_LINK_CAP_ASPM) != 0) { 478253455Sjkim ctl = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_CTL, 2); 479253455Sjkim printf(" ASPM %s(%s)", aspm_string(ctl & PCIEM_LINK_CTL_ASPMC), 480253455Sjkim aspm_string((cap & PCIEM_LINK_CAP_ASPM) >> 10)); 481253455Sjkim } 482279470Srstone if ((cap2 & PCIEM_CAP2_ARI) != 0) { 483279470Srstone ctl = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CTL2, 4); 484279470Srstone printf(" ARI %s", 485279470Srstone (ctl & PCIEM_CTL2_ARI) ? "enabled" : "disabled"); 486279470Srstone } 487166435Sjhb} 488166435Sjhb 489166435Sjhbstatic void 490166435Sjhbcap_msix(int fd, struct pci_conf *p, uint8_t ptr) 491166435Sjhb{ 492246221Sneel uint32_t pba_offset, table_offset, val; 493246221Sneel int msgnum, pba_bar, table_bar; 494166435Sjhb uint16_t ctrl; 495166435Sjhb 496166435Sjhb ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_CTRL, 2); 497166435Sjhb msgnum = (ctrl & PCIM_MSIXCTRL_TABLE_SIZE) + 1; 498246221Sneel 499166435Sjhb val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_TABLE, 4); 500166435Sjhb table_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); 501246221Sneel table_offset = val & ~PCIM_MSIX_BIR_MASK; 502246221Sneel 503166435Sjhb val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_PBA, 4); 504246221Sneel pba_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); 505246221Sneel pba_offset = val & ~PCIM_MSIX_BIR_MASK; 506246221Sneel 507246221Sneel printf("MSI-X supports %d message%s%s\n", msgnum, 508246221Sneel (msgnum == 1) ? "" : "s", 509246221Sneel (ctrl & PCIM_MSIXCTRL_MSIX_ENABLE) ? ", enabled" : ""); 510246221Sneel 511246221Sneel printf(" "); 512246221Sneel printf("Table in map 0x%x[0x%x], PBA in map 0x%x[0x%x]", 513246221Sneel table_bar, table_offset, pba_bar, pba_offset); 514166435Sjhb} 515166435Sjhb 516188640Smavstatic void 517188640Smavcap_sata(int fd, struct pci_conf *p, uint8_t ptr) 518188640Smav{ 519188640Smav 520188640Smav printf("SATA Index-Data Pair"); 521188640Smav} 522188640Smav 523188640Smavstatic void 524188640Smavcap_pciaf(int fd, struct pci_conf *p, uint8_t ptr) 525188640Smav{ 526188640Smav uint8_t cap; 527188640Smav 528188640Smav cap = read_config(fd, &p->pc_sel, ptr + PCIR_PCIAF_CAP, 1); 529188641Smav printf("PCI Advanced Features:%s%s", 530188641Smav cap & PCIM_PCIAFCAP_FLR ? " FLR" : "", 531188641Smav cap & PCIM_PCIAFCAP_TP ? " TP" : ""); 532188640Smav} 533188640Smav 534166435Sjhbvoid 535166435Sjhblist_caps(int fd, struct pci_conf *p) 536166435Sjhb{ 537212749Sjhb int express; 538212369Sjhb uint16_t sta; 539166435Sjhb uint8_t ptr, cap; 540166435Sjhb 541166435Sjhb /* Are capabilities present for this device? */ 542212369Sjhb sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); 543212369Sjhb if (!(sta & PCIM_STATUS_CAPPRESENT)) 544166435Sjhb return; 545166435Sjhb 546166435Sjhb switch (p->pc_hdr & PCIM_HDRTYPE) { 547212369Sjhb case PCIM_HDRTYPE_NORMAL: 548212369Sjhb case PCIM_HDRTYPE_BRIDGE: 549166435Sjhb ptr = PCIR_CAP_PTR; 550166435Sjhb break; 551212369Sjhb case PCIM_HDRTYPE_CARDBUS: 552166435Sjhb ptr = PCIR_CAP_PTR_2; 553166435Sjhb break; 554166435Sjhb default: 555166435Sjhb errx(1, "list_caps: bad header type"); 556166435Sjhb } 557166435Sjhb 558166435Sjhb /* Walk the capability list. */ 559212749Sjhb express = 0; 560166435Sjhb ptr = read_config(fd, &p->pc_sel, ptr, 1); 561166435Sjhb while (ptr != 0 && ptr != 0xff) { 562166435Sjhb cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1); 563166435Sjhb printf(" cap %02x[%02x] = ", cap, ptr); 564166435Sjhb switch (cap) { 565166435Sjhb case PCIY_PMG: 566166435Sjhb cap_power(fd, p, ptr); 567166435Sjhb break; 568166435Sjhb case PCIY_AGP: 569166435Sjhb cap_agp(fd, p, ptr); 570166435Sjhb break; 571166435Sjhb case PCIY_VPD: 572166435Sjhb cap_vpd(fd, p, ptr); 573166435Sjhb break; 574166435Sjhb case PCIY_MSI: 575166435Sjhb cap_msi(fd, p, ptr); 576166435Sjhb break; 577166435Sjhb case PCIY_PCIX: 578166435Sjhb cap_pcix(fd, p, ptr); 579166435Sjhb break; 580166435Sjhb case PCIY_HT: 581166435Sjhb cap_ht(fd, p, ptr); 582166435Sjhb break; 583166435Sjhb case PCIY_VENDOR: 584166435Sjhb cap_vendor(fd, p, ptr); 585166435Sjhb break; 586166435Sjhb case PCIY_DEBUG: 587166435Sjhb cap_debug(fd, p, ptr); 588166435Sjhb break; 589166435Sjhb case PCIY_SUBVENDOR: 590166435Sjhb cap_subvendor(fd, p, ptr); 591166435Sjhb break; 592166435Sjhb case PCIY_EXPRESS: 593212749Sjhb express = 1; 594166435Sjhb cap_express(fd, p, ptr); 595166435Sjhb break; 596166435Sjhb case PCIY_MSIX: 597166435Sjhb cap_msix(fd, p, ptr); 598166435Sjhb break; 599188640Smav case PCIY_SATA: 600188640Smav cap_sata(fd, p, ptr); 601188640Smav break; 602188640Smav case PCIY_PCIAF: 603188640Smav cap_pciaf(fd, p, ptr); 604188640Smav break; 605166435Sjhb default: 606166435Sjhb printf("unknown"); 607166435Sjhb break; 608166435Sjhb } 609166435Sjhb printf("\n"); 610166435Sjhb ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1); 611166435Sjhb } 612212326Sjhb 613212749Sjhb if (express) 614212749Sjhb list_ecaps(fd, p); 615166435Sjhb} 616212326Sjhb 617212326Sjhb/* From <sys/systm.h>. */ 618212326Sjhbstatic __inline uint32_t 619212326Sjhbbitcount32(uint32_t x) 620212326Sjhb{ 621212326Sjhb 622212326Sjhb x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1); 623212326Sjhb x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2); 624212326Sjhb x = (x + (x >> 4)) & 0x0f0f0f0f; 625212326Sjhb x = (x + (x >> 8)); 626212326Sjhb x = (x + (x >> 16)) & 0x000000ff; 627212326Sjhb return (x); 628212326Sjhb} 629212326Sjhb 630212326Sjhbstatic void 631212326Sjhbecap_aer(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 632212326Sjhb{ 633212326Sjhb uint32_t sta, mask; 634212326Sjhb 635212326Sjhb printf("AER %d", ver); 636240474Sjhb if (ver < 1) 637212326Sjhb return; 638212326Sjhb sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_STATUS, 4); 639212326Sjhb mask = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_SEVERITY, 4); 640212326Sjhb printf(" %d fatal", bitcount32(sta & mask)); 641212326Sjhb printf(" %d non-fatal", bitcount32(sta & ~mask)); 642212326Sjhb sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_COR_STATUS, 4); 643212326Sjhb printf(" %d corrected", bitcount32(sta)); 644212326Sjhb} 645212326Sjhb 646212326Sjhbstatic void 647212326Sjhbecap_vc(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 648212326Sjhb{ 649212326Sjhb uint32_t cap1; 650212326Sjhb 651212326Sjhb printf("VC %d", ver); 652240474Sjhb if (ver < 1) 653212326Sjhb return; 654212326Sjhb cap1 = read_config(fd, &p->pc_sel, ptr + PCIR_VC_CAP1, 4); 655212326Sjhb printf(" max VC%d", cap1 & PCIM_VC_CAP1_EXT_COUNT); 656212326Sjhb if ((cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) != 0) 657212326Sjhb printf(" lowpri VC0-VC%d", 658212326Sjhb (cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) >> 4); 659212326Sjhb} 660212326Sjhb 661212326Sjhbstatic void 662212326Sjhbecap_sernum(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 663212326Sjhb{ 664212326Sjhb uint32_t high, low; 665212326Sjhb 666212326Sjhb printf("Serial %d", ver); 667240474Sjhb if (ver < 1) 668212326Sjhb return; 669212326Sjhb low = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_LOW, 4); 670212326Sjhb high = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_HIGH, 4); 671212326Sjhb printf(" %08x%08x", high, low); 672212326Sjhb} 673212326Sjhb 674212326Sjhbstatic void 675240474Sjhbecap_vendor(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 676240474Sjhb{ 677240474Sjhb uint32_t val; 678240474Sjhb 679240474Sjhb printf("Vendor %d", ver); 680240474Sjhb if (ver < 1) 681240474Sjhb return; 682240474Sjhb val = read_config(fd, &p->pc_sel, ptr + 4, 4); 683240474Sjhb printf(" ID %d", val & 0xffff); 684240474Sjhb} 685240474Sjhb 686240474Sjhbstatic void 687240474Sjhbecap_sec_pcie(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 688240474Sjhb{ 689240474Sjhb uint32_t val; 690240474Sjhb 691240474Sjhb printf("PCIe Sec %d", ver); 692240474Sjhb if (ver < 1) 693240474Sjhb return; 694240474Sjhb val = read_config(fd, &p->pc_sel, ptr + 8, 4); 695240474Sjhb printf(" lane errors %#x", val); 696240474Sjhb} 697240474Sjhb 698240474Sjhbstruct { 699240474Sjhb uint16_t id; 700240474Sjhb const char *name; 701240474Sjhb} ecap_names[] = { 702240474Sjhb { PCIZ_PWRBDGT, "Power Budgeting" }, 703240474Sjhb { PCIZ_RCLINK_DCL, "Root Complex Link Declaration" }, 704240474Sjhb { PCIZ_RCLINK_CTL, "Root Complex Internal Link Control" }, 705240474Sjhb { PCIZ_RCEC_ASSOC, "Root Complex Event Collector ASsociation" }, 706240474Sjhb { PCIZ_MFVC, "MFVC" }, 707240474Sjhb { PCIZ_RCRB, "RCRB" }, 708240474Sjhb { PCIZ_ACS, "ACS" }, 709240474Sjhb { PCIZ_ARI, "ARI" }, 710240474Sjhb { PCIZ_ATS, "ATS" }, 711240474Sjhb { PCIZ_SRIOV, "SRIOV" }, 712240474Sjhb { PCIZ_MULTICAST, "Multicast" }, 713240474Sjhb { PCIZ_RESIZE_BAR, "Resizable BAR" }, 714240474Sjhb { PCIZ_DPA, "DPA" }, 715240474Sjhb { PCIZ_TPH_REQ, "TPH Requester" }, 716240474Sjhb { PCIZ_LTR, "LTR" }, 717240474Sjhb { 0, NULL } 718240474Sjhb}; 719240474Sjhb 720240474Sjhbstatic void 721212326Sjhblist_ecaps(int fd, struct pci_conf *p) 722212326Sjhb{ 723240474Sjhb const char *name; 724212326Sjhb uint32_t ecap; 725212326Sjhb uint16_t ptr; 726240474Sjhb int i; 727212326Sjhb 728212326Sjhb ptr = PCIR_EXTCAP; 729212326Sjhb ecap = read_config(fd, &p->pc_sel, ptr, 4); 730212326Sjhb if (ecap == 0xffffffff || ecap == 0) 731212326Sjhb return; 732212326Sjhb for (;;) { 733241757Simp printf(" ecap %04x[%03x] = ", PCI_EXTCAP_ID(ecap), ptr); 734212326Sjhb switch (PCI_EXTCAP_ID(ecap)) { 735212326Sjhb case PCIZ_AER: 736212326Sjhb ecap_aer(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 737212326Sjhb break; 738212326Sjhb case PCIZ_VC: 739212326Sjhb ecap_vc(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 740212326Sjhb break; 741212326Sjhb case PCIZ_SERNUM: 742212326Sjhb ecap_sernum(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 743212326Sjhb break; 744240474Sjhb case PCIZ_VENDOR: 745240474Sjhb ecap_vendor(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 746240474Sjhb break; 747240474Sjhb case PCIZ_SEC_PCIE: 748240474Sjhb ecap_sec_pcie(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 749240474Sjhb break; 750212326Sjhb default: 751240474Sjhb name = "unknown"; 752240474Sjhb for (i = 0; ecap_names[i].name != NULL; i++) 753240474Sjhb if (ecap_names[i].id == PCI_EXTCAP_ID(ecap)) { 754240474Sjhb name = ecap_names[i].name; 755240474Sjhb break; 756240474Sjhb } 757240474Sjhb printf("%s %d", name, PCI_EXTCAP_VER(ecap)); 758212326Sjhb break; 759212326Sjhb } 760212326Sjhb printf("\n"); 761212326Sjhb ptr = PCI_EXTCAP_NEXTPTR(ecap); 762212326Sjhb if (ptr == 0) 763212326Sjhb break; 764212326Sjhb ecap = read_config(fd, &p->pc_sel, ptr, 4); 765212326Sjhb } 766212326Sjhb} 767236415Sjhb 768236415Sjhb/* Find offset of a specific capability. Returns 0 on failure. */ 769236415Sjhbuint8_t 770236415Sjhbpci_find_cap(int fd, struct pci_conf *p, uint8_t id) 771236415Sjhb{ 772236415Sjhb uint16_t sta; 773236415Sjhb uint8_t ptr, cap; 774236415Sjhb 775236415Sjhb /* Are capabilities present for this device? */ 776236415Sjhb sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); 777236415Sjhb if (!(sta & PCIM_STATUS_CAPPRESENT)) 778236415Sjhb return (0); 779236415Sjhb 780236415Sjhb switch (p->pc_hdr & PCIM_HDRTYPE) { 781236415Sjhb case PCIM_HDRTYPE_NORMAL: 782236415Sjhb case PCIM_HDRTYPE_BRIDGE: 783236415Sjhb ptr = PCIR_CAP_PTR; 784236415Sjhb break; 785236415Sjhb case PCIM_HDRTYPE_CARDBUS: 786236415Sjhb ptr = PCIR_CAP_PTR_2; 787236415Sjhb break; 788236415Sjhb default: 789236415Sjhb return (0); 790236415Sjhb } 791236415Sjhb 792236415Sjhb ptr = read_config(fd, &p->pc_sel, ptr, 1); 793236415Sjhb while (ptr != 0 && ptr != 0xff) { 794236415Sjhb cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1); 795236415Sjhb if (cap == id) 796236415Sjhb return (ptr); 797236415Sjhb ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1); 798236415Sjhb } 799236415Sjhb return (0); 800236415Sjhb} 801236415Sjhb 802236415Sjhb/* Find offset of a specific extended capability. Returns 0 on failure. */ 803236415Sjhbuint16_t 804236415Sjhbpcie_find_cap(int fd, struct pci_conf *p, uint16_t id) 805236415Sjhb{ 806236415Sjhb uint32_t ecap; 807236415Sjhb uint16_t ptr; 808236415Sjhb 809236415Sjhb ptr = PCIR_EXTCAP; 810236415Sjhb ecap = read_config(fd, &p->pc_sel, ptr, 4); 811236415Sjhb if (ecap == 0xffffffff || ecap == 0) 812236415Sjhb return (0); 813236415Sjhb for (;;) { 814236415Sjhb if (PCI_EXTCAP_ID(ecap) == id) 815236415Sjhb return (ptr); 816236415Sjhb ptr = PCI_EXTCAP_NEXTPTR(ecap); 817236415Sjhb if (ptr == 0) 818236415Sjhb break; 819236415Sjhb ecap = read_config(fd, &p->pc_sel, ptr, 4); 820236415Sjhb } 821236415Sjhb return (0); 822236415Sjhb} 823