cap.c revision 242085
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: head/usr.sbin/pciconf/cap.c 242085 2012-10-25 17:22:37Z jimharris $"; 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; 279166435Sjhb default: 280166435Sjhb printf("unknown %02x", command); 281166435Sjhb break; 282166435Sjhb } 283166435Sjhb} 284166435Sjhb 285166435Sjhbstatic void 286166435Sjhbcap_vendor(int fd, struct pci_conf *p, uint8_t ptr) 287166435Sjhb{ 288166435Sjhb uint8_t length; 289166435Sjhb 290166435Sjhb length = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_LENGTH, 1); 291166435Sjhb printf("vendor (length %d)", length); 292166435Sjhb if (p->pc_vendor == 0x8086) { 293166435Sjhb /* Intel */ 294166435Sjhb uint8_t version; 295166435Sjhb 296166435Sjhb version = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_DATA, 297166435Sjhb 1); 298166435Sjhb printf(" Intel cap %d version %d", version >> 4, version & 0xf); 299166435Sjhb if (version >> 4 == 1 && length == 12) { 300166435Sjhb /* Feature Detection */ 301166435Sjhb uint32_t fvec; 302166435Sjhb int comma; 303166435Sjhb 304166435Sjhb comma = 0; 305166435Sjhb fvec = read_config(fd, &p->pc_sel, ptr + 306166435Sjhb PCIR_VENDOR_DATA + 5, 4); 307166435Sjhb printf("\n\t\t features:"); 308166435Sjhb if (fvec & (1 << 0)) { 309166435Sjhb printf(" AMT"); 310166435Sjhb comma = 1; 311166435Sjhb } 312166435Sjhb fvec = read_config(fd, &p->pc_sel, ptr + 313166435Sjhb PCIR_VENDOR_DATA + 1, 4); 314166435Sjhb if (fvec & (1 << 21)) { 315166435Sjhb printf("%s Quick Resume", comma ? "," : ""); 316166435Sjhb comma = 1; 317166435Sjhb } 318166435Sjhb if (fvec & (1 << 18)) { 319166435Sjhb printf("%s SATA RAID-5", comma ? "," : ""); 320166435Sjhb comma = 1; 321166435Sjhb } 322166435Sjhb if (fvec & (1 << 9)) { 323166435Sjhb printf("%s Mobile", comma ? "," : ""); 324166435Sjhb comma = 1; 325166435Sjhb } 326166435Sjhb if (fvec & (1 << 7)) { 327166435Sjhb printf("%s 6 PCI-e x1 slots", comma ? "," : ""); 328166435Sjhb comma = 1; 329166435Sjhb } else { 330166435Sjhb printf("%s 4 PCI-e x1 slots", comma ? "," : ""); 331166435Sjhb comma = 1; 332166435Sjhb } 333166435Sjhb if (fvec & (1 << 5)) { 334166435Sjhb printf("%s SATA RAID-0/1/10", comma ? "," : ""); 335166435Sjhb comma = 1; 336166435Sjhb } 337166435Sjhb if (fvec & (1 << 3)) { 338166435Sjhb printf("%s SATA AHCI", comma ? "," : ""); 339166435Sjhb comma = 1; 340166435Sjhb } 341166435Sjhb } 342166435Sjhb } 343166435Sjhb} 344166435Sjhb 345166435Sjhbstatic void 346166435Sjhbcap_debug(int fd, struct pci_conf *p, uint8_t ptr) 347166435Sjhb{ 348166435Sjhb uint16_t debug_port; 349166435Sjhb 350166435Sjhb debug_port = read_config(fd, &p->pc_sel, ptr + PCIR_DEBUG_PORT, 2); 351166435Sjhb printf("EHCI Debug Port at offset 0x%x in map 0x%x", debug_port & 352166435Sjhb PCIM_DEBUG_PORT_OFFSET, PCIR_BAR(debug_port >> 13)); 353166435Sjhb} 354166435Sjhb 355166435Sjhbstatic void 356166435Sjhbcap_subvendor(int fd, struct pci_conf *p, uint8_t ptr) 357166435Sjhb{ 358166435Sjhb uint32_t id; 359166435Sjhb 360166435Sjhb id = read_config(fd, &p->pc_sel, ptr + PCIR_SUBVENDCAP_ID, 4); 361166435Sjhb printf("PCI Bridge card=0x%08x", id); 362166435Sjhb} 363166435Sjhb 364191222Sjhb#define MAX_PAYLOAD(field) (128 << (field)) 365191222Sjhb 366242085Sjimharrisstatic const char * 367242085Sjimharrislink_speed_string(uint8_t speed) 368242085Sjimharris{ 369242085Sjimharris 370242085Sjimharris switch (speed) { 371242085Sjimharris case 1: 372242085Sjimharris return ("2.5"); 373242085Sjimharris case 2: 374242085Sjimharris return ("5.0"); 375242085Sjimharris case 3: 376242085Sjimharris return ("8.0"); 377242085Sjimharris default: 378242085Sjimharris return ("undef"); 379242085Sjimharris } 380242085Sjimharris} 381242085Sjimharris 382166435Sjhbstatic void 383166435Sjhbcap_express(int fd, struct pci_conf *p, uint8_t ptr) 384166435Sjhb{ 385191222Sjhb uint32_t val; 386166435Sjhb uint16_t flags; 387166435Sjhb 388240680Sgavin flags = read_config(fd, &p->pc_sel, ptr + PCIER_FLAGS, 2); 389240680Sgavin printf("PCI-Express %d ", flags & PCIEM_FLAGS_VERSION); 390240680Sgavin switch (flags & PCIEM_FLAGS_TYPE) { 391240680Sgavin case PCIEM_TYPE_ENDPOINT: 392166435Sjhb printf("endpoint"); 393166435Sjhb break; 394240680Sgavin case PCIEM_TYPE_LEGACY_ENDPOINT: 395166435Sjhb printf("legacy endpoint"); 396166435Sjhb break; 397240680Sgavin case PCIEM_TYPE_ROOT_PORT: 398166435Sjhb printf("root port"); 399166435Sjhb break; 400240680Sgavin case PCIEM_TYPE_UPSTREAM_PORT: 401166435Sjhb printf("upstream port"); 402166435Sjhb break; 403240680Sgavin case PCIEM_TYPE_DOWNSTREAM_PORT: 404166435Sjhb printf("downstream port"); 405166435Sjhb break; 406240680Sgavin case PCIEM_TYPE_PCI_BRIDGE: 407166435Sjhb printf("PCI bridge"); 408166435Sjhb break; 409240680Sgavin case PCIEM_TYPE_PCIE_BRIDGE: 410191222Sjhb printf("PCI to PCIe bridge"); 411191222Sjhb break; 412240680Sgavin case PCIEM_TYPE_ROOT_INT_EP: 413191222Sjhb printf("root endpoint"); 414191222Sjhb break; 415240680Sgavin case PCIEM_TYPE_ROOT_EC: 416191222Sjhb printf("event collector"); 417191222Sjhb break; 418166435Sjhb default: 419240680Sgavin printf("type %d", (flags & PCIEM_FLAGS_TYPE) >> 4); 420166435Sjhb break; 421166435Sjhb } 422240680Sgavin if (flags & PCIEM_FLAGS_SLOT) 423240146Sgavin printf(" slot"); 424240680Sgavin if (flags & PCIEM_FLAGS_IRQ) 425240680Sgavin printf(" IRQ %d", (flags & PCIEM_FLAGS_IRQ) >> 9); 426240680Sgavin val = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CAP, 4); 427240680Sgavin flags = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CTL, 2); 428191222Sjhb printf(" max data %d(%d)", 429240680Sgavin MAX_PAYLOAD((flags & PCIEM_CTL_MAX_PAYLOAD) >> 5), 430240680Sgavin MAX_PAYLOAD(val & PCIEM_CAP_MAX_PAYLOAD)); 431240680Sgavin if (val & PCIEM_CAP_FLR) 432240474Sjhb printf(" FLR"); 433240680Sgavin val = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_CAP, 4); 434240680Sgavin flags = read_config(fd, &p->pc_sel, ptr+ PCIER_LINK_STA, 2); 435240680Sgavin printf(" link x%d(x%d)", (flags & PCIEM_LINK_STA_WIDTH) >> 4, 436240680Sgavin (val & PCIEM_LINK_CAP_MAX_WIDTH) >> 4); 437242085Sjimharris /* 438242085Sjimharris * Only print link speed info if the link's max width is 439242085Sjimharris * greater than 0. 440242085Sjimharris */ 441242085Sjimharris if ((val & PCIEM_LINK_CAP_MAX_WIDTH) != 0) { 442242085Sjimharris printf("\n speed"); 443242085Sjimharris printf(" %s(%s)", (flags & PCIEM_LINK_STA_WIDTH) == 0 ? 444242085Sjimharris "0.0" : link_speed_string(flags & PCIEM_LINK_STA_SPEED), 445242085Sjimharris link_speed_string(val & PCIEM_LINK_CAP_MAX_SPEED)); 446242085Sjimharris } 447166435Sjhb} 448166435Sjhb 449166435Sjhbstatic void 450166435Sjhbcap_msix(int fd, struct pci_conf *p, uint8_t ptr) 451166435Sjhb{ 452166435Sjhb uint32_t val; 453166435Sjhb uint16_t ctrl; 454166435Sjhb int msgnum, table_bar, pba_bar; 455166435Sjhb 456166435Sjhb ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_CTRL, 2); 457166435Sjhb msgnum = (ctrl & PCIM_MSIXCTRL_TABLE_SIZE) + 1; 458166435Sjhb val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_TABLE, 4); 459166435Sjhb table_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); 460166435Sjhb val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_PBA, 4); 461166435Sjhb pba_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); 462166435Sjhb printf("MSI-X supports %d message%s ", msgnum, 463166435Sjhb (msgnum == 1) ? "" : "s"); 464166435Sjhb if (table_bar == pba_bar) 465166435Sjhb printf("in map 0x%x", table_bar); 466166435Sjhb else 467166435Sjhb printf("in maps 0x%x and 0x%x", table_bar, pba_bar); 468166435Sjhb if (ctrl & PCIM_MSIXCTRL_MSIX_ENABLE) 469166435Sjhb printf(" enabled"); 470166435Sjhb} 471166435Sjhb 472188640Smavstatic void 473188640Smavcap_sata(int fd, struct pci_conf *p, uint8_t ptr) 474188640Smav{ 475188640Smav 476188640Smav printf("SATA Index-Data Pair"); 477188640Smav} 478188640Smav 479188640Smavstatic void 480188640Smavcap_pciaf(int fd, struct pci_conf *p, uint8_t ptr) 481188640Smav{ 482188640Smav uint8_t cap; 483188640Smav 484188640Smav cap = read_config(fd, &p->pc_sel, ptr + PCIR_PCIAF_CAP, 1); 485188641Smav printf("PCI Advanced Features:%s%s", 486188641Smav cap & PCIM_PCIAFCAP_FLR ? " FLR" : "", 487188641Smav cap & PCIM_PCIAFCAP_TP ? " TP" : ""); 488188640Smav} 489188640Smav 490166435Sjhbvoid 491166435Sjhblist_caps(int fd, struct pci_conf *p) 492166435Sjhb{ 493212749Sjhb int express; 494212369Sjhb uint16_t sta; 495166435Sjhb uint8_t ptr, cap; 496166435Sjhb 497166435Sjhb /* Are capabilities present for this device? */ 498212369Sjhb sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); 499212369Sjhb if (!(sta & PCIM_STATUS_CAPPRESENT)) 500166435Sjhb return; 501166435Sjhb 502166435Sjhb switch (p->pc_hdr & PCIM_HDRTYPE) { 503212369Sjhb case PCIM_HDRTYPE_NORMAL: 504212369Sjhb case PCIM_HDRTYPE_BRIDGE: 505166435Sjhb ptr = PCIR_CAP_PTR; 506166435Sjhb break; 507212369Sjhb case PCIM_HDRTYPE_CARDBUS: 508166435Sjhb ptr = PCIR_CAP_PTR_2; 509166435Sjhb break; 510166435Sjhb default: 511166435Sjhb errx(1, "list_caps: bad header type"); 512166435Sjhb } 513166435Sjhb 514166435Sjhb /* Walk the capability list. */ 515212749Sjhb express = 0; 516166435Sjhb ptr = read_config(fd, &p->pc_sel, ptr, 1); 517166435Sjhb while (ptr != 0 && ptr != 0xff) { 518166435Sjhb cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1); 519166435Sjhb printf(" cap %02x[%02x] = ", cap, ptr); 520166435Sjhb switch (cap) { 521166435Sjhb case PCIY_PMG: 522166435Sjhb cap_power(fd, p, ptr); 523166435Sjhb break; 524166435Sjhb case PCIY_AGP: 525166435Sjhb cap_agp(fd, p, ptr); 526166435Sjhb break; 527166435Sjhb case PCIY_VPD: 528166435Sjhb cap_vpd(fd, p, ptr); 529166435Sjhb break; 530166435Sjhb case PCIY_MSI: 531166435Sjhb cap_msi(fd, p, ptr); 532166435Sjhb break; 533166435Sjhb case PCIY_PCIX: 534166435Sjhb cap_pcix(fd, p, ptr); 535166435Sjhb break; 536166435Sjhb case PCIY_HT: 537166435Sjhb cap_ht(fd, p, ptr); 538166435Sjhb break; 539166435Sjhb case PCIY_VENDOR: 540166435Sjhb cap_vendor(fd, p, ptr); 541166435Sjhb break; 542166435Sjhb case PCIY_DEBUG: 543166435Sjhb cap_debug(fd, p, ptr); 544166435Sjhb break; 545166435Sjhb case PCIY_SUBVENDOR: 546166435Sjhb cap_subvendor(fd, p, ptr); 547166435Sjhb break; 548166435Sjhb case PCIY_EXPRESS: 549212749Sjhb express = 1; 550166435Sjhb cap_express(fd, p, ptr); 551166435Sjhb break; 552166435Sjhb case PCIY_MSIX: 553166435Sjhb cap_msix(fd, p, ptr); 554166435Sjhb break; 555188640Smav case PCIY_SATA: 556188640Smav cap_sata(fd, p, ptr); 557188640Smav break; 558188640Smav case PCIY_PCIAF: 559188640Smav cap_pciaf(fd, p, ptr); 560188640Smav break; 561166435Sjhb default: 562166435Sjhb printf("unknown"); 563166435Sjhb break; 564166435Sjhb } 565166435Sjhb printf("\n"); 566166435Sjhb ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1); 567166435Sjhb } 568212326Sjhb 569212749Sjhb if (express) 570212749Sjhb list_ecaps(fd, p); 571166435Sjhb} 572212326Sjhb 573212326Sjhb/* From <sys/systm.h>. */ 574212326Sjhbstatic __inline uint32_t 575212326Sjhbbitcount32(uint32_t x) 576212326Sjhb{ 577212326Sjhb 578212326Sjhb x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1); 579212326Sjhb x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2); 580212326Sjhb x = (x + (x >> 4)) & 0x0f0f0f0f; 581212326Sjhb x = (x + (x >> 8)); 582212326Sjhb x = (x + (x >> 16)) & 0x000000ff; 583212326Sjhb return (x); 584212326Sjhb} 585212326Sjhb 586212326Sjhbstatic void 587212326Sjhbecap_aer(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 588212326Sjhb{ 589212326Sjhb uint32_t sta, mask; 590212326Sjhb 591212326Sjhb printf("AER %d", ver); 592240474Sjhb if (ver < 1) 593212326Sjhb return; 594212326Sjhb sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_STATUS, 4); 595212326Sjhb mask = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_SEVERITY, 4); 596212326Sjhb printf(" %d fatal", bitcount32(sta & mask)); 597212326Sjhb printf(" %d non-fatal", bitcount32(sta & ~mask)); 598212326Sjhb sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_COR_STATUS, 4); 599212326Sjhb printf(" %d corrected", bitcount32(sta)); 600212326Sjhb} 601212326Sjhb 602212326Sjhbstatic void 603212326Sjhbecap_vc(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 604212326Sjhb{ 605212326Sjhb uint32_t cap1; 606212326Sjhb 607212326Sjhb printf("VC %d", ver); 608240474Sjhb if (ver < 1) 609212326Sjhb return; 610212326Sjhb cap1 = read_config(fd, &p->pc_sel, ptr + PCIR_VC_CAP1, 4); 611212326Sjhb printf(" max VC%d", cap1 & PCIM_VC_CAP1_EXT_COUNT); 612212326Sjhb if ((cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) != 0) 613212326Sjhb printf(" lowpri VC0-VC%d", 614212326Sjhb (cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) >> 4); 615212326Sjhb} 616212326Sjhb 617212326Sjhbstatic void 618212326Sjhbecap_sernum(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 619212326Sjhb{ 620212326Sjhb uint32_t high, low; 621212326Sjhb 622212326Sjhb printf("Serial %d", ver); 623240474Sjhb if (ver < 1) 624212326Sjhb return; 625212326Sjhb low = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_LOW, 4); 626212326Sjhb high = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_HIGH, 4); 627212326Sjhb printf(" %08x%08x", high, low); 628212326Sjhb} 629212326Sjhb 630212326Sjhbstatic void 631240474Sjhbecap_vendor(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 632240474Sjhb{ 633240474Sjhb uint32_t val; 634240474Sjhb 635240474Sjhb printf("Vendor %d", ver); 636240474Sjhb if (ver < 1) 637240474Sjhb return; 638240474Sjhb val = read_config(fd, &p->pc_sel, ptr + 4, 4); 639240474Sjhb printf(" ID %d", val & 0xffff); 640240474Sjhb} 641240474Sjhb 642240474Sjhbstatic void 643240474Sjhbecap_sec_pcie(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 644240474Sjhb{ 645240474Sjhb uint32_t val; 646240474Sjhb 647240474Sjhb printf("PCIe Sec %d", ver); 648240474Sjhb if (ver < 1) 649240474Sjhb return; 650240474Sjhb val = read_config(fd, &p->pc_sel, ptr + 8, 4); 651240474Sjhb printf(" lane errors %#x", val); 652240474Sjhb} 653240474Sjhb 654240474Sjhbstruct { 655240474Sjhb uint16_t id; 656240474Sjhb const char *name; 657240474Sjhb} ecap_names[] = { 658240474Sjhb { PCIZ_PWRBDGT, "Power Budgeting" }, 659240474Sjhb { PCIZ_RCLINK_DCL, "Root Complex Link Declaration" }, 660240474Sjhb { PCIZ_RCLINK_CTL, "Root Complex Internal Link Control" }, 661240474Sjhb { PCIZ_RCEC_ASSOC, "Root Complex Event Collector ASsociation" }, 662240474Sjhb { PCIZ_MFVC, "MFVC" }, 663240474Sjhb { PCIZ_RCRB, "RCRB" }, 664240474Sjhb { PCIZ_ACS, "ACS" }, 665240474Sjhb { PCIZ_ARI, "ARI" }, 666240474Sjhb { PCIZ_ATS, "ATS" }, 667240474Sjhb { PCIZ_SRIOV, "SRIOV" }, 668240474Sjhb { PCIZ_MULTICAST, "Multicast" }, 669240474Sjhb { PCIZ_RESIZE_BAR, "Resizable BAR" }, 670240474Sjhb { PCIZ_DPA, "DPA" }, 671240474Sjhb { PCIZ_TPH_REQ, "TPH Requester" }, 672240474Sjhb { PCIZ_LTR, "LTR" }, 673240474Sjhb { 0, NULL } 674240474Sjhb}; 675240474Sjhb 676240474Sjhbstatic void 677212326Sjhblist_ecaps(int fd, struct pci_conf *p) 678212326Sjhb{ 679240474Sjhb const char *name; 680212326Sjhb uint32_t ecap; 681212326Sjhb uint16_t ptr; 682240474Sjhb int i; 683212326Sjhb 684212326Sjhb ptr = PCIR_EXTCAP; 685212326Sjhb ecap = read_config(fd, &p->pc_sel, ptr, 4); 686212326Sjhb if (ecap == 0xffffffff || ecap == 0) 687212326Sjhb return; 688212326Sjhb for (;;) { 689241757Simp printf(" ecap %04x[%03x] = ", PCI_EXTCAP_ID(ecap), ptr); 690212326Sjhb switch (PCI_EXTCAP_ID(ecap)) { 691212326Sjhb case PCIZ_AER: 692212326Sjhb ecap_aer(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 693212326Sjhb break; 694212326Sjhb case PCIZ_VC: 695212326Sjhb ecap_vc(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 696212326Sjhb break; 697212326Sjhb case PCIZ_SERNUM: 698212326Sjhb ecap_sernum(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 699212326Sjhb break; 700240474Sjhb case PCIZ_VENDOR: 701240474Sjhb ecap_vendor(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 702240474Sjhb break; 703240474Sjhb case PCIZ_SEC_PCIE: 704240474Sjhb ecap_sec_pcie(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 705240474Sjhb break; 706212326Sjhb default: 707240474Sjhb name = "unknown"; 708240474Sjhb for (i = 0; ecap_names[i].name != NULL; i++) 709240474Sjhb if (ecap_names[i].id == PCI_EXTCAP_ID(ecap)) { 710240474Sjhb name = ecap_names[i].name; 711240474Sjhb break; 712240474Sjhb } 713240474Sjhb printf("%s %d", name, PCI_EXTCAP_VER(ecap)); 714212326Sjhb break; 715212326Sjhb } 716212326Sjhb printf("\n"); 717212326Sjhb ptr = PCI_EXTCAP_NEXTPTR(ecap); 718212326Sjhb if (ptr == 0) 719212326Sjhb break; 720212326Sjhb ecap = read_config(fd, &p->pc_sel, ptr, 4); 721212326Sjhb } 722212326Sjhb} 723236415Sjhb 724236415Sjhb/* Find offset of a specific capability. Returns 0 on failure. */ 725236415Sjhbuint8_t 726236415Sjhbpci_find_cap(int fd, struct pci_conf *p, uint8_t id) 727236415Sjhb{ 728236415Sjhb uint16_t sta; 729236415Sjhb uint8_t ptr, cap; 730236415Sjhb 731236415Sjhb /* Are capabilities present for this device? */ 732236415Sjhb sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); 733236415Sjhb if (!(sta & PCIM_STATUS_CAPPRESENT)) 734236415Sjhb return (0); 735236415Sjhb 736236415Sjhb switch (p->pc_hdr & PCIM_HDRTYPE) { 737236415Sjhb case PCIM_HDRTYPE_NORMAL: 738236415Sjhb case PCIM_HDRTYPE_BRIDGE: 739236415Sjhb ptr = PCIR_CAP_PTR; 740236415Sjhb break; 741236415Sjhb case PCIM_HDRTYPE_CARDBUS: 742236415Sjhb ptr = PCIR_CAP_PTR_2; 743236415Sjhb break; 744236415Sjhb default: 745236415Sjhb return (0); 746236415Sjhb } 747236415Sjhb 748236415Sjhb ptr = read_config(fd, &p->pc_sel, ptr, 1); 749236415Sjhb while (ptr != 0 && ptr != 0xff) { 750236415Sjhb cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1); 751236415Sjhb if (cap == id) 752236415Sjhb return (ptr); 753236415Sjhb ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1); 754236415Sjhb } 755236415Sjhb return (0); 756236415Sjhb} 757236415Sjhb 758236415Sjhb/* Find offset of a specific extended capability. Returns 0 on failure. */ 759236415Sjhbuint16_t 760236415Sjhbpcie_find_cap(int fd, struct pci_conf *p, uint16_t id) 761236415Sjhb{ 762236415Sjhb uint32_t ecap; 763236415Sjhb uint16_t ptr; 764236415Sjhb 765236415Sjhb ptr = PCIR_EXTCAP; 766236415Sjhb ecap = read_config(fd, &p->pc_sel, ptr, 4); 767236415Sjhb if (ecap == 0xffffffff || ecap == 0) 768236415Sjhb return (0); 769236415Sjhb for (;;) { 770236415Sjhb if (PCI_EXTCAP_ID(ecap) == id) 771236415Sjhb return (ptr); 772236415Sjhb ptr = PCI_EXTCAP_NEXTPTR(ecap); 773236415Sjhb if (ptr == 0) 774236415Sjhb break; 775236415Sjhb ecap = read_config(fd, &p->pc_sel, ptr, 4); 776236415Sjhb } 777236415Sjhb return (0); 778236415Sjhb} 779