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