xref: /freebsd/sys/dev/pci/pci_user.c (revision 74aa2d49)
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 /*
450  * Like PVE_NEXT but takes an explicit length since 'pve' is a user
451  * pointer that cannot be dereferenced.
452  */
453 #define	PVE_NEXT_LEN(pve, datalen)					\
454 	((struct pci_vpd_element *)((char *)(pve) +			\
455 	    sizeof(struct pci_vpd_element) + (datalen)))
456 
457 static int
458 pci_list_vpd(device_t dev, struct pci_list_vpd_io *lvio)
459 {
460 	struct pci_vpd_element vpd_element, *vpd_user;
461 	struct pcicfg_vpd *vpd;
462 	size_t len;
463 	int error, i;
464 
465 	vpd = pci_fetch_vpd_list(dev);
466 	if (vpd->vpd_reg == 0 || vpd->vpd_ident == NULL)
467 		return (ENXIO);
468 
469 	/*
470 	 * Calculate the amount of space needed in the data buffer.  An
471 	 * identifier element is always present followed by the read-only
472 	 * and read-write keywords.
473 	 */
474 	len = sizeof(struct pci_vpd_element) + strlen(vpd->vpd_ident);
475 	for (i = 0; i < vpd->vpd_rocnt; i++)
476 		len += sizeof(struct pci_vpd_element) + vpd->vpd_ros[i].len;
477 	for (i = 0; i < vpd->vpd_wcnt; i++)
478 		len += sizeof(struct pci_vpd_element) + vpd->vpd_w[i].len;
479 
480 	if (lvio->plvi_len == 0) {
481 		lvio->plvi_len = len;
482 		return (0);
483 	}
484 	if (lvio->plvi_len < len) {
485 		lvio->plvi_len = len;
486 		return (ENOMEM);
487 	}
488 
489 	/*
490 	 * Copyout the identifier string followed by each keyword and
491 	 * value.
492 	 */
493 	vpd_user = lvio->plvi_data;
494 	vpd_element.pve_keyword[0] = '\0';
495 	vpd_element.pve_keyword[1] = '\0';
496 	vpd_element.pve_flags = PVE_FLAG_IDENT;
497 	vpd_element.pve_datalen = strlen(vpd->vpd_ident);
498 	error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
499 	if (error)
500 		return (error);
501 	error = copyout(vpd->vpd_ident, vpd_user->pve_data,
502 	    strlen(vpd->vpd_ident));
503 	if (error)
504 		return (error);
505 	vpd_user = PVE_NEXT_LEN(vpd_user, vpd_element.pve_datalen);
506 	vpd_element.pve_flags = 0;
507 	for (i = 0; i < vpd->vpd_rocnt; i++) {
508 		vpd_element.pve_keyword[0] = vpd->vpd_ros[i].keyword[0];
509 		vpd_element.pve_keyword[1] = vpd->vpd_ros[i].keyword[1];
510 		vpd_element.pve_datalen = vpd->vpd_ros[i].len;
511 		error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
512 		if (error)
513 			return (error);
514 		error = copyout(vpd->vpd_ros[i].value, vpd_user->pve_data,
515 		    vpd->vpd_ros[i].len);
516 		if (error)
517 			return (error);
518 		vpd_user = PVE_NEXT_LEN(vpd_user, vpd_element.pve_datalen);
519 	}
520 	vpd_element.pve_flags = PVE_FLAG_RW;
521 	for (i = 0; i < vpd->vpd_wcnt; i++) {
522 		vpd_element.pve_keyword[0] = vpd->vpd_w[i].keyword[0];
523 		vpd_element.pve_keyword[1] = vpd->vpd_w[i].keyword[1];
524 		vpd_element.pve_datalen = vpd->vpd_w[i].len;
525 		error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
526 		if (error)
527 			return (error);
528 		error = copyout(vpd->vpd_w[i].value, vpd_user->pve_data,
529 		    vpd->vpd_w[i].len);
530 		if (error)
531 			return (error);
532 		vpd_user = PVE_NEXT_LEN(vpd_user, vpd_element.pve_datalen);
533 	}
534 	KASSERT((char *)vpd_user - (char *)lvio->plvi_data == len,
535 	    ("length mismatch"));
536 	lvio->plvi_len = len;
537 	return (0);
538 }
539 
540 static size_t
541 pci_match_conf_size(u_long cmd)
542 {
543 
544 	switch (cmd) {
545 	case PCIOCGETCONF:
546 		return (sizeof(struct pci_match_conf));
547 #ifdef PRE7_COMPAT
548 	case PCIOCGETCONF_OLD:
549 		return (sizeof(struct pci_match_conf_old));
550 #ifdef COMPAT_FREEBSD32
551 	case PCIOCGETCONF_OLD32:
552 		return (sizeof(struct pci_match_conf_old32));
553 #endif
554 #endif
555 	default:
556 		/* programmer error */
557 		return (0);
558 	}
559 }
560 
561 static size_t
562 pci_conf_size(u_long cmd)
563 {
564 
565 	switch (cmd) {
566 	case PCIOCGETCONF:
567 		return (sizeof(struct pci_conf));
568 #ifdef PRE7_COMPAT
569 	case PCIOCGETCONF_OLD:
570 		return (sizeof(struct pci_conf_old));
571 #ifdef COMPAT_FREEBSD32
572 	case PCIOCGETCONF_OLD32:
573 		return (sizeof(struct pci_conf_old32));
574 #endif
575 #endif
576 	default:
577 		/* programmer error */
578 		return (0);
579 	}
580 }
581 
582 static void
583 pci_conf_io_init(struct pci_conf_io *cio, caddr_t data, u_long cmd)
584 {
585 #if defined(PRE7_COMPAT) && defined(COMPAT_FREEBSD32)
586 	struct pci_conf_io32 *cio32;
587 #endif
588 
589 	switch (cmd) {
590 	case PCIOCGETCONF:
591 #ifdef PRE7_COMPAT
592 	case PCIOCGETCONF_OLD:
593 #endif
594 		*cio = *(struct pci_conf_io *)data;
595 		return;
596 
597 #if defined(PRE7_COMPAT) && defined(COMPAT_FREEBSD32)
598 	case PCIOCGETCONF_OLD32:
599                cio32 = (struct pci_conf_io32 *)data;
600                cio->pat_buf_len = cio32->pat_buf_len;
601                cio->num_patterns = cio32->num_patterns;
602                cio->patterns = (void *)(uintptr_t)cio32->patterns;
603                cio->match_buf_len = cio32->match_buf_len;
604                cio->num_matches = cio32->num_matches;
605                cio->matches = (void *)(uintptr_t)cio32->matches;
606                cio->offset = cio32->offset;
607                cio->generation = cio32->generation;
608                cio->status = cio32->status;
609                return;
610 #endif
611 
612 	default:
613 		/* programmer error */
614 		return;
615 	}
616 }
617 
618 static void
619 pci_conf_io_update_data(const struct pci_conf_io *cio, caddr_t data,
620     u_long cmd)
621 {
622 	struct pci_conf_io *d_cio;
623 #if defined(PRE7_COMPAT) && defined(COMPAT_FREEBSD32)
624 	struct pci_conf_io32 *cio32;
625 #endif
626 
627 	switch (cmd) {
628 	case PCIOCGETCONF:
629 #ifdef PRE7_COMPAT
630 	case PCIOCGETCONF_OLD:
631 #endif
632 		d_cio = (struct pci_conf_io *)data;
633 		d_cio->status = cio->status;
634 		d_cio->generation = cio->generation;
635 		d_cio->offset = cio->offset;
636 		d_cio->num_matches = cio->num_matches;
637 		return;
638 
639 #if defined(PRE7_COMPAT) && defined(COMPAT_FREEBSD32)
640 	case PCIOCGETCONF_OLD32:
641 		cio32 = (struct pci_conf_io32 *)data;
642 
643 		cio32->status = cio->status;
644 		cio32->generation = cio->generation;
645 		cio32->offset = cio->offset;
646 		cio32->num_matches = cio->num_matches;
647 		return;
648 #endif
649 
650 	default:
651 		/* programmer error */
652 		return;
653 	}
654 }
655 
656 static void
657 pci_conf_for_copyout(const struct pci_conf *pcp, union pci_conf_union *pcup,
658     u_long cmd)
659 {
660 
661 	memset(pcup, 0, sizeof(*pcup));
662 
663 	switch (cmd) {
664 	case PCIOCGETCONF:
665 		pcup->pc = *pcp;
666 		return;
667 
668 #ifdef PRE7_COMPAT
669 #ifdef COMPAT_FREEBSD32
670 	case PCIOCGETCONF_OLD32:
671 		pcup->pco32.pc_sel.pc_bus = pcp->pc_sel.pc_bus;
672 		pcup->pco32.pc_sel.pc_dev = pcp->pc_sel.pc_dev;
673 		pcup->pco32.pc_sel.pc_func = pcp->pc_sel.pc_func;
674 		pcup->pco32.pc_hdr = pcp->pc_hdr;
675 		pcup->pco32.pc_subvendor = pcp->pc_subvendor;
676 		pcup->pco32.pc_subdevice = pcp->pc_subdevice;
677 		pcup->pco32.pc_vendor = pcp->pc_vendor;
678 		pcup->pco32.pc_device = pcp->pc_device;
679 		pcup->pco32.pc_class = pcp->pc_class;
680 		pcup->pco32.pc_subclass = pcp->pc_subclass;
681 		pcup->pco32.pc_progif = pcp->pc_progif;
682 		pcup->pco32.pc_revid = pcp->pc_revid;
683 		strlcpy(pcup->pco32.pd_name, pcp->pd_name,
684 		    sizeof(pcup->pco32.pd_name));
685 		pcup->pco32.pd_unit = (uint32_t)pcp->pd_unit;
686 		return;
687 
688 #endif /* COMPAT_FREEBSD32 */
689 	case PCIOCGETCONF_OLD:
690 		pcup->pco.pc_sel.pc_bus = pcp->pc_sel.pc_bus;
691 		pcup->pco.pc_sel.pc_dev = pcp->pc_sel.pc_dev;
692 		pcup->pco.pc_sel.pc_func = pcp->pc_sel.pc_func;
693 		pcup->pco.pc_hdr = pcp->pc_hdr;
694 		pcup->pco.pc_subvendor = pcp->pc_subvendor;
695 		pcup->pco.pc_subdevice = pcp->pc_subdevice;
696 		pcup->pco.pc_vendor = pcp->pc_vendor;
697 		pcup->pco.pc_device = pcp->pc_device;
698 		pcup->pco.pc_class = pcp->pc_class;
699 		pcup->pco.pc_subclass = pcp->pc_subclass;
700 		pcup->pco.pc_progif = pcp->pc_progif;
701 		pcup->pco.pc_revid = pcp->pc_revid;
702 		strlcpy(pcup->pco.pd_name, pcp->pd_name,
703 		    sizeof(pcup->pco.pd_name));
704 		pcup->pco.pd_unit = pcp->pd_unit;
705 		return;
706 #endif /* PRE7_COMPAT */
707 
708 	default:
709 		/* programmer error */
710 		return;
711 	}
712 }
713 
714 static int
715 pci_bar_mmap(device_t pcidev, struct pci_bar_mmap *pbm)
716 {
717 	vm_map_t map;
718 	vm_object_t obj;
719 	struct thread *td;
720 	struct sglist *sg;
721 	struct pci_map *pm;
722 	vm_paddr_t pbase;
723 	vm_size_t plen;
724 	vm_offset_t addr;
725 	vm_prot_t prot;
726 	int error, flags;
727 
728 	td = curthread;
729 	map = &td->td_proc->p_vmspace->vm_map;
730 	if ((pbm->pbm_flags & ~(PCIIO_BAR_MMAP_FIXED | PCIIO_BAR_MMAP_EXCL |
731 	    PCIIO_BAR_MMAP_RW | PCIIO_BAR_MMAP_ACTIVATE)) != 0 ||
732 	    pbm->pbm_memattr != (vm_memattr_t)pbm->pbm_memattr ||
733 	    !pmap_is_valid_memattr(map->pmap, pbm->pbm_memattr))
734 		return (EINVAL);
735 
736 	/* Fetch the BAR physical base and length. */
737 	pm = pci_find_bar(pcidev, pbm->pbm_reg);
738 	if (pm == NULL)
739 		return (EINVAL);
740 	if (!pci_bar_enabled(pcidev, pm))
741 		return (EBUSY); /* XXXKIB enable if _ACTIVATE */
742 	if (!PCI_BAR_MEM(pm->pm_value))
743 		return (EIO);
744 	pbase = trunc_page(pm->pm_value);
745 	plen = round_page(pm->pm_value + ((pci_addr_t)1 << pm->pm_size)) -
746 	    pbase;
747 	prot = VM_PROT_READ | (((pbm->pbm_flags & PCIIO_BAR_MMAP_RW) != 0) ?
748 	    VM_PROT_WRITE : 0);
749 
750 	/* Create vm structures and mmap. */
751 	sg = sglist_alloc(1, M_WAITOK);
752 	error = sglist_append_phys(sg, pbase, plen);
753 	if (error != 0)
754 		goto out;
755 	obj = vm_pager_allocate(OBJT_SG, sg, plen, prot, 0, td->td_ucred);
756 	if (obj == NULL) {
757 		error = EIO;
758 		goto out;
759 	}
760 	obj->memattr = pbm->pbm_memattr;
761 	flags = MAP_SHARED;
762 	addr = 0;
763 	if ((pbm->pbm_flags & PCIIO_BAR_MMAP_FIXED) != 0) {
764 		addr = (uintptr_t)pbm->pbm_map_base;
765 		flags |= MAP_FIXED;
766 	}
767 	if ((pbm->pbm_flags & PCIIO_BAR_MMAP_EXCL) != 0)
768 		flags |= MAP_CHECK_EXCL;
769 	error = vm_mmap_object(map, &addr, plen, prot, prot, flags, obj, 0,
770 	    FALSE, td);
771 	if (error != 0) {
772 		vm_object_deallocate(obj);
773 		goto out;
774 	}
775 	pbm->pbm_map_base = (void *)addr;
776 	pbm->pbm_map_length = plen;
777 	pbm->pbm_bar_off = pm->pm_value - pbase;
778 	pbm->pbm_bar_length = (pci_addr_t)1 << pm->pm_size;
779 
780 out:
781 	sglist_free(sg);
782 	return (error);
783 }
784 
785 static int
786 pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
787 {
788 	device_t pcidev;
789 	const char *name;
790 	struct devlist *devlist_head;
791 	struct pci_conf_io *cio = NULL;
792 	struct pci_devinfo *dinfo;
793 	struct pci_io *io;
794 	struct pci_bar_io *bio;
795 	struct pci_list_vpd_io *lvio;
796 	struct pci_match_conf *pattern_buf;
797 	struct pci_map *pm;
798 	struct pci_bar_mmap *pbm;
799 	size_t confsz, iolen;
800 	int error, ionum, i, num_patterns;
801 	union pci_conf_union pcu;
802 #ifdef PRE7_COMPAT
803 	struct pci_io iodata;
804 	struct pci_io_old *io_old;
805 
806 	io_old = NULL;
807 #endif
808 
809 	if (!(flag & FWRITE)) {
810 		switch (cmd) {
811 		case PCIOCGETCONF:
812 #ifdef PRE7_COMPAT
813 		case PCIOCGETCONF_OLD:
814 #ifdef COMPAT_FREEBSD32
815 		case PCIOCGETCONF_OLD32:
816 #endif
817 #endif
818 		case PCIOCGETBAR:
819 		case PCIOCLISTVPD:
820 			break;
821 		default:
822 			return (EPERM);
823 		}
824 	}
825 
826 
827 	switch (cmd) {
828 	case PCIOCGETCONF:
829 #ifdef PRE7_COMPAT
830 	case PCIOCGETCONF_OLD:
831 #ifdef COMPAT_FREEBSD32
832 	case PCIOCGETCONF_OLD32:
833 #endif
834 #endif
835 		cio = malloc(sizeof(struct pci_conf_io), M_TEMP,
836 		    M_WAITOK | M_ZERO);
837 		pci_conf_io_init(cio, data, cmd);
838 		pattern_buf = NULL;
839 		num_patterns = 0;
840 		dinfo = NULL;
841 
842 		cio->num_matches = 0;
843 
844 		/*
845 		 * If the user specified an offset into the device list,
846 		 * but the list has changed since they last called this
847 		 * ioctl, tell them that the list has changed.  They will
848 		 * have to get the list from the beginning.
849 		 */
850 		if ((cio->offset != 0)
851 		 && (cio->generation != pci_generation)){
852 			cio->status = PCI_GETCONF_LIST_CHANGED;
853 			error = 0;
854 			goto getconfexit;
855 		}
856 
857 		/*
858 		 * Check to see whether the user has asked for an offset
859 		 * past the end of our list.
860 		 */
861 		if (cio->offset >= pci_numdevs) {
862 			cio->status = PCI_GETCONF_LAST_DEVICE;
863 			error = 0;
864 			goto getconfexit;
865 		}
866 
867 		/* get the head of the device queue */
868 		devlist_head = &pci_devq;
869 
870 		/*
871 		 * Determine how much room we have for pci_conf structures.
872 		 * Round the user's buffer size down to the nearest
873 		 * multiple of sizeof(struct pci_conf) in case the user
874 		 * didn't specify a multiple of that size.
875 		 */
876 		confsz = pci_conf_size(cmd);
877 		iolen = min(cio->match_buf_len - (cio->match_buf_len % confsz),
878 		    pci_numdevs * confsz);
879 
880 		/*
881 		 * Since we know that iolen is a multiple of the size of
882 		 * the pciconf union, it's okay to do this.
883 		 */
884 		ionum = iolen / confsz;
885 
886 		/*
887 		 * If this test is true, the user wants the pci_conf
888 		 * structures returned to match the supplied entries.
889 		 */
890 		if ((cio->num_patterns > 0) && (cio->num_patterns < pci_numdevs)
891 		 && (cio->pat_buf_len > 0)) {
892 			/*
893 			 * pat_buf_len needs to be:
894 			 * num_patterns * sizeof(struct pci_match_conf)
895 			 * While it is certainly possible the user just
896 			 * allocated a large buffer, but set the number of
897 			 * matches correctly, it is far more likely that
898 			 * their kernel doesn't match the userland utility
899 			 * they're using.  It's also possible that the user
900 			 * forgot to initialize some variables.  Yes, this
901 			 * may be overly picky, but I hazard to guess that
902 			 * it's far more likely to just catch folks that
903 			 * updated their kernel but not their userland.
904 			 */
905 			if (cio->num_patterns * pci_match_conf_size(cmd) !=
906 			    cio->pat_buf_len) {
907 				/* The user made a mistake, return an error. */
908 				cio->status = PCI_GETCONF_ERROR;
909 				error = EINVAL;
910 				goto getconfexit;
911 			}
912 
913 			/*
914 			 * Allocate a buffer to hold the patterns.
915 			 */
916 			pattern_buf = malloc(cio->pat_buf_len, M_TEMP,
917 			    M_WAITOK);
918 			error = copyin(cio->patterns, pattern_buf,
919 			    cio->pat_buf_len);
920 			if (error != 0) {
921 				error = EINVAL;
922 				goto getconfexit;
923 			}
924 			num_patterns = cio->num_patterns;
925 		} else if ((cio->num_patterns > 0)
926 			|| (cio->pat_buf_len > 0)) {
927 			/*
928 			 * The user made a mistake, spit out an error.
929 			 */
930 			cio->status = PCI_GETCONF_ERROR;
931 			error = EINVAL;
932                        goto getconfexit;
933 		}
934 
935 		/*
936 		 * Go through the list of devices and copy out the devices
937 		 * that match the user's criteria.
938 		 */
939 		for (cio->num_matches = 0, i = 0,
940 				 dinfo = STAILQ_FIRST(devlist_head);
941 		     dinfo != NULL;
942 		     dinfo = STAILQ_NEXT(dinfo, pci_links), i++) {
943 
944 			if (i < cio->offset)
945 				continue;
946 
947 			/* Populate pd_name and pd_unit */
948 			name = NULL;
949 			if (dinfo->cfg.dev)
950 				name = device_get_name(dinfo->cfg.dev);
951 			if (name) {
952 				strncpy(dinfo->conf.pd_name, name,
953 					sizeof(dinfo->conf.pd_name));
954 				dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0;
955 				dinfo->conf.pd_unit =
956 					device_get_unit(dinfo->cfg.dev);
957 			} else {
958 				dinfo->conf.pd_name[0] = '\0';
959 				dinfo->conf.pd_unit = 0;
960 			}
961 
962 			if (pattern_buf == NULL ||
963 			    pci_conf_match(cmd, pattern_buf, num_patterns,
964 			    &dinfo->conf) == 0) {
965 				/*
966 				 * If we've filled up the user's buffer,
967 				 * break out at this point.  Since we've
968 				 * got a match here, we'll pick right back
969 				 * up at the matching entry.  We can also
970 				 * tell the user that there are more matches
971 				 * left.
972 				 */
973 				if (cio->num_matches >= ionum) {
974 					error = 0;
975 					break;
976 				}
977 
978 				pci_conf_for_copyout(&dinfo->conf, &pcu, cmd);
979 				error = copyout(&pcu,
980 				    (caddr_t)cio->matches +
981 				    confsz * cio->num_matches, confsz);
982 				if (error)
983 					break;
984 				cio->num_matches++;
985 			}
986 		}
987 
988 		/*
989 		 * Set the pointer into the list, so if the user is getting
990 		 * n records at a time, where n < pci_numdevs,
991 		 */
992 		cio->offset = i;
993 
994 		/*
995 		 * Set the generation, the user will need this if they make
996 		 * another ioctl call with offset != 0.
997 		 */
998 		cio->generation = pci_generation;
999 
1000 		/*
1001 		 * If this is the last device, inform the user so he won't
1002 		 * bother asking for more devices.  If dinfo isn't NULL, we
1003 		 * know that there are more matches in the list because of
1004 		 * the way the traversal is done.
1005 		 */
1006 		if (dinfo == NULL)
1007 			cio->status = PCI_GETCONF_LAST_DEVICE;
1008 		else
1009 			cio->status = PCI_GETCONF_MORE_DEVS;
1010 
1011 getconfexit:
1012 		pci_conf_io_update_data(cio, data, cmd);
1013 		free(cio, M_TEMP);
1014 		free(pattern_buf, M_TEMP);
1015 
1016 		break;
1017 
1018 #ifdef PRE7_COMPAT
1019 	case PCIOCREAD_OLD:
1020 	case PCIOCWRITE_OLD:
1021 		io_old = (struct pci_io_old *)data;
1022 		iodata.pi_sel.pc_domain = 0;
1023 		iodata.pi_sel.pc_bus = io_old->pi_sel.pc_bus;
1024 		iodata.pi_sel.pc_dev = io_old->pi_sel.pc_dev;
1025 		iodata.pi_sel.pc_func = io_old->pi_sel.pc_func;
1026 		iodata.pi_reg = io_old->pi_reg;
1027 		iodata.pi_width = io_old->pi_width;
1028 		iodata.pi_data = io_old->pi_data;
1029 		data = (caddr_t)&iodata;
1030 		/* FALLTHROUGH */
1031 #endif
1032 	case PCIOCREAD:
1033 	case PCIOCWRITE:
1034 		io = (struct pci_io *)data;
1035 		switch(io->pi_width) {
1036 		case 4:
1037 		case 2:
1038 		case 1:
1039 			/* Make sure register is not negative and aligned. */
1040 			if (io->pi_reg < 0 ||
1041 			    io->pi_reg & (io->pi_width - 1)) {
1042 				error = EINVAL;
1043 				break;
1044 			}
1045 			/*
1046 			 * Assume that the user-level bus number is
1047 			 * in fact the physical PCI bus number.
1048 			 * Look up the grandparent, i.e. the bridge device,
1049 			 * so that we can issue configuration space cycles.
1050 			 */
1051 			pcidev = pci_find_dbsf(io->pi_sel.pc_domain,
1052 			    io->pi_sel.pc_bus, io->pi_sel.pc_dev,
1053 			    io->pi_sel.pc_func);
1054 			if (pcidev) {
1055 #ifdef PRE7_COMPAT
1056 				if (cmd == PCIOCWRITE || cmd == PCIOCWRITE_OLD)
1057 #else
1058 				if (cmd == PCIOCWRITE)
1059 #endif
1060 					pci_write_config(pcidev,
1061 							  io->pi_reg,
1062 							  io->pi_data,
1063 							  io->pi_width);
1064 #ifdef PRE7_COMPAT
1065 				else if (cmd == PCIOCREAD_OLD)
1066 					io_old->pi_data =
1067 						pci_read_config(pcidev,
1068 							  io->pi_reg,
1069 							  io->pi_width);
1070 #endif
1071 				else
1072 					io->pi_data =
1073 						pci_read_config(pcidev,
1074 							  io->pi_reg,
1075 							  io->pi_width);
1076 				error = 0;
1077 			} else {
1078 #ifdef COMPAT_FREEBSD4
1079 				if (cmd == PCIOCREAD_OLD) {
1080 					io_old->pi_data = -1;
1081 					error = 0;
1082 				} else
1083 #endif
1084 					error = ENODEV;
1085 			}
1086 			break;
1087 		default:
1088 			error = EINVAL;
1089 			break;
1090 		}
1091 		break;
1092 
1093 	case PCIOCGETBAR:
1094 		bio = (struct pci_bar_io *)data;
1095 
1096 		/*
1097 		 * Assume that the user-level bus number is
1098 		 * in fact the physical PCI bus number.
1099 		 */
1100 		pcidev = pci_find_dbsf(bio->pbi_sel.pc_domain,
1101 		    bio->pbi_sel.pc_bus, bio->pbi_sel.pc_dev,
1102 		    bio->pbi_sel.pc_func);
1103 		if (pcidev == NULL) {
1104 			error = ENODEV;
1105 			break;
1106 		}
1107 		pm = pci_find_bar(pcidev, bio->pbi_reg);
1108 		if (pm == NULL) {
1109 			error = EINVAL;
1110 			break;
1111 		}
1112 		bio->pbi_base = pm->pm_value;
1113 		bio->pbi_length = (pci_addr_t)1 << pm->pm_size;
1114 		bio->pbi_enabled = pci_bar_enabled(pcidev, pm);
1115 		error = 0;
1116 		break;
1117 	case PCIOCATTACHED:
1118 		error = 0;
1119 		io = (struct pci_io *)data;
1120 		pcidev = pci_find_dbsf(io->pi_sel.pc_domain, io->pi_sel.pc_bus,
1121 				       io->pi_sel.pc_dev, io->pi_sel.pc_func);
1122 		if (pcidev != NULL)
1123 			io->pi_data = device_is_attached(pcidev);
1124 		else
1125 			error = ENODEV;
1126 		break;
1127 	case PCIOCLISTVPD:
1128 		lvio = (struct pci_list_vpd_io *)data;
1129 
1130 		/*
1131 		 * Assume that the user-level bus number is
1132 		 * in fact the physical PCI bus number.
1133 		 */
1134 		pcidev = pci_find_dbsf(lvio->plvi_sel.pc_domain,
1135 		    lvio->plvi_sel.pc_bus, lvio->plvi_sel.pc_dev,
1136 		    lvio->plvi_sel.pc_func);
1137 		if (pcidev == NULL) {
1138 			error = ENODEV;
1139 			break;
1140 		}
1141 		error = pci_list_vpd(pcidev, lvio);
1142 		break;
1143 
1144 	case PCIOCBARMMAP:
1145 		pbm = (struct pci_bar_mmap *)data;
1146 		if ((flag & FWRITE) == 0 &&
1147 		    (pbm->pbm_flags & PCIIO_BAR_MMAP_RW) != 0)
1148 			return (EPERM);
1149 		pcidev = pci_find_dbsf(pbm->pbm_sel.pc_domain,
1150 		    pbm->pbm_sel.pc_bus, pbm->pbm_sel.pc_dev,
1151 		    pbm->pbm_sel.pc_func);
1152 		error = pcidev == NULL ? ENODEV : pci_bar_mmap(pcidev, pbm);
1153 		break;
1154 
1155 	default:
1156 		error = ENOTTY;
1157 		break;
1158 	}
1159 
1160 	return (error);
1161 }
1162