summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt42
-rw-r--r--apps/test_multithread.c14
-rw-r--r--driver/Makefile26
-rw-r--r--driver/base.c820
-rw-r--r--driver/base.h90
-rw-r--r--driver/common.h108
-rw-r--r--driver/compat.c26
-rw-r--r--driver/compat.h197
-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.c333
-rw-r--r--driver/int.h3
-rw-r--r--driver/ioctl.c529
-rw-r--r--driver/ioctl.h183
-rw-r--r--driver/kmem.c1027
-rw-r--r--driver/kmem.h36
-rw-r--r--driver/pciDriver.h245
-rw-r--r--driver/pcibus.c25
-rw-r--r--driver/pcibus.h7
-rw-r--r--driver/pcidriver.h11
-rw-r--r--driver/rdma.c41
-rw-r--r--driver/rdma.h4
-rw-r--r--driver/sysfs.c440
-rw-r--r--driver/sysfs.h30
-rw-r--r--driver/umem.c632
-rw-r--r--driver/umem.h21
-rw-r--r--pcilib/error.c13
-rw-r--r--pcilib/locking.c207
-rw-r--r--pcilib/pci.h2
-rw-r--r--pcilib/pcilib.h6
-rw-r--r--pcilib/property.c4
-rw-r--r--pcilib/py.c319
-rw-r--r--pyserver/api_server.py2
-rw-r--r--pyserver/scripts/test_script.py (renamed from xml/scripts/test_script.py)0
-rw-r--r--pyserver/scripts/test_script2.py (renamed from xml/scripts/test_script2.py)0
-rw-r--r--pywrap/CMakeLists.txt1
-rw-r--r--pywrap/pcilib.py4
-rw-r--r--pywrap/pcipywrap.c40
-rw-r--r--pywrap/pcipywrap.h36
-rw-r--r--pywrap/pcipywrap.i8
-rw-r--r--pywrap/test_pcilib.py6
-rwxr-xr-xrun6
-rw-r--r--xml/test/props.xml6
-rw-r--r--xml/test/test_prop2.py3
-rw-r--r--xml/test/test_prop4.py (renamed from xml/test/test_prop_mt.py)14
47 files changed, 2632 insertions, 3242 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bc9abc7..5c2d45b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
project(pcitool)
-set(PCILIB_VERSION "0.2.6")
+set(PCILIB_VERSION "0.2.7")
set(PCILIB_ABI_VERSION "2")
cmake_minimum_required(VERSION 2.8)
@@ -38,29 +38,27 @@ find_package(PkgConfig REQUIRED)
find_package(Threads REQUIRED)
if (NOT DISABLE_PYTHON)
- set(PYTHON_VERSION 2.7 CACHE PATH "python version")
-
- find_package(PythonLibs ${PYTHON_VERSION} REQUIRED)
+ set(PYTHON_VERSION 2.7 CACHE STRING "python version")
+
find_package(PythonInterp ${PYTHON_VERSION} REQUIRED)
-
+ find_package(PythonLibs ${PYTHON_VERSION_STRING} EXACT REQUIRED)
+
find_package(SWIG REQUIRED)
if (NOT PYTHON_VERSION_STRING VERSION_EQUAL PYTHONLIBS_VERSION_STRING)
- message (FATAL_ERROR "Version mismatch between python interpreter and libraries")
+ message (FATAL_ERROR "Version mismatch between python interpreter and libraries")
endif (NOT PYTHON_VERSION_STRING VERSION_EQUAL PYTHONLIBS_VERSION_STRING)
# execute_process (COMMAND ${PYTHON_EXECUTABLE} -c "from sysconfig import get_path; print get_path('platlib')" OUTPUT_VARIABLE PYTHON_INSTALL_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
- execute_process (COMMAND ${PYTHON_EXECUTABLE} -c "import site; print(site.PREFIXES[-1])" OUTPUT_VARIABLE PYTHON_PREFIX OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process (COMMAND ${PYTHON_EXECUTABLE} -c "import site; print site.PREFIXES[-1]" OUTPUT_VARIABLE PYTHON_PREFIX OUTPUT_STRIP_TRAILING_WHITESPACE)
file (TO_CMAKE_PATH "${PYTHON_PREFIX}" PYTHON_PREFIX)
- execute_process (COMMAND ${PYTHON_EXECUTABLE} -c "import site; print(site.getsitepackages()[0])" OUTPUT_VARIABLE PYTHON_SITE_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process (COMMAND ${PYTHON_EXECUTABLE} -c "import site; print site.getsitepackages()[0]" OUTPUT_VARIABLE PYTHON_SITE_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
file (TO_CMAKE_PATH "${PYTHON_SITE_DIR}" PYTHON_SITE_DIR)
string (REGEX REPLACE "^${PYTHON_PREFIX}/" "${CMAKE_INSTALL_PREFIX}/" PYTHON_SITE_DIR "${PYTHON_SITE_DIR}")
-
set(PYTHON_INSTALL_DIR ${PYTHON_SITE_DIR} CACHE PATH "path to install python module")
- message(${PYTHON_INSTALL_DIR})
+
set(HAVE_PYTHON TRUE)
- include(FindPythonInterp)
endif (NOT DISABLE_PYTHON)
set(EXTRA_SYSTEM_LIBS -lrt)
@@ -132,18 +130,16 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/pcilib/version.h.in ${CMAKE_CURRENT_B
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/docs/Doxyfile)
if (NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
- file(COPY ${CMAKE_SOURCE_DIR}/xml DESTINATION ${CMAKE_BINARY_DIR})
- file(COPY ${CMAKE_SOURCE_DIR}/pyserver DESTINATION ${CMAKE_BINARY_DIR})
- file(COPY ${CMAKE_SOURCE_DIR}/pci
- DESTINATION ${CMAKE_BINARY_DIR}
- FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
- )
- file(COPY ${CMAKE_SOURCE_DIR}/run
- DESTINATION ${CMAKE_BINARY_DIR}
- FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
- )
-
- configure_file(${CMAKE_SOURCE_DIR}/pcilib/version.h.in ${CMAKE_SOURCE_DIR}/pcilib/version.h)
+ file(COPY ${CMAKE_SOURCE_DIR}/xml DESTINATION ${CMAKE_BINARY_DIR})
+ file(COPY ${CMAKE_SOURCE_DIR}/pyserver DESTINATION ${CMAKE_BINARY_DIR})
+ file(COPY ${CMAKE_SOURCE_DIR}/pci
+ DESTINATION ${CMAKE_BINARY_DIR}
+ FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
+ )
+ file(COPY ${CMAKE_SOURCE_DIR}/run
+ DESTINATION ${CMAKE_BINARY_DIR}
+ FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
+ )
endif(NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
install(FILES
diff --git a/apps/test_multithread.c b/apps/test_multithread.c
index 4d0e8f2..f6afae7 100644
--- a/apps/test_multithread.c
+++ b/apps/test_multithread.c
@@ -1,8 +1,10 @@
#include <stdio.h>
#include <pthread.h>
-#include "pcilib.h"
#include <stdlib.h>
+#include "pcilib.h"
+#include "pcilib/error.h"
+
const char* prop = "/registers/fpga/reg1";
char* reg;
int stop = 0;
@@ -18,14 +20,14 @@ void *get_prop(void *arg)
err = pcilib_get_property(ctx, prop, &val);
if(err)
{
- printf("err pcilib_read_register\n");
+ pcilib_error("Error in pcilib_read_register");
return NULL;
}
long value = pcilib_get_value_as_int(ctx, &val, &err);
pcilib_clean_value(ctx, &val);
if(err)
{
- printf("err pcilib_get_value_as_int\n");
+ pcilib_error("Error in pcilib_get_value_as_int");
return NULL;
}
printf("reg = %li\n", value);
@@ -47,20 +49,20 @@ void *read_reg(void *arg)
if(err)
{
- printf("err pcilib_read_register\n");
+ pcilib_error("Error in pcilib_read_register");
return NULL;
}
err = pcilib_set_value_from_register_value(ctx, &val, reg_val);
if(err)
{
- printf("err pcilib_set_value_from_register_value\n");
+ pcilib_error("Error in pcilib_set_value_from_register_value");
return NULL;
}
long value = pcilib_get_value_as_int(ctx, &val, &err);
pcilib_clean_value(ctx, &val);
if(err)
{
- printf("err pcilib_get_value_as_int\n");
+ pcilib_error("Error in pcilib_get_value_as_int");
return NULL;
}
printf("reg = %li\n", value);
diff --git a/driver/Makefile b/driver/Makefile
index 0a860bf..a55e7c7 100644
--- a/driver/Makefile
+++ b/driver/Makefile
@@ -1,10 +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)/kernel/extra
+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)/..
@@ -53,15 +55,25 @@ install:
@mkdir -p $(INSTALLDIR)
@echo "INSTALL $(INSTALLDIR)/pciDriver.ko"
@install -m 755 pciDriver.ko $(INSTALLDIR)
- @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 $(INSTALLDIR)/pciDriver.symvers"
+ @install -m 644 Module.symvers $(INSTALLDIR)/pciDriver.symvers
+ @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"
@rm -f $(INSTALLDIR)/pciDriver.ko
- @echo "UNINSTALL /usr/include/pciDriver/driver/pciDriver.h"
- @rm -rf /usr/include/pciDriver/driver
+ @rm -f $(MAININSTALLDIR)/pciDriver.ko
+ @rm -f $(INSTALLDIR)/pciDriver.symvers
+ @rm -f $(MAININSTALLDIR)/pciDriver.symvers
+ @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 4e55dda..8bfbed6 100644
--- a/driver/base.c
+++ b/driver/base.c
@@ -1,148 +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.
- *
- * 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>
@@ -165,302 +20,197 @@
#include <linux/wait.h>
#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"
+#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_privdata = 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);
- /* 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);
- }
+/* Hold the allocated major & minor numbers */
+static dev_t pcidriver_devt;
- return 0;
+/* Number of devices allocated */
+static atomic_t pcidriver_deviceCount;
-init_pcireg_fail:
- class_destroy(pcidriver_class);
-init_class_fail:
- unregister_chrdev_region(pcidriver_devt, MAXDEVICES);
-init_alloc_fail:
- return err;
-}
+/* Private data for probed devices */
+static pcidriver_privdata_t* pcidriver_privdata[MAXDEVICES];
-/**
- *
- * 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 */
- unregister_chrdev_region(pcidriver_devt, MAXDEVICES);
+pcidriver_privdata_t *pcidriver_get_privdata(int devid) {
+ if (devid >= MAXDEVICES)
+ return NULL;
- if (pcidriver_class != NULL)
- class_destroy(pcidriver_class);
-
- 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)
{
- 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");
-#endif /* 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));
+ }
- /* 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;
- }
-
- 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);
+ /* Enable the device */
+ if ((err = pci_enable_device(pdev)) != 0) {
+ mod_info("Couldn't enable device\n");
+ goto probe_pcien_fail;
+ }
-#ifdef PCIDRIVER_DUMMY_DEVICE
- pcidriver_privdata = privdata;
-#else /* PCIDRIVER_DUMMY_DEVICE */
- pci_set_drvdata(pdev, privdata);
- privdata->pdev = pdev;
+ /* 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 */
- /* Device add to sysfs */
- devno = MKDEV(MAJOR(pcidriver_devt), MINOR(pcidriver_devt) + devid);
- privdata->devno = devno;
+ /* 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);
- /* 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);
+ pcidriver_dummydata = privdata;
#else /* PCIDRIVER_DUMMY_DEVICE */
- privdata->class_dev = class_device_create(pcidriver_class, NULL, devno, &(pdev->dev), NODENAMEFMT, MINOR(pcidriver_devt) + devid, privdata);
+ pci_set_drvdata(pdev, privdata);
+ privdata->pdev = pdev;
#endif /* PCIDRIVER_DUMMY_DEVICE */
- class_set_devdata( privdata->class_dev, privdata );
- mod_info("Device /dev/%s%d added\n",NODENAME,MINOR(pcidriver_devt) + devid);
+
+ /* Device add to sysfs */
+ devno = MKDEV(MAJOR(pcidriver_devt), MINOR(pcidriver_devt) + devid);
+ privdata->devno = devno;
+
+ /* FIXME: some error checking missing here */
+ 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
- /* 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 { \
- 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;
- }
-
- return 0;
+ /* TODO: correct errorhandling. ewww. must remove the files in reversed order :-( */
+ if (pcidriver_create_sysfs_attributes(privdata) != 0)
+ goto probe_device_create_fail;
+
+ /* Register character device */
+ cdev_init(&(privdata->cdev), pcidriver_get_fops());
+ privdata->cdev.owner = THIS_MODULE;
+ privdata->cdev.ops = pcidriver_get_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;
}
/**
@@ -470,262 +220,126 @@ 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_privdata;
- pcidriver_privdata = 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 */
- /* 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 );
+ // Theoretically we should lock here and when using...
+ pcidriver_privdata[privdata->devid] = NULL;
+
+ /* Removing sysfs attributes from class device */
+ pcidriver_remove_sysfs_attributes(privdata);
+
+ /* 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 */
+ 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 */
}
-/*************************************************************************/
-/* 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,
-#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,
+#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;
+ int err = 0;
- /* Set the private data area for the file */
- privdata = container_of( inode->i_cdev, pcidriver_privdata_t, cdev);
- filp->private_data = privdata;
+ /* Initialize the device count */
+ atomic_set(&pcidriver_deviceCount, 0);
- pcidriver_module_get(privdata);
+ memset(pcidriver_privdata, 0, sizeof(pcidriver_privdata));
- return 0;
-}
+ /* 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);
-/**
- *
- * 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;
+ /* Register driver class */
+ pcidriver_class = class_create(THIS_MODULE, NODENAME);
- /* Get the private data area */
- privdata = filp->private_data;
+ 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) {
+#else /* PCIDRIVER_DUMMY_DEVICE */
+ 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;
+ }
- pcidriver_module_put(privdata);
+ 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;
-/**
- *
- * 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) */
- }
-
- return ret;
+init_pcireg_fail:
+ class_destroy(pcidriver_class);
+init_class_fail:
+ unregister_chrdev_region(pcidriver_devt, MAXDEVICES);
+init_alloc_fail:
+ return err;
}
-/*************************************************************************/
-/* Internal driver functions */
-int pcidriver_mmap_pci(pcidriver_privdata_t *privdata, struct vm_area_struct *vmap, int bar)
+static void pcidriver_exit(void)
{
#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 */
-#ifdef pgprot_noncached
- vmap->vm_page_prot = pgprot_noncached(vmap->vm_page_prot);
-#endif
-
- /* 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))
-// 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 */
+ pcidriver_remove(NULL);
+#else
+ pci_unregister_driver(&pcidriver_driver);
#endif /* PCIDRIVER_DUMMY_DEVICE */
+
+ unregister_chrdev_region(pcidriver_devt, MAXDEVICES);
+
+ 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 5b977fa..0203808 100644
--- a/driver/base.h
+++ b/driver/base.h
@@ -1,87 +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;
-
-/* 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 6bc1329..0000000
--- a/driver/common.h
+++ /dev/null
@@ -1,108 +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 {
- 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);
-
-/*************************************************************************/
-/* 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.c b/driver/compat.c
deleted file mode 100644
index a632781..0000000
--- a/driver/compat.c
+++ /dev/null
@@ -1,26 +0,0 @@
-#include <linux/pci.h>
-
-int pcidriver_pcie_get_mps(struct pci_dev *dev)
-{
- u16 ctl;
-
- pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &ctl);
-
- return 128 << ((ctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5);
-}
-
-int pcidriver_pcie_set_mps(struct pci_dev *dev, int mps)
-{
- u16 v;
-
- if (mps < 128 || mps > 4096 || !is_power_of_2(mps))
- return -EINVAL;
-
- v = ffs(mps) - 8;
- if (v > dev->pcie_mpss)
- return -EINVAL;
- v <<= 5;
-
- return pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
- PCI_EXP_DEVCTL_PAYLOAD, v);
-}
diff --git a/driver/compat.h b/driver/compat.h
index 5232a22..24cc5a9 100644
--- a/driver/compat.h
+++ b/driver/compat.h
@@ -10,198 +10,31 @@
#ifndef _COMPAT_H
#define _COMPAT_H
-/*
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)
-# error "Linux 3.0 and latter are supported"
-#endif
-*/
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
-# define __devinit
-# define __devexit
-# define __devinitdata
-#endif
-
-/* dev_name is the wrapper one needs to use to access what was formerly called
- * bus_id in struct device. However, before 2.6.27, direct access was necessary,
- * so we provide our own version. */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
-static inline const char *dev_name(struct device *dev) {
- return dev->bus_id;
-}
-#endif
-
-/* SetPageLocked disappeared in v2.6.27 */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
- #define compat_lock_page SetPageLocked
- #define compat_unlock_page ClearPageLocked
-#else
- /* in v2.6.28, __set_page_locked and __clear_page_locked was introduced */
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
- #define compat_lock_page __set_page_locked
- #define compat_unlock_page __clear_page_locked
- #else
- /* However, in v2.6.27 itself, neither of them is there, so
- * we need to use our own function fiddling with bits inside
- * the page struct :-\ */
- static inline void compat_lock_page(struct page *page) {
- __set_bit(PG_locked, &page->flags);
- }
-
- static inline void compat_unlock_page(struct page *page) {
- __clear_bit(PG_locked, &page->flags);
- }
- #endif
-#endif
-
-/* Before 2.6.13, simple_class was the standard interface. Nowadays, it's just called class */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
-
- #define class_compat class_simple
-
- /* These functions are redirected to their old corresponding functions */
- #define class_create(module, name) class_simple_create(module, name)
- #define class_destroy(type) class_simple_destroy(type)
- #define class_device_destroy(unused, devno) class_simple_device_remove(devno)
- #define class_device_create(type, unused, devno, devpointer, nameformat, minor, unused) \
- class_simple_device_add(type, devno, devpointer, nameformat, minor)
- #define class_set_devdata(classdev, privdata) classdev->class_data = privdata
- #define DEVICE_ATTR_COMPAT
- #define sysfs_attr_def_name(name) class_device_attr_##name
- #define sysfs_attr_def_pointer privdata->class_dev
- #define SYSFS_GET_FUNCTION(name) ssize_t name(struct class_device *cls, char *buf)
- #define SYSFS_SET_FUNCTION(name) ssize_t name(struct class_device *cls, const char *buf, size_t count)
- #define SYSFS_GET_PRIVDATA (pcidriver_privdata_t*)cls->class_data
-
-#else
-
-/* In 2.6.26, device.h was changed quite significantly. Luckily, it only affected
- type/function names, for the most part. */
-//#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
- #define class_device_attribute device_attribute
- #define CLASS_DEVICE_ATTR DEVICE_ATTR
- #define class_device device
- #define class_data dev
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
- #define class_device_create(type, parent, devno, devpointer, nameformat, minor, privdata) \
- device_create(type, parent, devno, privdata, nameformat, minor)
-#else
- #define class_device_create(type, parent, devno, devpointer, nameformat, minor, unused) \
- device_create(type, parent, devno, nameformat, minor)
-#endif
- #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)
-
-//#endif
-
-#define class_compat class
-
-#endif
-
-/* The arguments of IRQ handlers have been changed in 2.6.19. It's very likely that
- int irq will disappear somewhen in the future (current is 2.6.29), too. */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
- #define IRQ_HANDLER_FUNC(name) irqreturn_t name(int irq, void *dev_id)
-#else
- #define IRQ_HANDLER_FUNC(name) irqreturn_t name(int irq, void *dev_id, struct pt_regs *regs)
-#endif
-
-/* atomic_inc_return appeared in 2.6.9, at least in CERN scientific linux, provide
- compatibility wrapper for older kernels */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
-static int atomic_inc_return(atomic_t *variable) {
- atomic_inc(variable);
- return atomic_read(variable);
-}
-#endif
-
-/* sg_set_page is available starting at 2.6.24 */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
-
-#define sg_set_page(sg, set_page, set_length, set_offset) do { \
- (sg)->page = set_page; \
- (sg)->length = set_length; \
- (sg)->offset = set_offset; \
-} while (0)
-
-#endif
-
-/* Before 2.6.20, disable was not an atomic counter, so this check was needed */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
-#define pci_disable_device(pdev) do { \
- if (pdev->is_enabled) \
- pci_disable_device(pdev); \
-} while (0)
-#endif
+#include <linux/version.h>
-/* Before 2.6.24, scatter/gather lists did not need to be initialized */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
- #define sg_init_table(sg, nr_pages)
+/* Check macros and kernel version first */
+#ifndef KERNEL_VERSION
+# error "No KERNEL_VERSION macro! Stopping."
#endif
-/* SA_SHIRQ was renamed to IRQF_SHARED in 2.6.24 */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
- #define request_irq(irq, irq_handler, modname, privdata) request_irq(irq, irq_handler, IRQF_SHARED, modname, privdata)
-#else
- #define request_irq(irq, irq_handler, modname, privdata) request_irq(irq, irq_handler, SA_SHIRQ, modname, privdata)
+#ifndef LINUX_VERSION_CODE
+# error "No LINUX_VERSION_CODE macro! Stopping."
#endif
-/* In 2.6.13, io_remap_page_range was removed in favor for io_remap_pfn_range which works on
- more platforms and allows more memory space */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
-#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)
-#else
-#define io_remap_pfn_range_compat(vmap, vm_start, bar_addr, bar_length, vm_page_prot) \
- io_remap_page_range(vmap, vm_start, bar_addr, bar_length, vm_page_prot)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0)
+# error "Linux 3.2 and latter are supported"
#endif
-/* In 2.6.10, remap_pfn_range was introduced, see io_remap_pfn_range_compat */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
-#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)
-
-#else
-#define remap_pfn_range_compat(vmap, vm_start, bar_addr, bar_length, vm_page_prot) \
- remap_page_range(vmap, vm_start, bar_addr, bar_length, vm_page_prot)
-
-#define remap_pfn_range_cpua_compat(vmap, vm_start, cpua, size, vm_page_prot) \
- remap_page_range(vmap, vm_start, virt_to_phys((void*)cpua), size, vm_page_prot)
+/* VM_RESERVED is removed in 3.7-rc1 */
+#ifndef VM_RESERVED
+# define VM_RESERVED (VM_DONTEXPAND | VM_DONTDUMP)
#endif
-/**
- * Go over the pages of the kmem buffer, and mark them as reserved.
- * This is needed, otherwise mmaping the kernel memory to user space
- * will fail silently (mmaping /dev/null) when using remap_xx_range.
- */
-static inline void set_pages_reserved_compat(unsigned long cpua, unsigned long size)
-{
- /* Starting in 2.6.15, the PG_RESERVED bit was removed.
- See also http://lwn.net/Articles/161204/ */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
- struct page *page, *last_page;
-
- page = virt_to_page(cpua);
- last_page = virt_to_page(cpua + size - 1);
- for (; page <= last_page; page++)
- SetPageReserved(page);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
+# define __devinit
+# define __devexit
+# define __devinitdata
#endif
-}
-
-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 5dbcb7f..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 "compat.h"
+#include "base.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)
/**
*
@@ -92,90 +68,90 @@
*/
int pcidriver_probe_irq(pcidriver_privdata_t *privdata)
{
- unsigned char int_pin, int_line;
- unsigned long bar_addr, bar_len, bar_flags;
- int i;
- int err;
-
- for (i = 0; i < 6; i++)
- privdata->bars_kmapped[i] = NULL;
-
- for (i = 0; i < 6; i++) {
- bar_addr = pci_resource_start(privdata->pdev, i);
- bar_len = pci_resource_len(privdata->pdev, i);
- bar_flags = pci_resource_flags(privdata->pdev, i);
-
- /* check if it is a valid BAR, skip if not */
- if ((bar_addr == 0) || (bar_len == 0))
- continue;
-
- /* Skip IO regions (map only mem regions) */
- if (bar_flags & IORESOURCE_IO)
- continue;
-
- /* Check if the region is available */
- if ((err = pci_request_region(privdata->pdev, i, NULL)) != 0) {
- mod_info( "Failed to request BAR memory region.\n" );
- return err;
- }
-
- /* Map it into kernel space. */
- /* For x86 this is just a dereference of the pointer, but that is
- * not portable. So we need to do the portable way. Thanks Joern!
- */
-
- /* respect the cacheable-bility of the region */
- if (bar_flags & IORESOURCE_PREFETCH)
- privdata->bars_kmapped[i] = ioremap(bar_addr, bar_len);
- else
- privdata->bars_kmapped[i] = ioremap_nocache(bar_addr, bar_len);
-
- /* check for error */
- if (privdata->bars_kmapped[i] == NULL) {
- mod_info( "Failed to remap BAR%d into kernel space.\n", i );
- return -EIO;
- }
- }
-
- /* Initialize the interrupt handler for this device */
- /* Initialize the wait queues */
- for (i = 0; i < PCIDRIVER_INT_MAXSOURCES; i++) {
- init_waitqueue_head(&(privdata->irq_queues[i]));
- atomic_set(&(privdata->irq_outstanding[i]), 0);
- }
-
- /* Initialize the irq config */
- if ((err = pci_read_config_byte(privdata->pdev, PCI_INTERRUPT_PIN, &int_pin)) != 0) {
- /* continue without interrupts */
- int_pin = 0;
- mod_info("Error getting the interrupt pin. Disabling interrupts for this device\n");
- }
-
- /* Disable interrupts and activate them if everything can be set up properly */
- privdata->irq_enabled = 0;
-
- if (int_pin == 0)
- return 0;
-
- if ((err = pci_read_config_byte(privdata->pdev, PCI_INTERRUPT_LINE, &int_line)) != 0) {
- mod_info("Error getting the interrupt line. Disabling interrupts for this device\n");
- return 0;
- }
-
- /* Enable interrupts using MSI mode */
- if (!pci_enable_msi(privdata->pdev))
- privdata->msi_mode = 1;
-
- /* register interrupt handler */
- if ((err = request_irq(privdata->pdev->irq, pcidriver_irq_handler, MODNAME, privdata)) != 0) {
- mod_info("Error registering the interrupt handler. Disabling interrupts for this device\n");
- return 0;
- }
-
- privdata->irq_enabled = 1;
- mod_info("Registered Interrupt Handler at pin %i, line %i, IRQ %i\n", int_pin, int_line, privdata->pdev->irq );
-
- return 0;
+ unsigned char int_pin, int_line;
+ unsigned long bar_addr, bar_len, bar_flags;
+ int i;
+ int err;
+
+ for (i = 0; i < 6; i++)
+ privdata->bars_kmapped[i] = NULL;
+
+ for (i = 0; i < 6; i++) {
+ bar_addr = pci_resource_start(privdata->pdev, i);
+ bar_len = pci_resource_len(privdata->pdev, i);
+ bar_flags = pci_resource_flags(privdata->pdev, i);
+
+ /* check if it is a valid BAR, skip if not */
+ if ((bar_addr == 0) || (bar_len == 0))
+ continue;
+
+ /* Skip IO regions (map only mem regions) */
+ if (bar_flags & IORESOURCE_IO)
+ continue;
+
+ /* Check if the region is available */
+ if ((err = pci_request_region(privdata->pdev, i, NULL)) != 0) {
+ mod_info( "Failed to request BAR memory region.\n" );
+ return err;
+ }
+
+ /* Map it into kernel space. */
+ /* For x86 this is just a dereference of the pointer, but that is
+ * not portable. So we need to do the portable way. Thanks Joern!
+ */
+
+ /* respect the cacheable-bility of the region */
+ if (bar_flags & IORESOURCE_PREFETCH)
+ privdata->bars_kmapped[i] = ioremap(bar_addr, bar_len);
+ else
+ privdata->bars_kmapped[i] = ioremap_nocache(bar_addr, bar_len);
+
+ /* check for error */
+ if (privdata->bars_kmapped[i] == NULL) {
+ mod_info( "Failed to remap BAR%d into kernel space.\n", i );
+ return -EIO;
+ }
+ }
+
+ /* Initialize the interrupt handler for this device */
+ /* Initialize the wait queues */
+ for (i = 0; i < PCIDRIVER_INT_MAXSOURCES; i++) {
+ init_waitqueue_head(&(privdata->irq_queues[i]));
+ atomic_set(&(privdata->irq_outstanding[i]), 0);
+ }
+
+ /* Initialize the irq config */
+ if ((err = pci_read_config_byte(privdata->pdev, PCI_INTERRUPT_PIN, &int_pin)) != 0) {
+ /* continue without interrupts */
+ int_pin = 0;
+ mod_info("Error getting the interrupt pin. Disabling interrupts for this device\n");
+ }
+
+ /* Disable interrupts and activate them if everything can be set up properly */
+ privdata->irq_enabled = 0;
+
+ if (int_pin == 0)
+ return 0;
+
+ if ((err = pci_read_config_byte(privdata->pdev, PCI_INTERRUPT_LINE, &int_line)) != 0) {
+ mod_info("Error getting the interrupt line. Disabling interrupts for this device\n");
+ return 0;
+ }
+
+ /* Enable interrupts using MSI mode */
+ if (!pci_enable_msi(privdata->pdev))
+ privdata->msi_mode = 1;
+
+ /* register interrupt handler */
+ 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;
+ }
+
+ privdata->irq_enabled = 1;
+ mod_info("Registered Interrupt Handler at pin %i, line %i, IRQ %i\n", int_pin, int_line, privdata->pdev->irq );
+
+ return 0;
}
/**
@@ -185,16 +161,16 @@ int pcidriver_probe_irq(pcidriver_privdata_t *privdata)
*/
void pcidriver_remove_irq(pcidriver_privdata_t *privdata)
{
- /* Release the IRQ handler */
- if (privdata->irq_enabled != 0)
- free_irq(privdata->pdev->irq, privdata);
-
- if (privdata->msi_mode) {
- pci_disable_msi(privdata->pdev);
- privdata->msi_mode = 0;
- }
-
- pcidriver_irq_unmap_bars(privdata);
+ /* Release the IRQ handler */
+ if (privdata->irq_enabled != 0)
+ free_irq(privdata->pdev->irq, privdata);
+
+ if (privdata->msi_mode) {
+ pci_disable_msi(privdata->pdev);
+ privdata->msi_mode = 0;
+ }
+
+ pcidriver_irq_unmap_bars(privdata);
}
/**
@@ -204,55 +180,14 @@ void pcidriver_remove_irq(pcidriver_privdata_t *privdata)
*/
void pcidriver_irq_unmap_bars(pcidriver_privdata_t *privdata)
{
- int i;
+ int i;
- for (i = 0; i < 6; i++) {
- if (privdata->bars_kmapped[i] == NULL)
- continue;
+ for (i = 0; i < 6; i++) {
+ if (privdata->bars_kmapped[i] == NULL)
+ continue;
- iounmap((void*)privdata->bars_kmapped[i]);
- pci_release_region(privdata->pdev, i);
- }
-}
-
-/**
- *
- * 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;
+ iounmap((void*)privdata->bars_kmapped[i]);
+ pci_release_region(privdata->pdev, i);
+ }
}
-/**
- *
- * 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 f957561..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) \
@@ -60,13 +54,13 @@
*/
static int ioctl_mmap_mode(pcidriver_privdata_t *privdata, unsigned long arg)
{
- if ((arg != PCIDRIVER_MMAP_PCI) && (arg != PCIDRIVER_MMAP_KMEM))
- return -EINVAL;
+ if ((arg != PCIDRIVER_MMAP_PCI) && (arg != PCIDRIVER_MMAP_KMEM))
+ return -EINVAL;
- /* change the mode */
- privdata->mmap_mode = arg;
+ /* change the mode */
+ privdata->mmap_mode = arg;
- return 0;
+ return 0;
}
/**
@@ -76,112 +70,103 @@ static int ioctl_mmap_mode(pcidriver_privdata_t *privdata, unsigned long arg)
*/
static int ioctl_mmap_area(pcidriver_privdata_t *privdata, unsigned long arg)
{
- /* validate input */
- if ((arg < PCIDRIVER_BAR0) || (arg > PCIDRIVER_BAR5))
- return -EINVAL;
+ /* validate input */
+ if ((arg < PCIDRIVER_BAR0) || (arg > PCIDRIVER_BAR5))
+ return -EINVAL;
- /* change the PCI area to mmap */
- privdata->mmap_area = arg;
+ /* change the PCI area to mmap */
+ privdata->mmap_area = arg;
- return 0;
+ return 0;
}
/**
- *
* 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)
{
#ifdef PCIDRIVER_DUMMY_DEVICE
- return -ENXIO;
+ return -ENXIO;
#else /* PCIDRIVER_DUMMY_DEVICE */
- int ret;
- READ_FROM_USER(pci_cfg_cmd, pci_cmd);
-
- if (cmd == PCIDRIVER_IOC_PCI_CFG_RD) {
- 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;
- case PCIDRIVER_PCI_CFG_SZ_WORD:
- ret = pci_read_config_word( privdata->pdev, pci_cmd.addr, &(pci_cmd.val.word) );
- break;
- case PCIDRIVER_PCI_CFG_SZ_DWORD:
- ret = pci_read_config_dword( privdata->pdev, pci_cmd.addr, &(pci_cmd.val.dword) );
- break;
- default:
- return -EINVAL; /* Wrong size setting */
- }
- } else {
- 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;
- case PCIDRIVER_PCI_CFG_SZ_WORD:
- ret = pci_write_config_word( privdata->pdev, pci_cmd.addr, pci_cmd.val.word );
- break;
- case PCIDRIVER_PCI_CFG_SZ_DWORD:
- ret = pci_write_config_dword( privdata->pdev, pci_cmd.addr, pci_cmd.val.dword );
- break;
- default:
- return -EINVAL; /* Wrong size setting */
- break;
- }
- }
-
- WRITE_TO_USER(pci_cfg_cmd, pci_cmd);
-
- return 0;
+ int ret;
+ READ_FROM_USER(pci_cfg_cmd, pci_cmd);
+
+ if (cmd == PCIDRIVER_IOC_PCI_CFG_RD) {
+ 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;
+ case PCIDRIVER_PCI_CFG_SZ_WORD:
+ ret = pci_read_config_word( privdata->pdev, pci_cmd.addr, &(pci_cmd.val.word) );
+ break;
+ case PCIDRIVER_PCI_CFG_SZ_DWORD:
+ ret = pci_read_config_dword( privdata->pdev, pci_cmd.addr, &(pci_cmd.val.dword) );
+ break;
+ default:
+ return -EINVAL; /* Wrong size setting */
+ }
+ } else {
+ 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;
+ case PCIDRIVER_PCI_CFG_SZ_WORD:
+ ret = pci_write_config_word( privdata->pdev, pci_cmd.addr, pci_cmd.val.word );
+ break;
+ case PCIDRIVER_PCI_CFG_SZ_DWORD:
+ ret = pci_write_config_dword( privdata->pdev, pci_cmd.addr, pci_cmd.val.dword );
+ break;
+ default:
+ return -EINVAL; /* Wrong size setting */
+ break;
+ }
+ }
+
+ WRITE_TO_USER(pci_cfg_cmd, pci_cmd);
+
+ return 0;
#endif /* PCIDRIVER_DUMMY_DEVICE */
}
/**
- *
* Gets the PCI information for the device.
- *
- * @see pcidriver_pci_info
- *
*/
static int ioctl_pci_info(pcidriver_privdata_t *privdata, unsigned long arg)
{
- int ret;
+ int ret;
#ifdef PCIDRIVER_DUMMY_DEVICE
- READ_FROM_USER(pcilib_board_info_t, pci_info);
- memset(&pci_info, 0, sizeof(pci_info));
- WRITE_TO_USER(pcilib_board_info_t, pci_info);
+ READ_FROM_USER(pcilib_board_info_t, pci_info);
+ memset(&pci_info, 0, sizeof(pci_info));
+ WRITE_TO_USER(pcilib_board_info_t, pci_info);
#else /* PCIDRIVER_DUMMY_DEVICE */
- int bar;
+ int bar;
- READ_FROM_USER(pcilib_board_info_t, pci_info);
+ READ_FROM_USER(pcilib_board_info_t, pci_info);
- pci_info.vendor_id = privdata->pdev->vendor;
- pci_info.device_id = privdata->pdev->device;
- pci_info.bus = privdata->pdev->bus->number;
- pci_info.slot = PCI_SLOT(privdata->pdev->devfn);
- pci_info.devfn = privdata->pdev->devfn;
- pci_info.func = PCI_FUNC(privdata->pdev->devfn);
+ pci_info.vendor_id = privdata->pdev->vendor;
+ pci_info.device_id = privdata->pdev->device;
+ pci_info.bus = privdata->pdev->bus->number;
+ pci_info.slot = PCI_SLOT(privdata->pdev->devfn);
+ pci_info.devfn = privdata->pdev->devfn;
+ pci_info.func = PCI_FUNC(privdata->pdev->devfn);
- if ((ret = pci_read_config_byte(privdata->pdev, PCI_INTERRUPT_PIN, &(pci_info.interrupt_pin))) != 0)
- return ret;
+ if ((ret = pci_read_config_byte(privdata->pdev, PCI_INTERRUPT_PIN, &(pci_info.interrupt_pin))) != 0)
+ return ret;
- if ((ret = pci_read_config_byte(privdata->pdev, PCI_INTERRUPT_LINE, &(pci_info.interrupt_line))) != 0)
- return ret;
+ if ((ret = pci_read_config_byte(privdata->pdev, PCI_INTERRUPT_LINE, &(pci_info.interrupt_line))) != 0)
+ return ret;
- for (bar = 0; bar < 6; bar++) {
- pci_info.bar_start[bar] = pci_resource_start(privdata->pdev, bar);
- pci_info.bar_length[bar] = pci_resource_len(privdata->pdev, bar);
- pci_info.bar_flags[bar] = pci_resource_flags(privdata->pdev, bar);
- }
+ for (bar = 0; bar < 6; bar++) {
+ pci_info.bar_start[bar] = pci_resource_start(privdata->pdev, bar);
+ pci_info.bar_length[bar] = pci_resource_len(privdata->pdev, bar);
+ pci_info.bar_flags[bar] = pci_resource_flags(privdata->pdev, bar);
+ }
- WRITE_TO_USER(pcilib_board_info_t, pci_info);
+ WRITE_TO_USER(pcilib_board_info_t, pci_info);
#endif /* PCIDRIVER_DUMMY_DEVICE */
- return 0;
+ return 0;
}
/**
@@ -193,13 +178,13 @@ static int ioctl_pci_info(pcidriver_privdata_t *privdata, unsigned long arg)
*/
static int ioctl_kmem_alloc(pcidriver_privdata_t *privdata, unsigned long arg)
{
- int err, ret;
+ int err, ret;
- READ_FROM_USER(kmem_handle_t, khandle);
- err = pcidriver_kmem_alloc(privdata, &khandle);
- WRITE_TO_USER(kmem_handle_t, khandle);
+ READ_FROM_USER(kmem_handle_t, khandle);
+ err = pcidriver_kmem_alloc(privdata, &khandle);
+ WRITE_TO_USER(kmem_handle_t, khandle);
- return err;
+ return err;
}
/**
@@ -211,13 +196,13 @@ static int ioctl_kmem_alloc(pcidriver_privdata_t *privdata, unsigned long arg)
*/
static int ioctl_kmem_free(pcidriver_privdata_t *privdata, unsigned long arg)
{
- int ret;
- READ_FROM_USER(kmem_handle_t, khandle);
+ int ret;
+ READ_FROM_USER(kmem_handle_t, khandle);
- if ((ret = pcidriver_kmem_free(privdata, &khandle)) != 0)
- return ret;
+ if ((ret = pcidriver_kmem_free(privdata, &khandle)) != 0)
+ return ret;
- return 0;
+ return 0;
}
/**
@@ -229,15 +214,15 @@ static int ioctl_kmem_free(pcidriver_privdata_t *privdata, unsigned long arg)
*/
static int ioctl_kmem_sync(pcidriver_privdata_t *privdata, unsigned long arg)
{
- int ret;
- READ_FROM_USER(kmem_sync_t, ksync);
-
- if ((ret = pcidriver_kmem_sync(privdata, &ksync)) != 0)
- return ret;
-
- WRITE_TO_USER(kmem_sync_t, ksync);
-
- return 0;
+ int ret;
+ READ_FROM_USER(kmem_sync_t, ksync);
+
+ if ((ret = pcidriver_kmem_sync(privdata, &ksync)) != 0)
+ return ret;
+
+ WRITE_TO_USER(kmem_sync_t, ksync);
+
+ return 0;
}
/*
@@ -249,15 +234,15 @@ static int ioctl_kmem_sync(pcidriver_privdata_t *privdata, unsigned long arg)
*/
static int ioctl_umem_sgmap(pcidriver_privdata_t *privdata, unsigned long arg)
{
- int ret;
- READ_FROM_USER(umem_handle_t, uhandle);
+ int ret;
+ READ_FROM_USER(umem_handle_t, uhandle);
- if ((ret = pcidriver_umem_sgmap(privdata, &uhandle)) != 0)
- return ret;
+ if ((ret = pcidriver_umem_sgmap(privdata, &uhandle)) != 0)
+ return ret;
- WRITE_TO_USER(umem_handle_t, uhandle);
+ WRITE_TO_USER(umem_handle_t, uhandle);
- return 0;
+ return 0;
}
/**
@@ -269,19 +254,19 @@ static int ioctl_umem_sgmap(pcidriver_privdata_t *privdata, unsigned long arg)
*/
static int ioctl_umem_sgunmap(pcidriver_privdata_t *privdata, unsigned long arg)
{
- int ret;
- pcidriver_umem_entry_t *umem_entry;
- READ_FROM_USER(umem_handle_t, uhandle);
+ int ret;
+ pcidriver_umem_entry_t *umem_entry;
+ READ_FROM_USER(umem_handle_t, uhandle);
- /* Find the associated umem_entry for this buffer,
- * return -EINVAL if the specified handle id is invalid */
- if ((umem_entry = pcidriver_umem_find_entry_id(privdata, uhandle.handle_id)) == NULL)
- return -EINVAL;
+ /* Find the associated umem_entry for this buffer,
+ * return -EINVAL if the specified handle id is invalid */
+ if ((umem_entry = pcidriver_umem_find_entry_id(privdata, uhandle.handle_id)) == NULL)
+ return -EINVAL;
- if ((ret = pcidriver_umem_sgunmap(privdata, umem_entry)) != 0)
- return ret;
+ if ((ret = pcidriver_umem_sgunmap(privdata, umem_entry)) != 0)
+ return ret;
- return 0;
+ return 0;
}
/**
@@ -293,35 +278,35 @@ static int ioctl_umem_sgunmap(pcidriver_privdata_t *privdata, unsigned long arg)
*/
static int ioctl_umem_sgget(pcidriver_privdata_t *privdata, unsigned long arg)
{
- int ret;
- READ_FROM_USER(umem_sglist_t, usglist);
+ int ret;
+ READ_FROM_USER(umem_sglist_t, usglist);
- /* The umem_sglist_t has a pointer to the scatter/gather list itself which
- * needs to be copied separately. The number of elements is stored in ->nents.
- * As the list can get very big, we need to use vmalloc. */
- if ((usglist.sg = vmalloc(usglist.nents * sizeof(umem_sgentry_t))) == NULL)
- return -ENOMEM;
+ /* The umem_sglist_t has a pointer to the scatter/gather list itself which
+ * needs to be copied separately. The number of elements is stored in ->nents.
+ * As the list can get very big, we need to use vmalloc. */
+ if ((usglist.sg = vmalloc(usglist.nents * sizeof(umem_sgentry_t))) == NULL)
+ return -ENOMEM;
- /* copy array to kernel structure */
- ret = copy_from_user(usglist.sg, ((umem_sglist_t *)arg)->sg, (usglist.nents)*sizeof(umem_sgentry_t));
- if (ret) return -EFAULT;
+ /* copy array to kernel structure */
+ ret = copy_from_user(usglist.sg, ((umem_sglist_t *)arg)->sg, (usglist.nents)*sizeof(umem_sgentry_t));
+ if (ret) return -EFAULT;
- if ((ret = pcidriver_umem_sgget(privdata, &usglist)) != 0)
- return ret;
+ if ((ret = pcidriver_umem_sgget(privdata, &usglist)) != 0)
+ return ret;
- /* write data to user space */
- ret = copy_to_user(((umem_sglist_t *)arg)->sg, usglist.sg, (usglist.nents)*sizeof(umem_sgentry_t));
- if (ret) return -EFAULT;
+ /* write data to user space */
+ ret = copy_to_user(((umem_sglist_t *)arg)->sg, usglist.sg, (usglist.nents)*sizeof(umem_sgentry_t));
+ if (ret) return -EFAULT;
- /* free array memory */
- vfree(usglist.sg);
+ /* free array memory */
+ vfree(usglist.sg);
- /* restore sg pointer to vma address in user space before copying */
- usglist.sg = ((umem_sglist_t *)arg)->sg;
+ /* restore sg pointer to vma address in user space before copying */
+ usglist.sg = ((umem_sglist_t *)arg)->sg;
- WRITE_TO_USER(umem_sglist_t, usglist);
+ WRITE_TO_USER(umem_sglist_t, usglist);
- return 0;
+ return 0;
}
/**
@@ -333,10 +318,10 @@ static int ioctl_umem_sgget(pcidriver_privdata_t *privdata, unsigned long arg)
*/
static int ioctl_umem_sync(pcidriver_privdata_t *privdata, unsigned long arg)
{
- int ret;
- READ_FROM_USER(umem_handle_t, uhandle);
+ int ret;
+ READ_FROM_USER(umem_handle_t, uhandle);
- return pcidriver_umem_sync( privdata, &uhandle );
+ return pcidriver_umem_sync( privdata, &uhandle );
}
/**
@@ -349,47 +334,47 @@ static int ioctl_umem_sync(pcidriver_privdata_t *privdata, unsigned long arg)
static int ioctl_wait_interrupt(pcidriver_privdata_t *privdata, unsigned long arg)
{
#ifdef ENABLE_IRQ
- int ret;
- unsigned long timeout;
- unsigned int irq_source;
- unsigned long temp = 0;
+ int ret;
+ unsigned long timeout;
+ unsigned int irq_source;
+ unsigned long temp = 0;
- READ_FROM_USER(interrupt_wait_t, irq_handle);
+ READ_FROM_USER(interrupt_wait_t, irq_handle);
- irq_source = irq_handle.source;
+ irq_source = irq_handle.source;
- if (irq_source >= PCIDRIVER_INT_MAXSOURCES)
- return -EFAULT; /* User tried to overrun the IRQ_SOURCES array */
+ if (irq_source >= PCIDRIVER_INT_MAXSOURCES)
+ return -EFAULT; /* User tried to overrun the IRQ_SOURCES array */
- timeout = jiffies + (irq_handle.timeout * HZ / 1000000);
+ timeout = jiffies + (irq_handle.timeout * HZ / 1000000);
- /* Thanks to Joern for the correction and tips! */
- /* done this way to avoid wrong behaviour (endless loop) of the compiler in AMD platforms */
- do {
- /* We wait here with an interruptible timeout. This will be interrupted
+ /* Thanks to Joern for the correction and tips! */
+ /* done this way to avoid wrong behaviour (endless loop) of the compiler in AMD platforms */
+ do {
+ /* We wait here with an interruptible timeout. This will be interrupted
* by int.c:check_acknowledge_channel() as soon as in interrupt for
* the specified source arrives. */
- wait_event_interruptible_timeout( (privdata->irq_queues[irq_source]), (atomic_read(&(privdata->irq_outstanding[irq_source])) > 0), (10*HZ/1000) );
-
- if (atomic_add_negative( -1, &(privdata->irq_outstanding[irq_source])) )
- atomic_inc( &(privdata->irq_outstanding[irq_source]) );
- else
- temp = 1;
- } while ((!temp)&&(jiffies < timeout));
-
- if ((temp)&&(irq_handle.count)) {
- while (!atomic_add_negative( -1, &(privdata->irq_outstanding[irq_source]))) temp++;
- atomic_inc( &(privdata->irq_outstanding[irq_source]) );
- }
-
- irq_handle.count = temp;
-
- WRITE_TO_USER(interrupt_wait_t, irq_handle);
-
- return 0;
+ wait_event_interruptible_timeout( (privdata->irq_queues[irq_source]), (atomic_read(&(privdata->irq_outstanding[irq_source])) > 0), (10*HZ/1000) );
+
+ if (atomic_add_negative( -1, &(privdata->irq_outstanding[irq_source])) )
+ atomic_inc( &(privdata->irq_outstanding[irq_source]) );
+ else
+ temp = 1;
+ } while ((!temp)&&(jiffies < timeout));
+
+ if ((temp)&&(irq_handle.count)) {
+ while (!atomic_add_negative( -1, &(privdata->irq_outstanding[irq_source]))) temp++;
+ atomic_inc( &(privdata->irq_outstanding[irq_source]) );
+ }
+
+ irq_handle.count = temp;
+
+ WRITE_TO_USER(interrupt_wait_t, irq_handle);
+
+ return 0;
#else
- mod_info("Asked to wait for interrupt but interrupts are not enabled in the driver\n");
- return -EFAULT;
+ mod_info("Asked to wait for interrupt but interrupts are not enabled in the driver\n");
+ return -EFAULT;
#endif
}
@@ -404,18 +389,18 @@ static int ioctl_wait_interrupt(pcidriver_privdata_t *privdata, unsigned long ar
static int ioctl_clear_ioq(pcidriver_privdata_t *privdata, unsigned long arg)
{
#ifdef ENABLE_IRQ
- unsigned int irq_source;
+ unsigned int irq_source;
- if (arg >= PCIDRIVER_INT_MAXSOURCES)
- return -EFAULT;
+ if (arg >= PCIDRIVER_INT_MAXSOURCES)
+ return -EFAULT;
- irq_source = arg;
- atomic_set(&(privdata->irq_outstanding[irq_source]), 0);
+ irq_source = arg;
+ atomic_set(&(privdata->irq_outstanding[irq_source]), 0);
- return 0;
+ return 0;
#else
- mod_info("Asked to wait for interrupt but interrupts are not enabled in the driver\n");
- return -EFAULT;
+ mod_info("Asked to wait for interrupt but interrupts are not enabled in the driver\n");
+ return -EFAULT;
#endif
}
@@ -429,18 +414,18 @@ static int ioctl_clear_ioq(pcidriver_privdata_t *privdata, unsigned long arg)
*/
static int ioctl_version(pcidriver_privdata_t *privdata, unsigned long arg)
{
- int ret;
- pcilib_driver_version_t info;
+ int ret;
+ pcilib_driver_version_t info;
- info = (pcilib_driver_version_t) {
- .version = PCILIB_VERSION,
- .interface = PCIDRIVER_INTERFACE_VERSION,
- .ioctls = PCIDRIVER_IOC_MAX + 1
- };
+ info = (pcilib_driver_version_t) {
+ .version = PCILIB_VERSION,
+ .interface = PCIDRIVER_INTERFACE_VERSION,
+ .ioctls = PCIDRIVER_IOC_MAX + 1
+ };
- WRITE_TO_USER(pcilib_driver_version_t, info);
+ WRITE_TO_USER(pcilib_driver_version_t, info);
- return 0;
+ return 0;
}
/**
@@ -452,24 +437,24 @@ static int ioctl_version(pcidriver_privdata_t *privdata, unsigned long arg)
*/
static int ioctl_device_state(pcidriver_privdata_t *privdata, unsigned long arg)
{
- int ret;
- pcilib_device_state_t info;
+ int ret;
+ pcilib_device_state_t info;
#ifdef PCIDRIVER_DUMMY_DEVICE
- memset(&info, 0, sizeof(info));
+ memset(&info, 0, sizeof(info));
#else /* PCIDRIVER_DUMMY_DEVICE */
- info = (pcilib_device_state_t) {
- .iommu = iommu_present(privdata->pdev->dev.bus),
- .mps = pcidriver_pcie_get_mps(privdata->pdev),
- .readrq = pcie_get_readrq(privdata->pdev),
- .dma_mask = privdata->pdev->dma_mask
- };
+ info = (pcilib_device_state_t) {
+ .iommu = iommu_present(privdata->pdev->dev.bus),
+ .mps = pcidriver_pcie_get_mps(privdata->pdev),
+ .readrq = pcie_get_readrq(privdata->pdev),
+ .dma_mask = privdata->pdev->dma_mask
+ };
#endif /* PCIDRIVER_DUMMY_DEVICE */
- WRITE_TO_USER(pcilib_device_state_t, info);
+ WRITE_TO_USER(pcilib_device_state_t, info);
- return 0;
+ return 0;
}
@@ -483,19 +468,19 @@ static int ioctl_device_state(pcidriver_privdata_t *privdata, unsigned long arg)
static int ioctl_set_dma_mask(pcidriver_privdata_t *privdata, unsigned long arg)
{
#ifndef PCIDRIVER_DUMMY_DEVICE
- int err;
+ int err;
- if ((arg < 24) || (arg > 64))
- return -EINVAL;
+ if ((arg < 24) || (arg > 64))
+ return -EINVAL;
- err = pci_set_dma_mask(privdata->pdev, DMA_BIT_MASK(arg));
- if (err < 0) {
- printk(KERN_ERR "pci_set_dma_mask(%lu) failed\n", arg);
- return err;
- }
+ err = pci_set_dma_mask(privdata->pdev, DMA_BIT_MASK(arg));
+ if (err < 0) {
+ printk(KERN_ERR "pci_set_dma_mask(%lu) failed\n", arg);
+ return err;
+ }
#endif /* ! PCIDRIVER_DUMMY_DEVICE */
-
- return 0;
+
+ return 0;
}
/**
@@ -508,19 +493,19 @@ static int ioctl_set_dma_mask(pcidriver_privdata_t *privdata, unsigned long arg)
static int ioctl_set_mps(pcidriver_privdata_t *privdata, unsigned long arg)
{
#ifndef PCIDRIVER_DUMMY_DEVICE
- int err;
+ int err;
- if ((arg != 128) && (arg != 256) && (arg != 512))
- return -EINVAL;
+ if ((arg != 128) && (arg != 256) && (arg != 512))
+ return -EINVAL;
- err = pcidriver_pcie_set_mps(privdata->pdev, arg);
- if (err < 0) {
- printk(KERN_ERR "pcie_set_mps(%lu) failed\n", arg);
- return err;
- }
+ err = pcidriver_pcie_set_mps(privdata->pdev, arg);
+ if (err < 0) {
+ printk(KERN_ERR "pcie_set_mps(%lu) failed\n", arg);
+ return err;
+ }
#endif /* ! PCIDRIVER_DUMMY_DEVICE */
-
- return 0;
+
+ return 0;
}
@@ -533,69 +518,65 @@ static int ioctl_set_mps(pcidriver_privdata_t *privdata, unsigned long arg)
* @returns -EFAULT when an invalid memory pointer is passed
*
*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
-int pcidriver_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
-#else
long pcidriver_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-#endif
{
- pcidriver_privdata_t *privdata = filp->private_data;
+ pcidriver_privdata_t *privdata = filp->private_data;
+
+ /* Select the appropiate command */
+ switch (cmd) {
+ case PCIDRIVER_IOC_MMAP_MODE:
+ return ioctl_mmap_mode(privdata, arg);
- /* Select the appropiate command */
- switch (cmd) {
- case PCIDRIVER_IOC_MMAP_MODE:
- return ioctl_mmap_mode(privdata, arg);
+ case PCIDRIVER_IOC_MMAP_AREA:
+ return ioctl_mmap_area(privdata, arg);
- case PCIDRIVER_IOC_MMAP_AREA:
- return ioctl_mmap_area(privdata, arg);
+ case PCIDRIVER_IOC_PCI_CFG_RD:
+ case PCIDRIVER_IOC_PCI_CFG_WR:
+ return ioctl_pci_config_read_write(privdata, cmd, arg);
- case PCIDRIVER_IOC_PCI_CFG_RD:
- case PCIDRIVER_IOC_PCI_CFG_WR:
- return ioctl_pci_config_read_write(privdata, cmd, arg);
+ case PCIDRIVER_IOC_PCI_INFO:
+ return ioctl_pci_info(privdata, arg);
- case PCIDRIVER_IOC_PCI_INFO:
- return ioctl_pci_info(privdata, arg);
+ case PCIDRIVER_IOC_KMEM_ALLOC:
+ return ioctl_kmem_alloc(privdata, arg);
- case PCIDRIVER_IOC_KMEM_ALLOC:
- return ioctl_kmem_alloc(privdata, arg);
+ case PCIDRIVER_IOC_KMEM_FREE:
+ return ioctl_kmem_free(privdata, arg);
- case PCIDRIVER_IOC_KMEM_FREE:
- return ioctl_kmem_free(privdata, arg);
+ case PCIDRIVER_IOC_KMEM_SYNC:
+ return ioctl_kmem_sync(privdata, arg);
- case PCIDRIVER_IOC_KMEM_SYNC:
- return ioctl_kmem_sync(privdata, arg);
+ case PCIDRIVER_IOC_UMEM_SGMAP:
+ return ioctl_umem_sgmap(privdata, arg);
- case PCIDRIVER_IOC_UMEM_SGMAP:
- return ioctl_umem_sgmap(privdata, arg);
+ case PCIDRIVER_IOC_UMEM_SGUNMAP:
+ return ioctl_umem_sgunmap(privdata, arg);
- case PCIDRIVER_IOC_UMEM_SGUNMAP:
- return ioctl_umem_sgunmap(privdata, arg);
+ case PCIDRIVER_IOC_UMEM_SGGET:
+ return ioctl_umem_sgget(privdata, arg);
- case PCIDRIVER_IOC_UMEM_SGGET:
- return ioctl_umem_sgget(privdata, arg);
+ case PCIDRIVER_IOC_UMEM_SYNC:
+ return ioctl_umem_sync(privdata, arg);
- case PCIDRIVER_IOC_UMEM_SYNC:
- return ioctl_umem_sync(privdata, arg);
+ case PCIDRIVER_IOC_WAITI:
+ return ioctl_wait_interrupt(privdata, arg);
- case PCIDRIVER_IOC_WAITI:
- return ioctl_wait_interrupt(privdata, arg);
+ case PCIDRIVER_IOC_CLEAR_IOQ:
+ return ioctl_clear_ioq(privdata, arg);
- case PCIDRIVER_IOC_CLEAR_IOQ:
- return ioctl_clear_ioq(privdata, arg);
-
- case PCIDRIVER_IOC_VERSION:
- return ioctl_version(privdata, arg);
+ case PCIDRIVER_IOC_VERSION:
+ return ioctl_version(privdata, arg);
- case PCIDRIVER_IOC_DEVICE_STATE:
- return ioctl_device_state(privdata, arg);
+ case PCIDRIVER_IOC_DEVICE_STATE:
+ return ioctl_device_state(privdata, arg);
- case PCIDRIVER_IOC_DMA_MASK:
- return ioctl_set_dma_mask(privdata, arg);
+ case PCIDRIVER_IOC_DMA_MASK:
+ return ioctl_set_dma_mask(privdata, arg);
- case PCIDRIVER_IOC_MPS:
- return ioctl_set_mps(privdata, arg);
+ case PCIDRIVER_IOC_MPS:
+ return ioctl_set_mps(privdata, arg);
- default:
- return -EINVAL;
- }
+ default:
+ return -EINVAL;
+ }
}
diff --git a/driver/ioctl.h b/driver/ioctl.h
index 696fb8b..a102092 100644
--- a/driver/ioctl.h
+++ b/driver/ioctl.h
@@ -1,5 +1,178 @@
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
-int pcidriver_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
-#else
-long pcidriver_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
-#endif
+#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 9bc1eb7..522f3bc 100644
--- a/driver/kmem.c
+++ b/driver/kmem.c
@@ -17,17 +17,8 @@
#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 */
-
-/* VM_RESERVED is removed in 3.7-rc1 */
-#ifndef VM_RESERVED
-# define VM_RESERVED (VM_DONTEXPAND | VM_DONTDUMP)
-#endif
+#include "base.h"
+
/**
*
@@ -37,270 +28,269 @@
*/
int pcidriver_kmem_alloc(pcidriver_privdata_t *privdata, kmem_handle_t *kmem_handle)
{
- int flags;
- pcidriver_kmem_entry_t *kmem_entry;
- void *retptr;
-
- if (kmem_handle->flags&KMEM_FLAG_REUSE) {
- kmem_entry = pcidriver_kmem_find_entry_use(privdata, kmem_handle->use, kmem_handle->item);
- if (kmem_entry) {
- unsigned long flags = kmem_handle->flags;
-
- if (flags&KMEM_FLAG_TRY) {
- kmem_handle->type = kmem_entry->type;
- kmem_handle->size = kmem_entry->size;
- kmem_handle->align = kmem_entry->align;
- } else {
- if (kmem_handle->type != kmem_entry->type) {
- mod_info("Invalid type of reusable kmem_entry, currently: %lu, but requested: %lu\n", kmem_entry->type, kmem_handle->type);
- kmem_handle->type = kmem_entry->type;
- return -EINVAL;
- }
-
- if (((kmem_handle->type&PCILIB_KMEM_TYPE_MASK) == PCILIB_KMEM_TYPE_PAGE)&&(kmem_handle->size == 0)) {
- kmem_handle->size = kmem_entry->size;
- } else if (kmem_handle->size != kmem_entry->size) {
- mod_info("Invalid size of reusable kmem_entry, currently: %lu, but requested: %lu\n", kmem_entry->size, kmem_handle->size);
- kmem_handle->size = kmem_entry->size;
- return -EINVAL;
- }
-
- if (kmem_handle->align != kmem_entry->align) {
- mod_info("Invalid alignment of reusable kmem_entry, currently: %lu, but requested: %lu\n", kmem_entry->align, kmem_handle->align);
- kmem_handle->align = kmem_entry->align;
- return -EINVAL;
- }
-
- if (((kmem_entry->mode&KMEM_MODE_EXCLUSIVE)?1:0) != ((flags&KMEM_FLAG_EXCLUSIVE)?1:0)) {
- mod_info("Invalid mode of reusable kmem_entry\n");
- kmem_handle->flags = (kmem_entry->mode&KMEM_MODE_EXCLUSIVE)?KMEM_FLAG_EXCLUSIVE:0;
- return -EINVAL;
- }
- }
-
-
- if ((kmem_entry->mode&KMEM_MODE_COUNT)==KMEM_MODE_COUNT) {
- mod_info("Reuse counter of kmem_entry is overflown");
- return -EBUSY;
- }
-
-
- kmem_handle->handle_id = kmem_entry->id;
- kmem_handle->ba = (unsigned long)(kmem_entry->dma_handle);
- kmem_handle->pa = virt_to_phys((void*)kmem_entry->cpua);
-
- kmem_handle->flags = KMEM_FLAG_REUSED;
- if (kmem_entry->refs&KMEM_REF_HW) kmem_handle->flags |= KMEM_FLAG_REUSED_HW;
- if (kmem_entry->mode&KMEM_MODE_PERSISTENT) kmem_handle->flags |= KMEM_FLAG_REUSED_PERSISTENT;
-
- kmem_entry->mode += 1;
- if (flags&KMEM_FLAG_HW) {
- if ((kmem_entry->refs&KMEM_REF_HW)==0)
- pcidriver_module_get(privdata);
-
- kmem_entry->refs |= KMEM_REF_HW;
- }
- if (flags&KMEM_FLAG_PERSISTENT) kmem_entry->mode |= KMEM_MODE_PERSISTENT;
-
- privdata->kmem_cur_id = kmem_entry->id;
-
- return 0;
- }
-
- if (kmem_handle->flags&KMEM_FLAG_TRY) return -ENOENT;
- }
-
- /* First, allocate zeroed memory for the kmem_entry */
- if ((kmem_entry = kcalloc(1, sizeof(pcidriver_kmem_entry_t), GFP_KERNEL)) == NULL)
- goto kmem_alloc_entry_fail;
-
- /* Initialize the kmem_entry */
- kmem_entry->id = atomic_inc_return(&privdata->kmem_count) - 1;
- privdata->kmem_cur_id = kmem_entry->id;
- kmem_handle->handle_id = kmem_entry->id;
-
- kmem_entry->use = kmem_handle->use;
- kmem_entry->item = kmem_handle->item;
- kmem_entry->type = kmem_handle->type;
- kmem_entry->align = kmem_handle->align;
- kmem_entry->direction = PCI_DMA_NONE;
-
- /* Initialize sysfs if possible */
- if (pcidriver_sysfs_initialize_kmem(privdata, kmem_entry->id, &(kmem_entry->sysfs_attr)) != 0)
- goto kmem_alloc_mem_fail;
-
- /* ...and allocate the DMA memory */
- /* note this is a memory pair, referencing the same area: the cpu address (cpua)
- * and the PCI bus address (pa). The CPU and PCI addresses may not be the same.
- * The CPU sees only CPU addresses, while the device sees only PCI addresses.
- * CPU address is used for the mmap (internal to the driver), and
- * PCI address is the address passed to the DMA Controller in the device.
- */
- switch (kmem_entry->type&PCILIB_KMEM_TYPE_MASK) {
- case PCILIB_KMEM_TYPE_CONSISTENT:
+ int flags;
+ pcidriver_kmem_entry_t *kmem_entry;
+ void *retptr;
+
+ if (kmem_handle->flags&KMEM_FLAG_REUSE) {
+ kmem_entry = pcidriver_kmem_find_entry_use(privdata, kmem_handle->use, kmem_handle->item);
+ if (kmem_entry) {
+ unsigned long flags = kmem_handle->flags;
+
+ if (flags&KMEM_FLAG_TRY) {
+ kmem_handle->type = kmem_entry->type;
+ kmem_handle->size = kmem_entry->size;
+ kmem_handle->align = kmem_entry->align;
+ } else {
+ if (kmem_handle->type != kmem_entry->type) {
+ mod_info("Invalid type of reusable kmem_entry, currently: %lu, but requested: %lu\n", kmem_entry->type, kmem_handle->type);
+ kmem_handle->type = kmem_entry->type;
+ return -EINVAL;
+ }
+
+ if (((kmem_handle->type&PCILIB_KMEM_TYPE_MASK) == PCILIB_KMEM_TYPE_PAGE)&&(kmem_handle->size == 0)) {
+ kmem_handle->size = kmem_entry->size;
+ } else if (kmem_handle->size != kmem_entry->size) {
+ mod_info("Invalid size of reusable kmem_entry, currently: %lu, but requested: %lu\n", kmem_entry->size, kmem_handle->size);
+ kmem_handle->size = kmem_entry->size;
+ return -EINVAL;
+ }
+
+ if (kmem_handle->align != kmem_entry->align) {
+ mod_info("Invalid alignment of reusable kmem_entry, currently: %lu, but requested: %lu\n", kmem_entry->align, kmem_handle->align);
+ kmem_handle->align = kmem_entry->align;
+ return -EINVAL;
+ }
+
+ if (((kmem_entry->mode&KMEM_MODE_EXCLUSIVE)?1:0) != ((flags&KMEM_FLAG_EXCLUSIVE)?1:0)) {
+ mod_info("Invalid mode of reusable kmem_entry\n");
+ kmem_handle->flags = (kmem_entry->mode&KMEM_MODE_EXCLUSIVE)?KMEM_FLAG_EXCLUSIVE:0;
+ return -EINVAL;
+ }
+ }
+
+
+ if ((kmem_entry->mode&KMEM_MODE_COUNT)==KMEM_MODE_COUNT) {
+ mod_info("Reuse counter of kmem_entry is overflown");
+ return -EBUSY;
+ }
+
+
+ kmem_handle->handle_id = kmem_entry->id;
+ kmem_handle->ba = (unsigned long)(kmem_entry->dma_handle);
+ kmem_handle->pa = virt_to_phys((void*)kmem_entry->cpua);
+
+ kmem_handle->flags = KMEM_FLAG_REUSED;
+ if (kmem_entry->refs&KMEM_REF_HW) kmem_handle->flags |= KMEM_FLAG_REUSED_HW;
+ if (kmem_entry->mode&KMEM_MODE_PERSISTENT) kmem_handle->flags |= KMEM_FLAG_REUSED_PERSISTENT;
+
+ kmem_entry->mode += 1;
+ if (flags&KMEM_FLAG_HW) {
+ if ((kmem_entry->refs&KMEM_REF_HW)==0)
+ pcidriver_module_get(privdata);
+
+ kmem_entry->refs |= KMEM_REF_HW;
+ }
+ if (flags&KMEM_FLAG_PERSISTENT) kmem_entry->mode |= KMEM_MODE_PERSISTENT;
+
+ privdata->kmem_cur_id = kmem_entry->id;
+
+ return 0;
+ }
+
+ if (kmem_handle->flags&KMEM_FLAG_TRY) return -ENOENT;
+ }
+
+ /* First, allocate zeroed memory for the kmem_entry */
+ if ((kmem_entry = kcalloc(1, sizeof(pcidriver_kmem_entry_t), GFP_KERNEL)) == NULL)
+ goto kmem_alloc_entry_fail;
+
+ /* Initialize the kmem_entry */
+ kmem_entry->id = atomic_inc_return(&privdata->kmem_count) - 1;
+ privdata->kmem_cur_id = kmem_entry->id;
+ kmem_handle->handle_id = kmem_entry->id;
+
+ kmem_entry->use = kmem_handle->use;
+ kmem_entry->item = kmem_handle->item;
+ kmem_entry->type = kmem_handle->type;
+ kmem_entry->align = kmem_handle->align;
+ kmem_entry->direction = PCI_DMA_NONE;
+
+ /* Initialize sysfs if possible */
+ if (pcidriver_sysfs_initialize_kmem(privdata, kmem_entry->id, &(kmem_entry->sysfs_attr)) != 0)
+ goto kmem_alloc_mem_fail;
+
+ /* ...and allocate the DMA memory */
+ /* note this is a memory pair, referencing the same area: the cpu address (cpua)
+ * and the PCI bus address (pa). The CPU and PCI addresses may not be the same.
+ * The CPU sees only CPU addresses, while the device sees only PCI addresses.
+ * CPU address is used for the mmap (internal to the driver), and
+ * PCI address is the address passed to the DMA Controller in the device.
+ */
+ switch (kmem_entry->type&PCILIB_KMEM_TYPE_MASK) {
+ case PCILIB_KMEM_TYPE_CONSISTENT:
#ifdef PCIDRIVER_DUMMY_DEVICE
- retptr = kmalloc( kmem_handle->size, GFP_KERNEL);
+ retptr = kmalloc( kmem_handle->size, GFP_KERNEL);
#else /* PCIDRIVER_DUMMY_DEVICE */
- retptr = pci_alloc_consistent( privdata->pdev, kmem_handle->size, &(kmem_entry->dma_handle) );
+ retptr = pci_alloc_consistent( privdata->pdev, kmem_handle->size, &(kmem_entry->dma_handle) );
#endif /* PCIDRIVER_DUMMY_DEVICE */
- break;
- case PCILIB_KMEM_TYPE_REGION:
- retptr = ioremap(kmem_handle->pa, kmem_handle->size);
- kmem_entry->dma_handle = kmem_handle->pa;
- if (kmem_entry->type == PCILIB_KMEM_TYPE_REGION_S2C) {
- kmem_entry->direction = PCI_DMA_TODEVICE;
- } else if (kmem_entry->type == PCILIB_KMEM_TYPE_REGION_C2S) {
- kmem_entry->direction = PCI_DMA_FROMDEVICE;
- }
- break;
- case PCILIB_KMEM_TYPE_PAGE:
- flags = GFP_KERNEL;
-
- if (kmem_handle->size == 0)
- kmem_handle->size = PAGE_SIZE;
- else if (kmem_handle->size%PAGE_SIZE)
- goto kmem_alloc_mem_fail;
- else
- flags |= __GFP_COMP;
-
- retptr = (void*)__get_free_pages(flags, get_order(kmem_handle->size));
- kmem_entry->dma_handle = 0;
-
- if (retptr) {
+ break;
+ case PCILIB_KMEM_TYPE_REGION:
+ retptr = ioremap(kmem_handle->pa, kmem_handle->size);
+ kmem_entry->dma_handle = kmem_handle->pa;
+ if (kmem_entry->type == PCILIB_KMEM_TYPE_REGION_S2C) {
+ kmem_entry->direction = PCI_DMA_TODEVICE;
+ } else if (kmem_entry->type == PCILIB_KMEM_TYPE_REGION_C2S) {
+ kmem_entry->direction = PCI_DMA_FROMDEVICE;
+ }
+ break;
+ case PCILIB_KMEM_TYPE_PAGE:
+ flags = GFP_KERNEL;
+
+ if (kmem_handle->size == 0)
+ kmem_handle->size = PAGE_SIZE;
+ else if (kmem_handle->size%PAGE_SIZE)
+ goto kmem_alloc_mem_fail;
+ else
+ flags |= __GFP_COMP;
+
+ retptr = (void*)__get_free_pages(flags, get_order(kmem_handle->size));
+ kmem_entry->dma_handle = 0;
+
+ if (retptr) {
#ifndef PCIDRIVER_DUMMY_DEVICE
- if (kmem_entry->type == PCILIB_KMEM_TYPE_DMA_S2C_PAGE) {
- kmem_entry->direction = PCI_DMA_TODEVICE;
- kmem_entry->dma_handle = pci_map_single(privdata->pdev, retptr, kmem_handle->size, PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(privdata->pdev, kmem_entry->dma_handle)) {
- free_pages((unsigned long)retptr, get_order(kmem_handle->size));
- goto kmem_alloc_mem_fail;
- }
- } else if (kmem_entry->type == PCILIB_KMEM_TYPE_DMA_C2S_PAGE) {
- kmem_entry->direction = PCI_DMA_FROMDEVICE;
- kmem_entry->dma_handle = pci_map_single(privdata->pdev, retptr, kmem_handle->size, PCI_DMA_FROMDEVICE);
- if (pci_dma_mapping_error(privdata->pdev, kmem_entry->dma_handle)) {
- free_pages((unsigned long)retptr, get_order(kmem_handle->size));
- goto kmem_alloc_mem_fail;
-
- }
- }
+ if (kmem_entry->type == PCILIB_KMEM_TYPE_DMA_S2C_PAGE) {
+ kmem_entry->direction = PCI_DMA_TODEVICE;
+ kmem_entry->dma_handle = pci_map_single(privdata->pdev, retptr, kmem_handle->size, PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(privdata->pdev, kmem_entry->dma_handle)) {
+ free_pages((unsigned long)retptr, get_order(kmem_handle->size));
+ goto kmem_alloc_mem_fail;
+ }
+ } else if (kmem_entry->type == PCILIB_KMEM_TYPE_DMA_C2S_PAGE) {
+ kmem_entry->direction = PCI_DMA_FROMDEVICE;
+ kmem_entry->dma_handle = pci_map_single(privdata->pdev, retptr, kmem_handle->size, PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(privdata->pdev, kmem_entry->dma_handle)) {
+ free_pages((unsigned long)retptr, get_order(kmem_handle->size));
+ goto kmem_alloc_mem_fail;
+
+ }
+ }
#endif /* ! PCIDRIVER_DUMMY_DEVICE */
- }
-
- break;
- default:
- goto kmem_alloc_mem_fail;
- }
-
-
- if (retptr == NULL)
- goto kmem_alloc_mem_fail;
-
- kmem_entry->size = kmem_handle->size;
- kmem_entry->cpua = (unsigned long)retptr;
- kmem_handle->ba = (unsigned long)(kmem_entry->dma_handle);
- kmem_handle->pa = virt_to_phys(retptr);
-
- kmem_entry->mode = 1;
- if (kmem_handle->flags&KMEM_FLAG_REUSE) {
- kmem_entry->mode |= KMEM_MODE_REUSABLE;
- if (kmem_handle->flags&KMEM_FLAG_EXCLUSIVE) kmem_entry->mode |= KMEM_MODE_EXCLUSIVE;
- if (kmem_handle->flags&KMEM_FLAG_PERSISTENT) kmem_entry->mode |= KMEM_MODE_PERSISTENT;
- }
-
- kmem_entry->refs = 0;
- if (kmem_handle->flags&KMEM_FLAG_HW) {
- pcidriver_module_get(privdata);
-
- kmem_entry->refs |= KMEM_REF_HW;
- }
-
- kmem_handle->flags = 0;
-
- set_pages_reserved_compat(kmem_entry->cpua, kmem_entry->size);
-
- /* Add the kmem_entry to the list of the device */
- spin_lock( &(privdata->kmemlist_lock) );
- list_add_tail( &(kmem_entry->list), &(privdata->kmem_list) );
- spin_unlock( &(privdata->kmemlist_lock) );
-
- return 0;
+ }
+
+ break;
+ default:
+ goto kmem_alloc_mem_fail;
+ }
+
+
+ if (retptr == NULL)
+ goto kmem_alloc_mem_fail;
+
+ kmem_entry->size = kmem_handle->size;
+ kmem_entry->cpua = (unsigned long)retptr;
+ kmem_handle->ba = (unsigned long)(kmem_entry->dma_handle);
+ kmem_handle->pa = virt_to_phys(retptr);
+
+ kmem_entry->mode = 1;
+ if (kmem_handle->flags&KMEM_FLAG_REUSE) {
+ kmem_entry->mode |= KMEM_MODE_REUSABLE;
+ if (kmem_handle->flags&KMEM_FLAG_EXCLUSIVE) kmem_entry->mode |= KMEM_MODE_EXCLUSIVE;
+ if (kmem_handle->flags&KMEM_FLAG_PERSISTENT) kmem_entry->mode |= KMEM_MODE_PERSISTENT;
+ }
+
+ kmem_entry->refs = 0;
+ if (kmem_handle->flags&KMEM_FLAG_HW) {
+ pcidriver_module_get(privdata);
+
+ kmem_entry->refs |= KMEM_REF_HW;
+ }
+
+ kmem_handle->flags = 0;
+
+ /* Add the kmem_entry to the list of the device */
+ spin_lock( &(privdata->kmemlist_lock) );
+ list_add_tail( &(kmem_entry->list), &(privdata->kmem_list) );
+ spin_unlock( &(privdata->kmemlist_lock) );
+
+ return 0;
kmem_alloc_mem_fail:
- kfree(kmem_entry);
+ kfree(kmem_entry);
kmem_alloc_entry_fail:
- return -ENOMEM;
+ return -ENOMEM;
}
static int pcidriver_kmem_free_check(pcidriver_privdata_t *privdata, kmem_handle_t *kmem_handle, pcidriver_kmem_entry_t *kmem_entry) {
- if ((kmem_handle->flags & KMEM_FLAG_FORCE) == 0) {
- if (kmem_entry->mode&KMEM_MODE_COUNT)
- kmem_entry->mode -= 1;
-
- if (kmem_handle->flags&KMEM_FLAG_HW) {
- if (kmem_entry->refs&KMEM_REF_HW)
- pcidriver_module_put(privdata);
-
- kmem_entry->refs &= ~KMEM_REF_HW;
- }
-
- if (kmem_handle->flags&KMEM_FLAG_PERSISTENT)
- kmem_entry->mode &= ~KMEM_MODE_PERSISTENT;
-
- if (kmem_handle->flags&KMEM_FLAG_REUSE)
- return 0;
-
- if (kmem_entry->refs) {
- kmem_entry->mode += 1;
- mod_info("can't free referenced kmem_entry, refs = %lx\n", kmem_entry->refs);
- return -EBUSY;
- }
-
- if (kmem_entry->mode & KMEM_MODE_PERSISTENT) {
- kmem_entry->mode += 1;
- mod_info("can't free persistent kmem_entry\n");
- return -EBUSY;
- }
-
- if (((kmem_entry->mode&KMEM_MODE_EXCLUSIVE)==0)&&(kmem_entry->mode&KMEM_MODE_COUNT)&&((kmem_handle->flags&KMEM_FLAG_EXCLUSIVE)==0))
- return 0;
- } else {
- if (kmem_entry->refs&KMEM_REF_HW)
- pcidriver_module_put(privdata);
-
- while (!atomic_add_negative(-1, &(privdata->refs))) pcidriver_module_put(privdata);
- atomic_inc(&(privdata->refs));
-
- }
-
- return 1;
+ if ((kmem_handle->flags & KMEM_FLAG_FORCE) == 0) {
+ if (kmem_entry->mode&KMEM_MODE_COUNT)
+ kmem_entry->mode -= 1;
+
+ if (kmem_handle->flags&KMEM_FLAG_HW) {
+ if (kmem_entry->refs&KMEM_REF_HW)
+ pcidriver_module_put(privdata);
+
+ kmem_entry->refs &= ~KMEM_REF_HW;
+ }
+
+ if (kmem_handle->flags&KMEM_FLAG_PERSISTENT)
+ kmem_entry->mode &= ~KMEM_MODE_PERSISTENT;
+
+ if (kmem_handle->flags&KMEM_FLAG_REUSE)
+ return 0;
+
+ if (((kmem_entry->mode&KMEM_MODE_EXCLUSIVE)==0)&&(kmem_entry->mode&KMEM_MODE_COUNT)&&((kmem_handle->flags&KMEM_FLAG_EXCLUSIVE)==0))
+ return 0;
+
+ if (kmem_entry->refs) {
+ kmem_entry->mode += 1;
+ mod_info("can't free referenced kmem_entry, refs = %lx\n", kmem_entry->refs);
+ return -EBUSY;
+ }
+
+ if (kmem_entry->mode & KMEM_MODE_PERSISTENT) {
+ kmem_entry->mode += 1;
+ mod_info("can't free persistent kmem_entry\n");
+ return -EBUSY;
+ }
+
+ } else {
+ if (kmem_entry->refs&KMEM_REF_HW)
+ pcidriver_module_put(privdata);
+
+ while (!atomic_add_negative(-1, &(privdata->refs))) pcidriver_module_put(privdata);
+ atomic_inc(&(privdata->refs));
+
+ }
+
+ return 1;
}
static int pcidriver_kmem_free_use(pcidriver_privdata_t *privdata, kmem_handle_t *kmem_handle)
{
- int err;
- int failed = 0;
- struct list_head *ptr, *next;
- pcidriver_kmem_entry_t *kmem_entry;
-
- /* iterate safely over the entries and delete them */
- list_for_each_safe(ptr, next, &(privdata->kmem_list)) {
- kmem_entry = list_entry(ptr, pcidriver_kmem_entry_t, list);
- if (kmem_entry->use == kmem_handle->use) {
- err = pcidriver_kmem_free_check(privdata, kmem_handle, kmem_entry);
- if (err > 0)
- pcidriver_kmem_free_entry(privdata, kmem_entry); /* spin lock inside! */
- else
- failed = 1;
- }
- }
-
- if (failed) {
- mod_info("Some kmem_entries for use %lx are still referenced\n", kmem_handle->use);
- return -EBUSY;
- }
-
- return 0;
+ int err;
+ int failed = 0;
+ struct list_head *ptr, *next;
+ pcidriver_kmem_entry_t *kmem_entry;
+
+ /* iterate safely over the entries and delete them */
+ list_for_each_safe(ptr, next, &(privdata->kmem_list)) {
+ kmem_entry = list_entry(ptr, pcidriver_kmem_entry_t, list);
+ if (kmem_entry->use == kmem_handle->use) {
+ err = pcidriver_kmem_free_check(privdata, kmem_handle, kmem_entry);
+ if (err > 0)
+ pcidriver_kmem_free_entry(privdata, kmem_entry); /* spin lock inside! */
+ else
+ failed = 1;
+ }
+ }
+
+ if (failed) {
+ mod_info("Some kmem_entries for use %lx are still referenced\n", kmem_handle->use);
+ return -EBUSY;
+ }
+
+ return 0;
}
/**
@@ -310,24 +300,24 @@ static int pcidriver_kmem_free_use(pcidriver_privdata_t *privdata, kmem_handle_t
*/
int pcidriver_kmem_free( pcidriver_privdata_t *privdata, kmem_handle_t *kmem_handle )
{
- int err;
- pcidriver_kmem_entry_t *kmem_entry;
-
- if (kmem_handle->flags&KMEM_FLAG_MASS) {
- kmem_handle->flags &= ~KMEM_FLAG_MASS;
- return pcidriver_kmem_free_use(privdata, kmem_handle);
- }
-
- /* Find the associated kmem_entry for this buffer */
- if ((kmem_entry = pcidriver_kmem_find_entry(privdata, kmem_handle)) == NULL)
- return -EINVAL; /* kmem_handle is not valid */
-
- err = pcidriver_kmem_free_check(privdata, kmem_handle, kmem_entry);
-
- if (err > 0)
- return pcidriver_kmem_free_entry(privdata, kmem_entry);
-
- return err;
+ int err;
+ pcidriver_kmem_entry_t *kmem_entry;
+
+ if (kmem_handle->flags&KMEM_FLAG_MASS) {
+ kmem_handle->flags &= ~KMEM_FLAG_MASS;
+ return pcidriver_kmem_free_use(privdata, kmem_handle);
+ }
+
+ /* Find the associated kmem_entry for this buffer */
+ if ((kmem_entry = pcidriver_kmem_find_entry(privdata, kmem_handle)) == NULL)
+ return -EINVAL; /* kmem_handle is not valid */
+
+ err = pcidriver_kmem_free_check(privdata, kmem_handle, kmem_entry);
+
+ if (err > 0)
+ return pcidriver_kmem_free_entry(privdata, kmem_entry);
+
+ return err;
}
/**
@@ -338,24 +328,24 @@ int pcidriver_kmem_free( pcidriver_privdata_t *privdata, kmem_handle_t *kmem_han
int pcidriver_kmem_free_all(pcidriver_privdata_t *privdata)
{
// int failed = 0;
- struct list_head *ptr, *next;
- pcidriver_kmem_entry_t *kmem_entry;
-
- /* iterate safely over the entries and delete them */
- list_for_each_safe(ptr, next, &(privdata->kmem_list)) {
- kmem_entry = list_entry(ptr, pcidriver_kmem_entry_t, list);
- /*if (kmem_entry->refs)
- failed = 1;
- else*/
- pcidriver_kmem_free_entry(privdata, kmem_entry); /* spin lock inside! */
- }
-/*
- if (failed) {
- mod_info("Some kmem_entries are still referenced\n");
- return -EBUSY;
- }
-*/
- return 0;
+ struct list_head *ptr, *next;
+ pcidriver_kmem_entry_t *kmem_entry;
+
+ /* iterate safely over the entries and delete them */
+ list_for_each_safe(ptr, next, &(privdata->kmem_list)) {
+ kmem_entry = list_entry(ptr, pcidriver_kmem_entry_t, list);
+ /*if (kmem_entry->refs)
+ failed = 1;
+ else*/
+ pcidriver_kmem_free_entry(privdata, kmem_entry); /* spin lock inside! */
+ }
+ /*
+ if (failed) {
+ mod_info("Some kmem_entries are still referenced\n");
+ return -EBUSY;
+ }
+ */
+ return 0;
}
@@ -366,43 +356,27 @@ int pcidriver_kmem_free_all(pcidriver_privdata_t *privdata)
*/
int pcidriver_kmem_sync_entry( pcidriver_privdata_t *privdata, pcidriver_kmem_entry_t *kmem_entry, int direction)
{
- if (kmem_entry->direction == PCI_DMA_NONE)
- return -EINVAL;
+ if (kmem_entry->direction == PCI_DMA_NONE)
+ return -EINVAL;
#ifndef PCIDRIVER_DUMMY_DEVICE
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
- switch (direction) {
- case PCILIB_KMEM_SYNC_TODEVICE:
- pci_dma_sync_single_for_device( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, kmem_entry->direction );
- break;
- case PCILIB_KMEM_SYNC_FROMDEVICE:
- pci_dma_sync_single_for_cpu( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, kmem_entry->direction );
- break;
- case PCILIB_KMEM_SYNC_BIDIRECTIONAL:
- pci_dma_sync_single_for_device( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, kmem_entry->direction );
- pci_dma_sync_single_for_cpu( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, kmem_entry->direction );
- break;
- default:
- return -EINVAL; /* wrong direction parameter */
- }
-#else
- switch (direction) {
- case PCILIB_KMEM_SYNC_TODEVICE:
- pci_dma_sync_single( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, kmem_entry->direction );
- break;
- case PCILIB_KMEM_SYNC_FROMDEVICE:
- pci_dma_sync_single( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, kmem_entry->direction );
- break;
- case PCILIB_KMEM_SYNC_BIDIRECTIONAL:
- pci_dma_sync_single( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, kmem_entry->direction );
- break;
- default:
- return -EINVAL; /* wrong direction parameter */
- }
-#endif
+ switch (direction) {
+ case PCILIB_KMEM_SYNC_TODEVICE:
+ pci_dma_sync_single_for_device( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, kmem_entry->direction );
+ break;
+ case PCILIB_KMEM_SYNC_FROMDEVICE:
+ pci_dma_sync_single_for_cpu( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, kmem_entry->direction );
+ break;
+ case PCILIB_KMEM_SYNC_BIDIRECTIONAL:
+ pci_dma_sync_single_for_device( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, kmem_entry->direction );
+ pci_dma_sync_single_for_cpu( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, kmem_entry->direction );
+ break;
+ default:
+ return -EINVAL; /* wrong direction parameter */
+ }
#endif /* ! PCIDRIVER_DUMMY_DEVICE */
- return 0; /* success */
+ return 0; /* success */
}
/**
@@ -412,41 +386,41 @@ int pcidriver_kmem_sync_entry( pcidriver_privdata_t *privdata, pcidriver_kmem_en
*/
int pcidriver_kmem_sync( pcidriver_privdata_t *privdata, kmem_sync_t *kmem_sync )
{
- pcidriver_kmem_entry_t *kmem_entry = NULL;
-
- /*
- * This is a shortcut to quickly find a next item in big multi-page kernel buffers
- */
- spin_lock(&(privdata->kmemlist_lock));
- if (privdata->kmem_last_sync) {
- if (privdata->kmem_last_sync->id == kmem_sync->handle.handle_id)
- kmem_entry = privdata->kmem_last_sync;
- else {
- privdata->kmem_last_sync = container_of(privdata->kmem_last_sync->list.next, pcidriver_kmem_entry_t, list);
-
- if (privdata->kmem_last_sync) {
- if (privdata->kmem_last_sync->id == kmem_sync->handle.handle_id)
- kmem_entry = privdata->kmem_last_sync;
- else
- privdata->kmem_last_sync = NULL;
- }
- }
- }
- spin_unlock(&(privdata->kmemlist_lock));
-
- /*
- * If not found go the standard way
- */
- if (!kmem_entry) {
- if ((kmem_entry = pcidriver_kmem_find_entry(privdata, &(kmem_sync->handle))) == NULL)
- return -EINVAL; /* kmem_handle is not valid */
-
- spin_lock(&(privdata->kmemlist_lock));
- privdata->kmem_last_sync = kmem_entry;
- spin_unlock(&(privdata->kmemlist_lock));
- }
-
- return pcidriver_kmem_sync_entry(privdata, kmem_entry, kmem_sync->dir);
+ pcidriver_kmem_entry_t *kmem_entry = NULL;
+
+ /*
+ * This is a shortcut to quickly find a next item in big multi-page kernel buffers
+ */
+ spin_lock(&(privdata->kmemlist_lock));
+ if (privdata->kmem_last_sync) {
+ if (privdata->kmem_last_sync->id == kmem_sync->handle.handle_id)
+ kmem_entry = privdata->kmem_last_sync;
+ else {
+ privdata->kmem_last_sync = container_of(privdata->kmem_last_sync->list.next, pcidriver_kmem_entry_t, list);
+
+ if (privdata->kmem_last_sync) {
+ if (privdata->kmem_last_sync->id == kmem_sync->handle.handle_id)
+ kmem_entry = privdata->kmem_last_sync;
+ else
+ privdata->kmem_last_sync = NULL;
+ }
+ }
+ }
+ spin_unlock(&(privdata->kmemlist_lock));
+
+ /*
+ * If not found go the standard way
+ */
+ if (!kmem_entry) {
+ if ((kmem_entry = pcidriver_kmem_find_entry(privdata, &(kmem_sync->handle))) == NULL)
+ return -EINVAL; /* kmem_handle is not valid */
+
+ spin_lock(&(privdata->kmemlist_lock));
+ privdata->kmem_last_sync = kmem_entry;
+ spin_unlock(&(privdata->kmemlist_lock));
+ }
+
+ return pcidriver_kmem_sync_entry(privdata, kmem_entry, kmem_sync->dir);
}
/**
@@ -456,75 +430,46 @@ int pcidriver_kmem_sync( pcidriver_privdata_t *privdata, kmem_sync_t *kmem_sync
*/
int pcidriver_kmem_free_entry(pcidriver_privdata_t *privdata, pcidriver_kmem_entry_t *kmem_entry)
{
- pcidriver_sysfs_remove(privdata, &(kmem_entry->sysfs_attr));
-
- /* Go over the pages of the kmem buffer, and mark them as not reserved */
-#if 0
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
- /*
- * This code is DISABLED.
- * Apparently, it is not needed to unreserve them. Doing so here
- * hangs the machine. Why?
- *
- * Uhm.. see links:
- *
- * http://lwn.net/Articles/161204/
- * http://lists.openfabrics.org/pipermail/general/2007-March/034101.html
- *
- * I insist, this should be enabled, but doing so hangs the machine.
- * Literature supports the point, and there is even a similar problem (see link)
- * But this is not the case. It seems right to me. but obviously is not.
- *
- * Anyway, this goes away in kernel >=2.6.15.
- */
- unsigned long start = __pa(kmem_entry->cpua) >> PAGE_SHIFT;
- unsigned long end = __pa(kmem_entry->cpua + kmem_entry->size) >> PAGE_SHIFT;
- unsigned long i;
- for(i=start;i<end;i++) {
- struct page *kpage = pfn_to_page(i);
- ClearPageReserved(kpage);
- }
-#endif
-#endif
-
- /* Release DMA memory */
- switch (kmem_entry->type&PCILIB_KMEM_TYPE_MASK) {
- case PCILIB_KMEM_TYPE_CONSISTENT:
+ pcidriver_sysfs_remove(privdata, &(kmem_entry->sysfs_attr));
+
+ /* Release DMA memory */
+ switch (kmem_entry->type&PCILIB_KMEM_TYPE_MASK) {
+ case PCILIB_KMEM_TYPE_CONSISTENT:
#ifdef PCIDRIVER_DUMMY_DEVICE
- kfree((void*)(kmem_entry->cpua));
+ kfree((void*)(kmem_entry->cpua));
#else /* PCIDRIVER_DUMMY_DEVICE */
- pci_free_consistent( privdata->pdev, kmem_entry->size, (void *)(kmem_entry->cpua), kmem_entry->dma_handle );
+ pci_free_consistent( privdata->pdev, kmem_entry->size, (void *)(kmem_entry->cpua), kmem_entry->dma_handle );
#endif /* PCIDRIVER_DUMMY_DEVICE */
- break;
- case PCILIB_KMEM_TYPE_REGION:
- iounmap((void *)(kmem_entry->cpua));
- break;
- case PCILIB_KMEM_TYPE_PAGE:
+ break;
+ case PCILIB_KMEM_TYPE_REGION:
+ iounmap((void *)(kmem_entry->cpua));
+ break;
+ case PCILIB_KMEM_TYPE_PAGE:
#ifndef PCIDRIVER_DUMMY_DEVICE
- if (kmem_entry->dma_handle) {
- if (kmem_entry->type == PCILIB_KMEM_TYPE_DMA_S2C_PAGE) {
- pci_unmap_single(privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_TODEVICE);
- } else if (kmem_entry->type == PCILIB_KMEM_TYPE_DMA_C2S_PAGE) {
- pci_unmap_single(privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_FROMDEVICE);
- }
- }
+ if (kmem_entry->dma_handle) {
+ if (kmem_entry->type == PCILIB_KMEM_TYPE_DMA_S2C_PAGE) {
+ pci_unmap_single(privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_TODEVICE);
+ } else if (kmem_entry->type == PCILIB_KMEM_TYPE_DMA_C2S_PAGE) {
+ pci_unmap_single(privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_FROMDEVICE);
+ }
+ }
#endif /* ! PCIDRIVER_DUMMY_DEVICE */
- free_pages((unsigned long)kmem_entry->cpua, get_order(kmem_entry->size));
- break;
- }
+ free_pages((unsigned long)kmem_entry->cpua, get_order(kmem_entry->size));
+ break;
+ }
- /* Remove the kmem list entry */
- spin_lock( &(privdata->kmemlist_lock) );
- if (privdata->kmem_last_sync == kmem_entry)
- privdata->kmem_last_sync = NULL;
- list_del( &(kmem_entry->list) );
- spin_unlock( &(privdata->kmemlist_lock) );
+ /* Remove the kmem list entry */
+ spin_lock( &(privdata->kmemlist_lock) );
+ if (privdata->kmem_last_sync == kmem_entry)
+ privdata->kmem_last_sync = NULL;
+ list_del( &(kmem_entry->list) );
+ spin_unlock( &(privdata->kmemlist_lock) );
- /* Release kmem_entry memory */
- kfree(kmem_entry);
+ /* Release kmem_entry memory */
+ kfree(kmem_entry);
- return 0;
+ return 0;
}
/**
@@ -534,23 +479,23 @@ int pcidriver_kmem_free_entry(pcidriver_privdata_t *privdata, pcidriver_kmem_ent
*/
pcidriver_kmem_entry_t *pcidriver_kmem_find_entry(pcidriver_privdata_t *privdata, kmem_handle_t *kmem_handle)
{
- struct list_head *ptr;
- pcidriver_kmem_entry_t *entry, *result = NULL;
+ struct list_head *ptr;
+ pcidriver_kmem_entry_t *entry, *result = NULL;
- /* should I implement it better using the handle_id? */
+ /* should I implement it better using the handle_id? */
- spin_lock(&(privdata->kmemlist_lock));
- list_for_each(ptr, &(privdata->kmem_list)) {
- entry = list_entry(ptr, pcidriver_kmem_entry_t, list);
+ spin_lock(&(privdata->kmemlist_lock));
+ list_for_each(ptr, &(privdata->kmem_list)) {
+ entry = list_entry(ptr, pcidriver_kmem_entry_t, list);
- if (entry->id == kmem_handle->handle_id) {
- result = entry;
- break;
- }
- }
+ if (entry->id == kmem_handle->handle_id) {
+ result = entry;
+ break;
+ }
+ }
- spin_unlock(&(privdata->kmemlist_lock));
- return result;
+ spin_unlock(&(privdata->kmemlist_lock));
+ return result;
}
/**
@@ -560,21 +505,21 @@ pcidriver_kmem_entry_t *pcidriver_kmem_find_entry(pcidriver_privdata_t *privdata
*/
pcidriver_kmem_entry_t *pcidriver_kmem_find_entry_id(pcidriver_privdata_t *privdata, int id)
{
- struct list_head *ptr;
- pcidriver_kmem_entry_t *entry, *result = NULL;
+ struct list_head *ptr;
+ pcidriver_kmem_entry_t *entry, *result = NULL;
- spin_lock(&(privdata->kmemlist_lock));
- list_for_each(ptr, &(privdata->kmem_list)) {
- entry = list_entry(ptr, pcidriver_kmem_entry_t, list);
+ spin_lock(&(privdata->kmemlist_lock));
+ list_for_each(ptr, &(privdata->kmem_list)) {
+ entry = list_entry(ptr, pcidriver_kmem_entry_t, list);
- if (entry->id == id) {
- result = entry;
- break;
- }
- }
+ if (entry->id == id) {
+ result = entry;
+ break;
+ }
+ }
- spin_unlock(&(privdata->kmemlist_lock));
- return result;
+ spin_unlock(&(privdata->kmemlist_lock));
+ return result;
}
/**
@@ -584,21 +529,21 @@ pcidriver_kmem_entry_t *pcidriver_kmem_find_entry_id(pcidriver_privdata_t *privd
*/
pcidriver_kmem_entry_t *pcidriver_kmem_find_entry_use(pcidriver_privdata_t *privdata, unsigned long use, unsigned long item)
{
- struct list_head *ptr;
- pcidriver_kmem_entry_t *entry, *result = NULL;
+ struct list_head *ptr;
+ pcidriver_kmem_entry_t *entry, *result = NULL;
- spin_lock(&(privdata->kmemlist_lock));
- list_for_each(ptr, &(privdata->kmem_list)) {
- entry = list_entry(ptr, pcidriver_kmem_entry_t, list);
+ spin_lock(&(privdata->kmemlist_lock));
+ list_for_each(ptr, &(privdata->kmem_list)) {
+ entry = list_entry(ptr, pcidriver_kmem_entry_t, list);
- if ((entry->use == use)&&(entry->item == item)&&(entry->mode&KMEM_MODE_REUSABLE)) {
- result = entry;
- break;
- }
- }
+ if ((entry->use == use)&&(entry->item == item)&&(entry->mode&KMEM_MODE_REUSABLE)) {
+ result = entry;
+ break;
+ }
+ }
- spin_unlock(&(privdata->kmemlist_lock));
- return result;
+ spin_unlock(&(privdata->kmemlist_lock));
+ return result;
}
@@ -606,18 +551,18 @@ void pcidriver_kmem_mmap_close(struct vm_area_struct *vma) {
unsigned long vma_size;
pcidriver_kmem_entry_t *kmem_entry = (pcidriver_kmem_entry_t*)vma->vm_private_data;
if (kmem_entry) {
-/*
- if (kmem_entry->id == 0) {
- mod_info("refs: %p %p %lx\n", vma, vma->vm_private_data, kmem_entry->refs);
- mod_info("kmem_size: %lu vma_size: %lu, s: %lx, e: %lx\n", kmem_entry->size, (vma->vm_end - vma->vm_start), vma->vm_start, vma->vm_end);
- }
-*/
-
- vma_size = (vma->vm_end - vma->vm_start);
-
- if (kmem_entry->refs&KMEM_REF_COUNT) {
- kmem_entry->refs -= vma_size / PAGE_SIZE;
- }
+ /*
+ if (kmem_entry->id == 0) {
+ mod_info("refs: %p %p %lx\n", vma, vma->vm_private_data, kmem_entry->refs);
+ mod_info("kmem_size: %lu vma_size: %lu, s: %lx, e: %lx\n", kmem_entry->size, (vma->vm_end - vma->vm_start), vma->vm_start, vma->vm_end);
+ }
+ */
+
+ vma_size = (vma->vm_end - vma->vm_start);
+
+ if (kmem_entry->refs&KMEM_REF_COUNT) {
+ kmem_entry->refs -= vma_size / PAGE_SIZE;
+ }
}
}
@@ -632,78 +577,66 @@ static struct vm_operations_struct pcidriver_kmem_mmap_ops = {
*/
int pcidriver_mmap_kmem(pcidriver_privdata_t *privdata, struct vm_area_struct *vma)
{
- unsigned long vma_size;
- pcidriver_kmem_entry_t *kmem_entry;
- int ret;
-
- mod_info_dbg("Entering mmap_kmem\n");
-
- /* FIXME: Is this really right? Always just the latest one? Can't we identify one? */
- /* Get latest entry on the kmem_list */
- kmem_entry = pcidriver_kmem_find_entry_id(privdata, privdata->kmem_cur_id);
- if (!kmem_entry) {
- mod_info("Trying to mmap a kernel memory buffer without creating it first!\n");
- return -EFAULT;
- }
-
- mod_info_dbg("Got kmem_entry with id: %d\n", kmem_entry->id);
-
- /* Check sizes */
- vma_size = (vma->vm_end - vma->vm_start);
-
- if ((vma_size > kmem_entry->size) &&
- ((kmem_entry->size < PAGE_SIZE) && (vma_size != PAGE_SIZE))) {
- mod_info("kem_entry size(%lu) and vma size do not match(%lu)\n", kmem_entry->size, vma_size);
- return -EINVAL;
- }
-
- /* reference counting */
- if ((kmem_entry->mode&KMEM_MODE_EXCLUSIVE)&&(kmem_entry->refs&KMEM_REF_COUNT)) {
- mod_info("can't make second mmaping for exclusive kmem_entry\n");
- return -EBUSY;
- }
- if (((kmem_entry->refs&KMEM_REF_COUNT) + (vma_size / PAGE_SIZE)) > KMEM_REF_COUNT) {
- mod_info("maximal amount of references is reached by kmem_entry\n");
- return -EBUSY;
- }
-
- kmem_entry->refs += vma_size / PAGE_SIZE;
-
- vma->vm_flags |= (VM_RESERVED);
-
-#ifdef pgprot_noncached
- // This is coherent memory, so it must not be cached.
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-#endif
-
- mod_info_dbg("Mapping address %08lx / PFN %08lx\n",
- virt_to_phys((void*)kmem_entry->cpua),
- 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);
- } 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 );
- }
-
- if (ret) {
- mod_info("kmem remap failed: %d (%lx)\n", ret,kmem_entry->cpua);
- kmem_entry->refs -= 1;
- return -EAGAIN;
- }
-
- vma->vm_ops = &pcidriver_kmem_mmap_ops;
- vma->vm_private_data = (void*)kmem_entry;
-
- return ret;
+ unsigned long vma_size;
+ pcidriver_kmem_entry_t *kmem_entry;
+ int ret;
+
+ mod_info_dbg("Entering mmap_kmem\n");
+
+ /* FIXME: Is this really right? Always just the latest one? Can't we identify one? */
+ /* Get latest entry on the kmem_list */
+ kmem_entry = pcidriver_kmem_find_entry_id(privdata, privdata->kmem_cur_id);
+ if (!kmem_entry) {
+ mod_info("Trying to mmap a kernel memory buffer without creating it first!\n");
+ return -EFAULT;
+ }
+
+ mod_info_dbg("Got kmem_entry with id: %d\n", kmem_entry->id);
+
+ /* Check sizes */
+ vma_size = (vma->vm_end - vma->vm_start);
+
+ if ((vma_size > kmem_entry->size) &&
+ ((kmem_entry->size < PAGE_SIZE) && (vma_size != PAGE_SIZE))) {
+ mod_info("kem_entry size(%lu) and vma size do not match(%lu)\n", kmem_entry->size, vma_size);
+ return -EINVAL;
+ }
+
+ /* reference counting */
+ if ((kmem_entry->mode&KMEM_MODE_EXCLUSIVE)&&(kmem_entry->refs&KMEM_REF_COUNT)) {
+ mod_info("can't make second mmaping for exclusive kmem_entry\n");
+ return -EBUSY;
+ }
+ if (((kmem_entry->refs&KMEM_REF_COUNT) + (vma_size / PAGE_SIZE)) > KMEM_REF_COUNT) {
+ mod_info("maximal amount of references is reached by kmem_entry\n");
+ return -EBUSY;
+ }
+
+ kmem_entry->refs += vma_size / PAGE_SIZE;
+
+ vma->vm_flags |= (VM_RESERVED);
+
+ // This is coherent memory, so it must not be cached.
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ mod_info_dbg("Mapping address %08lx / PFN %08lx\n",
+ virt_to_phys((void*)kmem_entry->cpua),
+ 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(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(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) {
+ mod_info("kmem remap failed: %d (%lx)\n", ret,kmem_entry->cpua);
+ kmem_entry->refs -= 1;
+ return -EAGAIN;
+ }
+
+ vma->vm_ops = &pcidriver_kmem_mmap_ops;
+ vma->vm_private_data = (void*)kmem_entry;
+
+ return 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 371bd88..0000000
--- a/driver/pciDriver.h
+++ /dev/null
@@ -1,245 +0,0 @@
-#ifndef PCIDRIVER_H_
-#define PCIDRIVER_H_
-
-/**
- * This is a full rewrite of the pciDriver.
- * New default is to support kernel 2.6, using kernel 2.6 APIs.
- *
- * This header defines the interface to the outside world.
- *
- * $Revision: 1.6 $
- * $Date: 2008-01-24 14:21:36 $
- *
- */
-
-/*
- * Change History:
- *
- * $Log: not supported by cvs2svn $
- * Revision 1.5 2008-01-11 10:15:14 marcus
- * Removed unused interrupt code.
- * Added intSource to the wait interrupt call.
- *
- * Revision 1.4 2006/11/17 18:44:42 marcus
- * Type of SG list can now be selected at runtime. Added type to sglist.
- *
- * Revision 1.3 2006/11/17 16:23:02 marcus
- * Added slot number to the PCI info IOctl.
- *
- * Revision 1.2 2006/11/13 12:29:09 marcus
- * Added a IOctl call, to confiure the interrupt response. (testing pending).
- * Basic interrupts are now supported.
- *
- * Revision 1.1 2006/10/10 14:46:52 marcus
- * Initial commit of the new pciDriver for kernel 2.6
- *
- * Revision 1.7 2006/10/06 15:18:06 marcus
- * Updated PCI info and PCI cmd
- *
- * Revision 1.6 2006/09/25 16:51:07 marcus
- * Added PCI config IOctls, and implemented basic mmap functions.
- *
- * Revision 1.5 2006/09/18 17:13:12 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/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/pcibus.c b/driver/pcibus.c
new file mode 100644
index 0000000..f28f527
--- /dev/null
+++ b/driver/pcibus.c
@@ -0,0 +1,25 @@
+#include <linux/pci.h>
+
+int pcidriver_pcie_get_mps(struct pci_dev *dev)
+{
+ u16 ctl;
+
+ pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &ctl);
+
+ return 128 << ((ctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5);
+}
+
+int pcidriver_pcie_set_mps(struct pci_dev *dev, int mps)
+{
+ u16 v;
+
+ if (mps < 128 || mps > 4096 || !is_power_of_2(mps))
+ return -EINVAL;
+
+ v = ffs(mps) - 8;
+ if (v > dev->pcie_mpss)
+ return -EINVAL;
+ v <<= 5;
+
+ return pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_PAYLOAD, v);
+}
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 22a4a5e..b1d939a 100644
--- a/driver/rdma.c
+++ b/driver/rdma.c
@@ -7,8 +7,9 @@
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/hugetlb.h>
+#include <linux/cdev.h>
-#include "rdma.h"
+#include "base.h"
static unsigned long pcidriver_follow_pte(struct mm_struct *mm, unsigned long address)
{
@@ -17,37 +18,53 @@ static unsigned long pcidriver_follow_pte(struct mm_struct *mm, unsigned long ad
pmd_t *pmd;
pte_t *pte;
- spinlock_t *ptl;
+ spinlock_t *ptl;
unsigned long pfn = 0;
pgd = pgd_offset(mm, address);
- if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
- return 0;
-
+ if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
+ return 0;
+
pud = pud_offset(pgd, address);
- if (pud_none(*pud) || unlikely(pud_bad(*pud)))
- return 0;
+ if (pud_none(*pud) || unlikely(pud_bad(*pud)))
+ return 0;
pmd = pmd_offset(pud, address);
- if (pmd_none(*pmd))
- return 0;
+ if (pmd_none(*pmd))
+ return 0;
pte = pte_offset_map_lock(mm, pmd, address, &ptl);
if (!pte_none(*pte))
- pfn = (pte_pfn(*pte) << PAGE_SHIFT);
- pte_unmap_unlock(pte, ptl);
+ pfn = (pte_pfn(*pte) << PAGE_SHIFT);
+ pte_unmap_unlock(pte, ptl);
return pfn;
}
unsigned long pcidriver_resolve_bar(unsigned long address) {
+ int dev, bar;
unsigned long pfn;
address = (address >> PAGE_SHIFT) << PAGE_SHIFT;
pfn = pcidriver_follow_pte(current->mm, address);
- return pfn;
+ for (dev = 0; dev < MAXDEVICES; dev++)
+ {
+ pcidriver_privdata_t *privdata = pcidriver_get_privdata(dev);
+ if (!privdata) continue;
+
+ for (bar = 0; bar < 6; bar++)
+ {
+ unsigned long start = pci_resource_start(privdata->pdev, bar);
+ unsigned long end = start + pci_resource_len(privdata->pdev, bar);
+ if ((pfn >= start)&&(pfn < end))
+ return pfn;
+ }
+ pcidriver_put_privdata(privdata);
+ }
+
+ return 0;
}
EXPORT_SYMBOL(pcidriver_resolve_bar);
diff --git a/driver/rdma.h b/driver/rdma.h
index 4aeda78..813406d 100644
--- a/driver/rdma.h
+++ b/driver/rdma.h
@@ -1,9 +1,5 @@
#ifndef _PCIDRIVER_RDMA_H
#define _PCIDRIVER_RDMA_H
-#include <linux/mm.h>
-#include <linux/pagemap.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 abc1c8a..d0fd870 100644
--- a/driver/sysfs.c
+++ b/driver/sysfs.c
@@ -18,291 +18,321 @@
#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 */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
- char namebuffer[16];
+#define SYSFS_ATTR_NAME(name) (dev_attr_##name)
- /* allocate space for the name of the attribute */
- snprintf(namebuffer, sizeof(namebuffer), fmtstring, id);
+#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)
- if ((sysfs_attr->attr.name = kstrdup(namebuffer, GFP_KERNEL)) == NULL)
- return -ENOMEM;
+#define SYSFS_ATTR_REMOVE(name) do { \
+ device_remove_file(privdata->class_dev, &SYSFS_ATTR_NAME(name)); \
+ } while (0)
- sysfs_attr->attr.mode = S_IRUGO;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
- // DS: Shall we lock now while accessing driver data structures???
- sysfs_attr->attr.owner = THIS_MODULE;
-#endif
- sysfs_attr->show = callback;
- sysfs_attr->store = NULL;
-
- /* 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. */
-#endif
+#ifdef ENABLE_IRQ
+static SYSFS_GET_FUNCTION(pcidriver_show_irq_count)
+{
+ pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
- return 0;
+ return snprintf(buf, PAGE_SIZE, "%d\n", privdata->irq_count);
}
-int pcidriver_sysfs_initialize_kmem(pcidriver_privdata_t *privdata, int id, struct class_device_attribute *sysfs_attr)
+static SYSFS_GET_FUNCTION(pcidriver_show_irq_queues)
{
- return _pcidriver_sysfs_initialize(privdata, id, sysfs_attr, "kbuf%d", pcidriver_show_kmem_entry);
-}
+ pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
+ int i, offset;
-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);
-}
+ /* output will be truncated to PAGE_SIZE */
+ offset = snprintf(buf, PAGE_SIZE, "Queue\tOutstanding IRQs\n");
+ for (i = 0; i < PCIDRIVER_INT_MAXSOURCES; i++)
+ offset += snprintf(buf+offset, PAGE_SIZE-offset, "%d\t%d\n", i, atomic_read(&(privdata->irq_outstanding[i])) );
-/**
- *
- * 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)
-{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
- class_device_remove_file(privdata->class_dev, sysfs_attr);
- kfree(sysfs_attr->attr.name);
-#endif
+ return (offset > PAGE_SIZE ? PAGE_SIZE : offset+1);
}
+#endif
-static SYSFS_GET_FUNCTION(pcidriver_show_kmem_entry)
+static SYSFS_GET_FUNCTION(pcidriver_show_mmap_mode)
{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
- 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);
-#else
- return 0;
-#endif
+ pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", privdata->mmap_mode);
}
-static SYSFS_GET_FUNCTION(pcidriver_show_umem_entry)
+static SYSFS_SET_FUNCTION(pcidriver_store_mmap_mode)
{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
-#if 0
- pcidriver_privdata_t *privdata = (pcidriver_privdata_t *)cls->class_data;
+ pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
+ int mode = -1;
- return snprintf(buf, PAGE_SIZE, "I am in the umem_entry show function, class_device_kobj_name: %s\n", cls->kobj.name);
-#endif
- return 0;
-#else
- return 0;
-#endif
+ /* Set the mmap-mode if it is either PCIDRIVER_MMAP_PCI or PCIDRIVER_MMAP_KMEM */
+ if (sscanf(buf, "%d", &mode) == 1 &&
+ (mode == PCIDRIVER_MMAP_PCI || mode == PCIDRIVER_MMAP_KMEM))
+ privdata->mmap_mode = mode;
+
+ return strlen(buf);
}
-#ifdef ENABLE_IRQ
-SYSFS_GET_FUNCTION(pcidriver_show_irq_count)
+static SYSFS_GET_FUNCTION(pcidriver_show_mmap_area)
{
- pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
+ pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
- return snprintf(buf, PAGE_SIZE, "%d\n", privdata->irq_count);
+ return snprintf(buf, PAGE_SIZE, "%d\n", privdata->mmap_area);
}
-SYSFS_GET_FUNCTION(pcidriver_show_irq_queues)
+static SYSFS_SET_FUNCTION(pcidriver_store_mmap_area)
{
- pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
- int i, offset;
+ pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
+ int temp = -1;
+
+ sscanf(buf, "%d", &temp);
- /* output will be truncated to PAGE_SIZE */
- offset = snprintf(buf, PAGE_SIZE, "Queue\tOutstanding IRQs\n");
- for (i = 0; i < PCIDRIVER_INT_MAXSOURCES; i++)
- offset += snprintf(buf+offset, PAGE_SIZE-offset, "%d\t%d\n", i, atomic_read(&(privdata->irq_outstanding[i])) );
+ if ((temp >= PCIDRIVER_BAR0) && (temp <= PCIDRIVER_BAR5))
+ privdata->mmap_area = temp;
- return (offset > PAGE_SIZE ? PAGE_SIZE : offset+1);
+ return strlen(buf);
}
-#endif
-SYSFS_GET_FUNCTION(pcidriver_show_mmap_mode)
+static SYSFS_GET_FUNCTION(pcidriver_show_kmem_count)
{
- pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
+ pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
- return snprintf(buf, PAGE_SIZE, "%d\n", privdata->mmap_mode);
+ return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&(privdata->kmem_count)));
}
-SYSFS_SET_FUNCTION(pcidriver_store_mmap_mode)
+static SYSFS_SET_FUNCTION(pcidriver_store_kmem_alloc)
{
- pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
- int mode = -1;
+ pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
+ kmem_handle_t kmem_handle;
- /* Set the mmap-mode if it is either PCIDRIVER_MMAP_PCI or PCIDRIVER_MMAP_KMEM */
- if (sscanf(buf, "%d", &mode) == 1 &&
- (mode == PCIDRIVER_MMAP_PCI || mode == PCIDRIVER_MMAP_KMEM))
- privdata->mmap_mode = mode;
+ /* FIXME: guillermo: is validation of parsing an unsigned int enough? */
+ if (sscanf(buf, "%lu", &kmem_handle.size) == 1)
+ pcidriver_kmem_alloc(privdata, &kmem_handle);
- return strlen(buf);
+ return strlen(buf);
}
-SYSFS_GET_FUNCTION(pcidriver_show_mmap_area)
+static SYSFS_SET_FUNCTION(pcidriver_store_kmem_free)
{
- pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
+ pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
+ unsigned int id;
+ pcidriver_kmem_entry_t *kmem_entry;
+
+ /* Parse the ID of the kernel memory to be freed, check bounds */
+ if (sscanf(buf, "%u", &id) != 1 ||
+ (id >= atomic_read(&(privdata->kmem_count))))
+ goto err;
+
+ if ((kmem_entry = pcidriver_kmem_find_entry_id(privdata,id)) == NULL)
+ goto err;
- return snprintf(buf, PAGE_SIZE, "%d\n", privdata->mmap_area);
+ pcidriver_kmem_free_entry(privdata, kmem_entry );
+err:
+ return strlen(buf);
}
-SYSFS_SET_FUNCTION(pcidriver_store_mmap_area)
+static SYSFS_GET_FUNCTION(pcidriver_show_kbuffers)
{
- pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
- int temp = -1;
+ pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
+ int offset = 0;
+ struct list_head *ptr;
+ pcidriver_kmem_entry_t *entry;
- sscanf(buf, "%d", &temp);
+ /* print the header */
+ offset += snprintf(buf, PAGE_SIZE, "kbuf#\tcpu addr\tsize\n");
- if ((temp >= PCIDRIVER_BAR0) && (temp <= PCIDRIVER_BAR5))
- privdata->mmap_area = temp;
+ spin_lock(&(privdata->kmemlist_lock));
+ list_for_each(ptr, &(privdata->kmem_list)) {
+ entry = list_entry(ptr, pcidriver_kmem_entry_t, list);
- return strlen(buf);
-}
+ /* print entry info */
+ if (offset > PAGE_SIZE) {
+ spin_unlock( &(privdata->kmemlist_lock) );
+ return PAGE_SIZE;
+ }
-SYSFS_GET_FUNCTION(pcidriver_show_kmem_count)
-{
- pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
+ offset += snprintf(buf+offset, PAGE_SIZE-offset, "%3d\t%08lx\t%lu\n", entry->id, (unsigned long)(entry->dma_handle), entry->size );
+ }
+
+ spin_unlock(&(privdata->kmemlist_lock));
- return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&(privdata->kmem_count)));
+ /* output will be truncated to PAGE_SIZE */
+ return (offset > PAGE_SIZE ? PAGE_SIZE : offset+1);
}
-SYSFS_SET_FUNCTION(pcidriver_store_kmem_alloc)
+static SYSFS_GET_FUNCTION(pcidriver_show_umappings)
{
- pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
- kmem_handle_t kmem_handle;
+ int offset = 0;
+ pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
+ struct list_head *ptr;
+ pcidriver_umem_entry_t *entry;
- /* FIXME: guillermo: is validation of parsing an unsigned int enough? */
- if (sscanf(buf, "%lu", &kmem_handle.size) == 1)
- pcidriver_kmem_alloc(privdata, &kmem_handle);
+ /* print the header */
+ offset += snprintf(buf, PAGE_SIZE, "umap#\tn_pages\tsg_ents\n");
- return strlen(buf);
+ spin_lock( &(privdata->umemlist_lock) );
+ list_for_each( ptr, &(privdata->umem_list) ) {
+ entry = list_entry(ptr, pcidriver_umem_entry_t, list );
+
+ /* print entry info */
+ if (offset > PAGE_SIZE) {
+ spin_unlock( &(privdata->umemlist_lock) );
+ return PAGE_SIZE;
+ }
+
+ offset += snprintf(buf+offset, PAGE_SIZE-offset, "%3d\t%lu\t%lu\n", entry->id,
+ (unsigned long)(entry->nr_pages), (unsigned long)(entry->nents));
+ }
+
+ spin_unlock( &(privdata->umemlist_lock) );
+
+ /* output will be truncated to PAGE_SIZE */
+ return (offset > PAGE_SIZE ? PAGE_SIZE : offset+1);
}
-SYSFS_SET_FUNCTION(pcidriver_store_kmem_free)
+static SYSFS_SET_FUNCTION(pcidriver_store_umem_unmap)
{
- pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
- unsigned int id;
- pcidriver_kmem_entry_t *kmem_entry;
+ pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
+ pcidriver_umem_entry_t *umem_entry;
+ unsigned int id;
- /* Parse the ID of the kernel memory to be freed, check bounds */
- if (sscanf(buf, "%u", &id) != 1 ||
- (id >= atomic_read(&(privdata->kmem_count))))
- goto err;
+ if (sscanf(buf, "%u", &id) != 1 ||
+ (id >= atomic_read(&(privdata->umem_count))))
+ goto err;
- if ((kmem_entry = pcidriver_kmem_find_entry_id(privdata,id)) == NULL)
- goto err;
+ if ((umem_entry = pcidriver_umem_find_entry_id(privdata, id)) == NULL)
+ goto err;
- pcidriver_kmem_free_entry(privdata, kmem_entry );
+ pcidriver_umem_sgunmap(privdata, umem_entry);
err:
- return strlen(buf);
+ return strlen(buf);
}
-SYSFS_GET_FUNCTION(pcidriver_show_kbuffers)
+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)
{
- pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
- int offset = 0;
- struct list_head *ptr;
- pcidriver_kmem_entry_t *entry;
+ return 0;
+}
- /* print the header */
- offset += snprintf(buf, PAGE_SIZE, "kbuf#\tcpu addr\tsize\n");
- spin_lock(&(privdata->kmemlist_lock));
- list_for_each(ptr, &(privdata->kmem_list)) {
- entry = list_entry(ptr, pcidriver_kmem_entry_t, list);
+#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
- /* print entry info */
- if (offset > PAGE_SIZE) {
- spin_unlock( &(privdata->kmemlist_lock) );
- return PAGE_SIZE;
- }
+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);
- offset += snprintf(buf+offset, PAGE_SIZE-offset, "%3d\t%08lx\t%lu\n", entry->id, (unsigned long)(entry->dma_handle), entry->size );
- }
+int pcidriver_create_sysfs_attributes(pcidriver_privdata_t *privdata) {
+#ifdef ENABLE_IRQ
+ SYSFS_ATTR_CREATE(irq_count);
+ SYSFS_ATTR_CREATE(irq_queues);
+#endif
- spin_unlock(&(privdata->kmemlist_lock));
+ 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
- /* output will be truncated to PAGE_SIZE */
- return (offset > PAGE_SIZE ? PAGE_SIZE : offset+1);
+ 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);
}
-SYSFS_GET_FUNCTION(pcidriver_show_umappings)
+/**
+ *
+ * Removes the file from sysfs and frees the allocated (kstrdup()) memory.
+ *
+ */
+void pcidriver_sysfs_remove(pcidriver_privdata_t *privdata, struct device_attribute *sysfs_attr)
{
- int offset = 0;
- pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
- struct list_head *ptr;
- pcidriver_umem_entry_t *entry;
+ device_remove_file(privdata->class_dev, sysfs_attr);
+ kfree(sysfs_attr->attr.name);
+}
- /* print the header */
- offset += snprintf(buf, PAGE_SIZE, "umap#\tn_pages\tsg_ents\n");
+/**
+ *
+ * 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];
- spin_lock( &(privdata->umemlist_lock) );
- list_for_each( ptr, &(privdata->umem_list) ) {
- entry = list_entry(ptr, pcidriver_umem_entry_t, list );
+ /* allocate space for the name of the attribute */
+ snprintf(namebuffer, sizeof(namebuffer), fmtstring, id);
- /* print entry info */
- if (offset > PAGE_SIZE) {
- spin_unlock( &(privdata->umemlist_lock) );
- return PAGE_SIZE;
- }
+ if ((sysfs_attr->attr.name = kstrdup(namebuffer, GFP_KERNEL)) == NULL)
+ return -ENOMEM;
- offset += snprintf(buf+offset, PAGE_SIZE-offset, "%3d\t%lu\t%lu\n", entry->id,
- (unsigned long)(entry->nr_pages), (unsigned long)(entry->nents));
- }
+ sysfs_attr->attr.mode = S_IRUGO;
+ sysfs_attr->show = callback;
+ sysfs_attr->store = NULL;
- spin_unlock( &(privdata->umemlist_lock) );
+ /* 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. */
- /* output will be truncated to PAGE_SIZE */
- return (offset > PAGE_SIZE ? PAGE_SIZE : offset+1);
+ return 0;
}
-SYSFS_SET_FUNCTION(pcidriver_store_umem_unmap)
+int pcidriver_sysfs_initialize_kmem(pcidriver_privdata_t *privdata, int id, struct device_attribute *sysfs_attr)
{
- pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
- pcidriver_umem_entry_t *umem_entry;
- unsigned int id;
-
- if (sscanf(buf, "%u", &id) != 1 ||
- (id >= atomic_read(&(privdata->umem_count))))
- goto err;
-
- if ((umem_entry = pcidriver_umem_find_entry_id(privdata, id)) == NULL)
- goto err;
+ return _pcidriver_sysfs_initialize(privdata, id, sysfs_attr, "kbuf%d", pcidriver_show_kmem_entry);
+}
- pcidriver_umem_sgunmap(privdata, umem_entry);
-err:
- return strlen(buf);
+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 7a8dcc1..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"
/**
*
@@ -32,153 +27,153 @@
*/
int pcidriver_umem_sgmap(pcidriver_privdata_t *privdata, umem_handle_t *umem_handle)
{
- int i, res, nr_pages;
- struct page **pages;
- struct scatterlist *sg = NULL;
- pcidriver_umem_entry_t *umem_entry;
- unsigned int nents;
- unsigned long count,offset,length;
-
- /*
- * We do some checks first. Then, the following is necessary to create a
- * Scatter/Gather list from a user memory area:
- * - Determine the number of pages
- * - Get the pages for the memory area
- * - Lock them.
- * - Create a scatter/gather list of the pages
- * - Map the list from memory to PCI bus addresses
- *
- * Then, we:
- * - Create an entry on the umem list of the device, to cache the mapping.
- * - Create a sysfs attribute that gives easy access to the SG list
- */
-
- /* zero-size?? */
- if (umem_handle->size == 0)
- return -EINVAL;
-
- /* Direction is better ignoring during mapping. */
- /* We assume bidirectional buffers always, except when sync'ing */
-
- /* calculate the number of pages */
- nr_pages = ((umem_handle->vma & ~PAGE_MASK) + umem_handle->size + ~PAGE_MASK) >> PAGE_SHIFT;
-
- mod_info_dbg("nr_pages computed: %u\n", nr_pages);
-
- /* Allocate space for the page information */
- /* This can be very big, so we use vmalloc */
- if ((pages = vmalloc(nr_pages * sizeof(*pages))) == NULL)
- return -ENOMEM;
-
- mod_info_dbg("allocated space for the pages.\n");
-
- /* Allocate space for the scatterlist */
- /* We do not know how many entries will be, but the maximum is nr_pages. */
- /* This can be very big, so we use vmalloc */
- if ((sg = vmalloc(nr_pages * sizeof(*sg))) == NULL)
- goto umem_sgmap_pages;
-
- sg_init_table(sg, nr_pages);
-
- mod_info_dbg("allocated space for the SG list.\n");
-
- /* Get the page information */
- down_read(&current->mm->mmap_sem);
- res = get_user_pages(
- current,
- current->mm,
- umem_handle->vma,
- nr_pages,
- 1,
- 0, /* do not force, FIXME: shall I? */
- pages,
- NULL );
- up_read(&current->mm->mmap_sem);
-
- /* Error, not all pages mapped */
- if (res < (int)nr_pages) {
- mod_info("Could not map all user pages (%d of %d)\n", res, nr_pages);
- /* If only some pages could be mapped, we release those. If a real
- * error occured, we set nr_pages to 0 */
- nr_pages = (res > 0 ? res : 0);
- goto umem_sgmap_unmap;
- }
-
- mod_info_dbg("Got the pages (%d).\n", res);
-
- /* Lock the pages, then populate the SG list with the pages */
- /* page0 is different */
- if ( !PageReserved(pages[0]) )
- compat_lock_page(pages[0]);
-
- offset = (umem_handle->vma & ~PAGE_MASK);
- length = (umem_handle->size > (PAGE_SIZE-offset) ? (PAGE_SIZE-offset) : umem_handle->size);
-
- sg_set_page(&sg[0], pages[0], length, offset);
-
- count = umem_handle->size - length;
- for(i=1;i<nr_pages;i++) {
- /* Lock page first */
- if ( !PageReserved(pages[i]) )
- compat_lock_page(pages[i]);
-
- /* Populate the list */
- sg_set_page(&sg[i], pages[i], ((count > PAGE_SIZE) ? PAGE_SIZE : count), 0);
- count -= sg[i].length;
- }
-
- /* Use the page list to populate the SG list */
- /* SG entries may be merged, res is the number of used entries */
- /* We have originally nr_pages entries in the sg list */
- if ((nents = pci_map_sg(privdata->pdev, sg, nr_pages, PCI_DMA_BIDIRECTIONAL)) == 0)
- goto umem_sgmap_unmap;
-
- mod_info_dbg("Mapped SG list (%d entries).\n", nents);
-
- /* Add an entry to the umem_list of the device, and update the handle with the id */
- /* Allocate space for the new umem entry */
- if ((umem_entry = kmalloc(sizeof(*umem_entry), GFP_KERNEL)) == NULL)
- goto umem_sgmap_entry;
-
- /* Fill entry to be added to the umem list */
- umem_entry->id = atomic_inc_return(&privdata->umem_count) - 1;
- umem_entry->nr_pages = nr_pages; /* Will be needed when unmapping */
- umem_entry->pages = pages;
- umem_entry->nents = nents;
- umem_entry->sg = sg;
-
- if (pcidriver_sysfs_initialize_umem(privdata, umem_entry->id, &(umem_entry->sysfs_attr)) != 0)
- goto umem_sgmap_name_fail;
-
- /* Add entry to the umem list */
- spin_lock( &(privdata->umemlist_lock) );
- list_add_tail( &(umem_entry->list), &(privdata->umem_list) );
- spin_unlock( &(privdata->umemlist_lock) );
-
- /* Update the Handle with the Handle ID of the entry */
- umem_handle->handle_id = umem_entry->id;
-
- return 0;
+ int i, res, nr_pages;
+ struct page **pages;
+ struct scatterlist *sg = NULL;
+ pcidriver_umem_entry_t *umem_entry;
+ unsigned int nents;
+ unsigned long count,offset,length;
+
+ /*
+ * We do some checks first. Then, the following is necessary to create a
+ * Scatter/Gather list from a user memory area:
+ * - Determine the number of pages
+ * - Get the pages for the memory area
+ * - Lock them.
+ * - Create a scatter/gather list of the pages
+ * - Map the list from memory to PCI bus addresses
+ *
+ * Then, we:
+ * - Create an entry on the umem list of the device, to cache the mapping.
+ * - Create a sysfs attribute that gives easy access to the SG list
+ */
+
+ /* zero-size?? */
+ if (umem_handle->size == 0)
+ return -EINVAL;
+
+ /* Direction is better ignoring during mapping. */
+ /* We assume bidirectional buffers always, except when sync'ing */
+
+ /* calculate the number of pages */
+ nr_pages = ((umem_handle->vma & ~PAGE_MASK) + umem_handle->size + ~PAGE_MASK) >> PAGE_SHIFT;
+
+ mod_info_dbg("nr_pages computed: %u\n", nr_pages);
+
+ /* Allocate space for the page information */
+ /* This can be very big, so we use vmalloc */
+ if ((pages = vmalloc(nr_pages * sizeof(*pages))) == NULL)
+ return -ENOMEM;
+
+ mod_info_dbg("allocated space for the pages.\n");
+
+ /* Allocate space for the scatterlist */
+ /* We do not know how many entries will be, but the maximum is nr_pages. */
+ /* This can be very big, so we use vmalloc */
+ if ((sg = vmalloc(nr_pages * sizeof(*sg))) == NULL)
+ goto umem_sgmap_pages;
+
+ sg_init_table(sg, nr_pages);
+
+ mod_info_dbg("allocated space for the SG list.\n");
+
+ /* Get the page information */
+ down_read(&current->mm->mmap_sem);
+ res = get_user_pages(
+ current,
+ current->mm,
+ umem_handle->vma,
+ nr_pages,
+ 1,
+ 0, /* do not force, FIXME: shall I? */
+ pages,
+ NULL );
+ up_read(&current->mm->mmap_sem);
+
+ /* Error, not all pages mapped */
+ if (res < (int)nr_pages) {
+ mod_info("Could not map all user pages (%d of %d)\n", res, nr_pages);
+ /* If only some pages could be mapped, we release those. If a real
+ * error occured, we set nr_pages to 0 */
+ nr_pages = (res > 0 ? res : 0);
+ goto umem_sgmap_unmap;
+ }
+
+ mod_info_dbg("Got the pages (%d).\n", res);
+
+ /* Lock the pages, then populate the SG list with the pages */
+ /* page0 is different */
+ if ( !PageReserved(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);
+
+ sg_set_page(&sg[0], pages[0], length, offset);
+
+ count = umem_handle->size - length;
+ for(i=1; i<nr_pages; i++) {
+ /* Lock page first */
+ if ( !PageReserved(pages[i]) )
+ __set_page_locked(pages[i]);
+
+ /* Populate the list */
+ sg_set_page(&sg[i], pages[i], ((count > PAGE_SIZE) ? PAGE_SIZE : count), 0);
+ count -= sg[i].length;
+ }
+
+ /* Use the page list to populate the SG list */
+ /* SG entries may be merged, res is the number of used entries */
+ /* We have originally nr_pages entries in the sg list */
+ if ((nents = pci_map_sg(privdata->pdev, sg, nr_pages, PCI_DMA_BIDIRECTIONAL)) == 0)
+ goto umem_sgmap_unmap;
+
+ mod_info_dbg("Mapped SG list (%d entries).\n", nents);
+
+ /* Add an entry to the umem_list of the device, and update the handle with the id */
+ /* Allocate space for the new umem entry */
+ if ((umem_entry = kmalloc(sizeof(*umem_entry), GFP_KERNEL)) == NULL)
+ goto umem_sgmap_entry;
+
+ /* Fill entry to be added to the umem list */
+ umem_entry->id = atomic_inc_return(&privdata->umem_count) - 1;
+ umem_entry->nr_pages = nr_pages; /* Will be needed when unmapping */
+ umem_entry->pages = pages;
+ umem_entry->nents = nents;
+ umem_entry->sg = sg;
+
+ if (pcidriver_sysfs_initialize_umem(privdata, umem_entry->id, &(umem_entry->sysfs_attr)) != 0)
+ goto umem_sgmap_name_fail;
+
+ /* Add entry to the umem list */
+ spin_lock( &(privdata->umemlist_lock) );
+ list_add_tail( &(umem_entry->list), &(privdata->umem_list) );
+ spin_unlock( &(privdata->umemlist_lock) );
+
+ /* Update the Handle with the Handle ID of the entry */
+ umem_handle->handle_id = umem_entry->id;
+
+ return 0;
umem_sgmap_name_fail:
- kfree(umem_entry);
+ kfree(umem_entry);
umem_sgmap_entry:
- pci_unmap_sg( privdata->pdev, sg, nr_pages, PCI_DMA_BIDIRECTIONAL );
+ pci_unmap_sg( privdata->pdev, sg, nr_pages, PCI_DMA_BIDIRECTIONAL );
umem_sgmap_unmap:
- /* release pages */
- if (nr_pages > 0) {
- for(i=0;i<nr_pages;i++) {
- if (PageLocked(pages[i]))
- compat_unlock_page(pages[i]);
- if (!PageReserved(pages[i]))
- set_page_dirty(pages[i]);
- page_cache_release(pages[i]);
- }
- }
- vfree(sg);
+ /* release pages */
+ if (nr_pages > 0) {
+ for(i=0; i<nr_pages; i++) {
+ if (PageLocked(pages[i]))
+ __clear_page_locked(pages[i]);
+ if (!PageReserved(pages[i]))
+ set_page_dirty(pages[i]);
+ page_cache_release(pages[i]);
+ }
+ }
+ vfree(sg);
umem_sgmap_pages:
- vfree(pages);
- return -ENOMEM;
+ vfree(pages);
+ return -ENOMEM;
}
@@ -189,39 +184,39 @@ umem_sgmap_pages:
*/
int pcidriver_umem_sgunmap(pcidriver_privdata_t *privdata, pcidriver_umem_entry_t *umem_entry)
{
- int i;
- pcidriver_sysfs_remove(privdata, &(umem_entry->sysfs_attr));
-
- /* Unmap user memory */
- pci_unmap_sg( privdata->pdev, umem_entry->sg, umem_entry->nr_pages, PCI_DMA_BIDIRECTIONAL );
-
- /* Release the pages */
- if (umem_entry->nr_pages > 0) {
- for(i=0;i<(umem_entry->nr_pages);i++) {
- /* 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]);
- }
- /* and release it from the cache */
- page_cache_release( umem_entry->pages[i] );
- }
- }
-
- /* Remove the umem list entry */
- spin_lock( &(privdata->umemlist_lock) );
- list_del( &(umem_entry->list) );
- spin_unlock( &(privdata->umemlist_lock) );
-
- /* Release SG list and page list memory */
- /* These two are in the vm area of the kernel */
- vfree(umem_entry->pages);
- vfree(umem_entry->sg);
-
- /* Release umem_entry memory */
- kfree(umem_entry);
-
- return 0;
+ int i;
+ pcidriver_sysfs_remove(privdata, &(umem_entry->sysfs_attr));
+
+ /* Unmap user memory */
+ pci_unmap_sg( privdata->pdev, umem_entry->sg, umem_entry->nr_pages, PCI_DMA_BIDIRECTIONAL );
+
+ /* Release the pages */
+ if (umem_entry->nr_pages > 0) {
+ for(i=0; i<(umem_entry->nr_pages); i++) {
+ /* Mark pages as Dirty and unlock it */
+ if ( !PageReserved( umem_entry->pages[i] )) {
+ SetPageDirty( umem_entry->pages[i] );
+ __clear_page_locked(umem_entry->pages[i]);
+ }
+ /* and release it from the cache */
+ page_cache_release( umem_entry->pages[i] );
+ }
+ }
+
+ /* Remove the umem list entry */
+ spin_lock( &(privdata->umemlist_lock) );
+ list_del( &(umem_entry->list) );
+ spin_unlock( &(privdata->umemlist_lock) );
+
+ /* Release SG list and page list memory */
+ /* These two are in the vm area of the kernel */
+ vfree(umem_entry->pages);
+ vfree(umem_entry->sg);
+
+ /* Release umem_entry memory */
+ kfree(umem_entry);
+
+ return 0;
}
/**
@@ -231,16 +226,16 @@ int pcidriver_umem_sgunmap(pcidriver_privdata_t *privdata, pcidriver_umem_entry_
*/
int pcidriver_umem_sgunmap_all(pcidriver_privdata_t *privdata)
{
- struct list_head *ptr, *next;
- pcidriver_umem_entry_t *umem_entry;
+ struct list_head *ptr, *next;
+ pcidriver_umem_entry_t *umem_entry;
- /* iterate safely over the entries and delete them */
- list_for_each_safe( ptr, next, &(privdata->umem_list) ) {
- umem_entry = list_entry(ptr, pcidriver_umem_entry_t, list );
- pcidriver_umem_sgunmap( privdata, umem_entry ); /* spin lock inside! */
- }
+ /* iterate safely over the entries and delete them */
+ list_for_each_safe( ptr, next, &(privdata->umem_list) ) {
+ umem_entry = list_entry(ptr, pcidriver_umem_entry_t, list );
+ pcidriver_umem_sgunmap( privdata, umem_entry ); /* spin lock inside! */
+ }
- return 0;
+ return 0;
}
/**
@@ -250,117 +245,68 @@ int pcidriver_umem_sgunmap_all(pcidriver_privdata_t *privdata)
*/
int pcidriver_umem_sgget(pcidriver_privdata_t *privdata, umem_sglist_t *umem_sglist)
{
- int i;
- pcidriver_umem_entry_t *umem_entry;
- struct scatterlist *sg;
- int idx = 0;
- dma_addr_t cur_addr;
- unsigned int cur_size;
-
- /* Find the associated umem_entry for this buffer */
- umem_entry = pcidriver_umem_find_entry_id( privdata, umem_sglist->handle_id );
- if (umem_entry == NULL)
- return -EINVAL; /* umem_handle is not valid */
-
- /* Check if passed SG list is enough */
- if (umem_sglist->nents < umem_entry->nents)
- return -EINVAL; /* sg has not enough entries */
-
- /* Copy the SG list to the user format */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
- if (umem_sglist->type == PCIDRIVER_SG_MERGED) {
- for_each_sg(umem_entry->sg, sg, umem_entry->nents, i ) {
- if (i==0) {
- umem_sglist->sg[0].addr = sg_dma_address( sg );
- umem_sglist->sg[0].size = sg_dma_len( sg );
- idx = 0;
- }
- else {
- cur_addr = sg_dma_address( sg );
- cur_size = sg_dma_len( sg );
-
- /* Check if entry fits after current entry */
- if (cur_addr == (umem_sglist->sg[idx].addr + umem_sglist->sg[idx].size)) {
- umem_sglist->sg[idx].size += cur_size;
- continue;
- }
-
- /* Skip if the entry is zero-length (yes, it can happen.... at the end of the list) */
- if (cur_size == 0)
- continue;
-
- /* None of the above, add new entry */
- idx++;
- umem_sglist->sg[idx].addr = cur_addr;
- umem_sglist->sg[idx].size = cur_size;
- }
- }
- /* Set the used size of the SG list */
- umem_sglist->nents = idx+1;
- } else {
- for_each_sg(umem_entry->sg, sg, umem_entry->nents, i ) {
- mod_info("entry: %d\n",i);
- umem_sglist->sg[i].addr = sg_dma_address( sg );
- umem_sglist->sg[i].size = sg_dma_len( sg );
- }
-
- /* Set the used size of the SG list */
- /* Check if the last one is zero-length */
- if ( umem_sglist->sg[ umem_entry->nents - 1].size == 0)
- umem_sglist->nents = umem_entry->nents -1;
- else
- umem_sglist->nents = umem_entry->nents;
- }
-#else
- if (umem_sglist->type == PCIDRIVER_SG_MERGED) {
- /* Merge entries that are contiguous into a single entry */
- /* Non-optimal but fast for most cases */
- /* First one always true */
- sg=umem_entry->sg;
- umem_sglist->sg[0].addr = sg_dma_address( sg );
- umem_sglist->sg[0].size = sg_dma_len( sg );
- sg++;
- idx = 0;
-
- /* Iterate over the SG entries */
- for(i=1; i< umem_entry->nents; i++, sg++ ) {
- cur_addr = sg_dma_address( sg );
- cur_size = sg_dma_len( sg );
-
- /* Check if entry fits after current entry */
- if (cur_addr == (umem_sglist->sg[idx].addr + umem_sglist->sg[idx].size)) {
- umem_sglist->sg[idx].size += cur_size;
- continue;
- }
-
- /* Skip if the entry is zero-length (yes, it can happen.... at the end of the list) */
- if (cur_size == 0)
- continue;
-
- /* None of the above, add new entry */
- idx++;
- umem_sglist->sg[idx].addr = cur_addr;
- umem_sglist->sg[idx].size = cur_size;
- }
- /* Set the used size of the SG list */
- umem_sglist->nents = idx+1;
- } else {
- /* Assume pci_map_sg made a good job (ehem..) and just copy it.
- * actually, now I assume it just gives them plainly to me. */
- for(i=0, sg=umem_entry->sg ; i< umem_entry->nents; i++, sg++ ) {
- umem_sglist->sg[i].addr = sg_dma_address( sg );
- umem_sglist->sg[i].size = sg_dma_len( sg );
- }
- /* Set the used size of the SG list */
- /* Check if the last one is zero-length */
- if ( umem_sglist->sg[ umem_entry->nents - 1].size == 0)
- umem_sglist->nents = umem_entry->nents -1;
- else
- umem_sglist->nents = umem_entry->nents;
- }
-#endif
-
- return 0;
+ int i;
+ pcidriver_umem_entry_t *umem_entry;
+ struct scatterlist *sg;
+ int idx = 0;
+ dma_addr_t cur_addr;
+ unsigned int cur_size;
+
+ /* Find the associated umem_entry for this buffer */
+ umem_entry = pcidriver_umem_find_entry_id( privdata, umem_sglist->handle_id );
+ if (umem_entry == NULL)
+ return -EINVAL; /* umem_handle is not valid */
+
+ /* Check if passed SG list is enough */
+ if (umem_sglist->nents < umem_entry->nents)
+ return -EINVAL; /* sg has not enough entries */
+
+ /* Copy the SG list to the user format */
+ if (umem_sglist->type == PCIDRIVER_SG_MERGED) {
+ for_each_sg(umem_entry->sg, sg, umem_entry->nents, i ) {
+ if (i==0) {
+ umem_sglist->sg[0].addr = sg_dma_address( sg );
+ umem_sglist->sg[0].size = sg_dma_len( sg );
+ idx = 0;
+ }
+ else {
+ cur_addr = sg_dma_address( sg );
+ cur_size = sg_dma_len( sg );
+
+ /* Check if entry fits after current entry */
+ if (cur_addr == (umem_sglist->sg[idx].addr + umem_sglist->sg[idx].size)) {
+ umem_sglist->sg[idx].size += cur_size;
+ continue;
+ }
+
+ /* Skip if the entry is zero-length (yes, it can happen.... at the end of the list) */
+ if (cur_size == 0)
+ continue;
+
+ /* None of the above, add new entry */
+ idx++;
+ umem_sglist->sg[idx].addr = cur_addr;
+ umem_sglist->sg[idx].size = cur_size;
+ }
+ }
+ /* Set the used size of the SG list */
+ umem_sglist->nents = idx+1;
+ } else {
+ for_each_sg(umem_entry->sg, sg, umem_entry->nents, i ) {
+ mod_info("entry: %d\n",i);
+ umem_sglist->sg[i].addr = sg_dma_address( sg );
+ umem_sglist->sg[i].size = sg_dma_len( sg );
+ }
+
+ /* Set the used size of the SG list */
+ /* Check if the last one is zero-length */
+ if ( umem_sglist->sg[ umem_entry->nents - 1].size == 0)
+ umem_sglist->nents = umem_entry->nents -1;
+ else
+ umem_sglist->nents = umem_entry->nents;
+ }
+
+ return 0;
}
/**
@@ -370,45 +316,29 @@ int pcidriver_umem_sgget(pcidriver_privdata_t *privdata, umem_sglist_t *umem_sgl
*/
int pcidriver_umem_sync( pcidriver_privdata_t *privdata, umem_handle_t *umem_handle )
{
- pcidriver_umem_entry_t *umem_entry;
-
- /* Find the associated umem_entry for this buffer */
- umem_entry = pcidriver_umem_find_entry_id( privdata, umem_handle->handle_id );
- if (umem_entry == NULL)
- return -EINVAL; /* umem_handle is not valid */
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
- switch (umem_handle->dir) {
- case PCIDRIVER_DMA_TODEVICE:
- pci_dma_sync_sg_for_device( privdata->pdev, umem_entry->sg, umem_entry->nents, PCI_DMA_TODEVICE );
- break;
- case PCIDRIVER_DMA_FROMDEVICE:
- pci_dma_sync_sg_for_cpu( privdata->pdev, umem_entry->sg, umem_entry->nents, PCI_DMA_FROMDEVICE );
- break;
- case PCIDRIVER_DMA_BIDIRECTIONAL:
- pci_dma_sync_sg_for_device( privdata->pdev, umem_entry->sg, umem_entry->nents, PCI_DMA_BIDIRECTIONAL );
- pci_dma_sync_sg_for_cpu( privdata->pdev, umem_entry->sg, umem_entry->nents, PCI_DMA_BIDIRECTIONAL );
- break;
- default:
- return -EINVAL; /* wrong direction parameter */
- }
-#else
- switch (umem_handle->dir) {
- case PCIDRIVER_DMA_TODEVICE:
- pci_dma_sync_sg( privdata->pdev, umem_entry->sg, umem_entry->nents, PCI_DMA_TODEVICE );
- break;
- case PCIDRIVER_DMA_FROMDEVICE:
- pci_dma_sync_sg( privdata->pdev, umem_entry->sg, umem_entry->nents, PCI_DMA_FROMDEVICE );
- break;
- case PCIDRIVER_DMA_BIDIRECTIONAL:
- pci_dma_sync_sg( privdata->pdev, umem_entry->sg, umem_entry->nents, PCI_DMA_BIDIRECTIONAL );
- break;
- default:
- return -EINVAL; /* wrong direction parameter */
- }
-#endif
-
- return 0;
+ pcidriver_umem_entry_t *umem_entry;
+
+ /* Find the associated umem_entry for this buffer */
+ umem_entry = pcidriver_umem_find_entry_id( privdata, umem_handle->handle_id );
+ if (umem_entry == NULL)
+ return -EINVAL; /* umem_handle is not valid */
+
+ switch (umem_handle->dir) {
+ case PCIDRIVER_DMA_TODEVICE:
+ pci_dma_sync_sg_for_device( privdata->pdev, umem_entry->sg, umem_entry->nents, PCI_DMA_TODEVICE );
+ break;
+ case PCIDRIVER_DMA_FROMDEVICE:
+ pci_dma_sync_sg_for_cpu( privdata->pdev, umem_entry->sg, umem_entry->nents, PCI_DMA_FROMDEVICE );
+ break;
+ case PCIDRIVER_DMA_BIDIRECTIONAL:
+ pci_dma_sync_sg_for_device( privdata->pdev, umem_entry->sg, umem_entry->nents, PCI_DMA_BIDIRECTIONAL );
+ pci_dma_sync_sg_for_cpu( privdata->pdev, umem_entry->sg, umem_entry->nents, PCI_DMA_BIDIRECTIONAL );
+ break;
+ default:
+ return -EINVAL; /* wrong direction parameter */
+ }
+
+ return 0;
}
/*
@@ -420,19 +350,19 @@ int pcidriver_umem_sync( pcidriver_privdata_t *privdata, umem_handle_t *umem_han
*/
pcidriver_umem_entry_t *pcidriver_umem_find_entry_id(pcidriver_privdata_t *privdata, int id)
{
- struct list_head *ptr;
- pcidriver_umem_entry_t *entry;
+ struct list_head *ptr;
+ pcidriver_umem_entry_t *entry;
- spin_lock(&(privdata->umemlist_lock));
- list_for_each(ptr, &(privdata->umem_list)) {
- entry = list_entry(ptr, pcidriver_umem_entry_t, list );
+ spin_lock(&(privdata->umemlist_lock));
+ list_for_each(ptr, &(privdata->umem_list)) {
+ entry = list_entry(ptr, pcidriver_umem_entry_t, list );
- if (entry->id == id) {
- spin_unlock( &(privdata->umemlist_lock) );
- return entry;
- }
- }
+ if (entry->id == id) {
+ spin_unlock( &(privdata->umemlist_lock) );
+ return entry;
+ }
+ }
- spin_unlock(&(privdata->umemlist_lock));
- return NULL;
+ spin_unlock(&(privdata->umemlist_lock));
+ return NULL;
}
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 */
diff --git a/pcilib/error.c b/pcilib/error.c
index ae8bacb..8d25c82 100644
--- a/pcilib/error.c
+++ b/pcilib/error.c
@@ -12,8 +12,17 @@
#define PCILIB_LOGGER_HISTORY 16
void pcilib_print_error(void *arg, const char *file, int line, pcilib_log_priority_t prio, const char *msg, va_list va) {
- vprintf(msg, va);
- printf(" [%s:%d]\n", file, line);
+ size_t size = strlen(msg) + strlen(file) + 64;
+ char *stmp = alloca(size * sizeof(char*));
+
+ if (stmp) {
+ sprintf(stmp, "%s [%s:%d]\n", msg, file, line);
+ vprintf(stmp, va);
+ } else {
+ // Bad for multithreading...
+ vprintf(msg, va);
+ printf(" [%s:%d]\n", file, line);
+ }
}
static void *pcilib_logger_argument = NULL;
diff --git a/pcilib/locking.c b/pcilib/locking.c
index 28aa4c4..71f204e 100644
--- a/pcilib/locking.c
+++ b/pcilib/locking.c
@@ -102,117 +102,118 @@ pcilib_lock_t *pcilib_get_lock_by_id(pcilib_t *ctx, pcilib_lock_id_t id) {
}
pcilib_lock_t *pcilib_get_lock(pcilib_t *ctx, pcilib_lock_flags_t flags, const char *lock_id, ...) {
- pcilib_lock_id_t i;
- int err, ret;
+ pcilib_lock_id_t i;
+ int err, ret;
+
+ pcilib_lock_t *lock;
+ char buffer[PCILIB_LOCK_SIZE];
- pcilib_lock_t *lock;
- char buffer[PCILIB_LOCK_SIZE];
+ /* we construct the complete lock_id given the parameters of the function*/
+ va_list pa;
+ va_start(pa, lock_id);
+ ret = vsnprintf(buffer, PCILIB_LOCK_SIZE, lock_id, pa);
+ va_end(pa);
- /* we construct the complete lock_id given the parameters of the function*/
- va_list pa;
- va_start(pa, lock_id);
- ret = vsnprintf(buffer, PCILIB_LOCK_SIZE, lock_id, pa);
- va_end(pa);
+ if (ret < 0) {
+ pcilib_error("Failed to construct the lock id, probably arguments does not match the format string (%s)...", lock_id);
+ return NULL;
+ }
+
+
+ /* we iterate through locks to see if there is one already with the same name*/
+ // Would be nice to have hash here
+ for (i = 0; i < PCILIB_MAX_LOCKS; i++) {
+ lock = pcilib_get_lock_by_id(ctx, i);
- if (ret < 0) {
- pcilib_error("Failed to construct the lock id, probably arguments does not match the format string (%s)...", lock_id);
- return NULL;
- }
+ const char *name = pcilib_lock_get_name(lock);
+ if (!name) break;
+
+ if (!strcmp(buffer, name)) {
+ if ((pcilib_lock_get_flags(lock)&PCILIB_LOCK_FLAG_PERSISTENT) != (flags&PCILIB_LOCK_FLAG_PERSISTENT)) {
+ if (flags&PCILIB_LOCK_FLAG_PERSISTENT)
+ pcilib_error("Requesting persistent lock (%s), but requested lock is already existing and is robust", name);
+ else
+ pcilib_error("Requesting robust lock (%s), but requested lock is already existing and is persistent", name);
+ return NULL;
+ }
+#ifndef HAVE_STDATOMIC_H
+ if ((flags&PCILIB_LOCK_FLAG_UNLOCKED)==0) {
+ err = pcilib_lock(ctx->locks.locking);
+ if (err) {
+ pcilib_error("Error (%i) obtaining global lock", err);
+ return NULL;
+ }
+ }
+#endif /* ! HAVE_STDATOMIC_H */
+ /* if yes, we increment its ref variable*/
+ pcilib_lock_ref(lock);
+#ifndef HAVE_STDATOMIC_H
+ if ((flags&PCILIB_LOCK_FLAG_UNLOCKED)==0)
+ pcilib_unlock(ctx->locks.locking);
+#endif /* ! HAVE_STDATOMIC_H */
- /* we iterate through locks to see if there is one already with the same name*/
- // Would be nice to have hash here
- for (i = 0; i < PCILIB_MAX_LOCKS; i++) {
- lock = pcilib_get_lock_by_id(ctx, i);
+ return lock;
+ }
+ }
- const char *name = pcilib_lock_get_name(lock);
- if (!name) break;
+ if ((flags&PCILIB_LOCK_FLAG_UNLOCKED)==0) {
+ err = pcilib_lock(ctx->locks.locking);
+ if (err) {
+ pcilib_error("Error (%i) obtaining global lock", err);
+ return NULL;
+ }
+ }
- if (!strcmp(buffer, name)) {
- if ((pcilib_lock_get_flags(lock)&PCILIB_LOCK_FLAG_PERSISTENT) != (flags&PCILIB_LOCK_FLAG_PERSISTENT)) {
- if (flags&PCILIB_LOCK_FLAG_PERSISTENT)
- pcilib_error("Requesting persistent lock (%s), but requested lock is already existing and is robust", name);
- else
- pcilib_error("Requesting robust lock (%s), but requested lock is already existing and is persistent", name);
- return NULL;
- }
+ // Make sure it was not allocated meanwhile
+ for (; i < PCILIB_MAX_LOCKS; i++) {
+ lock = pcilib_get_lock_by_id(ctx, i);
-#ifndef HAVE_STDATOMIC_H
- if ((flags&PCILIB_LOCK_FLAG_UNLOCKED)==0) {
- err = pcilib_lock(ctx->locks.locking);
- if (err) {
- pcilib_error("Error (%i) obtaining global lock", err);
- return NULL;
- }
- }
-#endif /* ! HAVE_STDATOMIC_H */
- /* if yes, we increment its ref variable*/
- pcilib_lock_ref(lock);
- #ifndef HAVE_STDATOMIC_H
- if ((flags&PCILIB_LOCK_FLAG_UNLOCKED)==0)
- pcilib_unlock(ctx->locks.locking);
- #endif /* ! HAVE_STDATOMIC_H */
- return lock;
- }
- }
-
- if ((flags&PCILIB_LOCK_FLAG_UNLOCKED)==0) {
- err = pcilib_lock(ctx->locks.locking);
- if (err) {
- pcilib_error("Error (%i) obtaining global lock", err);
- return NULL;
- }
- }
-
- // Make sure it was not allocated meanwhile
- for (; i < PCILIB_MAX_LOCKS; i++) {
- lock = pcilib_get_lock_by_id(ctx, i);
-
- const char *name = pcilib_lock_get_name(lock);
- if (!name) break;
-
- if (!strcmp(buffer, name)) {
- if ((pcilib_lock_get_flags(lock)&PCILIB_LOCK_FLAG_PERSISTENT) != (flags&PCILIB_LOCK_FLAG_PERSISTENT)) {
- if (flags&PCILIB_LOCK_FLAG_PERSISTENT)
- pcilib_error("Requesting persistent lock (%s), but requested lock is already existing and is robust", name);
- else
- pcilib_error("Requesting robust lock (%s), but requested lock is already existing and is persistent", name);
-
- if ((flags&PCILIB_LOCK_FLAG_UNLOCKED)==0)
- pcilib_unlock(ctx->locks.locking);
- return NULL;
- }
-
- pcilib_lock_ref(lock);
- if ((flags&PCILIB_LOCK_FLAG_UNLOCKED)==0)
- pcilib_unlock(ctx->locks.locking);
- return lock;
- }
- }
-
- if (i == PCILIB_MAX_LOCKS) {
- if ((flags&PCILIB_LOCK_FLAG_UNLOCKED)==0)
- pcilib_unlock(ctx->locks.locking);
- pcilib_error("Failed to create lock (%s), only %u locks is supported", buffer, PCILIB_MAX_LOCKS);
- return NULL;
- }
-
- /* if the lock did not exist before, then we create it*/
- err = pcilib_init_lock(lock, flags, buffer);
-
- if (err) {
- pcilib_error("Lock initialization failed with error %i", err);
-
- if ((flags&PCILIB_LOCK_FLAG_UNLOCKED)==0)
- pcilib_unlock(ctx->locks.locking);
-
- return NULL;
- }
-
- if ((flags&PCILIB_LOCK_FLAG_UNLOCKED)==0)
- pcilib_unlock(ctx->locks.locking);
-
- return lock;
+ const char *name = pcilib_lock_get_name(lock);
+ if (!name) break;
+
+ if (!strcmp(buffer, name)) {
+ if ((pcilib_lock_get_flags(lock)&PCILIB_LOCK_FLAG_PERSISTENT) != (flags&PCILIB_LOCK_FLAG_PERSISTENT)) {
+ if (flags&PCILIB_LOCK_FLAG_PERSISTENT)
+ pcilib_error("Requesting persistent lock (%s), but requested lock is already existing and is robust", name);
+ else
+ pcilib_error("Requesting robust lock (%s), but requested lock is already existing and is persistent", name);
+
+ if ((flags&PCILIB_LOCK_FLAG_UNLOCKED)==0)
+ pcilib_unlock(ctx->locks.locking);
+ return NULL;
+ }
+
+ pcilib_lock_ref(lock);
+ if ((flags&PCILIB_LOCK_FLAG_UNLOCKED)==0)
+ pcilib_unlock(ctx->locks.locking);
+ return lock;
+ }
+ }
+
+ if (i == PCILIB_MAX_LOCKS) {
+ if ((flags&PCILIB_LOCK_FLAG_UNLOCKED)==0)
+ pcilib_unlock(ctx->locks.locking);
+ pcilib_error("Failed to create lock (%s), only %u locks is supported", buffer, PCILIB_MAX_LOCKS);
+ return NULL;
+ }
+
+ /* if the lock did not exist before, then we create it*/
+ err = pcilib_init_lock(lock, flags, buffer);
+
+ if (err) {
+ pcilib_error("Lock initialization failed with error %i", err);
+
+ if ((flags&PCILIB_LOCK_FLAG_UNLOCKED)==0)
+ pcilib_unlock(ctx->locks.locking);
+
+ return NULL;
+ }
+
+ if ((flags&PCILIB_LOCK_FLAG_UNLOCKED)==0)
+ pcilib_unlock(ctx->locks.locking);
+
+ return lock;
}
void pcilib_return_lock(pcilib_t *ctx, pcilib_lock_flags_t flags, pcilib_lock_t *lock) {
diff --git a/pcilib/pci.h b/pcilib/pci.h
index 172a6fc..bfd3796 100644
--- a/pcilib/pci.h
+++ b/pcilib/pci.h
@@ -18,7 +18,7 @@
#include <uthash.h>
#include "linux-3.10.h"
-#include "driver/pciDriver.h"
+#include "driver/ioctl.h"
#include "timing.h"
#include "cpu.h"
diff --git a/pcilib/pcilib.h b/pcilib/pcilib.h
index f1c0dd7..b82e517 100644
--- a/pcilib/pcilib.h
+++ b/pcilib/pcilib.h
@@ -1,5 +1,5 @@
-#ifndef _PCITOOL_PCILIB_H
-#define _PCITOOL_PCILIB_H
+#ifndef _PCILIB_H
+#define _PCILIB_H
#include <sys/time.h>
#include <stddef.h>
@@ -1331,4 +1331,4 @@ int pcilib_convert_value_type(pcilib_t *ctx, pcilib_value_t *val, pcilib_value_t
}
#endif
-#endif /* _PCITOOL_PCILIB_H */
+#endif /* _PCILIB_H */
diff --git a/pcilib/property.c b/pcilib/property.c
index 1dba1be..dfab9a6 100644
--- a/pcilib/property.c
+++ b/pcilib/property.c
@@ -226,8 +226,8 @@ pcilib_property_info_t *pcilib_get_property_list(pcilib_t *ctx, const char *bran
}
HASH_ITER(hh, dir_hash, dir, dir_tmp) {
- HASH_DEL(dir_hash, dir);
- free(dir);
+ HASH_DEL(dir_hash, dir);
+ free(dir);
}
HASH_CLEAR(hh, dir_hash);
diff --git a/pcilib/py.c b/pcilib/py.c
index b8f4800..9e4ca90 100644
--- a/pcilib/py.c
+++ b/pcilib/py.c
@@ -17,6 +17,8 @@
#include "error.h"
#ifdef HAVE_PYTHON
+#define PCILIB_PYTHON_WRAPPER "pcipywrap"
+
typedef struct pcilib_script_s pcilib_script_t;
struct pcilib_script_s {
@@ -43,59 +45,70 @@ void pcilib_log_python_error(const char *file, int line, pcilib_log_flags_t flag
PyGILState_STATE gstate;
PyObject *pytype = NULL;
PyObject *pyval = NULL;
+ PyObject *pystr = NULL;
PyObject *pytraceback = NULL;
gstate = PyGILState_Ensure();
if (PyErr_Occurred()) {
- PyErr_Fetch(&pytype, &pyval, &pytraceback);
-
-#if PY_MAJOR_VERSION >= 3
- type = PyUnicode_AsUTF8(pytype);
- val = PyUnicode_AsUTF8(pyval);
-#else /*PY_MAJOR_VERSION >= 3*/
- PyObject *buf = PyUnicode_AsASCIIString(pytype);
- type = PyString_AsString(buf);
- Py_DecRef(buf);
-
- buf = PyUnicode_AsASCIIString(pyval);
- val = PyString_AsString(buf);
- Py_DecRef(buf);
-#endif /*PY_MAJOR_VERSION >= 3*/
-
-
+ PyErr_Fetch(&pytype, &pyval, &pytraceback);
+ PyErr_NormalizeException(&pytype, &pyval, &pytraceback);
+ if (pyval) pystr = PyObject_Str(pyval);
+
+# if PY_MAJOR_VERSION >= 3
+ if (pytype) {
+ if (PyUnicode_Check(pytype))
+ type = PyUnicode_AsUTF8(pytype);
+ else
+ type = PyExceptionClass_Name(pytype);
+ }
+ if (pystr) {
+ val = PyUnicode_AsUTF8(pystr);
+ }
+# else /* PY_MAJOR_VERSION >= 3 */
+ if (pytype) {
+ if (PyString_Check(pytype))
+ type = PyString_AsString(pytype);
+ else
+ type = PyExceptionClass_Name(pytype);
+ }
+ if (pystr) {
+ val = PyString_AsString(pystr);
+ }
+# endif /*PY_MAJOR_VERSION >= 3*/
}
PyGILState_Release(gstate);
#endif /* HAVE_PYTHON */
-
+
va_start(va, msg);
if (type) {
- char *str;
- size_t len = 32;
-
- if (msg) len += strlen(msg);
- if (type) len += strlen(type);
- if (val) len += strlen(val);
-
- str = alloca(len * sizeof(char));
- if (str) {
- if (msg&&val)
- sprintf(str, "%s <%s: %s>", msg, type, val);
- else if (msg)
- sprintf(str, "%s <%s>", msg, type);
- else if (val)
- sprintf(str, "Python error %s: %s", type, val);
- else
- sprintf(str, "Python error %s", type);
-
- pcilib_log_vmessage(file, line, flags, prio, str, va);
- }
+ char *str;
+ size_t len = 32;
+
+ if (msg) len += strlen(msg);
+ if (type) len += strlen(type);
+ if (val) len += strlen(val);
+
+ str = alloca(len * sizeof(char));
+ if (str) {
+ if (msg&&val)
+ sprintf(str, "%s <%s: %s>", msg, type, val);
+ else if (msg)
+ sprintf(str, "%s <%s>", msg, type);
+ else if (val)
+ sprintf(str, "Python error %s: %s", type, val);
+ else
+ sprintf(str, "Python error %s", type);
+
+ pcilib_log_vmessage(file, line, flags, prio, str, va);
+ }
} else {
- pcilib_log_vmessage(file, line, flags, prio, msg, va);
+ pcilib_log_vmessage(file, line, flags, prio, msg, va);
}
va_end(va);
#ifdef HAVE_PYTHON
+ if (pystr) Py_DECREF(pystr);
if (pytype) Py_DECREF(pytype);
if (pyval) Py_DECREF(pyval);
if (pytraceback) Py_DECREF(pytraceback);
@@ -114,40 +127,39 @@ int pcilib_init_py(pcilib_t *ctx) {
if(!Py_IsInitialized()) {
Py_Initialize();
- // Since python is being initializing from c programm, it needs to initialize threads to work properly with c threads
+ // Since python is being initializing from c programm, it needs to initialize threads to work properly with c threads
PyEval_InitThreads();
PyEval_ReleaseLock();
- ctx->py->finalyze = 1;
+ ctx->py->finalyze = 1;
}
ctx->py->main_module = PyImport_AddModule("__parser__");
if (!ctx->py->main_module) {
- pcilib_python_error("Error importing python parser");
- return PCILIB_ERROR_FAILED;
+ pcilib_python_error("Error importing python parser");
+ return PCILIB_ERROR_FAILED;
}
ctx->py->global_dict = PyModule_GetDict(ctx->py->main_module);
if (!ctx->py->global_dict) {
- pcilib_python_error("Error locating global python dictionary");
- return PCILIB_ERROR_FAILED;
+ pcilib_python_error("Error locating global python dictionary");
+ return PCILIB_ERROR_FAILED;
}
- PyObject *pywrap = PyImport_ImportModule("pcilib");
+ PyObject *pywrap = PyImport_ImportModule(PCILIB_PYTHON_WRAPPER);
if (!pywrap) {
- pcilib_python_error("Error importing pcilib python wrapper");
- return PCILIB_ERROR_FAILED;
+ pcilib_python_error("Error importing pcilib python wrapper");
+ return PCILIB_ERROR_FAILED;
}
- PyObject *mod_name = PyUnicode_FromString("Pcilib");
+ PyObject *mod_name = PyUnicode_FromString(PCILIB_PYTHON_WRAPPER);
PyObject *pyctx = PyCapsule_New(ctx, "pcilib", NULL);
-
ctx->py->pcilib_pywrap = PyObject_CallMethodObjArgs(pywrap, mod_name, pyctx, NULL);
Py_XDECREF(pyctx);
Py_XDECREF(mod_name);
if (!ctx->py->pcilib_pywrap) {
- pcilib_python_error("Error initializing python wrapper");
- return PCILIB_ERROR_FAILED;
+ pcilib_python_error("Error initializing python wrapper");
+ return PCILIB_ERROR_FAILED;
}
#endif /* HAVE_PYTHON */
@@ -167,54 +179,53 @@ int pcilib_py_add_script_dir(pcilib_t *ctx, const char *dir) {
if (!dir) dir = ctx->model;
if (*dir == '/') {
- script_dir = (char*)dir;
+ script_dir = (char*)dir;
} else {
- script_dir = alloca(strlen(model_dir) + strlen(dir) + 2);
- if (!script_dir) return PCILIB_ERROR_MEMORY;
- sprintf(script_dir, "%s/%s", model_dir, dir);
+ script_dir = alloca(strlen(model_dir) + strlen(dir) + 2);
+ if (!script_dir) return PCILIB_ERROR_MEMORY;
+ sprintf(script_dir, "%s/%s", model_dir, dir);
}
pypath = PySys_GetObject("path");
if (!pypath) {
- pcilib_python_error("Can't get python path");
- return PCILIB_ERROR_FAILED;
+ pcilib_python_error("Can't get python path");
+ return PCILIB_ERROR_FAILED;
}
pynewdir = PyUnicode_FromString(script_dir);
-
if (!pynewdir) {
- pcilib_python_error("Can't create python string");
- return PCILIB_ERROR_MEMORY;
+ pcilib_python_error("Can't create python string");
+ return PCILIB_ERROR_MEMORY;
}
- // Checking if the directory already in the path
+ // Checking if the directory already in the path?
pydict = PyDict_New();
if (pydict) {
- pystr = PyUnicode_FromString("cur");
+ pystr = PyUnicode_FromString("cur");
if (pystr) {
- PyDict_SetItem(pydict, pystr, pynewdir);
- Py_DECREF(pystr);
- }
-
- pystr = PyUnicode_FromString("path");
- if (pystr) {
- PyDict_SetItem(pydict, pystr, pypath);
- Py_DECREF(pystr);
- }
-
- pyret = PyRun_String("cur in path", Py_eval_input, ctx->py->global_dict, pydict);
- Py_DECREF(pydict);
+ PyDict_SetItem(pydict, pystr, pynewdir);
+ Py_DECREF(pystr);
+ }
+
+ pystr = PyUnicode_FromString("path");
+ if (pystr) {
+ PyDict_SetItem(pydict, pystr, pypath);
+ Py_DECREF(pystr);
+ }
+
+ pyret = PyRun_String("cur in path", Py_eval_input, ctx->py->global_dict, pydict);
+ Py_DECREF(pydict);
}
if ((pyret == Py_False)&&(PyList_Append(pypath, pynewdir) == -1))
- err = PCILIB_ERROR_FAILED;
+ err = PCILIB_ERROR_FAILED;
if (pyret) Py_DECREF(pyret);
Py_DECREF(pynewdir);
if (err) {
- pcilib_python_error("Can't add directory (%s) to python path", script_dir);
- return err;
+ pcilib_python_error("Can't add directory (%s) to python path", script_dir);
+ return err;
}
#endif /* HAVE_PYTHON */
@@ -226,24 +237,24 @@ void pcilib_free_py(pcilib_t *ctx) {
int finalyze = 0;
if (ctx->py) {
- if (ctx->py->finalyze) finalyze = 1;
-
- if (ctx->py->script_hash) {
- pcilib_script_t *script, *script_tmp;
-
- HASH_ITER(hh, ctx->py->script_hash, script, script_tmp) {
- Py_DECREF(script->module);
- HASH_DEL(ctx->py->script_hash, script);
- free(script);
- }
- ctx->py->script_hash = NULL;
- }
-
- if (ctx->py->pcilib_pywrap)
- Py_DECREF(ctx->py->pcilib_pywrap);
-
- free(ctx->py);
- ctx->py = NULL;
+ if (ctx->py->finalyze) finalyze = 1;
+
+ if (ctx->py->script_hash) {
+ pcilib_script_t *script, *script_tmp;
+
+ HASH_ITER(hh, ctx->py->script_hash, script, script_tmp) {
+ Py_DECREF(script->module);
+ HASH_DEL(ctx->py->script_hash, script);
+ free(script);
+ }
+ ctx->py->script_hash = NULL;
+ }
+
+ if (ctx->py->pcilib_pywrap)
+ Py_DECREF(ctx->py->pcilib_pywrap);
+
+ free(ctx->py);
+ ctx->py = NULL;
}
if (finalyze)
@@ -262,8 +273,8 @@ int pcilib_py_load_script(pcilib_t *ctx, const char *script_name) {
char *py = strrchr(module_name, '.');
if ((!py)||(strcasecmp(py, ".py"))) {
- pcilib_error("Invalid script name (%s) is specified", script_name);
- return PCILIB_ERROR_INVALID_ARGUMENT;
+ pcilib_error("Invalid script name (%s) is specified", script_name);
+ return PCILIB_ERROR_INVALID_ARGUMENT;
}
*py = 0;
@@ -272,8 +283,8 @@ int pcilib_py_load_script(pcilib_t *ctx, const char *script_name) {
pymodule = PyImport_ImportModule(module_name);
if (!pymodule) {
- pcilib_python_error("Error importing script (%s)", script_name);
- return PCILIB_ERROR_FAILED;
+ pcilib_python_error("Error importing script (%s)", script_name);
+ return PCILIB_ERROR_FAILED;
}
module = (pcilib_script_t*)malloc(sizeof(pcilib_script_t));
@@ -297,26 +308,26 @@ int pcilib_py_get_transform_script_properties(pcilib_t *ctx, const char *script_
HASH_FIND_STR(ctx->py->script_hash, script_name, module);
if(!module) {
- pcilib_error("Script (%s) is not loaded yet", script_name);
- return PCILIB_ERROR_NOTFOUND;
+ pcilib_error("Script (%s) is not loaded yet", script_name);
+ return PCILIB_ERROR_NOTFOUND;
}
dict = PyModule_GetDict(module->module);
if (!dict) {
- pcilib_python_error("Error getting dictionary for script (%s)", script_name);
- return PCILIB_ERROR_FAILED;
+ pcilib_python_error("Error getting dictionary for script (%s)", script_name);
+ return PCILIB_ERROR_FAILED;
}
pystr = PyUnicode_FromString("read_from_register");
if (pystr) {
- if (PyDict_Contains(dict, pystr)) mode |= PCILIB_ACCESS_R;
- Py_DECREF(pystr);
+ if (PyDict_Contains(dict, pystr)) mode |= PCILIB_ACCESS_R;
+ Py_DECREF(pystr);
}
pystr = PyUnicode_FromString("write_to_register");
if (pystr) {
- if (PyDict_Contains(dict, pystr)) mode |= PCILIB_ACCESS_W;
- Py_DECREF(pystr);
+ if (PyDict_Contains(dict, pystr)) mode |= PCILIB_ACCESS_W;
+ Py_DECREF(pystr);
}
#endif /* HAVE_PYTHON */
@@ -335,28 +346,28 @@ pcilib_py_object *pcilib_get_value_as_pyobject(pcilib_t* ctx, pcilib_value_t *va
gstate = PyGILState_Ensure();
switch(val->type) {
- case PCILIB_TYPE_LONG:
- ival = pcilib_get_value_as_int(ctx, val, &err);
- if (!err) res = (PyObject*)PyLong_FromLong(ival);
- break;
- case PCILIB_TYPE_DOUBLE:
- fval = pcilib_get_value_as_float(ctx, val, &err);
- if (!err) res = (PyObject*)PyFloat_FromDouble(fval);
- break;
- default:
- PyGILState_Release(gstate);
- pcilib_error("Can't convert pcilib value of type (%lu) to PyObject", val->type);
- if (ret) *ret = PCILIB_ERROR_NOTSUPPORTED;
- return NULL;
+ case PCILIB_TYPE_LONG:
+ ival = pcilib_get_value_as_int(ctx, val, &err);
+ if (!err) res = (PyObject*)PyLong_FromLong(ival);
+ break;
+ case PCILIB_TYPE_DOUBLE:
+ fval = pcilib_get_value_as_float(ctx, val, &err);
+ if (!err) res = (PyObject*)PyFloat_FromDouble(fval);
+ break;
+ default:
+ PyGILState_Release(gstate);
+ pcilib_error("Can't convert pcilib value of type (%lu) to PyObject", val->type);
+ if (ret) *ret = PCILIB_ERROR_NOTSUPPORTED;
+ return NULL;
}
PyGILState_Release(gstate);
if (err) {
- if (ret) *ret = err;
- return NULL;
+ if (ret) *ret = err;
+ return NULL;
} else if (!res) {
- if (ret) *ret = PCILIB_ERROR_MEMORY;
- return res;
+ if (ret) *ret = PCILIB_ERROR_MEMORY;
+ return res;
}
if (ret) *ret = 0;
@@ -374,25 +385,27 @@ int pcilib_set_value_from_pyobject(pcilib_t* ctx, pcilib_value_t *val, pcilib_py
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
-#if PY_MAJOR_VERSION < 3
- if (PyInt_Check(pyval)) {
- err = pcilib_set_value_from_int(ctx, val, PyInt_AsLong(pyval));
- } else if (PyString_Check(pyval)) {
- err = pcilib_set_value_from_string(ctx, val, PyString_AsString(pyval));
- } else
-#endif /*PY_MAJOR_VERSION >= 3*/
if (PyLong_Check(pyval)) {
err = pcilib_set_value_from_int(ctx, val, PyLong_AsLong(pyval));
} else if (PyFloat_Check(pyval)) {
err = pcilib_set_value_from_float(ctx, val, PyFloat_AsDouble(pyval));
+#if PY_MAJOR_VERSION < 3
+ } else if (PyInt_Check(pyval)) {
+ err = pcilib_set_value_from_int(ctx, val, PyInt_AsLong(pyval));
+ } else if (PyString_Check(pyval)) {
+ err = pcilib_set_value_from_string(ctx, val, PyString_AsString(pyval));
} else if (PyUnicode_Check(pyval)) {
-#if PY_MAJOR_VERSION >= 3
- err = pcilib_set_value_from_string(ctx, val, PyUnicode_AsUTF8(pyval));
-#else /*PY_MAJOR_VERSION >= 3*/
PyObject *buf = PyUnicode_AsASCIIString(pyval);
- err = pcilib_set_value_from_string(ctx, val, PyString_AsString(buf));
- Py_DecRef(buf);
-#endif /*PY_MAJOR_VERSION >= 3*/
+ if (buf) {
+ err = pcilib_set_value_from_string(ctx, val, PyString_AsString(buf));
+ Py_DecRef(buf);
+ } else {
+ err = PCILIB_ERROR_FAILED;
+ }
+#else /* PY_MAJOR_VERSION < 3 */
+ } else if (PyUnicode_Check(pyval)) {
+ err = pcilib_set_value_from_string(ctx, val, PyUnicode_AsUTF8(pyval));
+#endif /* PY_MAJOR_VERSION < 3 */
} else {
PyGILState_Release(gstate);
pcilib_error("Can't convert PyObject to polymorphic pcilib value");
@@ -453,7 +466,7 @@ static char *pcilib_py_parse_string(pcilib_t *ctx, const char *codestr, pcilib_v
strcpy(dst + offset, cur);
offset += reg - cur;
- // find the end of the register name
+ // find the end of the register name
reg++;
if (*reg == '{') {
reg++;
@@ -469,7 +482,7 @@ static char *pcilib_py_parse_string(pcilib_t *ctx, const char *codestr, pcilib_v
save = reg[i];
reg[i] = 0;
- // determine replacement value
+ // determine replacement value
if (!strcasecmp(reg, "value")) {
if (!value) {
pcilib_error("Python formula (%s) relies on the value of register, but it is not provided", codestr);
@@ -497,7 +510,7 @@ static char *pcilib_py_parse_string(pcilib_t *ctx, const char *codestr, pcilib_v
if (save == '}') i++;
else reg[i] = save;
- // Advance to the next register if any
+ // Advance to the next register if any
cur = reg + i;
reg = strchr(cur, '$');
}
@@ -507,8 +520,8 @@ static char *pcilib_py_parse_string(pcilib_t *ctx, const char *codestr, pcilib_v
free(src);
if (err) {
- free(dst);
- return NULL;
+ free(dst);
+ return NULL;
}
return dst;
@@ -562,22 +575,22 @@ int pcilib_py_eval_func(pcilib_t *ctx, const char *script_name, const char *func
HASH_FIND_STR(ctx->py->script_hash, script_name, module);
if (!module) {
- pcilib_error("Script (%s) is not loaded", script_name);
- return PCILIB_ERROR_NOTFOUND;
+ pcilib_error("Script (%s) is not loaded", script_name);
+ return PCILIB_ERROR_NOTFOUND;
}
if (val) {
- pyval = pcilib_get_value_as_pyobject(ctx, val, &err);
- if (err) return err;
+ pyval = pcilib_get_value_as_pyobject(ctx, val, &err);
+ if (err) return err;
}
PyGILState_STATE gstate = PyGILState_Ensure();
pyfunc = PyUnicode_FromString(func_name);
if (!pyfunc) {
- if (pyval) Py_DECREF(pyval);
- PyGILState_Release(gstate);
- return PCILIB_ERROR_MEMORY;
+ if (pyval) Py_DECREF(pyval);
+ PyGILState_Release(gstate);
+ return PCILIB_ERROR_MEMORY;
}
pyret = PyObject_CallMethodObjArgs(module->module, pyfunc, ctx->py->pcilib_pywrap, pyval, NULL);
@@ -586,13 +599,13 @@ int pcilib_py_eval_func(pcilib_t *ctx, const char *script_name, const char *func
Py_DECREF(pyval);
if (!pyret) {
- PyGILState_Release(gstate);
- pcilib_python_error("Error executing function (%s) of python script (%s)", func_name, script_name);
- return PCILIB_ERROR_FAILED;
+ PyGILState_Release(gstate);
+ pcilib_python_error("Error executing function (%s) of python script (%s)", func_name, script_name);
+ return PCILIB_ERROR_FAILED;
}
if ((val)&&(pyret != Py_None))
- err = pcilib_set_value_from_pyobject(ctx, val, pyret);
+ err = pcilib_set_value_from_pyobject(ctx, val, pyret);
Py_DECREF(pyret);
PyGILState_Release(gstate);
diff --git a/pyserver/api_server.py b/pyserver/api_server.py
index 736d521..7e8b7ef 100644
--- a/pyserver/api_server.py
+++ b/pyserver/api_server.py
@@ -516,7 +516,7 @@ class ApiServer(MultiThreadedHTTPServer):
#redirect logs to exeption
pcilib.redirect_logs_to_exeption()
#pass Pcipywrap to to server handler
- self.lib = pcilib.Pcilib(device, model)
+ self.lib = pcilib.pcilib(device, model)
def handler(*args):
PcilibServerHandler(self.lib, *args)
MultiThreadedHTTPServer.__init__(self, adress, handler)
diff --git a/xml/scripts/test_script.py b/pyserver/scripts/test_script.py
index 8f236e9..8f236e9 100644
--- a/xml/scripts/test_script.py
+++ b/pyserver/scripts/test_script.py
diff --git a/xml/scripts/test_script2.py b/pyserver/scripts/test_script2.py
index 16e4adb..16e4adb 100644
--- a/xml/scripts/test_script2.py
+++ b/pyserver/scripts/test_script2.py
diff --git a/pywrap/CMakeLists.txt b/pywrap/CMakeLists.txt
index 4cc51da..033298e 100644
--- a/pywrap/CMakeLists.txt
+++ b/pywrap/CMakeLists.txt
@@ -22,6 +22,5 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pcipywrap.py DESTINATION ${PYTHON_INST
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pcilib.py DESTINATION ${PYTHON_INSTALL_DIR})
if (NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
- file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/pcilib.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/test_pcilib.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
endif(NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
diff --git a/pywrap/pcilib.py b/pywrap/pcilib.py
index 7696524..f4976bf 100644
--- a/pywrap/pcilib.py
+++ b/pywrap/pcilib.py
@@ -2,9 +2,9 @@ from pcipywrap import *
import os
import sys
-class Pcilib(Pcipywrap):
+class pcilib(pcipywrap):
def __init__(s, *args):
- Pcipywrap.__init__(s, *args)
+ pcipywrap.__init__(s, *args)
#load scripts
scripts_dir = os.environ.get('PCILIB_SCRIPTS_DIR')
diff --git a/pywrap/pcipywrap.c b/pywrap/pcipywrap.c
index a1092be..cb99ce2 100644
--- a/pywrap/pcipywrap.c
+++ b/pywrap/pcipywrap.c
@@ -322,7 +322,7 @@ PyObject * pcilib_convert_register_info_to_pyobject(pcilib_t* ctx, pcilib_regist
}
-Pcipywrap *new_Pcipywrap(const char* fpga_device, const char* model)
+pcipywrap *new_pcipywrap(const char* fpga_device, const char* model)
{
//opening device
pcilib_t* ctx = pcilib_open(fpga_device, model);
@@ -331,14 +331,14 @@ Pcipywrap *new_Pcipywrap(const char* fpga_device, const char* model)
set_python_exception("Failed pcilib_open(%s, %s)", fpga_device, model);
return NULL;
}
- Pcipywrap *self;
- self = (Pcipywrap *) malloc(sizeof(Pcipywrap));
+ pcipywrap *self;
+ self = (pcipywrap *) malloc(sizeof(pcipywrap));
self->shared = 0;
self->ctx = ctx;
return self;
}
-Pcipywrap *create_Pcipywrap(PyObject* ctx)
+pcipywrap *create_pcipywrap(PyObject* ctx)
{
if(!PyCapsule_CheckExact(ctx))
{
@@ -346,22 +346,22 @@ Pcipywrap *create_Pcipywrap(PyObject* ctx)
return NULL;
}
- Pcipywrap *self;
- self = (Pcipywrap *) malloc(sizeof(Pcipywrap));
+ pcipywrap *self;
+ self = (pcipywrap *) malloc(sizeof(pcipywrap));
self->shared = 1;
self->ctx = PyCapsule_GetPointer(ctx, PyCapsule_GetName(ctx));
return self;
}
-void delete_Pcipywrap(Pcipywrap *self) {
+void delete_pcipywrap(pcipywrap *self) {
if(!self->shared)
pcilib_close(self->ctx);
free(self);
}
-PyObject* Pcipywrap_read_register(Pcipywrap *self, const char *regname, const char *bank)
+PyObject* pcipywrap_read_register(pcipywrap *self, const char *regname, const char *bank)
{
pcilib_value_t val = {0};
pcilib_register_value_t reg_value;
@@ -385,7 +385,7 @@ PyObject* Pcipywrap_read_register(Pcipywrap *self, const char *regname, const ch
return pcilib_get_value_as_pyobject(self->ctx, &val, NULL);
}
-PyObject* Pcipywrap_write_register(Pcipywrap *self, PyObject* val, const char *regname, const char *bank)
+PyObject* pcipywrap_write_register(pcipywrap *self, PyObject* val, const char *regname, const char *bank)
{
pcilib_value_t val_internal = {0};
pcilib_register_value_t reg_value;
@@ -419,7 +419,7 @@ PyObject* Pcipywrap_write_register(Pcipywrap *self, PyObject* val, const char *r
return PyLong_FromLong((long)1);
}
-PyObject* Pcipywrap_get_property(Pcipywrap *self, const char *prop)
+PyObject* pcipywrap_get_property(pcipywrap *self, const char *prop)
{
int err;
pcilib_value_t val = {0};
@@ -435,7 +435,7 @@ PyObject* Pcipywrap_get_property(Pcipywrap *self, const char *prop)
return pcilib_get_value_as_pyobject(self->ctx, &val, NULL);
}
-PyObject* Pcipywrap_set_property(Pcipywrap *self, PyObject* val, const char *prop)
+PyObject* pcipywrap_set_property(pcipywrap *self, PyObject* val, const char *prop)
{
int err;
@@ -457,7 +457,7 @@ PyObject* Pcipywrap_set_property(Pcipywrap *self, PyObject* val, const char *pro
return PyLong_FromLong((long)1);
}
-PyObject* Pcipywrap_get_registers_list(Pcipywrap *self, const char *bank)
+PyObject* pcipywrap_get_registers_list(pcipywrap *self, const char *bank)
{
pcilib_register_info_t *list = pcilib_get_register_list(self->ctx, bank, PCILIB_LIST_FLAGS_DEFAULT);
@@ -477,7 +477,7 @@ PyObject* Pcipywrap_get_registers_list(Pcipywrap *self, const char *bank)
return pyList;
}
-PyObject* Pcipywrap_get_register_info(Pcipywrap *self, const char* reg,const char *bank)
+PyObject* pcipywrap_get_register_info(pcipywrap *self, const char* reg,const char *bank)
{
pcilib_register_info_t *info = pcilib_get_register_info(self->ctx, bank, reg, PCILIB_LIST_FLAGS_DEFAULT);
@@ -493,7 +493,7 @@ PyObject* Pcipywrap_get_register_info(Pcipywrap *self, const char* reg,const cha
return py_info;
}
-PyObject* Pcipywrap_get_property_list(Pcipywrap *self, const char* branch)
+PyObject* pcipywrap_get_property_list(pcipywrap *self, const char* branch)
{
pcilib_property_info_t *list = pcilib_get_property_list(self->ctx, branch, PCILIB_LIST_FLAGS_DEFAULT);
@@ -511,7 +511,7 @@ PyObject* Pcipywrap_get_property_list(Pcipywrap *self, const char* branch)
return pyList;
}
-PyObject* Pcipywrap_read_dma(Pcipywrap *self, unsigned char dma, size_t size)
+PyObject* pcipywrap_read_dma(pcipywrap *self, unsigned char dma, size_t size)
{
int err;
void* buf = NULL;
@@ -532,7 +532,7 @@ PyObject* Pcipywrap_read_dma(Pcipywrap *self, unsigned char dma, size_t size)
return py_buf;
}
-PyObject* Pcipywrap_lock_global(Pcipywrap *self)
+PyObject* pcipywrap_lock_global(pcipywrap *self)
{
int err;
@@ -546,13 +546,13 @@ PyObject* Pcipywrap_lock_global(Pcipywrap *self)
return PyLong_FromLong((long)1);
}
-void Pcipywrap_unlock_global(Pcipywrap *self)
+void pcipywrap_unlock_global(pcipywrap *self)
{
pcilib_unlock_global(self->ctx);
return;
}
-PyObject* Pcipywrap_lock(Pcipywrap *self, const char *lock_id)
+PyObject* pcipywrap_lock(pcipywrap *self, const char *lock_id)
{
pcilib_lock_t* lock = pcilib_get_lock(self->ctx,
PCILIB_LOCK_FLAG_PERSISTENT,
@@ -574,7 +574,7 @@ PyObject* Pcipywrap_lock(Pcipywrap *self, const char *lock_id)
return PyLong_FromLong((long)1);
}
-PyObject* Pcipywrap_try_lock(Pcipywrap *self, const char *lock_id)
+PyObject* pcipywrap_try_lock(pcipywrap *self, const char *lock_id)
{
pcilib_lock_t* lock = pcilib_get_lock(self->ctx,
PCILIB_LOCK_FLAG_PERSISTENT,
@@ -595,7 +595,7 @@ PyObject* Pcipywrap_try_lock(Pcipywrap *self, const char *lock_id)
return PyLong_FromLong((long)1);
}
-PyObject* Pcipywrap_unlock(Pcipywrap *self, const char *lock_id)
+PyObject* pcipywrap_unlock(pcipywrap *self, const char *lock_id)
{
pcilib_lock_t* lock = pcilib_get_lock(self->ctx,
PCILIB_LOCK_FLAG_PERSISTENT,
diff --git a/pywrap/pcipywrap.h b/pywrap/pcipywrap.h
index 0258f04..1b71a56 100644
--- a/pywrap/pcipywrap.h
+++ b/pywrap/pcipywrap.h
@@ -8,7 +8,7 @@
typedef struct {
void* ctx;
int shared;
-} Pcipywrap;
+} pcipywrap;
/*!
* \brief Redirect pcilib standart log stream to exeption text.
@@ -26,9 +26,9 @@ void redirect_logs_to_exeption();
*/
PyObject* create_pcilib_instance(const char *fpga_device, const char *model);
-Pcipywrap *new_Pcipywrap(const char* fpga_device, const char* model);
-Pcipywrap *create_Pcipywrap(PyObject* ctx);
-void delete_Pcipywrap(Pcipywrap *self);
+pcipywrap *new_pcipywrap(const char* fpga_device, const char* model);
+pcipywrap *create_pcipywrap(PyObject* ctx);
+void delete_pcipywrap(pcipywrap *self);
/*!
* \brief Reads register value. Wrap for pcilib_read_register function.
@@ -36,7 +36,7 @@ void delete_Pcipywrap(Pcipywrap *self);
* \param[in] bank should specify the bank name if register with the same name may occur in multiple banks, NULL otherwise
* \return register value, can be integer or float type; NULL with exeption text, if failed.
*/
-PyObject* Pcipywrap_read_register(Pcipywrap *self, const char *regname, const char *bank);
+PyObject* pcipywrap_read_register(pcipywrap *self, const char *regname, const char *bank);
/*!
* \brief Writes value to register. Wrap for pcilib_write_register function.
@@ -45,14 +45,14 @@ PyObject* Pcipywrap_read_register(Pcipywrap *self, const char *regname, const ch
* \param[in] bank should specify the bank name if register with the same name may occur in multiple banks, NULL otherwise
* \return 1, serialized to PyObject or NULL with exeption text, if failed.
*/
-PyObject* Pcipywrap_write_register(Pcipywrap *self, PyObject* val, const char *regname, const char *bank);
+PyObject* pcipywrap_write_register(pcipywrap *self, PyObject* val, const char *regname, const char *bank);
/*!
* \brief Reads propety value. Wrap for pcilib_get_property function.
* \param[in] prop property name (full name including path)
* \return property value, can be integer or float type; NULL with exeption text, if failed.
*/
-PyObject* Pcipywrap_get_property(Pcipywrap *self, const char *prop);
+PyObject* pcipywrap_get_property(pcipywrap *self, const char *prop);
/*!
* \brief Writes value to property. Wrap for pcilib_set_property function.
@@ -60,27 +60,27 @@ PyObject* Pcipywrap_get_property(Pcipywrap *self, const char *prop);
* \param[in] val Property value, that needs to be set. Can be int, float or string.
* \return 1, serialized to PyObject or NULL with exeption text, if failed.
*/
-PyObject* Pcipywrap_set_property(Pcipywrap *self, PyObject* val, const char *prop);
-PyObject* Pcipywrap_get_registers_list(Pcipywrap *self, const char *bank);
-PyObject* Pcipywrap_get_register_info(Pcipywrap *self, const char* reg,const char *bank);
-PyObject* Pcipywrap_get_property_list(Pcipywrap *self, const char* branch);
+PyObject* pcipywrap_set_property(pcipywrap *self, PyObject* val, const char *prop);
+PyObject* pcipywrap_get_registers_list(pcipywrap *self, const char *bank);
+PyObject* pcipywrap_get_register_info(pcipywrap *self, const char* reg,const char *bank);
+PyObject* pcipywrap_get_property_list(pcipywrap *self, const char* branch);
-PyObject* Pcipywrap_read_dma(Pcipywrap *self, unsigned char dma, size_t size);
+PyObject* pcipywrap_read_dma(pcipywrap *self, unsigned char dma, size_t size);
-PyObject* Pcipywrap_lock_global(Pcipywrap *self);
-void Pcipywrap_unlock_global(Pcipywrap *self);
+PyObject* pcipywrap_lock_global(pcipywrap *self);
+void pcipywrap_unlock_global(pcipywrap *self);
/*!
* \brief Wrap for pcilib_lock
* \param lock_id lock identificator
* \warning This function should be called only under Python standart threading lock.
- * Otherwise it will stuck with more than 1 threads. See /xml/test/test_prop_mt.py
+ * Otherwise it will stuck with more than 1 threads. See /xml/test/test_prop4.py
* for example.
* \return 1, serialized to PyObject or NULL with exeption text, if failed.
*/
-PyObject* Pcipywrap_lock(Pcipywrap *self, const char *lock_id);
+PyObject* pcipywrap_lock(pcipywrap *self, const char *lock_id);
-PyObject* Pcipywrap_try_lock(Pcipywrap *self, const char *lock_id);
-PyObject* Pcipywrap_unlock(Pcipywrap *self, const char *lock_id);
+PyObject* pcipywrap_try_lock(pcipywrap *self, const char *lock_id);
+PyObject* pcipywrap_unlock(pcipywrap *self, const char *lock_id);
#endif /* PCIPYWRAP_H */
diff --git a/pywrap/pcipywrap.i b/pywrap/pcipywrap.i
index 7749a67..5ee1bd1 100644
--- a/pywrap/pcipywrap.i
+++ b/pywrap/pcipywrap.i
@@ -8,9 +8,9 @@ extern void redirect_logs_to_exeption();
typedef struct {
%extend {
- Pcipywrap(const char* fpga_device = "/dev/fpga0", const char* model = NULL);
- Pcipywrap(PyObject* ctx){return create_Pcipywrap(ctx);}
- ~Pcipywrap();
+ pcipywrap(const char* fpga_device = "/dev/fpga0", const char* model = NULL);
+ pcipywrap(PyObject* ctx){return create_pcipywrap(ctx);}
+ ~pcipywrap();
PyObject* read_register(const char *regname = NULL, const char *bank = NULL);
PyObject* write_register(PyObject* val, const char *regname, const char *bank = NULL);
@@ -30,4 +30,4 @@ typedef struct {
PyObject* try_lock(const char *lock_id);
PyObject* unlock(const char *lock_id);
}
-} Pcipywrap;
+} pcipywrap;
diff --git a/pywrap/test_pcilib.py b/pywrap/test_pcilib.py
index aed2dc3..398d975 100644
--- a/pywrap/test_pcilib.py
+++ b/pywrap/test_pcilib.py
@@ -35,7 +35,7 @@ class test_pcilib():
#create pcilib_instance
self.device = device
self.model = model
- self.pcilib = pcilib.Pcilib(device, model)
+ self.pcilib = pcilib.pcilib(device, model)
self.num_threads = num_threads
self.write_percentage = write_percentage
self.register = register
@@ -83,7 +83,7 @@ class test_pcilib():
try:
while(1):
val = long(random.randint(0, 8096))
- self.pcilib = pcilib.Pcilib(self.device, self.model)
+ self.pcilib = pcilib.pcilib(self.device, self.model)
print(self.pcilib.get_property_list(self.branch))
print(self.pcilib.get_register_info(self.register))
print(self.pcilib.get_registers_list())
@@ -145,7 +145,7 @@ if __name__ == '__main__':
type="string", dest="device", default=str('/dev/fpga0'),
help="FPGA device (/dev/fpga0)")
parser.add_option("-m", "--model", action="store",
- type="string", dest="model", default=None,
+ type="string", dest="model", default=str('test'),
help="Memory model (autodetected)")
parser.add_option("-t", "--threads", action="store",
type="int", dest="threads", default=150,
diff --git a/run b/run
index 6c322c5..ebc558b 100755
--- a/run
+++ b/run
@@ -2,8 +2,4 @@
APP_PATH=`dirname $0`
-PYTHONPATH="$APP_PATH/pywrap:$PYTHONPATH" \
-PCILIB_MODEL_DIR="$APP_PATH/xml" \
-LD_LIBRARY_PATH="$APP_PATH/pcilib" \
-PCILIB_SCRIPTS_DIR="$APP_PATH/xml/scripts" \
-$*
+PYTHONPATH="$APP_PATH/pywrap:$PYTHONPATH" PCILIB_SCRIPTS_DIR="$APP_PATH/pyserver/scripts" PCILIB_MODEL_DIR="$APP_PATH/xml" LD_LIBRARY_PATH="$APP_PATH/pcilib" $*
diff --git a/xml/test/props.xml b/xml/test/props.xml
index dc08cbe..750881d 100644
--- a/xml/test/props.xml
+++ b/xml/test/props.xml
@@ -3,9 +3,5 @@
<transform path="/test/prop1" register="test_prop1" unit="C" read_from_register="(503975./1024000)*${/registers/fpga/sensor_temperature:C} - 27315./100" description="formula to get real fpga temperature from the fpga_temperature register in decimal"/>
<transform path="/test/prop2" register="test_prop2" unit="C" script="test_prop2.py" description="test python script #1" write_verification="0" />
<transform path="/test/prop3" register="test_prop3" unit="C" script="test_prop3.py" description="test python script #2" />
- <transform path="/test/prop_mt"
- register="test_prop_mt"
- unit="C"
- script="test_prop_mt.py"
- description="Example of thread safe python property"/>
+ <transform path="/test/prop4" register="test_prop4" unit="C" script="test_prop4.py" description="Example of thread safe python property"/>
</model>
diff --git a/xml/test/test_prop2.py b/xml/test/test_prop2.py
index d78dbea..8a3ebf6 100644
--- a/xml/test/test_prop2.py
+++ b/xml/test/test_prop2.py
@@ -1,6 +1,5 @@
def read_from_register(ctx, value):
return ctx.get_property('/test/prop3') / 2
-
+
def write_to_register(ctx, value):
ctx.set_property(value*2, '/test/prop3')
-
diff --git a/xml/test/test_prop_mt.py b/xml/test/test_prop4.py
index 224a80c..a7e0269 100644
--- a/xml/test/test_prop_mt.py
+++ b/xml/test/test_prop4.py
@@ -4,21 +4,21 @@ lock = threading.Lock()
def read_from_register(ctx, value):
with lock:
- ctx.lock('lock12')
-
+ ctx.lock('test_prop4')
+
cur = read_from_register.counter
read_from_register.counter += 1
for i in range (0, 5):
time.sleep(0.1)
print(cur)
out = ctx.get_property('/test/prop3') / 2
- ctx.unlock('lock12')
-
+
+ ctx.unlock('test_prop4')
+
return out
-
-
+
read_from_register.counter = 0
-
+
def write_to_register(ctx, value):
with lock:
ctx.set_property(value*2, '/test/prop3')