2 * Copyright (c) 1997, Stefan Esser <se@kfreebsd.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice unmodified, this list of conditions, and the following
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * $FreeBSD: src/sys/dev/pci/pci_user.c,v 1.22.2.4.2.1 2009/04/15 03:14:26 kensmith Exp $
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/malloc.h>
32 #include <sys/module.h>
33 #include <sys/linker.h>
34 #include <sys/fcntl.h>
37 #include <sys/kernel.h>
39 #include <sys/queue.h>
40 #include <sys/types.h>
44 #include <vm/vm_extern.h>
48 #include <sys/device.h>
49 #include <sys/pciio.h>
50 #include <bus/pci/pcireg.h>
51 #include <bus/pci/pcivar.h>
57 * This is the user interface to PCI configuration space.
59 static struct lwkt_token pci_token
= LWKT_TOKEN_INITIALIZER(pci_token
);
61 static d_open_t pci_open
;
62 static d_close_t pci_close
;
63 static int pci_conf_match(struct pci_match_conf
*matches
, int num_matches
,
64 struct pci_conf
*match_buf
);
65 static d_ioctl_t pci_ioctl
;
67 struct dev_ops pci_ops
= {
68 { "pci", 0, D_MPSAFE
},
75 pci_open(struct dev_open_args
*ap
)
77 int oflags
= ap
->a_oflags
;
80 * Disallow access to disk volumes if RESTRICTEDROOT
82 if (caps_priv_check_self(SYSCAP_RESTRICTEDROOT
))
85 if (oflags
& FWRITE
) {
94 pci_close(struct dev_close_args
*ap
)
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(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) || defined(__DragonFly__)
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 #define PCIOCGETCONF_OLD _IOWR('p', 1, struct pci_conf_io)
228 #define PCIOCREAD_OLD _IOWR('p', 2, struct pci_io_old)
229 #define PCIOCWRITE_OLD _IOWR('p', 3, struct pci_io_old)
231 static int pci_conf_match_old(struct pci_match_conf_old
*matches
,
232 int num_matches
, struct pci_conf
*match_buf
);
235 pci_conf_match_old(struct pci_match_conf_old
*matches
, int num_matches
,
236 struct pci_conf
*match_buf
)
240 if ((matches
== NULL
) || (match_buf
== NULL
) || (num_matches
<= 0))
243 for (i
= 0; i
< num_matches
; i
++) {
244 if (match_buf
->pc_sel
.pc_domain
!= 0)
248 * I'm not sure why someone would do this...but...
250 if (matches
[i
].flags
== PCI_GETCONF_NO_MATCH_OLD
)
254 * Look at each of the match flags. If it's set, do the
255 * comparison. If the comparison fails, we don't have a
256 * match, go on to the next item if there is one.
258 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_BUS_OLD
) != 0)
259 && (match_buf
->pc_sel
.pc_bus
!= matches
[i
].pc_sel
.pc_bus
))
262 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_DEV_OLD
) != 0)
263 && (match_buf
->pc_sel
.pc_dev
!= matches
[i
].pc_sel
.pc_dev
))
266 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_FUNC_OLD
) != 0)
267 && (match_buf
->pc_sel
.pc_func
!= matches
[i
].pc_sel
.pc_func
))
270 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_VENDOR_OLD
) != 0)
271 && (match_buf
->pc_vendor
!= matches
[i
].pc_vendor
))
274 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_DEVICE_OLD
) != 0)
275 && (match_buf
->pc_device
!= matches
[i
].pc_device
))
278 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_CLASS_OLD
) != 0)
279 && (match_buf
->pc_class
!= matches
[i
].pc_class
))
282 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_UNIT_OLD
) != 0)
283 && (match_buf
->pd_unit
!= matches
[i
].pd_unit
))
286 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_NAME_OLD
) != 0)
287 && (strncmp(matches
[i
].pd_name
, match_buf
->pd_name
,
288 sizeof(match_buf
->pd_name
)) != 0))
300 pci_ioctl(struct dev_ioctl_args
*ap
)
302 device_t pcidev
, brdev
;
305 struct devlist
*devlist_head
;
306 struct pci_conf_io
*cio
;
307 struct pci_devinfo
*dinfo
;
309 struct pci_bar_io
*bio
;
310 struct pci_match_conf
*pattern_buf
;
311 struct resource_list_entry
*rle
;
313 size_t confsz
, iolen
, pbufsz
;
314 int error
, ionum
, i
, num_patterns
;
316 struct pci_conf_old conf_old
;
317 struct pci_io iodata
;
318 struct pci_io_old
*io_old
;
319 struct pci_match_conf_old
*pattern_buf_old
;
322 pattern_buf_old
= NULL
;
324 if (!(ap
->a_fflag
& FWRITE
) && ap
->a_cmd
!= PCIOCGETBAR
&&
325 ap
->a_cmd
!= PCIOCGETCONF
&& ap
->a_cmd
!= PCIOCGETCONF_OLD
)
328 if (!(ap
->a_fflag
& FWRITE
) && ap
->a_cmd
!= PCIOCGETBAR
&& ap
->a_cmd
!= PCIOCGETCONF
)
332 lwkt_gettoken(&pci_token
);
336 case PCIOCGETCONF_OLD
:
340 cio
= (struct pci_conf_io
*)ap
->a_data
;
346 cio
->num_matches
= 0;
349 * If the user specified an offset into the device list,
350 * but the list has changed since they last called this
351 * ioctl, tell them that the list has changed. They will
352 * have to get the list from the beginning.
354 if ((cio
->offset
!= 0)
355 && (cio
->generation
!= pci_generation
)){
356 cio
->status
= PCI_GETCONF_LIST_CHANGED
;
362 * Check to see whether the user has asked for an offset
363 * past the end of our list.
365 if (cio
->offset
>= pci_numdevs
) {
366 cio
->status
= PCI_GETCONF_LAST_DEVICE
;
371 /* get the head of the device queue */
372 devlist_head
= &pci_devq
;
375 * Determine how much room we have for pci_conf structures.
376 * Round the user's buffer size down to the nearest
377 * multiple of sizeof(struct pci_conf) in case the user
378 * didn't specify a multiple of that size.
381 if (ap
->a_cmd
== PCIOCGETCONF_OLD
)
382 confsz
= sizeof(struct pci_conf_old
);
385 confsz
= sizeof(struct pci_conf
);
386 iolen
= min(cio
->match_buf_len
- (cio
->match_buf_len
% confsz
),
387 pci_numdevs
* confsz
);
390 * Since we know that iolen is a multiple of the size of
391 * the pciconf union, it's okay to do this.
393 ionum
= iolen
/ confsz
;
396 * If this test is true, the user wants the pci_conf
397 * structures returned to match the supplied entries.
399 if ((cio
->num_patterns
> 0) && (cio
->num_patterns
< pci_numdevs
)
400 && (cio
->pat_buf_len
> 0)) {
402 * pat_buf_len needs to be:
403 * num_patterns * sizeof(struct pci_match_conf)
404 * While it is certainly possible the user just
405 * allocated a large buffer, but set the number of
406 * matches correctly, it is far more likely that
407 * their kernel doesn't match the userland utility
408 * they're using. It's also possible that the user
409 * forgot to initialize some variables. Yes, this
410 * may be overly picky, but I hazard to guess that
411 * it's far more likely to just catch folks that
412 * updated their kernel but not their userland.
415 if (ap
->a_cmd
== PCIOCGETCONF_OLD
)
416 pbufsz
= sizeof(struct pci_match_conf_old
);
419 pbufsz
= sizeof(struct pci_match_conf
);
420 if (cio
->num_patterns
* pbufsz
!= cio
->pat_buf_len
) {
421 /* The user made a mistake, return an error. */
422 cio
->status
= PCI_GETCONF_ERROR
;
428 * Allocate a buffer to hold the patterns.
431 if (ap
->a_cmd
== PCIOCGETCONF_OLD
) {
432 pattern_buf_old
= kmalloc(cio
->pat_buf_len
,
434 error
= copyin(cio
->patterns
,
435 pattern_buf_old
, cio
->pat_buf_len
);
439 pattern_buf
= kmalloc(cio
->pat_buf_len
, M_TEMP
,
441 error
= copyin(cio
->patterns
, pattern_buf
,
448 num_patterns
= cio
->num_patterns
;
449 } else if ((cio
->num_patterns
> 0)
450 || (cio
->pat_buf_len
> 0)) {
452 * The user made a mistake, spit out an error.
454 cio
->status
= PCI_GETCONF_ERROR
;
460 * Go through the list of devices and copy out the devices
461 * that match the user's criteria.
463 for (cio
->num_matches
= 0, error
= 0, i
= 0,
464 dinfo
= STAILQ_FIRST(devlist_head
);
465 (dinfo
!= NULL
) && (cio
->num_matches
< ionum
)
466 && (error
== 0) && (i
< pci_numdevs
) && (dinfo
!= NULL
);
467 dinfo
= STAILQ_NEXT(dinfo
, pci_links
), i
++) {
472 /* Populate pd_name and pd_unit */
475 name
= device_get_name(dinfo
->cfg
.dev
);
477 strncpy(dinfo
->conf
.pd_name
, name
,
478 sizeof(dinfo
->conf
.pd_name
));
479 dinfo
->conf
.pd_name
[PCI_MAXNAMELEN
] = 0;
480 dinfo
->conf
.pd_unit
=
481 device_get_unit(dinfo
->cfg
.dev
);
483 dinfo
->conf
.pd_name
[0] = '\0';
484 dinfo
->conf
.pd_unit
= 0;
488 if ((ap
->a_cmd
== PCIOCGETCONF_OLD
&&
489 (pattern_buf_old
== NULL
||
490 pci_conf_match_old(pattern_buf_old
, num_patterns
,
491 &dinfo
->conf
) == 0)) ||
492 (ap
->a_cmd
== PCIOCGETCONF
&&
493 (pattern_buf
== NULL
||
494 pci_conf_match(pattern_buf
, num_patterns
,
495 &dinfo
->conf
) == 0))) {
497 if (pattern_buf
== NULL
||
498 pci_conf_match(pattern_buf
, num_patterns
,
499 &dinfo
->conf
) == 0) {
502 * If we've filled up the user's buffer,
503 * break out at this point. Since we've
504 * got a match here, we'll pick right back
505 * up at the matching entry. We can also
506 * tell the user that there are more matches
509 if (cio
->num_matches
>= ionum
)
513 if (ap
->a_cmd
== PCIOCGETCONF_OLD
) {
514 conf_old
.pc_sel
.pc_bus
=
515 dinfo
->conf
.pc_sel
.pc_bus
;
516 conf_old
.pc_sel
.pc_dev
=
517 dinfo
->conf
.pc_sel
.pc_dev
;
518 conf_old
.pc_sel
.pc_func
=
519 dinfo
->conf
.pc_sel
.pc_func
;
520 conf_old
.pc_hdr
= dinfo
->conf
.pc_hdr
;
521 conf_old
.pc_subvendor
=
522 dinfo
->conf
.pc_subvendor
;
523 conf_old
.pc_subdevice
=
524 dinfo
->conf
.pc_subdevice
;
526 dinfo
->conf
.pc_vendor
;
528 dinfo
->conf
.pc_device
;
530 dinfo
->conf
.pc_class
;
531 conf_old
.pc_subclass
=
532 dinfo
->conf
.pc_subclass
;
534 dinfo
->conf
.pc_progif
;
536 dinfo
->conf
.pc_revid
;
537 strncpy(conf_old
.pd_name
,
539 sizeof(conf_old
.pd_name
));
540 conf_old
.pd_name
[PCI_MAXNAMELEN
] = 0;
543 confdata
= &conf_old
;
546 confdata
= &dinfo
->conf
;
547 /* Only if we can copy it out do we count it. */
548 if (!(error
= copyout(confdata
,
549 (caddr_t
)cio
->matches
+
550 confsz
* cio
->num_matches
, confsz
)))
556 * Set the pointer into the list, so if the user is getting
557 * n records at a time, where n < pci_numdevs,
562 * Set the generation, the user will need this if they make
563 * another ioctl call with offset != 0.
565 cio
->generation
= pci_generation
;
568 * If this is the last device, inform the user so he won't
569 * bother asking for more devices. If dinfo isn't NULL, we
570 * know that there are more matches in the list because of
571 * the way the traversal is done.
574 cio
->status
= PCI_GETCONF_LAST_DEVICE
;
576 cio
->status
= PCI_GETCONF_MORE_DEVS
;
579 if (pattern_buf
!= NULL
)
580 kfree(pattern_buf
, M_TEMP
);
582 if (pattern_buf_old
!= NULL
)
583 kfree(pattern_buf_old
, M_TEMP
);
591 io_old
= (struct pci_io_old
*)ap
->a_data
;
592 iodata
.pi_sel
.pc_domain
= 0;
593 iodata
.pi_sel
.pc_bus
= io_old
->pi_sel
.pc_bus
;
594 iodata
.pi_sel
.pc_dev
= io_old
->pi_sel
.pc_dev
;
595 iodata
.pi_sel
.pc_func
= io_old
->pi_sel
.pc_func
;
596 iodata
.pi_reg
= io_old
->pi_reg
;
597 iodata
.pi_width
= io_old
->pi_width
;
598 iodata
.pi_data
= io_old
->pi_data
;
599 ap
->a_data
= (caddr_t
)&iodata
;
604 io
= (struct pci_io
*)ap
->a_data
;
605 switch(io
->pi_width
) {
609 /* Make sure register is not negative and aligned. */
610 if (io
->pi_reg
< 0 ||
611 io
->pi_reg
& (io
->pi_width
- 1)) {
616 * Assume that the user-level bus number is
617 * in fact the physical PCI bus number.
618 * Look up the grandparent, i.e. the bridge device,
619 * so that we can issue configuration space cycles.
621 pcidev
= pci_find_dbsf(io
->pi_sel
.pc_domain
,
622 io
->pi_sel
.pc_bus
, io
->pi_sel
.pc_dev
,
625 brdev
= device_get_parent(
626 device_get_parent(pcidev
));
629 if (ap
->a_cmd
== PCIOCWRITE
|| ap
->a_cmd
== PCIOCWRITE_OLD
)
631 if (ap
->a_cmd
== PCIOCWRITE
)
633 PCIB_WRITE_CONFIG(brdev
,
641 else if (ap
->a_cmd
== PCIOCREAD_OLD
)
643 PCIB_READ_CONFIG(brdev
,
652 PCIB_READ_CONFIG(brdev
,
660 #ifdef COMPAT_FREEBSD4
661 if (cmd
== PCIOCREAD_OLD
) {
662 io_old
->pi_data
= -1;
676 bio
= (struct pci_bar_io
*)ap
->a_data
;
679 * Assume that the user-level bus number is
680 * in fact the physical PCI bus number.
682 pcidev
= pci_find_dbsf(bio
->pbi_sel
.pc_domain
,
683 bio
->pbi_sel
.pc_bus
, bio
->pbi_sel
.pc_dev
,
684 bio
->pbi_sel
.pc_func
);
685 if (pcidev
== NULL
) {
689 dinfo
= device_get_ivars(pcidev
);
692 * Look for a resource list entry matching the requested BAR.
694 * XXX: This will not find BARs that are not initialized, but
697 rle
= resource_list_find(&dinfo
->resources
, SYS_RES_MEMORY
,
700 rle
= resource_list_find(&dinfo
->resources
,
701 SYS_RES_IOPORT
, bio
->pbi_reg
);
702 if (rle
== NULL
|| rle
->res
== NULL
) {
708 * Ok, we have a resource for this BAR. Read the lower
709 * 32 bits to get any flags.
711 value
= pci_read_config(pcidev
, bio
->pbi_reg
, 4);
712 if (PCI_BAR_MEM(value
)) {
713 if (rle
->type
!= SYS_RES_MEMORY
) {
717 value
&= ~PCIM_BAR_MEM_BASE
;
719 if (rle
->type
!= SYS_RES_IOPORT
) {
723 value
&= ~PCIM_BAR_IO_BASE
;
725 bio
->pbi_base
= rman_get_start(rle
->res
) | value
;
726 bio
->pbi_length
= rman_get_size(rle
->res
);
729 * Check the command register to determine if this BAR
732 value
= pci_read_config(pcidev
, PCIR_COMMAND
, 2);
733 if (rle
->type
== SYS_RES_MEMORY
)
734 bio
->pbi_enabled
= (value
& PCIM_CMD_MEMEN
) != 0;
736 bio
->pbi_enabled
= (value
& PCIM_CMD_PORTEN
) != 0;
741 io
= (struct pci_io
*)ap
->a_data
;
742 pcidev
= pci_find_dbsf(io
->pi_sel
.pc_domain
, io
->pi_sel
.pc_bus
,
743 io
->pi_sel
.pc_dev
, io
->pi_sel
.pc_func
);
745 io
->pi_data
= device_is_attached(pcidev
);
753 lwkt_reltoken(&pci_token
);