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