]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/pci/pci_user.c
Copy libevent sources to contrib
[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 /*
450  * Like PVE_NEXT but takes an explicit length since 'pve' is a user
451  * pointer that cannot be dereferenced.
452  */
453 #define PVE_NEXT_LEN(pve, datalen)                                      \
454         ((struct pci_vpd_element *)((char *)(pve) +                     \
455             sizeof(struct pci_vpd_element) + (datalen)))
456
457 static int
458 pci_list_vpd(device_t dev, struct pci_list_vpd_io *lvio)
459 {
460         struct pci_vpd_element vpd_element, *vpd_user;
461         struct pcicfg_vpd *vpd;
462         size_t len;
463         int error, i;
464
465         vpd = pci_fetch_vpd_list(dev);
466         if (vpd->vpd_reg == 0 || vpd->vpd_ident == NULL)
467                 return (ENXIO);
468
469         /*
470          * Calculate the amount of space needed in the data buffer.  An
471          * identifier element is always present followed by the read-only
472          * and read-write keywords.
473          */
474         len = sizeof(struct pci_vpd_element) + strlen(vpd->vpd_ident);
475         for (i = 0; i < vpd->vpd_rocnt; i++)
476                 len += sizeof(struct pci_vpd_element) + vpd->vpd_ros[i].len;
477         for (i = 0; i < vpd->vpd_wcnt; i++)
478                 len += sizeof(struct pci_vpd_element) + vpd->vpd_w[i].len;
479
480         if (lvio->plvi_len == 0) {
481                 lvio->plvi_len = len;
482                 return (0);
483         }
484         if (lvio->plvi_len < len) {
485                 lvio->plvi_len = len;
486                 return (ENOMEM);
487         }
488
489         /*
490          * Copyout the identifier string followed by each keyword and
491          * value.
492          */
493         vpd_user = lvio->plvi_data;
494         vpd_element.pve_keyword[0] = '\0';
495         vpd_element.pve_keyword[1] = '\0';
496         vpd_element.pve_flags = PVE_FLAG_IDENT;
497         vpd_element.pve_datalen = strlen(vpd->vpd_ident);
498         error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
499         if (error)
500                 return (error);
501         error = copyout(vpd->vpd_ident, vpd_user->pve_data,
502             strlen(vpd->vpd_ident));
503         if (error)
504                 return (error);
505         vpd_user = PVE_NEXT_LEN(vpd_user, vpd_element.pve_datalen);
506         vpd_element.pve_flags = 0;
507         for (i = 0; i < vpd->vpd_rocnt; i++) {
508                 vpd_element.pve_keyword[0] = vpd->vpd_ros[i].keyword[0];
509                 vpd_element.pve_keyword[1] = vpd->vpd_ros[i].keyword[1];
510                 vpd_element.pve_datalen = vpd->vpd_ros[i].len;
511                 error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
512                 if (error)
513                         return (error);
514                 error = copyout(vpd->vpd_ros[i].value, vpd_user->pve_data,
515                     vpd->vpd_ros[i].len);
516                 if (error)
517                         return (error);
518                 vpd_user = PVE_NEXT_LEN(vpd_user, vpd_element.pve_datalen);
519         }
520         vpd_element.pve_flags = PVE_FLAG_RW;
521         for (i = 0; i < vpd->vpd_wcnt; i++) {
522                 vpd_element.pve_keyword[0] = vpd->vpd_w[i].keyword[0];
523                 vpd_element.pve_keyword[1] = vpd->vpd_w[i].keyword[1];
524                 vpd_element.pve_datalen = vpd->vpd_w[i].len;
525                 error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
526                 if (error)
527                         return (error);
528                 error = copyout(vpd->vpd_w[i].value, vpd_user->pve_data,
529                     vpd->vpd_w[i].len);
530                 if (error)
531                         return (error);
532                 vpd_user = PVE_NEXT_LEN(vpd_user, vpd_element.pve_datalen);
533         }
534         KASSERT((char *)vpd_user - (char *)lvio->plvi_data == len,
535             ("length mismatch"));
536         lvio->plvi_len = len;
537         return (0);
538 }
539
540 static size_t
541 pci_match_conf_size(u_long cmd)
542 {
543
544         switch (cmd) {
545         case PCIOCGETCONF:
546                 return (sizeof(struct pci_match_conf));
547 #ifdef PRE7_COMPAT
548         case PCIOCGETCONF_OLD:
549                 return (sizeof(struct pci_match_conf_old));
550 #ifdef COMPAT_FREEBSD32
551         case PCIOCGETCONF_OLD32:
552                 return (sizeof(struct pci_match_conf_old32));
553 #endif
554 #endif
555         default:
556                 /* programmer error */
557                 return (0);
558         }
559 }
560
561 static size_t
562 pci_conf_size(u_long cmd)
563 {
564
565         switch (cmd) {
566         case PCIOCGETCONF:
567                 return (sizeof(struct pci_conf));
568 #ifdef PRE7_COMPAT
569         case PCIOCGETCONF_OLD:
570                 return (sizeof(struct pci_conf_old));
571 #ifdef COMPAT_FREEBSD32
572         case PCIOCGETCONF_OLD32:
573                 return (sizeof(struct pci_conf_old32));
574 #endif
575 #endif
576         default:
577                 /* programmer error */
578                 return (0);
579         }
580 }
581
582 static void
583 pci_conf_io_init(struct pci_conf_io *cio, caddr_t data, u_long cmd)
584 {
585 #if defined(PRE7_COMPAT) && defined(COMPAT_FREEBSD32)
586         struct pci_conf_io32 *cio32;
587 #endif
588
589         switch (cmd) {
590         case PCIOCGETCONF:
591 #ifdef PRE7_COMPAT
592         case PCIOCGETCONF_OLD:
593 #endif
594                 *cio = *(struct pci_conf_io *)data;
595                 return;
596
597 #if defined(PRE7_COMPAT) && defined(COMPAT_FREEBSD32)
598         case PCIOCGETCONF_OLD32:
599                cio32 = (struct pci_conf_io32 *)data;
600                cio->pat_buf_len = cio32->pat_buf_len;
601                cio->num_patterns = cio32->num_patterns;
602                cio->patterns = (void *)(uintptr_t)cio32->patterns;
603                cio->match_buf_len = cio32->match_buf_len;
604                cio->num_matches = cio32->num_matches;
605                cio->matches = (void *)(uintptr_t)cio32->matches;
606                cio->offset = cio32->offset;
607                cio->generation = cio32->generation;
608                cio->status = cio32->status;
609                return;
610 #endif
611
612         default:
613                 /* programmer error */
614                 return;
615         }
616 }
617
618 static void
619 pci_conf_io_update_data(const struct pci_conf_io *cio, caddr_t data,
620     u_long cmd)
621 {
622         struct pci_conf_io *d_cio;
623 #if defined(PRE7_COMPAT) && defined(COMPAT_FREEBSD32)
624         struct pci_conf_io32 *cio32;
625 #endif
626
627         switch (cmd) {
628         case PCIOCGETCONF:
629 #ifdef PRE7_COMPAT
630         case PCIOCGETCONF_OLD:
631 #endif
632                 d_cio = (struct pci_conf_io *)data;
633                 d_cio->status = cio->status;
634                 d_cio->generation = cio->generation;
635                 d_cio->offset = cio->offset;
636                 d_cio->num_matches = cio->num_matches;
637                 return;
638
639 #if defined(PRE7_COMPAT) && defined(COMPAT_FREEBSD32)
640         case PCIOCGETCONF_OLD32:
641                 cio32 = (struct pci_conf_io32 *)data;
642
643                 cio32->status = cio->status;
644                 cio32->generation = cio->generation;
645                 cio32->offset = cio->offset;
646                 cio32->num_matches = cio->num_matches;
647                 return;
648 #endif
649
650         default:
651                 /* programmer error */
652                 return;
653         }
654 }
655
656 static void
657 pci_conf_for_copyout(const struct pci_conf *pcp, union pci_conf_union *pcup,
658     u_long cmd)
659 {
660
661         memset(pcup, 0, sizeof(*pcup));
662
663         switch (cmd) {
664         case PCIOCGETCONF:
665                 pcup->pc = *pcp;
666                 return;
667
668 #ifdef PRE7_COMPAT
669 #ifdef COMPAT_FREEBSD32
670         case PCIOCGETCONF_OLD32:
671                 pcup->pco32.pc_sel.pc_bus = pcp->pc_sel.pc_bus;
672                 pcup->pco32.pc_sel.pc_dev = pcp->pc_sel.pc_dev;
673                 pcup->pco32.pc_sel.pc_func = pcp->pc_sel.pc_func;
674                 pcup->pco32.pc_hdr = pcp->pc_hdr;
675                 pcup->pco32.pc_subvendor = pcp->pc_subvendor;
676                 pcup->pco32.pc_subdevice = pcp->pc_subdevice;
677                 pcup->pco32.pc_vendor = pcp->pc_vendor;
678                 pcup->pco32.pc_device = pcp->pc_device;
679                 pcup->pco32.pc_class = pcp->pc_class;
680                 pcup->pco32.pc_subclass = pcp->pc_subclass;
681                 pcup->pco32.pc_progif = pcp->pc_progif;
682                 pcup->pco32.pc_revid = pcp->pc_revid;
683                 strlcpy(pcup->pco32.pd_name, pcp->pd_name,
684                     sizeof(pcup->pco32.pd_name));
685                 pcup->pco32.pd_unit = (uint32_t)pcp->pd_unit;
686                 return;
687
688 #endif /* COMPAT_FREEBSD32 */
689         case PCIOCGETCONF_OLD:
690                 pcup->pco.pc_sel.pc_bus = pcp->pc_sel.pc_bus;
691                 pcup->pco.pc_sel.pc_dev = pcp->pc_sel.pc_dev;
692                 pcup->pco.pc_sel.pc_func = pcp->pc_sel.pc_func;
693                 pcup->pco.pc_hdr = pcp->pc_hdr;
694                 pcup->pco.pc_subvendor = pcp->pc_subvendor;
695                 pcup->pco.pc_subdevice = pcp->pc_subdevice;
696                 pcup->pco.pc_vendor = pcp->pc_vendor;
697                 pcup->pco.pc_device = pcp->pc_device;
698                 pcup->pco.pc_class = pcp->pc_class;
699                 pcup->pco.pc_subclass = pcp->pc_subclass;
700                 pcup->pco.pc_progif = pcp->pc_progif;
701                 pcup->pco.pc_revid = pcp->pc_revid;
702                 strlcpy(pcup->pco.pd_name, pcp->pd_name,
703                     sizeof(pcup->pco.pd_name));
704                 pcup->pco.pd_unit = pcp->pd_unit;
705                 return;
706 #endif /* PRE7_COMPAT */
707
708         default:
709                 /* programmer error */
710                 return;
711         }
712 }
713
714 static int
715 pci_bar_mmap(device_t pcidev, struct pci_bar_mmap *pbm)
716 {
717         vm_map_t map;
718         vm_object_t obj;
719         struct thread *td;
720         struct sglist *sg;
721         struct pci_map *pm;
722         vm_paddr_t pbase;
723         vm_size_t plen;
724         vm_offset_t addr;
725         vm_prot_t prot;
726         int error, flags;
727
728         td = curthread;
729         map = &td->td_proc->p_vmspace->vm_map;
730         if ((pbm->pbm_flags & ~(PCIIO_BAR_MMAP_FIXED | PCIIO_BAR_MMAP_EXCL |
731             PCIIO_BAR_MMAP_RW | PCIIO_BAR_MMAP_ACTIVATE)) != 0 ||
732             pbm->pbm_memattr != (vm_memattr_t)pbm->pbm_memattr ||
733             !pmap_is_valid_memattr(map->pmap, pbm->pbm_memattr))
734                 return (EINVAL);
735
736         /* Fetch the BAR physical base and length. */
737         pm = pci_find_bar(pcidev, pbm->pbm_reg);
738         if (pm == NULL)
739                 return (EINVAL);
740         if (!pci_bar_enabled(pcidev, pm))
741                 return (EBUSY); /* XXXKIB enable if _ACTIVATE */
742         if (!PCI_BAR_MEM(pm->pm_value))
743                 return (EIO);
744         pbase = trunc_page(pm->pm_value);
745         plen = round_page(pm->pm_value + ((pci_addr_t)1 << pm->pm_size)) -
746             pbase;
747         prot = VM_PROT_READ | (((pbm->pbm_flags & PCIIO_BAR_MMAP_RW) != 0) ?
748             VM_PROT_WRITE : 0);
749
750         /* Create vm structures and mmap. */
751         sg = sglist_alloc(1, M_WAITOK);
752         error = sglist_append_phys(sg, pbase, plen);
753         if (error != 0)
754                 goto out;
755         obj = vm_pager_allocate(OBJT_SG, sg, plen, prot, 0, td->td_ucred);
756         if (obj == NULL) {
757                 error = EIO;
758                 goto out;
759         }
760         obj->memattr = pbm->pbm_memattr;
761         flags = MAP_SHARED;
762         addr = 0;
763         if ((pbm->pbm_flags & PCIIO_BAR_MMAP_FIXED) != 0) {
764                 addr = (uintptr_t)pbm->pbm_map_base;
765                 flags |= MAP_FIXED;
766         }
767         if ((pbm->pbm_flags & PCIIO_BAR_MMAP_EXCL) != 0)
768                 flags |= MAP_CHECK_EXCL;
769         error = vm_mmap_object(map, &addr, plen, prot, prot, flags, obj, 0,
770             FALSE, td);
771         if (error != 0) {
772                 vm_object_deallocate(obj);
773                 goto out;
774         }
775         pbm->pbm_map_base = (void *)addr;
776         pbm->pbm_map_length = plen;
777         pbm->pbm_bar_off = pm->pm_value - pbase;
778         pbm->pbm_bar_length = (pci_addr_t)1 << pm->pm_size;
779
780 out:
781         sglist_free(sg);
782         return (error);
783 }
784
785 static int
786 pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
787 {
788         device_t pcidev;
789         const char *name;
790         struct devlist *devlist_head;
791         struct pci_conf_io *cio = NULL;
792         struct pci_devinfo *dinfo;
793         struct pci_io *io;
794         struct pci_bar_io *bio;
795         struct pci_list_vpd_io *lvio;
796         struct pci_match_conf *pattern_buf;
797         struct pci_map *pm;
798         struct pci_bar_mmap *pbm;
799         size_t confsz, iolen;
800         int error, ionum, i, num_patterns;
801         union pci_conf_union pcu;
802 #ifdef PRE7_COMPAT
803         struct pci_io iodata;
804         struct pci_io_old *io_old;
805
806         io_old = NULL;
807 #endif
808
809         if (!(flag & FWRITE)) {
810                 switch (cmd) {
811                 case PCIOCGETCONF:
812 #ifdef PRE7_COMPAT
813                 case PCIOCGETCONF_OLD:
814 #ifdef COMPAT_FREEBSD32
815                 case PCIOCGETCONF_OLD32:
816 #endif
817 #endif
818                 case PCIOCGETBAR:
819                 case PCIOCLISTVPD:
820                         break;
821                 default:
822                         return (EPERM);
823                 }
824         }
825
826
827         switch (cmd) {
828         case PCIOCGETCONF:
829 #ifdef PRE7_COMPAT
830         case PCIOCGETCONF_OLD:
831 #ifdef COMPAT_FREEBSD32
832         case PCIOCGETCONF_OLD32:
833 #endif
834 #endif
835                 cio = malloc(sizeof(struct pci_conf_io), M_TEMP,
836                     M_WAITOK | M_ZERO);
837                 pci_conf_io_init(cio, data, cmd);
838                 pattern_buf = NULL;
839                 num_patterns = 0;
840                 dinfo = NULL;
841
842                 cio->num_matches = 0;
843
844                 /*
845                  * If the user specified an offset into the device list,
846                  * but the list has changed since they last called this
847                  * ioctl, tell them that the list has changed.  They will
848                  * have to get the list from the beginning.
849                  */
850                 if ((cio->offset != 0)
851                  && (cio->generation != pci_generation)){
852                         cio->status = PCI_GETCONF_LIST_CHANGED;
853                         error = 0;
854                         goto getconfexit;
855                 }
856
857                 /*
858                  * Check to see whether the user has asked for an offset
859                  * past the end of our list.
860                  */
861                 if (cio->offset >= pci_numdevs) {
862                         cio->status = PCI_GETCONF_LAST_DEVICE;
863                         error = 0;
864                         goto getconfexit;
865                 }
866
867                 /* get the head of the device queue */
868                 devlist_head = &pci_devq;
869
870                 /*
871                  * Determine how much room we have for pci_conf structures.
872                  * Round the user's buffer size down to the nearest
873                  * multiple of sizeof(struct pci_conf) in case the user
874                  * didn't specify a multiple of that size.
875                  */
876                 confsz = pci_conf_size(cmd);
877                 iolen = min(cio->match_buf_len - (cio->match_buf_len % confsz),
878                     pci_numdevs * confsz);
879
880                 /*
881                  * Since we know that iolen is a multiple of the size of
882                  * the pciconf union, it's okay to do this.
883                  */
884                 ionum = iolen / confsz;
885
886                 /*
887                  * If this test is true, the user wants the pci_conf
888                  * structures returned to match the supplied entries.
889                  */
890                 if ((cio->num_patterns > 0) && (cio->num_patterns < pci_numdevs)
891                  && (cio->pat_buf_len > 0)) {
892                         /*
893                          * pat_buf_len needs to be:
894                          * num_patterns * sizeof(struct pci_match_conf)
895                          * While it is certainly possible the user just
896                          * allocated a large buffer, but set the number of
897                          * matches correctly, it is far more likely that
898                          * their kernel doesn't match the userland utility
899                          * they're using.  It's also possible that the user
900                          * forgot to initialize some variables.  Yes, this
901                          * may be overly picky, but I hazard to guess that
902                          * it's far more likely to just catch folks that
903                          * updated their kernel but not their userland.
904                          */
905                         if (cio->num_patterns * pci_match_conf_size(cmd) !=
906                             cio->pat_buf_len) {
907                                 /* The user made a mistake, return an error. */
908                                 cio->status = PCI_GETCONF_ERROR;
909                                 error = EINVAL;
910                                 goto getconfexit;
911                         }
912
913                         /*
914                          * Allocate a buffer to hold the patterns.
915                          */
916                         pattern_buf = malloc(cio->pat_buf_len, M_TEMP,
917                             M_WAITOK);
918                         error = copyin(cio->patterns, pattern_buf,
919                             cio->pat_buf_len);
920                         if (error != 0) {
921                                 error = EINVAL;
922                                 goto getconfexit;
923                         }
924                         num_patterns = cio->num_patterns;
925                 } else if ((cio->num_patterns > 0)
926                         || (cio->pat_buf_len > 0)) {
927                         /*
928                          * The user made a mistake, spit out an error.
929                          */
930                         cio->status = PCI_GETCONF_ERROR;
931                         error = EINVAL;
932                        goto getconfexit;
933                 }
934
935                 /*
936                  * Go through the list of devices and copy out the devices
937                  * that match the user's criteria.
938                  */
939                 for (cio->num_matches = 0, i = 0,
940                                  dinfo = STAILQ_FIRST(devlist_head);
941                      dinfo != NULL;
942                      dinfo = STAILQ_NEXT(dinfo, pci_links), i++) {
943
944                         if (i < cio->offset)
945                                 continue;
946
947                         /* Populate pd_name and pd_unit */
948                         name = NULL;
949                         if (dinfo->cfg.dev)
950                                 name = device_get_name(dinfo->cfg.dev);
951                         if (name) {
952                                 strncpy(dinfo->conf.pd_name, name,
953                                         sizeof(dinfo->conf.pd_name));
954                                 dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0;
955                                 dinfo->conf.pd_unit =
956                                         device_get_unit(dinfo->cfg.dev);
957                         } else {
958                                 dinfo->conf.pd_name[0] = '\0';
959                                 dinfo->conf.pd_unit = 0;
960                         }
961
962                         if (pattern_buf == NULL ||
963                             pci_conf_match(cmd, pattern_buf, num_patterns,
964                             &dinfo->conf) == 0) {
965                                 /*
966                                  * If we've filled up the user's buffer,
967                                  * break out at this point.  Since we've
968                                  * got a match here, we'll pick right back
969                                  * up at the matching entry.  We can also
970                                  * tell the user that there are more matches
971                                  * left.
972                                  */
973                                 if (cio->num_matches >= ionum) {
974                                         error = 0;
975                                         break;
976                                 }
977
978                                 pci_conf_for_copyout(&dinfo->conf, &pcu, cmd);
979                                 error = copyout(&pcu,
980                                     (caddr_t)cio->matches +
981                                     confsz * cio->num_matches, confsz);
982                                 if (error)
983                                         break;
984                                 cio->num_matches++;
985                         }
986                 }
987
988                 /*
989                  * Set the pointer into the list, so if the user is getting
990                  * n records at a time, where n < pci_numdevs,
991                  */
992                 cio->offset = i;
993
994                 /*
995                  * Set the generation, the user will need this if they make
996                  * another ioctl call with offset != 0.
997                  */
998                 cio->generation = pci_generation;
999
1000                 /*
1001                  * If this is the last device, inform the user so he won't
1002                  * bother asking for more devices.  If dinfo isn't NULL, we
1003                  * know that there are more matches in the list because of
1004                  * the way the traversal is done.
1005                  */
1006                 if (dinfo == NULL)
1007                         cio->status = PCI_GETCONF_LAST_DEVICE;
1008                 else
1009                         cio->status = PCI_GETCONF_MORE_DEVS;
1010
1011 getconfexit:
1012                 pci_conf_io_update_data(cio, data, cmd);
1013                 free(cio, M_TEMP);
1014                 free(pattern_buf, M_TEMP);
1015
1016                 break;
1017
1018 #ifdef PRE7_COMPAT
1019         case PCIOCREAD_OLD:
1020         case PCIOCWRITE_OLD:
1021                 io_old = (struct pci_io_old *)data;
1022                 iodata.pi_sel.pc_domain = 0;
1023                 iodata.pi_sel.pc_bus = io_old->pi_sel.pc_bus;
1024                 iodata.pi_sel.pc_dev = io_old->pi_sel.pc_dev;
1025                 iodata.pi_sel.pc_func = io_old->pi_sel.pc_func;
1026                 iodata.pi_reg = io_old->pi_reg;
1027                 iodata.pi_width = io_old->pi_width;
1028                 iodata.pi_data = io_old->pi_data;
1029                 data = (caddr_t)&iodata;
1030                 /* FALLTHROUGH */
1031 #endif
1032         case PCIOCREAD:
1033         case PCIOCWRITE:
1034                 io = (struct pci_io *)data;
1035                 switch(io->pi_width) {
1036                 case 4:
1037                 case 2:
1038                 case 1:
1039                         /* Make sure register is not negative and aligned. */
1040                         if (io->pi_reg < 0 ||
1041                             io->pi_reg & (io->pi_width - 1)) {
1042                                 error = EINVAL;
1043                                 break;
1044                         }
1045                         /*
1046                          * Assume that the user-level bus number is
1047                          * in fact the physical PCI bus number.
1048                          * Look up the grandparent, i.e. the bridge device,
1049                          * so that we can issue configuration space cycles.
1050                          */
1051                         pcidev = pci_find_dbsf(io->pi_sel.pc_domain,
1052                             io->pi_sel.pc_bus, io->pi_sel.pc_dev,
1053                             io->pi_sel.pc_func);
1054                         if (pcidev) {
1055 #ifdef PRE7_COMPAT
1056                                 if (cmd == PCIOCWRITE || cmd == PCIOCWRITE_OLD)
1057 #else
1058                                 if (cmd == PCIOCWRITE)
1059 #endif
1060                                         pci_write_config(pcidev,
1061                                                           io->pi_reg,
1062                                                           io->pi_data,
1063                                                           io->pi_width);
1064 #ifdef PRE7_COMPAT
1065                                 else if (cmd == PCIOCREAD_OLD)
1066                                         io_old->pi_data =
1067                                                 pci_read_config(pcidev,
1068                                                           io->pi_reg,
1069                                                           io->pi_width);
1070 #endif
1071                                 else
1072                                         io->pi_data =
1073                                                 pci_read_config(pcidev,
1074                                                           io->pi_reg,
1075                                                           io->pi_width);
1076                                 error = 0;
1077                         } else {
1078 #ifdef COMPAT_FREEBSD4
1079                                 if (cmd == PCIOCREAD_OLD) {
1080                                         io_old->pi_data = -1;
1081                                         error = 0;
1082                                 } else
1083 #endif
1084                                         error = ENODEV;
1085                         }
1086                         break;
1087                 default:
1088                         error = EINVAL;
1089                         break;
1090                 }
1091                 break;
1092
1093         case PCIOCGETBAR:
1094                 bio = (struct pci_bar_io *)data;
1095
1096                 /*
1097                  * Assume that the user-level bus number is
1098                  * in fact the physical PCI bus number.
1099                  */
1100                 pcidev = pci_find_dbsf(bio->pbi_sel.pc_domain,
1101                     bio->pbi_sel.pc_bus, bio->pbi_sel.pc_dev,
1102                     bio->pbi_sel.pc_func);
1103                 if (pcidev == NULL) {
1104                         error = ENODEV;
1105                         break;
1106                 }
1107                 pm = pci_find_bar(pcidev, bio->pbi_reg);
1108                 if (pm == NULL) {
1109                         error = EINVAL;
1110                         break;
1111                 }
1112                 bio->pbi_base = pm->pm_value;
1113                 bio->pbi_length = (pci_addr_t)1 << pm->pm_size;
1114                 bio->pbi_enabled = pci_bar_enabled(pcidev, pm);
1115                 error = 0;
1116                 break;
1117         case PCIOCATTACHED:
1118                 error = 0;
1119                 io = (struct pci_io *)data;
1120                 pcidev = pci_find_dbsf(io->pi_sel.pc_domain, io->pi_sel.pc_bus,
1121                                        io->pi_sel.pc_dev, io->pi_sel.pc_func);
1122                 if (pcidev != NULL)
1123                         io->pi_data = device_is_attached(pcidev);
1124                 else
1125                         error = ENODEV;
1126                 break;
1127         case PCIOCLISTVPD:
1128                 lvio = (struct pci_list_vpd_io *)data;
1129
1130                 /*
1131                  * Assume that the user-level bus number is
1132                  * in fact the physical PCI bus number.
1133                  */
1134                 pcidev = pci_find_dbsf(lvio->plvi_sel.pc_domain,
1135                     lvio->plvi_sel.pc_bus, lvio->plvi_sel.pc_dev,
1136                     lvio->plvi_sel.pc_func);
1137                 if (pcidev == NULL) {
1138                         error = ENODEV;
1139                         break;
1140                 }
1141                 error = pci_list_vpd(pcidev, lvio);
1142                 break;
1143
1144         case PCIOCBARMMAP:
1145                 pbm = (struct pci_bar_mmap *)data;
1146                 if ((flag & FWRITE) == 0 &&
1147                     (pbm->pbm_flags & PCIIO_BAR_MMAP_RW) != 0)
1148                         return (EPERM);
1149                 pcidev = pci_find_dbsf(pbm->pbm_sel.pc_domain,
1150                     pbm->pbm_sel.pc_bus, pbm->pbm_sel.pc_dev,
1151                     pbm->pbm_sel.pc_func);
1152                 error = pcidev == NULL ? ENODEV : pci_bar_mmap(pcidev, pbm);
1153                 break;
1154
1155         default:
1156                 error = ENOTTY;
1157                 break;
1158         }
1159
1160         return (error);
1161 }