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