1 /* $OpenBSD: pci_subr.c,v 1.17 2004/11/21 17:01:39 grange 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 #endif
47
48 /*
49 * Descriptions of known PCI classes and subclasses.
50 *
51 * Subclasses are described in the same way as classes, but have a
52 * NULL subclass pointer.
53 */
54 struct pci_class {
55 const char *name;
56 int val; /* as wide as pci_{,sub}class_t */
57 const struct pci_class *subclasses;
58 };
59
60 const struct pci_class pci_subclass_prehistoric[] = {
61 { "miscellaneous", PCI_SUBCLASS_PREHISTORIC_MISC, },
62 { "VGA", PCI_SUBCLASS_PREHISTORIC_VGA, },
63 { 0 }
64 };
65
66 const struct pci_class pci_subclass_mass_storage[] = {
67 { "SCSI", PCI_SUBCLASS_MASS_STORAGE_SCSI, },
68 { "IDE", PCI_SUBCLASS_MASS_STORAGE_IDE, },
69 { "floppy", PCI_SUBCLASS_MASS_STORAGE_FLOPPY, },
70 { "IPI", PCI_SUBCLASS_MASS_STORAGE_IPI, },
71 { "RAID", PCI_SUBCLASS_MASS_STORAGE_RAID, },
72 { "ATA", PCI_SUBCLASS_MASS_STORAGE_ATA, },
73 { "SATA", PCI_SUBCLASS_MASS_STORAGE_SATA, },
74 { "miscellaneous", PCI_SUBCLASS_MASS_STORAGE_MISC, },
75 { 0 },
76 };
77
78 const struct pci_class pci_subclass_network[] = {
79 { "ethernet", PCI_SUBCLASS_NETWORK_ETHERNET, },
80 { "token ring", PCI_SUBCLASS_NETWORK_TOKENRING, },
81 { "FDDI", PCI_SUBCLASS_NETWORK_FDDI, },
82 { "ATM", PCI_SUBCLASS_NETWORK_ATM, },
83 { "ISDN", PCI_SUBCLASS_NETWORK_ISDN, },
84 { "WorldFip", PCI_SUBCLASS_NETWORK_WORLDFIP, },
85 { "PCMIG Multi Computing", PCI_SUBCLASS_NETWORK_PCIMGMULTICOMP, },
86 { "miscellaneous", PCI_SUBCLASS_NETWORK_MISC, },
87 { 0 },
88 };
89
90 const struct pci_class pci_subclass_display[] = {
91 { "VGA", PCI_SUBCLASS_DISPLAY_VGA, },
92 { "XGA", PCI_SUBCLASS_DISPLAY_XGA, },
93 { "3D", PCI_SUBCLASS_DISPLAY_3D, },
94 { "miscellaneous", PCI_SUBCLASS_DISPLAY_MISC, },
95 { 0 },
96 };
97
98 const struct pci_class pci_subclass_multimedia[] = {
99 { "video", PCI_SUBCLASS_MULTIMEDIA_VIDEO, },
100 { "audio", PCI_SUBCLASS_MULTIMEDIA_AUDIO, },
101 { "telephony", PCI_SUBCLASS_MULTIMEDIA_TELEPHONY, },
102 { "miscellaneous", PCI_SUBCLASS_MULTIMEDIA_MISC, },
103 { 0 },
104 };
105
106 const struct pci_class pci_subclass_memory[] = {
107 { "RAM", PCI_SUBCLASS_MEMORY_RAM, },
108 { "flash", PCI_SUBCLASS_MEMORY_FLASH, },
109 { "miscellaneous", PCI_SUBCLASS_MEMORY_MISC, },
110 { 0 },
111 };
112
113 const struct pci_class pci_subclass_bridge[] = {
114 { "host", PCI_SUBCLASS_BRIDGE_HOST, },
115 { "ISA", PCI_SUBCLASS_BRIDGE_ISA, },
116 { "EISA", PCI_SUBCLASS_BRIDGE_EISA, },
117 { "MicroChannel", PCI_SUBCLASS_BRIDGE_MC, },
118 { "PCI", PCI_SUBCLASS_BRIDGE_PCI, },
119 { "PCMCIA", PCI_SUBCLASS_BRIDGE_PCMCIA, },
120 { "NuBus", PCI_SUBCLASS_BRIDGE_NUBUS, },
121 { "CardBus", PCI_SUBCLASS_BRIDGE_CARDBUS, },
122 { "RACEway", PCI_SUBCLASS_BRIDGE_RACEWAY, },
123 { "Semi-transparent PCI", PCI_SUBCLASS_BRIDGE_STPCI, },
124 { "InfiniBand", PCI_SUBCLASS_BRIDGE_INFINIBAND, },
125 { "miscellaneous", PCI_SUBCLASS_BRIDGE_MISC, },
126 { 0 },
127 };
128
129 const struct pci_class pci_subclass_communications[] = {
130 { "serial", PCI_SUBCLASS_COMMUNICATIONS_SERIAL, },
131 { "parallel", PCI_SUBCLASS_COMMUNICATIONS_PARALLEL, },
132 { "multi-port serial", PCI_SUBCLASS_COMMUNICATIONS_MPSERIAL, },
133 { "modem", PCI_SUBCLASS_COMMUNICATIONS_MODEM, },
134 { "GPIB", PCI_SUBCLASS_COMMUNICATIONS_GPIB, },
135 { "smartcard", PCI_SUBCLASS_COMMUNICATIONS_SMARTCARD, },
136 { "miscellaneous", PCI_SUBCLASS_COMMUNICATIONS_MISC, },
137 { 0 },
138 };
139
140 const struct pci_class pci_subclass_system[] = {
141 { "interrupt", PCI_SUBCLASS_SYSTEM_PIC, },
142 { "8237 DMA", PCI_SUBCLASS_SYSTEM_DMA, },
143 { "8254 timer", PCI_SUBCLASS_SYSTEM_TIMER, },
144 { "RTC", PCI_SUBCLASS_SYSTEM_RTC, },
145 { "PCI Hot-Plug", PCI_SUBCLASS_SYSTEM_PCIHOTPLUG, },
146 { "SD Host Controller", PCI_SUBCLASS_SYSTEM_SDHC, },
147 { "miscellaneous", PCI_SUBCLASS_SYSTEM_MISC, },
148 { 0 },
149 };
150
151 const struct pci_class pci_subclass_input[] = {
152 { "keyboard", PCI_SUBCLASS_INPUT_KEYBOARD, },
153 { "digitizer", PCI_SUBCLASS_INPUT_DIGITIZER, },
154 { "mouse", PCI_SUBCLASS_INPUT_MOUSE, },
155 { "scanner", PCI_SUBCLASS_INPUT_SCANNER, },
156 { "game port", PCI_SUBCLASS_INPUT_GAMEPORT, },
157 { "miscellaneous", PCI_SUBCLASS_INPUT_MISC, },
158 { 0 },
159 };
160
161 const struct pci_class pci_subclass_dock[] = {
162 { "generic", PCI_SUBCLASS_DOCK_GENERIC, },
163 { "miscellaneous", PCI_SUBCLASS_DOCK_MISC, },
164 { 0 },
165 };
166
167 const struct pci_class pci_subclass_processor[] = {
168 { "386", PCI_SUBCLASS_PROCESSOR_386, },
169 { "486", PCI_SUBCLASS_PROCESSOR_486, },
170 { "Pentium", PCI_SUBCLASS_PROCESSOR_PENTIUM, },
171 { "Alpha", PCI_SUBCLASS_PROCESSOR_ALPHA, },
172 { "PowerPC", PCI_SUBCLASS_PROCESSOR_POWERPC, },
173 { "MIPS", PCI_SUBCLASS_PROCESSOR_MIPS, },
174 { "Co-processor", PCI_SUBCLASS_PROCESSOR_COPROC, },
175 { 0 },
176 };
177
178 const struct pci_class pci_subclass_serialbus[] = {
179 { "Firewire", PCI_SUBCLASS_SERIALBUS_FIREWIRE, },
180 { "ACCESS.bus", PCI_SUBCLASS_SERIALBUS_ACCESS, },
181 { "SSA", PCI_SUBCLASS_SERIALBUS_SSA, },
182 { "USB", PCI_SUBCLASS_SERIALBUS_USB, },
183 /* XXX Fiber Channel/_FIBRECHANNEL */
184 { "Fiber Channel", PCI_SUBCLASS_SERIALBUS_FIBER, },
185 { "SMBus", PCI_SUBCLASS_SERIALBUS_SMBUS, },
186 { "InfiniBand", PCI_SUBCLASS_SERIALBUS_INFINIBAND, },
187 { "IPMI", PCI_SUBCLASS_SERIALBUS_IPMI, },
188 { "SERCOS", PCI_SUBCLASS_SERIALBUS_SERCOS, },
189 { "CANbus", PCI_SUBCLASS_SERIALBUS_CANBUS, },
190 { 0 },
191 };
192
193 const struct pci_class pci_subclass_wireless[] = {
194 { "IrDA", PCI_SUBCLASS_WIRELESS_IRDA, },
195 { "Consumer IR", PCI_SUBCLASS_WIRELESS_CONSUMERIR, },
196 { "RF", PCI_SUBCLASS_WIRELESS_RF, },
197 { "bluetooth", PCI_SUBCLASS_WIRELESS_BLUETOOTH, },
198 { "broadband", PCI_SUBCLASS_WIRELESS_BROADBAND, },
199 { "802.11a (5 GHz)", PCI_SUBCLASS_WIRELESS_802_11A, },
200 { "802.11b (2.4 GHz)", PCI_SUBCLASS_WIRELESS_802_11B, },
201 { "miscellaneous", PCI_SUBCLASS_WIRELESS_MISC, },
202 { 0 },
203 };
204
205 const struct pci_class pci_subclass_i2o[] = {
206 { "standard", PCI_SUBCLASS_I2O_STANDARD, },
207 { 0 },
208 };
209
210 const struct pci_class pci_subclass_satcom[] = {
211 { "TV", PCI_SUBCLASS_SATCOM_TV, },
212 { "audio", PCI_SUBCLASS_SATCOM_AUDIO, },
213 { "voice", PCI_SUBCLASS_SATCOM_VOICE, },
214 { "data", PCI_SUBCLASS_SATCOM_DATA, },
215 { 0 },
216 };
217
218 const struct pci_class pci_subclass_crypto[] = {
219 { "network/computing", PCI_SUBCLASS_CRYPTO_NETCOMP, },
220 { "entertainment", PCI_SUBCLASS_CRYPTO_ENTERTAINMENT, },
221 { "miscellaneous", PCI_SUBCLASS_CRYPTO_MISC, },
222 { 0 },
223 };
224
225 const struct pci_class pci_subclass_dasp[] = {
226 { "DPIO", PCI_SUBCLASS_DASP_DPIO, },
227 { "Time and Frequency", PCI_SUBCLASS_DASP_TIMEFREQ, },
228 { "synchronization", PCI_SUBCLASS_DASP_SYNC, },
229 { "management", PCI_SUBCLASS_DASP_MGMT, },
230 { "miscellaneous", PCI_SUBCLASS_DASP_MISC, },
231 { 0 },
232 };
233
234 const struct pci_class pci_class[] = {
235 { "prehistoric", PCI_CLASS_PREHISTORIC,
236 pci_subclass_prehistoric, },
237 { "mass storage", PCI_CLASS_MASS_STORAGE,
238 pci_subclass_mass_storage, },
239 { "network", PCI_CLASS_NETWORK,
240 pci_subclass_network, },
241 { "display", PCI_CLASS_DISPLAY,
242 pci_subclass_display, },
243 { "multimedia", PCI_CLASS_MULTIMEDIA,
244 pci_subclass_multimedia, },
245 { "memory", PCI_CLASS_MEMORY,
246 pci_subclass_memory, },
247 { "bridge", PCI_CLASS_BRIDGE,
248 pci_subclass_bridge, },
249 { "communications", PCI_CLASS_COMMUNICATIONS,
250 pci_subclass_communications, },
251 { "system", PCI_CLASS_SYSTEM,
252 pci_subclass_system, },
253 { "input", PCI_CLASS_INPUT,
254 pci_subclass_input, },
255 { "dock", PCI_CLASS_DOCK,
256 pci_subclass_dock, },
257 { "processor", PCI_CLASS_PROCESSOR,
258 pci_subclass_processor, },
259 { "serial bus", PCI_CLASS_SERIALBUS,
260 pci_subclass_serialbus, },
261 { "wireless", PCI_CLASS_WIRELESS,
262 pci_subclass_wireless, },
263 { "I2O", PCI_CLASS_I2O,
264 pci_subclass_i2o, },
265 { "satellite comm", PCI_CLASS_SATCOM,
266 pci_subclass_satcom, },
267 { "crypto", PCI_CLASS_CRYPTO,
268 pci_subclass_crypto, },
269 { "DASP", PCI_CLASS_DASP,
270 pci_subclass_dasp, },
271 { "undefined", PCI_CLASS_UNDEFINED,
272 0, },
273 { 0 },
274 };
275
276 #ifdef PCIVERBOSE
277 /*
278 * Descriptions of known vendors and devices ("products").
279 */
280 struct pci_known_vendor {
281 pci_vendor_id_t vendor;
282 const char *vendorname;
283 };
284
285 struct pci_known_product {
286 pci_vendor_id_t vendor;
287 pci_product_id_t product;
288 const char *productname;
289 };
290
291 #include <dev/pci/pcidevs_data.h>
292 #endif /* PCIVERBOSE */
293
294 const char *
pci_findvendor(pcireg_t id_reg)295 pci_findvendor(pcireg_t id_reg)
296 {
297 #ifdef PCIVERBOSE
298 pci_vendor_id_t vendor = PCI_VENDOR(id_reg);
299 const struct pci_known_vendor *kdp;
300
301 kdp = pci_known_vendors;
302 while (kdp->vendorname != NULL) { /* all have vendor name */
303 if (kdp->vendor == vendor)
304 break;
305 kdp++;
306 }
307 return (kdp->vendorname);
308 #else
309 return (NULL);
310 #endif
311 }
312
313 void
pci_devinfo(pcireg_t id_reg,pcireg_t class_reg,int showclass,char * cp,size_t cp_max)314 pci_devinfo(pcireg_t id_reg, pcireg_t class_reg, int showclass, char *cp,
315 size_t cp_max)
316 {
317 pci_vendor_id_t vendor;
318 pci_product_id_t product;
319 pci_class_t class;
320 pci_subclass_t subclass;
321 pci_interface_t interface;
322 pci_revision_t revision;
323 const char *vendor_namep = NULL, *product_namep = NULL;
324 const struct pci_class *classp, *subclassp;
325 size_t cp_len = 0;
326 #ifdef PCIVERBOSE
327 const struct pci_known_vendor *pkv;
328 const struct pci_known_product *pkp;
329 const char *unmatched = "unknown ";
330 #else
331 const char *unmatched = "";
332 #endif
333
334 vendor = PCI_VENDOR(id_reg);
335 product = PCI_PRODUCT(id_reg);
336
337 class = PCI_CLASS(class_reg);
338 subclass = PCI_SUBCLASS(class_reg);
339 interface = PCI_INTERFACE(class_reg);
340 revision = PCI_REVISION(class_reg);
341
342 #ifdef PCIVERBOSE
343 pkv = pci_known_vendors;
344 while (pkv->vendorname != NULL) { /* all have vendor name */
345 if (pkv->vendor == vendor) {
346 vendor_namep = pkv->vendorname;
347 break;
348 }
349 pkv++;
350 }
351 if (vendor_namep) {
352 pkp = pci_known_products;
353 while (pkp->productname != NULL) { /* all have product name */
354 if (pkp->vendor == vendor && pkp->product == product) {
355 product_namep = pkp->productname;
356 break;
357 }
358 pkp++;
359 }
360 }
361 #endif /* PCIVERBOSE */
362
363 classp = pci_class;
364 while (classp->name != NULL) {
365 if (class == classp->val)
366 break;
367 classp++;
368 }
369
370 subclassp = (classp->name != NULL) ? classp->subclasses : NULL;
371 while (subclassp && subclassp->name != NULL) {
372 if (subclass == subclassp->val)
373 break;
374 subclassp++;
375 }
376
377 if (vendor_namep == NULL)
378 snprintf(cp, cp_max, "%svendor 0x%04x product 0x%04x",
379 unmatched, vendor, product);
380 else if (product_namep != NULL)
381 snprintf(cp, cp_max, "\"%s %s\"", vendor_namep, product_namep);
382 else
383 snprintf(cp, cp_max, "vendor \"%s\", unknown product 0x%04x",
384 vendor_namep, product);
385 if (showclass && product_namep == NULL) {
386 strlcat(cp, " (", cp_max);
387 cp_len = strlen(cp);
388 if (classp->name == NULL)
389 snprintf(cp + cp_len, cp_max - cp_len,
390 "unknown class 0x%02x, subclass 0x%02x",
391 class, subclass);
392 else if (subclassp == NULL || subclassp->name == NULL)
393 snprintf(cp + cp_len, cp_max - cp_len,
394 "class %s unknown subclass 0x%02x", classp->name,
395 subclass);
396 else
397 snprintf(cp + cp_len, cp_max - cp_len,
398 "class %s subclass %s", classp->name,
399 subclassp->name);
400 #if 0 /* not very useful */
401 cp_len = strlen(cp);
402 snprintf(cp + cp_len, cp_max - cp_len,
403 ", interface 0x%02x", interface);
404 #endif
405 cp_len = strlen(cp);
406 snprintf(cp + cp_len, cp_max - cp_len,
407 ", rev 0x%02x)", revision);
408 } else {
409 cp_len = strlen(cp);
410 snprintf(cp + cp_len, cp_max - cp_len, " rev 0x%02x",
411 revision);
412 }
413 }
414