cap.c revision 173576
1193323Sed/*- 2193323Sed * Copyright (c) 2007 Yahoo!, Inc. 3193323Sed * All rights reserved. 4193323Sed * Written by: John Baldwin <jhb@FreeBSD.org> 5193323Sed * 6193323Sed * Redistribution and use in source and binary forms, with or without 7193323Sed * modification, are permitted provided that the following conditions 8193323Sed * are met: 9193323Sed * 1. Redistributions of source code must retain the above copyright 10193323Sed * notice, this list of conditions and the following disclaimer. 11193323Sed * 2. Redistributions in binary form must reproduce the above copyright 12193323Sed * notice, this list of conditions and the following disclaimer in the 13193323Sed * documentation and/or other materials provided with the distribution. 14193323Sed * 3. Neither the name of the author nor the names of any co-contributors 15193323Sed * may be used to endorse or promote products derived from this software 16193323Sed * without specific prior written permission. 17193323Sed * 18193323Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20193323Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21193323Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22193323Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23193323Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26193323Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27193323Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28193323Sed * SUCH DAMAGE. 29193323Sed */ 30193323Sed 31193323Sed#ifndef lint 32193323Sedstatic const char rcsid[] = 33193323Sed "$FreeBSD: head/usr.sbin/pciconf/cap.c 173576 2007-11-13 01:30:40Z jb $"; 34193323Sed#endif /* not lint */ 35193323Sed 36193323Sed#include <sys/types.h> 37193323Sed 38193323Sed#include <err.h> 39193323Sed#include <stdio.h> 40193323Sed#include <sys/agpio.h> 41193323Sed#include <sys/pciio.h> 42193323Sed 43193323Sed#include <dev/agp/agpreg.h> 44193323Sed#include <dev/pci/pcireg.h> 45193323Sed 46193323Sed#include "pciconf.h" 47193323Sed 48193323Sedstatic void 49193323Sedcap_power(int fd, struct pci_conf *p, uint8_t ptr) 50193323Sed{ 51193323Sed uint16_t cap, status; 52193323Sed 53193323Sed cap = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_CAP, 2); 54193323Sed status = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_STATUS, 2); 55193323Sed printf("powerspec %d supports D0%s%s D3 current D%d", 56193323Sed cap & PCIM_PCAP_SPEC, 57193323Sed cap & PCIM_PCAP_D1SUPP ? " D1" : "", 58193323Sed cap & PCIM_PCAP_D2SUPP ? " D2" : "", 59193323Sed status & PCIM_PSTAT_DMASK); 60193323Sed} 61193323Sed 62193323Sedstatic void 63193323Sedcap_agp(int fd, struct pci_conf *p, uint8_t ptr) 64193323Sed{ 65193323Sed uint32_t status, command; 66193323Sed 67193323Sed status = read_config(fd, &p->pc_sel, ptr + AGP_STATUS, 4); 68193323Sed command = read_config(fd, &p->pc_sel, ptr + AGP_CAPID, 4); 69193323Sed printf("AGP "); 70193323Sed if (AGP_MODE_GET_MODE_3(status)) { 71193323Sed printf("v3 "); 72193323Sed if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_8x) 73193323Sed printf("8x "); 74193323Sed if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_4x) 75193323Sed printf("4x "); 76193323Sed } else { 77193323Sed if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_4x) 78193323Sed printf("4x "); 79193323Sed if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_2x) 80193323Sed printf("2x "); 81193323Sed if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_1x) 82193323Sed printf("1x "); 83193323Sed } 84193323Sed if (AGP_MODE_GET_SBA(status)) 85193323Sed printf("SBA "); 86193323Sed if (AGP_MODE_GET_AGP(command)) { 87193323Sed printf("enabled at "); 88193323Sed if (AGP_MODE_GET_MODE_3(command)) { 89193323Sed printf("v3 "); 90193323Sed switch (AGP_MODE_GET_RATE(command)) { 91193323Sed case AGP_MODE_V3_RATE_8x: 92193323Sed printf("8x "); 93193323Sed break; 94193323Sed case AGP_MODE_V3_RATE_4x: 95193323Sed printf("4x "); 96193323Sed break; 97193323Sed } 98193323Sed } else 99193323Sed switch (AGP_MODE_GET_RATE(command)) { 100193323Sed case AGP_MODE_V2_RATE_4x: 101193323Sed printf("4x "); 102193323Sed break; 103193323Sed case AGP_MODE_V2_RATE_2x: 104193323Sed printf("2x "); 105193323Sed break; 106193323Sed case AGP_MODE_V2_RATE_1x: 107193323Sed printf("1x "); 108193323Sed break; 109193323Sed } 110193323Sed if (AGP_MODE_GET_SBA(command)) 111193323Sed printf("SBA "); 112193323Sed } else 113193323Sed printf("disabled"); 114193323Sed} 115193323Sed 116193323Sedstatic void 117193323Sedcap_vpd(int fd, struct pci_conf *p, uint8_t ptr) 118193323Sed{ 119193323Sed 120193323Sed printf("VPD"); 121193323Sed} 122193323Sed 123193323Sedstatic void 124193323Sedcap_msi(int fd, struct pci_conf *p, uint8_t ptr) 125193323Sed{ 126193323Sed uint16_t ctrl; 127193323Sed int msgnum; 128193323Sed 129193323Sed ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSI_CTRL, 2); 130193323Sed msgnum = 1 << ((ctrl & PCIM_MSICTRL_MMC_MASK) >> 1); 131193323Sed printf("MSI supports %d message%s%s%s ", msgnum, 132193323Sed (msgnum == 1) ? "" : "s", 133193323Sed (ctrl & PCIM_MSICTRL_64BIT) ? ", 64 bit" : "", 134193323Sed (ctrl & PCIM_MSICTRL_VECTOR) ? ", vector masks" : ""); 135193323Sed if (ctrl & PCIM_MSICTRL_MSI_ENABLE) { 136193323Sed msgnum = 1 << ((ctrl & PCIM_MSICTRL_MME_MASK) >> 4); 137193323Sed printf("enabled with %d message%s", msgnum, 138193323Sed (msgnum == 1) ? "" : "s"); 139193323Sed } 140193323Sed} 141193323Sed 142193323Sedstatic void 143193323Sedcap_pcix(int fd, struct pci_conf *p, uint8_t ptr) 144193323Sed{ 145193323Sed uint32_t status; 146193323Sed int comma, max_splits, max_burst_read; 147193323Sed 148193323Sed status = read_config(fd, &p->pc_sel, ptr + PCIXR_STATUS, 4); 149193323Sed printf("PCI-X "); 150193323Sed if (status & PCIXM_STATUS_64BIT) 151193323Sed printf("64-bit "); 152193323Sed if ((p->pc_hdr & PCIM_HDRTYPE) == 1) 153193323Sed printf("bridge "); 154193323Sed printf("supports"); 155193323Sed comma = 0; 156193323Sed if (status & PCIXM_STATUS_133CAP) { 157193323Sed printf("%s 133MHz", comma ? "," : ""); 158193323Sed comma = 1; 159193323Sed } 160193323Sed if (status & PCIXM_STATUS_266CAP) { 161193323Sed printf("%s 266MHz", comma ? "," : ""); 162193323Sed comma = 1; 163193323Sed } 164193323Sed if (status & PCIXM_STATUS_533CAP) { 165193323Sed printf("%s 533MHz", comma ? "," : ""); 166193323Sed comma = 1; 167193323Sed } 168193323Sed if ((p->pc_hdr & PCIM_HDRTYPE) == 1) 169193323Sed return; 170193323Sed switch (status & PCIXM_STATUS_MAX_READ) { 171193323Sed case PCIXM_STATUS_MAX_READ_512: 172193323Sed max_burst_read = 512; 173193323Sed break; 174193323Sed case PCIXM_STATUS_MAX_READ_1024: 175193323Sed max_burst_read = 1024; 176193323Sed break; 177193323Sed case PCIXM_STATUS_MAX_READ_2048: 178193323Sed max_burst_read = 2048; 179193323Sed break; 180193323Sed case PCIXM_STATUS_MAX_READ_4096: 181193323Sed max_burst_read = 4096; 182193323Sed break; 183193323Sed } 184193323Sed switch (status & PCIXM_STATUS_MAX_SPLITS) { 185193323Sed case PCIXM_STATUS_MAX_SPLITS_1: 186193323Sed max_splits = 1; 187193323Sed break; 188193323Sed case PCIXM_STATUS_MAX_SPLITS_2: 189193323Sed max_splits = 2; 190193323Sed break; 191193323Sed case PCIXM_STATUS_MAX_SPLITS_3: 192193323Sed max_splits = 3; 193193323Sed break; 194193323Sed case PCIXM_STATUS_MAX_SPLITS_4: 195193323Sed max_splits = 4; 196193323Sed break; 197193323Sed case PCIXM_STATUS_MAX_SPLITS_8: 198193323Sed max_splits = 8; 199193323Sed break; 200193323Sed case PCIXM_STATUS_MAX_SPLITS_12: 201193323Sed max_splits = 12; 202193323Sed break; 203193323Sed case PCIXM_STATUS_MAX_SPLITS_16: 204193323Sed max_splits = 16; 205193323Sed break; 206193323Sed case PCIXM_STATUS_MAX_SPLITS_32: 207193323Sed max_splits = 32; 208193323Sed break; 209193323Sed } 210193323Sed printf("%s %d burst read, %d split transaction%s", comma ? "," : "", 211193323Sed max_burst_read, max_splits, max_splits == 1 ? "" : "s"); 212193323Sed} 213193323Sed 214193323Sedstatic void 215193323Sedcap_ht(int fd, struct pci_conf *p, uint8_t ptr) 216193323Sed{ 217193323Sed uint32_t reg; 218193323Sed uint16_t command; 219193323Sed 220193323Sed command = read_config(fd, &p->pc_sel, ptr + PCIR_HT_COMMAND, 2); 221193323Sed printf("HT "); 222193323Sed if ((command & 0xe000) == PCIM_HTCAP_SLAVE) 223193323Sed printf("slave"); 224193323Sed else if ((command & 0xe000) == PCIM_HTCAP_HOST) 225193323Sed printf("host"); 226193323Sed else 227193323Sed switch (command & PCIM_HTCMD_CAP_MASK) { 228193323Sed case PCIM_HTCAP_SWITCH: 229193323Sed printf("switch"); 230193323Sed break; 231193323Sed case PCIM_HTCAP_INTERRUPT: 232193323Sed printf("interrupt"); 233193323Sed break; 234193323Sed case PCIM_HTCAP_REVISION_ID: 235193323Sed printf("revision ID"); 236193323Sed break; 237193323Sed case PCIM_HTCAP_UNITID_CLUMPING: 238193323Sed printf("unit ID clumping"); 239193323Sed break; 240193323Sed case PCIM_HTCAP_EXT_CONFIG_SPACE: 241193323Sed printf("extended config space"); 242193323Sed break; 243193323Sed case PCIM_HTCAP_ADDRESS_MAPPING: 244193323Sed printf("address mapping"); 245193323Sed break; 246193323Sed case PCIM_HTCAP_MSI_MAPPING: 247193323Sed printf("MSI %saddress window %s at 0x", 248193323Sed command & PCIM_HTCMD_MSI_FIXED ? "fixed " : "", 249193323Sed command & PCIM_HTCMD_MSI_ENABLE ? "enabled" : 250193323Sed "disabled"); 251193323Sed if (command & PCIM_HTCMD_MSI_FIXED) 252193323Sed printf("fee00000"); 253193323Sed else { 254193323Sed reg = read_config(fd, &p->pc_sel, 255193323Sed ptr + PCIR_HTMSI_ADDRESS_HI, 4); 256193323Sed if (reg != 0) 257193323Sed printf("%08x", reg); 258193323Sed reg = read_config(fd, &p->pc_sel, 259193323Sed ptr + PCIR_HTMSI_ADDRESS_LO, 4); 260193323Sed printf("%08x", reg); 261193323Sed } 262193323Sed break; 263193323Sed case PCIM_HTCAP_DIRECT_ROUTE: 264193323Sed printf("direct route"); 265193323Sed break; 266193323Sed case PCIM_HTCAP_VCSET: 267193323Sed printf("VC set"); 268193323Sed break; 269193323Sed case PCIM_HTCAP_RETRY_MODE: 270193323Sed printf("retry mode"); 271193323Sed break; 272193323Sed case PCIM_HTCAP_X86_ENCODING: 273193323Sed printf("X86 encoding"); 274193323Sed break; 275193323Sed default: 276193323Sed printf("unknown %02x", command); 277193323Sed break; 278193323Sed } 279193323Sed} 280193323Sed 281193323Sedstatic void 282193323Sedcap_vendor(int fd, struct pci_conf *p, uint8_t ptr) 283193323Sed{ 284193323Sed uint8_t length; 285193323Sed 286193323Sed length = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_LENGTH, 1); 287193323Sed printf("vendor (length %d)", length); 288193323Sed if (p->pc_vendor == 0x8086) { 289193323Sed /* Intel */ 290193323Sed uint8_t version; 291193323Sed 292193323Sed version = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_DATA, 293193323Sed 1); 294193323Sed printf(" Intel cap %d version %d", version >> 4, version & 0xf); 295193323Sed if (version >> 4 == 1 && length == 12) { 296193323Sed /* Feature Detection */ 297193323Sed uint32_t fvec; 298193323Sed int comma; 299193323Sed 300193323Sed comma = 0; 301193323Sed fvec = read_config(fd, &p->pc_sel, ptr + 302193323Sed PCIR_VENDOR_DATA + 5, 4); 303193323Sed printf("\n\t\t features:"); 304193323Sed if (fvec & (1 << 0)) { 305193323Sed printf(" AMT"); 306193323Sed comma = 1; 307193323Sed } 308193323Sed fvec = read_config(fd, &p->pc_sel, ptr + 309193323Sed PCIR_VENDOR_DATA + 1, 4); 310193323Sed if (fvec & (1 << 21)) { 311193323Sed printf("%s Quick Resume", comma ? "," : ""); 312193323Sed comma = 1; 313193323Sed } 314193323Sed if (fvec & (1 << 18)) { 315193323Sed printf("%s SATA RAID-5", comma ? "," : ""); 316193323Sed comma = 1; 317193323Sed } 318193323Sed if (fvec & (1 << 9)) { 319193323Sed printf("%s Mobile", comma ? "," : ""); 320193323Sed comma = 1; 321193323Sed } 322193323Sed if (fvec & (1 << 7)) { 323193323Sed printf("%s 6 PCI-e x1 slots", comma ? "," : ""); 324193323Sed comma = 1; 325193323Sed } else { 326193323Sed printf("%s 4 PCI-e x1 slots", comma ? "," : ""); 327193323Sed comma = 1; 328193323Sed } 329193323Sed if (fvec & (1 << 5)) { 330193323Sed printf("%s SATA RAID-0/1/10", comma ? "," : ""); 331193323Sed comma = 1; 332193323Sed } 333193323Sed if (fvec & (1 << 3)) { 334193323Sed printf("%s SATA AHCI", comma ? "," : ""); 335193323Sed comma = 1; 336193323Sed } 337193323Sed } 338193323Sed } 339193323Sed} 340193323Sed 341193323Sedstatic void 342193323Sedcap_debug(int fd, struct pci_conf *p, uint8_t ptr) 343193323Sed{ 344193323Sed uint16_t debug_port; 345193323Sed 346193323Sed debug_port = read_config(fd, &p->pc_sel, ptr + PCIR_DEBUG_PORT, 2); 347193323Sed printf("EHCI Debug Port at offset 0x%x in map 0x%x", debug_port & 348193323Sed PCIM_DEBUG_PORT_OFFSET, PCIR_BAR(debug_port >> 13)); 349193323Sed} 350193323Sed 351193323Sedstatic void 352193323Sedcap_subvendor(int fd, struct pci_conf *p, uint8_t ptr) 353193323Sed{ 354193323Sed uint32_t id; 355193323Sed 356193323Sed id = read_config(fd, &p->pc_sel, ptr + PCIR_SUBVENDCAP_ID, 4); 357193323Sed printf("PCI Bridge card=0x%08x", id); 358193323Sed} 359193323Sed 360193323Sedstatic void 361193323Sedcap_express(int fd, struct pci_conf *p, uint8_t ptr) 362193323Sed{ 363193323Sed uint16_t flags; 364193323Sed 365193323Sed flags = read_config(fd, &p->pc_sel, ptr + PCIR_EXPRESS_FLAGS, 2); 366193323Sed printf("PCI-Express %d ", flags & PCIM_EXP_FLAGS_VERSION); 367193323Sed switch (flags & PCIM_EXP_FLAGS_TYPE) { 368193323Sed case PCIM_EXP_TYPE_ENDPOINT: 369193323Sed printf("endpoint"); 370193323Sed break; 371193323Sed case PCIM_EXP_TYPE_LEGACY_ENDPOINT: 372193323Sed printf("legacy endpoint"); 373193323Sed break; 374193323Sed case PCIM_EXP_TYPE_ROOT_PORT: 375193323Sed printf("root port"); 376193323Sed break; 377193323Sed case PCIM_EXP_TYPE_UPSTREAM_PORT: 378193323Sed printf("upstream port"); 379193323Sed break; 380193323Sed case PCIM_EXP_TYPE_DOWNSTREAM_PORT: 381193323Sed printf("downstream port"); 382193323Sed break; 383193323Sed case PCIM_EXP_TYPE_PCI_BRIDGE: 384193323Sed printf("PCI bridge"); 385193323Sed break; 386193323Sed default: 387193323Sed printf("type %d", (flags & PCIM_EXP_FLAGS_TYPE) >> 8); 388193323Sed break; 389193323Sed } 390193323Sed if (flags & PCIM_EXP_FLAGS_IRQ) 391193323Sed printf(" IRQ %d", (flags & PCIM_EXP_FLAGS_IRQ) >> 17); 392193323Sed} 393193323Sed 394193323Sedstatic void 395193323Sedcap_msix(int fd, struct pci_conf *p, uint8_t ptr) 396193323Sed{ 397193323Sed uint32_t val; 398193323Sed uint16_t ctrl; 399193323Sed int msgnum, table_bar, pba_bar; 400193323Sed 401193323Sed ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_CTRL, 2); 402193323Sed msgnum = (ctrl & PCIM_MSIXCTRL_TABLE_SIZE) + 1; 403193323Sed val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_TABLE, 4); 404193323Sed table_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); 405193323Sed val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_PBA, 4); 406193323Sed pba_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); 407193323Sed printf("MSI-X supports %d message%s ", msgnum, 408193323Sed (msgnum == 1) ? "" : "s"); 409193323Sed if (table_bar == pba_bar) 410193323Sed printf("in map 0x%x", table_bar); 411193323Sed else 412193323Sed printf("in maps 0x%x and 0x%x", table_bar, pba_bar); 413193323Sed if (ctrl & PCIM_MSIXCTRL_MSIX_ENABLE) 414193323Sed printf(" enabled"); 415193323Sed} 416193323Sed 417193323Sedvoid 418193323Sedlist_caps(int fd, struct pci_conf *p) 419193323Sed{ 420193323Sed uint16_t cmd; 421193323Sed uint8_t ptr, cap; 422193323Sed 423193323Sed /* Are capabilities present for this device? */ 424193323Sed cmd = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); 425193323Sed if (!(cmd & PCIM_STATUS_CAPPRESENT)) 426193323Sed return; 427193323Sed 428193323Sed switch (p->pc_hdr & PCIM_HDRTYPE) { 429193323Sed case 0: 430193323Sed case 1: 431193323Sed ptr = PCIR_CAP_PTR; 432193323Sed break; 433193323Sed case 2: 434193323Sed ptr = PCIR_CAP_PTR_2; 435193323Sed break; 436193323Sed default: 437193323Sed errx(1, "list_caps: bad header type"); 438193323Sed } 439193323Sed 440193323Sed /* Walk the capability list. */ 441193323Sed ptr = read_config(fd, &p->pc_sel, ptr, 1); 442193323Sed while (ptr != 0 && ptr != 0xff) { 443193323Sed cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1); 444193323Sed printf(" cap %02x[%02x] = ", cap, ptr); 445193323Sed switch (cap) { 446193323Sed case PCIY_PMG: 447193323Sed cap_power(fd, p, ptr); 448193323Sed break; 449193323Sed case PCIY_AGP: 450193323Sed cap_agp(fd, p, ptr); 451193323Sed break; 452193323Sed case PCIY_VPD: 453193323Sed cap_vpd(fd, p, ptr); 454193323Sed break; 455193323Sed case PCIY_MSI: 456193323Sed cap_msi(fd, p, ptr); 457193323Sed break; 458193323Sed case PCIY_PCIX: 459193323Sed cap_pcix(fd, p, ptr); 460193323Sed break; 461193323Sed case PCIY_HT: 462 cap_ht(fd, p, ptr); 463 break; 464 case PCIY_VENDOR: 465 cap_vendor(fd, p, ptr); 466 break; 467 case PCIY_DEBUG: 468 cap_debug(fd, p, ptr); 469 break; 470 case PCIY_SUBVENDOR: 471 cap_subvendor(fd, p, ptr); 472 break; 473 case PCIY_EXPRESS: 474 cap_express(fd, p, ptr); 475 break; 476 case PCIY_MSIX: 477 cap_msix(fd, p, ptr); 478 break; 479 default: 480 printf("unknown"); 481 break; 482 } 483 printf("\n"); 484 ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1); 485 } 486} 487