pciba.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:22k
- /*
- * arch/ia64/sn/io/pciba.c
- *
- * IRIX PCIBA-inspired user mode PCI interface
- *
- * requires: devfs
- *
- * device nodes show up in /dev/pci/BB/SS.F (where BB is the bus the
- * device is on, SS is the slot the device is in, and F is the
- * device's function on a multi-function card).
- *
- * when compiled into the kernel, it will only be initialized by the
- * sgi sn1 specific initialization code. in this case, device nodes
- * are under /dev/hw/..../
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file "COPYING" in the main directory of
- * this archive for more details.
- *
- * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved.
- *
- * 03262001 - Initial version by Chad Talbott
- */
- /* jesse's beefs:
- register_pci_device should be documented
-
- grossness with do_swap should be documented
-
- big, gross union'ized node_data should be replaced with independent
- structures
- replace global list of nodes with global lists of resources. could
- use object oriented approach of allocating and cleaning up
- resources.
-
- */
- #include <linux/config.h>
- #ifndef CONFIG_DEVFS_FS
- # error PCIBA requires devfs
- #endif
- #include <linux/module.h>
- #include <linux/devfs_fs_kernel.h>
- #include <linux/pci.h>
- #include <linux/list.h>
- #include <linux/mm.h>
- #include <linux/slab.h>
- #include <linux/vmalloc.h>
- #include <linux/mman.h>
- #include <linux/init.h>
- #include <linux/raw.h>
- #include <linux/capability.h>
- #include <asm/uaccess.h>
- #include <asm/io.h>
- #include <asm/pgalloc.h>
- #include <asm/page.h>
- #include <asm/sn/pci/pciba.h>
- MODULE_DESCRIPTION("User mode PCI interface");
- MODULE_AUTHOR("Chad Talbott");
- #undef DEBUG_PCIBA
- /* #define DEBUG_PCIBA */
- #undef TRACE_PCIBA
- /* #define TRACE_PCIBA */
- #if defined(DEBUG_PCIBA)
- # define DPRINTF(x...) printk(KERN_DEBUG x)
- #else
- # define DPRINTF(x...)
- #endif
- #if defined(TRACE_PCIBA)
- # if defined(__GNUC__)
- # define TRACE() printk(KERN_DEBUG "%s:%d:%sn",
- __FILE__, __LINE__, __FUNCTION__)
- # else
- # define TRACE() printk(KERN_DEBUG "%s:%dn", __LINE__, __FILE__)
- # endif
- #else
- # define TRACE()
- #endif
- typedef enum { failure, success } status;
- typedef enum { false, true } boolean;
- /* major data structures:
- struct node_data -
-
- one for each file registered with devfs. contains everything
- that any file's fops would need to know about.
- struct dma_allocation -
- a single DMA allocation. only the 'dma' nodes care about
- these. they are there primarily to allow the driver to look
- up the kernel virtual address of dma buffers allocated by
- pci_alloc_consistent, as the application is only given the
- physical address (to program the device's dma, presumably) and
- cannot supply the kernel virtual address when freeing the
- buffer.
- it's also useful to maintain a list of buffers allocated
- through a specific node to allow some sanity checking by this
- driver. this prevents (for example) a broken application from
- freeing buffers that it didn't allocate, or buffers allocated
- on another node.
-
- global_node_list -
- a list of all nodes allocated. this allows the driver to free
- all the memory it has 'kmalloc'd in case of an error, or on
- module removal.
- global_dma_list -
- a list of all dma buffers allocated by this driver. this
- allows the driver to 'pci_free_consistent' all buffers on
- module removal or error.
- */
- struct node_data {
- /* flat list of all the device nodes. makes it easy to free
- them all when we're unregistered */
- struct list_head global_node_list;
- devfs_handle_t devfs_handle;
- void (* cleanup)(struct node_data *);
- union {
- struct {
- struct pci_dev * dev;
- struct list_head dma_allocs;
- boolean mmapped;
- } dma;
- struct {
- struct pci_dev * dev;
- u32 saved_rom_base_reg;
- boolean mmapped;
- } rom;
- struct {
- struct resource * res;
- } base;
- struct {
- struct pci_dev * dev;
- } config;
- } u;
- };
- struct dma_allocation {
- struct list_head list;
- dma_addr_t handle;
- void * va;
- size_t size;
- };
- static LIST_HEAD(global_node_list);
- static LIST_HEAD(global_dma_list);
- /* module entry points */
- int __init pciba_init(void);
- void __exit pciba_exit(void);
- static status __init register_with_devfs(void);
- static void __exit unregister_with_devfs(void);
- static status __init register_pci_device(devfs_handle_t device_dir_handle,
- struct pci_dev * dev);
- /* file operations */
- static int generic_open(struct inode * inode, struct file * file);
- static int rom_mmap(struct file * file, struct vm_area_struct * vma);
- static int rom_release(struct inode * inode, struct file * file);
- static int base_mmap(struct file * file, struct vm_area_struct * vma);
- static int config_ioctl(struct inode * inode, struct file * file,
- unsigned int cmd,
- unsigned long arg);
- static int dma_ioctl(struct inode * inode, struct file * file,
- unsigned int cmd,
- unsigned long arg);
- static int dma_mmap(struct file * file, struct vm_area_struct * vma);
- /* support routines */
- static int mmap_pci_address(struct vm_area_struct * vma, unsigned long pci_va);
- static int mmap_kernel_address(struct vm_area_struct * vma, void * kernel_va);
- #ifdef DEBUG_PCIBA
- static void dump_nodes(struct list_head * nodes);
- static void dump_allocations(struct list_head * dalp);
- #endif
- /* file operations for each type of node */
- static struct file_operations rom_fops = {
- owner: THIS_MODULE,
- mmap: rom_mmap,
- open: generic_open,
- release: rom_release
- };
-
- static struct file_operations base_fops = {
- owner: THIS_MODULE,
- mmap: base_mmap,
- open: generic_open
- };
- static struct file_operations config_fops = {
- owner: THIS_MODULE,
- ioctl: config_ioctl,
- open: generic_open
- };
- static struct file_operations dma_fops = {
- owner: THIS_MODULE,
- ioctl: dma_ioctl,
- mmap: dma_mmap,
- open: generic_open
- };
- module_init(pciba_init);
- module_exit(pciba_exit);
- int __init
- pciba_init(void)
- {
- TRACE();
- if (register_with_devfs() == failure)
- return 1; /* failure */
- printk("PCIBA (a user mode PCI interface) initialized.n");
- return 0; /* success */
- }
- void __exit
- pciba_exit(void)
- {
- TRACE();
- /* FIXME: should also free all that memory that we allocated
- ;) */
- unregister_with_devfs();
- }
- # if 0
- static void __exit
- free_nodes(void)
- {
- struct node_data * nd;
-
- TRACE();
- list_for_each(nd, &node_list) {
- kfree(list_entry(nd, struct nd, node_list));
- }
- }
- #endif
- static devfs_handle_t pciba_devfs_handle;
- #if !defined(CONFIG_IA64_SGI_SN1)
- static status __init
- register_with_devfs(void)
- {
- struct pci_dev * dev;
- devfs_handle_t device_dir_handle;
- char devfs_path[40];
- TRACE();
- pciba_devfs_handle = devfs_mk_dir(NULL, "pci", NULL);
- if (pciba_devfs_handle == NULL)
- return failure;
- /* FIXME: don't forget /dev/pci/mem & /dev/pci/io */
- pci_for_each_dev(dev) {
- sprintf(devfs_path, "%02x/%02x.%x",
- dev->bus->number,
- PCI_SLOT(dev->devfn),
- PCI_FUNC(dev->devfn));
-
- device_dir_handle =
- devfs_mk_dir(pciba_devfs_handle, devfs_path, NULL);
- if (device_dir_handle == NULL)
- return failure;
- if (register_pci_device(device_dir_handle, dev) == failure) {
- devfs_unregister(pciba_devfs_handle);
- return failure;
- }
- }
- return success;
- }
- #else
- extern devfs_handle_t
- devfn_to_vertex(unsigned char busnum, unsigned int devfn);
- static status __init
- register_with_devfs(void)
- {
- struct pci_dev * dev;
- devfs_handle_t device_dir_handle;
- TRACE();
- /* FIXME: don't forget /dev/.../pci/mem & /dev/.../pci/io */
- pci_for_each_dev(dev) {
- device_dir_handle = devfn_to_vertex(dev->bus->number,
- dev->devfn);
- if (device_dir_handle == NULL)
- return failure;
-
- if (register_pci_device(device_dir_handle, dev) == failure) {
- devfs_unregister(pciba_devfs_handle);
- return failure;
- }
- }
- return success;
- }
- #endif /* CONFIG_IA64_SGI_SN1 */
- static void __exit
- unregister_with_devfs(void)
- {
- struct list_head * lhp;
- struct node_data * nd;
-
- TRACE();
- list_for_each(lhp, &global_node_list) {
- nd = list_entry(lhp, struct node_data, global_node_list);
- devfs_unregister(nd->devfs_handle);
- }
- }
- struct node_data * new_node(void)
- {
- struct node_data * node;
-
- TRACE();
-
- node = kmalloc(sizeof(struct node_data), GFP_KERNEL);
- if (node == NULL)
- return NULL;
- list_add(&node->global_node_list, &global_node_list);
- return node;
- }
- void dma_cleanup(struct node_data * dma_node)
- {
- TRACE();
- /* FIXME: should free these allocations */
- #ifdef DEBUG_PCIBA
- dump_allocations(&dma_node->u.dma.dma_allocs);
- #endif
- devfs_unregister(dma_node->devfs_handle);
- }
- void init_dma_node(struct node_data * node,
- struct pci_dev * dev, devfs_handle_t dh)
- {
- TRACE();
- node->devfs_handle = dh;
- node->u.dma.dev = dev;
- node->cleanup = dma_cleanup;
- INIT_LIST_HEAD(&node->u.dma.dma_allocs);
- }
- void rom_cleanup(struct node_data * rom_node)
- {
- TRACE();
- if (rom_node->u.rom.mmapped)
- pci_write_config_dword(rom_node->u.rom.dev,
- PCI_ROM_ADDRESS,
- rom_node->u.rom.saved_rom_base_reg);
- devfs_unregister(rom_node->devfs_handle);
- }
- void init_rom_node(struct node_data * node,
- struct pci_dev * dev, devfs_handle_t dh)
- {
- TRACE();
- node->devfs_handle = dh;
- node->u.rom.dev = dev;
- node->cleanup = rom_cleanup;
- node->u.rom.mmapped = false;
- }
- static status __init
- register_pci_device(devfs_handle_t device_dir_handle, struct pci_dev * dev)
- {
- struct node_data * nd;
- char devfs_path[20];
- devfs_handle_t node_devfs_handle;
- int ri;
- TRACE();
- /* register nodes for all the device's base address registers */
- for (ri = 0; ri < PCI_ROM_RESOURCE; ri++) {
- if (pci_resource_len(dev, ri) != 0) {
- sprintf(devfs_path, "base/%d", ri);
- if (devfs_register(device_dir_handle, devfs_path,
- DEVFS_FL_NONE,
- 0, 0,
- S_IFREG | S_IRUSR | S_IWUSR,
- &base_fops,
- &dev->resource[ri]) == NULL)
- return failure;
- }
- }
-
- /* register a node corresponding to the first MEM resource on
- the device */
- for (ri = 0; ri < PCI_ROM_RESOURCE; ri++) {
- if (dev->resource[ri].flags & IORESOURCE_MEM &&
- pci_resource_len(dev, ri) != 0) {
- if (devfs_register(device_dir_handle, "mem",
- DEVFS_FL_NONE, 0, 0,
- S_IFREG | S_IRUSR | S_IWUSR,
- &base_fops,
- &dev->resource[ri]) == NULL)
- return failure;
- break;
- }
- }
- /* also register a node corresponding to the first IO resource
- on the device */
- for (ri = 0; ri < PCI_ROM_RESOURCE; ri++) {
- if (dev->resource[ri].flags & IORESOURCE_IO &&
- pci_resource_len(dev, ri) != 0) {
- if (devfs_register(device_dir_handle, "io",
- DEVFS_FL_NONE, 0, 0,
- S_IFREG | S_IRUSR | S_IWUSR,
- &base_fops,
- &dev->resource[ri]) == NULL)
- return failure;
- break;
- }
- }
- /* register a node corresponding to the device's ROM resource,
- if present */
- if (pci_resource_len(dev, PCI_ROM_RESOURCE) != 0) {
- nd = new_node();
- if (nd == NULL)
- return failure;
- node_devfs_handle = devfs_register(device_dir_handle, "rom",
- DEVFS_FL_NONE, 0, 0,
- S_IFREG | S_IRUSR,
- &rom_fops, nd);
- if (node_devfs_handle == NULL)
- return failure;
- init_rom_node(nd, dev, node_devfs_handle);
- }
- /* register a node that allows ioctl's to read and write to
- the device's config space */
- if (devfs_register(device_dir_handle, "config", DEVFS_FL_NONE,
- 0, 0, S_IFREG | S_IRUSR | S_IWUSR,
- &config_fops, dev) == NULL)
- return failure;
- /* finally, register a node that allows ioctl's to allocate
- and free DMA buffers, as well as memory map those
- buffers. */
- nd = new_node();
- if (nd == NULL)
- return failure;
- node_devfs_handle =
- devfs_register(device_dir_handle, "dma", DEVFS_FL_NONE,
- 0, 0, S_IFREG | S_IRUSR | S_IWUSR,
- &dma_fops, nd);
- if (node_devfs_handle == NULL)
- return failure;
- init_dma_node(nd, dev, node_devfs_handle);
- #ifdef DEBUG_PCIBA
- dump_nodes(&global_node_list);
- #endif
-
- return success;
- }
- static int
- generic_open(struct inode * inode, struct file * file)
- {
- TRACE();
- /* FIXME: should check that they're not trying to open the ROM
- writable */
- return 0; /* success */
- }
- static int
- rom_mmap(struct file * file, struct vm_area_struct * vma)
- {
- unsigned long pci_pa;
- struct node_data * nd;
- TRACE();
- nd = (struct node_data * )file->private_data;
- pci_pa = pci_resource_start(nd->u.rom.dev, PCI_ROM_RESOURCE);
- if (!nd->u.rom.mmapped) {
- nd->u.rom.mmapped = true;
- DPRINTF("Enabling ROM address decoder.n");
- DPRINTF(
- "rom_mmap: FIXME: some cards do not allow both ROM and memory addresses ton"
- "rom_mmap: FIXME: be enabled simultaneously, as they share a decoder.n");
- pci_read_config_dword(nd->u.rom.dev, PCI_ROM_ADDRESS,
- &nd->u.rom.saved_rom_base_reg);
- DPRINTF("ROM base address contains %xn",
- nd->u.rom.saved_rom_base_reg);
- pci_write_config_dword(nd->u.rom.dev, PCI_ROM_ADDRESS,
- nd->u.rom.saved_rom_base_reg |
- PCI_ROM_ADDRESS_ENABLE);
- }
-
- return mmap_pci_address(vma, pci_pa);
- }
- static int
- rom_release(struct inode * inode, struct file * file)
- {
- struct node_data * nd;
- TRACE();
- nd = (struct node_data * )file->private_data;
- if (nd->u.rom.mmapped) {
- nd->u.rom.mmapped = false;
- DPRINTF("Disabling ROM address decoder.n");
- pci_write_config_dword(nd->u.rom.dev, PCI_ROM_ADDRESS,
- nd->u.rom.saved_rom_base_reg);
- }
- return 0; /* indicate success */
- }
- static int
- base_mmap(struct file * file, struct vm_area_struct * vma)
- {
- struct resource * resource;
- TRACE();
- resource = (struct resource *)file->private_data;
- return mmap_pci_address(vma, resource->start);
- }
- static int
- config_ioctl(struct inode * inode, struct file * file,
- unsigned int cmd,
- unsigned long arg)
- {
- struct pci_dev * dev;
- union cfg_data {
- uint8_t byte;
- uint16_t word;
- uint32_t dword;
- } read_data, write_data;
- int dir, size, offset;
- TRACE();
- DPRINTF("cmd = %x (DIR = %x, TYPE = %x, NR = %x, SIZE = %x)n",
- cmd,
- _IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd));
- DPRINTF("arg = %lxn", arg);
- dev = (struct pci_dev *)file->private_data;
- /* PCIIOCCFG{RD,WR}: read and/or write PCI configuration
- space. If both, the read happens first (this becomes a swap
- operation, atomic with respect to other updates through
- this path). */
- dir = _IOC_DIR(cmd);
- #define do_swap(suffix, type)
- do {
- if (dir & _IOC_READ) {
- pci_read_config_##suffix(dev, _IOC_NR(cmd),
- &read_data.suffix);
- }
- if (dir & _IOC_WRITE) {
- get_user(write_data.suffix, (type)arg);
- pci_write_config_##suffix(dev, _IOC_NR(cmd),
- write_data.suffix);
- }
- if (dir & _IOC_READ) {
- put_user(read_data.suffix, (type)arg);
- }
- } while (0)
- size = _IOC_SIZE(cmd);
- offset = _IOC_NR(cmd);
- DPRINTF("sanity checkn");
- if (((size > 0) || (size <= 4)) &&
- ((offset + size) <= 256) &&
- (dir & (_IOC_READ | _IOC_WRITE))) {
- switch (size)
- {
- case 1:
- do_swap(byte, uint8_t *);
- break;
- case 2:
- do_swap(word, uint16_t *);
- break;
- case 4:
- do_swap(dword, uint32_t *);
- break;
- default:
- DPRINTF("invalid ioctln");
- return -EINVAL;
- }
- } else
- return -EINVAL;
-
- return 0;
- }
- #ifdef DEBUG_PCIBA
- static void
- dump_allocations(struct list_head * dalp)
- {
- struct dma_allocation * dap;
- struct list_head * p;
-
- printk("{n");
- list_for_each(p, dalp) {
- dap = list_entry(p, struct dma_allocation,
- list);
- printk(" handle = %lx, va = %pn",
- dap->handle, dap->va);
- }
- printk("}n");
- }
- static void
- dump_nodes(struct list_head * nodes)
- {
- struct node_data * ndp;
- struct list_head * p;
-
- printk("{n");
- list_for_each(p, nodes) {
- ndp = list_entry(p, struct node_data,
- global_node_list);
- printk(" %pn", (void *)ndp);
- }
- printk("}n");
- }
- #if 0
- #define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL))
- static void
- test_list(void)
- {
- u64 i;
- LIST_HEAD(the_list);
- for (i = 0; i < 5; i++) {
- struct dma_allocation * new_alloc;
- NEW(new_alloc);
- new_alloc->va = (void *)i;
- new_alloc->handle = 5*i;
- printk("%d - the_list->next = %lxn", i, the_list.next);
- list_add(&new_alloc->list, &the_list);
- }
- dump_allocations(&the_list);
- }
- #endif
- #endif
- static LIST_HEAD(dma_buffer_list);
- static int
- dma_ioctl(struct inode * inode, struct file * file,
- unsigned int cmd,
- unsigned long arg)
- {
- struct node_data * nd;
- uint64_t argv;
- int result;
- struct dma_allocation * dma_alloc;
- struct list_head * iterp;
- TRACE();
- DPRINTF("cmd = %xn", cmd);
- DPRINTF("arg = %lxn", arg);
- nd = (struct node_data *)file->private_data;
- #ifdef DEBUG_PCIBA
- DPRINTF("at dma_ioctl entryn");
- dump_allocations(&nd->u.dma.dma_allocs);
- #endif
- switch (cmd) {
- case PCIIOCDMAALLOC:
- /* PCIIOCDMAALLOC: allocate a chunk of physical memory
- and set it up for DMA. Return the PCI address that
- gets to it. */
- DPRINTF("case PCIIOCDMAALLOC (%lx)n", PCIIOCDMAALLOC);
-
- if ( (result = get_user(argv, (uint64_t *)arg)) )
- return result;
- DPRINTF("argv (size of buffer) = %lxn", argv);
- dma_alloc = (struct dma_allocation *)
- kmalloc(sizeof(struct dma_allocation), GFP_KERNEL);
- if (dma_alloc == NULL)
- return -ENOMEM;
- dma_alloc->size = (size_t)argv;
- dma_alloc->va = pci_alloc_consistent(nd->u.dma.dev,
- dma_alloc->size,
- &dma_alloc->handle);
- DPRINTF("dma_alloc->va = %p, dma_alloc->handle = %lxn",
- dma_alloc->va, dma_alloc->handle);
- if (dma_alloc->va == NULL) {
- kfree(dma_alloc);
- return -ENOMEM;
- }
- list_add(&dma_alloc->list, &nd->u.dma.dma_allocs);
- if ( (result = put_user((uint64_t)dma_alloc->handle,
- (uint64_t *)arg)) ) {
- DPRINTF("put_user failedn");
- pci_free_consistent(nd->u.dma.dev, (size_t)argv,
- dma_alloc->va, dma_alloc->handle);
- kfree(dma_alloc);
- return result;
- }
- #ifdef DEBUG_PCIBA
- DPRINTF("after insertionn");
- dump_allocations(&nd->u.dma.dma_allocs);
- #endif
- break;
- case PCIIOCDMAFREE:
- DPRINTF("case PCIIOCDMAFREE (%lx)n", PCIIOCDMAFREE);
- if ( (result = get_user(argv, (uint64_t *)arg)) ) {
- DPRINTF("get_user failedn");
- return result;
- }
- DPRINTF("argv (physical address of DMA buffer) = %lxn", argv);
- list_for_each(iterp, &nd->u.dma.dma_allocs) {
- struct dma_allocation * da =
- list_entry(iterp, struct dma_allocation, list);
- if (da->handle == argv) {
- pci_free_consistent(nd->u.dma.dev, da->size,
- da->va, da->handle);
- list_del(&da->list);
- kfree(da);
- #ifdef DEBUG_PCIBA
- DPRINTF("after deletionn");
- dump_allocations(&nd->u.dma.dma_allocs);
- #endif
- return 0; /* success */
- }
- }
- /* previously allocated dma buffer wasn't found */
- DPRINTF("attempt to free invalid dma handlen");
- return -EINVAL;
- default:
- DPRINTF("undefined ioctln");
- return -EINVAL;
- }
- DPRINTF("successn");
- return 0;
- }
-
- static int
- dma_mmap(struct file * file, struct vm_area_struct * vma)
- {
- struct node_data * nd;
- struct list_head * iterp;
- int result;
-
- TRACE();
- nd = (struct node_data *)file->private_data;
-
- DPRINTF("vma->vm_start is %lxn", vma->vm_start);
- DPRINTF("vma->vm_end is %lxn", vma->vm_end);
- DPRINTF("offset = %lxn", vma->vm_pgoff);
- /* get kernel virtual address for the dma buffer (necessary
- * for the mmap). */
- list_for_each(iterp, &nd->u.dma.dma_allocs) {
- struct dma_allocation * da =
- list_entry(iterp, struct dma_allocation, list);
- /* why does mmap shift its offset argument? */
- if (da->handle == vma->vm_pgoff << PAGE_SHIFT) {
- DPRINTF("found dma handlen");
- if ( (result = mmap_kernel_address(vma,
- da->va)) ) {
- return result; /* failure */
- } else {
- /* it seems like at least one of these
- should show up in user land....
- I'm missing something */
- *(char *)da->va = 0xaa;
- strncpy(da->va, " Toastie!", da->size);
- if (put_user(0x18badbeeful,
- (u64 *)vma->vm_start))
- DPRINTF("put_user failed?!n");
- return 0; /* success */
- }
- }
- }
- DPRINTF("attempt to mmap an invalid dma handlen");
- return -EINVAL;
- }
- static int
- mmap_pci_address(struct vm_area_struct * vma, unsigned long pci_va)
- {
- unsigned long pci_pa;
- TRACE();
- DPRINTF("vma->vm_start is %lxn", vma->vm_start);
- DPRINTF("vma->vm_end is %lxn", vma->vm_end);
- /* the size of the vma doesn't necessarily correspond to the
- size specified in the mmap call. So we can't really do any
- kind of sanity check here. This is a dangerous driver, and
- it's very easy for a user process to kill the machine. */
- DPRINTF("PCI base at virtual address %lxn", pci_va);
- /* the __pa macro is intended for region 7 on IA64, so it
- doesn't work for region 6 */
- /* pci_pa = __pa(pci_va); */
- /* should be replaced by __tpa or equivalent (preferably a
- generic equivalent) */
- pci_pa = pci_va & ~0xe000000000000000ul;
- DPRINTF("PCI base at physical address %lxn", pci_pa);
- /* there are various arch-specific versions of this function
- defined in linux/drivers/char/mem.c, but it would be nice
- if all architectures put it in pgtable.h. it's defined
- there for ia64.... */
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- vma->vm_flags |= VM_NONCACHED | VM_RESERVED | VM_IO;
- return io_remap_page_range(vma->vm_start, pci_pa,
- vma->vm_end-vma->vm_start,
- vma->vm_page_prot);
- }
- static int
- mmap_kernel_address(struct vm_area_struct * vma, void * kernel_va)
- {
- unsigned long kernel_pa;
- TRACE();
- DPRINTF("vma->vm_start is %lxn", vma->vm_start);
- DPRINTF("vma->vm_end is %lxn", vma->vm_end);
- /* the size of the vma doesn't necessarily correspond to the
- size specified in the mmap call. So we can't really do any
- kind of sanity check here. This is a dangerous driver, and
- it's very easy for a user process to kill the machine. */
- DPRINTF("mapping virtual address %pn", kernel_va);
- kernel_pa = __pa(kernel_va);
- DPRINTF("mapping physical address %lxn", kernel_pa);
- vma->vm_flags |= VM_NONCACHED | VM_RESERVED | VM_IO;
- return remap_page_range(vma->vm_start, kernel_pa,
- vma->vm_end-vma->vm_start,
- vma->vm_page_prot);
- }