Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/pci/pci_user.c
Show All 25 Lines | |||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include "opt_bus.h" /* XXX trim includes */ | #include "opt_bus.h" /* XXX trim includes */ | ||||
#include <sys/types.h> | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/linker.h> | #include <sys/linker.h> | ||||
#include <sys/fcntl.h> | #include <sys/fcntl.h> | ||||
#include <sys/conf.h> | #include <sys/conf.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/mman.h> | |||||
#include <sys/proc.h> | #include <sys/proc.h> | ||||
#include <sys/queue.h> | #include <sys/queue.h> | ||||
#include <sys/types.h> | #include <sys/rwlock.h> | ||||
#include <sys/sglist.h> | |||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/pmap.h> | #include <vm/pmap.h> | ||||
#include <vm/vm_extern.h> | #include <vm/vm_extern.h> | ||||
#include <vm/vm_map.h> | |||||
#include <vm/vm_object.h> | |||||
#include <vm/vm_page.h> | |||||
#include <vm/vm_pager.h> | |||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#include <sys/rman.h> | #include <sys/rman.h> | ||||
#include <machine/resource.h> | #include <machine/resource.h> | ||||
#include <sys/pciio.h> | #include <sys/pciio.h> | ||||
#include <dev/pci/pcireg.h> | #include <dev/pci/pcireg.h> | ||||
▲ Show 20 Lines • Show All 635 Lines • ▼ Show 20 Lines | #endif /* PRE7_COMPAT */ | ||||
default: | default: | ||||
/* programmer error */ | /* programmer error */ | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
static int | static int | ||||
pci_bar_mmap(device_t pcidev, struct pci_bar_mmap *pbm) | |||||
{ | |||||
vm_map_t map; | |||||
vm_object_t obj; | |||||
struct thread *td; | |||||
struct sglist *sg; | |||||
struct pci_map *pm; | |||||
vm_paddr_t pbase; | |||||
vm_size_t plen; | |||||
vm_offset_t addr; | |||||
vm_prot_t prot; | |||||
int error, flags; | |||||
td = curthread; | |||||
map = &td->td_proc->p_vmspace->vm_map; | |||||
if ((pbm->pbm_flags & ~(PCIIO_BAR_MMAP_FIXED | PCIIO_BAR_MMAP_EXCL | | |||||
PCIIO_BAR_MMAP_RW | PCIIO_BAR_MMAP_ACTIVATE)) != 0 || | |||||
pbm->pbm_memattr != (vm_memattr_t)pbm->pbm_memattr || | |||||
!pmap_is_valid_memattr(map->pmap, pbm->pbm_memattr)) | |||||
return (EINVAL); | |||||
/* Fetch the BAR physical base and length. */ | |||||
pm = pci_find_bar(pcidev, pbm->pbm_reg); | |||||
if (pm == NULL) | |||||
return (EINVAL); | |||||
if (!pci_bar_enabled(pcidev, pm)) | |||||
return (EBUSY); /* XXXKIB enable if _ACTIVATE */ | |||||
if (!PCI_BAR_MEM(pm->pm_value)) | |||||
return (EIO); | |||||
pbase = trunc_page(pm->pm_value); | |||||
plen = round_page(pm->pm_value + ((pci_addr_t)1 << pm->pm_size)) - | |||||
pbase; | |||||
prot = VM_PROT_READ | (((pbm->pbm_flags & PCIIO_BAR_MMAP_RW) != 0) ? | |||||
VM_PROT_WRITE : 0); | |||||
/* Create vm structures and mmap. */ | |||||
sg = sglist_alloc(1, M_WAITOK); | |||||
error = sglist_append_phys(sg, pbase, plen); | |||||
if (error != 0) | |||||
goto out; | |||||
obj = vm_pager_allocate(OBJT_SG, sg, plen, prot, 0, td->td_ucred); | |||||
if (obj == NULL) { | |||||
error = EIO; | |||||
goto out; | |||||
} | |||||
obj->memattr = pbm->pbm_memattr; | |||||
flags = MAP_SHARED; | |||||
addr = 0; | |||||
if ((pbm->pbm_flags & PCIIO_BAR_MMAP_FIXED) != 0) { | |||||
addr = (uintptr_t)pbm->pbm_map_base; | |||||
flags |= MAP_FIXED; | |||||
} | |||||
if ((pbm->pbm_flags & PCIIO_BAR_MMAP_EXCL) != 0) | |||||
flags |= MAP_CHECK_EXCL; | |||||
error = vm_mmap_object(map, &addr, plen, prot, prot, flags, obj, 0, | |||||
FALSE, td); | |||||
if (error != 0) { | |||||
vm_object_deallocate(obj); | |||||
goto out; | |||||
} | |||||
pbm->pbm_map_base = (void *)addr; | |||||
pbm->pbm_map_length = plen; | |||||
pbm->pbm_bar_off = pm->pm_value - pbase; | |||||
pbm->pbm_bar_length = (pci_addr_t)1 << pm->pm_size; | |||||
out: | |||||
sglist_free(sg); | |||||
return (error); | |||||
} | |||||
static int | |||||
pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) | pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) | ||||
{ | { | ||||
device_t pcidev; | device_t pcidev; | ||||
const char *name; | const char *name; | ||||
struct devlist *devlist_head; | struct devlist *devlist_head; | ||||
struct pci_conf_io *cio = NULL; | struct pci_conf_io *cio = NULL; | ||||
struct pci_devinfo *dinfo; | struct pci_devinfo *dinfo; | ||||
struct pci_io *io; | struct pci_io *io; | ||||
struct pci_bar_io *bio; | struct pci_bar_io *bio; | ||||
struct pci_list_vpd_io *lvio; | struct pci_list_vpd_io *lvio; | ||||
struct pci_match_conf *pattern_buf; | struct pci_match_conf *pattern_buf; | ||||
struct pci_map *pm; | struct pci_map *pm; | ||||
struct pci_bar_mmap *pbm; | |||||
size_t confsz, iolen; | size_t confsz, iolen; | ||||
int error, ionum, i, num_patterns; | int error, ionum, i, num_patterns; | ||||
union pci_conf_union pcu; | union pci_conf_union pcu; | ||||
#ifdef PRE7_COMPAT | #ifdef PRE7_COMPAT | ||||
struct pci_io iodata; | struct pci_io iodata; | ||||
struct pci_io_old *io_old; | struct pci_io_old *io_old; | ||||
io_old = NULL; | io_old = NULL; | ||||
#endif | #endif | ||||
if (!(flag & FWRITE)) { | if (!(flag & FWRITE)) { | ||||
switch (cmd) { | switch (cmd) { | ||||
case PCIOCGETCONF: | case PCIOCGETCONF: | ||||
#ifdef PRE7_COMPAT | #ifdef PRE7_COMPAT | ||||
case PCIOCGETCONF_OLD: | case PCIOCGETCONF_OLD: | ||||
#ifdef COMPAT_FREEBSD32 | #ifdef COMPAT_FREEBSD32 | ||||
case PCIOCGETCONF_OLD32: | case PCIOCGETCONF_OLD32: | ||||
#endif | #endif | ||||
#endif | #endif | ||||
case PCIOCGETBAR: | case PCIOCGETBAR: | ||||
case PCIOCLISTVPD: | case PCIOCLISTVPD: | ||||
case PCIOCBARMMAP: | |||||
break; | break; | ||||
default: | default: | ||||
return (EPERM); | return (EPERM); | ||||
} | } | ||||
} | } | ||||
switch (cmd) { | switch (cmd) { | ||||
▲ Show 20 Lines • Show All 307 Lines • ▼ Show 20 Lines | pcidev = pci_find_dbsf(lvio->plvi_sel.pc_domain, | ||||
lvio->plvi_sel.pc_bus, lvio->plvi_sel.pc_dev, | lvio->plvi_sel.pc_bus, lvio->plvi_sel.pc_dev, | ||||
lvio->plvi_sel.pc_func); | lvio->plvi_sel.pc_func); | ||||
if (pcidev == NULL) { | if (pcidev == NULL) { | ||||
error = ENODEV; | error = ENODEV; | ||||
break; | break; | ||||
} | } | ||||
error = pci_list_vpd(pcidev, lvio); | error = pci_list_vpd(pcidev, lvio); | ||||
break; | break; | ||||
case PCIOCBARMMAP: | |||||
pbm = (struct pci_bar_mmap *)data; | |||||
if ((flag & FWRITE) == 0 && | |||||
(pbm->pbm_flags & PCIIO_BAR_MMAP_RW) != 0) | |||||
return (EPERM); | |||||
pcidev = pci_find_dbsf(pbm->pbm_sel.pc_domain, | |||||
pbm->pbm_sel.pc_bus, pbm->pbm_sel.pc_dev, | |||||
pbm->pbm_sel.pc_func); | |||||
error = pcidev == NULL ? ENODEV : pci_bar_mmap(pcidev, pbm); | |||||
break; | |||||
default: | default: | ||||
error = ENOTTY; | error = ENOTTY; | ||||
break; | break; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } |