diff options
Diffstat (limited to 'driver/base.c')
-rw-r--r-- | driver/base.c | 789 |
1 files changed, 317 insertions, 472 deletions
diff --git a/driver/base.c b/driver/base.c index dfd82c6..220f1f3 100644 --- a/driver/base.c +++ b/driver/base.c @@ -5,144 +5,9 @@ * @date 2009-04-05 * @brief Contains the main code which connects all the different parts and does * basic driver tasks like initialization. - * - * This is a full rewrite of the pciDriver. - * New default is to support kernel 2.6, using kernel 2.6 APIs. - * */ -/* - * Change History: - * - * $Log: not supported by cvs2svn $ - * Revision 1.13 2008-05-30 11:38:15 marcus - * Added patches for kernel 2.6.24 - * - * Revision 1.12 2008-01-24 14:21:36 marcus - * Added a CLEAR_INTERRUPT_QUEUE ioctl. - * Added a sysfs attribute to show the outstanding IRQ queues. - * - * Revision 1.11 2008-01-24 12:53:11 marcus - * Corrected wait_event condition in waiti_ioctl. Improved the loop too. - * - * Revision 1.10 2008-01-14 10:39:39 marcus - * Set some messages as debug instead of normal. - * - * Revision 1.9 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.8 2007-07-17 13:15:55 marcus - * Removed Tasklets. - * Using newest map for the ABB interrupts. - * - * Revision 1.7 2007-07-06 15:56:04 marcus - * Change default status for OLD_REGISTERS to not defined. - * - * Revision 1.6 2007-07-05 15:29:59 marcus - * Corrected issue with the bar mapping for interrupt handling. - * Added support up to kernel 2.6.20 - * - * Revision 1.5 2007-05-29 07:50:18 marcus - * Split code into 2 files. May get merged in the future again.... - * - * Revision 1.4 2007/03/01 17:47:34 marcus - * Fixed bug when the kernel memory was less than one page, it was not locked properly, recalling an old mapping issue in this case. - * - * Revision 1.3 2007/03/01 17:01:22 marcus - * comment fix (again). - * - * Revision 1.2 2007/03/01 17:00:25 marcus - * Changed some comment in the log. - * - * 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. - * - * From pciDriver.c: - * Revision 1.11 2006/12/11 16:15:43 marcus - * Fixed kernel buffer mmapping, and driver crash when application crashes. - * Buffer memory is now marked reserved during allocation, and mmaped with - * remap_xx_range. - * - * Revision 1.10 2006/11/21 09:50:49 marcus - * Added PROGRAPE4 vendor/device IDs. - * - * Revision 1.9 2006/11/17 18:47:36 marcus - * Removed MERGE_SGENTRIES flag, now it is selected at runtime with 'type'. - * Removed noncached in non-prefetchable areas, to allow the use of MTRRs. - * - * Revision 1.8 2006/11/17 16:41:21 marcus - * Added slot number to the PCI info IOctl. - * - * Revision 1.7 2006/11/13 12:30:34 marcus - * Added a IOctl call, to confiure the interrupt response. (testing pending). - * Basic interrupts are now supported, using a Tasklet and Completions. - * - * Revision 1.6 2006/11/08 21:30:02 marcus - * Added changes after compile tests in kernel 2.6.16 - * - * Revision 1.5 2006/10/31 07:57:38 marcus - * Improved the pfn calculation in nopage(), to deal with some possible border - * conditions. It was really no issue, because they are normally page-aligned - * anyway, but to be on the safe side. - * - * Revision 1.4 2006/10/30 19:37:40 marcus - * Solved bug on kernel memory not mapping properly. - * - * Revision 1.3 2006/10/18 11:19:20 marcus - * Added kernel 2.6.8 support based on comments from Joern Adamczewski (GSI). - * - * Revision 1.2 2006/10/18 11:04:15 marcus - * Bus Master is only activated when we detect a specific board. - * - * Revision 1.1 2006/10/10 14:46:51 marcus - * Initial commit of the new pciDriver for kernel 2.6 - * - * Revision 1.9 2006/10/05 11:30:46 marcus - * Prerelease. Added bus and devfn to pciInfo for compatibility. - * - * Revision 1.8 2006/09/25 16:51:07 marcus - * Added PCI config IOctls, and implemented basic mmap functions. - * - * Revision 1.7 2006/09/20 11:12:41 marcus - * Added Merge SG entries - * - * Revision 1.6 2006/09/19 17:22:18 marcus - * backup commit. - * - * Revision 1.5 2006/09/18 17:13:11 marcus - * backup commit. - * - * Revision 1.4 2006/09/15 15:44:41 marcus - * backup commit. - * - * Revision 1.3 2006/08/15 11:40:02 marcus - * backup commit. - * - * Revision 1.2 2006/08/12 18:28:42 marcus - * Sync with the laptop - * - * Revision 1.1 2006/08/11 15:30:46 marcus - * Sync with the laptop - * - */ - -#include <linux/version.h> -/* Check macros and kernel version first */ -#ifndef KERNEL_VERSION -#error "No KERNEL_VERSION macro! Stopping." -#endif - -#ifndef LINUX_VERSION_CODE -#error "No LINUX_VERSION_CODE macro! Stopping." -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8) -#error "This driver has been tested only for Kernel 2.6.8 or above." -#endif - -/* Required includes */ #include <linux/string.h> #include <linux/slab.h> #include <linux/types.h> @@ -166,32 +31,15 @@ #include "../pcilib/version.h" -/* Configuration for the driver (what should be compiled in, module name, etc...) */ #include "config.h" - -/* Compatibility functions/definitions (provides functions which are not available on older kernels) */ #include "compat.h" - -/* External interface for the driver */ #include "pciDriver.h" - -/* Internal definitions for all parts (prototypes, data, macros) */ #include "common.h" - -/* Internal definitions for the base part */ #include "base.h" - -/* Internal definitions of the IRQ handling part */ #include "int.h" - -/* Internal definitions for kernel memory */ #include "kmem.h" - -/* Internal definitions for user space memory */ #include "umem.h" - #include "ioctl.h" - #include "build.h" /*************************************************************************/ @@ -221,54 +69,54 @@ pcidriver_privdata_t *pcidriver_dummydata = NULL; */ 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); - - /* Register driver class */ - pcidriver_class = class_create(THIS_MODULE, NODENAME); - - if (IS_ERR(pcidriver_class)) { - mod_info("No sysfs support. Module not loaded.\n"); - goto init_class_fail; - } - - /* Register PCI driver. This function returns the number of devices on some - * systems, therefore check for errors as < 0. */ + 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); + + /* Register driver class */ + pcidriver_class = class_create(THIS_MODULE, NODENAME); + + if (IS_ERR(pcidriver_class)) { + mod_info("No sysfs support. Module not loaded.\n"); + goto init_class_fail; + } + + /* 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) { + if ((err = pcidriver_probe(NULL, NULL)) < 0) { #else /* PCIDRIVER_DUMMY_DEVICE */ - if ((err = pci_register_driver(&pcidriver_driver)) < 0) { + 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; - } + 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); - } + 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; + return 0; init_pcireg_fail: - class_destroy(pcidriver_class); + class_destroy(pcidriver_class); init_class_fail: - unregister_chrdev_region(pcidriver_devt, MAXDEVICES); + unregister_chrdev_region(pcidriver_devt, MAXDEVICES); init_alloc_fail: - return err; + return err; } /** @@ -279,17 +127,17 @@ init_alloc_fail: static void pcidriver_exit(void) { #ifdef PCIDRIVER_DUMMY_DEVICE - pcidriver_remove(NULL); + pcidriver_remove(NULL); #else - pci_unregister_driver(&pcidriver_driver); + pci_unregister_driver(&pcidriver_driver); #endif /* PCIDRIVER_DUMMY_DEVICE */ - unregister_chrdev_region(pcidriver_devt, MAXDEVICES); + unregister_chrdev_region(pcidriver_devt, MAXDEVICES); - if (pcidriver_class != NULL) - class_destroy(pcidriver_class); + if (pcidriver_class != NULL) + class_destroy(pcidriver_class); - mod_info("Module unloaded\n"); + mod_info("Module unloaded\n"); } /*************************************************************************/ @@ -303,10 +151,10 @@ static void pcidriver_exit(void) */ #ifndef PCIDRIVER_DUMMY_DEVICE static struct pci_driver pcidriver_driver = { - .name = MODNAME, - .id_table = pcidriver_ids, - .probe = pcidriver_probe, - .remove = pcidriver_remove, + .name = MODNAME, + .id_table = pcidriver_ids, + .probe = pcidriver_probe, + .remove = pcidriver_remove, }; #endif /* ! PCIDRIVER_DUMMY_DEVICE */ @@ -318,155 +166,155 @@ static struct pci_driver pcidriver_driver = { */ static int __devinit pcidriver_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - int err = 0; - int devno; - pcidriver_privdata_t *privdata; - int devid; - - /* At the moment there is no difference between these boards here, other than - * printing a different message in the log. - * - * However, there is some difference in the interrupt handling functions. - */ + int err = 0; + int devno; + pcidriver_privdata_t *privdata; + int devid; + + /* At the moment there is no difference between these boards here, other than + * printing a different message in the log. + * + * However, there is some difference in the interrupt handling functions. + */ #ifdef PCIDRIVER_DUMMY_DEVICE - mod_info("Emulated device\n"); + mod_info("Emulated device\n"); #else /* PCIDRIVER_DUMMY_DEVICE */ - if (id->vendor == PCIE_XILINX_VENDOR_ID) { - if (id->device == PCIE_ML605_DEVICE_ID) { - mod_info("Found ML605 board at %s\n", dev_name(&pdev->dev)); - } else if (id->device == PCIE_IPECAMERA_DEVICE_ID) { - mod_info("Found IPE Camera at %s\n", dev_name(&pdev->dev)); - } else if (id->device == PCIE_KAPTURE_DEVICE_ID) { - mod_info("Found KAPTURE board at %s\n", dev_name(&pdev->dev)); - } else { - mod_info("Found unknown Xilinx device (%x) at %s\n", id->device, dev_name(&pdev->dev)); - } - } else { - /* It is something else */ - mod_info("Found unknown board (%x:%x) at %s\n", id->vendor, id->device, dev_name(&pdev->dev)); - } - - /* Enable the device */ - if ((err = pci_enable_device(pdev)) != 0) { - mod_info("Couldn't enable device\n"); - goto probe_pcien_fail; - } - - /* Bus master & dma */ - pci_set_master(pdev); - - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (err < 0) { - printk(KERN_ERR "pci_set_dma_mask failed\n"); - goto probe_dma_fail; - } - - /* Set Memory-Write-Invalidate support */ - if ((err = pci_set_mwi(pdev)) != 0) - mod_info("MWI not supported. Continue without enabling MWI.\n"); + if (id->vendor == PCIE_XILINX_VENDOR_ID) { + if (id->device == PCIE_ML605_DEVICE_ID) { + mod_info("Found ML605 board at %s\n", dev_name(&pdev->dev)); + } else if (id->device == PCIE_IPECAMERA_DEVICE_ID) { + mod_info("Found IPE Camera at %s\n", dev_name(&pdev->dev)); + } else if (id->device == PCIE_KAPTURE_DEVICE_ID) { + mod_info("Found KAPTURE board at %s\n", dev_name(&pdev->dev)); + } else { + mod_info("Found unknown Xilinx device (%x) at %s\n", id->device, dev_name(&pdev->dev)); + } + } else { + /* It is something else */ + mod_info("Found unknown board (%x:%x) at %s\n", id->vendor, id->device, dev_name(&pdev->dev)); + } + + /* Enable the device */ + if ((err = pci_enable_device(pdev)) != 0) { + mod_info("Couldn't enable device\n"); + goto probe_pcien_fail; + } + + /* Bus master & dma */ + pci_set_master(pdev); + + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (err < 0) { + printk(KERN_ERR "pci_set_dma_mask failed\n"); + goto probe_dma_fail; + } + + /* Set Memory-Write-Invalidate support */ + if ((err = pci_set_mwi(pdev)) != 0) + mod_info("MWI not supported. Continue without enabling MWI.\n"); #endif /* PCIDRIVER_DUMMY_DEVICE */ - /* Get / Increment the device id */ - devid = atomic_inc_return(&pcidriver_deviceCount) - 1; - if (devid >= MAXDEVICES) { - mod_info("Maximum number of devices reached! Increase MAXDEVICES.\n"); - err = -ENOMSG; - goto probe_maxdevices_fail; - } - - /* Allocate and initialize the private data for this device */ - if ((privdata = kcalloc(1, sizeof(*privdata), GFP_KERNEL)) == NULL) { - err = -ENOMEM; - goto probe_nomem; - } - - privdata->devid = devid; - - INIT_LIST_HEAD(&(privdata->kmem_list)); - spin_lock_init(&(privdata->kmemlist_lock)); - atomic_set(&privdata->kmem_count, 0); - - INIT_LIST_HEAD(&(privdata->umem_list)); - spin_lock_init(&(privdata->umemlist_lock)); - atomic_set(&privdata->umem_count, 0); + /* Get / Increment the device id */ + devid = atomic_inc_return(&pcidriver_deviceCount) - 1; + if (devid >= MAXDEVICES) { + mod_info("Maximum number of devices reached! Increase MAXDEVICES.\n"); + err = -ENOMSG; + goto probe_maxdevices_fail; + } + + /* Allocate and initialize the private data for this device */ + if ((privdata = kcalloc(1, sizeof(*privdata), GFP_KERNEL)) == NULL) { + err = -ENOMEM; + goto probe_nomem; + } + + privdata->devid = devid; + + INIT_LIST_HEAD(&(privdata->kmem_list)); + spin_lock_init(&(privdata->kmemlist_lock)); + atomic_set(&privdata->kmem_count, 0); + + INIT_LIST_HEAD(&(privdata->umem_list)); + spin_lock_init(&(privdata->umemlist_lock)); + atomic_set(&privdata->umem_count, 0); #ifdef PCIDRIVER_DUMMY_DEVICE - pcidriver_dummydata = privdata; + pcidriver_dummydata = privdata; #else /* PCIDRIVER_DUMMY_DEVICE */ - pci_set_drvdata(pdev, privdata); - privdata->pdev = pdev; + pci_set_drvdata(pdev, privdata); + privdata->pdev = pdev; #endif /* PCIDRIVER_DUMMY_DEVICE */ - /* Device add to sysfs */ - devno = MKDEV(MAJOR(pcidriver_devt), MINOR(pcidriver_devt) + devid); - privdata->devno = devno; + /* Device add to sysfs */ + devno = MKDEV(MAJOR(pcidriver_devt), MINOR(pcidriver_devt) + devid); + privdata->devno = devno; - /* FIXME: some error checking missing here */ + /* 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); + 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); + 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 ); - mod_info("Device /dev/%s%d added\n",NODENAME,MINOR(pcidriver_devt) + devid); + class_set_devdata( privdata->class_dev, privdata ); + mod_info("Device /dev/%s%d added\n",NODENAME,MINOR(pcidriver_devt) + devid); #ifndef PCIDRIVER_DUMMY_DEVICE - /* Setup mmaped BARs into kernel space */ - if ((err = pcidriver_probe_irq(privdata)) != 0) - goto probe_irq_probe_fail; + /* Setup mmaped BARs into kernel space */ + if ((err = pcidriver_probe_irq(privdata)) != 0) + 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 { \ + /* 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 - - /* Register character device */ - cdev_init( &(privdata->cdev), &pcidriver_fops ); - privdata->cdev.owner = THIS_MODULE; - privdata->cdev.ops = &pcidriver_fops; - err = cdev_add( &privdata->cdev, devno, 1 ); - if (err) { - mod_info( "Couldn't add character device.\n" ); - goto probe_cdevadd_fail; - } - - pcidriver_privdata[devid] = privdata; - - return 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 + + /* Register character device */ + cdev_init( &(privdata->cdev), &pcidriver_fops ); + privdata->cdev.owner = THIS_MODULE; + privdata->cdev.ops = &pcidriver_fops; + err = cdev_add( &privdata->cdev, devno, 1 ); + if (err) { + mod_info( "Couldn't add character device.\n" ); + goto probe_cdevadd_fail; + } + + pcidriver_privdata[devid] = privdata; + + return 0; probe_device_create_fail: probe_cdevadd_fail: #ifndef PCIDRIVER_DUMMY_DEVICE probe_irq_probe_fail: - pcidriver_irq_unmap_bars(privdata); + pcidriver_irq_unmap_bars(privdata); #endif /* ! PCIDRIVER_DUMMY_DEVICE */ - kfree(privdata); + kfree(privdata); probe_nomem: - atomic_dec(&pcidriver_deviceCount); + atomic_dec(&pcidriver_deviceCount); probe_maxdevices_fail: #ifndef PCIDRIVER_DUMMY_DEVICE probe_dma_fail: - pci_disable_device(pdev); + pci_disable_device(pdev); probe_pcien_fail: #endif /* ! PCIDRIVER_DUMMY_DEVICE */ - return err; + return err; } /** @@ -476,62 +324,62 @@ probe_pcien_fail: */ static void __devexit pcidriver_remove(struct pci_dev *pdev) { - pcidriver_privdata_t *privdata; + pcidriver_privdata_t *privdata; #ifdef PCIDRIVER_DUMMY_DEVICE - privdata = pcidriver_dummydata; - pcidriver_dummydata = NULL; + privdata = pcidriver_dummydata; + pcidriver_dummydata = NULL; #else /* PCIDRIVER_DUMMY_DEVICE */ - /* Get private data from the device */ - privdata = pci_get_drvdata(pdev); + /* Get private data from the device */ + privdata = pci_get_drvdata(pdev); #endif /* PCIDRIVER_DUMMY_DEVICE */ - // Theoretically we should lock here and when using... - pcidriver_privdata[privdata->devid] = NULL; + // Theoretically we should lock here and when using... + pcidriver_privdata[privdata->devid] = NULL; - /* Removing sysfs attributes from class device */ - #define sysfs_attr(name) do { \ + /* 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 - - /* Free all allocated kmem buffers before leaving */ - pcidriver_kmem_free_all( privdata ); +#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 + + /* Free all allocated kmem buffers before leaving */ + pcidriver_kmem_free_all( privdata ); #ifndef PCIDRIVER_DUMMY_DEVICE # ifdef ENABLE_IRQ - pcidriver_remove_irq(privdata); + pcidriver_remove_irq(privdata); # endif #endif /* ! PCIDRIVER_DUMMY_DEVICE */ - /* Removing Character device */ - cdev_del(&(privdata->cdev)); + /* Removing Character device */ + cdev_del(&(privdata->cdev)); - /* Removing the device from sysfs */ - class_device_destroy(pcidriver_class, privdata->devno); + /* Removing the device from sysfs */ + class_device_destroy(pcidriver_class, privdata->devno); - /* Releasing privdata */ - kfree(privdata); + /* Releasing privdata */ + kfree(privdata); #ifdef PCIDRIVER_DUMMY_DEVICE - mod_info("Device at " NODENAMEFMT " removed\n", 0); + mod_info("Device at " NODENAMEFMT " removed\n", 0); #else /* PCIDRIVER_DUMMY_DEVICE */ - /* Disabling PCI device */ - pci_disable_device(pdev); - mod_info("Device at %s removed\n", dev_name(&pdev->dev)); + /* Disabling PCI device */ + pci_disable_device(pdev); + mod_info("Device at %s removed\n", dev_name(&pdev->dev)); #endif /* PCIDRIVER_DUMMY_DEVICE */ } @@ -550,15 +398,11 @@ static void __devexit pcidriver_remove(struct pci_dev *pdev) * */ static struct file_operations pcidriver_fops = { - .owner = THIS_MODULE, -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) - .ioctl = pcidriver_ioctl, -#else - .unlocked_ioctl = pcidriver_ioctl, -#endif - .mmap = pcidriver_mmap, - .open = pcidriver_open, - .release = pcidriver_release, + .owner = THIS_MODULE, + .unlocked_ioctl = pcidriver_ioctl, + .mmap = pcidriver_mmap, + .open = pcidriver_open, + .release = pcidriver_release, }; void pcidriver_module_get(pcidriver_privdata_t *privdata) { @@ -568,8 +412,8 @@ void pcidriver_module_get(pcidriver_privdata_t *privdata) { void pcidriver_module_put(pcidriver_privdata_t *privdata) { if (atomic_add_negative(-1, &(privdata->refs))) { - atomic_inc(&(privdata->refs)); - mod_info("Reference counting error..."); + atomic_inc(&(privdata->refs)); + mod_info("Reference counting error..."); } else { // mod_info("Unref: %i\n", atomic_read(&(privdata->refs))); } @@ -583,15 +427,15 @@ void pcidriver_module_put(pcidriver_privdata_t *privdata) { */ int pcidriver_open(struct inode *inode, struct file *filp) { - pcidriver_privdata_t *privdata; + 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; + /* 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); + pcidriver_module_get(privdata); - return 0; + return 0; } /** @@ -602,14 +446,14 @@ int pcidriver_open(struct inode *inode, struct file *filp) */ int pcidriver_release(struct inode *inode, struct file *filp) { - pcidriver_privdata_t *privdata; + pcidriver_privdata_t *privdata; - /* Get the private data area */ - privdata = filp->private_data; + /* Get the private data area */ + privdata = filp->private_data; - pcidriver_module_put(privdata); + pcidriver_module_put(privdata); - return 0; + return 0; } /** @@ -623,42 +467,54 @@ int pcidriver_release(struct inode *inode, struct file *filp) */ 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) */ - } - - return ret; + 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) */ + } + + return ret; } /*************************************************************************/ @@ -666,76 +522,65 @@ int pcidriver_mmap(struct file *filp, struct vm_area_struct *vma) int pcidriver_mmap_pci(pcidriver_privdata_t *privdata, struct vm_area_struct *vmap, int bar) { #ifdef PCIDRIVER_DUMMY_DEVICE - return -ENXIO; + return -ENXIO; #else /* PCIDRIVER_DUMMY_DEVICE */ - int ret = 0; - unsigned long bar_addr; - unsigned long bar_length, vma_size; - unsigned long bar_flags; + int ret = 0; + unsigned long bar_addr; + unsigned long bar_length, vma_size; + unsigned long bar_flags; - mod_info_dbg("Entering mmap_pci\n"); + 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); + /* 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); + /* 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 ((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 */ + if (bar_flags & IORESOURCE_IO) { + /* Unlikely case, we will mmap a IO region */ - /* IO regions are never cacheable */ -#ifdef pgprot_noncached - vmap->vm_page_prot = pgprot_noncached(vmap->vm_page_prot); -#endif + /* 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. */ -#ifdef pgprot_noncached -/* 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)) + /* 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); -#endif - /* Map the BAR */ - ret = remap_pfn_range_compat( - vmap, - vmap->vm_start, - bar_addr, - bar_length, - vmap->vm_page_prot); - } - - if (ret) { - mod_info("remap_pfn_range failed\n"); - return -EAGAIN; - } - - return 0; /* success */ + + /* Map the BAR */ + ret = remap_pfn_range_compat(vmap, vmap->vm_start, bar_addr, bar_length, vmap->vm_page_prot); + } + + if (ret) { + mod_info("remap_pfn_range failed\n"); + return -EAGAIN; + } + + return 0; /* success */ #endif /* PCIDRIVER_DUMMY_DEVICE */ } |