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{ 413253455Sjkim uint32_t cap; 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); 455253455Sjkim ctl = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CTL, 2); 456191222Sjhb printf(" max data %d(%d)", 457253455Sjkim MAX_PAYLOAD((ctl & PCIEM_CTL_MAX_PAYLOAD) >> 5), 458253455Sjkim MAX_PAYLOAD(cap & PCIEM_CAP_MAX_PAYLOAD)); 459253455Sjkim if ((cap & PCIEM_CAP_FLR) != 0) 460240474Sjhb printf(" FLR"); 461253455Sjkim cap = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_CAP, 4); 462253455Sjkim sta = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_STA, 2); 463253455Sjkim printf(" link x%d(x%d)", (sta & PCIEM_LINK_STA_WIDTH) >> 4, 464253455Sjkim (cap & PCIEM_LINK_CAP_MAX_WIDTH) >> 4); 465253455Sjkim if ((cap & (PCIEM_LINK_CAP_MAX_WIDTH | PCIEM_LINK_CAP_ASPM)) != 0) 466253455Sjkim printf("\n "); 467253455Sjkim if ((cap & PCIEM_LINK_CAP_MAX_WIDTH) != 0) { 468253455Sjkim printf(" speed %s(%s)", (sta & PCIEM_LINK_STA_WIDTH) == 0 ? 469253455Sjkim "0.0" : link_speed_string(sta & PCIEM_LINK_STA_SPEED), 470253455Sjkim link_speed_string(cap & PCIEM_LINK_CAP_MAX_SPEED)); 471242085Sjimharris } 472253455Sjkim if ((cap & PCIEM_LINK_CAP_ASPM) != 0) { 473253455Sjkim ctl = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_CTL, 2); 474253455Sjkim printf(" ASPM %s(%s)", aspm_string(ctl & PCIEM_LINK_CTL_ASPMC), 475253455Sjkim aspm_string((cap & PCIEM_LINK_CAP_ASPM) >> 10)); 476253455Sjkim } 477166435Sjhb} 478166435Sjhb 479166435Sjhbstatic void 480166435Sjhbcap_msix(int fd, struct pci_conf *p, uint8_t ptr) 481166435Sjhb{ 482246221Sneel uint32_t pba_offset, table_offset, val; 483246221Sneel int msgnum, pba_bar, table_bar; 484166435Sjhb uint16_t ctrl; 485166435Sjhb 486166435Sjhb ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_CTRL, 2); 487166435Sjhb msgnum = (ctrl & PCIM_MSIXCTRL_TABLE_SIZE) + 1; 488246221Sneel 489166435Sjhb val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_TABLE, 4); 490166435Sjhb table_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); 491246221Sneel table_offset = val & ~PCIM_MSIX_BIR_MASK; 492246221Sneel 493166435Sjhb val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_PBA, 4); 494246221Sneel pba_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); 495246221Sneel pba_offset = val & ~PCIM_MSIX_BIR_MASK; 496246221Sneel 497246221Sneel printf("MSI-X supports %d message%s%s\n", msgnum, 498246221Sneel (msgnum == 1) ? "" : "s", 499246221Sneel (ctrl & PCIM_MSIXCTRL_MSIX_ENABLE) ? ", enabled" : ""); 500246221Sneel 501246221Sneel printf(" "); 502246221Sneel printf("Table in map 0x%x[0x%x], PBA in map 0x%x[0x%x]", 503246221Sneel table_bar, table_offset, pba_bar, pba_offset); 504166435Sjhb} 505166435Sjhb 506188640Smavstatic void 507188640Smavcap_sata(int fd, struct pci_conf *p, uint8_t ptr) 508188640Smav{ 509188640Smav 510188640Smav printf("SATA Index-Data Pair"); 511188640Smav} 512188640Smav 513188640Smavstatic void 514188640Smavcap_pciaf(int fd, struct pci_conf *p, uint8_t ptr) 515188640Smav{ 516188640Smav uint8_t cap; 517188640Smav 518188640Smav cap = read_config(fd, &p->pc_sel, ptr + PCIR_PCIAF_CAP, 1); 519188641Smav printf("PCI Advanced Features:%s%s", 520188641Smav cap & PCIM_PCIAFCAP_FLR ? " FLR" : "", 521188641Smav cap & PCIM_PCIAFCAP_TP ? " TP" : ""); 522188640Smav} 523188640Smav 524166435Sjhbvoid 525166435Sjhblist_caps(int fd, struct pci_conf *p) 526166435Sjhb{ 527212749Sjhb int express; 528212369Sjhb uint16_t sta; 529166435Sjhb uint8_t ptr, cap; 530166435Sjhb 531166435Sjhb /* Are capabilities present for this device? */ 532212369Sjhb sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); 533212369Sjhb if (!(sta & PCIM_STATUS_CAPPRESENT)) 534166435Sjhb return; 535166435Sjhb 536166435Sjhb switch (p->pc_hdr & PCIM_HDRTYPE) { 537212369Sjhb case PCIM_HDRTYPE_NORMAL: 538212369Sjhb case PCIM_HDRTYPE_BRIDGE: 539166435Sjhb ptr = PCIR_CAP_PTR; 540166435Sjhb break; 541212369Sjhb case PCIM_HDRTYPE_CARDBUS: 542166435Sjhb ptr = PCIR_CAP_PTR_2; 543166435Sjhb break; 544166435Sjhb default: 545166435Sjhb errx(1, "list_caps: bad header type"); 546166435Sjhb } 547166435Sjhb 548166435Sjhb /* Walk the capability list. */ 549212749Sjhb express = 0; 550166435Sjhb ptr = read_config(fd, &p->pc_sel, ptr, 1); 551166435Sjhb while (ptr != 0 && ptr != 0xff) { 552166435Sjhb cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1); 553166435Sjhb printf(" cap %02x[%02x] = ", cap, ptr); 554166435Sjhb switch (cap) { 555166435Sjhb case PCIY_PMG: 556166435Sjhb cap_power(fd, p, ptr); 557166435Sjhb break; 558166435Sjhb case PCIY_AGP: 559166435Sjhb cap_agp(fd, p, ptr); 560166435Sjhb break; 561166435Sjhb case PCIY_VPD: 562166435Sjhb cap_vpd(fd, p, ptr); 563166435Sjhb break; 564166435Sjhb case PCIY_MSI: 565166435Sjhb cap_msi(fd, p, ptr); 566166435Sjhb break; 567166435Sjhb case PCIY_PCIX: 568166435Sjhb cap_pcix(fd, p, ptr); 569166435Sjhb break; 570166435Sjhb case PCIY_HT: 571166435Sjhb cap_ht(fd, p, ptr); 572166435Sjhb break; 573166435Sjhb case PCIY_VENDOR: 574166435Sjhb cap_vendor(fd, p, ptr); 575166435Sjhb break; 576166435Sjhb case PCIY_DEBUG: 577166435Sjhb cap_debug(fd, p, ptr); 578166435Sjhb break; 579166435Sjhb case PCIY_SUBVENDOR: 580166435Sjhb cap_subvendor(fd, p, ptr); 581166435Sjhb break; 582166435Sjhb case PCIY_EXPRESS: 583212749Sjhb express = 1; 584166435Sjhb cap_express(fd, p, ptr); 585166435Sjhb break; 586166435Sjhb case PCIY_MSIX: 587166435Sjhb cap_msix(fd, p, ptr); 588166435Sjhb break; 589188640Smav case PCIY_SATA: 590188640Smav cap_sata(fd, p, ptr); 591188640Smav break; 592188640Smav case PCIY_PCIAF: 593188640Smav cap_pciaf(fd, p, ptr); 594188640Smav break; 595166435Sjhb default: 596166435Sjhb printf("unknown"); 597166435Sjhb break; 598166435Sjhb } 599166435Sjhb printf("\n"); 600166435Sjhb ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1); 601166435Sjhb } 602212326Sjhb 603212749Sjhb if (express) 604212749Sjhb list_ecaps(fd, p); 605166435Sjhb} 606212326Sjhb 607212326Sjhb/* From <sys/systm.h>. */ 608212326Sjhbstatic __inline uint32_t 609212326Sjhbbitcount32(uint32_t x) 610212326Sjhb{ 611212326Sjhb 612212326Sjhb x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1); 613212326Sjhb x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2); 614212326Sjhb x = (x + (x >> 4)) & 0x0f0f0f0f; 615212326Sjhb x = (x + (x >> 8)); 616212326Sjhb x = (x + (x >> 16)) & 0x000000ff; 617212326Sjhb return (x); 618212326Sjhb} 619212326Sjhb 620212326Sjhbstatic void 621212326Sjhbecap_aer(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 622212326Sjhb{ 623212326Sjhb uint32_t sta, mask; 624212326Sjhb 625212326Sjhb printf("AER %d", ver); 626240474Sjhb if (ver < 1) 627212326Sjhb return; 628212326Sjhb sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_STATUS, 4); 629212326Sjhb mask = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_SEVERITY, 4); 630212326Sjhb printf(" %d fatal", bitcount32(sta & mask)); 631212326Sjhb printf(" %d non-fatal", bitcount32(sta & ~mask)); 632212326Sjhb sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_COR_STATUS, 4); 633212326Sjhb printf(" %d corrected", bitcount32(sta)); 634212326Sjhb} 635212326Sjhb 636212326Sjhbstatic void 637212326Sjhbecap_vc(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 638212326Sjhb{ 639212326Sjhb uint32_t cap1; 640212326Sjhb 641212326Sjhb printf("VC %d", ver); 642240474Sjhb if (ver < 1) 643212326Sjhb return; 644212326Sjhb cap1 = read_config(fd, &p->pc_sel, ptr + PCIR_VC_CAP1, 4); 645212326Sjhb printf(" max VC%d", cap1 & PCIM_VC_CAP1_EXT_COUNT); 646212326Sjhb if ((cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) != 0) 647212326Sjhb printf(" lowpri VC0-VC%d", 648212326Sjhb (cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) >> 4); 649212326Sjhb} 650212326Sjhb 651212326Sjhbstatic void 652212326Sjhbecap_sernum(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 653212326Sjhb{ 654212326Sjhb uint32_t high, low; 655212326Sjhb 656212326Sjhb printf("Serial %d", ver); 657240474Sjhb if (ver < 1) 658212326Sjhb return; 659212326Sjhb low = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_LOW, 4); 660212326Sjhb high = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_HIGH, 4); 661212326Sjhb printf(" %08x%08x", high, low); 662212326Sjhb} 663212326Sjhb 664212326Sjhbstatic void 665240474Sjhbecap_vendor(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 666240474Sjhb{ 667240474Sjhb uint32_t val; 668240474Sjhb 669240474Sjhb printf("Vendor %d", ver); 670240474Sjhb if (ver < 1) 671240474Sjhb return; 672240474Sjhb val = read_config(fd, &p->pc_sel, ptr + 4, 4); 673240474Sjhb printf(" ID %d", val & 0xffff); 674240474Sjhb} 675240474Sjhb 676240474Sjhbstatic void 677240474Sjhbecap_sec_pcie(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 678240474Sjhb{ 679240474Sjhb uint32_t val; 680240474Sjhb 681240474Sjhb printf("PCIe Sec %d", ver); 682240474Sjhb if (ver < 1) 683240474Sjhb return; 684240474Sjhb val = read_config(fd, &p->pc_sel, ptr + 8, 4); 685240474Sjhb printf(" lane errors %#x", val); 686240474Sjhb} 687240474Sjhb 688240474Sjhbstruct { 689240474Sjhb uint16_t id; 690240474Sjhb const char *name; 691240474Sjhb} ecap_names[] = { 692240474Sjhb { PCIZ_PWRBDGT, "Power Budgeting" }, 693240474Sjhb { PCIZ_RCLINK_DCL, "Root Complex Link Declaration" }, 694240474Sjhb { PCIZ_RCLINK_CTL, "Root Complex Internal Link Control" }, 695240474Sjhb { PCIZ_RCEC_ASSOC, "Root Complex Event Collector ASsociation" }, 696240474Sjhb { PCIZ_MFVC, "MFVC" }, 697240474Sjhb { PCIZ_RCRB, "RCRB" }, 698240474Sjhb { PCIZ_ACS, "ACS" }, 699240474Sjhb { PCIZ_ARI, "ARI" }, 700240474Sjhb { PCIZ_ATS, "ATS" }, 701240474Sjhb { PCIZ_SRIOV, "SRIOV" }, 702240474Sjhb { PCIZ_MULTICAST, "Multicast" }, 703240474Sjhb { PCIZ_RESIZE_BAR, "Resizable BAR" }, 704240474Sjhb { PCIZ_DPA, "DPA" }, 705240474Sjhb { PCIZ_TPH_REQ, "TPH Requester" }, 706240474Sjhb { PCIZ_LTR, "LTR" }, 707240474Sjhb { 0, NULL } 708240474Sjhb}; 709240474Sjhb 710240474Sjhbstatic void 711212326Sjhblist_ecaps(int fd, struct pci_conf *p) 712212326Sjhb{ 713240474Sjhb const char *name; 714212326Sjhb uint32_t ecap; 715212326Sjhb uint16_t ptr; 716240474Sjhb int i; 717212326Sjhb 718212326Sjhb ptr = PCIR_EXTCAP; 719212326Sjhb ecap = read_config(fd, &p->pc_sel, ptr, 4); 720212326Sjhb if (ecap == 0xffffffff || ecap == 0) 721212326Sjhb return; 722212326Sjhb for (;;) { 723241757Simp printf(" ecap %04x[%03x] = ", PCI_EXTCAP_ID(ecap), ptr); 724212326Sjhb switch (PCI_EXTCAP_ID(ecap)) { 725212326Sjhb case PCIZ_AER: 726212326Sjhb ecap_aer(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 727212326Sjhb break; 728212326Sjhb case PCIZ_VC: 729212326Sjhb ecap_vc(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 730212326Sjhb break; 731212326Sjhb case PCIZ_SERNUM: 732212326Sjhb ecap_sernum(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 733212326Sjhb break; 734240474Sjhb case PCIZ_VENDOR: 735240474Sjhb ecap_vendor(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 736240474Sjhb break; 737240474Sjhb case PCIZ_SEC_PCIE: 738240474Sjhb ecap_sec_pcie(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 739240474Sjhb break; 740212326Sjhb default: 741240474Sjhb name = "unknown"; 742240474Sjhb for (i = 0; ecap_names[i].name != NULL; i++) 743240474Sjhb if (ecap_names[i].id == PCI_EXTCAP_ID(ecap)) { 744240474Sjhb name = ecap_names[i].name; 745240474Sjhb break; 746240474Sjhb } 747240474Sjhb printf("%s %d", name, PCI_EXTCAP_VER(ecap)); 748212326Sjhb break; 749212326Sjhb } 750212326Sjhb printf("\n"); 751212326Sjhb ptr = PCI_EXTCAP_NEXTPTR(ecap); 752212326Sjhb if (ptr == 0) 753212326Sjhb break; 754212326Sjhb ecap = read_config(fd, &p->pc_sel, ptr, 4); 755212326Sjhb } 756212326Sjhb} 757236415Sjhb 758236415Sjhb/* Find offset of a specific capability. Returns 0 on failure. */ 759236415Sjhbuint8_t 760236415Sjhbpci_find_cap(int fd, struct pci_conf *p, uint8_t id) 761236415Sjhb{ 762236415Sjhb uint16_t sta; 763236415Sjhb uint8_t ptr, cap; 764236415Sjhb 765236415Sjhb /* Are capabilities present for this device? */ 766236415Sjhb sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); 767236415Sjhb if (!(sta & PCIM_STATUS_CAPPRESENT)) 768236415Sjhb return (0); 769236415Sjhb 770236415Sjhb switch (p->pc_hdr & PCIM_HDRTYPE) { 771236415Sjhb case PCIM_HDRTYPE_NORMAL: 772236415Sjhb case PCIM_HDRTYPE_BRIDGE: 773236415Sjhb ptr = PCIR_CAP_PTR; 774236415Sjhb break; 775236415Sjhb case PCIM_HDRTYPE_CARDBUS: 776236415Sjhb ptr = PCIR_CAP_PTR_2; 777236415Sjhb break; 778236415Sjhb default: 779236415Sjhb return (0); 780236415Sjhb } 781236415Sjhb 782236415Sjhb ptr = read_config(fd, &p->pc_sel, ptr, 1); 783236415Sjhb while (ptr != 0 && ptr != 0xff) { 784236415Sjhb cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1); 785236415Sjhb if (cap == id) 786236415Sjhb return (ptr); 787236415Sjhb ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1); 788236415Sjhb } 789236415Sjhb return (0); 790236415Sjhb} 791236415Sjhb 792236415Sjhb/* Find offset of a specific extended capability. Returns 0 on failure. */ 793236415Sjhbuint16_t 794236415Sjhbpcie_find_cap(int fd, struct pci_conf *p, uint16_t id) 795236415Sjhb{ 796236415Sjhb uint32_t ecap; 797236415Sjhb uint16_t ptr; 798236415Sjhb 799236415Sjhb ptr = PCIR_EXTCAP; 800236415Sjhb ecap = read_config(fd, &p->pc_sel, ptr, 4); 801236415Sjhb if (ecap == 0xffffffff || ecap == 0) 802236415Sjhb return (0); 803236415Sjhb for (;;) { 804236415Sjhb if (PCI_EXTCAP_ID(ecap) == id) 805236415Sjhb return (ptr); 806236415Sjhb ptr = PCI_EXTCAP_NEXTPTR(ecap); 807236415Sjhb if (ptr == 0) 808236415Sjhb break; 809236415Sjhb ecap = read_config(fd, &p->pc_sel, ptr, 4); 810236415Sjhb } 811236415Sjhb return (0); 812236415Sjhb} 813