]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/pci/pci_user.c
Move most of the contents of opt_compat.h to opt_global.h.
[FreeBSD/FreeBSD.git] / sys / dev / pci / pci_user.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice unmodified, this list of conditions, and the following
12  *    disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include "opt_bus.h"    /* XXX trim includes */
33
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/proc.h>
43 #include <sys/queue.h>
44 #include <sys/types.h>
45
46 #include <vm/vm.h>
47 #include <vm/pmap.h>
48 #include <vm/vm_extern.h>
49
50 #include <sys/bus.h>
51 #include <machine/bus.h>
52 #include <sys/rman.h>
53 #include <machine/resource.h>
54
55 #include <sys/pciio.h>
56 #include <dev/pci/pcireg.h>
57 #include <dev/pci/pcivar.h>
58
59 #include "pcib_if.h"
60 #include "pci_if.h"
61
62 /*
63  * This is the user interface to PCI configuration space.
64  */
65
66 static d_open_t         pci_open;
67 static d_close_t        pci_close;
68 static int      pci_conf_match(struct pci_match_conf *matches, int num_matches,
69                                struct pci_conf *match_buf);
70 static d_ioctl_t        pci_ioctl;
71
72 struct cdevsw pcicdev = {
73         .d_version =    D_VERSION,
74         .d_flags =      D_NEEDGIANT,
75         .d_open =       pci_open,
76         .d_close =      pci_close,
77         .d_ioctl =      pci_ioctl,
78         .d_name =       "pci",
79 };
80   
81 static int
82 pci_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
83 {
84         int error;
85
86         if (oflags & FWRITE) {
87                 error = securelevel_gt(td->td_ucred, 0);
88                 if (error)
89                         return (error);
90         }
91
92         return (0);
93 }
94
95 static int
96 pci_close(struct cdev *dev, int flag, int devtype, struct thread *td)
97 {
98         return 0;
99 }
100
101 /*
102  * Match a single pci_conf structure against an array of pci_match_conf
103  * structures.  The first argument, 'matches', is an array of num_matches
104  * pci_match_conf structures.  match_buf is a pointer to the pci_conf
105  * structure that will be compared to every entry in the matches array.
106  * This function returns 1 on failure, 0 on success.
107  */
108 static int
109 pci_conf_match(struct pci_match_conf *matches, int num_matches, 
110                struct pci_conf *match_buf)
111 {
112         int i;
113
114         if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
115                 return(1);
116
117         for (i = 0; i < num_matches; i++) {
118                 /*
119                  * I'm not sure why someone would do this...but...
120                  */
121                 if (matches[i].flags == PCI_GETCONF_NO_MATCH)
122                         continue;
123
124                 /*
125                  * Look at each of the match flags.  If it's set, do the
126                  * comparison.  If the comparison fails, we don't have a
127                  * match, go on to the next item if there is one.
128                  */
129                 if (((matches[i].flags & PCI_GETCONF_MATCH_DOMAIN) != 0)
130                  && (match_buf->pc_sel.pc_domain !=
131                  matches[i].pc_sel.pc_domain))
132                         continue;
133
134                 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0)
135                  && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
136                         continue;
137
138                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0)
139                  && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
140                         continue;
141
142                 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0)
143                  && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
144                         continue;
145
146                 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0) 
147                  && (match_buf->pc_vendor != matches[i].pc_vendor))
148                         continue;
149
150                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0)
151                  && (match_buf->pc_device != matches[i].pc_device))
152                         continue;
153
154                 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0)
155                  && (match_buf->pc_class != matches[i].pc_class))
156                         continue;
157
158                 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0)
159                  && (match_buf->pd_unit != matches[i].pd_unit))
160                         continue;
161
162                 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0)
163                  && (strncmp(matches[i].pd_name, match_buf->pd_name,
164                              sizeof(match_buf->pd_name)) != 0))
165                         continue;
166
167                 return(0);
168         }
169
170         return(1);
171 }
172
173 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
174     defined(COMPAT_FREEBSD6)
175 #define PRE7_COMPAT
176
177 typedef enum {
178         PCI_GETCONF_NO_MATCH_OLD        = 0x00,
179         PCI_GETCONF_MATCH_BUS_OLD       = 0x01,
180         PCI_GETCONF_MATCH_DEV_OLD       = 0x02,
181         PCI_GETCONF_MATCH_FUNC_OLD      = 0x04,
182         PCI_GETCONF_MATCH_NAME_OLD      = 0x08,
183         PCI_GETCONF_MATCH_UNIT_OLD      = 0x10,
184         PCI_GETCONF_MATCH_VENDOR_OLD    = 0x20,
185         PCI_GETCONF_MATCH_DEVICE_OLD    = 0x40,
186         PCI_GETCONF_MATCH_CLASS_OLD     = 0x80
187 } pci_getconf_flags_old;
188
189 struct pcisel_old {
190         u_int8_t        pc_bus;         /* bus number */
191         u_int8_t        pc_dev;         /* device on this bus */
192         u_int8_t        pc_func;        /* function on this device */
193 };
194
195 struct pci_conf_old {
196         struct pcisel_old pc_sel;       /* bus+slot+function */
197         u_int8_t        pc_hdr;         /* PCI header type */
198         u_int16_t       pc_subvendor;   /* card vendor ID */
199         u_int16_t       pc_subdevice;   /* card device ID, assigned by
200                                            card vendor */
201         u_int16_t       pc_vendor;      /* chip vendor ID */
202         u_int16_t       pc_device;      /* chip device ID, assigned by
203                                            chip vendor */
204         u_int8_t        pc_class;       /* chip PCI class */
205         u_int8_t        pc_subclass;    /* chip PCI subclass */
206         u_int8_t        pc_progif;      /* chip PCI programming interface */
207         u_int8_t        pc_revid;       /* chip revision ID */
208         char            pd_name[PCI_MAXNAMELEN + 1];  /* device name */
209         u_long          pd_unit;        /* device unit number */
210 };
211
212 struct pci_match_conf_old {
213         struct pcisel_old       pc_sel;         /* bus+slot+function */
214         char                    pd_name[PCI_MAXNAMELEN + 1];  /* device name */
215         u_long                  pd_unit;        /* Unit number */
216         u_int16_t               pc_vendor;      /* PCI Vendor ID */
217         u_int16_t               pc_device;      /* PCI Device ID */
218         u_int8_t                pc_class;       /* PCI class */
219         pci_getconf_flags_old   flags;          /* Matching expression */
220 };
221
222 struct pci_io_old {
223         struct pcisel_old pi_sel;       /* device to operate on */
224         int             pi_reg;         /* configuration register to examine */
225         int             pi_width;       /* width (in bytes) of read or write */
226         u_int32_t       pi_data;        /* data to write or result of read */
227 };
228
229 #ifdef COMPAT_FREEBSD32
230 struct pci_conf_old32 {
231         struct pcisel_old pc_sel;       /* bus+slot+function */
232         uint8_t         pc_hdr;         /* PCI header type */
233         uint16_t        pc_subvendor;   /* card vendor ID */
234         uint16_t        pc_subdevice;   /* card device ID, assigned by
235                                            card vendor */
236         uint16_t        pc_vendor;      /* chip vendor ID */
237         uint16_t        pc_device;      /* chip device ID, assigned by
238                                            chip vendor */
239         uint8_t         pc_class;       /* chip PCI class */
240         uint8_t         pc_subclass;    /* chip PCI subclass */
241         uint8_t         pc_progif;      /* chip PCI programming interface */
242         uint8_t         pc_revid;       /* chip revision ID */
243         char            pd_name[PCI_MAXNAMELEN + 1]; /* device name */
244         uint32_t        pd_unit;        /* device unit number (u_long) */
245 };
246
247 struct pci_match_conf_old32 {
248         struct pcisel_old pc_sel;       /* bus+slot+function */
249         char            pd_name[PCI_MAXNAMELEN + 1]; /* device name */
250         uint32_t        pd_unit;        /* Unit number (u_long) */
251         uint16_t        pc_vendor;      /* PCI Vendor ID */
252         uint16_t        pc_device;      /* PCI Device ID */
253         uint8_t         pc_class;       /* PCI class */
254         pci_getconf_flags_old flags;    /* Matching expression */
255 };
256
257 struct pci_conf_io32 {
258         uint32_t        pat_buf_len;    /* pattern buffer length */
259         uint32_t        num_patterns;   /* number of patterns */
260         uint32_t        patterns;       /* pattern buffer
261                                            (struct pci_match_conf_old32 *) */
262         uint32_t        match_buf_len;  /* match buffer length */
263         uint32_t        num_matches;    /* number of matches returned */
264         uint32_t        matches;        /* match buffer
265                                            (struct pci_conf_old32 *) */
266         uint32_t        offset;         /* offset into device list */
267         uint32_t        generation;     /* device list generation */
268         pci_getconf_status status;      /* request status */
269 };
270
271 #define PCIOCGETCONF_OLD32      _IOWR('p', 1, struct pci_conf_io32)
272 #endif  /* COMPAT_FREEBSD32 */
273
274 #define PCIOCGETCONF_OLD        _IOWR('p', 1, struct pci_conf_io)
275 #define PCIOCREAD_OLD           _IOWR('p', 2, struct pci_io_old)
276 #define PCIOCWRITE_OLD          _IOWR('p', 3, struct pci_io_old)
277
278 static int      pci_conf_match_old(struct pci_match_conf_old *matches,
279                     int num_matches, struct pci_conf *match_buf);
280
281 static int
282 pci_conf_match_old(struct pci_match_conf_old *matches, int num_matches,
283     struct pci_conf *match_buf)
284 {
285         int i;
286
287         if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
288                 return(1);
289
290         for (i = 0; i < num_matches; i++) {
291                 if (match_buf->pc_sel.pc_domain != 0)
292                         continue;
293
294                 /*
295                  * I'm not sure why someone would do this...but...
296                  */
297                 if (matches[i].flags == PCI_GETCONF_NO_MATCH_OLD)
298                         continue;
299
300                 /*
301                  * Look at each of the match flags.  If it's set, do the
302                  * comparison.  If the comparison fails, we don't have a
303                  * match, go on to the next item if there is one.
304                  */
305                 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_OLD) != 0)
306                  && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
307                         continue;
308
309                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_OLD) != 0)
310                  && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
311                         continue;
312
313                 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_OLD) != 0)
314                  && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
315                         continue;
316
317                 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_OLD) != 0)
318                  && (match_buf->pc_vendor != matches[i].pc_vendor))
319                         continue;
320
321                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_OLD) != 0)
322                  && (match_buf->pc_device != matches[i].pc_device))
323                         continue;
324
325                 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_OLD) != 0)
326                  && (match_buf->pc_class != matches[i].pc_class))
327                         continue;
328
329                 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_OLD) != 0)
330                  && (match_buf->pd_unit != matches[i].pd_unit))
331                         continue;
332
333                 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_OLD) != 0)
334                  && (strncmp(matches[i].pd_name, match_buf->pd_name,
335                              sizeof(match_buf->pd_name)) != 0))
336                         continue;
337
338                 return(0);
339         }
340
341         return(1);
342 }
343
344 #ifdef COMPAT_FREEBSD32
345 static int
346 pci_conf_match_old32(struct pci_match_conf_old32 *matches, int num_matches,
347     struct pci_conf *match_buf)
348 {
349         int i;
350
351         if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
352                 return(1);
353
354         for (i = 0; i < num_matches; i++) {
355                 if (match_buf->pc_sel.pc_domain != 0)
356                         continue;
357
358                 /*
359                  * I'm not sure why someone would do this...but...
360                  */
361                 if (matches[i].flags == PCI_GETCONF_NO_MATCH_OLD)
362                         continue;
363
364                 /*
365                  * Look at each of the match flags.  If it's set, do the
366                  * comparison.  If the comparison fails, we don't have a
367                  * match, go on to the next item if there is one.
368                  */
369                 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_OLD) != 0) &&
370                     (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
371                         continue;
372
373                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_OLD) != 0) &&
374                     (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
375                         continue;
376
377                 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_OLD) != 0) &&
378                     (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
379                         continue;
380
381                 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_OLD) != 0) &&
382                     (match_buf->pc_vendor != matches[i].pc_vendor))
383                         continue;
384
385                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_OLD) != 0) &&
386                     (match_buf->pc_device != matches[i].pc_device))
387                         continue;
388
389                 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_OLD) != 0) &&
390                     (match_buf->pc_class != matches[i].pc_class))
391                         continue;
392
393                 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_OLD) != 0) &&
394                     ((u_int32_t)match_buf->pd_unit != matches[i].pd_unit))
395                         continue;
396
397                 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_OLD) != 0) &&
398                     (strncmp(matches[i].pd_name, match_buf->pd_name,
399                     sizeof(match_buf->pd_name)) != 0))
400                         continue;
401
402                 return (0);
403         }
404
405         return (1);
406 }
407 #endif  /* COMPAT_FREEBSD32 */
408 #endif  /* PRE7_COMPAT */
409
410 static int
411 pci_list_vpd(device_t dev, struct pci_list_vpd_io *lvio)
412 {
413         struct pci_vpd_element vpd_element, *vpd_user;
414         struct pcicfg_vpd *vpd;
415         size_t len;
416         int error, i;
417
418         vpd = pci_fetch_vpd_list(dev);
419         if (vpd->vpd_reg == 0 || vpd->vpd_ident == NULL)
420                 return (ENXIO);
421
422         /*
423          * Calculate the amount of space needed in the data buffer.  An
424          * identifier element is always present followed by the read-only
425          * and read-write keywords.
426          */
427         len = sizeof(struct pci_vpd_element) + strlen(vpd->vpd_ident);
428         for (i = 0; i < vpd->vpd_rocnt; i++)
429                 len += sizeof(struct pci_vpd_element) + vpd->vpd_ros[i].len;
430         for (i = 0; i < vpd->vpd_wcnt; i++)
431                 len += sizeof(struct pci_vpd_element) + vpd->vpd_w[i].len;
432
433         if (lvio->plvi_len == 0) {
434                 lvio->plvi_len = len;
435                 return (0);
436         }
437         if (lvio->plvi_len < len) {
438                 lvio->plvi_len = len;
439                 return (ENOMEM);
440         }
441
442         /*
443          * Copyout the identifier string followed by each keyword and
444          * value.
445          */
446         vpd_user = lvio->plvi_data;
447         vpd_element.pve_keyword[0] = '\0';
448         vpd_element.pve_keyword[1] = '\0';
449         vpd_element.pve_flags = PVE_FLAG_IDENT;
450         vpd_element.pve_datalen = strlen(vpd->vpd_ident);
451         error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
452         if (error)
453                 return (error);
454         error = copyout(vpd->vpd_ident, vpd_user->pve_data,
455             strlen(vpd->vpd_ident));
456         if (error)
457                 return (error);
458         vpd_user = PVE_NEXT(vpd_user);
459         vpd_element.pve_flags = 0;
460         for (i = 0; i < vpd->vpd_rocnt; i++) {
461                 vpd_element.pve_keyword[0] = vpd->vpd_ros[i].keyword[0];
462                 vpd_element.pve_keyword[1] = vpd->vpd_ros[i].keyword[1];
463                 vpd_element.pve_datalen = vpd->vpd_ros[i].len;
464                 error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
465                 if (error)
466                         return (error);
467                 error = copyout(vpd->vpd_ros[i].value, vpd_user->pve_data,
468                     vpd->vpd_ros[i].len);
469                 if (error)
470                         return (error);
471                 vpd_user = PVE_NEXT(vpd_user);
472         }
473         vpd_element.pve_flags = PVE_FLAG_RW;
474         for (i = 0; i < vpd->vpd_wcnt; i++) {
475                 vpd_element.pve_keyword[0] = vpd->vpd_w[i].keyword[0];
476                 vpd_element.pve_keyword[1] = vpd->vpd_w[i].keyword[1];
477                 vpd_element.pve_datalen = vpd->vpd_w[i].len;
478                 error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
479                 if (error)
480                         return (error);
481                 error = copyout(vpd->vpd_w[i].value, vpd_user->pve_data,
482                     vpd->vpd_w[i].len);
483                 if (error)
484                         return (error);
485                 vpd_user = PVE_NEXT(vpd_user);
486         }
487         KASSERT((char *)vpd_user - (char *)lvio->plvi_data == len,
488             ("length mismatch"));
489         lvio->plvi_len = len;
490         return (0);
491 }
492
493 static int
494 pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
495 {
496         device_t pcidev;
497         void *confdata;
498         const char *name;
499         struct devlist *devlist_head;
500         struct pci_conf_io *cio = NULL;
501         struct pci_devinfo *dinfo;
502         struct pci_io *io;
503         struct pci_bar_io *bio;
504         struct pci_list_vpd_io *lvio;
505         struct pci_match_conf *pattern_buf;
506         struct pci_map *pm;
507         size_t confsz, iolen, pbufsz;
508         int error, ionum, i, num_patterns;
509 #ifdef PRE7_COMPAT
510 #ifdef COMPAT_FREEBSD32
511         struct pci_conf_io32 *cio32 = NULL;
512         struct pci_conf_old32 conf_old32;
513         struct pci_match_conf_old32 *pattern_buf_old32 = NULL;
514 #endif
515         struct pci_conf_old conf_old;
516         struct pci_io iodata;
517         struct pci_io_old *io_old;
518         struct pci_match_conf_old *pattern_buf_old = NULL;
519
520         io_old = NULL;
521 #endif
522
523         if (!(flag & FWRITE)) {
524                 switch (cmd) {
525 #ifdef PRE7_COMPAT
526 #ifdef COMPAT_FREEBSD32
527                 case PCIOCGETCONF_OLD32:
528 #endif
529                 case PCIOCGETCONF_OLD:
530 #endif
531                 case PCIOCGETCONF:
532                 case PCIOCGETBAR:
533                 case PCIOCLISTVPD:
534                         break;
535                 default:
536                         return (EPERM);
537                 }
538         }
539
540         switch (cmd) {
541 #ifdef PRE7_COMPAT
542 #ifdef COMPAT_FREEBSD32
543         case PCIOCGETCONF_OLD32:
544                cio32 = (struct pci_conf_io32 *)data;
545                cio = malloc(sizeof(struct pci_conf_io), M_TEMP, M_WAITOK);
546                cio->pat_buf_len = cio32->pat_buf_len;
547                cio->num_patterns = cio32->num_patterns;
548                cio->patterns = (void *)(uintptr_t)cio32->patterns;
549                cio->match_buf_len = cio32->match_buf_len;
550                cio->num_matches = cio32->num_matches;
551                cio->matches = (void *)(uintptr_t)cio32->matches;
552                cio->offset = cio32->offset;
553                cio->generation = cio32->generation;
554                cio->status = cio32->status;
555                cio32->num_matches = 0;
556                break;
557 #endif
558         case PCIOCGETCONF_OLD:
559 #endif
560         case PCIOCGETCONF:
561                 cio = (struct pci_conf_io *)data;
562         }
563
564         switch (cmd) {
565 #ifdef PRE7_COMPAT
566 #ifdef COMPAT_FREEBSD32
567         case PCIOCGETCONF_OLD32:
568 #endif
569         case PCIOCGETCONF_OLD:
570 #endif
571         case PCIOCGETCONF:
572
573                 pattern_buf = NULL;
574                 num_patterns = 0;
575                 dinfo = NULL;
576
577                 cio->num_matches = 0;
578
579                 /*
580                  * If the user specified an offset into the device list,
581                  * but the list has changed since they last called this
582                  * ioctl, tell them that the list has changed.  They will
583                  * have to get the list from the beginning.
584                  */
585                 if ((cio->offset != 0)
586                  && (cio->generation != pci_generation)){
587                         cio->status = PCI_GETCONF_LIST_CHANGED;
588                         error = 0;
589                         goto getconfexit;
590                 }
591
592                 /*
593                  * Check to see whether the user has asked for an offset
594                  * past the end of our list.
595                  */
596                 if (cio->offset >= pci_numdevs) {
597                         cio->status = PCI_GETCONF_LAST_DEVICE;
598                         error = 0;
599                         goto getconfexit;
600                 }
601
602                 /* get the head of the device queue */
603                 devlist_head = &pci_devq;
604
605                 /*
606                  * Determine how much room we have for pci_conf structures.
607                  * Round the user's buffer size down to the nearest
608                  * multiple of sizeof(struct pci_conf) in case the user
609                  * didn't specify a multiple of that size.
610                  */
611 #ifdef PRE7_COMPAT
612 #ifdef COMPAT_FREEBSD32
613                 if (cmd == PCIOCGETCONF_OLD32)
614                         confsz = sizeof(struct pci_conf_old32);
615                 else
616 #endif
617                 if (cmd == PCIOCGETCONF_OLD)
618                         confsz = sizeof(struct pci_conf_old);
619                 else
620 #endif
621                         confsz = sizeof(struct pci_conf);
622                 iolen = min(cio->match_buf_len - (cio->match_buf_len % confsz),
623                     pci_numdevs * confsz);
624
625                 /*
626                  * Since we know that iolen is a multiple of the size of
627                  * the pciconf union, it's okay to do this.
628                  */
629                 ionum = iolen / confsz;
630
631                 /*
632                  * If this test is true, the user wants the pci_conf
633                  * structures returned to match the supplied entries.
634                  */
635                 if ((cio->num_patterns > 0) && (cio->num_patterns < pci_numdevs)
636                  && (cio->pat_buf_len > 0)) {
637                         /*
638                          * pat_buf_len needs to be:
639                          * num_patterns * sizeof(struct pci_match_conf)
640                          * While it is certainly possible the user just
641                          * allocated a large buffer, but set the number of
642                          * matches correctly, it is far more likely that
643                          * their kernel doesn't match the userland utility
644                          * they're using.  It's also possible that the user
645                          * forgot to initialize some variables.  Yes, this
646                          * may be overly picky, but I hazard to guess that
647                          * it's far more likely to just catch folks that
648                          * updated their kernel but not their userland.
649                          */
650 #ifdef PRE7_COMPAT
651 #ifdef COMPAT_FREEBSD32
652                         if (cmd == PCIOCGETCONF_OLD32)
653                                 pbufsz = sizeof(struct pci_match_conf_old32);
654                         else
655 #endif
656                         if (cmd == PCIOCGETCONF_OLD)
657                                 pbufsz = sizeof(struct pci_match_conf_old);
658                         else
659 #endif
660                                 pbufsz = sizeof(struct pci_match_conf);
661                         if (cio->num_patterns * pbufsz != cio->pat_buf_len) {
662                                 /* The user made a mistake, return an error. */
663                                 cio->status = PCI_GETCONF_ERROR;
664                                 error = EINVAL;
665                                 goto getconfexit;
666                         }
667
668                         /*
669                          * Allocate a buffer to hold the patterns.
670                          */
671 #ifdef PRE7_COMPAT
672 #ifdef COMPAT_FREEBSD32
673                         if (cmd == PCIOCGETCONF_OLD32) {
674                                 pattern_buf_old32 = malloc(cio->pat_buf_len,
675                                     M_TEMP, M_WAITOK);
676                                 error = copyin(cio->patterns,
677                                     pattern_buf_old32, cio->pat_buf_len);
678                         } else
679 #endif /* COMPAT_FREEBSD32 */
680                         if (cmd == PCIOCGETCONF_OLD) {
681                                 pattern_buf_old = malloc(cio->pat_buf_len,
682                                     M_TEMP, M_WAITOK);
683                                 error = copyin(cio->patterns,
684                                     pattern_buf_old, cio->pat_buf_len);
685                         } else
686 #endif /* PRE7_COMPAT */
687                         {
688                                 pattern_buf = malloc(cio->pat_buf_len, M_TEMP,
689                                     M_WAITOK);
690                                 error = copyin(cio->patterns, pattern_buf,
691                                     cio->pat_buf_len);
692                         }
693                         if (error != 0) {
694                                 error = EINVAL;
695                                 goto getconfexit;
696                         }
697                         num_patterns = cio->num_patterns;
698                 } else if ((cio->num_patterns > 0)
699                         || (cio->pat_buf_len > 0)) {
700                         /*
701                          * The user made a mistake, spit out an error.
702                          */
703                         cio->status = PCI_GETCONF_ERROR;
704                         error = EINVAL;
705                        goto getconfexit;
706                 }
707
708                 /*
709                  * Go through the list of devices and copy out the devices
710                  * that match the user's criteria.
711                  */
712                 for (cio->num_matches = 0, i = 0,
713                                  dinfo = STAILQ_FIRST(devlist_head);
714                      dinfo != NULL;
715                      dinfo = STAILQ_NEXT(dinfo, pci_links), i++) {
716
717                         if (i < cio->offset)
718                                 continue;
719
720                         /* Populate pd_name and pd_unit */
721                         name = NULL;
722                         if (dinfo->cfg.dev)
723                                 name = device_get_name(dinfo->cfg.dev);
724                         if (name) {
725                                 strncpy(dinfo->conf.pd_name, name,
726                                         sizeof(dinfo->conf.pd_name));
727                                 dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0;
728                                 dinfo->conf.pd_unit =
729                                         device_get_unit(dinfo->cfg.dev);
730                         } else {
731                                 dinfo->conf.pd_name[0] = '\0';
732                                 dinfo->conf.pd_unit = 0;
733                         }
734
735 #ifdef PRE7_COMPAT
736                         if (
737 #ifdef COMPAT_FREEBSD32
738                             (cmd == PCIOCGETCONF_OLD32 &&
739                             (pattern_buf_old32 == NULL ||
740                             pci_conf_match_old32(pattern_buf_old32,
741                             num_patterns, &dinfo->conf) == 0)) ||
742 #endif
743                             (cmd == PCIOCGETCONF_OLD &&
744                             (pattern_buf_old == NULL ||
745                             pci_conf_match_old(pattern_buf_old, num_patterns,
746                             &dinfo->conf) == 0)) ||
747                             (cmd == PCIOCGETCONF &&
748                             (pattern_buf == NULL ||
749                             pci_conf_match(pattern_buf, num_patterns,
750                             &dinfo->conf) == 0))) {
751 #else
752                         if (pattern_buf == NULL ||
753                             pci_conf_match(pattern_buf, num_patterns,
754                             &dinfo->conf) == 0) {
755 #endif
756                                 /*
757                                  * If we've filled up the user's buffer,
758                                  * break out at this point.  Since we've
759                                  * got a match here, we'll pick right back
760                                  * up at the matching entry.  We can also
761                                  * tell the user that there are more matches
762                                  * left.
763                                  */
764                                 if (cio->num_matches >= ionum) {
765                                         error = 0;
766                                         break;
767                                 }
768
769 #ifdef PRE7_COMPAT
770 #ifdef COMPAT_FREEBSD32
771                                 if (cmd == PCIOCGETCONF_OLD32) {
772                                         memset(&conf_old32, 0,
773                                             sizeof(conf_old32));
774                                         conf_old32.pc_sel.pc_bus =
775                                             dinfo->conf.pc_sel.pc_bus;
776                                         conf_old32.pc_sel.pc_dev =
777                                             dinfo->conf.pc_sel.pc_dev;
778                                         conf_old32.pc_sel.pc_func =
779                                             dinfo->conf.pc_sel.pc_func;
780                                         conf_old32.pc_hdr = dinfo->conf.pc_hdr;
781                                         conf_old32.pc_subvendor =
782                                             dinfo->conf.pc_subvendor;
783                                         conf_old32.pc_subdevice =
784                                             dinfo->conf.pc_subdevice;
785                                         conf_old32.pc_vendor =
786                                             dinfo->conf.pc_vendor;
787                                         conf_old32.pc_device =
788                                             dinfo->conf.pc_device;
789                                         conf_old32.pc_class =
790                                             dinfo->conf.pc_class;
791                                         conf_old32.pc_subclass =
792                                             dinfo->conf.pc_subclass;
793                                         conf_old32.pc_progif =
794                                             dinfo->conf.pc_progif;
795                                         conf_old32.pc_revid =
796                                             dinfo->conf.pc_revid;
797                                         strncpy(conf_old32.pd_name,
798                                             dinfo->conf.pd_name,
799                                             sizeof(conf_old32.pd_name));
800                                         conf_old32.pd_name[PCI_MAXNAMELEN] = 0;
801                                         conf_old32.pd_unit =
802                                             (uint32_t)dinfo->conf.pd_unit;
803                                         confdata = &conf_old32;
804                                 } else
805 #endif /* COMPAT_FREEBSD32 */
806                                 if (cmd == PCIOCGETCONF_OLD) {
807                                         memset(&conf_old, 0, sizeof(conf_old));
808                                         conf_old.pc_sel.pc_bus =
809                                             dinfo->conf.pc_sel.pc_bus;
810                                         conf_old.pc_sel.pc_dev =
811                                             dinfo->conf.pc_sel.pc_dev;
812                                         conf_old.pc_sel.pc_func =
813                                             dinfo->conf.pc_sel.pc_func;
814                                         conf_old.pc_hdr = dinfo->conf.pc_hdr;
815                                         conf_old.pc_subvendor =
816                                             dinfo->conf.pc_subvendor;
817                                         conf_old.pc_subdevice =
818                                             dinfo->conf.pc_subdevice;
819                                         conf_old.pc_vendor =
820                                             dinfo->conf.pc_vendor;
821                                         conf_old.pc_device =
822                                             dinfo->conf.pc_device;
823                                         conf_old.pc_class =
824                                             dinfo->conf.pc_class;
825                                         conf_old.pc_subclass =
826                                             dinfo->conf.pc_subclass;
827                                         conf_old.pc_progif =
828                                             dinfo->conf.pc_progif;
829                                         conf_old.pc_revid =
830                                             dinfo->conf.pc_revid;
831                                         strncpy(conf_old.pd_name,
832                                             dinfo->conf.pd_name,
833                                             sizeof(conf_old.pd_name));
834                                         conf_old.pd_name[PCI_MAXNAMELEN] = 0;
835                                         conf_old.pd_unit =
836                                             dinfo->conf.pd_unit;
837                                         confdata = &conf_old;
838                                 } else
839 #endif /* PRE7_COMPAT */
840                                         confdata = &dinfo->conf;
841                                 error = copyout(confdata,
842                                     (caddr_t)cio->matches +
843                                     confsz * cio->num_matches, confsz);
844                                 if (error)
845                                         break;
846                                 cio->num_matches++;
847                         }
848                 }
849
850                 /*
851                  * Set the pointer into the list, so if the user is getting
852                  * n records at a time, where n < pci_numdevs,
853                  */
854                 cio->offset = i;
855
856                 /*
857                  * Set the generation, the user will need this if they make
858                  * another ioctl call with offset != 0.
859                  */
860                 cio->generation = pci_generation;
861
862                 /*
863                  * If this is the last device, inform the user so he won't
864                  * bother asking for more devices.  If dinfo isn't NULL, we
865                  * know that there are more matches in the list because of
866                  * the way the traversal is done.
867                  */
868                 if (dinfo == NULL)
869                         cio->status = PCI_GETCONF_LAST_DEVICE;
870                 else
871                         cio->status = PCI_GETCONF_MORE_DEVS;
872
873 getconfexit:
874 #ifdef PRE7_COMPAT
875 #ifdef COMPAT_FREEBSD32
876                 if (cmd == PCIOCGETCONF_OLD32) {
877                         cio32->status = cio->status;
878                         cio32->generation = cio->generation;
879                         cio32->offset = cio->offset;
880                         cio32->num_matches = cio->num_matches;
881                         free(cio, M_TEMP);
882                 }
883                 if (pattern_buf_old32 != NULL)
884                         free(pattern_buf_old32, M_TEMP);
885 #endif
886                 if (pattern_buf_old != NULL)
887                         free(pattern_buf_old, M_TEMP);
888 #endif
889                 if (pattern_buf != NULL)
890                         free(pattern_buf, M_TEMP);
891
892                 break;
893
894 #ifdef PRE7_COMPAT
895         case PCIOCREAD_OLD:
896         case PCIOCWRITE_OLD:
897                 io_old = (struct pci_io_old *)data;
898                 iodata.pi_sel.pc_domain = 0;
899                 iodata.pi_sel.pc_bus = io_old->pi_sel.pc_bus;
900                 iodata.pi_sel.pc_dev = io_old->pi_sel.pc_dev;
901                 iodata.pi_sel.pc_func = io_old->pi_sel.pc_func;
902                 iodata.pi_reg = io_old->pi_reg;
903                 iodata.pi_width = io_old->pi_width;
904                 iodata.pi_data = io_old->pi_data;
905                 data = (caddr_t)&iodata;
906                 /* FALLTHROUGH */
907 #endif
908         case PCIOCREAD:
909         case PCIOCWRITE:
910                 io = (struct pci_io *)data;
911                 switch(io->pi_width) {
912                 case 4:
913                 case 2:
914                 case 1:
915                         /* Make sure register is not negative and aligned. */
916                         if (io->pi_reg < 0 ||
917                             io->pi_reg & (io->pi_width - 1)) {
918                                 error = EINVAL;
919                                 break;
920                         }
921                         /*
922                          * Assume that the user-level bus number is
923                          * in fact the physical PCI bus number.
924                          * Look up the grandparent, i.e. the bridge device,
925                          * so that we can issue configuration space cycles.
926                          */
927                         pcidev = pci_find_dbsf(io->pi_sel.pc_domain,
928                             io->pi_sel.pc_bus, io->pi_sel.pc_dev,
929                             io->pi_sel.pc_func);
930                         if (pcidev) {
931 #ifdef PRE7_COMPAT
932                                 if (cmd == PCIOCWRITE || cmd == PCIOCWRITE_OLD)
933 #else
934                                 if (cmd == PCIOCWRITE)
935 #endif
936                                         pci_write_config(pcidev,
937                                                           io->pi_reg,
938                                                           io->pi_data,
939                                                           io->pi_width);
940 #ifdef PRE7_COMPAT
941                                 else if (cmd == PCIOCREAD_OLD)
942                                         io_old->pi_data =
943                                                 pci_read_config(pcidev,
944                                                           io->pi_reg,
945                                                           io->pi_width);
946 #endif
947                                 else
948                                         io->pi_data =
949                                                 pci_read_config(pcidev,
950                                                           io->pi_reg,
951                                                           io->pi_width);
952                                 error = 0;
953                         } else {
954 #ifdef COMPAT_FREEBSD4
955                                 if (cmd == PCIOCREAD_OLD) {
956                                         io_old->pi_data = -1;
957                                         error = 0;
958                                 } else
959 #endif
960                                         error = ENODEV;
961                         }
962                         break;
963                 default:
964                         error = EINVAL;
965                         break;
966                 }
967                 break;
968
969         case PCIOCGETBAR:
970                 bio = (struct pci_bar_io *)data;
971
972                 /*
973                  * Assume that the user-level bus number is
974                  * in fact the physical PCI bus number.
975                  */
976                 pcidev = pci_find_dbsf(bio->pbi_sel.pc_domain,
977                     bio->pbi_sel.pc_bus, bio->pbi_sel.pc_dev,
978                     bio->pbi_sel.pc_func);
979                 if (pcidev == NULL) {
980                         error = ENODEV;
981                         break;
982                 }
983                 pm = pci_find_bar(pcidev, bio->pbi_reg);
984                 if (pm == NULL) {
985                         error = EINVAL;
986                         break;
987                 }
988                 bio->pbi_base = pm->pm_value;
989                 bio->pbi_length = (pci_addr_t)1 << pm->pm_size;
990                 bio->pbi_enabled = pci_bar_enabled(pcidev, pm);
991                 error = 0;
992                 break;
993         case PCIOCATTACHED:
994                 error = 0;
995                 io = (struct pci_io *)data;
996                 pcidev = pci_find_dbsf(io->pi_sel.pc_domain, io->pi_sel.pc_bus,
997                                        io->pi_sel.pc_dev, io->pi_sel.pc_func);
998                 if (pcidev != NULL)
999                         io->pi_data = device_is_attached(pcidev);
1000                 else
1001                         error = ENODEV;
1002                 break;
1003         case PCIOCLISTVPD:
1004                 lvio = (struct pci_list_vpd_io *)data;
1005
1006                 /*
1007                  * Assume that the user-level bus number is
1008                  * in fact the physical PCI bus number.
1009                  */
1010                 pcidev = pci_find_dbsf(lvio->plvi_sel.pc_domain,
1011                     lvio->plvi_sel.pc_bus, lvio->plvi_sel.pc_dev,
1012                     lvio->plvi_sel.pc_func);
1013                 if (pcidev == NULL) {
1014                         error = ENODEV;
1015                         break;
1016                 }
1017                 error = pci_list_vpd(pcidev, lvio);
1018                 break;
1019         default:
1020                 error = ENOTTY;
1021                 break;
1022         }
1023
1024         return (error);
1025 }