1 /*- 2 * Copyright (c) 2007 John Baldwin <jhb@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the author nor the names of any co-contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #ifndef lint 31 static const char rcsid[] = 32 "$FreeBSD$"; 33 #endif /* not lint */ 34 35 #include <sys/types.h> 36 37 #include <err.h> 38 #include <stdio.h> 39 #include <sys/agpio.h> 40 #include <sys/pciio.h> 41 42 #include <pci/agpreg.h> 43 #include <dev/pci/pcireg.h> 44 45 #include "pciconf.h" 46 47 static void 48 cap_power(int fd, struct pci_conf *p, uint8_t ptr) 49 { 50 uint16_t cap, status; 51 52 cap = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_CAP, 2); 53 status = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_STATUS, 2); 54 printf("powerspec %d supports D0%s%s D3 current D%d", 55 cap & PCIM_PCAP_SPEC, 56 cap & PCIM_PCAP_D1SUPP ? " D1" : "", 57 cap & PCIM_PCAP_D2SUPP ? " D2" : "", 58 status & PCIM_PSTAT_DMASK); 59 } 60 61 static void 62 cap_agp(int fd, struct pci_conf *p, uint8_t ptr) 63 { 64 uint32_t status, command; 65 66 status = read_config(fd, &p->pc_sel, ptr + AGP_STATUS, 4); 67 command = read_config(fd, &p->pc_sel, ptr + AGP_CAPID, 4); 68 printf("AGP "); 69 if (AGP_MODE_GET_MODE_3(status)) { 70 printf("v3 "); 71 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_8x) 72 printf("8x "); 73 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_4x) 74 printf("4x "); 75 } else { 76 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_4x) 77 printf("4x "); 78 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_2x) 79 printf("2x "); 80 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_1x) 81 printf("1x "); 82 } 83 if (AGP_MODE_GET_SBA(status)) 84 printf("SBA "); 85 if (AGP_MODE_GET_AGP(command)) { 86 printf("enabled at "); 87 if (AGP_MODE_GET_MODE_3(command)) { 88 printf("v3 "); 89 switch (AGP_MODE_GET_RATE(command)) { 90 case AGP_MODE_V3_RATE_8x: 91 printf("8x "); 92 break; 93 case AGP_MODE_V3_RATE_4x: 94 printf("4x "); 95 break; 96 } 97 } else 98 switch (AGP_MODE_GET_RATE(command)) { 99 case AGP_MODE_V2_RATE_4x: 100 printf("4x "); 101 break; 102 case AGP_MODE_V2_RATE_2x: 103 printf("2x "); 104 break; 105 case AGP_MODE_V2_RATE_1x: 106 printf("1x "); 107 break; 108 } 109 if (AGP_MODE_GET_SBA(command)) 110 printf("SBA "); 111 } else 112 printf("disabled"); 113 } 114 115 static void 116 cap_vpd(int fd, struct pci_conf *p, uint8_t ptr) 117 { 118 119 printf("VPD"); 120 } 121 122 static void 123 cap_msi(int fd, struct pci_conf *p, uint8_t ptr) 124 { 125 uint16_t ctrl; 126 int msgnum; 127 128 ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSI_CTRL, 2); 129 msgnum = 1 << ((ctrl & PCIM_MSICTRL_MMC_MASK) >> 1); 130 printf("MSI supports %d message%s%s%s ", msgnum, 131 (msgnum == 1) ? "" : "s", 132 (ctrl & PCIM_MSICTRL_64BIT) ? ", 64 bit" : "", 133 (ctrl & PCIM_MSICTRL_VECTOR) ? ", vector masks" : ""); 134 if (ctrl & PCIM_MSICTRL_MSI_ENABLE) { 135 msgnum = 1 << ((ctrl & PCIM_MSICTRL_MME_MASK) >> 4); 136 printf("enabled with %d message%s", msgnum, 137 (msgnum == 1) ? "" : "s"); 138 } 139 } 140 141 static void 142 cap_pcix(int fd, struct pci_conf *p, uint8_t ptr) 143 { 144 uint32_t status; 145 int comma, max_splits, max_burst_read; 146 147 status = read_config(fd, &p->pc_sel, ptr + PCIXR_STATUS, 4); 148 printf("PCI-X "); 149 if (status & PCIXM_STATUS_64BIT) 150 printf("64-bit "); 151 if ((p->pc_hdr & PCIM_HDRTYPE) == 1) 152 printf("bridge "); 153 printf("supports"); 154 comma = 0; 155 if (status & PCIXM_STATUS_133CAP) { 156 printf("%s 133MHz", comma ? "," : ""); 157 comma = 1; 158 } 159 if (status & PCIXM_STATUS_266CAP) { 160 printf("%s 266MHz", comma ? "," : ""); 161 comma = 1; 162 } 163 if (status & PCIXM_STATUS_533CAP) { 164 printf("%s 533MHz", comma ? "," : ""); 165 comma = 1; 166 } 167 if ((p->pc_hdr & PCIM_HDRTYPE) == 1) 168 return; 169 switch (status & PCIXM_STATUS_MAX_READ) { 170 case PCIXM_STATUS_MAX_READ_512: 171 max_burst_read = 512; 172 break; 173 case PCIXM_STATUS_MAX_READ_1024: 174 max_burst_read = 1024; 175 break; 176 case PCIXM_STATUS_MAX_READ_2048: 177 max_burst_read = 2048; 178 break; 179 case PCIXM_STATUS_MAX_READ_4096: 180 max_burst_read = 4096; 181 break; 182 } 183 switch (status & PCIXM_STATUS_MAX_SPLITS) { 184 case PCIXM_STATUS_MAX_SPLITS_1: 185 max_splits = 1; 186 break; 187 case PCIXM_STATUS_MAX_SPLITS_2: 188 max_splits = 2; 189 break; 190 case PCIXM_STATUS_MAX_SPLITS_3: 191 max_splits = 3; 192 break; 193 case PCIXM_STATUS_MAX_SPLITS_4: 194 max_splits = 4; 195 break; 196 case PCIXM_STATUS_MAX_SPLITS_8: 197 max_splits = 8; 198 break; 199 case PCIXM_STATUS_MAX_SPLITS_12: 200 max_splits = 12; 201 break; 202 case PCIXM_STATUS_MAX_SPLITS_16: 203 max_splits = 16; 204 break; 205 case PCIXM_STATUS_MAX_SPLITS_32: 206 max_splits = 32; 207 break; 208 } 209 printf("%s %d burst read, %d split transaction%s", comma ? "," : "", 210 max_burst_read, max_splits, max_splits == 1 ? "" : "s"); 211 } 212 213 static void 214 cap_ht(int fd, struct pci_conf *p, uint8_t ptr) 215 { 216 uint32_t reg; 217 uint16_t command; 218 219 command = read_config(fd, &p->pc_sel, ptr + PCIR_HT_COMMAND, 2); 220 printf("HT "); 221 if ((command & 0xe000) == PCIM_HTCAP_SLAVE) 222 printf("slave"); 223 else if ((command & 0xe000) == PCIM_HTCAP_HOST) 224 printf("host"); 225 else 226 switch (command & PCIM_HTCMD_CAP_MASK) { 227 case PCIM_HTCAP_SWITCH: 228 printf("switch"); 229 break; 230 case PCIM_HTCAP_INTERRUPT: 231 printf("interrupt"); 232 break; 233 case PCIM_HTCAP_REVISION_ID: 234 printf("revision ID"); 235 break; 236 case PCIM_HTCAP_UNITID_CLUMPING: 237 printf("unit ID clumping"); 238 break; 239 case PCIM_HTCAP_EXT_CONFIG_SPACE: 240 printf("extended config space"); 241 break; 242 case PCIM_HTCAP_ADDRESS_MAPPING: 243 printf("address mapping"); 244 break; 245 case PCIM_HTCAP_MSI_MAPPING: 246 printf("MSI address window %s at 0x", 247 command & PCIM_HTCMD_MSI_ENABLE ? "enabled" : 248 "disabled"); 249 reg = read_config(fd, &p->pc_sel, 250 ptr + PCIR_HTMSI_ADDRESS_HI, 4); 251 if (reg != 0) 252 printf("%08x", reg); 253 reg = read_config(fd, &p->pc_sel, 254 ptr + PCIR_HTMSI_ADDRESS_LO, 4); 255 printf("%08x", reg); 256 break; 257 case PCIM_HTCAP_DIRECT_ROUTE: 258 printf("direct route"); 259 break; 260 case PCIM_HTCAP_VCSET: 261 printf("VC set"); 262 break; 263 case PCIM_HTCAP_RETRY_MODE: 264 printf("retry mode"); 265 break; 266 default: 267 printf("unknown %02x", command); 268 break; 269 } 270 } 271 272 static void 273 cap_vendor(int fd, struct pci_conf *p, uint8_t ptr) 274 { 275 uint8_t length; 276 277 length = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_LENGTH, 1); 278 printf("vendor (length %d)", length); 279 if (p->pc_vendor == 0x8086) { 280 /* Intel */ 281 uint8_t version; 282 283 version = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_DATA, 284 1); 285 printf(" Intel cap %d version %d", version >> 4, version & 0xf); 286 if (version >> 4 == 1 && length == 12) { 287 /* Feature Detection */ 288 uint32_t fvec; 289 int comma; 290 291 comma = 0; 292 fvec = read_config(fd, &p->pc_sel, ptr + 293 PCIR_VENDOR_DATA + 5, 4); 294 printf("\n\t\t features:"); 295 if (fvec & (1 << 0)) { 296 printf(" AMT"); 297 comma = 1; 298 } 299 fvec = read_config(fd, &p->pc_sel, ptr + 300 PCIR_VENDOR_DATA + 1, 4); 301 if (fvec & (1 << 21)) { 302 printf("%s Quick Resume", comma ? "," : ""); 303 comma = 1; 304 } 305 if (fvec & (1 << 18)) { 306 printf("%s SATA RAID-5", comma ? "," : ""); 307 comma = 1; 308 } 309 if (fvec & (1 << 9)) { 310 printf("%s Mobile", comma ? "," : ""); 311 comma = 1; 312 } 313 if (fvec & (1 << 7)) { 314 printf("%s 6 PCI-e x1 slots", comma ? "," : ""); 315 comma = 1; 316 } else { 317 printf("%s 4 PCI-e x1 slots", comma ? "," : ""); 318 comma = 1; 319 } 320 if (fvec & (1 << 5)) { 321 printf("%s SATA RAID-0/1/10", comma ? "," : ""); 322 comma = 1; 323 } 324 if (fvec & (1 << 3)) { 325 printf("%s SATA AHCI", comma ? "," : ""); 326 comma = 1; 327 } 328 } 329 } 330 } 331 332 static void 333 cap_debug(int fd, struct pci_conf *p, uint8_t ptr) 334 { 335 uint16_t debug_port; 336 337 debug_port = read_config(fd, &p->pc_sel, ptr + PCIR_DEBUG_PORT, 2); 338 printf("EHCI Debug Port at offset 0x%x in map 0x%x", debug_port & 339 PCIM_DEBUG_PORT_OFFSET, PCIR_BAR(debug_port >> 13)); 340 } 341 342 static void 343 cap_subvendor(int fd, struct pci_conf *p, uint8_t ptr) 344 { 345 uint32_t id; 346 347 id = read_config(fd, &p->pc_sel, ptr + PCIR_SUBVENDCAP_ID, 4); 348 printf("PCI Bridge card=0x%08x", id); 349 } 350 351 static void 352 cap_express(int fd, struct pci_conf *p, uint8_t ptr) 353 { 354 uint16_t flags; 355 356 flags = read_config(fd, &p->pc_sel, ptr + PCIR_EXPRESS_FLAGS, 2); 357 printf("PCI-Express %d ", flags & PCIM_EXP_FLAGS_VERSION); 358 switch (flags & PCIM_EXP_FLAGS_TYPE) { 359 case PCIM_EXP_TYPE_ENDPOINT: 360 printf("endpoint"); 361 break; 362 case PCIM_EXP_TYPE_LEGACY_ENDPOINT: 363 printf("legacy endpoint"); 364 break; 365 case PCIM_EXP_TYPE_ROOT_PORT: 366 printf("root port"); 367 break; 368 case PCIM_EXP_TYPE_UPSTREAM_PORT: 369 printf("upstream port"); 370 break; 371 case PCIM_EXP_TYPE_DOWNSTREAM_PORT: 372 printf("downstream port"); 373 break; 374 case PCIM_EXP_TYPE_PCI_BRIDGE: 375 printf("PCI bridge"); 376 break; 377 default: 378 printf("type %d", (flags & PCIM_EXP_FLAGS_TYPE) >> 8); 379 break; 380 } 381 if (flags & PCIM_EXP_FLAGS_IRQ) 382 printf(" IRQ %d", (flags & PCIM_EXP_FLAGS_IRQ) >> 17); 383 } 384 385 static void 386 cap_msix(int fd, struct pci_conf *p, uint8_t ptr) 387 { 388 uint32_t val; 389 uint16_t ctrl; 390 int msgnum, table_bar, pba_bar; 391 392 ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_CTRL, 2); 393 msgnum = (ctrl & PCIM_MSIXCTRL_TABLE_SIZE) + 1; 394 val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_TABLE, 4); 395 table_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); 396 val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_PBA, 4); 397 pba_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); 398 printf("MSI-X supports %d message%s ", msgnum, 399 (msgnum == 1) ? "" : "s"); 400 if (table_bar == pba_bar) 401 printf("in map 0x%x", table_bar); 402 else 403 printf("in maps 0x%x and 0x%x", table_bar, pba_bar); 404 if (ctrl & PCIM_MSIXCTRL_MSIX_ENABLE) 405 printf(" enabled"); 406 } 407 408 void 409 list_caps(int fd, struct pci_conf *p) 410 { 411 uint16_t cmd; 412 uint8_t ptr, cap; 413 414 /* Are capabilities present for this device? */ 415 cmd = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); 416 if (!(cmd & PCIM_STATUS_CAPPRESENT)) 417 return; 418 419 switch (p->pc_hdr & PCIM_HDRTYPE) { 420 case 0: 421 case 1: 422 ptr = PCIR_CAP_PTR; 423 break; 424 case 2: 425 ptr = PCIR_CAP_PTR_2; 426 break; 427 default: 428 errx(1, "list_caps: bad header type"); 429 } 430 431 /* Walk the capability list. */ 432 ptr = read_config(fd, &p->pc_sel, ptr, 1); 433 while (ptr != 0 && ptr != 0xff) { 434 cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1); 435 printf(" cap %02x[%02x] = ", cap, ptr); 436 switch (cap) { 437 case PCIY_PMG: 438 cap_power(fd, p, ptr); 439 break; 440 case PCIY_AGP: 441 cap_agp(fd, p, ptr); 442 break; 443 case PCIY_VPD: 444 cap_vpd(fd, p, ptr); 445 break; 446 case PCIY_MSI: 447 cap_msi(fd, p, ptr); 448 break; 449 case PCIY_PCIX: 450 cap_pcix(fd, p, ptr); 451 break; 452 case PCIY_HT: 453 cap_ht(fd, p, ptr); 454 break; 455 case PCIY_VENDOR: 456 cap_vendor(fd, p, ptr); 457 break; 458 case PCIY_DEBUG: 459 cap_debug(fd, p, ptr); 460 break; 461 case PCIY_SUBVENDOR: 462 cap_subvendor(fd, p, ptr); 463 break; 464 case PCIY_EXPRESS: 465 cap_express(fd, p, ptr); 466 break; 467 case PCIY_MSIX: 468 cap_msix(fd, p, ptr); 469 break; 470 default: 471 printf("unknown"); 472 break; 473 } 474 printf("\n"); 475 ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1); 476 } 477 } 478