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 *
pci_findvendor(pcireg_t id_reg)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 *
pci_findproduct(pcireg_t id_reg)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
pci_devinfo(pcireg_t id_reg,pcireg_t class_reg,int showclass,char * cp,size_t cp_max)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