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>
36 #include <sys/kernel.h>
38 #include <sys/queue.h>
39 #include <sys/types.h>
43 #include <vm/vm_extern.h>
47 #include <sys/device.h>
48 #include <sys/pciio.h>
49 #include <bus/pci/pcireg.h>
50 #include <bus/pci/pcivar.h>
56 * This is the user interface to PCI configuration space.
58 static struct lwkt_token pci_token
= LWKT_TOKEN_INITIALIZER(pci_token
);
60 static d_open_t pci_open
;
61 static d_close_t pci_close
;
62 static int pci_conf_match(struct pci_match_conf
*matches
, int num_matches
,
63 struct pci_conf
*match_buf
);
64 static d_ioctl_t pci_ioctl
;
66 struct dev_ops pci_ops
= {
67 { "pci", 0, D_MPSAFE
},
74 pci_open(struct dev_open_args
*ap
)
76 int oflags
= ap
->a_oflags
;
78 if (oflags
& FWRITE
) {
87 pci_close(struct dev_close_args
*ap
)
93 * Match a single pci_conf structure against an array of pci_match_conf
94 * structures. The first argument, 'matches', is an array of num_matches
95 * pci_match_conf structures. match_buf is a pointer to the pci_conf
96 * structure that will be compared to every entry in the matches array.
97 * This function returns 1 on failure, 0 on success.
100 pci_conf_match(struct pci_match_conf
*matches
, int num_matches
,
101 struct pci_conf
*match_buf
)
105 if ((matches
== NULL
) || (match_buf
== NULL
) || (num_matches
<= 0))
108 for (i
= 0; i
< num_matches
; i
++) {
110 * I'm not sure why someone would do this...but...
112 if (matches
[i
].flags
== PCI_GETCONF_NO_MATCH
)
116 * Look at each of the match flags. If it's set, do the
117 * comparison. If the comparison fails, we don't have a
118 * match, go on to the next item if there is one.
120 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_DOMAIN
) != 0)
121 && (match_buf
->pc_sel
.pc_domain
!=
122 matches
[i
].pc_sel
.pc_domain
))
125 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_BUS
) != 0)
126 && (match_buf
->pc_sel
.pc_bus
!= matches
[i
].pc_sel
.pc_bus
))
129 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_DEV
) != 0)
130 && (match_buf
->pc_sel
.pc_dev
!= matches
[i
].pc_sel
.pc_dev
))
133 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_FUNC
) != 0)
134 && (match_buf
->pc_sel
.pc_func
!= matches
[i
].pc_sel
.pc_func
))
137 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_VENDOR
) != 0)
138 && (match_buf
->pc_vendor
!= matches
[i
].pc_vendor
))
141 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_DEVICE
) != 0)
142 && (match_buf
->pc_device
!= matches
[i
].pc_device
))
145 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_CLASS
) != 0)
146 && (match_buf
->pc_class
!= matches
[i
].pc_class
))
149 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_UNIT
) != 0)
150 && (match_buf
->pd_unit
!= matches
[i
].pd_unit
))
153 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_NAME
) != 0)
154 && (strncmp(matches
[i
].pd_name
, match_buf
->pd_name
,
155 sizeof(match_buf
->pd_name
)) != 0))
164 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
165 defined(COMPAT_FREEBSD6) || defined(__DragonFly__)
169 PCI_GETCONF_NO_MATCH_OLD
= 0x00,
170 PCI_GETCONF_MATCH_BUS_OLD
= 0x01,
171 PCI_GETCONF_MATCH_DEV_OLD
= 0x02,
172 PCI_GETCONF_MATCH_FUNC_OLD
= 0x04,
173 PCI_GETCONF_MATCH_NAME_OLD
= 0x08,
174 PCI_GETCONF_MATCH_UNIT_OLD
= 0x10,
175 PCI_GETCONF_MATCH_VENDOR_OLD
= 0x20,
176 PCI_GETCONF_MATCH_DEVICE_OLD
= 0x40,
177 PCI_GETCONF_MATCH_CLASS_OLD
= 0x80
178 } pci_getconf_flags_old
;
181 u_int8_t pc_bus
; /* bus number */
182 u_int8_t pc_dev
; /* device on this bus */
183 u_int8_t pc_func
; /* function on this device */
186 struct pci_conf_old
{
187 struct pcisel_old pc_sel
; /* bus+slot+function */
188 u_int8_t pc_hdr
; /* PCI header type */
189 u_int16_t pc_subvendor
; /* card vendor ID */
190 u_int16_t pc_subdevice
; /* card device ID, assigned by
192 u_int16_t pc_vendor
; /* chip vendor ID */
193 u_int16_t pc_device
; /* chip device ID, assigned by
195 u_int8_t pc_class
; /* chip PCI class */
196 u_int8_t pc_subclass
; /* chip PCI subclass */
197 u_int8_t pc_progif
; /* chip PCI programming interface */
198 u_int8_t pc_revid
; /* chip revision ID */
199 char pd_name
[PCI_MAXNAMELEN
+ 1]; /* device name */
200 u_long pd_unit
; /* device unit number */
203 struct pci_match_conf_old
{
204 struct pcisel_old pc_sel
; /* bus+slot+function */
205 char pd_name
[PCI_MAXNAMELEN
+ 1]; /* device name */
206 u_long pd_unit
; /* Unit number */
207 u_int16_t pc_vendor
; /* PCI Vendor ID */
208 u_int16_t pc_device
; /* PCI Device ID */
209 u_int8_t pc_class
; /* PCI class */
210 pci_getconf_flags_old flags
; /* Matching expression */
214 struct pcisel_old pi_sel
; /* device to operate on */
215 int pi_reg
; /* configuration register to examine */
216 int pi_width
; /* width (in bytes) of read or write */
217 u_int32_t pi_data
; /* data to write or result of read */
220 #define PCIOCGETCONF_OLD _IOWR('p', 1, struct pci_conf_io)
221 #define PCIOCREAD_OLD _IOWR('p', 2, struct pci_io_old)
222 #define PCIOCWRITE_OLD _IOWR('p', 3, struct pci_io_old)
224 static int pci_conf_match_old(struct pci_match_conf_old
*matches
,
225 int num_matches
, struct pci_conf
*match_buf
);
228 pci_conf_match_old(struct pci_match_conf_old
*matches
, int num_matches
,
229 struct pci_conf
*match_buf
)
233 if ((matches
== NULL
) || (match_buf
== NULL
) || (num_matches
<= 0))
236 for (i
= 0; i
< num_matches
; i
++) {
237 if (match_buf
->pc_sel
.pc_domain
!= 0)
241 * I'm not sure why someone would do this...but...
243 if (matches
[i
].flags
== PCI_GETCONF_NO_MATCH_OLD
)
247 * Look at each of the match flags. If it's set, do the
248 * comparison. If the comparison fails, we don't have a
249 * match, go on to the next item if there is one.
251 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_BUS_OLD
) != 0)
252 && (match_buf
->pc_sel
.pc_bus
!= matches
[i
].pc_sel
.pc_bus
))
255 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_DEV_OLD
) != 0)
256 && (match_buf
->pc_sel
.pc_dev
!= matches
[i
].pc_sel
.pc_dev
))
259 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_FUNC_OLD
) != 0)
260 && (match_buf
->pc_sel
.pc_func
!= matches
[i
].pc_sel
.pc_func
))
263 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_VENDOR_OLD
) != 0)
264 && (match_buf
->pc_vendor
!= matches
[i
].pc_vendor
))
267 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_DEVICE_OLD
) != 0)
268 && (match_buf
->pc_device
!= matches
[i
].pc_device
))
271 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_CLASS_OLD
) != 0)
272 && (match_buf
->pc_class
!= matches
[i
].pc_class
))
275 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_UNIT_OLD
) != 0)
276 && (match_buf
->pd_unit
!= matches
[i
].pd_unit
))
279 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_NAME_OLD
) != 0)
280 && (strncmp(matches
[i
].pd_name
, match_buf
->pd_name
,
281 sizeof(match_buf
->pd_name
)) != 0))
293 pci_ioctl(struct dev_ioctl_args
*ap
)
295 device_t pcidev
, brdev
;
298 struct devlist
*devlist_head
;
299 struct pci_conf_io
*cio
;
300 struct pci_devinfo
*dinfo
;
302 struct pci_bar_io
*bio
;
303 struct pci_match_conf
*pattern_buf
;
304 struct resource_list_entry
*rle
;
306 size_t confsz
, iolen
, pbufsz
;
307 int error
, ionum
, i
, num_patterns
;
309 struct pci_conf_old conf_old
;
310 struct pci_io iodata
;
311 struct pci_io_old
*io_old
;
312 struct pci_match_conf_old
*pattern_buf_old
;
315 pattern_buf_old
= NULL
;
317 if (!(ap
->a_fflag
& FWRITE
) && ap
->a_cmd
!= PCIOCGETBAR
&&
318 ap
->a_cmd
!= PCIOCGETCONF
&& ap
->a_cmd
!= PCIOCGETCONF_OLD
)
321 if (!(ap
->a_fflag
& FWRITE
) && ap
->a_cmd
!= PCIOCGETBAR
&& ap
->a_cmd
!= PCIOCGETCONF
)
325 lwkt_gettoken(&pci_token
);
329 case PCIOCGETCONF_OLD
:
333 cio
= (struct pci_conf_io
*)ap
->a_data
;
339 cio
->num_matches
= 0;
342 * If the user specified an offset into the device list,
343 * but the list has changed since they last called this
344 * ioctl, tell them that the list has changed. They will
345 * have to get the list from the beginning.
347 if ((cio
->offset
!= 0)
348 && (cio
->generation
!= pci_generation
)){
349 cio
->status
= PCI_GETCONF_LIST_CHANGED
;
355 * Check to see whether the user has asked for an offset
356 * past the end of our list.
358 if (cio
->offset
>= pci_numdevs
) {
359 cio
->status
= PCI_GETCONF_LAST_DEVICE
;
364 /* get the head of the device queue */
365 devlist_head
= &pci_devq
;
368 * Determine how much room we have for pci_conf structures.
369 * Round the user's buffer size down to the nearest
370 * multiple of sizeof(struct pci_conf) in case the user
371 * didn't specify a multiple of that size.
374 if (ap
->a_cmd
== PCIOCGETCONF_OLD
)
375 confsz
= sizeof(struct pci_conf_old
);
378 confsz
= sizeof(struct pci_conf
);
379 iolen
= min(cio
->match_buf_len
- (cio
->match_buf_len
% confsz
),
380 pci_numdevs
* confsz
);
383 * Since we know that iolen is a multiple of the size of
384 * the pciconf union, it's okay to do this.
386 ionum
= iolen
/ confsz
;
389 * If this test is true, the user wants the pci_conf
390 * structures returned to match the supplied entries.
392 if ((cio
->num_patterns
> 0) && (cio
->num_patterns
< pci_numdevs
)
393 && (cio
->pat_buf_len
> 0)) {
395 * pat_buf_len needs to be:
396 * num_patterns * sizeof(struct pci_match_conf)
397 * While it is certainly possible the user just
398 * allocated a large buffer, but set the number of
399 * matches correctly, it is far more likely that
400 * their kernel doesn't match the userland utility
401 * they're using. It's also possible that the user
402 * forgot to initialize some variables. Yes, this
403 * may be overly picky, but I hazard to guess that
404 * it's far more likely to just catch folks that
405 * updated their kernel but not their userland.
408 if (ap
->a_cmd
== PCIOCGETCONF_OLD
)
409 pbufsz
= sizeof(struct pci_match_conf_old
);
412 pbufsz
= sizeof(struct pci_match_conf
);
413 if (cio
->num_patterns
* pbufsz
!= cio
->pat_buf_len
) {
414 /* The user made a mistake, return an error. */
415 cio
->status
= PCI_GETCONF_ERROR
;
421 * Allocate a buffer to hold the patterns.
424 if (ap
->a_cmd
== PCIOCGETCONF_OLD
) {
425 pattern_buf_old
= kmalloc(cio
->pat_buf_len
,
427 error
= copyin(cio
->patterns
,
428 pattern_buf_old
, cio
->pat_buf_len
);
432 pattern_buf
= kmalloc(cio
->pat_buf_len
, M_TEMP
,
434 error
= copyin(cio
->patterns
, pattern_buf
,
441 num_patterns
= cio
->num_patterns
;
442 } else if ((cio
->num_patterns
> 0)
443 || (cio
->pat_buf_len
> 0)) {
445 * The user made a mistake, spit out an error.
447 cio
->status
= PCI_GETCONF_ERROR
;
453 * Go through the list of devices and copy out the devices
454 * that match the user's criteria.
456 for (cio
->num_matches
= 0, error
= 0, i
= 0,
457 dinfo
= STAILQ_FIRST(devlist_head
);
458 (dinfo
!= NULL
) && (cio
->num_matches
< ionum
)
459 && (error
== 0) && (i
< pci_numdevs
) && (dinfo
!= NULL
);
460 dinfo
= STAILQ_NEXT(dinfo
, pci_links
), i
++) {
465 /* Populate pd_name and pd_unit */
468 name
= device_get_name(dinfo
->cfg
.dev
);
470 strncpy(dinfo
->conf
.pd_name
, name
,
471 sizeof(dinfo
->conf
.pd_name
));
472 dinfo
->conf
.pd_name
[PCI_MAXNAMELEN
] = 0;
473 dinfo
->conf
.pd_unit
=
474 device_get_unit(dinfo
->cfg
.dev
);
476 dinfo
->conf
.pd_name
[0] = '\0';
477 dinfo
->conf
.pd_unit
= 0;
481 if ((ap
->a_cmd
== PCIOCGETCONF_OLD
&&
482 (pattern_buf_old
== NULL
||
483 pci_conf_match_old(pattern_buf_old
, num_patterns
,
484 &dinfo
->conf
) == 0)) ||
485 (ap
->a_cmd
== PCIOCGETCONF
&&
486 (pattern_buf
== NULL
||
487 pci_conf_match(pattern_buf
, num_patterns
,
488 &dinfo
->conf
) == 0))) {
490 if (pattern_buf
== NULL
||
491 pci_conf_match(pattern_buf
, num_patterns
,
492 &dinfo
->conf
) == 0) {
495 * If we've filled up the user's buffer,
496 * break out at this point. Since we've
497 * got a match here, we'll pick right back
498 * up at the matching entry. We can also
499 * tell the user that there are more matches
502 if (cio
->num_matches
>= ionum
)
506 if (ap
->a_cmd
== PCIOCGETCONF_OLD
) {
507 conf_old
.pc_sel
.pc_bus
=
508 dinfo
->conf
.pc_sel
.pc_bus
;
509 conf_old
.pc_sel
.pc_dev
=
510 dinfo
->conf
.pc_sel
.pc_dev
;
511 conf_old
.pc_sel
.pc_func
=
512 dinfo
->conf
.pc_sel
.pc_func
;
513 conf_old
.pc_hdr
= dinfo
->conf
.pc_hdr
;
514 conf_old
.pc_subvendor
=
515 dinfo
->conf
.pc_subvendor
;
516 conf_old
.pc_subdevice
=
517 dinfo
->conf
.pc_subdevice
;
519 dinfo
->conf
.pc_vendor
;
521 dinfo
->conf
.pc_device
;
523 dinfo
->conf
.pc_class
;
524 conf_old
.pc_subclass
=
525 dinfo
->conf
.pc_subclass
;
527 dinfo
->conf
.pc_progif
;
529 dinfo
->conf
.pc_revid
;
530 strncpy(conf_old
.pd_name
,
532 sizeof(conf_old
.pd_name
));
533 conf_old
.pd_name
[PCI_MAXNAMELEN
] = 0;
536 confdata
= &conf_old
;
539 confdata
= &dinfo
->conf
;
540 /* Only if we can copy it out do we count it. */
541 if (!(error
= copyout(confdata
,
542 (caddr_t
)cio
->matches
+
543 confsz
* cio
->num_matches
, confsz
)))
549 * Set the pointer into the list, so if the user is getting
550 * n records at a time, where n < pci_numdevs,
555 * Set the generation, the user will need this if they make
556 * another ioctl call with offset != 0.
558 cio
->generation
= pci_generation
;
561 * If this is the last device, inform the user so he won't
562 * bother asking for more devices. If dinfo isn't NULL, we
563 * know that there are more matches in the list because of
564 * the way the traversal is done.
567 cio
->status
= PCI_GETCONF_LAST_DEVICE
;
569 cio
->status
= PCI_GETCONF_MORE_DEVS
;
572 if (pattern_buf
!= NULL
)
573 kfree(pattern_buf
, M_TEMP
);
575 if (pattern_buf_old
!= NULL
)
576 kfree(pattern_buf_old
, M_TEMP
);
584 io_old
= (struct pci_io_old
*)ap
->a_data
;
585 iodata
.pi_sel
.pc_domain
= 0;
586 iodata
.pi_sel
.pc_bus
= io_old
->pi_sel
.pc_bus
;
587 iodata
.pi_sel
.pc_dev
= io_old
->pi_sel
.pc_dev
;
588 iodata
.pi_sel
.pc_func
= io_old
->pi_sel
.pc_func
;
589 iodata
.pi_reg
= io_old
->pi_reg
;
590 iodata
.pi_width
= io_old
->pi_width
;
591 iodata
.pi_data
= io_old
->pi_data
;
592 ap
->a_data
= (caddr_t
)&iodata
;
597 io
= (struct pci_io
*)ap
->a_data
;
598 switch(io
->pi_width
) {
602 /* Make sure register is not negative and aligned. */
603 if (io
->pi_reg
< 0 ||
604 io
->pi_reg
& (io
->pi_width
- 1)) {
609 * Assume that the user-level bus number is
610 * in fact the physical PCI bus number.
611 * Look up the grandparent, i.e. the bridge device,
612 * so that we can issue configuration space cycles.
614 pcidev
= pci_find_dbsf(io
->pi_sel
.pc_domain
,
615 io
->pi_sel
.pc_bus
, io
->pi_sel
.pc_dev
,
618 brdev
= device_get_parent(
619 device_get_parent(pcidev
));
622 if (ap
->a_cmd
== PCIOCWRITE
|| ap
->a_cmd
== PCIOCWRITE_OLD
)
624 if (ap
->a_cmd
== PCIOCWRITE
)
626 PCIB_WRITE_CONFIG(brdev
,
634 else if (ap
->a_cmd
== PCIOCREAD_OLD
)
636 PCIB_READ_CONFIG(brdev
,
645 PCIB_READ_CONFIG(brdev
,
653 #ifdef COMPAT_FREEBSD4
654 if (cmd
== PCIOCREAD_OLD
) {
655 io_old
->pi_data
= -1;
669 bio
= (struct pci_bar_io
*)ap
->a_data
;
672 * Assume that the user-level bus number is
673 * in fact the physical PCI bus number.
675 pcidev
= pci_find_dbsf(bio
->pbi_sel
.pc_domain
,
676 bio
->pbi_sel
.pc_bus
, bio
->pbi_sel
.pc_dev
,
677 bio
->pbi_sel
.pc_func
);
678 if (pcidev
== NULL
) {
682 dinfo
= device_get_ivars(pcidev
);
685 * Look for a resource list entry matching the requested BAR.
687 * XXX: This will not find BARs that are not initialized, but
690 rle
= resource_list_find(&dinfo
->resources
, SYS_RES_MEMORY
,
693 rle
= resource_list_find(&dinfo
->resources
,
694 SYS_RES_IOPORT
, bio
->pbi_reg
);
695 if (rle
== NULL
|| rle
->res
== NULL
) {
701 * Ok, we have a resource for this BAR. Read the lower
702 * 32 bits to get any flags.
704 value
= pci_read_config(pcidev
, bio
->pbi_reg
, 4);
705 if (PCI_BAR_MEM(value
)) {
706 if (rle
->type
!= SYS_RES_MEMORY
) {
710 value
&= ~PCIM_BAR_MEM_BASE
;
712 if (rle
->type
!= SYS_RES_IOPORT
) {
716 value
&= ~PCIM_BAR_IO_BASE
;
718 bio
->pbi_base
= rman_get_start(rle
->res
) | value
;
719 bio
->pbi_length
= rman_get_size(rle
->res
);
722 * Check the command register to determine if this BAR
725 value
= pci_read_config(pcidev
, PCIR_COMMAND
, 2);
726 if (rle
->type
== SYS_RES_MEMORY
)
727 bio
->pbi_enabled
= (value
& PCIM_CMD_MEMEN
) != 0;
729 bio
->pbi_enabled
= (value
& PCIM_CMD_PORTEN
) != 0;
734 io
= (struct pci_io
*)ap
->a_data
;
735 pcidev
= pci_find_dbsf(io
->pi_sel
.pc_domain
, io
->pi_sel
.pc_bus
,
736 io
->pi_sel
.pc_dev
, io
->pi_sel
.pc_func
);
738 io
->pi_data
= device_is_attached(pcidev
);
746 lwkt_reltoken(&pci_token
);