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