1 /* $OpenBSD: pci_subr.c,v 1.22 2017/03/22 07:21:39 jsg Exp $ */ 2 /* $NetBSD: pci_subr.c,v 1.19 1996/10/13 01:38:29 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1995, 1996 Christopher G. Demetriou. All rights reserved. 6 * Copyright (c) 1994 Charles Hannum. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Charles Hannum. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * PCI autoconfiguration support functions. 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/device.h> 41 42 #include <dev/pci/pcireg.h> 43 #include <dev/pci/pcivar.h> 44 #ifdef PCIVERBOSE 45 #include <dev/pci/pcidevs.h> 46 #include <dev/pci/pcidevs_data.h> 47 #endif 48 49 /* 50 * Descriptions of known PCI classes and subclasses. 51 * 52 * Subclasses are described in the same way as classes, but have a 53 * NULL subclass pointer. 54 */ 55 struct pci_class { 56 const char *name; 57 int val; /* as wide as pci_{,sub}class_t */ 58 const struct pci_class *subclasses; 59 }; 60 61 const struct pci_class pci_subclass_prehistoric[] = { 62 { "miscellaneous", PCI_SUBCLASS_PREHISTORIC_MISC, }, 63 { "VGA", PCI_SUBCLASS_PREHISTORIC_VGA, }, 64 { 0 } 65 }; 66 67 const struct pci_class pci_subclass_mass_storage[] = { 68 { "SCSI", PCI_SUBCLASS_MASS_STORAGE_SCSI, }, 69 { "IDE", PCI_SUBCLASS_MASS_STORAGE_IDE, }, 70 { "floppy", PCI_SUBCLASS_MASS_STORAGE_FLOPPY, }, 71 { "IPI", PCI_SUBCLASS_MASS_STORAGE_IPI, }, 72 { "RAID", PCI_SUBCLASS_MASS_STORAGE_RAID, }, 73 { "ATA", PCI_SUBCLASS_MASS_STORAGE_ATA, }, 74 { "SATA", PCI_SUBCLASS_MASS_STORAGE_SATA, }, 75 { "SAS", PCI_SUBCLASS_MASS_STORAGE_SAS, }, 76 { "UFS", PCI_SUBCLASS_MASS_STORAGE_UFS, }, 77 { "miscellaneous", PCI_SUBCLASS_MASS_STORAGE_MISC, }, 78 { 0 }, 79 }; 80 81 const struct pci_class pci_subclass_network[] = { 82 { "ethernet", PCI_SUBCLASS_NETWORK_ETHERNET, }, 83 { "token ring", PCI_SUBCLASS_NETWORK_TOKENRING, }, 84 { "FDDI", PCI_SUBCLASS_NETWORK_FDDI, }, 85 { "ATM", PCI_SUBCLASS_NETWORK_ATM, }, 86 { "ISDN", PCI_SUBCLASS_NETWORK_ISDN, }, 87 { "WorldFip", PCI_SUBCLASS_NETWORK_WORLDFIP, }, 88 { "PCMIG Multi Computing", PCI_SUBCLASS_NETWORK_PCIMGMULTICOMP, }, 89 { "InfiniBand", PCI_SUBCLASS_NETWORK_INFINIBAND, }, 90 { "miscellaneous", PCI_SUBCLASS_NETWORK_MISC, }, 91 { 0 }, 92 }; 93 94 const struct pci_class pci_subclass_display[] = { 95 { "VGA", PCI_SUBCLASS_DISPLAY_VGA, }, 96 { "XGA", PCI_SUBCLASS_DISPLAY_XGA, }, 97 { "3D", PCI_SUBCLASS_DISPLAY_3D, }, 98 { "miscellaneous", PCI_SUBCLASS_DISPLAY_MISC, }, 99 { 0 }, 100 }; 101 102 const struct pci_class pci_subclass_multimedia[] = { 103 { "video", PCI_SUBCLASS_MULTIMEDIA_VIDEO, }, 104 { "audio", PCI_SUBCLASS_MULTIMEDIA_AUDIO, }, 105 { "telephony", PCI_SUBCLASS_MULTIMEDIA_TELEPHONY, }, 106 { "hdaudio", PCI_SUBCLASS_MULTIMEDIA_HDAUDIO, }, 107 { "miscellaneous", PCI_SUBCLASS_MULTIMEDIA_MISC, }, 108 { 0 }, 109 }; 110 111 const struct pci_class pci_subclass_memory[] = { 112 { "RAM", PCI_SUBCLASS_MEMORY_RAM, }, 113 { "flash", PCI_SUBCLASS_MEMORY_FLASH, }, 114 { "miscellaneous", PCI_SUBCLASS_MEMORY_MISC, }, 115 { 0 }, 116 }; 117 118 const struct pci_class pci_subclass_bridge[] = { 119 { "host", PCI_SUBCLASS_BRIDGE_HOST, }, 120 { "ISA", PCI_SUBCLASS_BRIDGE_ISA, }, 121 { "EISA", PCI_SUBCLASS_BRIDGE_EISA, }, 122 { "MicroChannel", PCI_SUBCLASS_BRIDGE_MC, }, 123 { "PCI", PCI_SUBCLASS_BRIDGE_PCI, }, 124 { "PCMCIA", PCI_SUBCLASS_BRIDGE_PCMCIA, }, 125 { "NuBus", PCI_SUBCLASS_BRIDGE_NUBUS, }, 126 { "CardBus", PCI_SUBCLASS_BRIDGE_CARDBUS, }, 127 { "RACEway", PCI_SUBCLASS_BRIDGE_RACEWAY, }, 128 { "Semi-transparent PCI", PCI_SUBCLASS_BRIDGE_STPCI, }, 129 { "InfiniBand", PCI_SUBCLASS_BRIDGE_INFINIBAND, }, 130 { "miscellaneous", PCI_SUBCLASS_BRIDGE_MISC, }, 131 { "advanced switching", PCI_SUBCLASS_BRIDGE_AS, }, 132 { 0 }, 133 }; 134 135 const struct pci_class pci_subclass_communications[] = { 136 { "serial", PCI_SUBCLASS_COMMUNICATIONS_SERIAL, }, 137 { "parallel", PCI_SUBCLASS_COMMUNICATIONS_PARALLEL, }, 138 { "multi-port serial", PCI_SUBCLASS_COMMUNICATIONS_MPSERIAL, }, 139 { "modem", PCI_SUBCLASS_COMMUNICATIONS_MODEM, }, 140 { "GPIB", PCI_SUBCLASS_COMMUNICATIONS_GPIB, }, 141 { "smartcard", PCI_SUBCLASS_COMMUNICATIONS_SMARTCARD, }, 142 { "miscellaneous", PCI_SUBCLASS_COMMUNICATIONS_MISC, }, 143 { 0 }, 144 }; 145 146 const struct pci_class pci_subclass_system[] = { 147 { "interrupt", PCI_SUBCLASS_SYSTEM_PIC, }, 148 { "8237 DMA", PCI_SUBCLASS_SYSTEM_DMA, }, 149 { "8254 timer", PCI_SUBCLASS_SYSTEM_TIMER, }, 150 { "RTC", PCI_SUBCLASS_SYSTEM_RTC, }, 151 { "PCI Hot-Plug", PCI_SUBCLASS_SYSTEM_PCIHOTPLUG, }, 152 { "SD Host Controller", PCI_SUBCLASS_SYSTEM_SDHC, }, 153 { "IOMMU", PCI_SUBCLASS_SYSTEM_IOMMU, }, 154 { "root complex event", PCI_SUBCLASS_SYSTEM_ROOTCOMPEVENT, }, 155 { "miscellaneous", PCI_SUBCLASS_SYSTEM_MISC, }, 156 { 0 }, 157 }; 158 159 const struct pci_class pci_subclass_input[] = { 160 { "keyboard", PCI_SUBCLASS_INPUT_KEYBOARD, }, 161 { "digitizer", PCI_SUBCLASS_INPUT_DIGITIZER, }, 162 { "mouse", PCI_SUBCLASS_INPUT_MOUSE, }, 163 { "scanner", PCI_SUBCLASS_INPUT_SCANNER, }, 164 { "game port", PCI_SUBCLASS_INPUT_GAMEPORT, }, 165 { "miscellaneous", PCI_SUBCLASS_INPUT_MISC, }, 166 { 0 }, 167 }; 168 169 const struct pci_class pci_subclass_dock[] = { 170 { "generic", PCI_SUBCLASS_DOCK_GENERIC, }, 171 { "miscellaneous", PCI_SUBCLASS_DOCK_MISC, }, 172 { 0 }, 173 }; 174 175 const struct pci_class pci_subclass_processor[] = { 176 { "386", PCI_SUBCLASS_PROCESSOR_386, }, 177 { "486", PCI_SUBCLASS_PROCESSOR_486, }, 178 { "Pentium", PCI_SUBCLASS_PROCESSOR_PENTIUM, }, 179 { "Alpha", PCI_SUBCLASS_PROCESSOR_ALPHA, }, 180 { "PowerPC", PCI_SUBCLASS_PROCESSOR_POWERPC, }, 181 { "MIPS", PCI_SUBCLASS_PROCESSOR_MIPS, }, 182 { "Co-processor", PCI_SUBCLASS_PROCESSOR_COPROC, }, 183 { 0 }, 184 }; 185 186 const struct pci_class pci_subclass_serialbus[] = { 187 { "Firewire", PCI_SUBCLASS_SERIALBUS_FIREWIRE, }, 188 { "ACCESS.bus", PCI_SUBCLASS_SERIALBUS_ACCESS, }, 189 { "SSA", PCI_SUBCLASS_SERIALBUS_SSA, }, 190 { "USB", PCI_SUBCLASS_SERIALBUS_USB, }, 191 /* XXX Fiber Channel/_FIBRECHANNEL */ 192 { "Fiber Channel", PCI_SUBCLASS_SERIALBUS_FIBER, }, 193 { "SMBus", PCI_SUBCLASS_SERIALBUS_SMBUS, }, 194 { "InfiniBand", PCI_SUBCLASS_SERIALBUS_INFINIBAND, }, 195 { "IPMI", PCI_SUBCLASS_SERIALBUS_IPMI, }, 196 { "SERCOS", PCI_SUBCLASS_SERIALBUS_SERCOS, }, 197 { "CANbus", PCI_SUBCLASS_SERIALBUS_CANBUS, }, 198 { 0 }, 199 }; 200 201 const struct pci_class pci_subclass_wireless[] = { 202 { "IrDA", PCI_SUBCLASS_WIRELESS_IRDA, }, 203 { "Consumer IR", PCI_SUBCLASS_WIRELESS_CONSUMERIR, }, 204 { "RF", PCI_SUBCLASS_WIRELESS_RF, }, 205 { "bluetooth", PCI_SUBCLASS_WIRELESS_BLUETOOTH, }, 206 { "broadband", PCI_SUBCLASS_WIRELESS_BROADBAND, }, 207 { "802.11a (5 GHz)", PCI_SUBCLASS_WIRELESS_802_11A, }, 208 { "802.11b (2.4 GHz)", PCI_SUBCLASS_WIRELESS_802_11B, }, 209 { "miscellaneous", PCI_SUBCLASS_WIRELESS_MISC, }, 210 { 0 }, 211 }; 212 213 const struct pci_class pci_subclass_i2o[] = { 214 { "standard", PCI_SUBCLASS_I2O_STANDARD, }, 215 { 0 }, 216 }; 217 218 const struct pci_class pci_subclass_satcom[] = { 219 { "TV", PCI_SUBCLASS_SATCOM_TV, }, 220 { "audio", PCI_SUBCLASS_SATCOM_AUDIO, }, 221 { "voice", PCI_SUBCLASS_SATCOM_VOICE, }, 222 { "data", PCI_SUBCLASS_SATCOM_DATA, }, 223 { 0 }, 224 }; 225 226 const struct pci_class pci_subclass_crypto[] = { 227 { "network/computing", PCI_SUBCLASS_CRYPTO_NETCOMP, }, 228 { "entertainment", PCI_SUBCLASS_CRYPTO_ENTERTAINMENT, }, 229 { "miscellaneous", PCI_SUBCLASS_CRYPTO_MISC, }, 230 { 0 }, 231 }; 232 233 const struct pci_class pci_subclass_dasp[] = { 234 { "DPIO", PCI_SUBCLASS_DASP_DPIO, }, 235 { "Time and Frequency", PCI_SUBCLASS_DASP_TIMEFREQ, }, 236 { "synchronization", PCI_SUBCLASS_DASP_SYNC, }, 237 { "management", PCI_SUBCLASS_DASP_MGMT, }, 238 { "miscellaneous", PCI_SUBCLASS_DASP_MISC, }, 239 { 0 }, 240 }; 241 242 const struct pci_class pci_class[] = { 243 { "prehistoric", PCI_CLASS_PREHISTORIC, 244 pci_subclass_prehistoric, }, 245 { "mass storage", PCI_CLASS_MASS_STORAGE, 246 pci_subclass_mass_storage, }, 247 { "network", PCI_CLASS_NETWORK, 248 pci_subclass_network, }, 249 { "display", PCI_CLASS_DISPLAY, 250 pci_subclass_display, }, 251 { "multimedia", PCI_CLASS_MULTIMEDIA, 252 pci_subclass_multimedia, }, 253 { "memory", PCI_CLASS_MEMORY, 254 pci_subclass_memory, }, 255 { "bridge", PCI_CLASS_BRIDGE, 256 pci_subclass_bridge, }, 257 { "communications", PCI_CLASS_COMMUNICATIONS, 258 pci_subclass_communications, }, 259 { "system", PCI_CLASS_SYSTEM, 260 pci_subclass_system, }, 261 { "input", PCI_CLASS_INPUT, 262 pci_subclass_input, }, 263 { "dock", PCI_CLASS_DOCK, 264 pci_subclass_dock, }, 265 { "processor", PCI_CLASS_PROCESSOR, 266 pci_subclass_processor, }, 267 { "serial bus", PCI_CLASS_SERIALBUS, 268 pci_subclass_serialbus, }, 269 { "wireless", PCI_CLASS_WIRELESS, 270 pci_subclass_wireless, }, 271 { "I2O", PCI_CLASS_I2O, 272 pci_subclass_i2o, }, 273 { "satellite comm", PCI_CLASS_SATCOM, 274 pci_subclass_satcom, }, 275 { "crypto", PCI_CLASS_CRYPTO, 276 pci_subclass_crypto, }, 277 { "DASP", PCI_CLASS_DASP, 278 pci_subclass_dasp, }, 279 { "accelerator", PCI_CLASS_ACCELERATOR, 280 NULL, }, 281 { "instrumentation", PCI_CLASS_INSTRUMENTATION, 282 NULL, }, 283 { "undefined", PCI_CLASS_UNDEFINED, 284 0, }, 285 { 0 }, 286 }; 287 288 const char * 289 pci_findvendor(pcireg_t id_reg) 290 { 291 #ifdef PCIVERBOSE 292 pci_vendor_id_t vendor = PCI_VENDOR(id_reg); 293 const struct pci_known_vendor *kdp; 294 295 kdp = pci_known_vendors; 296 while (kdp->vendorname != NULL) { /* all have vendor name */ 297 if (kdp->vendor == vendor) 298 break; 299 kdp++; 300 } 301 return (kdp->vendorname); 302 #else 303 return (NULL); 304 #endif 305 } 306 307 const char * 308 pci_findproduct(pcireg_t id_reg) 309 { 310 #ifdef PCIVERBOSE 311 pci_vendor_id_t vendor = PCI_VENDOR(id_reg); 312 pci_product_id_t product = PCI_PRODUCT(id_reg); 313 const struct pci_known_product *pkp; 314 315 pkp = pci_known_products; 316 while (pkp->productname != NULL) { /* all have product name */ 317 if (pkp->vendor == vendor && pkp->product == product) 318 break; 319 pkp++; 320 } 321 return (pkp->productname); 322 #else 323 return NULL; 324 #endif 325 } 326 327 void 328 pci_devinfo(pcireg_t id_reg, pcireg_t class_reg, int showclass, char *cp, 329 size_t cp_max) 330 { 331 pci_vendor_id_t vendor; 332 pci_product_id_t product; 333 pci_class_t class; 334 pci_subclass_t subclass; 335 pci_interface_t interface; 336 pci_revision_t revision; 337 const char *vendor_namep = NULL, *product_namep = NULL; 338 const struct pci_class *classp, *subclassp; 339 size_t cp_len = 0; 340 #ifdef PCIVERBOSE 341 const char *unmatched = "unknown "; 342 #else 343 const char *unmatched = ""; 344 #endif 345 346 vendor = PCI_VENDOR(id_reg); 347 product = PCI_PRODUCT(id_reg); 348 349 class = PCI_CLASS(class_reg); 350 subclass = PCI_SUBCLASS(class_reg); 351 interface = PCI_INTERFACE(class_reg); 352 revision = PCI_REVISION(class_reg); 353 354 #ifdef PCIVERBOSE 355 vendor_namep = pci_findvendor(id_reg); 356 if (vendor_namep != NULL) 357 product_namep = pci_findproduct(id_reg); 358 #endif /* PCIVERBOSE */ 359 360 classp = pci_class; 361 while (classp->name != NULL) { 362 if (class == classp->val) 363 break; 364 classp++; 365 } 366 367 subclassp = (classp->name != NULL) ? classp->subclasses : NULL; 368 while (subclassp && subclassp->name != NULL) { 369 if (subclass == subclassp->val) 370 break; 371 subclassp++; 372 } 373 374 if (vendor_namep == NULL) 375 snprintf(cp, cp_max, "%svendor 0x%04x product 0x%04x", 376 unmatched, vendor, product); 377 else if (product_namep != NULL) 378 snprintf(cp, cp_max, "\"%s %s\"", vendor_namep, product_namep); 379 else 380 snprintf(cp, cp_max, "vendor \"%s\", unknown product 0x%04x", 381 vendor_namep, product); 382 if (showclass && product_namep == NULL) { 383 strlcat(cp, " (", cp_max); 384 cp_len = strlen(cp); 385 if (classp->name == NULL) 386 snprintf(cp + cp_len, cp_max - cp_len, 387 "unknown class 0x%02x, subclass 0x%02x", 388 class, subclass); 389 else if (subclassp == NULL || subclassp->name == NULL) 390 snprintf(cp + cp_len, cp_max - cp_len, 391 "class %s unknown subclass 0x%02x", classp->name, 392 subclass); 393 else 394 snprintf(cp + cp_len, cp_max - cp_len, 395 "class %s subclass %s", classp->name, 396 subclassp->name); 397 #if 0 /* not very useful */ 398 cp_len = strlen(cp); 399 snprintf(cp + cp_len, cp_max - cp_len, 400 ", interface 0x%02x", interface); 401 #endif 402 cp_len = strlen(cp); 403 snprintf(cp + cp_len, cp_max - cp_len, 404 ", rev 0x%02x)", revision); 405 } else { 406 cp_len = strlen(cp); 407 snprintf(cp + cp_len, cp_max - cp_len, " rev 0x%02x", 408 revision); 409 } 410 } 411