summaryrefslogtreecommitdiffstats
path: root/driver
diff options
context:
space:
mode:
authorSuren A. Chilingaryan <csa@suren.me>2016-03-02 19:37:30 +0100
committerSuren A. Chilingaryan <csa@suren.me>2016-03-02 19:37:30 +0100
commit1120e8745ccd3e512fe2016c9e5092fcd378490a (patch)
tree0e89ac6cd82c213a78d79d10d3fecff06f21127d /driver
parent01e857cca352e73243d00b62a0c248a35cea6b71 (diff)
downloadpcitool-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/Makefile18
-rw-r--r--driver/base.c437
-rw-r--r--driver/base.h93
-rw-r--r--driver/common.h110
-rw-r--r--driver/compat.h43
-rw-r--r--driver/config.h34
-rw-r--r--driver/debug.h25
-rw-r--r--driver/dev.c196
-rw-r--r--driver/dev.h52
-rw-r--r--driver/int.c133
-rw-r--r--driver/int.h3
-rw-r--r--driver/ioctl.c25
-rw-r--r--driver/ioctl.h179
-rw-r--r--driver/kmem.c11
-rw-r--r--driver/kmem.h36
-rw-r--r--driver/pciDriver.h191
-rw-r--r--driver/pcibus.c (renamed from driver/compat.c)0
-rw-r--r--driver/pcibus.h7
-rw-r--r--driver/pcidriver.h11
-rw-r--r--driver/rdma.c6
-rw-r--r--driver/rdma.h1
-rw-r--r--driver/sysfs.c247
-rw-r--r--driver/sysfs.h30
-rw-r--r--driver/umem.c15
-rw-r--r--driver/umem.h21
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 */