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