cap.c revision 173059
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 31static const char rcsid[] = 32 "$FreeBSD: head/usr.sbin/pciconf/cap.c 173059 2007-10-27 13:16:25Z jhb $"; 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 47static void 48cap_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 61static void 62cap_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 115static void 116cap_vpd(int fd, struct pci_conf *p, uint8_t ptr) 117{ 118 119 printf("VPD"); 120} 121 122static void 123cap_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 141static void 142cap_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 213static void 214cap_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 %saddress window %s at 0x", 247 command & PCIM_HTCMD_MSI_FIXED ? "fixed " : "", 248 command & PCIM_HTCMD_MSI_ENABLE ? "enabled" : 249 "disabled"); 250 if (command & PCIM_HTCMD_MSI_FIXED) 251 printf("fee00000"); 252 else { 253 reg = read_config(fd, &p->pc_sel, 254 ptr + PCIR_HTMSI_ADDRESS_HI, 4); 255 if (reg != 0) 256 printf("%08x", reg); 257 reg = read_config(fd, &p->pc_sel, 258 ptr + PCIR_HTMSI_ADDRESS_LO, 4); 259 printf("%08x", reg); 260 } 261 break; 262 case PCIM_HTCAP_DIRECT_ROUTE: 263 printf("direct route"); 264 break; 265 case PCIM_HTCAP_VCSET: 266 printf("VC set"); 267 break; 268 case PCIM_HTCAP_RETRY_MODE: 269 printf("retry mode"); 270 break; 271 case PCIM_HTCAP_X86_ENCODING: 272 printf("X86 encoding"); 273 break; 274 default: 275 printf("unknown %02x", command); 276 break; 277 } 278} 279 280static void 281cap_vendor(int fd, struct pci_conf *p, uint8_t ptr) 282{ 283 uint8_t length; 284 285 length = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_LENGTH, 1); 286 printf("vendor (length %d)", length); 287 if (p->pc_vendor == 0x8086) { 288 /* Intel */ 289 uint8_t version; 290 291 version = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_DATA, 292 1); 293 printf(" Intel cap %d version %d", version >> 4, version & 0xf); 294 if (version >> 4 == 1 && length == 12) { 295 /* Feature Detection */ 296 uint32_t fvec; 297 int comma; 298 299 comma = 0; 300 fvec = read_config(fd, &p->pc_sel, ptr + 301 PCIR_VENDOR_DATA + 5, 4); 302 printf("\n\t\t features:"); 303 if (fvec & (1 << 0)) { 304 printf(" AMT"); 305 comma = 1; 306 } 307 fvec = read_config(fd, &p->pc_sel, ptr + 308 PCIR_VENDOR_DATA + 1, 4); 309 if (fvec & (1 << 21)) { 310 printf("%s Quick Resume", comma ? "," : ""); 311 comma = 1; 312 } 313 if (fvec & (1 << 18)) { 314 printf("%s SATA RAID-5", comma ? "," : ""); 315 comma = 1; 316 } 317 if (fvec & (1 << 9)) { 318 printf("%s Mobile", comma ? "," : ""); 319 comma = 1; 320 } 321 if (fvec & (1 << 7)) { 322 printf("%s 6 PCI-e x1 slots", comma ? "," : ""); 323 comma = 1; 324 } else { 325 printf("%s 4 PCI-e x1 slots", comma ? "," : ""); 326 comma = 1; 327 } 328 if (fvec & (1 << 5)) { 329 printf("%s SATA RAID-0/1/10", comma ? "," : ""); 330 comma = 1; 331 } 332 if (fvec & (1 << 3)) { 333 printf("%s SATA AHCI", comma ? "," : ""); 334 comma = 1; 335 } 336 } 337 } 338} 339 340static void 341cap_debug(int fd, struct pci_conf *p, uint8_t ptr) 342{ 343 uint16_t debug_port; 344 345 debug_port = read_config(fd, &p->pc_sel, ptr + PCIR_DEBUG_PORT, 2); 346 printf("EHCI Debug Port at offset 0x%x in map 0x%x", debug_port & 347 PCIM_DEBUG_PORT_OFFSET, PCIR_BAR(debug_port >> 13)); 348} 349 350static void 351cap_subvendor(int fd, struct pci_conf *p, uint8_t ptr) 352{ 353 uint32_t id; 354 355 id = read_config(fd, &p->pc_sel, ptr + PCIR_SUBVENDCAP_ID, 4); 356 printf("PCI Bridge card=0x%08x", id); 357} 358 359static void 360cap_express(int fd, struct pci_conf *p, uint8_t ptr) 361{ 362 uint16_t flags; 363 364 flags = read_config(fd, &p->pc_sel, ptr + PCIR_EXPRESS_FLAGS, 2); 365 printf("PCI-Express %d ", flags & PCIM_EXP_FLAGS_VERSION); 366 switch (flags & PCIM_EXP_FLAGS_TYPE) { 367 case PCIM_EXP_TYPE_ENDPOINT: 368 printf("endpoint"); 369 break; 370 case PCIM_EXP_TYPE_LEGACY_ENDPOINT: 371 printf("legacy endpoint"); 372 break; 373 case PCIM_EXP_TYPE_ROOT_PORT: 374 printf("root port"); 375 break; 376 case PCIM_EXP_TYPE_UPSTREAM_PORT: 377 printf("upstream port"); 378 break; 379 case PCIM_EXP_TYPE_DOWNSTREAM_PORT: 380 printf("downstream port"); 381 break; 382 case PCIM_EXP_TYPE_PCI_BRIDGE: 383 printf("PCI bridge"); 384 break; 385 default: 386 printf("type %d", (flags & PCIM_EXP_FLAGS_TYPE) >> 8); 387 break; 388 } 389 if (flags & PCIM_EXP_FLAGS_IRQ) 390 printf(" IRQ %d", (flags & PCIM_EXP_FLAGS_IRQ) >> 17); 391} 392 393static void 394cap_msix(int fd, struct pci_conf *p, uint8_t ptr) 395{ 396 uint32_t val; 397 uint16_t ctrl; 398 int msgnum, table_bar, pba_bar; 399 400 ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_CTRL, 2); 401 msgnum = (ctrl & PCIM_MSIXCTRL_TABLE_SIZE) + 1; 402 val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_TABLE, 4); 403 table_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); 404 val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_PBA, 4); 405 pba_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); 406 printf("MSI-X supports %d message%s ", msgnum, 407 (msgnum == 1) ? "" : "s"); 408 if (table_bar == pba_bar) 409 printf("in map 0x%x", table_bar); 410 else 411 printf("in maps 0x%x and 0x%x", table_bar, pba_bar); 412 if (ctrl & PCIM_MSIXCTRL_MSIX_ENABLE) 413 printf(" enabled"); 414} 415 416void 417list_caps(int fd, struct pci_conf *p) 418{ 419 uint16_t cmd; 420 uint8_t ptr, cap; 421 422 /* Are capabilities present for this device? */ 423 cmd = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); 424 if (!(cmd & PCIM_STATUS_CAPPRESENT)) 425 return; 426 427 switch (p->pc_hdr & PCIM_HDRTYPE) { 428 case 0: 429 case 1: 430 ptr = PCIR_CAP_PTR; 431 break; 432 case 2: 433 ptr = PCIR_CAP_PTR_2; 434 break; 435 default: 436 errx(1, "list_caps: bad header type"); 437 } 438 439 /* Walk the capability list. */ 440 ptr = read_config(fd, &p->pc_sel, ptr, 1); 441 while (ptr != 0 && ptr != 0xff) { 442 cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1); 443 printf(" cap %02x[%02x] = ", cap, ptr); 444 switch (cap) { 445 case PCIY_PMG: 446 cap_power(fd, p, ptr); 447 break; 448 case PCIY_AGP: 449 cap_agp(fd, p, ptr); 450 break; 451 case PCIY_VPD: 452 cap_vpd(fd, p, ptr); 453 break; 454 case PCIY_MSI: 455 cap_msi(fd, p, ptr); 456 break; 457 case PCIY_PCIX: 458 cap_pcix(fd, p, ptr); 459 break; 460 case PCIY_HT: 461 cap_ht(fd, p, ptr); 462 break; 463 case PCIY_VENDOR: 464 cap_vendor(fd, p, ptr); 465 break; 466 case PCIY_DEBUG: 467 cap_debug(fd, p, ptr); 468 break; 469 case PCIY_SUBVENDOR: 470 cap_subvendor(fd, p, ptr); 471 break; 472 case PCIY_EXPRESS: 473 cap_express(fd, p, ptr); 474 break; 475 case PCIY_MSIX: 476 cap_msix(fd, p, ptr); 477 break; 478 default: 479 printf("unknown"); 480 break; 481 } 482 printf("\n"); 483 ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1); 484 } 485} 486