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