2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice unmodified, this list of conditions, and the following
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.
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.
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include "opt_bus.h" /* XXX trim includes */
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>
41 #include <sys/kernel.h>
43 #include <sys/queue.h>
44 #include <sys/types.h>
48 #include <vm/vm_extern.h>
51 #include <machine/bus.h>
53 #include <machine/resource.h>
55 #include <sys/pciio.h>
56 #include <dev/pci/pcireg.h>
57 #include <dev/pci/pcivar.h>
63 * This is the user interface to PCI configuration space.
66 static d_open_t pci_open;
67 static d_close_t pci_close;
68 static d_ioctl_t pci_ioctl;
70 struct cdevsw pcicdev = {
71 .d_version = D_VERSION,
72 .d_flags = D_NEEDGIANT,
80 pci_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
84 if (oflags & FWRITE) {
85 error = securelevel_gt(td->td_ucred, 0);
94 pci_close(struct cdev *dev, int flag, int devtype, struct thread *td)
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.
107 pci_conf_match_native(struct pci_match_conf *matches, int num_matches,
108 struct pci_conf *match_buf)
112 if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
115 for (i = 0; i < num_matches; i++) {
117 * I'm not sure why someone would do this...but...
119 if (matches[i].flags == PCI_GETCONF_NO_MATCH)
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.
127 if (((matches[i].flags & PCI_GETCONF_MATCH_DOMAIN) != 0)
128 && (match_buf->pc_sel.pc_domain !=
129 matches[i].pc_sel.pc_domain))
132 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0)
133 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
136 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0)
137 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
140 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0)
141 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
144 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0)
145 && (match_buf->pc_vendor != matches[i].pc_vendor))
148 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0)
149 && (match_buf->pc_device != matches[i].pc_device))
152 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0)
153 && (match_buf->pc_class != matches[i].pc_class))
156 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0)
157 && (match_buf->pd_unit != matches[i].pd_unit))
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))
171 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
172 defined(COMPAT_FREEBSD6)
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;
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 */
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
199 u_int16_t pc_vendor; /* chip vendor ID */
200 u_int16_t pc_device; /* chip device ID, assigned by
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 */
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 */
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 */
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
234 uint16_t pc_vendor; /* chip vendor ID */
235 uint16_t pc_device; /* chip device ID, assigned by
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) */
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 */
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 */
269 #define PCIOCGETCONF_OLD32 _IOWR('p', 1, struct pci_conf_io32)
270 #endif /* COMPAT_FREEBSD32 */
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)
277 pci_conf_match_old(struct pci_match_conf_old *matches, int num_matches,
278 struct pci_conf *match_buf)
282 if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
285 for (i = 0; i < num_matches; i++) {
286 if (match_buf->pc_sel.pc_domain != 0)
290 * I'm not sure why someone would do this...but...
292 if (matches[i].flags == PCI_GETCONF_NO_MATCH_OLD)
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.
300 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_OLD) != 0)
301 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
304 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_OLD) != 0)
305 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
308 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_OLD) != 0)
309 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
312 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_OLD) != 0)
313 && (match_buf->pc_vendor != matches[i].pc_vendor))
316 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_OLD) != 0)
317 && (match_buf->pc_device != matches[i].pc_device))
320 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_OLD) != 0)
321 && (match_buf->pc_class != matches[i].pc_class))
324 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_OLD) != 0)
325 && (match_buf->pd_unit != matches[i].pd_unit))
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))
339 #ifdef COMPAT_FREEBSD32
341 pci_conf_match_old32(struct pci_match_conf_old32 *matches, int num_matches,
342 struct pci_conf *match_buf)
346 if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
349 for (i = 0; i < num_matches; i++) {
350 if (match_buf->pc_sel.pc_domain != 0)
354 * I'm not sure why someone would do this...but...
356 if (matches[i].flags == PCI_GETCONF_NO_MATCH_OLD)
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.
364 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_OLD) != 0) &&
365 (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
368 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_OLD) != 0) &&
369 (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
372 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_OLD) != 0) &&
373 (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
376 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_OLD) != 0) &&
377 (match_buf->pc_vendor != matches[i].pc_vendor))
380 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_OLD) != 0) &&
381 (match_buf->pc_device != matches[i].pc_device))
384 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_OLD) != 0) &&
385 (match_buf->pc_class != matches[i].pc_class))
388 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_OLD) != 0) &&
389 ((u_int32_t)match_buf->pd_unit != matches[i].pd_unit))
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))
402 #endif /* COMPAT_FREEBSD32 */
403 #endif /* !PRE7_COMPAT */
405 union pci_conf_union {
408 struct pci_conf_old pco;
409 #ifdef COMPAT_FREEBSD32
410 struct pci_conf_old32 pco32;
416 pci_conf_match(u_long cmd, struct pci_match_conf *matches, int num_matches,
417 struct pci_conf *match_buf)
422 return (pci_conf_match_native(
423 (struct pci_match_conf *)matches, num_matches, match_buf));
425 case PCIOCGETCONF_OLD:
426 return (pci_conf_match_old(
427 (struct pci_match_conf_old *)matches, num_matches,
429 #ifdef COMPAT_FREEBSD32
430 case PCIOCGETCONF_OLD32:
431 return (pci_conf_match_old32(
432 (struct pci_match_conf_old32 *)matches, num_matches,
437 /* programmer error */
443 pci_list_vpd(device_t dev, struct pci_list_vpd_io *lvio)
445 struct pci_vpd_element vpd_element, *vpd_user;
446 struct pcicfg_vpd *vpd;
450 vpd = pci_fetch_vpd_list(dev);
451 if (vpd->vpd_reg == 0 || vpd->vpd_ident == NULL)
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.
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;
465 if (lvio->plvi_len == 0) {
466 lvio->plvi_len = len;
469 if (lvio->plvi_len < len) {
470 lvio->plvi_len = len;
475 * Copyout the identifier string followed by each keyword and
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));
486 error = copyout(vpd->vpd_ident, vpd_user->pve_data,
487 strlen(vpd->vpd_ident));
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));
499 error = copyout(vpd->vpd_ros[i].value, vpd_user->pve_data,
500 vpd->vpd_ros[i].len);
503 vpd_user = PVE_NEXT(vpd_user);
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));
513 error = copyout(vpd->vpd_w[i].value, vpd_user->pve_data,
517 vpd_user = PVE_NEXT(vpd_user);
519 KASSERT((char *)vpd_user - (char *)lvio->plvi_data == len,
520 ("length mismatch"));
521 lvio->plvi_len = len;
526 pci_match_conf_size(u_long cmd)
531 return (sizeof(struct pci_match_conf));
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));
541 /* programmer error */
547 pci_conf_size(u_long cmd)
552 return (sizeof(struct pci_conf));
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));
562 /* programmer error */
568 pci_conf_io_init(struct pci_conf_io *cio, caddr_t data, u_long cmd)
570 #if defined(PRE7_COMPAT) && defined(COMPAT_FREEBSD32)
571 struct pci_conf_io32 *cio32;
577 case PCIOCGETCONF_OLD:
579 *cio = *(struct pci_conf_io *)data;
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;
598 /* programmer error */
604 pci_conf_io_update_data(const struct pci_conf_io *cio, caddr_t data,
607 struct pci_conf_io *d_cio;
608 #if defined(PRE7_COMPAT) && defined(COMPAT_FREEBSD32)
609 struct pci_conf_io32 *cio32;
615 case PCIOCGETCONF_OLD:
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;
624 #if defined(PRE7_COMPAT) && defined(COMPAT_FREEBSD32)
625 case PCIOCGETCONF_OLD32:
626 cio32 = (struct pci_conf_io32 *)data;
628 cio32->status = cio->status;
629 cio32->generation = cio->generation;
630 cio32->offset = cio->offset;
631 cio32->num_matches = cio->num_matches;
636 /* programmer error */
642 pci_conf_for_copyout(const struct pci_conf *pcp, union pci_conf_union *pcup,
646 memset(pcup, 0, sizeof(*pcup));
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;
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;
691 #endif /* PRE7_COMPAT */
694 /* programmer error */
700 pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
704 struct devlist *devlist_head;
705 struct pci_conf_io *cio = NULL;
706 struct pci_devinfo *dinfo;
708 struct pci_bar_io *bio;
709 struct pci_list_vpd_io *lvio;
710 struct pci_match_conf *pattern_buf;
712 size_t confsz, iolen;
713 int error, ionum, i, num_patterns;
714 union pci_conf_union pcu;
716 struct pci_io iodata;
717 struct pci_io_old *io_old;
722 if (!(flag & FWRITE)) {
726 case PCIOCGETCONF_OLD:
727 #ifdef COMPAT_FREEBSD32
728 case PCIOCGETCONF_OLD32:
743 case PCIOCGETCONF_OLD:
744 #ifdef COMPAT_FREEBSD32
745 case PCIOCGETCONF_OLD32:
748 cio = malloc(sizeof(struct pci_conf_io), M_TEMP,
750 pci_conf_io_init(cio, data, cmd);
755 cio->num_matches = 0;
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.
763 if ((cio->offset != 0)
764 && (cio->generation != pci_generation)){
765 cio->status = PCI_GETCONF_LIST_CHANGED;
771 * Check to see whether the user has asked for an offset
772 * past the end of our list.
774 if (cio->offset >= pci_numdevs) {
775 cio->status = PCI_GETCONF_LAST_DEVICE;
780 /* get the head of the device queue */
781 devlist_head = &pci_devq;
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.
789 confsz = pci_conf_size(cmd);
790 iolen = min(cio->match_buf_len - (cio->match_buf_len % confsz),
791 pci_numdevs * confsz);
794 * Since we know that iolen is a multiple of the size of
795 * the pciconf union, it's okay to do this.
797 ionum = iolen / confsz;
800 * If this test is true, the user wants the pci_conf
801 * structures returned to match the supplied entries.
803 if ((cio->num_patterns > 0) && (cio->num_patterns < pci_numdevs)
804 && (cio->pat_buf_len > 0)) {
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.
818 if (cio->num_patterns * pci_match_conf_size(cmd) !=
820 /* The user made a mistake, return an error. */
821 cio->status = PCI_GETCONF_ERROR;
827 * Allocate a buffer to hold the patterns.
829 pattern_buf = malloc(cio->pat_buf_len, M_TEMP,
831 error = copyin(cio->patterns, pattern_buf,
837 num_patterns = cio->num_patterns;
838 } else if ((cio->num_patterns > 0)
839 || (cio->pat_buf_len > 0)) {
841 * The user made a mistake, spit out an error.
843 cio->status = PCI_GETCONF_ERROR;
849 * Go through the list of devices and copy out the devices
850 * that match the user's criteria.
852 for (cio->num_matches = 0, i = 0,
853 dinfo = STAILQ_FIRST(devlist_head);
855 dinfo = STAILQ_NEXT(dinfo, pci_links), i++) {
860 /* Populate pd_name and pd_unit */
863 name = device_get_name(dinfo->cfg.dev);
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);
871 dinfo->conf.pd_name[0] = '\0';
872 dinfo->conf.pd_unit = 0;
875 if (pattern_buf == NULL ||
876 pci_conf_match(cmd, pattern_buf, num_patterns,
877 &dinfo->conf) == 0) {
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
886 if (cio->num_matches >= ionum) {
891 pci_conf_for_copyout(&dinfo->conf, &pcu, cmd);
892 error = copyout(&pcu,
893 (caddr_t)cio->matches +
894 confsz * cio->num_matches, confsz);
902 * Set the pointer into the list, so if the user is getting
903 * n records at a time, where n < pci_numdevs,
908 * Set the generation, the user will need this if they make
909 * another ioctl call with offset != 0.
911 cio->generation = pci_generation;
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.
920 cio->status = PCI_GETCONF_LAST_DEVICE;
922 cio->status = PCI_GETCONF_MORE_DEVS;
925 pci_conf_io_update_data(cio, data, cmd);
927 free(pattern_buf, M_TEMP);
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;
947 io = (struct pci_io *)data;
948 switch(io->pi_width) {
952 /* Make sure register is not negative and aligned. */
953 if (io->pi_reg < 0 ||
954 io->pi_reg & (io->pi_width - 1)) {
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.
964 pcidev = pci_find_dbsf(io->pi_sel.pc_domain,
965 io->pi_sel.pc_bus, io->pi_sel.pc_dev,
969 if (cmd == PCIOCWRITE || cmd == PCIOCWRITE_OLD)
971 if (cmd == PCIOCWRITE)
973 pci_write_config(pcidev,
978 else if (cmd == PCIOCREAD_OLD)
980 pci_read_config(pcidev,
986 pci_read_config(pcidev,
991 #ifdef COMPAT_FREEBSD4
992 if (cmd == PCIOCREAD_OLD) {
993 io_old->pi_data = -1;
1007 bio = (struct pci_bar_io *)data;
1010 * Assume that the user-level bus number is
1011 * in fact the physical PCI bus number.
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) {
1020 pm = pci_find_bar(pcidev, bio->pbi_reg);
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);
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);
1036 io->pi_data = device_is_attached(pcidev);
1041 lvio = (struct pci_list_vpd_io *)data;
1044 * Assume that the user-level bus number is
1045 * in fact the physical PCI bus number.
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) {
1054 error = pci_list_vpd(pcidev, lvio);