diff options
author | Suren A. Chilingaryan <csa@suren.me> | 2016-03-02 19:37:30 +0100 |
---|---|---|
committer | Suren A. Chilingaryan <csa@suren.me> | 2016-03-02 19:37:30 +0100 |
commit | 1120e8745ccd3e512fe2016c9e5092fcd378490a (patch) | |
tree | 0e89ac6cd82c213a78d79d10d3fecff06f21127d /driver | |
parent | 01e857cca352e73243d00b62a0c248a35cea6b71 (diff) | |
download | pcitool-1120e8745ccd3e512fe2016c9e5092fcd378490a.tar.gz pcitool-1120e8745ccd3e512fe2016c9e5092fcd378490a.tar.bz2 pcitool-1120e8745ccd3e512fe2016c9e5092fcd378490a.tar.xz pcitool-1120e8745ccd3e512fe2016c9e5092fcd378490a.zip |
Restructure driver headers
Diffstat (limited to 'driver')
-rw-r--r-- | driver/Makefile | 18 | ||||
-rw-r--r-- | driver/base.c | 437 | ||||
-rw-r--r-- | driver/base.h | 93 | ||||
-rw-r--r-- | driver/common.h | 110 | ||||
-rw-r--r-- | driver/compat.h | 43 | ||||
-rw-r--r-- | driver/config.h | 34 | ||||
-rw-r--r-- | driver/debug.h | 25 | ||||
-rw-r--r-- | driver/dev.c | 196 | ||||
-rw-r--r-- | driver/dev.h | 52 | ||||
-rw-r--r-- | driver/int.c | 133 | ||||
-rw-r--r-- | driver/int.h | 3 | ||||
-rw-r--r-- | driver/ioctl.c | 25 | ||||
-rw-r--r-- | driver/ioctl.h | 179 | ||||
-rw-r--r-- | driver/kmem.c | 11 | ||||
-rw-r--r-- | driver/kmem.h | 36 | ||||
-rw-r--r-- | driver/pciDriver.h | 191 | ||||
-rw-r--r-- | driver/pcibus.c (renamed from driver/compat.c) | 0 | ||||
-rw-r--r-- | driver/pcibus.h | 7 | ||||
-rw-r--r-- | driver/pcidriver.h | 11 | ||||
-rw-r--r-- | driver/rdma.c | 6 | ||||
-rw-r--r-- | driver/rdma.h | 1 | ||||
-rw-r--r-- | driver/sysfs.c | 247 | ||||
-rw-r--r-- | driver/sysfs.h | 30 | ||||
-rw-r--r-- | driver/umem.c | 15 | ||||
-rw-r--r-- | driver/umem.h | 21 |
25 files changed, 872 insertions, 1052 deletions
diff --git a/driver/Makefile b/driver/Makefile index 8d8ada8..a55e7c7 100644 --- a/driver/Makefile +++ b/driver/Makefile @@ -1,11 +1,12 @@ CONFIG_MODULE_SIG=n obj-m := pciDriver.o -pciDriver-objs := base.o int.o umem.o kmem.o sysfs.o ioctl.o compat.o rdma.o +pciDriver-objs := base.o dev.o int.o umem.o kmem.o sysfs.o ioctl.o pcibus.o rdma.o KERNELDIR ?= /lib/modules/$(shell uname -r)/build INSTALLDIR ?= /lib/modules/$(shell uname -r)/extra MAININSTALLDIR ?= /lib/modules/$(shell uname -r)/kernel/extra +HEADERDIR ?= /lib/modules/$(shell uname -r)/source/include PWD := $(shell pwd) EXTRA_CFLAGS += -I$(M)/.. @@ -56,9 +57,11 @@ install: @install -m 755 pciDriver.ko $(INSTALLDIR) @echo "INSTALL $(INSTALLDIR)/pciDriver.symvers" @install -m 644 Module.symvers $(INSTALLDIR)/pciDriver.symvers -# @echo "INSTALL /usr/include/pciDriver/driver/pciDriver.h" -# @mkdir -p /usr/include/pciDriver/driver -# @install -m 644 pciDriver.h /usr/include/pciDriver/driver + @echo "INSTALL $(HEADERDIR)/linux/pcidriver.h" + @install -m 644 pcidriver.h $(HEADERDIR)/linux/ + @echo "INSTALL /usr/include/linux/pcidriver.h" + @mkdir -p /usr/include/linux + @install -m 644 ioctl.h /usr/include/linux/pcidriver.h uninstall: @echo "UNINSTALL $(INSTALLDIR)/pciDriver.ko" @@ -66,8 +69,11 @@ uninstall: @rm -f $(MAININSTALLDIR)/pciDriver.ko @rm -f $(INSTALLDIR)/pciDriver.symvers @rm -f $(MAININSTALLDIR)/pciDriver.symvers - @echo "UNINSTALL /usr/include/pciDriver/driver/pciDriver.h" - @rm -rf /usr/include/pciDriver/driver + @echo "UNINSTALL /usr/include/linux/pcidriver.h" + @rm -rf /usr/include/pciDriver/ + @rm -rf /usr/include/linux/pcidriver.h + @echo "UNINSTALL $(HEADERDIR)/linux/pcidriver.h" + @rm -rf $(HEADERDIR)/linux/pcidriver.h clean: rm -rf *.o *.ko *.mod.c .*.o.cmd .*.o.tmp .*.ko.cmd .*.o *.symvers modules.order .tmp_versions diff --git a/driver/base.c b/driver/base.c index 220f1f3..8bfbed6 100644 --- a/driver/base.c +++ b/driver/base.c @@ -1,13 +1,3 @@ -/** - * - * @file base.c - * @author Guillermo Marcus - * @date 2009-04-05 - * @brief Contains the main code which connects all the different parts and does - * basic driver tasks like initialization. - */ - - #include <linux/string.h> #include <linux/slab.h> #include <linux/types.h> @@ -30,139 +20,66 @@ #include <linux/wait.h> #include "../pcilib/version.h" - -#include "config.h" -#include "compat.h" -#include "pciDriver.h" -#include "common.h" -#include "base.h" -#include "int.h" -#include "kmem.h" -#include "umem.h" -#include "ioctl.h" #include "build.h" +#include "base.h" -/*************************************************************************/ -/* Module device table associated with this driver */ -MODULE_DEVICE_TABLE(pci, pcidriver_ids); -/* Module init and exit points */ -module_init(pcidriver_init); -module_exit(pcidriver_exit); /* Module info */ MODULE_AUTHOR("Guillermo Marcus"); MODULE_DESCRIPTION("Simple PCI Driver"); MODULE_LICENSE("GPL v2"); -/* Module class */ -static struct class_compat *pcidriver_class; - -#ifdef PCIDRIVER_DUMMY_DEVICE -pcidriver_privdata_t *pcidriver_dummydata = NULL; -#endif /* PCIDRIVER_DUMMY_DEVICE */ - -/** - * - * Called when loading the driver +/* + * This is the table of PCI devices handled by this driver by default + * If you want to add devices dynamically to this list, do: * + * echo "vendor device" > /sys/bus/pci/drivers/pciDriver/new_id + * where vendor and device are in hex, without leading '0x'. */ -static int __init pcidriver_init(void) -{ - int err = 0; - - /* Initialize the device count */ - atomic_set(&pcidriver_deviceCount, 0); - memset(pcidriver_privdata, 0, sizeof(pcidriver_privdata)); - - /* Allocate character device region dynamically */ - if ((err = alloc_chrdev_region(&pcidriver_devt, MINORNR, MAXDEVICES, NODENAME)) != 0) { - mod_info("Couldn't allocate chrdev region. Module not loaded.\n"); - goto init_alloc_fail; - } - mod_info("Major %d allocated to nodename '%s'\n", MAJOR(pcidriver_devt), NODENAME); +static const __devinitdata struct pci_device_id pcidriver_ids[] = { + { PCI_DEVICE( PCIE_XILINX_VENDOR_ID, PCIE_ML605_DEVICE_ID ) }, // PCI-E Xilinx ML605 + { PCI_DEVICE( PCIE_XILINX_VENDOR_ID, PCIE_IPECAMERA_DEVICE_ID ) }, // PCI-E IPE Camera + { PCI_DEVICE( PCIE_XILINX_VENDOR_ID, PCIE_KAPTURE_DEVICE_ID ) }, // PCI-E KAPTURE board for HEB + {0,0,0,0}, +}; - /* Register driver class */ - pcidriver_class = class_create(THIS_MODULE, NODENAME); +MODULE_DEVICE_TABLE(pci, pcidriver_ids); - if (IS_ERR(pcidriver_class)) { - mod_info("No sysfs support. Module not loaded.\n"); - goto init_class_fail; - } +/* Module class */ +static struct class *pcidriver_class; - /* Register PCI driver. This function returns the number of devices on some - * systems, therefore check for errors as < 0. */ #ifdef PCIDRIVER_DUMMY_DEVICE - if ((err = pcidriver_probe(NULL, NULL)) < 0) { +pcidriver_privdata_t *pcidriver_dummydata = NULL; #else /* PCIDRIVER_DUMMY_DEVICE */ - if ((err = pci_register_driver(&pcidriver_driver)) < 0) { +static struct pci_driver pcidriver_driver; #endif /* PCIDRIVER_DUMMY_DEVICE */ - mod_info("Couldn't register PCI driver. Module not loaded.\n"); - goto init_pcireg_fail; - } - - mod_info("pcidriver %u.%u.%u loaded\n", PCILIB_VERSION_GET_MAJOR(PCILIB_VERSION), PCILIB_VERSION_GET_MINOR(PCILIB_VERSION), PCILIB_VERSION_GET_MICRO(PCILIB_VERSION)); - mod_info("%s\n", PCIDRIVER_BUILD); - mod_info("%s\n", PCIDRIVER_REVISION); - if (strlen(PCIDRIVER_CHANGES)) { - mod_info("Extra changes - %s\n", PCIDRIVER_CHANGES); - } - return 0; +/* Hold the allocated major & minor numbers */ +static dev_t pcidriver_devt; -init_pcireg_fail: - class_destroy(pcidriver_class); -init_class_fail: - unregister_chrdev_region(pcidriver_devt, MAXDEVICES); -init_alloc_fail: - return err; -} +/* Number of devices allocated */ +static atomic_t pcidriver_deviceCount; -/** - * - * Called when unloading the driver - * - */ -static void pcidriver_exit(void) -{ -#ifdef PCIDRIVER_DUMMY_DEVICE - pcidriver_remove(NULL); -#else - pci_unregister_driver(&pcidriver_driver); -#endif /* PCIDRIVER_DUMMY_DEVICE */ +/* Private data for probed devices */ +static pcidriver_privdata_t* pcidriver_privdata[MAXDEVICES]; - unregister_chrdev_region(pcidriver_devt, MAXDEVICES); - if (pcidriver_class != NULL) - class_destroy(pcidriver_class); +pcidriver_privdata_t *pcidriver_get_privdata(int devid) { + if (devid >= MAXDEVICES) + return NULL; - mod_info("Module unloaded\n"); + return pcidriver_privdata[devid]; } -/*************************************************************************/ -/* Driver functions */ +void pcidriver_put_privdata(pcidriver_privdata_t *privdata) { -/** - * - * This struct defines the PCI entry points. - * Will be registered at module init. - * - */ -#ifndef PCIDRIVER_DUMMY_DEVICE -static struct pci_driver pcidriver_driver = { - .name = MODNAME, - .id_table = pcidriver_ids, - .probe = pcidriver_probe, - .remove = pcidriver_remove, -}; -#endif /* ! PCIDRIVER_DUMMY_DEVICE */ +} /** - * * This function is called when installing the driver for a device * @param pdev Pointer to the PCI device - * */ static int __devinit pcidriver_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -250,12 +167,8 @@ static int __devinit pcidriver_probe(struct pci_dev *pdev, const struct pci_devi privdata->devno = devno; /* FIXME: some error checking missing here */ -#ifdef PCIDRIVER_DUMMY_DEVICE - privdata->class_dev = class_device_create(pcidriver_class, NULL, devno, NULL, NODENAMEFMT, MINOR(pcidriver_devt) + devid, privdata); -#else /* PCIDRIVER_DUMMY_DEVICE */ - privdata->class_dev = class_device_create(pcidriver_class, NULL, devno, &(pdev->dev), NODENAMEFMT, MINOR(pcidriver_devt) + devid, privdata); -#endif /* PCIDRIVER_DUMMY_DEVICE */ - class_set_devdata( privdata->class_dev, privdata ); + privdata->class_dev = device_create(pcidriver_class, NULL, devno, privdata, NODENAMEFMT, MINOR(pcidriver_devt) + devid); + dev_set_drvdata(privdata->class_dev, privdata); mod_info("Device /dev/%s%d added\n",NODENAME,MINOR(pcidriver_devt) + devid); #ifndef PCIDRIVER_DUMMY_DEVICE @@ -264,31 +177,14 @@ static int __devinit pcidriver_probe(struct pci_dev *pdev, const struct pci_devi goto probe_irq_probe_fail; #endif /* ! PCIDRIVER_DUMMY_DEVICE */ - /* Populate sysfs attributes for the class device */ /* TODO: correct errorhandling. ewww. must remove the files in reversed order :-( */ -#define sysfs_attr(name) do { \ - if (class_device_create_file(sysfs_attr_def_pointer, &sysfs_attr_def_name(name)) != 0) \ - goto probe_device_create_fail; \ - } while (0) -#ifdef ENABLE_IRQ - sysfs_attr(irq_count); - sysfs_attr(irq_queues); -#endif - - sysfs_attr(mmap_mode); - sysfs_attr(mmap_area); - sysfs_attr(kmem_count); - sysfs_attr(kmem_alloc); - sysfs_attr(kmem_free); - sysfs_attr(kbuffers); - sysfs_attr(umappings); - sysfs_attr(umem_unmap); -#undef sysfs_attr + if (pcidriver_create_sysfs_attributes(privdata) != 0) + goto probe_device_create_fail; /* Register character device */ - cdev_init( &(privdata->cdev), &pcidriver_fops ); + cdev_init(&(privdata->cdev), pcidriver_get_fops()); privdata->cdev.owner = THIS_MODULE; - privdata->cdev.ops = &pcidriver_fops; + privdata->cdev.ops = pcidriver_get_fops(); err = cdev_add( &privdata->cdev, devno, 1 ); if (err) { mod_info( "Couldn't add character device.\n" ); @@ -338,23 +234,7 @@ static void __devexit pcidriver_remove(struct pci_dev *pdev) pcidriver_privdata[privdata->devid] = NULL; /* Removing sysfs attributes from class device */ -#define sysfs_attr(name) do { \ - class_device_remove_file(sysfs_attr_def_pointer, &sysfs_attr_def_name(name)); \ - } while (0) -#ifdef ENABLE_IRQ - sysfs_attr(irq_count); - sysfs_attr(irq_queues); -#endif - - sysfs_attr(mmap_mode); - sysfs_attr(mmap_area); - sysfs_attr(kmem_count); - sysfs_attr(kmem_alloc); - sysfs_attr(kmem_free); - sysfs_attr(kbuffers); - sysfs_attr(umappings); - sysfs_attr(umem_unmap); -#undef sysfs_attr + pcidriver_remove_sysfs_attributes(privdata); /* Free all allocated kmem buffers before leaving */ pcidriver_kmem_free_all( privdata ); @@ -369,7 +249,7 @@ static void __devexit pcidriver_remove(struct pci_dev *pdev) cdev_del(&(privdata->cdev)); /* Removing the device from sysfs */ - class_device_destroy(pcidriver_class, privdata->devno); + device_destroy(pcidriver_class, privdata->devno); /* Releasing privdata */ kfree(privdata); @@ -384,213 +264,82 @@ static void __devexit pcidriver_remove(struct pci_dev *pdev) } -/*************************************************************************/ -/* File operations */ -/*************************************************************************/ - -/** - * This struct defines the file operation entry points. - * - * @see pcidriver_ioctl - * @see pcidriver_mmap - * @see pcidriver_open - * @see pcidriver_release - * - */ -static struct file_operations pcidriver_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = pcidriver_ioctl, - .mmap = pcidriver_mmap, - .open = pcidriver_open, - .release = pcidriver_release, +#ifndef PCIDRIVER_DUMMY_DEVICE +static struct pci_driver pcidriver_driver = { + .name = MODNAME, + .id_table = pcidriver_ids, + .probe = pcidriver_probe, + .remove = pcidriver_remove, }; +#endif /* ! PCIDRIVER_DUMMY_DEVICE */ -void pcidriver_module_get(pcidriver_privdata_t *privdata) { - atomic_inc(&(privdata->refs)); -// mod_info("Ref: %i\n", atomic_read(&(privdata->refs))); -} - -void pcidriver_module_put(pcidriver_privdata_t *privdata) { - if (atomic_add_negative(-1, &(privdata->refs))) { - atomic_inc(&(privdata->refs)); - mod_info("Reference counting error..."); - } else { -// mod_info("Unref: %i\n", atomic_read(&(privdata->refs))); - } -} - -/** - * - * Called when an application open()s a /dev/fpga*, attaches the private data - * with the file pointer. - * - */ -int pcidriver_open(struct inode *inode, struct file *filp) +static int __init pcidriver_init(void) { - pcidriver_privdata_t *privdata; - - /* Set the private data area for the file */ - privdata = container_of( inode->i_cdev, pcidriver_privdata_t, cdev); - filp->private_data = privdata; - - pcidriver_module_get(privdata); - - return 0; -} + int err = 0; -/** - * - * Called when the application close()s the file descriptor. Does nothing at - * the moment. - * - */ -int pcidriver_release(struct inode *inode, struct file *filp) -{ - pcidriver_privdata_t *privdata; + /* Initialize the device count */ + atomic_set(&pcidriver_deviceCount, 0); - /* Get the private data area */ - privdata = filp->private_data; + memset(pcidriver_privdata, 0, sizeof(pcidriver_privdata)); - pcidriver_module_put(privdata); + /* Allocate character device region dynamically */ + if ((err = alloc_chrdev_region(&pcidriver_devt, MINORNR, MAXDEVICES, NODENAME)) != 0) { + mod_info("Couldn't allocate chrdev region. Module not loaded.\n"); + goto init_alloc_fail; + } + mod_info("Major %d allocated to nodename '%s'\n", MAJOR(pcidriver_devt), NODENAME); - return 0; -} + /* Register driver class */ + pcidriver_class = class_create(THIS_MODULE, NODENAME); -/** - * - * This function is the entry point for mmap() and calls either pcidriver_mmap_pci - * or pcidriver_mmap_kmem - * - * @see pcidriver_mmap_pci - * @see pcidriver_mmap_kmem - * - */ -int pcidriver_mmap(struct file *filp, struct vm_area_struct *vma) -{ - pcidriver_privdata_t *privdata; - int ret = 0, bar; - - mod_info_dbg("Entering mmap\n"); - - /* Get the private data area */ - privdata = filp->private_data; - - /* Check the current mmap mode */ - switch (privdata->mmap_mode) { - case PCIDRIVER_MMAP_PCI: - /* Mmap a PCI region */ - switch (privdata->mmap_area) { - case PCIDRIVER_BAR0: - bar = 0; - break; - case PCIDRIVER_BAR1: - bar = 1; - break; - case PCIDRIVER_BAR2: - bar = 2; - break; - case PCIDRIVER_BAR3: - bar = 3; - break; - case PCIDRIVER_BAR4: - bar = 4; - break; - case PCIDRIVER_BAR5: - bar = 5; - break; - default: - mod_info("Attempted to mmap a PCI area with the wrong mmap_area value: %d\n",privdata->mmap_area); - return -EINVAL; /* invalid parameter */ - break; - } - ret = pcidriver_mmap_pci(privdata, vma, bar); - break; - case PCIDRIVER_MMAP_KMEM: - /* mmap a Kernel buffer */ - ret = pcidriver_mmap_kmem(privdata, vma); - break; - default: - mod_info( "Invalid mmap_mode value (%d)\n",privdata->mmap_mode ); - return -EINVAL; /* Invalid parameter (mode) */ + if (IS_ERR(pcidriver_class)) { + mod_info("No sysfs support. Module not loaded.\n"); + goto init_class_fail; } - return ret; -} - -/*************************************************************************/ -/* Internal driver functions */ -int pcidriver_mmap_pci(pcidriver_privdata_t *privdata, struct vm_area_struct *vmap, int bar) -{ + /* Register PCI driver. This function returns the number of devices on some + * systems, therefore check for errors as < 0. */ #ifdef PCIDRIVER_DUMMY_DEVICE - return -ENXIO; + if ((err = pcidriver_probe(NULL, NULL)) < 0) { #else /* PCIDRIVER_DUMMY_DEVICE */ - int ret = 0; - unsigned long bar_addr; - unsigned long bar_length, vma_size; - unsigned long bar_flags; - - mod_info_dbg("Entering mmap_pci\n"); - - - /* Get info of the BAR to be mapped */ - bar_addr = pci_resource_start(privdata->pdev, bar); - bar_length = pci_resource_len(privdata->pdev, bar); - bar_flags = pci_resource_flags(privdata->pdev, bar); - - /* Check sizes */ - vma_size = (vmap->vm_end - vmap->vm_start); - - if ((vma_size != bar_length) && - ((bar_length < PAGE_SIZE) && (vma_size != PAGE_SIZE))) { - mod_info( "mmap size is not correct! bar: %lu - vma: %lu\n", bar_length, vma_size ); - return -EINVAL; + if ((err = pci_register_driver(&pcidriver_driver)) < 0) { +#endif /* PCIDRIVER_DUMMY_DEVICE */ + mod_info("Couldn't register PCI driver. Module not loaded.\n"); + goto init_pcireg_fail; } - if (bar_flags & IORESOURCE_IO) { - /* Unlikely case, we will mmap a IO region */ - - /* IO regions are never cacheable */ - vmap->vm_page_prot = pgprot_noncached(vmap->vm_page_prot); - - /* Map the BAR */ - ret = io_remap_pfn_range_compat(vmap, vmap->vm_start, bar_addr, bar_length, vmap->vm_page_prot); - } else { - /* Normal case, mmap a memory region */ - - /* Ensure this VMA is non-cached, if it is not flaged as prefetchable. - * If it is prefetchable, caching is allowed and will give better performance. - * This should be set properly by the BIOS, but we want to be sure. */ - /* adapted from drivers/char/mem.c, mmap function. */ - - /* Setting noncached disables MTRR registers, and we want to use them. - * So we take this code out. This can lead to caching problems if and only if - * the System BIOS set something wrong. Check LDDv3, page 425. - */ - -// if (!(bar_flags & IORESOURCE_PREFETCH)) -// vmap->vm_page_prot = pgprot_noncached(vmap->vm_page_prot); - - - /* Map the BAR */ - ret = remap_pfn_range_compat(vmap, vmap->vm_start, bar_addr, bar_length, vmap->vm_page_prot); + mod_info("pcidriver %u.%u.%u loaded\n", PCILIB_VERSION_GET_MAJOR(PCILIB_VERSION), PCILIB_VERSION_GET_MINOR(PCILIB_VERSION), PCILIB_VERSION_GET_MICRO(PCILIB_VERSION)); + mod_info("%s\n", PCIDRIVER_BUILD); + mod_info("%s\n", PCIDRIVER_REVISION); + if (strlen(PCIDRIVER_CHANGES)) { + mod_info("Extra changes - %s\n", PCIDRIVER_CHANGES); } - if (ret) { - mod_info("remap_pfn_range failed\n"); - return -EAGAIN; - } + return 0; - return 0; /* success */ -#endif /* PCIDRIVER_DUMMY_DEVICE */ +init_pcireg_fail: + class_destroy(pcidriver_class); +init_class_fail: + unregister_chrdev_region(pcidriver_devt, MAXDEVICES); +init_alloc_fail: + return err; } -pcidriver_privdata_t *pcidriver_get_privdata(int devid) { - if (devid >= MAXDEVICES) - return NULL; +static void pcidriver_exit(void) +{ +#ifdef PCIDRIVER_DUMMY_DEVICE + pcidriver_remove(NULL); +#else + pci_unregister_driver(&pcidriver_driver); +#endif /* PCIDRIVER_DUMMY_DEVICE */ - return pcidriver_privdata[devid]; -} + unregister_chrdev_region(pcidriver_devt, MAXDEVICES); -void pcidriver_put_privdata(pcidriver_privdata_t *privdata) { + if (pcidriver_class != NULL) + class_destroy(pcidriver_class); + mod_info("Module unloaded\n"); } + +module_init(pcidriver_init); +module_exit(pcidriver_exit); diff --git a/driver/base.h b/driver/base.h index 8556480..0203808 100644 --- a/driver/base.h +++ b/driver/base.h @@ -1,90 +1,15 @@ #ifndef _PCIDRIVER_BASE_H #define _PCIDRIVER_BASE_H +#include "config.h" +#include "compat.h" +#include "debug.h" +#include "pcibus.h" #include "sysfs.h" +#include "dev.h" +#include "int.h" -/** - * - * This file contains prototypes and data structures for internal use of the pciDriver. - * - * - */ +pcidriver_privdata_t *pcidriver_get_privdata(int devid); +void pcidriver_put_privdata(pcidriver_privdata_t *privdata); -/* prototypes for file_operations */ -static struct file_operations pcidriver_fops; -int pcidriver_mmap( struct file *filp, struct vm_area_struct *vmap ); -int pcidriver_open(struct inode *inode, struct file *filp ); -int pcidriver_release(struct inode *inode, struct file *filp); - -/* prototypes for device operations */ -#ifndef PCIDRIVER_DUMMY_DEVICE -static struct pci_driver pcidriver_driver; -#endif /* ! PCIDRIVER_DUMMY_DEVICE */ -static int __devinit pcidriver_probe(struct pci_dev *pdev, const struct pci_device_id *id); -static void __devexit pcidriver_remove(struct pci_dev *pdev); - - - -/* prototypes for module operations */ -static int __init pcidriver_init(void); -static void pcidriver_exit(void); - -/* - * This is the table of PCI devices handled by this driver by default - * If you want to add devices dynamically to this list, do: - * - * echo "vendor device" > /sys/bus/pci/drivers/pciDriver/new_id - * where vendor and device are in hex, without leading '0x'. - * - * The IDs themselves can be found in common.h - * - * For more info, see <kernel-source>/Documentation/pci.txt - * - * __devinitdata is applied because the kernel does not need those - * tables any more after boot is finished on systems which don't - * support hotplug. - * - */ - -static const __devinitdata struct pci_device_id pcidriver_ids[] = { - { PCI_DEVICE( PCIE_XILINX_VENDOR_ID, PCIE_ML605_DEVICE_ID ) }, // PCI-E Xilinx ML605 - { PCI_DEVICE( PCIE_XILINX_VENDOR_ID, PCIE_IPECAMERA_DEVICE_ID ) }, // PCI-E IPE Camera - { PCI_DEVICE( PCIE_XILINX_VENDOR_ID, PCIE_KAPTURE_DEVICE_ID ) }, // PCI-E KAPTURE board for HEB - {0,0,0,0}, -}; - -/* prototypes for internal driver functions */ -int pcidriver_pci_read( pcidriver_privdata_t *privdata, pci_cfg_cmd *pci_cmd ); -int pcidriver_pci_write( pcidriver_privdata_t *privdata, pci_cfg_cmd *pci_cmd ); -int pcidriver_pci_info( pcidriver_privdata_t *privdata, pcilib_board_info_t *pci_info ); - -int pcidriver_mmap_pci( pcidriver_privdata_t *privdata, struct vm_area_struct *vmap , int bar ); -int pcidriver_mmap_kmem( pcidriver_privdata_t *privdata, struct vm_area_struct *vmap ); - -/*************************************************************************/ -/* Static data */ -/* Hold the allocated major & minor numbers */ -static dev_t pcidriver_devt; - -/* Number of devices allocated */ -static atomic_t pcidriver_deviceCount; - -/* Private data for probed devices */ -static pcidriver_privdata_t* pcidriver_privdata[MAXDEVICES]; - -/* Sysfs attributes */ -static DEVICE_ATTR(mmap_mode, 0664, pcidriver_show_mmap_mode, pcidriver_store_mmap_mode); -static DEVICE_ATTR(mmap_area, 0664, pcidriver_show_mmap_area, pcidriver_store_mmap_area); -static DEVICE_ATTR(kmem_count, S_IRUGO, pcidriver_show_kmem_count, NULL); -static DEVICE_ATTR(kbuffers, S_IRUGO, pcidriver_show_kbuffers, NULL); -static DEVICE_ATTR(kmem_alloc, 0220, NULL, pcidriver_store_kmem_alloc); -static DEVICE_ATTR(kmem_free, 0220, NULL, pcidriver_store_kmem_free); -static DEVICE_ATTR(umappings, S_IRUGO, pcidriver_show_umappings, NULL); -static DEVICE_ATTR(umem_unmap, 0220, NULL, pcidriver_store_umem_unmap); - -#ifdef ENABLE_IRQ -static DEVICE_ATTR(irq_count, S_IRUGO, pcidriver_show_irq_count, NULL); -static DEVICE_ATTR(irq_queues, S_IRUGO, pcidriver_show_irq_queues, NULL); -#endif - -#endif +#endif /* _PCIDRIVER_BASE_H */ diff --git a/driver/common.h b/driver/common.h deleted file mode 100644 index 48b2769..0000000 --- a/driver/common.h +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef _PCIDRIVER_COMMON_H -#define _PCIDRIVER_COMMON_H - -#include "../pcilib/kmem.h" -/*************************************************************************/ -/* Private data types and structures */ - - -/* Define an entry in the kmem list (this list is per device) */ -/* This list keeps references to the allocated kernel buffers */ -typedef struct { - int id; - enum dma_data_direction direction; - - struct list_head list; - dma_addr_t dma_handle; - unsigned long cpua; - unsigned long size; - unsigned long type; - unsigned long align; - - unsigned long use; - unsigned long item; - - spinlock_t lock; - unsigned long mode; - unsigned long refs; - - struct class_device_attribute sysfs_attr; /* initialized when adding the entry */ -} pcidriver_kmem_entry_t; - -/* Define an entry in the umem list (this list is per device) */ -/* This list keeps references to the SG lists for each mapped userspace region */ -typedef struct { - int id; - struct list_head list; - unsigned int nr_pages; /* number of pages for this user memeory area */ - struct page **pages; /* list of pointers to the pages */ - unsigned int nents; /* actual entries in the scatter/gatter list (NOT nents for the map function, but the result) */ - struct scatterlist *sg; /* list of sg entries */ - struct class_device_attribute sysfs_attr; /* initialized when adding the entry */ -} pcidriver_umem_entry_t; - -/* Hold the driver private data */ -typedef struct { - int devid; /* the device id */ - dev_t devno; /* device number (major and minor) */ - struct pci_dev *pdev; /* PCI device */ - struct class_device *class_dev; /* Class device */ - struct cdev cdev; /* char device struct */ - int mmap_mode; /* current mmap mode */ - int mmap_area; /* current PCI mmap area */ - -#ifdef ENABLE_IRQ - int irq_enabled; /* Non-zero if IRQ is enabled */ - int irq_count; /* Just an IRQ counter */ - - wait_queue_head_t irq_queues[ PCIDRIVER_INT_MAXSOURCES ]; /* One queue per interrupt source */ - atomic_t irq_outstanding[ PCIDRIVER_INT_MAXSOURCES ]; /* Outstanding interrupts per queue */ - volatile unsigned int *bars_kmapped[6]; /* PCI BARs mmapped in kernel space */ -#endif - - spinlock_t kmemlist_lock; /* Spinlock to lock kmem list operations */ - struct list_head kmem_list; /* List of 'kmem_list_entry's associated with this device */ - pcidriver_kmem_entry_t *kmem_last_sync; /* Last accessed kmem entry */ - atomic_t kmem_count; /* id for next kmem entry */ - - int kmem_cur_id; /* Currently selected kmem buffer, for mmap */ - - spinlock_t umemlist_lock; /* Spinlock to lock umem list operations */ - struct list_head umem_list; /* List of 'umem_list_entry's associated with this device */ - atomic_t umem_count; /* id for next umem entry */ - - int msi_mode; /* Flag specifying if interrupt have been initialized in MSI mode */ - atomic_t refs; /* Reference counter */ -} pcidriver_privdata_t; - - -void pcidriver_module_get(pcidriver_privdata_t *privdata); -void pcidriver_module_put(pcidriver_privdata_t *privdata); - -pcidriver_privdata_t *pcidriver_get_privdata(int devid); -void pcidriver_put_privdata(pcidriver_privdata_t *privdata); - - -/*************************************************************************/ -/* Some nice defines that make code more readable */ -/* This is to print nice info in the log */ - -#ifdef DEBUG -#define mod_info( args... ) \ - do { printk( KERN_INFO "%s - %s : ", MODNAME , __FUNCTION__ );\ - printk( args ); } while(0) -#define mod_info_dbg( args... ) \ - do { printk( KERN_INFO "%s - %s : ", MODNAME , __FUNCTION__ );\ - printk( args ); } while(0) -#else -#define mod_info( args... ) \ - do { printk( KERN_INFO "%s: ", MODNAME );\ - printk( args ); } while(0) -#define mod_info_dbg( args... ) -#endif - -#define mod_crit( args... ) \ - do { printk( KERN_CRIT "%s: ", MODNAME );\ - printk( args ); } while(0) - -#define MIN(a, b) ((a) < (b) ? (a) : (b)) - -#endif diff --git a/driver/compat.h b/driver/compat.h index a8a2cf0..24cc5a9 100644 --- a/driver/compat.h +++ b/driver/compat.h @@ -37,47 +37,4 @@ # define __devinitdata #endif -#define compat_lock_page __set_page_locked -#define compat_unlock_page __clear_page_locked - - -#define class_device_attribute device_attribute -#define CLASS_DEVICE_ATTR DEVICE_ATTR -#define class_device device -#define class_data dev -#define class_device_create(type, parent, devno, devpointer, nameformat, minor, privdata) \ - device_create(type, parent, devno, privdata, nameformat, minor) -#define class_device_create_file device_create_file -#define class_device_remove_file device_remove_file -#define class_device_destroy device_destroy -#define DEVICE_ATTR_COMPAT struct device_attribute *attr, -#define class_set_devdata dev_set_drvdata - -#define sysfs_attr_def_name(name) dev_attr_##name -#define sysfs_attr_def_pointer privdata->class_dev -#define SYSFS_GET_FUNCTION(name) ssize_t name(struct device *dev, struct device_attribute *attr, char *buf) -#define SYSFS_SET_FUNCTION(name) ssize_t name(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -#define SYSFS_GET_PRIVDATA dev_get_drvdata(dev) - -#define class_compat class - - -#define IRQ_HANDLER_FUNC(name) irqreturn_t name(int irq, void *dev_id) - -#define request_irq(irq, irq_handler, modname, privdata) request_irq(irq, irq_handler, IRQF_SHARED, modname, privdata) - - -#define io_remap_pfn_range_compat(vmap, vm_start, bar_addr, bar_length, vm_page_prot) \ - io_remap_pfn_range(vmap, vm_start, (bar_addr >> PAGE_SHIFT), bar_length, vm_page_prot) - -#define remap_pfn_range_compat(vmap, vm_start, bar_addr, bar_length, vm_page_prot) \ - remap_pfn_range(vmap, vm_start, (bar_addr >> PAGE_SHIFT), bar_length, vm_page_prot) - -#define remap_pfn_range_cpua_compat(vmap, vm_start, cpua, size, vm_page_prot) \ - remap_pfn_range(vmap, vm_start, page_to_pfn(virt_to_page((void*)cpua)), size, vm_page_prot) - - -int pcidriver_pcie_get_mps(struct pci_dev *dev); -int pcidriver_pcie_set_mps(struct pci_dev *dev, int mps); - #endif diff --git a/driver/config.h b/driver/config.h index c217afd..abf8011 100644 --- a/driver/config.h +++ b/driver/config.h @@ -1,6 +1,5 @@ -/*******************************/ -/* Configuration of the driver */ -/*******************************/ +#ifndef _PCIDRIVER_CONFIG_H +#define _PCIDRIVER_CONFIG_H /* Debug messages */ //#define DEBUG @@ -8,16 +7,29 @@ /* Enable/disable IRQ handling */ #define ENABLE_IRQ -/* The name of the module */ -#define MODNAME "pciDriver" +/* Maximum number of interrupt sources */ +#define PCIDRIVER_INT_MAXSOURCES 16 + +/* Maximum number of devices*/ +#define MAXDEVICES 4 -/* Major number is allocated dynamically */ /* Minor number */ -#define MINORNR 0 +#define MINORNR 0 + +/* The name of the module */ +#define MODNAME "pciDriver" /* Node name of the char device */ -#define NODENAME "fpga" -#define NODENAMEFMT "fpga%d" +#define NODENAME "fpga" +#define NODENAMEFMT "fpga%d" -/* Maximum number of devices*/ -#define MAXDEVICES 4 +/* Identifies the PCI-E Xilinx ML605 */ +#define PCIE_XILINX_VENDOR_ID 0x10ee +#define PCIE_ML605_DEVICE_ID 0x6024 + +/* Identifies the PCI-E IPE Hardware */ +#define PCIE_IPECAMERA_DEVICE_ID 0x6081 +#define PCIE_KAPTURE_DEVICE_ID 0x6028 + + +#endif /* _PCIDRIVER_CONFIG_H */ diff --git a/driver/debug.h b/driver/debug.h new file mode 100644 index 0000000..b30e81d --- /dev/null +++ b/driver/debug.h @@ -0,0 +1,25 @@ +#ifndef _PCIDRIVER_DEBUG_H +#define _PCIDRIVER_DEBUG_H + +#include "config.h" + +#ifdef DEBUG +#define mod_info( args... ) \ + do { printk( KERN_INFO "%s - %s : ", MODNAME , __FUNCTION__ );\ + printk( args ); } while(0) +#define mod_info_dbg( args... ) \ + do { printk( KERN_INFO "%s - %s : ", MODNAME , __FUNCTION__ );\ + printk( args ); } while(0) +#else +#define mod_info( args... ) \ + do { printk( KERN_INFO "%s: ", MODNAME );\ + printk( args ); } while(0) +#define mod_info_dbg( args... ) +#endif + +#define mod_crit( args... ) \ + do { printk( KERN_CRIT "%s: ", MODNAME );\ + printk( args ); } while(0) + + +#endif /* _PCIDRIVER_DEBUG_H */ diff --git a/driver/dev.c b/driver/dev.c new file mode 100644 index 0000000..2a047a4 --- /dev/null +++ b/driver/dev.c @@ -0,0 +1,196 @@ +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/cdev.h> +#include <linux/sysfs.h> +#include <asm/atomic.h> +#include <linux/pagemap.h> +#include <linux/spinlock.h> +#include <linux/list.h> +#include <asm/scatterlist.h> +#include <linux/vmalloc.h> +#include <linux/stat.h> +#include <linux/interrupt.h> +#include <linux/wait.h> + +#include "base.h" + + +/** + * + * Called when an application open()s a /dev/fpga*, attaches the private data + * with the file pointer. + * + */ +static int pcidriver_open(struct inode *inode, struct file *filp) +{ + pcidriver_privdata_t *privdata; + + /* Set the private data area for the file */ + privdata = container_of( inode->i_cdev, pcidriver_privdata_t, cdev); + filp->private_data = privdata; + + pcidriver_module_get(privdata); + + return 0; +} + +/** + * + * Called when the application close()s the file descriptor. Does nothing at + * the moment. + * + */ +static int pcidriver_release(struct inode *inode, struct file *filp) +{ + pcidriver_privdata_t *privdata; + + /* Get the private data area */ + privdata = filp->private_data; + + pcidriver_module_put(privdata); + + return 0; +} + + +/*************************************************************************/ +/* Internal driver functions */ +static int pcidriver_mmap_bar(pcidriver_privdata_t *privdata, struct vm_area_struct *vmap, int bar) +{ +#ifdef PCIDRIVER_DUMMY_DEVICE + return -ENXIO; +#else /* PCIDRIVER_DUMMY_DEVICE */ + int ret = 0; + unsigned long bar_addr; + unsigned long bar_length, vma_size; + unsigned long bar_flags; + + mod_info_dbg("Entering mmap_pci\n"); + + + /* Get info of the BAR to be mapped */ + bar_addr = pci_resource_start(privdata->pdev, bar); + bar_length = pci_resource_len(privdata->pdev, bar); + bar_flags = pci_resource_flags(privdata->pdev, bar); + + /* Check sizes */ + vma_size = (vmap->vm_end - vmap->vm_start); + + if ((vma_size != bar_length) && + ((bar_length < PAGE_SIZE) && (vma_size != PAGE_SIZE))) { + mod_info( "mmap size is not correct! bar: %lu - vma: %lu\n", bar_length, vma_size ); + return -EINVAL; + } + + if (bar_flags & IORESOURCE_IO) { + /* Unlikely case, we will mmap a IO region */ + + /* IO regions are never cacheable */ + vmap->vm_page_prot = pgprot_noncached(vmap->vm_page_prot); + + /* Map the BAR */ + ret = io_remap_pfn_range(vmap, vmap->vm_start, (bar_addr >> PAGE_SHIFT), bar_length, vmap->vm_page_prot); + } else { + /* Normal case, mmap a memory region */ + + /* Ensure this VMA is non-cached, if it is not flaged as prefetchable. + * If it is prefetchable, caching is allowed and will give better performance. + * This should be set properly by the BIOS, but we want to be sure. */ + /* adapted from drivers/char/mem.c, mmap function. */ + + /* Setting noncached disables MTRR registers, and we want to use them. + * So we take this code out. This can lead to caching problems if and only if + * the System BIOS set something wrong. Check LDDv3, page 425. + */ + +// if (!(bar_flags & IORESOURCE_PREFETCH)) +// vmap->vm_page_prot = pgprot_noncached(vmap->vm_page_prot); + + + /* Map the BAR */ + ret = remap_pfn_range(vmap, vmap->vm_start, (bar_addr >> PAGE_SHIFT), bar_length, vmap->vm_page_prot); + } + + if (ret) { + mod_info("remap_pfn_range failed\n"); + return -EAGAIN; + } + + return 0; /* success */ +#endif /* PCIDRIVER_DUMMY_DEVICE */ +} + +/** + * + * This function is the entry point for mmap() and calls either pcidriver_mmap_bar + * or pcidriver_mmap_kmem + * + * @see pcidriver_mmap_bar + * @see pcidriver_mmap_kmem + * + */ +static int pcidriver_mmap(struct file *filp, struct vm_area_struct *vma) +{ + pcidriver_privdata_t *privdata; + int ret = 0, bar; + + mod_info_dbg("Entering mmap\n"); + + /* Get the private data area */ + privdata = filp->private_data; + + /* Check the current mmap mode */ + switch (privdata->mmap_mode) { + case PCIDRIVER_MMAP_PCI: + bar = privdata->mmap_area; + if ((bar < 0)||(bar > 5)) { + mod_info("Attempted to mmap a PCI area with the wrong mmap_area value: %d\n",privdata->mmap_area); + return -EINVAL; + } + ret = pcidriver_mmap_bar(privdata, vma, bar); + break; + case PCIDRIVER_MMAP_KMEM: + ret = pcidriver_mmap_kmem(privdata, vma); + break; + default: + mod_info( "Invalid mmap_mode value (%d)\n",privdata->mmap_mode ); + return -EINVAL; /* Invalid parameter (mode) */ + } + + return ret; +} + +static struct file_operations pcidriver_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = pcidriver_ioctl, + .mmap = pcidriver_mmap, + .open = pcidriver_open, + .release = pcidriver_release, +}; + +const struct file_operations *pcidriver_get_fops(void) +{ + return &pcidriver_fops; +} + + +void pcidriver_module_get(pcidriver_privdata_t *privdata) { + atomic_inc(&(privdata->refs)); +// mod_info("Ref: %i\n", atomic_read(&(privdata->refs))); +} + +void pcidriver_module_put(pcidriver_privdata_t *privdata) { + if (atomic_add_negative(-1, &(privdata->refs))) { + atomic_inc(&(privdata->refs)); + mod_info("Reference counting error..."); + } else { +// mod_info("Unref: %i\n", atomic_read(&(privdata->refs))); + } +} diff --git a/driver/dev.h b/driver/dev.h new file mode 100644 index 0000000..5e95365 --- /dev/null +++ b/driver/dev.h @@ -0,0 +1,52 @@ +#ifndef _PCIDRIVER_DEV_H +#define _PCIDRIVER_DEV_H + +typedef struct pcidriver_privdata_s pcidriver_privdata_t; + +#include "kmem.h" +#include "umem.h" + + +/* Hold the driver private data */ +struct pcidriver_privdata_s { + int devid; /* the device id */ + dev_t devno; /* device number (major and minor) */ + struct pci_dev *pdev; /* PCI device */ + struct device *class_dev; /* Class device */ + struct cdev cdev; /* char device struct */ + int mmap_mode; /* current mmap mode */ + int mmap_area; /* current PCI mmap area */ + +#ifdef ENABLE_IRQ + int irq_enabled; /* Non-zero if IRQ is enabled */ + int irq_count; /* Just an IRQ counter */ + + wait_queue_head_t irq_queues[ PCIDRIVER_INT_MAXSOURCES ]; /* One queue per interrupt source */ + atomic_t irq_outstanding[ PCIDRIVER_INT_MAXSOURCES ]; /* Outstanding interrupts per queue */ + volatile unsigned int *bars_kmapped[6]; /* PCI BARs mmapped in kernel space */ +#endif + + spinlock_t kmemlist_lock; /* Spinlock to lock kmem list operations */ + struct list_head kmem_list; /* List of 'kmem_list_entry's associated with this device */ + pcidriver_kmem_entry_t *kmem_last_sync; /* Last accessed kmem entry */ + atomic_t kmem_count; /* id for next kmem entry */ + + int kmem_cur_id; /* Currently selected kmem buffer, for mmap */ + + spinlock_t umemlist_lock; /* Spinlock to lock umem list operations */ + struct list_head umem_list; /* List of 'umem_list_entry's associated with this device */ + atomic_t umem_count; /* id for next umem entry */ + + int msi_mode; /* Flag specifying if interrupt have been initialized in MSI mode */ + atomic_t refs; /* Reference counter */ +}; + +const struct file_operations *pcidriver_get_fops(void); + +void pcidriver_module_get(pcidriver_privdata_t *privdata); +void pcidriver_module_put(pcidriver_privdata_t *privdata); + +long pcidriver_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); + +#endif /* _PCIDRIVER_DEV_H */ + diff --git a/driver/int.c b/driver/int.c index f78c6ec..4bbfb26 100644 --- a/driver/int.c +++ b/driver/int.c @@ -7,36 +7,6 @@ * */ -/* - * Change History: - * - * $Log: not supported by cvs2svn $ - * Revision 1.7 2008-01-11 10:18:28 marcus - * Modified interrupt mechanism. Added atomic functions and queues, to address race conditions. Removed unused interrupt code. - * - * Revision 1.6 2007-11-04 20:58:22 marcus - * Added interrupt generator acknowledge. - * Fixed wrong operator. - * - * Revision 1.5 2007-10-31 15:42:21 marcus - * Added IG ack for testing, may be removed later. - * - * Revision 1.4 2007-07-17 13:15:56 marcus - * Removed Tasklets. - * Using newest map for the ABB interrupts. - * - * Revision 1.3 2007-07-05 15:30:30 marcus - * Added support for both register maps of the ABB. - * - * Revision 1.2 2007-05-29 07:50:18 marcus - * Split code into 2 files. May get merged in the future again.... - * - * Revision 1.1 2007/03/01 16:57:43 marcus - * Divided driver file to ease the interrupt hooks for the user of the driver. - * Modified Makefile accordingly. - * - */ - #include <linux/version.h> #include <linux/string.h> #include <linux/types.h> @@ -48,41 +18,47 @@ #include <linux/sched.h> #include <stdbool.h> -#include "config.h" +#include "base.h" -#include "compat.h" - -#include "pciDriver.h" +/** + * + * Acknowledges the receival of an interrupt to the card. + * + * @returns true if the card was acknowledget + * @returns false if the interrupt was not for one of our cards + * + * @see check_acknowlegde_channel + * + */ +static bool pcidriver_irq_acknowledge(pcidriver_privdata_t *privdata) +{ + int channel = 0; -#include "common.h" + atomic_inc(&(privdata->irq_outstanding[channel])); + wake_up_interruptible(&(privdata->irq_queues[channel])); -#include "int.h" + return true; +} -/* - * The ID between IRQ_SOURCE in irq_outstanding and the actual source is arbitrary. - * Therefore, be careful when communicating with multiple implementations. +/** + * + * Handles IRQs. At the moment, this acknowledges the card that this IRQ + * was received and then increases the driver's IRQ counter. + * + * @see pcidriver_irq_acknowledge + * */ +static irqreturn_t pcidriver_irq_handler(int irq, void *dev_id) +{ + pcidriver_privdata_t *privdata = (pcidriver_privdata_t *)dev_id; -/* IRQ_SOURCES */ -#define ABB_IRQ_CH0 0 -#define ABB_IRQ_CH1 1 -#define ABB_IRQ_IG 2 - -/* See ABB user’s guide, register definitions (3.1) */ -#define ABB_INT_ENABLE (0x0010 >> 2) -#define ABB_INT_STAT (0x0008 >> 2) + if (!pcidriver_irq_acknowledge(privdata)) + return IRQ_NONE; -#define ABB_INT_CH1_TIMEOUT (1 << 4) -#define ABB_INT_CH0_TIMEOUT (1 << 5) -#define ABB_INT_IG (1 << 2) -#define ABB_INT_CH0 (1 << 1) /* downstream */ -#define ABB_INT_CH1 (1) /* upstream */ + privdata->irq_count++; + return IRQ_HANDLED; +} -#define ABB_CH0_CTRL (108 >> 2) -#define ABB_CH1_CTRL (72 >> 2) -#define ABB_CH_RESET (0x0201000A) -#define ABB_IG_CTRL (0x0080 >> 2) -#define ABB_IG_ACK (0x00F0) /** * @@ -167,7 +143,7 @@ int pcidriver_probe_irq(pcidriver_privdata_t *privdata) privdata->msi_mode = 1; /* register interrupt handler */ - if ((err = request_irq(privdata->pdev->irq, pcidriver_irq_handler, MODNAME, privdata)) != 0) { + if ((err = request_irq(privdata->pdev->irq, pcidriver_irq_handler, IRQF_SHARED, MODNAME, privdata)) != 0) { mod_info("Error registering the interrupt handler. Disabling interrupts for this device\n"); return 0; } @@ -215,44 +191,3 @@ void pcidriver_irq_unmap_bars(pcidriver_privdata_t *privdata) } } -/** - * - * Acknowledges the receival of an interrupt to the card. - * - * @returns true if the card was acknowledget - * @returns false if the interrupt was not for one of our cards - * - * @see check_acknowlegde_channel - * - */ -static bool pcidriver_irq_acknowledge(pcidriver_privdata_t *privdata) -{ - int channel = 0; -// volatile unsigned int *bar; -// bar = privdata->bars_kmapped[0]; -// mod_info_dbg("interrupt registers. ISR: %x, IER: %x\n", bar[ABB_INT_STAT], bar[ABB_INT_ENABLE]); - - atomic_inc(&(privdata->irq_outstanding[channel])); - wake_up_interruptible(&(privdata->irq_queues[channel])); - - return true; -} - -/** - * - * Handles IRQs. At the moment, this acknowledges the card that this IRQ - * was received and then increases the driver's IRQ counter. - * - * @see pcidriver_irq_acknowledge - * - */ -IRQ_HANDLER_FUNC(pcidriver_irq_handler) -{ - pcidriver_privdata_t *privdata = (pcidriver_privdata_t *)dev_id; - - if (!pcidriver_irq_acknowledge(privdata)) - return IRQ_NONE; - - privdata->irq_count++; - return IRQ_HANDLED; -} diff --git a/driver/int.h b/driver/int.h index 4a834c7..42fa474 100644 --- a/driver/int.h +++ b/driver/int.h @@ -4,6 +4,5 @@ int pcidriver_probe_irq(pcidriver_privdata_t *privdata); void pcidriver_remove_irq(pcidriver_privdata_t *privdata); void pcidriver_irq_unmap_bars(pcidriver_privdata_t *privdata); -IRQ_HANDLER_FUNC(pcidriver_irq_handler); -#endif +#endif /* _PCIDRIVER_INT_H */ diff --git a/driver/ioctl.c b/driver/ioctl.c index 4fef5f9..f852f2c 100644 --- a/driver/ioctl.c +++ b/driver/ioctl.c @@ -32,13 +32,7 @@ #include "../pcilib/version.h" -#include "config.h" /* Configuration for the driver */ -#include "compat.h" /* Compatibility functions/definitions */ -#include "pciDriver.h" /* External interface for the driver */ -#include "common.h" /* Internal definitions for all parts */ -#include "kmem.h" /* Internal definitions for kernel memory */ -#include "umem.h" /* Internal definitions for user space memory */ -#include "ioctl.h" /* Internal definitions for the ioctl part */ +#include "base.h" /** Declares a variable of the given type with the given name and copies it from userspace */ #define READ_FROM_USER(type, name) \ @@ -87,12 +81,7 @@ static int ioctl_mmap_area(pcidriver_privdata_t *privdata, unsigned long arg) } /** - * * Reads/writes a byte/word/dword of the device's PCI config. - * - * @see pcidriver_pci_read - * @see pcidriver_pci_write - * */ static int ioctl_pci_config_read_write(pcidriver_privdata_t *privdata, unsigned int cmd, unsigned long arg) { @@ -103,7 +92,7 @@ static int ioctl_pci_config_read_write(pcidriver_privdata_t *privdata, unsigned READ_FROM_USER(pci_cfg_cmd, pci_cmd); if (cmd == PCIDRIVER_IOC_PCI_CFG_RD) { - switch (pci_cmd.size) { + switch (pci_cmd.size) { case PCIDRIVER_PCI_CFG_SZ_BYTE: ret = pci_read_config_byte( privdata->pdev, pci_cmd.addr, &(pci_cmd.val.byte) ); break; @@ -115,9 +104,9 @@ static int ioctl_pci_config_read_write(pcidriver_privdata_t *privdata, unsigned break; default: return -EINVAL; /* Wrong size setting */ - } + } } else { - switch (pci_cmd.size) { + switch (pci_cmd.size) { case PCIDRIVER_PCI_CFG_SZ_BYTE: ret = pci_write_config_byte( privdata->pdev, pci_cmd.addr, pci_cmd.val.byte ); break; @@ -130,7 +119,7 @@ static int ioctl_pci_config_read_write(pcidriver_privdata_t *privdata, unsigned default: return -EINVAL; /* Wrong size setting */ break; - } + } } WRITE_TO_USER(pci_cfg_cmd, pci_cmd); @@ -140,11 +129,7 @@ static int ioctl_pci_config_read_write(pcidriver_privdata_t *privdata, unsigned } /** - * * Gets the PCI information for the device. - * - * @see pcidriver_pci_info - * */ static int ioctl_pci_info(pcidriver_privdata_t *privdata, unsigned long arg) { diff --git a/driver/ioctl.h b/driver/ioctl.h index e989f95..a102092 100644 --- a/driver/ioctl.h +++ b/driver/ioctl.h @@ -1 +1,178 @@ -long pcidriver_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +#ifndef _PCIDRIVER_IOCTL_H_ +#define _PCIDRIVER_IOCTL_H_ + +#include <linux/ioctl.h> + +#define PCIDRIVER_INTERFACE_VERSION 2 /**< Driver API version, only the pcilib with the same driver interface version is allowed */ + +/* Possible values for ioctl commands */ + +/* PCI mmap areas */ +#define PCIDRIVER_BAR0 0 +#define PCIDRIVER_BAR1 1 +#define PCIDRIVER_BAR2 2 +#define PCIDRIVER_BAR3 3 +#define PCIDRIVER_BAR4 4 +#define PCIDRIVER_BAR5 5 + +/* mmap mode of the device */ +#define PCIDRIVER_MMAP_PCI 0 +#define PCIDRIVER_MMAP_KMEM 1 + +/* Direction of a DMA operation */ +#define PCIDRIVER_DMA_BIDIRECTIONAL 0 +#define PCIDRIVER_DMA_TODEVICE 1 // PCILIB_KMEM_SYNC_TODEVICE +#define PCIDRIVER_DMA_FROMDEVICE 2 // PCILIB_KMEM_SYNC_FROMDEVICE + +/* Possible sizes in a PCI command */ +#define PCIDRIVER_PCI_CFG_SZ_BYTE 1 +#define PCIDRIVER_PCI_CFG_SZ_WORD 2 +#define PCIDRIVER_PCI_CFG_SZ_DWORD 3 + +/* Possible types of SG lists */ +#define PCIDRIVER_SG_NONMERGED 0 +#define PCIDRIVER_SG_MERGED 1 + +#define KMEM_REF_HW 0x80000000 /**< Special reference to indicate hardware access */ +#define KMEM_REF_COUNT 0x0FFFFFFF /**< Mask of reference counter (mmap/munmap), couting in mmaped memory pages */ + +#define KMEM_MODE_REUSABLE 0x80000000 /**< Indicates reusable buffer */ +#define KMEM_MODE_EXCLUSIVE 0x40000000 /**< Only a single process is allowed to mmap the buffer */ +#define KMEM_MODE_PERSISTENT 0x20000000 /**< Persistent mode instructs kmem_free to preserve buffer in memory */ +#define KMEM_MODE_COUNT 0x0FFFFFFF /**< Mask of reuse counter (alloc/free) */ + +#define KMEM_FLAG_REUSE PCILIB_KMEM_FLAG_REUSE /**< Try to reuse existing buffer with the same use & item */ +#define KMEM_FLAG_EXCLUSIVE PCILIB_KMEM_FLAG_EXCLUSIVE /**< Allow only a single application accessing a specified use & item */ +#define KMEM_FLAG_PERSISTENT PCILIB_KMEM_FLAG_PERSISTENT /**< Sets persistent mode */ +#define KMEM_FLAG_HW PCILIB_KMEM_FLAG_HARDWARE /**< The buffer may be accessed by hardware, the hardware access will not occur any more if passed to _free function */ +#define KMEM_FLAG_FORCE PCILIB_KMEM_FLAG_FORCE /**< Force memory cleanup even if references are present */ +#define KMEM_FLAG_MASS PCILIB_KMEM_FLAG_MASS /**< Apply to all buffers of selected use */ +#define KMEM_FLAG_TRY PCILIB_KMEM_FLAG_TRY /**< Do not allocate buffers, try to reuse and fail if not possible */ + +#define KMEM_FLAG_REUSED PCILIB_KMEM_FLAG_REUSE /**< Indicates if buffer with specified use & item was already allocated and reused */ +#define KMEM_FLAG_REUSED_PERSISTENT PCILIB_KMEM_FLAG_PERSISTENT /**< Indicates that reused buffer was persistent before the call */ +#define KMEM_FLAG_REUSED_HW PCILIB_KMEM_FLAG_HARDWARE /**< Indicates that reused buffer had a HW reference before the call */ + +/* Types */ + +typedef struct { + unsigned long version; /**< pcilib version */ + unsigned long interface; /**< driver interface version */ + unsigned long ioctls; /**< number of supporterd ioctls */ + unsigned long reserved[5]; /**< reserved for the future use */ +} pcilib_driver_version_t; + +typedef struct { + int iommu; /**< Specifies if IOMMU is enabled or disabled */ + int mps; /**< PCIe maximum payload size */ + int readrq; /**< PCIe read request size */ + unsigned long dma_mask; /**< DMA mask */ +} pcilib_device_state_t; + +typedef struct { + unsigned short vendor_id; + unsigned short device_id; + unsigned short bus; + unsigned short slot; + unsigned short func; + unsigned short devfn; + unsigned char interrupt_pin; + unsigned char interrupt_line; + unsigned int irq; + unsigned long bar_start[6]; + unsigned long bar_length[6]; + unsigned long bar_flags[6]; +} pcilib_board_info_t; + +typedef struct { + unsigned long type; + unsigned long pa; + unsigned long ba; + unsigned long size; + unsigned long align; + unsigned long use; + unsigned long item; + int flags; + int handle_id; +} kmem_handle_t; + +typedef struct { + unsigned long addr; + unsigned long size; +} umem_sgentry_t; + +typedef struct { + int handle_id; + int type; + int nents; + umem_sgentry_t *sg; +} umem_sglist_t; + +typedef struct { + unsigned long vma; + unsigned long size; + int handle_id; + int dir; +} umem_handle_t; + +typedef struct { + kmem_handle_t handle; + int dir; +} kmem_sync_t; + +typedef struct { + unsigned long count; + unsigned long timeout; // microseconds + unsigned int source; +} interrupt_wait_t; + +typedef struct { + int size; + int addr; + union { + unsigned char byte; + unsigned short word; + unsigned int dword; /* not strict C, but if not can have problems */ + } val; +} pci_cfg_cmd; + +/* ioctl interface */ +/* See documentation for a detailed usage explanation */ + +/* + * one of the problems of ioctl, is that requires a type definition. + * This type is only 8-bits wide, and half-documented in + * <linux-src>/Documentation/ioctl-number.txt. + * previous SHL -> 'S' definition, conflicts with several devices, + * so I changed it to be pci -> 'p', in the range 0xA0-BF + */ +#define PCIDRIVER_IOC_MAGIC 'p' +#define PCIDRIVER_IOC_BASE 0xA0 + +#define PCIDRIVER_IOC_MMAP_MODE _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 0 ) +#define PCIDRIVER_IOC_MMAP_AREA _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 1 ) +#define PCIDRIVER_IOC_KMEM_ALLOC _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 2, kmem_handle_t * ) +#define PCIDRIVER_IOC_KMEM_FREE _IOW ( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 3, kmem_handle_t * ) +#define PCIDRIVER_IOC_KMEM_SYNC _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 4, kmem_sync_t * ) +#define PCIDRIVER_IOC_UMEM_SGMAP _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 5, umem_handle_t * ) +#define PCIDRIVER_IOC_UMEM_SGUNMAP _IOW( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 6, umem_handle_t * ) +#define PCIDRIVER_IOC_UMEM_SGGET _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 7, umem_sglist_t * ) +#define PCIDRIVER_IOC_UMEM_SYNC _IOW( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 8, umem_handle_t * ) +#define PCIDRIVER_IOC_WAITI _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 9 ) + +/* And now, the methods to access the PCI configuration area */ +#define PCIDRIVER_IOC_PCI_CFG_RD _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 10, pci_cfg_cmd * ) +#define PCIDRIVER_IOC_PCI_CFG_WR _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 11, pci_cfg_cmd * ) +#define PCIDRIVER_IOC_PCI_INFO _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 12, pcilib_board_info_t * ) + +/* Clear interrupt queues */ +#define PCIDRIVER_IOC_CLEAR_IOQ _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 13 ) + +#define PCIDRIVER_IOC_VERSION _IOR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 14, pcilib_driver_version_t * ) +#define PCIDRIVER_IOC_DEVICE_STATE _IOR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 15, pcilib_device_state_t * ) +#define PCIDRIVER_IOC_DMA_MASK _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 16) +#define PCIDRIVER_IOC_MPS _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 17) + +#define PCIDRIVER_IOC_MAX 17 + +#endif /* _PCIDRIVER_IOCTL_H */ diff --git a/driver/kmem.c b/driver/kmem.c index e3b0a97..47d1929 100644 --- a/driver/kmem.c +++ b/driver/kmem.c @@ -17,12 +17,7 @@ #include <linux/mm.h> #include <linux/pagemap.h> -#include "config.h" /* compile-time configuration */ -#include "compat.h" /* compatibility definitions for older linux */ -#include "pciDriver.h" /* external interface for the driver */ -#include "common.h" /* internal definitions for all parts */ -#include "kmem.h" /* prototypes for kernel memory */ -#include "sysfs.h" /* prototypes for sysfs */ +#include "base.h" /** @@ -628,9 +623,9 @@ int pcidriver_mmap_kmem(pcidriver_privdata_t *privdata, struct vm_area_struct *v page_to_pfn(virt_to_page((void*)kmem_entry->cpua))); if ((kmem_entry->type&PCILIB_KMEM_TYPE_MASK) == PCILIB_KMEM_TYPE_REGION) { - ret = remap_pfn_range_compat(vma, vma->vm_start, kmem_entry->dma_handle, (vma_size < kmem_entry->size)?vma_size:kmem_entry->size, vma->vm_page_prot); + ret = remap_pfn_range(vma, vma->vm_start, (kmem_entry->dma_handle >> PAGE_SHIFT), (vma_size < kmem_entry->size)?vma_size:kmem_entry->size, vma->vm_page_prot); } else { - ret = remap_pfn_range_cpua_compat(vma, vma->vm_start, kmem_entry->cpua, (vma_size < kmem_entry->size)?vma_size:kmem_entry->size, vma->vm_page_prot); + ret = remap_pfn_range(vma, vma->vm_start, page_to_pfn(virt_to_page((void*)(kmem_entry->cpua))), (vma_size < kmem_entry->size)?vma_size:kmem_entry->size, vma->vm_page_prot); } if (ret) { diff --git a/driver/kmem.h b/driver/kmem.h index 503620e..e793bd6 100644 --- a/driver/kmem.h +++ b/driver/kmem.h @@ -1,3 +1,35 @@ +#ifndef _PCIDRIVER_KMEM_H +#define _PCIDRIVER_KMEM_H + +#include <linux/sysfs.h> + +#include "../pcilib/kmem.h" +#include "ioctl.h" + +/* Define an entry in the kmem list (this list is per device) */ +/* This list keeps references to the allocated kernel buffers */ +typedef struct { + int id; + enum dma_data_direction direction; + + struct list_head list; + dma_addr_t dma_handle; + unsigned long cpua; + unsigned long size; + unsigned long type; + unsigned long align; + + unsigned long use; + unsigned long item; + + spinlock_t lock; + unsigned long mode; + unsigned long refs; + + struct device_attribute sysfs_attr; /* initialized when adding the entry */ +} pcidriver_kmem_entry_t; + + int pcidriver_kmem_alloc( pcidriver_privdata_t *privdata, kmem_handle_t *kmem_handle ); int pcidriver_kmem_free( pcidriver_privdata_t *privdata, kmem_handle_t *kmem_handle ); int pcidriver_kmem_sync_entry( pcidriver_privdata_t *privdata, pcidriver_kmem_entry_t *kmem_entry, int direction ); @@ -7,3 +39,7 @@ pcidriver_kmem_entry_t *pcidriver_kmem_find_entry( pcidriver_privdata_t *privdat pcidriver_kmem_entry_t *pcidriver_kmem_find_entry_id( pcidriver_privdata_t *privdata, int id ); pcidriver_kmem_entry_t *pcidriver_kmem_find_entry_use(pcidriver_privdata_t *privdata, unsigned long use, unsigned long item); int pcidriver_kmem_free_entry( pcidriver_privdata_t *privdata, pcidriver_kmem_entry_t *kmem_entry ); + +int pcidriver_mmap_kmem( pcidriver_privdata_t *privdata, struct vm_area_struct *vmap ); + +#endif /* _PCIDRIVER_KMEM_H */ diff --git a/driver/pciDriver.h b/driver/pciDriver.h deleted file mode 100644 index 3a231bd..0000000 --- a/driver/pciDriver.h +++ /dev/null @@ -1,191 +0,0 @@ -#ifndef PCIDRIVER_H_ -#define PCIDRIVER_H_ - - -#include <linux/ioctl.h> - -#define PCIDRIVER_INTERFACE_VERSION 2 /**< Driver API version, only the pcilib with the same driver interface version is allowed */ - -/* Identifies the PCI-E Xilinx ML605 */ -#define PCIE_XILINX_VENDOR_ID 0x10ee -#define PCIE_ML605_DEVICE_ID 0x6024 - -/* Identifies the PCI-E IPE Hardware */ -#define PCIE_IPECAMERA_DEVICE_ID 0x6081 -#define PCIE_KAPTURE_DEVICE_ID 0x6028 - - -/* Possible values for ioctl commands */ - -/* PCI mmap areas */ -#define PCIDRIVER_BAR0 0 -#define PCIDRIVER_BAR1 1 -#define PCIDRIVER_BAR2 2 -#define PCIDRIVER_BAR3 3 -#define PCIDRIVER_BAR4 4 -#define PCIDRIVER_BAR5 5 - -/* mmap mode of the device */ -#define PCIDRIVER_MMAP_PCI 0 -#define PCIDRIVER_MMAP_KMEM 1 - -/* Direction of a DMA operation */ -#define PCIDRIVER_DMA_BIDIRECTIONAL 0 -#define PCIDRIVER_DMA_TODEVICE 1//PCILIB_KMEM_SYNC_TODEVICE -#define PCIDRIVER_DMA_FROMDEVICE 2//PCILIB_KMEM_SYNC_FROMDEVICE - -/* Possible sizes in a PCI command */ -#define PCIDRIVER_PCI_CFG_SZ_BYTE 1 -#define PCIDRIVER_PCI_CFG_SZ_WORD 2 -#define PCIDRIVER_PCI_CFG_SZ_DWORD 3 - -/* Possible types of SG lists */ -#define PCIDRIVER_SG_NONMERGED 0 -#define PCIDRIVER_SG_MERGED 1 - -/* Maximum number of interrupt sources */ -#define PCIDRIVER_INT_MAXSOURCES 16 - -#define KMEM_REF_HW 0x80000000 /**< Special reference to indicate hardware access */ -#define KMEM_REF_COUNT 0x0FFFFFFF /**< Mask of reference counter (mmap/munmap), couting in mmaped memory pages */ - -#define KMEM_MODE_REUSABLE 0x80000000 /**< Indicates reusable buffer */ -#define KMEM_MODE_EXCLUSIVE 0x40000000 /**< Only a single process is allowed to mmap the buffer */ -#define KMEM_MODE_PERSISTENT 0x20000000 /**< Persistent mode instructs kmem_free to preserve buffer in memory */ -#define KMEM_MODE_COUNT 0x0FFFFFFF /**< Mask of reuse counter (alloc/free) */ - -#define KMEM_FLAG_REUSE PCILIB_KMEM_FLAG_REUSE /**< Try to reuse existing buffer with the same use & item */ -#define KMEM_FLAG_EXCLUSIVE PCILIB_KMEM_FLAG_EXCLUSIVE /**< Allow only a single application accessing a specified use & item */ -#define KMEM_FLAG_PERSISTENT PCILIB_KMEM_FLAG_PERSISTENT /**< Sets persistent mode */ -#define KMEM_FLAG_HW PCILIB_KMEM_FLAG_HARDWARE /**< The buffer may be accessed by hardware, the hardware access will not occur any more if passed to _free function */ -#define KMEM_FLAG_FORCE PCILIB_KMEM_FLAG_FORCE /**< Force memory cleanup even if references are present */ -#define KMEM_FLAG_MASS PCILIB_KMEM_FLAG_MASS /**< Apply to all buffers of selected use */ -#define KMEM_FLAG_TRY PCILIB_KMEM_FLAG_TRY /**< Do not allocate buffers, try to reuse and fail if not possible */ - -#define KMEM_FLAG_REUSED PCILIB_KMEM_FLAG_REUSE /**< Indicates if buffer with specified use & item was already allocated and reused */ -#define KMEM_FLAG_REUSED_PERSISTENT PCILIB_KMEM_FLAG_PERSISTENT /**< Indicates that reused buffer was persistent before the call */ -#define KMEM_FLAG_REUSED_HW PCILIB_KMEM_FLAG_HARDWARE /**< Indicates that reused buffer had a HW reference before the call */ - -/* Types */ - -typedef struct { - unsigned long version; /**< pcilib version */ - unsigned long interface; /**< driver interface version */ - unsigned long ioctls; /**< number of supporterd ioctls */ - unsigned long reserved[5]; /**< reserved for the future use */ -} pcilib_driver_version_t; - -typedef struct { - int iommu; /**< Specifies if IOMMU is enabled or disabled */ - int mps; /**< PCIe maximum payload size */ - int readrq; /**< PCIe read request size */ - unsigned long dma_mask; /**< DMA mask */ -} pcilib_device_state_t; - -typedef struct { - unsigned short vendor_id; - unsigned short device_id; - unsigned short bus; - unsigned short slot; - unsigned short func; - unsigned short devfn; - unsigned char interrupt_pin; - unsigned char interrupt_line; - unsigned int irq; - unsigned long bar_start[6]; - unsigned long bar_length[6]; - unsigned long bar_flags[6]; -} pcilib_board_info_t; - -typedef struct { - unsigned long type; - unsigned long pa; - unsigned long ba; - unsigned long size; - unsigned long align; - unsigned long use; - unsigned long item; - int flags; - int handle_id; -} kmem_handle_t; - -typedef struct { - unsigned long addr; - unsigned long size; -} umem_sgentry_t; - -typedef struct { - int handle_id; - int type; - int nents; - umem_sgentry_t *sg; -} umem_sglist_t; - -typedef struct { - unsigned long vma; - unsigned long size; - int handle_id; - int dir; -} umem_handle_t; - -typedef struct { - kmem_handle_t handle; - int dir; -} kmem_sync_t; - -typedef struct { - unsigned long count; - unsigned long timeout; // microseconds - unsigned int source; -} interrupt_wait_t; - -typedef struct { - int size; - int addr; - union { - unsigned char byte; - unsigned short word; - unsigned int dword; /* not strict C, but if not can have problems */ - } val; -} pci_cfg_cmd; - -/* ioctl interface */ -/* See documentation for a detailed usage explanation */ - -/* - * one of the problems of ioctl, is that requires a type definition. - * This type is only 8-bits wide, and half-documented in - * <linux-src>/Documentation/ioctl-number.txt. - * previous SHL -> 'S' definition, conflicts with several devices, - * so I changed it to be pci -> 'p', in the range 0xA0-BF - */ -#define PCIDRIVER_IOC_MAGIC 'p' -#define PCIDRIVER_IOC_BASE 0xA0 - -#define PCIDRIVER_IOC_MMAP_MODE _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 0 ) -#define PCIDRIVER_IOC_MMAP_AREA _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 1 ) -#define PCIDRIVER_IOC_KMEM_ALLOC _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 2, kmem_handle_t * ) -#define PCIDRIVER_IOC_KMEM_FREE _IOW ( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 3, kmem_handle_t * ) -#define PCIDRIVER_IOC_KMEM_SYNC _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 4, kmem_sync_t * ) -#define PCIDRIVER_IOC_UMEM_SGMAP _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 5, umem_handle_t * ) -#define PCIDRIVER_IOC_UMEM_SGUNMAP _IOW( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 6, umem_handle_t * ) -#define PCIDRIVER_IOC_UMEM_SGGET _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 7, umem_sglist_t * ) -#define PCIDRIVER_IOC_UMEM_SYNC _IOW( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 8, umem_handle_t * ) -#define PCIDRIVER_IOC_WAITI _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 9 ) - -/* And now, the methods to access the PCI configuration area */ -#define PCIDRIVER_IOC_PCI_CFG_RD _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 10, pci_cfg_cmd * ) -#define PCIDRIVER_IOC_PCI_CFG_WR _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 11, pci_cfg_cmd * ) -#define PCIDRIVER_IOC_PCI_INFO _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 12, pcilib_board_info_t * ) - -/* Clear interrupt queues */ -#define PCIDRIVER_IOC_CLEAR_IOQ _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 13 ) - -#define PCIDRIVER_IOC_VERSION _IOR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 14, pcilib_driver_version_t * ) -#define PCIDRIVER_IOC_DEVICE_STATE _IOR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 15, pcilib_device_state_t * ) -#define PCIDRIVER_IOC_DMA_MASK _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 16) -#define PCIDRIVER_IOC_MPS _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 17) - -#define PCIDRIVER_IOC_MAX 17 - -#endif diff --git a/driver/compat.c b/driver/pcibus.c index f28f527..f28f527 100644 --- a/driver/compat.c +++ b/driver/pcibus.c diff --git a/driver/pcibus.h b/driver/pcibus.h new file mode 100644 index 0000000..8e977ec --- /dev/null +++ b/driver/pcibus.h @@ -0,0 +1,7 @@ +#ifndef _PCIDRIVER_PCIBUS_H +#define _PCIDRIVER_PCIBUS_H + +int pcidriver_pcie_get_mps(struct pci_dev *dev); +int pcidriver_pcie_set_mps(struct pci_dev *dev, int mps); + +#endif /* _PCIDRIVER_PCIBUS_H */ diff --git a/driver/pcidriver.h b/driver/pcidriver.h new file mode 100644 index 0000000..d64c80a --- /dev/null +++ b/driver/pcidriver.h @@ -0,0 +1,11 @@ +#ifndef _PCIDRIVER_H +#define _PCIDRIVER_H + +/** + * Evaluates if the supplied user-space address is actually BAR mapping. + * @param[in] address - the user-space address + * @return - the hardware address of BAR or 0 if the \p address is not BAR mapping + */ +extern unsigned long pcidriver_resolve_bar(unsigned long address); + +#endif /* _PCIDRIVER_H */
\ No newline at end of file diff --git a/driver/rdma.c b/driver/rdma.c index c08eef9..b1d939a 100644 --- a/driver/rdma.c +++ b/driver/rdma.c @@ -9,11 +9,7 @@ #include <linux/hugetlb.h> #include <linux/cdev.h> -#include "config.h" -#include "compat.h" -#include "pciDriver.h" -#include "common.h" -#include "rdma.h" +#include "base.h" static unsigned long pcidriver_follow_pte(struct mm_struct *mm, unsigned long address) { diff --git a/driver/rdma.h b/driver/rdma.h index cfe9c83..813406d 100644 --- a/driver/rdma.h +++ b/driver/rdma.h @@ -1,6 +1,5 @@ #ifndef _PCIDRIVER_RDMA_H #define _PCIDRIVER_RDMA_H -extern unsigned long pcidriver_resolve_bar(unsigned long address); #endif /* _PCIDRIVER_RDMA_H */ diff --git a/driver/sysfs.c b/driver/sysfs.c index 19865fc..d0fd870 100644 --- a/driver/sysfs.c +++ b/driver/sysfs.c @@ -18,106 +18,32 @@ #include <linux/pagemap.h> #include <linux/kernel.h> -#include "compat.h" -#include "config.h" -#include "pciDriver.h" -#include "common.h" -#include "umem.h" -#include "kmem.h" -#include "sysfs.h" +#include "base.h" -static SYSFS_GET_FUNCTION(pcidriver_show_kmem_entry); -static SYSFS_GET_FUNCTION(pcidriver_show_umem_entry); +#define SYSFS_GET_PRIVDATA dev_get_drvdata(dev) +#define SYSFS_GET_FUNCTION(name) ssize_t name(struct device *dev, struct device_attribute *attr, char *buf) +#define SYSFS_SET_FUNCTION(name) ssize_t name(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -/** - * - * Initializes the sysfs attributes for an kmem/umem-entry - * - */ -static int _pcidriver_sysfs_initialize(pcidriver_privdata_t *privdata, - int id, - struct class_device_attribute *sysfs_attr, - const char *fmtstring, - SYSFS_GET_FUNCTION((*callback))) -{ - /* sysfs attributes for kmem buffers don’t make sense before 2.6.13, as - we have no mmap support before */ - char namebuffer[16]; - - /* allocate space for the name of the attribute */ - snprintf(namebuffer, sizeof(namebuffer), fmtstring, id); - - if ((sysfs_attr->attr.name = kstrdup(namebuffer, GFP_KERNEL)) == NULL) - return -ENOMEM; +#define SYSFS_ATTR_NAME(name) (dev_attr_##name) - sysfs_attr->attr.mode = S_IRUGO; - sysfs_attr->show = callback; - sysfs_attr->store = NULL; +#define SYSFS_ATTR_CREATE(name) do { \ + int err = device_create_file(privdata->class_dev, &SYSFS_ATTR_NAME(name)); \ + if (err != 0) return err; \ + } while (0) - /* name and add attribute */ - if (class_device_create_file(privdata->class_dev, sysfs_attr) != 0) - return -ENXIO; /* Device not configured. Not the really best choice, but hm. */ - - return 0; -} - -int pcidriver_sysfs_initialize_kmem(pcidriver_privdata_t *privdata, int id, struct class_device_attribute *sysfs_attr) -{ - return _pcidriver_sysfs_initialize(privdata, id, sysfs_attr, "kbuf%d", pcidriver_show_kmem_entry); -} - -int pcidriver_sysfs_initialize_umem(pcidriver_privdata_t *privdata, int id, struct class_device_attribute *sysfs_attr) -{ - return _pcidriver_sysfs_initialize(privdata, id, sysfs_attr, "umem%d", pcidriver_show_umem_entry); -} - -/** - * - * Removes the file from sysfs and frees the allocated (kstrdup()) memory. - * - */ -void pcidriver_sysfs_remove(pcidriver_privdata_t *privdata, struct class_device_attribute *sysfs_attr) -{ - class_device_remove_file(privdata->class_dev, sysfs_attr); - kfree(sysfs_attr->attr.name); -} - -static SYSFS_GET_FUNCTION(pcidriver_show_kmem_entry) -{ - pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; - - /* As we can be sure that attr.name contains a filename which we - * created (see _pcidriver_sysfs_initialize), we do not need to have - * sanity checks but can directly call simple_strtol() */ - int id = simple_strtol(attr->attr.name + strlen("kbuf"), NULL, 10); - pcidriver_kmem_entry_t *entry = pcidriver_kmem_find_entry_id(privdata, id); - if (entry) { - unsigned long addr = entry->cpua; - unsigned long dma_addr = entry->dma_handle; - - if (entry->size >= 16) { - pcidriver_kmem_sync_entry(privdata, entry, PCILIB_KMEM_SYNC_FROMDEVICE); - return snprintf(buf, PAGE_SIZE, "buffer: %d\naddr: %lx\nhw addr: %llx\nbus addr: %lx\ntype: %lx\nuse: 0x%lx\nitem: %lu\nsize: %lu\nrefs: %lu\nhw ref: %i\nmode: 0x%lx\ndata: %8x %8x %8x %8x\n", id, addr, virt_to_phys((void*)addr), dma_addr, entry->type, entry->use, entry->item, entry->size, entry->refs&KMEM_REF_COUNT, (entry->refs&KMEM_REF_HW)?1:0, entry->mode, *(u32*)(entry->cpua), *(u32*)(entry->cpua + 4), *(u32*)(entry->cpua + 8), *(u32*)(entry->cpua + 12)); - } else - return snprintf(buf, PAGE_SIZE, "buffer: %d\naddr: %lx\nhw addr: %llx\nbus addr: %lx\ntype: %lx\nuse: 0x%lx\nitem: %lu\nsize: %lu\nrefs: %lu\nhw ref: %i\nmode: 0x%lx\n", id, addr, virt_to_phys((void*)addr), dma_addr, entry->type, entry->use, entry->item, entry->size, entry->refs&KMEM_REF_COUNT, (entry->refs&KMEM_REF_HW)?1:0, entry->mode); - } else - return snprintf(buf, PAGE_SIZE, "I am in the kmem_entry show function for buffer %d\n", id); -} - -static SYSFS_GET_FUNCTION(pcidriver_show_umem_entry) -{ - return 0; -} +#define SYSFS_ATTR_REMOVE(name) do { \ + device_remove_file(privdata->class_dev, &SYSFS_ATTR_NAME(name)); \ + } while (0) #ifdef ENABLE_IRQ -SYSFS_GET_FUNCTION(pcidriver_show_irq_count) +static SYSFS_GET_FUNCTION(pcidriver_show_irq_count) { pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; return snprintf(buf, PAGE_SIZE, "%d\n", privdata->irq_count); } -SYSFS_GET_FUNCTION(pcidriver_show_irq_queues) +static SYSFS_GET_FUNCTION(pcidriver_show_irq_queues) { pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; int i, offset; @@ -131,14 +57,14 @@ SYSFS_GET_FUNCTION(pcidriver_show_irq_queues) } #endif -SYSFS_GET_FUNCTION(pcidriver_show_mmap_mode) +static SYSFS_GET_FUNCTION(pcidriver_show_mmap_mode) { pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; return snprintf(buf, PAGE_SIZE, "%d\n", privdata->mmap_mode); } -SYSFS_SET_FUNCTION(pcidriver_store_mmap_mode) +static SYSFS_SET_FUNCTION(pcidriver_store_mmap_mode) { pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; int mode = -1; @@ -151,14 +77,14 @@ SYSFS_SET_FUNCTION(pcidriver_store_mmap_mode) return strlen(buf); } -SYSFS_GET_FUNCTION(pcidriver_show_mmap_area) +static SYSFS_GET_FUNCTION(pcidriver_show_mmap_area) { pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; return snprintf(buf, PAGE_SIZE, "%d\n", privdata->mmap_area); } -SYSFS_SET_FUNCTION(pcidriver_store_mmap_area) +static SYSFS_SET_FUNCTION(pcidriver_store_mmap_area) { pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; int temp = -1; @@ -171,14 +97,14 @@ SYSFS_SET_FUNCTION(pcidriver_store_mmap_area) return strlen(buf); } -SYSFS_GET_FUNCTION(pcidriver_show_kmem_count) +static SYSFS_GET_FUNCTION(pcidriver_show_kmem_count) { pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&(privdata->kmem_count))); } -SYSFS_SET_FUNCTION(pcidriver_store_kmem_alloc) +static SYSFS_SET_FUNCTION(pcidriver_store_kmem_alloc) { pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; kmem_handle_t kmem_handle; @@ -190,7 +116,7 @@ SYSFS_SET_FUNCTION(pcidriver_store_kmem_alloc) return strlen(buf); } -SYSFS_SET_FUNCTION(pcidriver_store_kmem_free) +static SYSFS_SET_FUNCTION(pcidriver_store_kmem_free) { pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; unsigned int id; @@ -209,7 +135,7 @@ err: return strlen(buf); } -SYSFS_GET_FUNCTION(pcidriver_show_kbuffers) +static SYSFS_GET_FUNCTION(pcidriver_show_kbuffers) { pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; int offset = 0; @@ -238,7 +164,7 @@ SYSFS_GET_FUNCTION(pcidriver_show_kbuffers) return (offset > PAGE_SIZE ? PAGE_SIZE : offset+1); } -SYSFS_GET_FUNCTION(pcidriver_show_umappings) +static SYSFS_GET_FUNCTION(pcidriver_show_umappings) { int offset = 0; pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; @@ -268,7 +194,7 @@ SYSFS_GET_FUNCTION(pcidriver_show_umappings) return (offset > PAGE_SIZE ? PAGE_SIZE : offset+1); } -SYSFS_SET_FUNCTION(pcidriver_store_umem_unmap) +static SYSFS_SET_FUNCTION(pcidriver_store_umem_unmap) { pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; pcidriver_umem_entry_t *umem_entry; @@ -285,3 +211,128 @@ SYSFS_SET_FUNCTION(pcidriver_store_umem_unmap) err: return strlen(buf); } + +static SYSFS_GET_FUNCTION(pcidriver_show_kmem_entry) +{ + pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; + + /* As we can be sure that attr.name contains a filename which we + * created (see _pcidriver_sysfs_initialize), we do not need to have + * sanity checks but can directly call simple_strtol() */ + int id = simple_strtol(attr->attr.name + strlen("kbuf"), NULL, 10); + pcidriver_kmem_entry_t *entry = pcidriver_kmem_find_entry_id(privdata, id); + if (entry) { + unsigned long addr = entry->cpua; + unsigned long dma_addr = entry->dma_handle; + + if (entry->size >= 16) { + pcidriver_kmem_sync_entry(privdata, entry, PCILIB_KMEM_SYNC_FROMDEVICE); + return snprintf(buf, PAGE_SIZE, "buffer: %d\naddr: %lx\nhw addr: %llx\nbus addr: %lx\ntype: %lx\nuse: 0x%lx\nitem: %lu\nsize: %lu\nrefs: %lu\nhw ref: %i\nmode: 0x%lx\ndata: %8x %8x %8x %8x\n", id, addr, virt_to_phys((void*)addr), dma_addr, entry->type, entry->use, entry->item, entry->size, entry->refs&KMEM_REF_COUNT, (entry->refs&KMEM_REF_HW)?1:0, entry->mode, *(u32*)(entry->cpua), *(u32*)(entry->cpua + 4), *(u32*)(entry->cpua + 8), *(u32*)(entry->cpua + 12)); + } else + return snprintf(buf, PAGE_SIZE, "buffer: %d\naddr: %lx\nhw addr: %llx\nbus addr: %lx\ntype: %lx\nuse: 0x%lx\nitem: %lu\nsize: %lu\nrefs: %lu\nhw ref: %i\nmode: 0x%lx\n", id, addr, virt_to_phys((void*)addr), dma_addr, entry->type, entry->use, entry->item, entry->size, entry->refs&KMEM_REF_COUNT, (entry->refs&KMEM_REF_HW)?1:0, entry->mode); + } else + return snprintf(buf, PAGE_SIZE, "I am in the kmem_entry show function for buffer %d\n", id); +} + +static SYSFS_GET_FUNCTION(pcidriver_show_umem_entry) +{ + return 0; +} + + +#ifdef ENABLE_IRQ +static DEVICE_ATTR(irq_count, S_IRUGO, pcidriver_show_irq_count, NULL); +static DEVICE_ATTR(irq_queues, S_IRUGO, pcidriver_show_irq_queues, NULL); +#endif + +static DEVICE_ATTR(mmap_mode, 0664, pcidriver_show_mmap_mode, pcidriver_store_mmap_mode); +static DEVICE_ATTR(mmap_area, 0664, pcidriver_show_mmap_area, pcidriver_store_mmap_area); +static DEVICE_ATTR(kmem_count, 0444, pcidriver_show_kmem_count, NULL); +static DEVICE_ATTR(kbuffers, 0444, pcidriver_show_kbuffers, NULL); +static DEVICE_ATTR(kmem_alloc, 0220, NULL, pcidriver_store_kmem_alloc); +static DEVICE_ATTR(kmem_free, 0220, NULL, pcidriver_store_kmem_free); +static DEVICE_ATTR(umappings, 0444, pcidriver_show_umappings, NULL); +static DEVICE_ATTR(umem_unmap, 0220, NULL, pcidriver_store_umem_unmap); + +int pcidriver_create_sysfs_attributes(pcidriver_privdata_t *privdata) { +#ifdef ENABLE_IRQ + SYSFS_ATTR_CREATE(irq_count); + SYSFS_ATTR_CREATE(irq_queues); +#endif + + SYSFS_ATTR_CREATE(mmap_mode); + SYSFS_ATTR_CREATE(mmap_area); + SYSFS_ATTR_CREATE(kmem_count); + SYSFS_ATTR_CREATE(kmem_alloc); + SYSFS_ATTR_CREATE(kmem_free); + SYSFS_ATTR_CREATE(kbuffers); + SYSFS_ATTR_CREATE(umappings); + SYSFS_ATTR_CREATE(umem_unmap); + + return 0; +} + +void pcidriver_remove_sysfs_attributes(pcidriver_privdata_t *privdata) { +#ifdef ENABLE_IRQ + SYSFS_ATTR_REMOVE(irq_count); + SYSFS_ATTR_REMOVE(irq_queues); +#endif + + SYSFS_ATTR_REMOVE(mmap_mode); + SYSFS_ATTR_REMOVE(mmap_area); + SYSFS_ATTR_REMOVE(kmem_count); + SYSFS_ATTR_REMOVE(kmem_alloc); + SYSFS_ATTR_REMOVE(kmem_free); + SYSFS_ATTR_REMOVE(kbuffers); + SYSFS_ATTR_REMOVE(umappings); + SYSFS_ATTR_REMOVE(umem_unmap); +} + +/** + * + * Removes the file from sysfs and frees the allocated (kstrdup()) memory. + * + */ +void pcidriver_sysfs_remove(pcidriver_privdata_t *privdata, struct device_attribute *sysfs_attr) +{ + device_remove_file(privdata->class_dev, sysfs_attr); + kfree(sysfs_attr->attr.name); +} + +/** + * + * Initializes the sysfs attributes for an kmem/umem-entry + * + */ +static int _pcidriver_sysfs_initialize(pcidriver_privdata_t *privdata, int id, struct device_attribute *sysfs_attr, const char *fmtstring, SYSFS_GET_FUNCTION((*callback))) +{ + /* sysfs attributes for kmem buffers don’t make sense before 2.6.13, as + we have no mmap support before */ + char namebuffer[16]; + + /* allocate space for the name of the attribute */ + snprintf(namebuffer, sizeof(namebuffer), fmtstring, id); + + if ((sysfs_attr->attr.name = kstrdup(namebuffer, GFP_KERNEL)) == NULL) + return -ENOMEM; + + sysfs_attr->attr.mode = S_IRUGO; + sysfs_attr->show = callback; + sysfs_attr->store = NULL; + + /* name and add attribute */ + if (device_create_file(privdata->class_dev, sysfs_attr) != 0) + return -ENXIO; /* Device not configured. Not the really best choice, but hm. */ + + return 0; +} + +int pcidriver_sysfs_initialize_kmem(pcidriver_privdata_t *privdata, int id, struct device_attribute *sysfs_attr) +{ + return _pcidriver_sysfs_initialize(privdata, id, sysfs_attr, "kbuf%d", pcidriver_show_kmem_entry); +} + +int pcidriver_sysfs_initialize_umem(pcidriver_privdata_t *privdata, int id, struct device_attribute *sysfs_attr) +{ + return _pcidriver_sysfs_initialize(privdata, id, sysfs_attr, "umem%d", pcidriver_show_umem_entry); +} diff --git a/driver/sysfs.h b/driver/sysfs.h index 4c413f0..8de518b 100644 --- a/driver/sysfs.h +++ b/driver/sysfs.h @@ -1,23 +1,15 @@ #ifndef _PCIDRIVER_SYSFS_H #define _PCIDRIVER_SYSFS_H -int pcidriver_sysfs_initialize_kmem(pcidriver_privdata_t *privdata, int id, struct class_device_attribute *sysfs_attr); -int pcidriver_sysfs_initialize_umem(pcidriver_privdata_t *privdata, int id, struct class_device_attribute *sysfs_attr); -void pcidriver_sysfs_remove(pcidriver_privdata_t *privdata, struct class_device_attribute *sysfs_attr); -#ifdef ENABLE_IRQ -SYSFS_GET_FUNCTION(pcidriver_show_irq_count); -SYSFS_GET_FUNCTION(pcidriver_show_irq_queues); -#endif +#include <linux/sysfs.h> -/* prototypes for sysfs operations */ -SYSFS_GET_FUNCTION(pcidriver_show_mmap_mode); -SYSFS_SET_FUNCTION(pcidriver_store_mmap_mode); -SYSFS_GET_FUNCTION(pcidriver_show_mmap_area); -SYSFS_SET_FUNCTION(pcidriver_store_mmap_area); -SYSFS_GET_FUNCTION(pcidriver_show_kmem_count); -SYSFS_GET_FUNCTION(pcidriver_show_kbuffers); -SYSFS_SET_FUNCTION(pcidriver_store_kmem_alloc); -SYSFS_SET_FUNCTION(pcidriver_store_kmem_free); -SYSFS_GET_FUNCTION(pcidriver_show_umappings); -SYSFS_SET_FUNCTION(pcidriver_store_umem_unmap); -#endif +#include "dev.h" + +int pcidriver_create_sysfs_attributes(pcidriver_privdata_t *privdata); +void pcidriver_remove_sysfs_attributes(pcidriver_privdata_t *privdata); + +int pcidriver_sysfs_initialize_kmem(pcidriver_privdata_t *privdata, int id, struct device_attribute *sysfs_attr); +int pcidriver_sysfs_initialize_umem(pcidriver_privdata_t *privdata, int id, struct device_attribute *sysfs_attr); +void pcidriver_sysfs_remove(pcidriver_privdata_t *privdata, struct device_attribute *sysfs_attr); + +#endif /* _PCIDRIVER_SYSFS_H */ diff --git a/driver/umem.c b/driver/umem.c index bb9af1e..d8be358 100644 --- a/driver/umem.c +++ b/driver/umem.c @@ -18,12 +18,7 @@ #include <linux/pagemap.h> #include <linux/sched.h> -#include "config.h" /* compile-time configuration */ -#include "compat.h" /* compatibility definitions for older linux */ -#include "pciDriver.h" /* external interface for the driver */ -#include "common.h" /* internal definitions for all parts */ -#include "umem.h" /* prototypes for kernel memory */ -#include "sysfs.h" /* prototypes for sysfs */ +#include "base.h" /** * @@ -109,7 +104,7 @@ int pcidriver_umem_sgmap(pcidriver_privdata_t *privdata, umem_handle_t *umem_han /* Lock the pages, then populate the SG list with the pages */ /* page0 is different */ if ( !PageReserved(pages[0]) ) - compat_lock_page(pages[0]); + __set_page_locked(pages[0]); offset = (umem_handle->vma & ~PAGE_MASK); length = (umem_handle->size > (PAGE_SIZE-offset) ? (PAGE_SIZE-offset) : umem_handle->size); @@ -120,7 +115,7 @@ int pcidriver_umem_sgmap(pcidriver_privdata_t *privdata, umem_handle_t *umem_han for(i=1; i<nr_pages; i++) { /* Lock page first */ if ( !PageReserved(pages[i]) ) - compat_lock_page(pages[i]); + __set_page_locked(pages[i]); /* Populate the list */ sg_set_page(&sg[i], pages[i], ((count > PAGE_SIZE) ? PAGE_SIZE : count), 0); @@ -169,7 +164,7 @@ umem_sgmap_unmap: if (nr_pages > 0) { for(i=0; i<nr_pages; i++) { if (PageLocked(pages[i])) - compat_unlock_page(pages[i]); + __clear_page_locked(pages[i]); if (!PageReserved(pages[i])) set_page_dirty(pages[i]); page_cache_release(pages[i]); @@ -201,7 +196,7 @@ int pcidriver_umem_sgunmap(pcidriver_privdata_t *privdata, pcidriver_umem_entry_ /* Mark pages as Dirty and unlock it */ if ( !PageReserved( umem_entry->pages[i] )) { SetPageDirty( umem_entry->pages[i] ); - compat_unlock_page(umem_entry->pages[i]); + __clear_page_locked(umem_entry->pages[i]); } /* and release it from the cache */ page_cache_release( umem_entry->pages[i] ); diff --git a/driver/umem.h b/driver/umem.h index d16c466..d504ecb 100644 --- a/driver/umem.h +++ b/driver/umem.h @@ -1,5 +1,26 @@ +#ifndef _PCIDRIVER_UMEM_H +#define _PCIDRIVER_UMEM_H + +#include <linux/sysfs.h> + +#include "ioctl.h" + +/* Define an entry in the umem list (this list is per device) */ +/* This list keeps references to the SG lists for each mapped userspace region */ +typedef struct { + int id; + struct list_head list; + unsigned int nr_pages; /* number of pages for this user memeory area */ + struct page **pages; /* list of pointers to the pages */ + unsigned int nents; /* actual entries in the scatter/gatter list (NOT nents for the map function, but the result) */ + struct scatterlist *sg; /* list of sg entries */ + struct device_attribute sysfs_attr; /* initialized when adding the entry */ +} pcidriver_umem_entry_t; + int pcidriver_umem_sgmap( pcidriver_privdata_t *privdata, umem_handle_t *umem_handle ); int pcidriver_umem_sgunmap( pcidriver_privdata_t *privdata, pcidriver_umem_entry_t *umem_entry ); int pcidriver_umem_sgget( pcidriver_privdata_t *privdata, umem_sglist_t *umem_sglist ); int pcidriver_umem_sync( pcidriver_privdata_t *privdata, umem_handle_t *umem_handle ); pcidriver_umem_entry_t *pcidriver_umem_find_entry_id( pcidriver_privdata_t *privdata, int id ); + +#endif /* _PCIDRIVER_UMEM_H */ |