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.
59 static d_open_t pci_open
;
60 static d_close_t pci_close
;
61 static int pci_conf_match(struct pci_match_conf
*matches
, int num_matches
,
62 struct pci_conf
*match_buf
);
63 static d_ioctl_t pci_ioctl
;
65 struct dev_ops pci_ops
= {
73 pci_open(struct dev_open_args
*ap
)
75 int oflags
= ap
->a_oflags
;
77 if (oflags
& FWRITE
) {
86 pci_close(struct dev_close_args
*ap
)
92 * Match a single pci_conf structure against an array of pci_match_conf
93 * structures. The first argument, 'matches', is an array of num_matches
94 * pci_match_conf structures. match_buf is a pointer to the pci_conf
95 * structure that will be compared to every entry in the matches array.
96 * This function returns 1 on failure, 0 on success.
99 pci_conf_match(struct pci_match_conf
*matches
, int num_matches
,
100 struct pci_conf
*match_buf
)
104 if ((matches
== NULL
) || (match_buf
== NULL
) || (num_matches
<= 0))
107 for (i
= 0; i
< num_matches
; i
++) {
109 * I'm not sure why someone would do this...but...
111 if (matches
[i
].flags
== PCI_GETCONF_NO_MATCH
)
115 * Look at each of the match flags. If it's set, do the
116 * comparison. If the comparison fails, we don't have a
117 * match, go on to the next item if there is one.
119 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_DOMAIN
) != 0)
120 && (match_buf
->pc_sel
.pc_domain
!=
121 matches
[i
].pc_sel
.pc_domain
))
124 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_BUS
) != 0)
125 && (match_buf
->pc_sel
.pc_bus
!= matches
[i
].pc_sel
.pc_bus
))
128 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_DEV
) != 0)
129 && (match_buf
->pc_sel
.pc_dev
!= matches
[i
].pc_sel
.pc_dev
))
132 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_FUNC
) != 0)
133 && (match_buf
->pc_sel
.pc_func
!= matches
[i
].pc_sel
.pc_func
))
136 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_VENDOR
) != 0)
137 && (match_buf
->pc_vendor
!= matches
[i
].pc_vendor
))
140 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_DEVICE
) != 0)
141 && (match_buf
->pc_device
!= matches
[i
].pc_device
))
144 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_CLASS
) != 0)
145 && (match_buf
->pc_class
!= matches
[i
].pc_class
))
148 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_UNIT
) != 0)
149 && (match_buf
->pd_unit
!= matches
[i
].pd_unit
))
152 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_NAME
) != 0)
153 && (strncmp(matches
[i
].pd_name
, match_buf
->pd_name
,
154 sizeof(match_buf
->pd_name
)) != 0))
163 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
164 defined(COMPAT_FREEBSD6) || defined(__DragonFly__)
168 PCI_GETCONF_NO_MATCH_OLD
= 0x00,
169 PCI_GETCONF_MATCH_BUS_OLD
= 0x01,
170 PCI_GETCONF_MATCH_DEV_OLD
= 0x02,
171 PCI_GETCONF_MATCH_FUNC_OLD
= 0x04,
172 PCI_GETCONF_MATCH_NAME_OLD
= 0x08,
173 PCI_GETCONF_MATCH_UNIT_OLD
= 0x10,
174 PCI_GETCONF_MATCH_VENDOR_OLD
= 0x20,
175 PCI_GETCONF_MATCH_DEVICE_OLD
= 0x40,
176 PCI_GETCONF_MATCH_CLASS_OLD
= 0x80
177 } pci_getconf_flags_old
;
180 u_int8_t pc_bus
; /* bus number */
181 u_int8_t pc_dev
; /* device on this bus */
182 u_int8_t pc_func
; /* function on this device */
185 struct pci_conf_old
{
186 struct pcisel_old pc_sel
; /* bus+slot+function */
187 u_int8_t pc_hdr
; /* PCI header type */
188 u_int16_t pc_subvendor
; /* card vendor ID */
189 u_int16_t pc_subdevice
; /* card device ID, assigned by
191 u_int16_t pc_vendor
; /* chip vendor ID */
192 u_int16_t pc_device
; /* chip device ID, assigned by
194 u_int8_t pc_class
; /* chip PCI class */
195 u_int8_t pc_subclass
; /* chip PCI subclass */
196 u_int8_t pc_progif
; /* chip PCI programming interface */
197 u_int8_t pc_revid
; /* chip revision ID */
198 char pd_name
[PCI_MAXNAMELEN
+ 1]; /* device name */
199 u_long pd_unit
; /* device unit number */
202 struct pci_match_conf_old
{
203 struct pcisel_old pc_sel
; /* bus+slot+function */
204 char pd_name
[PCI_MAXNAMELEN
+ 1]; /* device name */
205 u_long pd_unit
; /* Unit number */
206 u_int16_t pc_vendor
; /* PCI Vendor ID */
207 u_int16_t pc_device
; /* PCI Device ID */
208 u_int8_t pc_class
; /* PCI class */
209 pci_getconf_flags_old flags
; /* Matching expression */
213 struct pcisel_old pi_sel
; /* device to operate on */
214 int pi_reg
; /* configuration register to examine */
215 int pi_width
; /* width (in bytes) of read or write */
216 u_int32_t pi_data
; /* data to write or result of read */
219 #define PCIOCGETCONF_OLD _IOWR('p', 1, struct pci_conf_io)
220 #define PCIOCREAD_OLD _IOWR('p', 2, struct pci_io_old)
221 #define PCIOCWRITE_OLD _IOWR('p', 3, struct pci_io_old)
223 static int pci_conf_match_old(struct pci_match_conf_old
*matches
,
224 int num_matches
, struct pci_conf
*match_buf
);
227 pci_conf_match_old(struct pci_match_conf_old
*matches
, int num_matches
,
228 struct pci_conf
*match_buf
)
232 if ((matches
== NULL
) || (match_buf
== NULL
) || (num_matches
<= 0))
235 for (i
= 0; i
< num_matches
; i
++) {
236 if (match_buf
->pc_sel
.pc_domain
!= 0)
240 * I'm not sure why someone would do this...but...
242 if (matches
[i
].flags
== PCI_GETCONF_NO_MATCH_OLD
)
246 * Look at each of the match flags. If it's set, do the
247 * comparison. If the comparison fails, we don't have a
248 * match, go on to the next item if there is one.
250 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_BUS_OLD
) != 0)
251 && (match_buf
->pc_sel
.pc_bus
!= matches
[i
].pc_sel
.pc_bus
))
254 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_DEV_OLD
) != 0)
255 && (match_buf
->pc_sel
.pc_dev
!= matches
[i
].pc_sel
.pc_dev
))
258 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_FUNC_OLD
) != 0)
259 && (match_buf
->pc_sel
.pc_func
!= matches
[i
].pc_sel
.pc_func
))
262 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_VENDOR_OLD
) != 0)
263 && (match_buf
->pc_vendor
!= matches
[i
].pc_vendor
))
266 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_DEVICE_OLD
) != 0)
267 && (match_buf
->pc_device
!= matches
[i
].pc_device
))
270 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_CLASS_OLD
) != 0)
271 && (match_buf
->pc_class
!= matches
[i
].pc_class
))
274 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_UNIT_OLD
) != 0)
275 && (match_buf
->pd_unit
!= matches
[i
].pd_unit
))
278 if (((matches
[i
].flags
& PCI_GETCONF_MATCH_NAME_OLD
) != 0)
279 && (strncmp(matches
[i
].pd_name
, match_buf
->pd_name
,
280 sizeof(match_buf
->pd_name
)) != 0))
292 pci_ioctl(struct dev_ioctl_args
*ap
)
294 device_t pcidev
, brdev
;
297 struct devlist
*devlist_head
;
298 struct pci_conf_io
*cio
;
299 struct pci_devinfo
*dinfo
;
301 struct pci_bar_io
*bio
;
302 struct pci_match_conf
*pattern_buf
;
303 struct resource_list_entry
*rle
;
305 size_t confsz
, iolen
, pbufsz
;
306 int error
, ionum
, i
, num_patterns
;
308 struct pci_conf_old conf_old
;
309 struct pci_io iodata
;
310 struct pci_io_old
*io_old
;
311 struct pci_match_conf_old
*pattern_buf_old
;
314 pattern_buf_old
= NULL
;
316 if (!(ap
->a_fflag
& FWRITE
) && ap
->a_cmd
!= PCIOCGETBAR
&&
317 ap
->a_cmd
!= PCIOCGETCONF
&& ap
->a_cmd
!= PCIOCGETCONF_OLD
)
320 if (!(ap
->a_fflag
& FWRITE
) && ap
->a_cmd
!= PCIOCGETBAR
&& ap
->a_cmd
!= PCIOCGETCONF
)
326 case PCIOCGETCONF_OLD
:
330 cio
= (struct pci_conf_io
*)ap
->a_data
;
336 cio
->num_matches
= 0;
339 * If the user specified an offset into the device list,
340 * but the list has changed since they last called this
341 * ioctl, tell them that the list has changed. They will
342 * have to get the list from the beginning.
344 if ((cio
->offset
!= 0)
345 && (cio
->generation
!= pci_generation
)){
346 cio
->status
= PCI_GETCONF_LIST_CHANGED
;
352 * Check to see whether the user has asked for an offset
353 * past the end of our list.
355 if (cio
->offset
>= pci_numdevs
) {
356 cio
->status
= PCI_GETCONF_LAST_DEVICE
;
361 /* get the head of the device queue */
362 devlist_head
= &pci_devq
;
365 * Determine how much room we have for pci_conf structures.
366 * Round the user's buffer size down to the nearest
367 * multiple of sizeof(struct pci_conf) in case the user
368 * didn't specify a multiple of that size.
371 if (ap
->a_cmd
== PCIOCGETCONF_OLD
)
372 confsz
= sizeof(struct pci_conf_old
);
375 confsz
= sizeof(struct pci_conf
);
376 iolen
= min(cio
->match_buf_len
- (cio
->match_buf_len
% confsz
),
377 pci_numdevs
* confsz
);
380 * Since we know that iolen is a multiple of the size of
381 * the pciconf union, it's okay to do this.
383 ionum
= iolen
/ confsz
;
386 * If this test is true, the user wants the pci_conf
387 * structures returned to match the supplied entries.
389 if ((cio
->num_patterns
> 0) && (cio
->num_patterns
< pci_numdevs
)
390 && (cio
->pat_buf_len
> 0)) {
392 * pat_buf_len needs to be:
393 * num_patterns * sizeof(struct pci_match_conf)
394 * While it is certainly possible the user just
395 * allocated a large buffer, but set the number of
396 * matches correctly, it is far more likely that
397 * their kernel doesn't match the userland utility
398 * they're using. It's also possible that the user
399 * forgot to initialize some variables. Yes, this
400 * may be overly picky, but I hazard to guess that
401 * it's far more likely to just catch folks that
402 * updated their kernel but not their userland.
405 if (ap
->a_cmd
== PCIOCGETCONF_OLD
)
406 pbufsz
= sizeof(struct pci_match_conf_old
);
409 pbufsz
= sizeof(struct pci_match_conf
);
410 if (cio
->num_patterns
* pbufsz
!= cio
->pat_buf_len
) {
411 /* The user made a mistake, return an error. */
412 cio
->status
= PCI_GETCONF_ERROR
;
418 * Allocate a buffer to hold the patterns.
421 if (ap
->a_cmd
== PCIOCGETCONF_OLD
) {
422 pattern_buf_old
= kmalloc(cio
->pat_buf_len
,
424 error
= copyin(cio
->patterns
,
425 pattern_buf_old
, cio
->pat_buf_len
);
429 pattern_buf
= kmalloc(cio
->pat_buf_len
, M_TEMP
,
431 error
= copyin(cio
->patterns
, pattern_buf
,
438 num_patterns
= cio
->num_patterns
;
439 } else if ((cio
->num_patterns
> 0)
440 || (cio
->pat_buf_len
> 0)) {
442 * The user made a mistake, spit out an error.
444 cio
->status
= PCI_GETCONF_ERROR
;
450 * Go through the list of devices and copy out the devices
451 * that match the user's criteria.
453 for (cio
->num_matches
= 0, error
= 0, i
= 0,
454 dinfo
= STAILQ_FIRST(devlist_head
);
455 (dinfo
!= NULL
) && (cio
->num_matches
< ionum
)
456 && (error
== 0) && (i
< pci_numdevs
) && (dinfo
!= NULL
);
457 dinfo
= STAILQ_NEXT(dinfo
, pci_links
), i
++) {
462 /* Populate pd_name and pd_unit */
465 name
= device_get_name(dinfo
->cfg
.dev
);
467 strncpy(dinfo
->conf
.pd_name
, name
,
468 sizeof(dinfo
->conf
.pd_name
));
469 dinfo
->conf
.pd_name
[PCI_MAXNAMELEN
] = 0;
470 dinfo
->conf
.pd_unit
=
471 device_get_unit(dinfo
->cfg
.dev
);
473 dinfo
->conf
.pd_name
[0] = '\0';
474 dinfo
->conf
.pd_unit
= 0;
478 if ((ap
->a_cmd
== PCIOCGETCONF_OLD
&&
479 (pattern_buf_old
== NULL
||
480 pci_conf_match_old(pattern_buf_old
, num_patterns
,
481 &dinfo
->conf
) == 0)) ||
482 (ap
->a_cmd
== PCIOCGETCONF
&&
483 (pattern_buf
== NULL
||
484 pci_conf_match(pattern_buf
, num_patterns
,
485 &dinfo
->conf
) == 0))) {
487 if (pattern_buf
== NULL
||
488 pci_conf_match(pattern_buf
, num_patterns
,
489 &dinfo
->conf
) == 0) {
492 * If we've filled up the user's buffer,
493 * break out at this point. Since we've
494 * got a match here, we'll pick right back
495 * up at the matching entry. We can also
496 * tell the user that there are more matches
499 if (cio
->num_matches
>= ionum
)
503 if (ap
->a_cmd
== PCIOCGETCONF_OLD
) {
504 conf_old
.pc_sel
.pc_bus
=
505 dinfo
->conf
.pc_sel
.pc_bus
;
506 conf_old
.pc_sel
.pc_dev
=
507 dinfo
->conf
.pc_sel
.pc_dev
;
508 conf_old
.pc_sel
.pc_func
=
509 dinfo
->conf
.pc_sel
.pc_func
;
510 conf_old
.pc_hdr
= dinfo
->conf
.pc_hdr
;
511 conf_old
.pc_subvendor
=
512 dinfo
->conf
.pc_subvendor
;
513 conf_old
.pc_subdevice
=
514 dinfo
->conf
.pc_subdevice
;
516 dinfo
->conf
.pc_vendor
;
518 dinfo
->conf
.pc_device
;
520 dinfo
->conf
.pc_class
;
521 conf_old
.pc_subclass
=
522 dinfo
->conf
.pc_subclass
;
524 dinfo
->conf
.pc_progif
;
526 dinfo
->conf
.pc_revid
;
527 strncpy(conf_old
.pd_name
,
529 sizeof(conf_old
.pd_name
));
530 conf_old
.pd_name
[PCI_MAXNAMELEN
] = 0;
533 confdata
= &conf_old
;
536 confdata
= &dinfo
->conf
;
537 /* Only if we can copy it out do we count it. */
538 if (!(error
= copyout(confdata
,
539 (caddr_t
)cio
->matches
+
540 confsz
* cio
->num_matches
, confsz
)))
546 * Set the pointer into the list, so if the user is getting
547 * n records at a time, where n < pci_numdevs,
552 * Set the generation, the user will need this if they make
553 * another ioctl call with offset != 0.
555 cio
->generation
= pci_generation
;
558 * If this is the last device, inform the user so he won't
559 * bother asking for more devices. If dinfo isn't NULL, we
560 * know that there are more matches in the list because of
561 * the way the traversal is done.
564 cio
->status
= PCI_GETCONF_LAST_DEVICE
;
566 cio
->status
= PCI_GETCONF_MORE_DEVS
;
569 if (pattern_buf
!= NULL
)
570 kfree(pattern_buf
, M_TEMP
);
572 if (pattern_buf_old
!= NULL
)
573 kfree(pattern_buf_old
, M_TEMP
);
581 io_old
= (struct pci_io_old
*)ap
->a_data
;
582 iodata
.pi_sel
.pc_domain
= 0;
583 iodata
.pi_sel
.pc_bus
= io_old
->pi_sel
.pc_bus
;
584 iodata
.pi_sel
.pc_dev
= io_old
->pi_sel
.pc_dev
;
585 iodata
.pi_sel
.pc_func
= io_old
->pi_sel
.pc_func
;
586 iodata
.pi_reg
= io_old
->pi_reg
;
587 iodata
.pi_width
= io_old
->pi_width
;
588 iodata
.pi_data
= io_old
->pi_data
;
589 ap
->a_data
= (caddr_t
)&iodata
;
594 io
= (struct pci_io
*)ap
->a_data
;
595 switch(io
->pi_width
) {
599 /* Make sure register is not negative and aligned. */
600 if (io
->pi_reg
< 0 ||
601 io
->pi_reg
& (io
->pi_width
- 1)) {
606 * Assume that the user-level bus number is
607 * in fact the physical PCI bus number.
608 * Look up the grandparent, i.e. the bridge device,
609 * so that we can issue configuration space cycles.
611 pcidev
= pci_find_dbsf(io
->pi_sel
.pc_domain
,
612 io
->pi_sel
.pc_bus
, io
->pi_sel
.pc_dev
,
615 brdev
= device_get_parent(
616 device_get_parent(pcidev
));
619 if (ap
->a_cmd
== PCIOCWRITE
|| ap
->a_cmd
== PCIOCWRITE_OLD
)
621 if (ap
->a_cmd
== PCIOCWRITE
)
623 PCIB_WRITE_CONFIG(brdev
,
631 else if (ap
->a_cmd
== PCIOCREAD_OLD
)
633 PCIB_READ_CONFIG(brdev
,
642 PCIB_READ_CONFIG(brdev
,
650 #ifdef COMPAT_FREEBSD4
651 if (cmd
== PCIOCREAD_OLD
) {
652 io_old
->pi_data
= -1;
666 bio
= (struct pci_bar_io
*)ap
->a_data
;
669 * Assume that the user-level bus number is
670 * in fact the physical PCI bus number.
672 pcidev
= pci_find_dbsf(bio
->pbi_sel
.pc_domain
,
673 bio
->pbi_sel
.pc_bus
, bio
->pbi_sel
.pc_dev
,
674 bio
->pbi_sel
.pc_func
);
675 if (pcidev
== NULL
) {
679 dinfo
= device_get_ivars(pcidev
);
682 * Look for a resource list entry matching the requested BAR.
684 * XXX: This will not find BARs that are not initialized, but
687 rle
= resource_list_find(&dinfo
->resources
, SYS_RES_MEMORY
,
690 rle
= resource_list_find(&dinfo
->resources
,
691 SYS_RES_IOPORT
, bio
->pbi_reg
);
692 if (rle
== NULL
|| rle
->res
== NULL
) {
698 * Ok, we have a resource for this BAR. Read the lower
699 * 32 bits to get any flags.
701 value
= pci_read_config(pcidev
, bio
->pbi_reg
, 4);
702 if (PCI_BAR_MEM(value
)) {
703 if (rle
->type
!= SYS_RES_MEMORY
) {
707 value
&= ~PCIM_BAR_MEM_BASE
;
709 if (rle
->type
!= SYS_RES_IOPORT
) {
713 value
&= ~PCIM_BAR_IO_BASE
;
715 bio
->pbi_base
= rman_get_start(rle
->res
) | value
;
716 bio
->pbi_length
= rman_get_size(rle
->res
);
719 * Check the command register to determine if this BAR
722 value
= pci_read_config(pcidev
, PCIR_COMMAND
, 2);
723 if (rle
->type
== SYS_RES_MEMORY
)
724 bio
->pbi_enabled
= (value
& PCIM_CMD_MEMEN
) != 0;
726 bio
->pbi_enabled
= (value
& PCIM_CMD_PORTEN
) != 0;
731 io
= (struct pci_io
*)ap
->a_data
;
732 pcidev
= pci_find_dbsf(io
->pi_sel
.pc_domain
, io
->pi_sel
.pc_bus
,
733 io
->pi_sel
.pc_dev
, io
->pi_sel
.pc_func
);
735 io
->pi_data
= device_is_attached(pcidev
);