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