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 printf("supports"); 155 comma = 0; 156 if (status & PCIXM_STATUS_133CAP) { 157 printf("%s 133MHz", comma ? "," : ""); 158 comma = 1; 159 } 160 if (status & PCIXM_STATUS_266CAP) { 161 printf("%s 266MHz", comma ? "," : ""); 162 comma = 1; 163 } 164 if (status & PCIXM_STATUS_533CAP) { 165 printf("%s 533MHz", comma ? "," : ""); 166 comma = 1; 167 } 168 if ((p->pc_hdr & PCIM_HDRTYPE) == 1) 169 return; 170 switch (status & PCIXM_STATUS_MAX_READ) { 171 case PCIXM_STATUS_MAX_READ_512: 172 max_burst_read = 512; 173 break; 174 case PCIXM_STATUS_MAX_READ_1024: 175 max_burst_read = 1024; 176 break; 177 case PCIXM_STATUS_MAX_READ_2048: 178 max_burst_read = 2048; 179 break; 180 case PCIXM_STATUS_MAX_READ_4096: 181 max_burst_read = 4096; 182 break; 183 } 184 switch (status & PCIXM_STATUS_MAX_SPLITS) { 185 case PCIXM_STATUS_MAX_SPLITS_1: 186 max_splits = 1; 187 break; 188 case PCIXM_STATUS_MAX_SPLITS_2: 189 max_splits = 2; 190 break; 191 case PCIXM_STATUS_MAX_SPLITS_3: 192 max_splits = 3; 193 break; 194 case PCIXM_STATUS_MAX_SPLITS_4: 195 max_splits = 4; 196 break; 197 case PCIXM_STATUS_MAX_SPLITS_8: 198 max_splits = 8; 199 break; 200 case PCIXM_STATUS_MAX_SPLITS_12: 201 max_splits = 12; 202 break; 203 case PCIXM_STATUS_MAX_SPLITS_16: 204 max_splits = 16; 205 break; 206 case PCIXM_STATUS_MAX_SPLITS_32: 207 max_splits = 32; 208 break; 209 } 210 printf("%s %d burst read, %d split transaction%s", comma ? "," : "", 211 max_burst_read, max_splits, max_splits == 1 ? "" : "s"); 212 } 213 214 static void 215 cap_ht(int fd, struct pci_conf *p, uint8_t ptr) 216 { 217 uint32_t reg; 218 uint16_t command; 219 220 command = read_config(fd, &p->pc_sel, ptr + PCIR_HT_COMMAND, 2); 221 printf("HT "); 222 if ((command & 0xe000) == PCIM_HTCAP_SLAVE) 223 printf("slave"); 224 else if ((command & 0xe000) == PCIM_HTCAP_HOST) 225 printf("host"); 226 else 227 switch (command & PCIM_HTCMD_CAP_MASK) { 228 case PCIM_HTCAP_SWITCH: 229 printf("switch"); 230 break; 231 case PCIM_HTCAP_INTERRUPT: 232 printf("interrupt"); 233 break; 234 case PCIM_HTCAP_REVISION_ID: 235 printf("revision ID"); 236 break; 237 case PCIM_HTCAP_UNITID_CLUMPING: 238 printf("unit ID clumping"); 239 break; 240 case PCIM_HTCAP_EXT_CONFIG_SPACE: 241 printf("extended config space"); 242 break; 243 case PCIM_HTCAP_ADDRESS_MAPPING: 244 printf("address mapping"); 245 break; 246 case PCIM_HTCAP_MSI_MAPPING: 247 printf("MSI %saddress window %s at 0x", 248 command & PCIM_HTCMD_MSI_FIXED ? "fixed " : "", 249 command & PCIM_HTCMD_MSI_ENABLE ? "enabled" : 250 "disabled"); 251 if (command & PCIM_HTCMD_MSI_FIXED) 252 printf("fee00000"); 253 else { 254 reg = read_config(fd, &p->pc_sel, 255 ptr + PCIR_HTMSI_ADDRESS_HI, 4); 256 if (reg != 0) 257 printf("%08x", reg); 258 reg = read_config(fd, &p->pc_sel, 259 ptr + PCIR_HTMSI_ADDRESS_LO, 4); 260 printf("%08x", reg); 261 } 262 break; 263 case PCIM_HTCAP_DIRECT_ROUTE: 264 printf("direct route"); 265 break; 266 case PCIM_HTCAP_VCSET: 267 printf("VC set"); 268 break; 269 case PCIM_HTCAP_RETRY_MODE: 270 printf("retry mode"); 271 break; 272 case PCIM_HTCAP_X86_ENCODING: 273 printf("X86 encoding"); 274 break; 275 default: 276 printf("unknown %02x", command); 277 break; 278 } 279 } 280 281 static void 282 cap_vendor(int fd, struct pci_conf *p, uint8_t ptr) 283 { 284 uint8_t length; 285 286 length = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_LENGTH, 1); 287 printf("vendor (length %d)", length); 288 if (p->pc_vendor == 0x8086) { 289 /* Intel */ 290 uint8_t version; 291 292 version = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_DATA, 293 1); 294 printf(" Intel cap %d version %d", version >> 4, version & 0xf); 295 if (version >> 4 == 1 && length == 12) { 296 /* Feature Detection */ 297 uint32_t fvec; 298 int comma; 299 300 comma = 0; 301 fvec = read_config(fd, &p->pc_sel, ptr + 302 PCIR_VENDOR_DATA + 5, 4); 303 printf("\n\t\t features:"); 304 if (fvec & (1 << 0)) { 305 printf(" AMT"); 306 comma = 1; 307 } 308 fvec = read_config(fd, &p->pc_sel, ptr + 309 PCIR_VENDOR_DATA + 1, 4); 310 if (fvec & (1 << 21)) { 311 printf("%s Quick Resume", comma ? "," : ""); 312 comma = 1; 313 } 314 if (fvec & (1 << 18)) { 315 printf("%s SATA RAID-5", comma ? "," : ""); 316 comma = 1; 317 } 318 if (fvec & (1 << 9)) { 319 printf("%s Mobile", comma ? "," : ""); 320 comma = 1; 321 } 322 if (fvec & (1 << 7)) { 323 printf("%s 6 PCI-e x1 slots", comma ? "," : ""); 324 comma = 1; 325 } else { 326 printf("%s 4 PCI-e x1 slots", comma ? "," : ""); 327 comma = 1; 328 } 329 if (fvec & (1 << 5)) { 330 printf("%s SATA RAID-0/1/10", comma ? "," : ""); 331 comma = 1; 332 } 333 if (fvec & (1 << 3)) { 334 printf("%s SATA AHCI", comma ? "," : ""); 335 comma = 1; 336 } 337 } 338 } 339 } 340 341 static void 342 cap_debug(int fd, struct pci_conf *p, uint8_t ptr) 343 { 344 uint16_t debug_port; 345 346 debug_port = read_config(fd, &p->pc_sel, ptr + PCIR_DEBUG_PORT, 2); 347 printf("EHCI Debug Port at offset 0x%x in map 0x%x", debug_port & 348 PCIM_DEBUG_PORT_OFFSET, PCIR_BAR(debug_port >> 13)); 349 } 350 351 static void 352 cap_subvendor(int fd, struct pci_conf *p, uint8_t ptr) 353 { 354 uint32_t id; 355 356 id = read_config(fd, &p->pc_sel, ptr + PCIR_SUBVENDCAP_ID, 4); 357 printf("PCI Bridge card=0x%08x", id); 358 } 359 360 static void 361 cap_express(int fd, struct pci_conf *p, uint8_t ptr) 362 { 363 uint16_t flags; 364 365 flags = read_config(fd, &p->pc_sel, ptr + PCIR_EXPRESS_FLAGS, 2); 366 printf("PCI-Express %d ", flags & PCIM_EXP_FLAGS_VERSION); 367 switch (flags & PCIM_EXP_FLAGS_TYPE) { 368 case PCIM_EXP_TYPE_ENDPOINT: 369 printf("endpoint"); 370 break; 371 case PCIM_EXP_TYPE_LEGACY_ENDPOINT: 372 printf("legacy endpoint"); 373 break; 374 case PCIM_EXP_TYPE_ROOT_PORT: 375 printf("root port"); 376 break; 377 case PCIM_EXP_TYPE_UPSTREAM_PORT: 378 printf("upstream port"); 379 break; 380 case PCIM_EXP_TYPE_DOWNSTREAM_PORT: 381 printf("downstream port"); 382 break; 383 case PCIM_EXP_TYPE_PCI_BRIDGE: 384 printf("PCI bridge"); 385 break; 386 default: 387 printf("type %d", (flags & PCIM_EXP_FLAGS_TYPE) >> 8); 388 break; 389 } 390 if (flags & PCIM_EXP_FLAGS_IRQ) 391 printf(" IRQ %d", (flags & PCIM_EXP_FLAGS_IRQ) >> 17); 392 } 393 394 static void 395 cap_msix(int fd, struct pci_conf *p, uint8_t ptr) 396 { 397 uint32_t val; 398 uint16_t ctrl; 399 int msgnum, table_bar, pba_bar; 400 401 ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_CTRL, 2); 402 msgnum = (ctrl & PCIM_MSIXCTRL_TABLE_SIZE) + 1; 403 val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_TABLE, 4); 404 table_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); 405 val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_PBA, 4); 406 pba_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); 407 printf("MSI-X supports %d message%s ", msgnum, 408 (msgnum == 1) ? "" : "s"); 409 if (table_bar == pba_bar) 410 printf("in map 0x%x", table_bar); 411 else 412 printf("in maps 0x%x and 0x%x", table_bar, pba_bar); 413 if (ctrl & PCIM_MSIXCTRL_MSIX_ENABLE) 414 printf(" enabled"); 415 } 416 417 void 418 list_caps(int fd, struct pci_conf *p) 419 { 420 uint16_t cmd; 421 uint8_t ptr, cap; 422 423 /* Are capabilities present for this device? */ 424 cmd = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); 425 if (!(cmd & PCIM_STATUS_CAPPRESENT)) 426 return; 427 428 switch (p->pc_hdr & PCIM_HDRTYPE) { 429 case 0: 430 case 1: 431 ptr = PCIR_CAP_PTR; 432 break; 433 case 2: 434 ptr = PCIR_CAP_PTR_2; 435 break; 436 default: 437 errx(1, "list_caps: bad header type"); 438 } 439 440 /* Walk the capability list. */ 441 ptr = read_config(fd, &p->pc_sel, ptr, 1); 442 while (ptr != 0 && ptr != 0xff) { 443 cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1); 444 printf(" cap %02x[%02x] = ", cap, ptr); 445 switch (cap) { 446 case PCIY_PMG: 447 cap_power(fd, p, ptr); 448 break; 449 case PCIY_AGP: 450 cap_agp(fd, p, ptr); 451 break; 452 case PCIY_VPD: 453 cap_vpd(fd, p, ptr); 454 break; 455 case PCIY_MSI: 456 cap_msi(fd, p, ptr); 457 break; 458 case PCIY_PCIX: 459 cap_pcix(fd, p, ptr); 460 break; 461 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