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