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