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