1 /*- 2 * Copyright (c) 2007 Yahoo!, Inc. 3 * All rights reserved. 4 * Written by: John Baldwin <jhb@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the author nor the names of any co-contributors 15 * may be used to endorse or promote products derived from this software 16 * without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $FreeBSD: src/usr.sbin/pciconf/cap.c,v 1.11 2010/09/16 16:03:12 jhb Exp $ 31 */ 32 33 #include <sys/types.h> 34 35 #include <err.h> 36 #include <stdio.h> 37 #include <sys/agpio.h> 38 #include <sys/pciio.h> 39 40 #include <dev/agp/agpreg.h> 41 #include <bus/pci/pcireg.h> 42 43 #include "pciconf.h" 44 45 static void list_ecaps(int fd, struct pci_conf *p); 46 static const char *aspm_string(uint8_t aspm); 47 static int slot_power(uint32_t cap); 48 49 static void 50 cap_power(int fd, struct pci_conf *p, uint8_t ptr) 51 { 52 uint16_t cap, status; 53 54 cap = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_CAP, 2); 55 status = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_STATUS, 2); 56 printf("powerspec %d supports D0%s%s D3 current D%d", 57 cap & PCIM_PCAP_SPEC, 58 cap & PCIM_PCAP_D1SUPP ? " D1" : "", 59 cap & PCIM_PCAP_D2SUPP ? " D2" : "", 60 status & PCIM_PSTAT_DMASK); 61 } 62 63 static void 64 cap_agp(int fd, struct pci_conf *p, uint8_t ptr) 65 { 66 uint32_t status, command; 67 68 status = read_config(fd, &p->pc_sel, ptr + AGP_STATUS, 4); 69 command = read_config(fd, &p->pc_sel, ptr + AGP_CAPID, 4); 70 printf("AGP "); 71 if (AGP_MODE_GET_MODE_3(status)) { 72 printf("v3 "); 73 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_8x) 74 printf("8x "); 75 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_4x) 76 printf("4x "); 77 } else { 78 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_4x) 79 printf("4x "); 80 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_2x) 81 printf("2x "); 82 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_1x) 83 printf("1x "); 84 } 85 if (AGP_MODE_GET_SBA(status)) 86 printf("SBA "); 87 if (AGP_MODE_GET_AGP(command)) { 88 printf("enabled at "); 89 if (AGP_MODE_GET_MODE_3(command)) { 90 printf("v3 "); 91 switch (AGP_MODE_GET_RATE(command)) { 92 case AGP_MODE_V3_RATE_8x: 93 printf("8x "); 94 break; 95 case AGP_MODE_V3_RATE_4x: 96 printf("4x "); 97 break; 98 } 99 } else 100 switch (AGP_MODE_GET_RATE(command)) { 101 case AGP_MODE_V2_RATE_4x: 102 printf("4x "); 103 break; 104 case AGP_MODE_V2_RATE_2x: 105 printf("2x "); 106 break; 107 case AGP_MODE_V2_RATE_1x: 108 printf("1x "); 109 break; 110 } 111 if (AGP_MODE_GET_SBA(command)) 112 printf("SBA "); 113 } else 114 printf("disabled"); 115 } 116 117 static void 118 cap_vpd(int fd __unused, struct pci_conf *p __unused, uint8_t ptr __unused) 119 { 120 121 printf("VPD"); 122 } 123 124 static void 125 cap_msi(int fd, struct pci_conf *p, uint8_t ptr) 126 { 127 uint16_t ctrl; 128 int msgnum; 129 130 ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSI_CTRL, 2); 131 msgnum = 1 << ((ctrl & PCIM_MSICTRL_MMC_MASK) >> 1); 132 printf("MSI supports %d message%s%s%s ", msgnum, 133 (msgnum == 1) ? "" : "s", 134 (ctrl & PCIM_MSICTRL_64BIT) ? ", 64 bit" : "", 135 (ctrl & PCIM_MSICTRL_VECTOR) ? ", vector masks" : ""); 136 if (ctrl & PCIM_MSICTRL_MSI_ENABLE) { 137 msgnum = 1 << ((ctrl & PCIM_MSICTRL_MME_MASK) >> 4); 138 printf("enabled with %d message%s", msgnum, 139 (msgnum == 1) ? "" : "s"); 140 } 141 } 142 143 static void 144 cap_pcix(int fd, struct pci_conf *p, uint8_t ptr) 145 { 146 uint32_t status; 147 int comma, max_splits = 0, max_burst_read = 0; 148 149 status = read_config(fd, &p->pc_sel, ptr + PCIXR_STATUS, 4); 150 printf("PCI-X "); 151 if (status & PCIXM_STATUS_64BIT) 152 printf("64-bit "); 153 if ((p->pc_hdr & PCIM_HDRTYPE) == 1) 154 printf("bridge "); 155 if ((p->pc_hdr & PCIM_HDRTYPE) != 1 || (status & (PCIXM_STATUS_133CAP | 156 PCIXM_STATUS_266CAP | PCIXM_STATUS_533CAP)) != 0) 157 printf("supports"); 158 comma = 0; 159 if (status & PCIXM_STATUS_133CAP) { 160 printf("%s 133MHz", comma ? "," : ""); 161 comma = 1; 162 } 163 if (status & PCIXM_STATUS_266CAP) { 164 printf("%s 266MHz", comma ? "," : ""); 165 comma = 1; 166 } 167 if (status & PCIXM_STATUS_533CAP) { 168 printf("%s 533MHz", comma ? "," : ""); 169 comma = 1; 170 } 171 if ((p->pc_hdr & PCIM_HDRTYPE) == 1) 172 return; 173 switch (status & PCIXM_STATUS_MAX_READ) { 174 case PCIXM_STATUS_MAX_READ_512: 175 max_burst_read = 512; 176 break; 177 case PCIXM_STATUS_MAX_READ_1024: 178 max_burst_read = 1024; 179 break; 180 case PCIXM_STATUS_MAX_READ_2048: 181 max_burst_read = 2048; 182 break; 183 case PCIXM_STATUS_MAX_READ_4096: 184 max_burst_read = 4096; 185 break; 186 } 187 switch (status & PCIXM_STATUS_MAX_SPLITS) { 188 case PCIXM_STATUS_MAX_SPLITS_1: 189 max_splits = 1; 190 break; 191 case PCIXM_STATUS_MAX_SPLITS_2: 192 max_splits = 2; 193 break; 194 case PCIXM_STATUS_MAX_SPLITS_3: 195 max_splits = 3; 196 break; 197 case PCIXM_STATUS_MAX_SPLITS_4: 198 max_splits = 4; 199 break; 200 case PCIXM_STATUS_MAX_SPLITS_8: 201 max_splits = 8; 202 break; 203 case PCIXM_STATUS_MAX_SPLITS_12: 204 max_splits = 12; 205 break; 206 case PCIXM_STATUS_MAX_SPLITS_16: 207 max_splits = 16; 208 break; 209 case PCIXM_STATUS_MAX_SPLITS_32: 210 max_splits = 32; 211 break; 212 } 213 printf("%s %d burst read, %d split transaction%s", comma ? "," : "", 214 max_burst_read, max_splits, max_splits == 1 ? "" : "s"); 215 } 216 217 static void 218 cap_ht(int fd, struct pci_conf *p, uint8_t ptr) 219 { 220 uint32_t reg; 221 uint16_t command; 222 223 command = read_config(fd, &p->pc_sel, ptr + PCIR_HT_COMMAND, 2); 224 printf("HT "); 225 if ((command & 0xe000) == PCIM_HTCAP_SLAVE) 226 printf("slave"); 227 else if ((command & 0xe000) == PCIM_HTCAP_HOST) 228 printf("host"); 229 else 230 switch (command & PCIM_HTCMD_CAP_MASK) { 231 case PCIM_HTCAP_SWITCH: 232 printf("switch"); 233 break; 234 case PCIM_HTCAP_INTERRUPT: 235 printf("interrupt"); 236 break; 237 case PCIM_HTCAP_REVISION_ID: 238 printf("revision ID"); 239 break; 240 case PCIM_HTCAP_UNITID_CLUMPING: 241 printf("unit ID clumping"); 242 break; 243 case PCIM_HTCAP_EXT_CONFIG_SPACE: 244 printf("extended config space"); 245 break; 246 case PCIM_HTCAP_ADDRESS_MAPPING: 247 printf("address mapping"); 248 break; 249 case PCIM_HTCAP_MSI_MAPPING: 250 printf("MSI %saddress window %s at 0x", 251 command & PCIM_HTCMD_MSI_FIXED ? "fixed " : "", 252 command & PCIM_HTCMD_MSI_ENABLE ? "enabled" : 253 "disabled"); 254 if (command & PCIM_HTCMD_MSI_FIXED) 255 printf("fee00000"); 256 else { 257 reg = read_config(fd, &p->pc_sel, 258 ptr + PCIR_HTMSI_ADDRESS_HI, 4); 259 if (reg != 0) 260 printf("%08x", reg); 261 reg = read_config(fd, &p->pc_sel, 262 ptr + PCIR_HTMSI_ADDRESS_LO, 4); 263 printf("%08x", reg); 264 } 265 break; 266 case PCIM_HTCAP_DIRECT_ROUTE: 267 printf("direct route"); 268 break; 269 case PCIM_HTCAP_VCSET: 270 printf("VC set"); 271 break; 272 case PCIM_HTCAP_RETRY_MODE: 273 printf("retry mode"); 274 break; 275 case PCIM_HTCAP_X86_ENCODING: 276 printf("X86 encoding"); 277 break; 278 default: 279 printf("unknown %02x", command); 280 break; 281 } 282 } 283 284 static void 285 cap_vendor(int fd, struct pci_conf *p, uint8_t ptr) 286 { 287 uint8_t length; 288 289 length = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_LENGTH, 1); 290 printf("vendor (length %d)", length); 291 if (p->pc_vendor == 0x8086) { 292 /* Intel */ 293 uint8_t version; 294 295 version = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_DATA, 296 1); 297 printf(" Intel cap %d version %d", version >> 4, version & 0xf); 298 if (version >> 4 == 1 && length == 12) { 299 /* Feature Detection */ 300 uint32_t fvec; 301 int comma; 302 303 comma = 0; 304 fvec = read_config(fd, &p->pc_sel, ptr + 305 PCIR_VENDOR_DATA + 5, 4); 306 printf("\n\t\t features:"); 307 if (fvec & (1 << 0)) { 308 printf(" AMT"); 309 comma = 1; 310 } 311 fvec = read_config(fd, &p->pc_sel, ptr + 312 PCIR_VENDOR_DATA + 1, 4); 313 if (fvec & (1 << 21)) { 314 printf("%s Quick Resume", comma ? "," : ""); 315 comma = 1; 316 } 317 if (fvec & (1 << 18)) { 318 printf("%s SATA RAID-5", comma ? "," : ""); 319 comma = 1; 320 } 321 if (fvec & (1 << 9)) { 322 printf("%s Mobile", comma ? "," : ""); 323 comma = 1; 324 } 325 if (fvec & (1 << 7)) { 326 printf("%s 6 PCI-e x1 slots", comma ? "," : ""); 327 comma = 1; 328 } else { 329 printf("%s 4 PCI-e x1 slots", comma ? "," : ""); 330 comma = 1; 331 } 332 if (fvec & (1 << 5)) { 333 printf("%s SATA RAID-0/1/10", comma ? "," : ""); 334 comma = 1; 335 } 336 if (fvec & (1 << 3)) { 337 printf("%s SATA AHCI", comma ? "," : ""); 338 comma = 1; 339 } 340 } 341 } 342 } 343 344 static void 345 cap_debug(int fd, struct pci_conf *p, uint8_t ptr) 346 { 347 uint16_t debug_port; 348 349 debug_port = read_config(fd, &p->pc_sel, ptr + PCIR_DEBUG_PORT, 2); 350 printf("EHCI Debug Port at offset 0x%x in map 0x%x", debug_port & 351 PCIM_DEBUG_PORT_OFFSET, PCIR_BAR(debug_port >> 13)); 352 } 353 354 static void 355 cap_subvendor(int fd, struct pci_conf *p, uint8_t ptr) 356 { 357 uint32_t id; 358 359 id = read_config(fd, &p->pc_sel, ptr + PCIR_SUBVENDCAP_ID, 4); 360 printf("PCI Bridge card=0x%08x", id); 361 } 362 363 #define MAX_PAYLOAD(field) (128 << (field)) 364 365 static void 366 cap_express(int fd, struct pci_conf *p, uint8_t ptr) 367 { 368 uint32_t cap; 369 uint16_t ctl, flags, sta; 370 unsigned int version; 371 372 flags = read_config(fd, &p->pc_sel, ptr + PCIER_CAPABILITY, 2); 373 version = flags & PCIEM_CAP_VER_MASK; 374 printf("PCI-Express %u ", version); 375 switch (flags & PCIEM_CAP_PORT_TYPE) { 376 case PCIE_END_POINT: 377 printf("endpoint"); 378 break; 379 case PCIE_LEG_END_POINT: 380 printf("legacy endpoint"); 381 break; 382 case PCIE_ROOT_PORT: 383 printf("root port"); 384 break; 385 case PCIE_UP_STREAM_PORT: 386 printf("upstream port"); 387 break; 388 case PCIE_DOWN_STREAM_PORT: 389 printf("downstream port"); 390 break; 391 case PCIE_PCIE2PCI_BRIDGE: 392 printf("PCI bridge"); 393 break; 394 case PCIE_PCI2PCIE_BRIDGE: 395 printf("PCI to PCIe bridge"); 396 break; 397 case PCIE_ROOT_END_POINT: 398 printf("root endpoint"); 399 break; 400 case PCIE_ROOT_EVT_COLL: 401 printf("event collector"); 402 break; 403 default: 404 printf("type %d", (flags & PCIEM_CAP_PORT_TYPE) >> 8); 405 break; 406 } 407 if (flags & PCIEM_CAP_IRQ_MSGNO) 408 printf(" IRQ %d", (flags & PCIEM_CAP_IRQ_MSGNO) >> 8); 409 cap = read_config(fd, &p->pc_sel, ptr + PCIER_DEVCAP, 4); 410 ctl = read_config(fd, &p->pc_sel, ptr + PCIER_DEVCTRL, 2); 411 printf(" max data %d(%d)", 412 MAX_PAYLOAD((ctl & PCIEM_DEVCAP_MAX_PAYLOAD) >> 5), 413 MAX_PAYLOAD(cap & PCIEM_DEVCAP_MAX_PAYLOAD)); 414 if ((cap & PCIEM_CAP_FLR) != 0) 415 printf(" FLR"); 416 if (ctl & PCIEM_DEVCTL_RELAX_ORDER) 417 printf(" RO"); 418 if (ctl & PCIEM_DEVCTL_NOSNOOP) 419 printf(" NS"); 420 if (ctl & PCIEM_DEVCTL_COR_ENABLE) 421 printf(" COR"); 422 if (ctl & PCIEM_DEVCTL_NFER_ENABLE) 423 printf(" NFER"); 424 if (ctl & PCIEM_DEVCTL_FER_ENABLE) 425 printf(" FER"); 426 if (ctl & PCIEM_DEVCTL_URR_ENABLE) 427 printf(" URR"); 428 if (version >= 2) { 429 cap = read_config(fd, &p->pc_sel, ptr + PCIER_DEVCAP2, 4); 430 if ((cap & PCIEM_DEVCAP2_ALT_RID_SUPP) != 0) { 431 ctl = read_config(fd, &p->pc_sel, 432 ptr + PCIER_DEVCTRL2, 4); 433 printf(" ARI %s", 434 (ctl & PCIEM_DEVCTL2_ALT_RID_ENABLE) ? 435 "enabled" : "disabled"); 436 437 } 438 if ((cap & PCIEM_DEVCAP2_LTR_SUPP) != 0) { 439 printf(" LTR %s", 440 (ctl & PCIEM_DEVCTL2_LTR_ENABLE) ? 441 "enabled" : "disabled"); 442 } 443 } 444 445 cap = read_config(fd, &p->pc_sel, ptr + PCIER_LINKCAP, 4); 446 sta = read_config(fd, &p->pc_sel, ptr+ PCIER_LINKSTAT, 2); 447 if (cap || sta) { 448 printf(" link x%d(x%d)", (sta & PCIEM_LNKSTAT_WIDTH) >> 4, 449 (cap & PCIEM_LNKCAP_MAXW_MASK) >> 4); 450 } 451 if (cap & PCIEM_LNKCAP_ASPM_MASK) { 452 ctl = read_config(fd, &p->pc_sel, ptr + PCIER_LINKCTRL, 2); 453 printf(" ASPM %s(%s)", 454 aspm_string(ctl & PCIEM_LNKCTL_ASPM_MASK), 455 aspm_string((cap & PCIEM_LNKCAP_ASPM_MASK) >> 10)); 456 } 457 if (flags & PCIEM_CAP_SLOT_IMPL) { 458 cap = read_config(fd, &p->pc_sel, ptr + PCIER_SLOTCAP, 4); 459 sta = read_config(fd, &p->pc_sel, ptr + PCIER_SLOTSTA, 2); 460 ctl = read_config(fd, &p->pc_sel, ptr + PCIER_SLOTCTL, 2); 461 printf("\n "); 462 printf(" slot %d", (cap & PCIEM_SLOTCAP_PSN) >> 19); 463 printf(" power limit %d mW", slot_power(cap)); 464 if (cap & PCIEM_SLOTCAP_HP_CAP) 465 printf(" HotPlug(%s)", sta & PCIEM_SLOTSTA_PDS ? 466 "present" : "empty"); 467 if (cap & PCIEM_SLOTCAP_HP_SURP) 468 printf(" surprise"); 469 if (cap & PCIEM_SLOTCAP_ATTEN_BTN) 470 printf(" Attn Button"); 471 if (cap & PCIEM_SLOTCAP_PWR_CTRL) 472 printf(" PC(%s)", ctl & PCIEM_SLOTCTL_PCC ? 473 "off" : "on"); 474 if (cap & PCIEM_SLOTCAP_MRL_SNS) 475 printf(" MRL(%s)", sta & PCIEM_SLOTSTA_MRLSS ? 476 "open" : "closed"); 477 if (cap & PCIEM_SLOTCAP_EIP) 478 printf(" EI(%s)", sta & PCIEM_SLOTSTA_EIS ? 479 "engaged" : "disengaged"); 480 } 481 } 482 483 static void 484 cap_msix(int fd, struct pci_conf *p, uint8_t ptr) 485 { 486 uint32_t val; 487 uint16_t ctrl; 488 int msgnum, table_bar, pba_bar; 489 490 ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_CTRL, 2); 491 msgnum = (ctrl & PCIM_MSIXCTRL_TABLE_SIZE) + 1; 492 val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_TABLE, 4); 493 table_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); 494 val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_PBA, 4); 495 pba_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); 496 printf("MSI-X supports %d message%s ", msgnum, 497 (msgnum == 1) ? "" : "s"); 498 if (table_bar == pba_bar) 499 printf("in map 0x%x", table_bar); 500 else 501 printf("in maps 0x%x and 0x%x", table_bar, pba_bar); 502 if (ctrl & PCIM_MSIXCTRL_MSIX_ENABLE) 503 printf(" enabled"); 504 } 505 506 static void 507 cap_sata(__unused int fd, __unused struct pci_conf *p, __unused uint8_t ptr) 508 { 509 510 printf("SATA Index-Data Pair"); 511 } 512 513 static void 514 cap_pciaf(int fd, struct pci_conf *p, uint8_t ptr) 515 { 516 uint8_t cap; 517 518 cap = read_config(fd, &p->pc_sel, ptr + PCIR_PCIAF_CAP, 1); 519 printf("PCI Advanced Features:%s%s", 520 cap & PCIM_PCIAFCAP_FLR ? " FLR" : "", 521 cap & PCIM_PCIAFCAP_TP ? " TP" : ""); 522 } 523 524 void 525 list_caps(int fd, struct pci_conf *p) 526 { 527 int express; 528 uint16_t sta; 529 uint8_t ptr, cap; 530 531 /* Are capabilities present for this device? */ 532 sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); 533 if (!(sta & PCIM_STATUS_CAPPRESENT)) 534 return; 535 536 switch (p->pc_hdr & PCIM_HDRTYPE) { 537 case PCIM_HDRTYPE_NORMAL: 538 case PCIM_HDRTYPE_BRIDGE: 539 ptr = PCIR_CAP_PTR; 540 break; 541 case PCIM_HDRTYPE_CARDBUS: 542 ptr = PCIR_CAP_PTR_2; 543 break; 544 default: 545 errx(1, "list_caps: bad header type"); 546 } 547 548 /* Walk the capability list. */ 549 express = 0; 550 ptr = read_config(fd, &p->pc_sel, ptr, 1); 551 while (ptr != 0 && ptr != 0xff) { 552 cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1); 553 printf(" cap %02x[%02x] = ", cap, ptr); 554 switch (cap) { 555 case PCIY_PMG: 556 cap_power(fd, p, ptr); 557 break; 558 case PCIY_AGP: 559 cap_agp(fd, p, ptr); 560 break; 561 case PCIY_VPD: 562 cap_vpd(fd, p, ptr); 563 break; 564 case PCIY_MSI: 565 cap_msi(fd, p, ptr); 566 break; 567 case PCIY_PCIX: 568 cap_pcix(fd, p, ptr); 569 break; 570 case PCIY_HT: 571 cap_ht(fd, p, ptr); 572 break; 573 case PCIY_VENDOR: 574 cap_vendor(fd, p, ptr); 575 break; 576 case PCIY_DEBUG: 577 cap_debug(fd, p, ptr); 578 break; 579 case PCIY_SUBVENDOR: 580 cap_subvendor(fd, p, ptr); 581 break; 582 case PCIY_EXPRESS: 583 express = 1; 584 cap_express(fd, p, ptr); 585 break; 586 case PCIY_MSIX: 587 cap_msix(fd, p, ptr); 588 break; 589 case PCIY_SATA: 590 cap_sata(fd, p, ptr); 591 break; 592 case PCIY_PCIAF: 593 cap_pciaf(fd, p, ptr); 594 break; 595 default: 596 printf("unknown"); 597 break; 598 } 599 printf("\n"); 600 ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1); 601 } 602 603 if (express) 604 list_ecaps(fd, p); 605 } 606 607 /* From <sys/systm.h>. */ 608 static __inline uint32_t 609 bitcount32(uint32_t x) 610 { 611 612 x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1); 613 x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2); 614 x = (x + (x >> 4)) & 0x0f0f0f0f; 615 x = (x + (x >> 8)); 616 x = (x + (x >> 16)) & 0x000000ff; 617 return (x); 618 } 619 620 static void 621 ecap_aer(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 622 { 623 uint32_t sta, mask; 624 625 printf("AER %d", ver); 626 if (ver < 1) 627 return; 628 sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_STATUS, 4); 629 mask = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_SEVERITY, 4); 630 printf(" %d fatal", bitcount32(sta & mask)); 631 printf(" %d non-fatal", bitcount32(sta & ~mask)); 632 sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_COR_STATUS, 4); 633 printf(" %d corrected", bitcount32(sta)); 634 } 635 636 static void 637 ecap_vc(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 638 { 639 uint32_t cap1; 640 641 printf("VC %d", ver); 642 if (ver != 1) 643 return; 644 cap1 = read_config(fd, &p->pc_sel, ptr + PCIR_VC_CAP1, 4); 645 printf(" max VC%d", cap1 & PCIM_VC_CAP1_EXT_COUNT); 646 if ((cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) != 0) 647 printf(" lowpri VC0-VC%d", 648 (cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) >> 4); 649 } 650 651 static void 652 ecap_sernum(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) 653 { 654 uint32_t high, low; 655 656 printf("Serial %d", ver); 657 if (ver != 1) 658 return; 659 low = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_LOW, 4); 660 high = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_HIGH, 4); 661 printf(" %08x%08x", high, low); 662 } 663 664 static void 665 list_ecaps(int fd, struct pci_conf *p) 666 { 667 uint32_t ecap; 668 uint16_t ptr; 669 670 ptr = PCIR_EXTCAP; 671 ecap = read_config(fd, &p->pc_sel, ptr, 4); 672 if (ecap == 0xffffffff || ecap == 0) 673 return; 674 for (;;) { 675 printf("ecap %04x[%03x] = ", PCI_EXTCAP_ID(ecap), ptr); 676 switch (PCI_EXTCAP_ID(ecap)) { 677 case PCIZ_AER: 678 ecap_aer(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 679 break; 680 case PCIZ_VC: 681 ecap_vc(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 682 break; 683 case PCIZ_SERNUM: 684 ecap_sernum(fd, p, ptr, PCI_EXTCAP_VER(ecap)); 685 break; 686 default: 687 printf("unknown %d", PCI_EXTCAP_VER(ecap)); 688 break; 689 } 690 printf("\n"); 691 ptr = PCI_EXTCAP_NEXTPTR(ecap); 692 if (ptr == 0) 693 break; 694 ecap = read_config(fd, &p->pc_sel, ptr, 4); 695 } 696 } 697 698 static const char * 699 aspm_string(uint8_t aspm) 700 { 701 switch (aspm) { 702 case 1: 703 return("L0s"); 704 case 2: 705 return("L1"); 706 case 3: 707 return("L0s/L1"); 708 default: 709 return("disabled"); 710 } 711 } 712 713 static int 714 slot_power(uint32_t cap) 715 { 716 int mwatts; 717 718 mwatts = (cap & PCIEM_SLOTCAP_SPLV) >> 7; 719 720 switch (cap & PCIEM_SLOTCAP_SPLS) { 721 case 0x0: 722 mwatts *= 10; 723 /* fallthrough */ 724 case 0x1: 725 mwatts *= 10; 726 /* fallthrough */ 727 case 0x2: 728 mwatts *= 10; 729 /* fallthrough */ 730 default: 731 break; 732 } 733 return mwatts; 734 } 735 736 uint8_t 737 pci_find_cap(int fd, struct pci_conf *p, uint8_t id) 738 { 739 uint16_t sta; 740 uint8_t ptr, cap; 741 742 /* Are capabilities present for this device? */ 743 sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); 744 if (!(sta & PCIM_STATUS_CAPPRESENT)) 745 return (0); 746 747 switch (p->pc_hdr & PCIM_HDRTYPE) { 748 case PCIM_HDRTYPE_NORMAL: 749 case PCIM_HDRTYPE_BRIDGE: 750 ptr = PCIR_CAP_PTR; 751 break; 752 case PCIM_HDRTYPE_CARDBUS: 753 ptr = PCIR_CAP_PTR_2; 754 break; 755 default: 756 return (0); 757 } 758 759 ptr = read_config(fd, &p->pc_sel, ptr, 1); 760 while (ptr != 0 && ptr != 0xff) { 761 cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1); 762 if (cap == id) 763 return (ptr); 764 ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1); 765 } 766 return (0); 767 } 768 769 /* Find offset of a specific extended capability. Returns 0 on failure. */ 770 uint16_t 771 pcie_find_cap(int fd, struct pci_conf *p, uint16_t id) 772 { 773 uint32_t ecap; 774 uint16_t ptr; 775 776 ptr = PCIR_EXTCAP; 777 ecap = read_config(fd, &p->pc_sel, ptr, 4); 778 if (ecap == 0xffffffff || ecap == 0) 779 return (0); 780 for (;;) { 781 if (PCI_EXTCAP_ID(ecap) == id) 782 return (ptr); 783 ptr = PCI_EXTCAP_NEXTPTR(ecap); 784 if (ptr == 0) 785 break; 786 ecap = read_config(fd, &p->pc_sel, ptr, 4); 787 } 788 return (0); 789 } 790