source: rtems-libbsd/freebsd/sys/dev/pci/pci_user.c @ 3d1e767

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 3d1e767 was 3d1e767, checked in by Sebastian Huber <sebastian.huber@…>, on 04/27/16 at 08:25:22

Directly use <sys/types.h> provided by Newlib

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