xref: /freebsd/sys/dev/pci/pci_user.c (revision 727de621c5f07681034eed2d6ce3662a8239e987)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright 1997, Stefan Esser <se@freebsd.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice unmodified, this list of conditions, and the following
11  *    disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 #include "opt_bus.h"	/* XXX trim includes */
30 
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/malloc.h>
35 #include <sys/module.h>
36 #include <sys/linker.h>
37 #include <sys/fcntl.h>
38 #include <sys/conf.h>
39 #include <sys/kernel.h>
40 #include <sys/mman.h>
41 #include <sys/proc.h>
42 #include <sys/queue.h>
43 #include <sys/rwlock.h>
44 #include <sys/sglist.h>
45 
46 #include <vm/vm.h>
47 #include <vm/pmap.h>
48 #include <vm/vm_extern.h>
49 #include <vm/vm_map.h>
50 #include <vm/vm_object.h>
51 #include <vm/vm_page.h>
52 #include <vm/vm_pager.h>
53 
54 #include <sys/bus.h>
55 #include <machine/bus.h>
56 #include <sys/rman.h>
57 #include <machine/resource.h>
58 
59 #include <sys/pciio.h>
60 #include <dev/pci/pcireg.h>
61 #include <dev/pci/pcivar.h>
62 
63 #include "pcib_if.h"
64 #include "pci_if.h"
65 
66 #ifdef COMPAT_FREEBSD32
67 struct pci_conf32 {
68 	struct pcisel	pc_sel;		/* domain+bus+slot+function */
69 	u_int8_t	pc_hdr;		/* PCI header type */
70 	u_int16_t	pc_subvendor;	/* card vendor ID */
71 	u_int16_t	pc_subdevice;	/* card device ID, assigned by
72 					   card vendor */
73 	u_int16_t	pc_vendor;	/* chip vendor ID */
74 	u_int16_t	pc_device;	/* chip device ID, assigned by
75 					   chip vendor */
76 	u_int8_t	pc_class;	/* chip PCI class */
77 	u_int8_t	pc_subclass;	/* chip PCI subclass */
78 	u_int8_t	pc_progif;	/* chip PCI programming interface */
79 	u_int8_t	pc_revid;	/* chip revision ID */
80 	char		pd_name[PCI_MAXNAMELEN + 1];  /* device name */
81 	u_int32_t	pd_unit;	/* device unit number */
82 };
83 
84 struct pci_match_conf32 {
85 	struct pcisel		pc_sel;		/* domain+bus+slot+function */
86 	char			pd_name[PCI_MAXNAMELEN + 1];  /* device name */
87 	u_int32_t		pd_unit;	/* Unit number */
88 	u_int16_t		pc_vendor;	/* PCI Vendor ID */
89 	u_int16_t		pc_device;	/* PCI Device ID */
90 	u_int8_t		pc_class;	/* PCI class */
91 	u_int32_t		flags;		/* Matching expression */
92 };
93 
94 struct pci_conf_io32 {
95 	u_int32_t		pat_buf_len;	/* pattern buffer length */
96 	u_int32_t		num_patterns;	/* number of patterns */
97 	u_int32_t		patterns;	/* struct pci_match_conf ptr */
98 	u_int32_t		match_buf_len;	/* match buffer length */
99 	u_int32_t		num_matches;	/* number of matches returned */
100 	u_int32_t		matches;	/* struct pci_conf ptr */
101 	u_int32_t		offset;		/* offset into device list */
102 	u_int32_t		generation;	/* device list generation */
103 	u_int32_t		status;		/* request status */
104 };
105 
106 #define	PCIOCGETCONF32	_IOC_NEWTYPE(PCIOCGETCONF, struct pci_conf_io32)
107 #endif
108 
109 /*
110  * This is the user interface to PCI configuration space.
111  */
112 
113 static d_open_t 	pci_open;
114 static d_close_t	pci_close;
115 static d_ioctl_t	pci_ioctl;
116 
117 struct cdevsw pcicdev = {
118 	.d_version =	D_VERSION,
119 	.d_flags =	0,
120 	.d_open =	pci_open,
121 	.d_close =	pci_close,
122 	.d_ioctl =	pci_ioctl,
123 	.d_name =	"pci",
124 };
125 
126 static int
pci_open(struct cdev * dev,int oflags,int devtype,struct thread * td)127 pci_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
128 {
129 	int error;
130 
131 	if (oflags & FWRITE) {
132 		error = securelevel_gt(td->td_ucred, 0);
133 		if (error)
134 			return (error);
135 	}
136 
137 	return (0);
138 }
139 
140 static int
pci_close(struct cdev * dev,int flag,int devtype,struct thread * td)141 pci_close(struct cdev *dev, int flag, int devtype, struct thread *td)
142 {
143 	return 0;
144 }
145 
146 /*
147  * Match a single pci_conf structure against an array of pci_match_conf
148  * structures.  The first argument, 'matches', is an array of num_matches
149  * pci_match_conf structures.  match_buf is a pointer to the pci_conf
150  * structure that will be compared to every entry in the matches array.
151  * This function returns 1 on failure, 0 on success.
152  */
153 static int
pci_conf_match_native(struct pci_match_conf * matches,int num_matches,struct pci_conf * match_buf)154 pci_conf_match_native(struct pci_match_conf *matches, int num_matches,
155 	       struct pci_conf *match_buf)
156 {
157 	int i;
158 
159 	if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
160 		return(1);
161 
162 	for (i = 0; i < num_matches; i++) {
163 		/*
164 		 * I'm not sure why someone would do this...but...
165 		 */
166 		if (matches[i].flags == PCI_GETCONF_NO_MATCH)
167 			continue;
168 
169 		/*
170 		 * Look at each of the match flags.  If it's set, do the
171 		 * comparison.  If the comparison fails, we don't have a
172 		 * match, go on to the next item if there is one.
173 		 */
174 		if (((matches[i].flags & PCI_GETCONF_MATCH_DOMAIN) != 0)
175 		 && (match_buf->pc_sel.pc_domain !=
176 		 matches[i].pc_sel.pc_domain))
177 			continue;
178 
179 		if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0)
180 		 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
181 			continue;
182 
183 		if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0)
184 		 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
185 			continue;
186 
187 		if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0)
188 		 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
189 			continue;
190 
191 		if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0)
192 		 && (match_buf->pc_vendor != matches[i].pc_vendor))
193 			continue;
194 
195 		if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0)
196 		 && (match_buf->pc_device != matches[i].pc_device))
197 			continue;
198 
199 		if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0)
200 		 && (match_buf->pc_class != matches[i].pc_class))
201 			continue;
202 
203 		if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0)
204 		 && (match_buf->pd_unit != matches[i].pd_unit))
205 			continue;
206 
207 		if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0)
208 		 && (strncmp(matches[i].pd_name, match_buf->pd_name,
209 			     sizeof(match_buf->pd_name)) != 0))
210 			continue;
211 
212 		return(0);
213 	}
214 
215 	return(1);
216 }
217 
218 #ifdef COMPAT_FREEBSD32
219 static int
pci_conf_match32(struct pci_match_conf32 * matches,int num_matches,struct pci_conf * match_buf)220 pci_conf_match32(struct pci_match_conf32 *matches, int num_matches,
221 	       struct pci_conf *match_buf)
222 {
223 	int i;
224 
225 	if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
226 		return(1);
227 
228 	for (i = 0; i < num_matches; i++) {
229 		/*
230 		 * I'm not sure why someone would do this...but...
231 		 */
232 		if (matches[i].flags == PCI_GETCONF_NO_MATCH)
233 			continue;
234 
235 		/*
236 		 * Look at each of the match flags.  If it's set, do the
237 		 * comparison.  If the comparison fails, we don't have a
238 		 * match, go on to the next item if there is one.
239 		 */
240 		if (((matches[i].flags & PCI_GETCONF_MATCH_DOMAIN) != 0)
241 		 && (match_buf->pc_sel.pc_domain !=
242 		 matches[i].pc_sel.pc_domain))
243 			continue;
244 
245 		if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0)
246 		 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
247 			continue;
248 
249 		if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0)
250 		 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
251 			continue;
252 
253 		if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0)
254 		 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
255 			continue;
256 
257 		if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0)
258 		 && (match_buf->pc_vendor != matches[i].pc_vendor))
259 			continue;
260 
261 		if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0)
262 		 && (match_buf->pc_device != matches[i].pc_device))
263 			continue;
264 
265 		if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0)
266 		 && (match_buf->pc_class != matches[i].pc_class))
267 			continue;
268 
269 		if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0)
270 		 && (match_buf->pd_unit != matches[i].pd_unit))
271 			continue;
272 
273 		if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0)
274 		 && (strncmp(matches[i].pd_name, match_buf->pd_name,
275 			     sizeof(match_buf->pd_name)) != 0))
276 			continue;
277 
278 		return(0);
279 	}
280 
281 	return(1);
282 }
283 #endif	/* COMPAT_FREEBSD32 */
284 
285 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
286     defined(COMPAT_FREEBSD6)
287 #define PRE7_COMPAT
288 
289 typedef enum {
290 	PCI_GETCONF_NO_MATCH_FREEBSD6	= 0x00,
291 	PCI_GETCONF_MATCH_BUS_FREEBSD6	= 0x01,
292 	PCI_GETCONF_MATCH_DEV_FREEBSD6	= 0x02,
293 	PCI_GETCONF_MATCH_FUNC_FREEBSD6	= 0x04,
294 	PCI_GETCONF_MATCH_NAME_FREEBSD6	= 0x08,
295 	PCI_GETCONF_MATCH_UNIT_FREEBSD6	= 0x10,
296 	PCI_GETCONF_MATCH_VENDOR_FREEBSD6 = 0x20,
297 	PCI_GETCONF_MATCH_DEVICE_FREEBSD6 = 0x40,
298 	PCI_GETCONF_MATCH_CLASS_FREEBSD6 = 0x80
299 } pci_getconf_flags_freebsd6;
300 
301 struct pcisel_freebsd6 {
302 	u_int8_t	pc_bus;		/* bus number */
303 	u_int8_t	pc_dev;		/* device on this bus */
304 	u_int8_t	pc_func;	/* function on this device */
305 };
306 
307 struct pci_conf_freebsd6 {
308 	struct pcisel_freebsd6 pc_sel;	/* bus+slot+function */
309 	u_int8_t	pc_hdr;		/* PCI header type */
310 	u_int16_t	pc_subvendor;	/* card vendor ID */
311 	u_int16_t	pc_subdevice;	/* card device ID, assigned by
312 					   card vendor */
313 	u_int16_t	pc_vendor;	/* chip vendor ID */
314 	u_int16_t	pc_device;	/* chip device ID, assigned by
315 					   chip vendor */
316 	u_int8_t	pc_class;	/* chip PCI class */
317 	u_int8_t	pc_subclass;	/* chip PCI subclass */
318 	u_int8_t	pc_progif;	/* chip PCI programming interface */
319 	u_int8_t	pc_revid;	/* chip revision ID */
320 	char		pd_name[PCI_MAXNAMELEN + 1];  /* device name */
321 	u_long		pd_unit;	/* device unit number */
322 };
323 
324 struct pci_match_conf_freebsd6 {
325 	struct pcisel_freebsd6	pc_sel;		/* bus+slot+function */
326 	char			pd_name[PCI_MAXNAMELEN + 1];  /* device name */
327 	u_long			pd_unit;	/* Unit number */
328 	u_int16_t		pc_vendor;	/* PCI Vendor ID */
329 	u_int16_t		pc_device;	/* PCI Device ID */
330 	u_int8_t		pc_class;	/* PCI class */
331 	pci_getconf_flags_freebsd6 flags;	/* Matching expression */
332 };
333 
334 struct pci_io_freebsd6 {
335 	struct pcisel_freebsd6 pi_sel;	/* device to operate on */
336 	int		pi_reg;		/* configuration register to examine */
337 	int		pi_width;	/* width (in bytes) of read or write */
338 	u_int32_t	pi_data;	/* data to write or result of read */
339 };
340 
341 #ifdef COMPAT_FREEBSD32
342 struct pci_conf_freebsd6_32 {
343 	struct pcisel_freebsd6 pc_sel;	/* bus+slot+function */
344 	uint8_t		pc_hdr;		/* PCI header type */
345 	uint16_t	pc_subvendor;	/* card vendor ID */
346 	uint16_t	pc_subdevice;	/* card device ID, assigned by
347 					   card vendor */
348 	uint16_t	pc_vendor;	/* chip vendor ID */
349 	uint16_t	pc_device;	/* chip device ID, assigned by
350 					   chip vendor */
351 	uint8_t		pc_class;	/* chip PCI class */
352 	uint8_t		pc_subclass;	/* chip PCI subclass */
353 	uint8_t		pc_progif;	/* chip PCI programming interface */
354 	uint8_t		pc_revid;	/* chip revision ID */
355 	char		pd_name[PCI_MAXNAMELEN + 1]; /* device name */
356 	uint32_t	pd_unit;	/* device unit number (u_long) */
357 };
358 
359 struct pci_match_conf_freebsd6_32 {
360 	struct pcisel_freebsd6 pc_sel;	/* bus+slot+function */
361 	char		pd_name[PCI_MAXNAMELEN + 1]; /* device name */
362 	uint32_t	pd_unit;	/* Unit number (u_long) */
363 	uint16_t	pc_vendor;	/* PCI Vendor ID */
364 	uint16_t	pc_device;	/* PCI Device ID */
365 	uint8_t		pc_class;	/* PCI class */
366 	pci_getconf_flags_freebsd6 flags; /* Matching expression */
367 };
368 
369 #define	PCIOCGETCONF_FREEBSD6_32	_IOWR('p', 1, struct pci_conf_io32)
370 #endif	/* COMPAT_FREEBSD32 */
371 
372 #define	PCIOCGETCONF_FREEBSD6	_IOWR('p', 1, struct pci_conf_io)
373 #define	PCIOCREAD_FREEBSD6	_IOWR('p', 2, struct pci_io_freebsd6)
374 #define	PCIOCWRITE_FREEBSD6	_IOWR('p', 3, struct pci_io_freebsd6)
375 
376 static int
pci_conf_match_freebsd6(struct pci_match_conf_freebsd6 * matches,int num_matches,struct pci_conf * match_buf)377 pci_conf_match_freebsd6(struct pci_match_conf_freebsd6 *matches, int num_matches,
378     struct pci_conf *match_buf)
379 {
380 	int i;
381 
382 	if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
383 		return(1);
384 
385 	for (i = 0; i < num_matches; i++) {
386 		if (match_buf->pc_sel.pc_domain != 0)
387 			continue;
388 
389 		/*
390 		 * I'm not sure why someone would do this...but...
391 		 */
392 		if (matches[i].flags == PCI_GETCONF_NO_MATCH_FREEBSD6)
393 			continue;
394 
395 		/*
396 		 * Look at each of the match flags.  If it's set, do the
397 		 * comparison.  If the comparison fails, we don't have a
398 		 * match, go on to the next item if there is one.
399 		 */
400 		if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_FREEBSD6) != 0)
401 		 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
402 			continue;
403 
404 		if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_FREEBSD6) != 0)
405 		 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
406 			continue;
407 
408 		if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_FREEBSD6) != 0)
409 		 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
410 			continue;
411 
412 		if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_FREEBSD6) != 0)
413 		 && (match_buf->pc_vendor != matches[i].pc_vendor))
414 			continue;
415 
416 		if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_FREEBSD6) != 0)
417 		 && (match_buf->pc_device != matches[i].pc_device))
418 			continue;
419 
420 		if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_FREEBSD6) != 0)
421 		 && (match_buf->pc_class != matches[i].pc_class))
422 			continue;
423 
424 		if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_FREEBSD6) != 0)
425 		 && (match_buf->pd_unit != matches[i].pd_unit))
426 			continue;
427 
428 		if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_FREEBSD6) != 0)
429 		 && (strncmp(matches[i].pd_name, match_buf->pd_name,
430 			     sizeof(match_buf->pd_name)) != 0))
431 			continue;
432 
433 		return(0);
434 	}
435 
436 	return(1);
437 }
438 
439 #ifdef COMPAT_FREEBSD32
440 static int
pci_conf_match_freebsd6_32(struct pci_match_conf_freebsd6_32 * matches,int num_matches,struct pci_conf * match_buf)441 pci_conf_match_freebsd6_32(struct pci_match_conf_freebsd6_32 *matches, int num_matches,
442     struct pci_conf *match_buf)
443 {
444 	int i;
445 
446 	if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
447 		return(1);
448 
449 	for (i = 0; i < num_matches; i++) {
450 		if (match_buf->pc_sel.pc_domain != 0)
451 			continue;
452 
453 		/*
454 		 * I'm not sure why someone would do this...but...
455 		 */
456 		if (matches[i].flags == PCI_GETCONF_NO_MATCH_FREEBSD6)
457 			continue;
458 
459 		/*
460 		 * Look at each of the match flags.  If it's set, do the
461 		 * comparison.  If the comparison fails, we don't have a
462 		 * match, go on to the next item if there is one.
463 		 */
464 		if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_FREEBSD6) != 0) &&
465 		    (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
466 			continue;
467 
468 		if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_FREEBSD6) != 0) &&
469 		    (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
470 			continue;
471 
472 		if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_FREEBSD6) != 0) &&
473 		    (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
474 			continue;
475 
476 		if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_FREEBSD6) != 0) &&
477 		    (match_buf->pc_vendor != matches[i].pc_vendor))
478 			continue;
479 
480 		if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_FREEBSD6) != 0) &&
481 		    (match_buf->pc_device != matches[i].pc_device))
482 			continue;
483 
484 		if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_FREEBSD6) != 0) &&
485 		    (match_buf->pc_class != matches[i].pc_class))
486 			continue;
487 
488 		if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_FREEBSD6) != 0) &&
489 		    ((u_int32_t)match_buf->pd_unit != matches[i].pd_unit))
490 			continue;
491 
492 		if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_FREEBSD6) != 0) &&
493 		    (strncmp(matches[i].pd_name, match_buf->pd_name,
494 		    sizeof(match_buf->pd_name)) != 0))
495 			continue;
496 
497 		return (0);
498 	}
499 
500 	return (1);
501 }
502 #endif	/* COMPAT_FREEBSD32 */
503 #endif	/* !PRE7_COMPAT */
504 
505 union pci_conf_union {
506 	struct pci_conf			pc;
507 #ifdef COMPAT_FREEBSD32
508 	struct pci_conf32		pc32;
509 #endif
510 #ifdef PRE7_COMPAT
511 	struct pci_conf_freebsd6	pco;
512 #ifdef COMPAT_FREEBSD32
513 	struct pci_conf_freebsd6_32	pco32;
514 #endif
515 #endif
516 };
517 
518 static int
pci_conf_match(u_long cmd,struct pci_match_conf * matches,int num_matches,struct pci_conf * match_buf)519 pci_conf_match(u_long cmd, struct pci_match_conf *matches, int num_matches,
520     struct pci_conf *match_buf)
521 {
522 
523 	switch (cmd) {
524 	case PCIOCGETCONF:
525 		return (pci_conf_match_native(
526 		    (struct pci_match_conf *)matches, num_matches, match_buf));
527 #ifdef COMPAT_FREEBSD32
528 	case PCIOCGETCONF32:
529 		return (pci_conf_match32((struct pci_match_conf32 *)matches,
530 		    num_matches, match_buf));
531 #endif
532 #ifdef PRE7_COMPAT
533 	case PCIOCGETCONF_FREEBSD6:
534 		return (pci_conf_match_freebsd6(
535 		    (struct pci_match_conf_freebsd6 *)matches, num_matches,
536 		    match_buf));
537 #ifdef COMPAT_FREEBSD32
538 	case PCIOCGETCONF_FREEBSD6_32:
539 		return (pci_conf_match_freebsd6_32(
540 		    (struct pci_match_conf_freebsd6_32 *)matches, num_matches,
541 		    match_buf));
542 #endif
543 #endif
544 	default:
545 		/* programmer error */
546 		return (0);
547 	}
548 }
549 
550 /*
551  * Like PVE_NEXT but takes an explicit length since 'pve' is a user
552  * pointer that cannot be dereferenced.
553  */
554 #define	PVE_NEXT_LEN(pve, datalen)					\
555 	((struct pci_vpd_element *)((char *)(pve) +			\
556 	    sizeof(struct pci_vpd_element) + (datalen)))
557 
558 static int
pci_list_vpd(device_t dev,struct pci_list_vpd_io * lvio)559 pci_list_vpd(device_t dev, struct pci_list_vpd_io *lvio)
560 {
561 	struct pci_vpd_element vpd_element, *vpd_user;
562 	struct pcicfg_vpd *vpd;
563 	size_t len, datalen;
564 	int error, i;
565 
566 	vpd = pci_fetch_vpd_list(dev);
567 	if (vpd->vpd_reg == 0 || vpd->vpd_ident == NULL)
568 		return (ENXIO);
569 
570 	/*
571 	 * Calculate the amount of space needed in the data buffer.  An
572 	 * identifier element is always present followed by the read-only
573 	 * and read-write keywords.
574 	 */
575 	len = sizeof(struct pci_vpd_element) + strlen(vpd->vpd_ident);
576 	for (i = 0; i < vpd->vpd_rocnt; i++)
577 		len += sizeof(struct pci_vpd_element) + vpd->vpd_ros[i].len;
578 	for (i = 0; i < vpd->vpd_wcnt; i++)
579 		len += sizeof(struct pci_vpd_element) + vpd->vpd_w[i].len;
580 
581 	if (lvio->plvi_len == 0) {
582 		lvio->plvi_len = len;
583 		return (0);
584 	}
585 	if (lvio->plvi_len < len) {
586 		lvio->plvi_len = len;
587 		return (ENOMEM);
588 	}
589 
590 	/*
591 	 * Copyout the identifier string followed by each keyword and
592 	 * value.
593 	 */
594 	datalen = strlen(vpd->vpd_ident);
595 	KASSERT(datalen <= 255, ("invalid VPD ident length"));
596 	vpd_user = lvio->plvi_data;
597 	vpd_element.pve_keyword[0] = '\0';
598 	vpd_element.pve_keyword[1] = '\0';
599 	vpd_element.pve_flags = PVE_FLAG_IDENT;
600 	vpd_element.pve_datalen = datalen;
601 	error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
602 	if (error)
603 		return (error);
604 	error = copyout(vpd->vpd_ident, vpd_user->pve_data, datalen);
605 	if (error)
606 		return (error);
607 	vpd_user = PVE_NEXT_LEN(vpd_user, vpd_element.pve_datalen);
608 	vpd_element.pve_flags = 0;
609 	for (i = 0; i < vpd->vpd_rocnt; i++) {
610 		vpd_element.pve_keyword[0] = vpd->vpd_ros[i].keyword[0];
611 		vpd_element.pve_keyword[1] = vpd->vpd_ros[i].keyword[1];
612 		vpd_element.pve_datalen = vpd->vpd_ros[i].len;
613 		error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
614 		if (error)
615 			return (error);
616 		error = copyout(vpd->vpd_ros[i].value, vpd_user->pve_data,
617 		    vpd->vpd_ros[i].len);
618 		if (error)
619 			return (error);
620 		vpd_user = PVE_NEXT_LEN(vpd_user, vpd_element.pve_datalen);
621 	}
622 	vpd_element.pve_flags = PVE_FLAG_RW;
623 	for (i = 0; i < vpd->vpd_wcnt; i++) {
624 		vpd_element.pve_keyword[0] = vpd->vpd_w[i].keyword[0];
625 		vpd_element.pve_keyword[1] = vpd->vpd_w[i].keyword[1];
626 		vpd_element.pve_datalen = vpd->vpd_w[i].len;
627 		error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
628 		if (error)
629 			return (error);
630 		error = copyout(vpd->vpd_w[i].value, vpd_user->pve_data,
631 		    vpd->vpd_w[i].len);
632 		if (error)
633 			return (error);
634 		vpd_user = PVE_NEXT_LEN(vpd_user, vpd_element.pve_datalen);
635 	}
636 	KASSERT((char *)vpd_user - (char *)lvio->plvi_data == len,
637 	    ("length mismatch"));
638 	lvio->plvi_len = len;
639 	return (0);
640 }
641 
642 static size_t
pci_match_conf_size(u_long cmd)643 pci_match_conf_size(u_long cmd)
644 {
645 
646 	switch (cmd) {
647 	case PCIOCGETCONF:
648 		return (sizeof(struct pci_match_conf));
649 #ifdef COMPAT_FREEBSD32
650 	case PCIOCGETCONF32:
651 		return (sizeof(struct pci_match_conf32));
652 #endif
653 #ifdef PRE7_COMPAT
654 	case PCIOCGETCONF_FREEBSD6:
655 		return (sizeof(struct pci_match_conf_freebsd6));
656 #ifdef COMPAT_FREEBSD32
657 	case PCIOCGETCONF_FREEBSD6_32:
658 		return (sizeof(struct pci_match_conf_freebsd6_32));
659 #endif
660 #endif
661 	default:
662 		/* programmer error */
663 		return (0);
664 	}
665 }
666 
667 static size_t
pci_conf_size(u_long cmd)668 pci_conf_size(u_long cmd)
669 {
670 
671 	switch (cmd) {
672 	case PCIOCGETCONF:
673 		return (sizeof(struct pci_conf));
674 #ifdef COMPAT_FREEBSD32
675 	case PCIOCGETCONF32:
676 		return (sizeof(struct pci_conf32));
677 #endif
678 #ifdef PRE7_COMPAT
679 	case PCIOCGETCONF_FREEBSD6:
680 		return (sizeof(struct pci_conf_freebsd6));
681 #ifdef COMPAT_FREEBSD32
682 	case PCIOCGETCONF_FREEBSD6_32:
683 		return (sizeof(struct pci_conf_freebsd6_32));
684 #endif
685 #endif
686 	default:
687 		/* programmer error */
688 		return (0);
689 	}
690 }
691 
692 static void
pci_conf_io_init(struct pci_conf_io * cio,caddr_t data,u_long cmd)693 pci_conf_io_init(struct pci_conf_io *cio, caddr_t data, u_long cmd)
694 {
695 #ifdef COMPAT_FREEBSD32
696 	struct pci_conf_io32 *cio32;
697 #endif
698 
699 	switch (cmd) {
700 	case PCIOCGETCONF:
701 #ifdef PRE7_COMPAT
702 	case PCIOCGETCONF_FREEBSD6:
703 #endif
704 		*cio = *(struct pci_conf_io *)data;
705 		return;
706 
707 #ifdef COMPAT_FREEBSD32
708 	case PCIOCGETCONF32:
709 #ifdef PRE7_COMPAT
710 	case PCIOCGETCONF_FREEBSD6_32:
711 #endif
712 		cio32 = (struct pci_conf_io32 *)data;
713 		cio->pat_buf_len = cio32->pat_buf_len;
714 		cio->num_patterns = cio32->num_patterns;
715 		cio->patterns = (void *)(uintptr_t)cio32->patterns;
716 		cio->match_buf_len = cio32->match_buf_len;
717 		cio->num_matches = cio32->num_matches;
718 		cio->matches = (void *)(uintptr_t)cio32->matches;
719 		cio->offset = cio32->offset;
720 		cio->generation = cio32->generation;
721 		cio->status = cio32->status;
722 		return;
723 #endif
724 
725 	default:
726 		/* programmer error */
727 		return;
728 	}
729 }
730 
731 static void
pci_conf_io_update_data(const struct pci_conf_io * cio,caddr_t data,u_long cmd)732 pci_conf_io_update_data(const struct pci_conf_io *cio, caddr_t data,
733     u_long cmd)
734 {
735 	struct pci_conf_io *d_cio;
736 #ifdef COMPAT_FREEBSD32
737 	struct pci_conf_io32 *cio32;
738 #endif
739 
740 	switch (cmd) {
741 	case PCIOCGETCONF:
742 #ifdef PRE7_COMPAT
743 	case PCIOCGETCONF_FREEBSD6:
744 #endif
745 		d_cio = (struct pci_conf_io *)data;
746 		d_cio->status = cio->status;
747 		d_cio->generation = cio->generation;
748 		d_cio->offset = cio->offset;
749 		d_cio->num_matches = cio->num_matches;
750 		return;
751 
752 #ifdef COMPAT_FREEBSD32
753 	case PCIOCGETCONF32:
754 #ifdef PRE7_COMPAT
755 	case PCIOCGETCONF_FREEBSD6_32:
756 #endif
757 		cio32 = (struct pci_conf_io32 *)data;
758 
759 		cio32->status = cio->status;
760 		cio32->generation = cio->generation;
761 		cio32->offset = cio->offset;
762 		cio32->num_matches = cio->num_matches;
763 		return;
764 #endif
765 
766 	default:
767 		/* programmer error */
768 		return;
769 	}
770 }
771 
772 static void
pci_conf_for_copyout(const struct pci_conf * pcp,union pci_conf_union * pcup,u_long cmd)773 pci_conf_for_copyout(const struct pci_conf *pcp, union pci_conf_union *pcup,
774     u_long cmd)
775 {
776 
777 	memset(pcup, 0, sizeof(*pcup));
778 
779 	switch (cmd) {
780 	case PCIOCGETCONF:
781 		pcup->pc = *pcp;
782 		return;
783 
784 #ifdef COMPAT_FREEBSD32
785 	case PCIOCGETCONF32:
786 		pcup->pc32.pc_sel = pcp->pc_sel;
787 		pcup->pc32.pc_hdr = pcp->pc_hdr;
788 		pcup->pc32.pc_subvendor = pcp->pc_subvendor;
789 		pcup->pc32.pc_subdevice = pcp->pc_subdevice;
790 		pcup->pc32.pc_vendor = pcp->pc_vendor;
791 		pcup->pc32.pc_device = pcp->pc_device;
792 		pcup->pc32.pc_class = pcp->pc_class;
793 		pcup->pc32.pc_subclass = pcp->pc_subclass;
794 		pcup->pc32.pc_progif = pcp->pc_progif;
795 		pcup->pc32.pc_revid = pcp->pc_revid;
796 		strlcpy(pcup->pc32.pd_name, pcp->pd_name,
797 		    sizeof(pcup->pc32.pd_name));
798 		pcup->pc32.pd_unit = (uint32_t)pcp->pd_unit;
799 		return;
800 #endif
801 
802 #ifdef PRE7_COMPAT
803 #ifdef COMPAT_FREEBSD32
804 	case PCIOCGETCONF_FREEBSD6_32:
805 		pcup->pco32.pc_sel.pc_bus = pcp->pc_sel.pc_bus;
806 		pcup->pco32.pc_sel.pc_dev = pcp->pc_sel.pc_dev;
807 		pcup->pco32.pc_sel.pc_func = pcp->pc_sel.pc_func;
808 		pcup->pco32.pc_hdr = pcp->pc_hdr;
809 		pcup->pco32.pc_subvendor = pcp->pc_subvendor;
810 		pcup->pco32.pc_subdevice = pcp->pc_subdevice;
811 		pcup->pco32.pc_vendor = pcp->pc_vendor;
812 		pcup->pco32.pc_device = pcp->pc_device;
813 		pcup->pco32.pc_class = pcp->pc_class;
814 		pcup->pco32.pc_subclass = pcp->pc_subclass;
815 		pcup->pco32.pc_progif = pcp->pc_progif;
816 		pcup->pco32.pc_revid = pcp->pc_revid;
817 		strlcpy(pcup->pco32.pd_name, pcp->pd_name,
818 		    sizeof(pcup->pco32.pd_name));
819 		pcup->pco32.pd_unit = (uint32_t)pcp->pd_unit;
820 		return;
821 
822 #endif /* COMPAT_FREEBSD32 */
823 	case PCIOCGETCONF_FREEBSD6:
824 		pcup->pco.pc_sel.pc_bus = pcp->pc_sel.pc_bus;
825 		pcup->pco.pc_sel.pc_dev = pcp->pc_sel.pc_dev;
826 		pcup->pco.pc_sel.pc_func = pcp->pc_sel.pc_func;
827 		pcup->pco.pc_hdr = pcp->pc_hdr;
828 		pcup->pco.pc_subvendor = pcp->pc_subvendor;
829 		pcup->pco.pc_subdevice = pcp->pc_subdevice;
830 		pcup->pco.pc_vendor = pcp->pc_vendor;
831 		pcup->pco.pc_device = pcp->pc_device;
832 		pcup->pco.pc_class = pcp->pc_class;
833 		pcup->pco.pc_subclass = pcp->pc_subclass;
834 		pcup->pco.pc_progif = pcp->pc_progif;
835 		pcup->pco.pc_revid = pcp->pc_revid;
836 		strlcpy(pcup->pco.pd_name, pcp->pd_name,
837 		    sizeof(pcup->pco.pd_name));
838 		pcup->pco.pd_unit = pcp->pd_unit;
839 		return;
840 #endif /* PRE7_COMPAT */
841 
842 	default:
843 		/* programmer error */
844 		return;
845 	}
846 }
847 
848 static int
pci_bar_mmap(device_t pcidev,struct pci_bar_mmap * pbm)849 pci_bar_mmap(device_t pcidev, struct pci_bar_mmap *pbm)
850 {
851 	vm_map_t map;
852 	vm_object_t obj;
853 	struct thread *td;
854 	struct sglist *sg;
855 	struct pci_map *pm;
856 	rman_res_t membase;
857 	vm_paddr_t pbase;
858 	vm_size_t plen;
859 	vm_offset_t addr;
860 	vm_prot_t prot;
861 	int error, flags;
862 
863 	td = curthread;
864 	map = &td->td_proc->p_vmspace->vm_map;
865 	if ((pbm->pbm_flags & ~(PCIIO_BAR_MMAP_FIXED | PCIIO_BAR_MMAP_EXCL |
866 	    PCIIO_BAR_MMAP_RW | PCIIO_BAR_MMAP_ACTIVATE)) != 0 ||
867 	    pbm->pbm_memattr != (vm_memattr_t)pbm->pbm_memattr ||
868 	    !pmap_is_valid_memattr(map->pmap, pbm->pbm_memattr))
869 		return (EINVAL);
870 
871 	/* Fetch the BAR physical base and length. */
872 	pm = pci_find_bar(pcidev, pbm->pbm_reg);
873 	if (pm == NULL)
874 		return (EINVAL);
875 	if (!pci_bar_enabled(pcidev, pm))
876 		return (EBUSY); /* XXXKIB enable if _ACTIVATE */
877 	if (!PCI_BAR_MEM(pm->pm_value))
878 		return (EIO);
879 	error = bus_translate_resource(pcidev, SYS_RES_MEMORY,
880 	    pm->pm_value & PCIM_BAR_MEM_BASE, &membase);
881 	if (error != 0)
882 		return (error);
883 
884 	pbase = trunc_page(membase);
885 	plen = round_page(membase + ((pci_addr_t)1 << pm->pm_size)) -
886 	    pbase;
887 	prot = VM_PROT_READ | (((pbm->pbm_flags & PCIIO_BAR_MMAP_RW) != 0) ?
888 	    VM_PROT_WRITE : 0);
889 
890 	/* Create vm structures and mmap. */
891 	sg = sglist_alloc(1, M_WAITOK);
892 	error = sglist_append_phys(sg, pbase, plen);
893 	if (error != 0)
894 		goto out;
895 	obj = vm_pager_allocate(OBJT_SG, sg, plen, prot, 0, td->td_ucred);
896 	if (obj == NULL) {
897 		error = EIO;
898 		goto out;
899 	}
900 	obj->memattr = pbm->pbm_memattr;
901 	flags = MAP_SHARED;
902 	addr = 0;
903 	if ((pbm->pbm_flags & PCIIO_BAR_MMAP_FIXED) != 0) {
904 		addr = (uintptr_t)pbm->pbm_map_base;
905 		flags |= MAP_FIXED;
906 	}
907 	if ((pbm->pbm_flags & PCIIO_BAR_MMAP_EXCL) != 0)
908 		flags |= MAP_CHECK_EXCL;
909 	error = vm_mmap_object(map, &addr, plen, prot, prot, flags, obj, 0,
910 	    FALSE, td);
911 	if (error != 0) {
912 		vm_object_deallocate(obj);
913 		goto out;
914 	}
915 	pbm->pbm_map_base = (void *)addr;
916 	pbm->pbm_map_length = plen;
917 	pbm->pbm_bar_off = membase - pbase;
918 	pbm->pbm_bar_length = (pci_addr_t)1 << pm->pm_size;
919 
920 out:
921 	sglist_free(sg);
922 	return (error);
923 }
924 
925 static int
pci_bar_io(device_t pcidev,struct pci_bar_ioreq * pbi)926 pci_bar_io(device_t pcidev, struct pci_bar_ioreq *pbi)
927 {
928 	struct pci_map *pm;
929 	struct resource *res;
930 	uint32_t offset, width;
931 	int bar, error, type;
932 
933 	if (pbi->pbi_op != PCIBARIO_READ &&
934 	    pbi->pbi_op != PCIBARIO_WRITE)
935 		return (EINVAL);
936 
937 	bar = PCIR_BAR(pbi->pbi_bar);
938 	pm = pci_find_bar(pcidev, bar);
939 	if (pm == NULL)
940 		return (EINVAL);
941 
942 	offset = pbi->pbi_offset;
943 	width = pbi->pbi_width;
944 
945 	if (offset + width < offset ||
946 	    ((pci_addr_t)1 << pm->pm_size) < offset + width)
947 		return (EINVAL);
948 
949 	type = PCI_BAR_MEM(pm->pm_value) ? SYS_RES_MEMORY : SYS_RES_IOPORT;
950 
951 	/*
952 	 * This will fail if a driver has allocated the resource.  This could be
953 	 * worked around by detecting that case and using bus_map_resource() to
954 	 * populate the handle, but so far this is not needed.
955 	 */
956 	res = bus_alloc_resource_any(pcidev, type, &bar, RF_ACTIVE);
957 	if (res == NULL)
958 		return (ENOENT);
959 
960 	error = 0;
961 	switch (pbi->pbi_op) {
962 	case PCIBARIO_READ:
963 		switch (pbi->pbi_width) {
964 		case 1:
965 			pbi->pbi_value = bus_read_1(res, offset);
966 			break;
967 		case 2:
968 			pbi->pbi_value = bus_read_2(res, offset);
969 			break;
970 		case 4:
971 			pbi->pbi_value = bus_read_4(res, offset);
972 			break;
973 #ifndef __i386__
974 		case 8:
975 			pbi->pbi_value = bus_read_8(res, offset);
976 			break;
977 #endif
978 		default:
979 			error = EINVAL;
980 			break;
981 		}
982 		break;
983 	case PCIBARIO_WRITE:
984 		switch (pbi->pbi_width) {
985 		case 1:
986 			bus_write_1(res, offset, pbi->pbi_value);
987 			break;
988 		case 2:
989 			bus_write_2(res, offset, pbi->pbi_value);
990 			break;
991 		case 4:
992 			bus_write_4(res, offset, pbi->pbi_value);
993 			break;
994 #ifndef __i386__
995 		case 8:
996 			bus_write_8(res, offset, pbi->pbi_value);
997 			break;
998 #endif
999 		default:
1000 			error = EINVAL;
1001 			break;
1002 		}
1003 		break;
1004 	}
1005 
1006 	bus_release_resource(pcidev, type, bar, res);
1007 
1008 	return (error);
1009 }
1010 
1011 static int
pci_ioctl(struct cdev * dev,u_long cmd,caddr_t data,int flag,struct thread * td)1012 pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
1013 {
1014 	device_t pcidev;
1015 	const char *name;
1016 	struct devlist *devlist_head;
1017 	struct pci_conf_io *cio = NULL;
1018 	struct pci_devinfo *dinfo;
1019 	struct pci_io *io;
1020 	struct pci_bar_ioreq *pbi;
1021 	struct pci_bar_io *bio;
1022 	struct pci_list_vpd_io *lvio;
1023 	struct pci_match_conf *pattern_buf;
1024 	struct pci_map *pm;
1025 	struct pci_bar_mmap *pbm;
1026 	size_t confsz, iolen;
1027 	int error, ionum, i, num_patterns;
1028 	union pci_conf_union pcu;
1029 #ifdef PRE7_COMPAT
1030 	struct pci_io iodata;
1031 	struct pci_io_freebsd6 *io_freebsd6;
1032 
1033 	io_freebsd6 = NULL;
1034 #endif
1035 
1036 	/*
1037 	 * Interpret read-only opened /dev/pci as a promise that no
1038 	 * operation of the file descriptor could modify system state,
1039 	 * including side-effects due to reading devices registers.
1040 	 */
1041 	if ((flag & FWRITE) == 0) {
1042 		switch (cmd) {
1043 		case PCIOCGETCONF:
1044 #ifdef COMPAT_FREEBSD32
1045 		case PCIOCGETCONF32:
1046 #endif
1047 #ifdef PRE7_COMPAT
1048 		case PCIOCGETCONF_FREEBSD6:
1049 #ifdef COMPAT_FREEBSD32
1050 		case PCIOCGETCONF_FREEBSD6_32:
1051 #endif
1052 #endif
1053 		case PCIOCGETBAR:
1054 		case PCIOCLISTVPD:
1055 			break;
1056 		default:
1057 			return (EPERM);
1058 		}
1059 	}
1060 
1061 	/*
1062 	 * Use bus topology lock to ensure that the pci list of devies doesn't
1063 	 * change while we're traversing the list, in some cases multiple times.
1064 	 */
1065 	bus_topo_lock();
1066 
1067 	switch (cmd) {
1068 	case PCIOCGETCONF:
1069 #ifdef COMPAT_FREEBSD32
1070 	case PCIOCGETCONF32:
1071 #endif
1072 #ifdef PRE7_COMPAT
1073 	case PCIOCGETCONF_FREEBSD6:
1074 #ifdef COMPAT_FREEBSD32
1075 	case PCIOCGETCONF_FREEBSD6_32:
1076 #endif
1077 #endif
1078 		cio = malloc(sizeof(struct pci_conf_io), M_TEMP,
1079 		    M_WAITOK | M_ZERO);
1080 		pci_conf_io_init(cio, data, cmd);
1081 		pattern_buf = NULL;
1082 		num_patterns = 0;
1083 		dinfo = NULL;
1084 
1085 		cio->num_matches = 0;
1086 
1087 		/*
1088 		 * If the user specified an offset into the device list,
1089 		 * but the list has changed since they last called this
1090 		 * ioctl, tell them that the list has changed.  They will
1091 		 * have to get the list from the beginning.
1092 		 */
1093 		if ((cio->offset != 0)
1094 		 && (cio->generation != pci_generation)){
1095 			cio->status = PCI_GETCONF_LIST_CHANGED;
1096 			error = 0;
1097 			goto getconfexit;
1098 		}
1099 
1100 		/*
1101 		 * Check to see whether the user has asked for an offset
1102 		 * past the end of our list.
1103 		 */
1104 		if (cio->offset >= pci_numdevs) {
1105 			cio->status = PCI_GETCONF_LAST_DEVICE;
1106 			error = 0;
1107 			goto getconfexit;
1108 		}
1109 
1110 		/* get the head of the device queue */
1111 		devlist_head = &pci_devq;
1112 
1113 		/*
1114 		 * Determine how much room we have for pci_conf structures.
1115 		 * Round the user's buffer size down to the nearest
1116 		 * multiple of sizeof(struct pci_conf) in case the user
1117 		 * didn't specify a multiple of that size.
1118 		 */
1119 		confsz = pci_conf_size(cmd);
1120 		iolen = min(cio->match_buf_len - (cio->match_buf_len % confsz),
1121 		    pci_numdevs * confsz);
1122 
1123 		/*
1124 		 * Since we know that iolen is a multiple of the size of
1125 		 * the pciconf union, it's okay to do this.
1126 		 */
1127 		ionum = iolen / confsz;
1128 
1129 		/*
1130 		 * If this test is true, the user wants the pci_conf
1131 		 * structures returned to match the supplied entries.
1132 		 */
1133 		if ((cio->num_patterns > 0) && (cio->num_patterns < pci_numdevs)
1134 		 && (cio->pat_buf_len > 0)) {
1135 			/*
1136 			 * pat_buf_len needs to be:
1137 			 * num_patterns * sizeof(struct pci_match_conf)
1138 			 * While it is certainly possible the user just
1139 			 * allocated a large buffer, but set the number of
1140 			 * matches correctly, it is far more likely that
1141 			 * their kernel doesn't match the userland utility
1142 			 * they're using.  It's also possible that the user
1143 			 * forgot to initialize some variables.  Yes, this
1144 			 * may be overly picky, but I hazard to guess that
1145 			 * it's far more likely to just catch folks that
1146 			 * updated their kernel but not their userland.
1147 			 */
1148 			if (cio->num_patterns * pci_match_conf_size(cmd) !=
1149 			    cio->pat_buf_len) {
1150 				/* The user made a mistake, return an error. */
1151 				cio->status = PCI_GETCONF_ERROR;
1152 				error = EINVAL;
1153 				goto getconfexit;
1154 			}
1155 
1156 			/*
1157 			 * Allocate a buffer to hold the patterns.
1158 			 */
1159 			pattern_buf = malloc(cio->pat_buf_len, M_TEMP,
1160 			    M_WAITOK);
1161 			error = copyin(cio->patterns, pattern_buf,
1162 			    cio->pat_buf_len);
1163 			if (error != 0) {
1164 				error = EINVAL;
1165 				goto getconfexit;
1166 			}
1167 			num_patterns = cio->num_patterns;
1168 		} else if ((cio->num_patterns > 0)
1169 			|| (cio->pat_buf_len > 0)) {
1170 			/*
1171 			 * The user made a mistake, spit out an error.
1172 			 */
1173 			cio->status = PCI_GETCONF_ERROR;
1174 			error = EINVAL;
1175 			goto getconfexit;
1176 		}
1177 
1178 		/*
1179 		 * Go through the list of devices and copy out the devices
1180 		 * that match the user's criteria.
1181 		 */
1182 		for (cio->num_matches = 0, i = 0,
1183 				 dinfo = STAILQ_FIRST(devlist_head);
1184 		     dinfo != NULL;
1185 		     dinfo = STAILQ_NEXT(dinfo, pci_links), i++) {
1186 			if (i < cio->offset)
1187 				continue;
1188 
1189 			/* Populate pd_name and pd_unit */
1190 			name = NULL;
1191 			if (dinfo->cfg.dev)
1192 				name = device_get_name(dinfo->cfg.dev);
1193 			if (name) {
1194 				strncpy(dinfo->conf.pd_name, name,
1195 					sizeof(dinfo->conf.pd_name));
1196 				dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0;
1197 				dinfo->conf.pd_unit =
1198 					device_get_unit(dinfo->cfg.dev);
1199 			} else {
1200 				dinfo->conf.pd_name[0] = '\0';
1201 				dinfo->conf.pd_unit = 0;
1202 			}
1203 
1204 			if (pattern_buf == NULL ||
1205 			    pci_conf_match(cmd, pattern_buf, num_patterns,
1206 			    &dinfo->conf) == 0) {
1207 				/*
1208 				 * If we've filled up the user's buffer,
1209 				 * break out at this point.  Since we've
1210 				 * got a match here, we'll pick right back
1211 				 * up at the matching entry.  We can also
1212 				 * tell the user that there are more matches
1213 				 * left.
1214 				 */
1215 				if (cio->num_matches >= ionum) {
1216 					error = 0;
1217 					break;
1218 				}
1219 
1220 				pci_conf_for_copyout(&dinfo->conf, &pcu, cmd);
1221 				error = copyout(&pcu,
1222 				    (caddr_t)cio->matches +
1223 				    confsz * cio->num_matches, confsz);
1224 				if (error)
1225 					break;
1226 				cio->num_matches++;
1227 			}
1228 		}
1229 
1230 		/*
1231 		 * Set the pointer into the list, so if the user is getting
1232 		 * n records at a time, where n < pci_numdevs,
1233 		 */
1234 		cio->offset = i;
1235 
1236 		/*
1237 		 * Set the generation, the user will need this if they make
1238 		 * another ioctl call with offset != 0.
1239 		 */
1240 		cio->generation = pci_generation;
1241 
1242 		/*
1243 		 * If this is the last device, inform the user so he won't
1244 		 * bother asking for more devices.  If dinfo isn't NULL, we
1245 		 * know that there are more matches in the list because of
1246 		 * the way the traversal is done.
1247 		 */
1248 		if (dinfo == NULL)
1249 			cio->status = PCI_GETCONF_LAST_DEVICE;
1250 		else
1251 			cio->status = PCI_GETCONF_MORE_DEVS;
1252 
1253 getconfexit:
1254 		pci_conf_io_update_data(cio, data, cmd);
1255 		free(cio, M_TEMP);
1256 		free(pattern_buf, M_TEMP);
1257 
1258 		break;
1259 
1260 #ifdef PRE7_COMPAT
1261 	case PCIOCREAD_FREEBSD6:
1262 	case PCIOCWRITE_FREEBSD6:
1263 		io_freebsd6 = (struct pci_io_freebsd6 *)data;
1264 		iodata.pi_sel.pc_domain = 0;
1265 		iodata.pi_sel.pc_bus = io_freebsd6->pi_sel.pc_bus;
1266 		iodata.pi_sel.pc_dev = io_freebsd6->pi_sel.pc_dev;
1267 		iodata.pi_sel.pc_func = io_freebsd6->pi_sel.pc_func;
1268 		iodata.pi_reg = io_freebsd6->pi_reg;
1269 		iodata.pi_width = io_freebsd6->pi_width;
1270 		iodata.pi_data = io_freebsd6->pi_data;
1271 		data = (caddr_t)&iodata;
1272 		/* FALLTHROUGH */
1273 #endif
1274 	case PCIOCREAD:
1275 	case PCIOCWRITE:
1276 		io = (struct pci_io *)data;
1277 		switch(io->pi_width) {
1278 		case 4:
1279 		case 2:
1280 		case 1:
1281 			/* Make sure register is not negative and aligned. */
1282 			if (io->pi_reg < 0 ||
1283 			    io->pi_reg & (io->pi_width - 1)) {
1284 				error = EINVAL;
1285 				break;
1286 			}
1287 			/*
1288 			 * Assume that the user-level bus number is
1289 			 * in fact the physical PCI bus number.
1290 			 * Look up the grandparent, i.e. the bridge device,
1291 			 * so that we can issue configuration space cycles.
1292 			 */
1293 			pcidev = pci_find_dbsf(io->pi_sel.pc_domain,
1294 			    io->pi_sel.pc_bus, io->pi_sel.pc_dev,
1295 			    io->pi_sel.pc_func);
1296 			if (pcidev) {
1297 #ifdef PRE7_COMPAT
1298 				if (cmd == PCIOCWRITE || cmd == PCIOCWRITE_FREEBSD6)
1299 #else
1300 				if (cmd == PCIOCWRITE)
1301 #endif
1302 					pci_write_config(pcidev,
1303 							  io->pi_reg,
1304 							  io->pi_data,
1305 							  io->pi_width);
1306 #ifdef PRE7_COMPAT
1307 				else if (cmd == PCIOCREAD_FREEBSD6)
1308 					io_freebsd6->pi_data =
1309 						pci_read_config(pcidev,
1310 							  io->pi_reg,
1311 							  io->pi_width);
1312 #endif
1313 				else
1314 					io->pi_data =
1315 						pci_read_config(pcidev,
1316 							  io->pi_reg,
1317 							  io->pi_width);
1318 				error = 0;
1319 			} else {
1320 #ifdef COMPAT_FREEBSD4
1321 				if (cmd == PCIOCREAD_FREEBSD6) {
1322 					io_freebsd6->pi_data = -1;
1323 					error = 0;
1324 				} else
1325 #endif
1326 					error = ENODEV;
1327 			}
1328 			break;
1329 		default:
1330 			error = EINVAL;
1331 			break;
1332 		}
1333 		break;
1334 
1335 	case PCIOCGETBAR:
1336 		bio = (struct pci_bar_io *)data;
1337 
1338 		/*
1339 		 * Assume that the user-level bus number is
1340 		 * in fact the physical PCI bus number.
1341 		 */
1342 		pcidev = pci_find_dbsf(bio->pbi_sel.pc_domain,
1343 		    bio->pbi_sel.pc_bus, bio->pbi_sel.pc_dev,
1344 		    bio->pbi_sel.pc_func);
1345 		if (pcidev == NULL) {
1346 			error = ENODEV;
1347 			break;
1348 		}
1349 		pm = pci_find_bar(pcidev, bio->pbi_reg);
1350 		if (pm == NULL) {
1351 			error = EINVAL;
1352 			break;
1353 		}
1354 		bio->pbi_base = pm->pm_value;
1355 		bio->pbi_length = (pci_addr_t)1 << pm->pm_size;
1356 		bio->pbi_enabled = pci_bar_enabled(pcidev, pm);
1357 		error = 0;
1358 		break;
1359 	case PCIOCATTACHED:
1360 		error = 0;
1361 		io = (struct pci_io *)data;
1362 		pcidev = pci_find_dbsf(io->pi_sel.pc_domain, io->pi_sel.pc_bus,
1363 				       io->pi_sel.pc_dev, io->pi_sel.pc_func);
1364 		if (pcidev != NULL)
1365 			io->pi_data = device_is_attached(pcidev);
1366 		else
1367 			error = ENODEV;
1368 		break;
1369 	case PCIOCLISTVPD:
1370 		lvio = (struct pci_list_vpd_io *)data;
1371 
1372 		/*
1373 		 * Assume that the user-level bus number is
1374 		 * in fact the physical PCI bus number.
1375 		 */
1376 		pcidev = pci_find_dbsf(lvio->plvi_sel.pc_domain,
1377 		    lvio->plvi_sel.pc_bus, lvio->plvi_sel.pc_dev,
1378 		    lvio->plvi_sel.pc_func);
1379 		if (pcidev == NULL) {
1380 			error = ENODEV;
1381 			break;
1382 		}
1383 		error = pci_list_vpd(pcidev, lvio);
1384 		break;
1385 
1386 	case PCIOCBARMMAP:
1387 		pbm = (struct pci_bar_mmap *)data;
1388 		if ((flag & FWRITE) == 0 &&
1389 		    (pbm->pbm_flags & PCIIO_BAR_MMAP_RW) != 0) {
1390 			error = EPERM;
1391 			break;
1392 		}
1393 		pcidev = pci_find_dbsf(pbm->pbm_sel.pc_domain,
1394 		    pbm->pbm_sel.pc_bus, pbm->pbm_sel.pc_dev,
1395 		    pbm->pbm_sel.pc_func);
1396 		error = pcidev == NULL ? ENODEV : pci_bar_mmap(pcidev, pbm);
1397 		break;
1398 
1399 	case PCIOCBARIO:
1400 		pbi = (struct pci_bar_ioreq *)data;
1401 
1402 		pcidev = pci_find_dbsf(pbi->pbi_sel.pc_domain,
1403 		    pbi->pbi_sel.pc_bus, pbi->pbi_sel.pc_dev,
1404 		    pbi->pbi_sel.pc_func);
1405 		if (pcidev == NULL) {
1406 			error = ENODEV;
1407 			break;
1408 		}
1409 		error = pci_bar_io(pcidev, pbi);
1410 		break;
1411 
1412 	default:
1413 		error = ENOTTY;
1414 		break;
1415 	}
1416 
1417 	bus_topo_unlock();
1418 
1419 	return (error);
1420 }
1421