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 31 #ifndef lint 32 static const char rcsid[] = 33 "$FreeBSD$"; 34 #endif /* not lint */ 35 36 #include <sys/types.h> 37 38 #include <err.h> 39 #include <stdio.h> 40 #include <sys/agpio.h> 41 #include <sys/pciio.h> 42 43 #include <dev/agp/agpreg.h> 44 #include <dev/pci/pcireg.h> 45 46 #include "pciconf.h" 47 48 static void 49 cap_power(int fd, struct pci_conf *p, uint8_t ptr) 50 { 51 uint16_t cap, status; 52 53 cap = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_CAP, 2); 54 status = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_STATUS, 2); 55 printf("powerspec %d supports D0%s%s D3 current D%d", 56 cap & PCIM_PCAP_SPEC, 57 cap & PCIM_PCAP_D1SUPP ? " D1" : "", 58 cap & PCIM_PCAP_D2SUPP ? " D2" : "", 59 status & PCIM_PSTAT_DMASK); 60 } 61 62 static void 63 cap_agp(int fd, struct pci_conf *p, uint8_t ptr) 64 { 65 uint32_t status, command; 66 67 status = read_config(fd, &p->pc_sel, ptr + AGP_STATUS, 4); 68 command = read_config(fd, &p->pc_sel, ptr + AGP_CAPID, 4); 69 printf("AGP "); 70 if (AGP_MODE_GET_MODE_3(status)) { 71 printf("v3 "); 72 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_8x) 73 printf("8x "); 74 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_4x) 75 printf("4x "); 76 } else { 77 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_4x) 78 printf("4x "); 79 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_2x) 80 printf("2x "); 81 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_1x) 82 printf("1x "); 83 } 84 if (AGP_MODE_GET_SBA(status)) 85 printf("SBA "); 86 if (AGP_MODE_GET_AGP(command)) { 87 printf("enabled at "); 88 if (AGP_MODE_GET_MODE_3(command)) { 89 printf("v3 "); 90 switch (AGP_MODE_GET_RATE(command)) { 91 case AGP_MODE_V3_RATE_8x: 92 printf("8x "); 93 break; 94 case AGP_MODE_V3_RATE_4x: 95 printf("4x "); 96 break; 97 } 98 } else 99 switch (AGP_MODE_GET_RATE(command)) { 100 case AGP_MODE_V2_RATE_4x: 101 printf("4x "); 102 break; 103 case AGP_MODE_V2_RATE_2x: 104 printf("2x "); 105 break; 106 case AGP_MODE_V2_RATE_1x: 107 printf("1x "); 108 break; 109 } 110 if (AGP_MODE_GET_SBA(command)) 111 printf("SBA "); 112 } else 113 printf("disabled"); 114 } 115 116 static void 117 cap_vpd(int fd, struct pci_conf *p, uint8_t ptr) 118 { 119 120 printf("VPD"); 121 } 122 123 static void 124 cap_msi(int fd, struct pci_conf *p, uint8_t ptr) 125 { 126 uint16_t ctrl; 127 int msgnum; 128 129 ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSI_CTRL, 2); 130 msgnum = 1 << ((ctrl & PCIM_MSICTRL_MMC_MASK) >> 1); 131 printf("MSI supports %d message%s%s%s ", msgnum, 132 (msgnum == 1) ? "" : "s", 133 (ctrl & PCIM_MSICTRL_64BIT) ? ", 64 bit" : "", 134 (ctrl & PCIM_MSICTRL_VECTOR) ? ", vector masks" : ""); 135 if (ctrl & PCIM_MSICTRL_MSI_ENABLE) { 136 msgnum = 1 << ((ctrl & PCIM_MSICTRL_MME_MASK) >> 4); 137 printf("enabled with %d message%s", msgnum, 138 (msgnum == 1) ? "" : "s"); 139 } 140 } 141 142 static void 143 cap_pcix(int fd, struct pci_conf *p, uint8_t ptr) 144 { 145 uint32_t status; 146 int comma, max_splits, max_burst_read; 147 148 status = read_config(fd, &p->pc_sel, ptr + PCIXR_STATUS, 4); 149 printf("PCI-X "); 150 if (status & PCIXM_STATUS_64BIT) 151 printf("64-bit "); 152 if ((p->pc_hdr & PCIM_HDRTYPE) == 1) 153 printf("bridge "); 154 if ((p->pc_hdr & PCIM_HDRTYPE) != 1 || (status & (PCIXM_STATUS_133CAP | 155 PCIXM_STATUS_266CAP | PCIXM_STATUS_533CAP)) != 0) 156 printf("supports"); 157 comma = 0; 158 if (status & PCIXM_STATUS_133CAP) { 159 printf("%s 133MHz", comma ? "," : ""); 160 comma = 1; 161 } 162 if (status & PCIXM_STATUS_266CAP) { 163 printf("%s 266MHz", comma ? "," : ""); 164 comma = 1; 165 } 166 if (status & PCIXM_STATUS_533CAP) { 167 printf("%s 533MHz", comma ? "," : ""); 168 comma = 1; 169 } 170 if ((p->pc_hdr & PCIM_HDRTYPE) == 1) 171 return; 172 switch (status & PCIXM_STATUS_MAX_READ) { 173 case PCIXM_STATUS_MAX_READ_512: 174 max_burst_read = 512; 175 break; 176 case PCIXM_STATUS_MAX_READ_1024: 177 max_burst_read = 1024; 178 break; 179 case PCIXM_STATUS_MAX_READ_2048: 180 max_burst_read = 2048; 181 break; 182 case PCIXM_STATUS_MAX_READ_4096: 183 max_burst_read = 4096; 184 break; 185 } 186 switch (status & PCIXM_STATUS_MAX_SPLITS) { 187 case PCIXM_STATUS_MAX_SPLITS_1: 188 max_splits = 1; 189 break; 190 case PCIXM_STATUS_MAX_SPLITS_2: 191 max_splits = 2; 192 break; 193 case PCIXM_STATUS_MAX_SPLITS_3: 194 max_splits = 3; 195 break; 196 case PCIXM_STATUS_MAX_SPLITS_4: 197 max_splits = 4; 198 break; 199 case PCIXM_STATUS_MAX_SPLITS_8: 200 max_splits = 8; 201 break; 202 case PCIXM_STATUS_MAX_SPLITS_12: 203 max_splits = 12; 204 break; 205 case PCIXM_STATUS_MAX_SPLITS_16: 206 max_splits = 16; 207 break; 208 case PCIXM_STATUS_MAX_SPLITS_32: 209 max_splits = 32; 210 break; 211 } 212 printf("%s %d burst read, %d split transaction%s", comma ? "," : "", 213 max_burst_read, max_splits, max_splits == 1 ? "" : "s"); 214 } 215 216 static void 217 cap_ht(int fd, struct pci_conf *p, uint8_t ptr) 218 { 219 uint32_t reg; 220 uint16_t command; 221 222 command = read_config(fd, &p->pc_sel, ptr + PCIR_HT_COMMAND, 2); 223 printf("HT "); 224 if ((command & 0xe000) == PCIM_HTCAP_SLAVE) 225 printf("slave"); 226 else if ((command & 0xe000) == PCIM_HTCAP_HOST) 227 printf("host"); 228 else 229 switch (command & PCIM_HTCMD_CAP_MASK) { 230 case PCIM_HTCAP_SWITCH: 231 printf("switch"); 232 break; 233 case PCIM_HTCAP_INTERRUPT: 234 printf("interrupt"); 235 break; 236 case PCIM_HTCAP_REVISION_ID: 237 printf("revision ID"); 238 break; 239 case PCIM_HTCAP_UNITID_CLUMPING: 240 printf("unit ID clumping"); 241 break; 242 case PCIM_HTCAP_EXT_CONFIG_SPACE: 243 printf("extended config space"); 244 break; 245 case PCIM_HTCAP_ADDRESS_MAPPING: 246 printf("address mapping"); 247 break; 248 case PCIM_HTCAP_MSI_MAPPING: 249 printf("MSI %saddress window %s at 0x", 250 command & PCIM_HTCMD_MSI_FIXED ? "fixed " : "", 251 command & PCIM_HTCMD_MSI_ENABLE ? "enabled" : 252 "disabled"); 253 if (command & PCIM_HTCMD_MSI_FIXED) 254 printf("fee00000"); 255 else { 256 reg = read_config(fd, &p->pc_sel, 257 ptr + PCIR_HTMSI_ADDRESS_HI, 4); 258 if (reg != 0) 259 printf("%08x", reg); 260 reg = read_config(fd, &p->pc_sel, 261 ptr + PCIR_HTMSI_ADDRESS_LO, 4); 262 printf("%08x", reg); 263 } 264 break; 265 case PCIM_HTCAP_DIRECT_ROUTE: 266 printf("direct route"); 267 break; 268 case PCIM_HTCAP_VCSET: 269 printf("VC set"); 270 break; 271 case PCIM_HTCAP_RETRY_MODE: 272 printf("retry mode"); 273 break; 274 case PCIM_HTCAP_X86_ENCODING: 275 printf("X86 encoding"); 276 break; 277 default: 278 printf("unknown %02x", command); 279 break; 280 } 281 } 282 283 static void 284 cap_vendor(int fd, struct pci_conf *p, uint8_t ptr) 285 { 286 uint8_t length; 287 288 length = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_LENGTH, 1); 289 printf("vendor (length %d)", length); 290 if (p->pc_vendor == 0x8086) { 291 /* Intel */ 292 uint8_t version; 293 294 version = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_DATA, 295 1); 296 printf(" Intel cap %d version %d", version >> 4, version & 0xf); 297 if (version >> 4 == 1 && length == 12) { 298 /* Feature Detection */ 299 uint32_t fvec; 300 int comma; 301 302 comma = 0; 303 fvec = read_config(fd, &p->pc_sel, ptr + 304 PCIR_VENDOR_DATA + 5, 4); 305 printf("\n\t\t features:"); 306 if (fvec & (1 << 0)) { 307 printf(" AMT"); 308 comma = 1; 309 } 310 fvec = read_config(fd, &p->pc_sel, ptr + 311 PCIR_VENDOR_DATA + 1, 4); 312 if (fvec & (1 << 21)) { 313 printf("%s Quick Resume", comma ? "," : ""); 314 comma = 1; 315 } 316 if (fvec & (1 << 18)) { 317 printf("%s SATA RAID-5", comma ? "," : ""); 318 comma = 1; 319 } 320 if (fvec & (1 << 9)) { 321 printf("%s Mobile", comma ? "," : ""); 322 comma = 1; 323 } 324 if (fvec & (1 << 7)) { 325 printf("%s 6 PCI-e x1 slots", comma ? "," : ""); 326 comma = 1; 327 } else { 328 printf("%s 4 PCI-e x1 slots", comma ? "," : ""); 329 comma = 1; 330 } 331 if (fvec & (1 << 5)) { 332 printf("%s SATA RAID-0/1/10", comma ? "," : ""); 333 comma = 1; 334 } 335 if (fvec & (1 << 3)) { 336 printf("%s SATA AHCI", comma ? "," : ""); 337 comma = 1; 338 } 339 } 340 } 341 } 342 343 static void 344 cap_debug(int fd, struct pci_conf *p, uint8_t ptr) 345 { 346 uint16_t debug_port; 347 348 debug_port = read_config(fd, &p->pc_sel, ptr + PCIR_DEBUG_PORT, 2); 349 printf("EHCI Debug Port at offset 0x%x in map 0x%x", debug_port & 350 PCIM_DEBUG_PORT_OFFSET, PCIR_BAR(debug_port >> 13)); 351 } 352 353 static void 354 cap_subvendor(int fd, struct pci_conf *p, uint8_t ptr) 355 { 356 uint32_t id; 357 358 id = read_config(fd, &p->pc_sel, ptr + PCIR_SUBVENDCAP_ID, 4); 359 printf("PCI Bridge card=0x%08x", id); 360 } 361 362 #define MAX_PAYLOAD(field) (128 << (field)) 363 364 static void 365 cap_express(int fd, struct pci_conf *p, uint8_t ptr) 366 { 367 uint32_t val; 368 uint16_t flags; 369 370 flags = read_config(fd, &p->pc_sel, ptr + PCIR_EXPRESS_FLAGS, 2); 371 printf("PCI-Express %d ", flags & PCIM_EXP_FLAGS_VERSION); 372 switch (flags & PCIM_EXP_FLAGS_TYPE) { 373 case PCIM_EXP_TYPE_ENDPOINT: 374 printf("endpoint"); 375 break; 376 case PCIM_EXP_TYPE_LEGACY_ENDPOINT: 377 printf("legacy endpoint"); 378 break; 379 case PCIM_EXP_TYPE_ROOT_PORT: 380 printf("root port"); 381 break; 382 case PCIM_EXP_TYPE_UPSTREAM_PORT: 383 printf("upstream port"); 384 break; 385 case PCIM_EXP_TYPE_DOWNSTREAM_PORT: 386 printf("downstream port"); 387 break; 388 case PCIM_EXP_TYPE_PCI_BRIDGE: 389 printf("PCI bridge"); 390 break; 391 case PCIM_EXP_TYPE_PCIE_BRIDGE: 392 printf("PCI to PCIe bridge"); 393 break; 394 case PCIM_EXP_TYPE_ROOT_INT_EP: 395 printf("root endpoint"); 396 break; 397 case PCIM_EXP_TYPE_ROOT_EC: 398 printf("event collector"); 399 break; 400 default: 401 printf("type %d", (flags & PCIM_EXP_FLAGS_TYPE) >> 4); 402 break; 403 } 404 if (flags & PCIM_EXP_FLAGS_IRQ) 405 printf(" IRQ %d", (flags & PCIM_EXP_FLAGS_IRQ) >> 8); 406 val = read_config(fd, &p->pc_sel, ptr + PCIR_EXPRESS_DEVICE_CAP, 4); 407 flags = read_config(fd, &p->pc_sel, ptr + PCIR_EXPRESS_DEVICE_CTL, 2); 408 printf(" max data %d(%d)", 409 MAX_PAYLOAD((flags & PCIM_EXP_CTL_MAX_PAYLOAD) >> 5), 410 MAX_PAYLOAD(val & PCIM_EXP_CAP_MAX_PAYLOAD)); 411 val = read_config(fd, &p->pc_sel, ptr + PCIR_EXPRESS_LINK_CAP, 4); 412 flags = read_config(fd, &p->pc_sel, ptr+ PCIR_EXPRESS_LINK_STA, 2); 413 printf(" link x%d(x%d)", (flags & PCIM_LINK_STA_WIDTH) >> 4, 414 (val & PCIM_LINK_CAP_MAX_WIDTH) >> 4); 415 } 416 417 static void 418 cap_msix(int fd, struct pci_conf *p, uint8_t ptr) 419 { 420 uint32_t val; 421 uint16_t ctrl; 422 int msgnum, table_bar, pba_bar; 423 424 ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_CTRL, 2); 425 msgnum = (ctrl & PCIM_MSIXCTRL_TABLE_SIZE) + 1; 426 val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_TABLE, 4); 427 table_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); 428 val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_PBA, 4); 429 pba_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); 430 printf("MSI-X supports %d message%s ", msgnum, 431 (msgnum == 1) ? "" : "s"); 432 if (table_bar == pba_bar) 433 printf("in map 0x%x", table_bar); 434 else 435 printf("in maps 0x%x and 0x%x", table_bar, pba_bar); 436 if (ctrl & PCIM_MSIXCTRL_MSIX_ENABLE) 437 printf(" enabled"); 438 } 439 440 static void 441 cap_sata(int fd, struct pci_conf *p, uint8_t ptr) 442 { 443 444 printf("SATA Index-Data Pair"); 445 } 446 447 static void 448 cap_pciaf(int fd, struct pci_conf *p, uint8_t ptr) 449 { 450 uint8_t cap; 451 452 cap = read_config(fd, &p->pc_sel, ptr + PCIR_PCIAF_CAP, 1); 453 printf("PCI Advanced Features:%s%s", 454 cap & PCIM_PCIAFCAP_FLR ? " FLR" : "", 455 cap & PCIM_PCIAFCAP_TP ? " TP" : ""); 456 } 457 458 void 459 list_caps(int fd, struct pci_conf *p) 460 { 461 uint16_t cmd; 462 uint8_t ptr, cap; 463 464 /* Are capabilities present for this device? */ 465 cmd = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); 466 if (!(cmd & PCIM_STATUS_CAPPRESENT)) 467 return; 468 469 switch (p->pc_hdr & PCIM_HDRTYPE) { 470 case 0: 471 case 1: 472 ptr = PCIR_CAP_PTR; 473 break; 474 case 2: 475 ptr = PCIR_CAP_PTR_2; 476 break; 477 default: 478 errx(1, "list_caps: bad header type"); 479 } 480 481 /* Walk the capability list. */ 482 ptr = read_config(fd, &p->pc_sel, ptr, 1); 483 while (ptr != 0 && ptr != 0xff) { 484 cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1); 485 printf(" cap %02x[%02x] = ", cap, ptr); 486 switch (cap) { 487 case PCIY_PMG: 488 cap_power(fd, p, ptr); 489 break; 490 case PCIY_AGP: 491 cap_agp(fd, p, ptr); 492 break; 493 case PCIY_VPD: 494 cap_vpd(fd, p, ptr); 495 break; 496 case PCIY_MSI: 497 cap_msi(fd, p, ptr); 498 break; 499 case PCIY_PCIX: 500 cap_pcix(fd, p, ptr); 501 break; 502 case PCIY_HT: 503 cap_ht(fd, p, ptr); 504 break; 505 case PCIY_VENDOR: 506 cap_vendor(fd, p, ptr); 507 break; 508 case PCIY_DEBUG: 509 cap_debug(fd, p, ptr); 510 break; 511 case PCIY_SUBVENDOR: 512 cap_subvendor(fd, p, ptr); 513 break; 514 case PCIY_EXPRESS: 515 cap_express(fd, p, ptr); 516 break; 517 case PCIY_MSIX: 518 cap_msix(fd, p, ptr); 519 break; 520 case PCIY_SATA: 521 cap_sata(fd, p, ptr); 522 break; 523 case PCIY_PCIAF: 524 cap_pciaf(fd, p, ptr); 525 break; 526 default: 527 printf("unknown"); 528 break; 529 } 530 printf("\n"); 531 ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1); 532 } 533 } 534