]> jspc29.x-matter.uni-frankfurt.de Git - trbnettools.git/commitdiff
initial release kernel module for pexor onlinux
authorhadaq <hadaq>
Mon, 10 Oct 2011 21:50:09 +0000 (21:50 +0000)
committerhadaq <hadaq>
Mon, 10 Oct 2011 21:50:09 +0000 (21:50 +0000)
pexor/kernel-module/Makefile [new file with mode: 0644]
pexor/kernel-module/load_pexor.sh [new file with mode: 0755]
pexor/kernel-module/pexor_trb.c [new file with mode: 0644]
pexor/kernel-module/pexor_trb.h [new file with mode: 0644]
pexor/kernel-module/pexor_user.h [new file with mode: 0644]

diff --git a/pexor/kernel-module/Makefile b/pexor/kernel-module/Makefile
new file mode 100644 (file)
index 0000000..356b906
--- /dev/null
@@ -0,0 +1,12 @@
+obj-m  := pexor.o
+
+pexor-objs := pexor_trb.o 
+
+KERNELDIR ?= /lib/modules/$(shell uname -r)/build
+PWD       := $(shell pwd)
+
+all:
+       $(MAKE) -C $(KERNELDIR) M=$(PWD)
+
+clean:
+       rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module.* modules.order
diff --git a/pexor/kernel-module/load_pexor.sh b/pexor/kernel-module/load_pexor.sh
new file mode 100755 (executable)
index 0000000..d587399
--- /dev/null
@@ -0,0 +1,5 @@
+#! /bin/bash
+echo "load_pexor..."
+sudo /sbin/insmod pexor.ko
+sudo /bin/chmod 666  /dev/pexor*
+echo "                 done."
diff --git a/pexor/kernel-module/pexor_trb.c b/pexor/kernel-module/pexor_trb.c
new file mode 100644 (file)
index 0000000..0e2b65a
--- /dev/null
@@ -0,0 +1,1445 @@
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/cdev.h>
+#include <linux/sysfs.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/highmem.h>
+#include <linux/scatterlist.h>
+#include <linux/vmalloc.h>
+
+#include "pexor_user.h"
+#include "pexor_trb.h"
+
+//#define PEXOR_DEBUGPRINT
+//#define PEXOR_TRB_DEBUG
+
+#ifdef PEXOR_DEBUGPRINT
+#define pexor_dbg( args... ) \
+  printk( args );
+#else
+#define pexor_dbg( args... ) ;
+#endif
+
+
+#define pexor_msg( args... ) \
+  printk( args );
+
+/* ---------------------------------------------------------------------- */
+
+#define PEXORNAME     "pexor"
+#define PEXORNAMEFMT  "pexor-%d"
+
+#define PEXOR_VENDOR_ID 0x1204
+#define PEXOR_DEVICE_ID 0x5303
+#define PEXOR_MAX_DEVS 4
+static dev_t pexor_major;
+static struct class *pexor_class;
+static dev_t pexor_devt;
+static int my_major_nr = 0;
+
+struct dev_pexor
+{
+  u32 *irq_control;             /* irq control register */
+  u32 *irq_status;              /* irq status register */
+  u32 *dma_control_stat;        /* dma control and statusregister */
+  u32 *dma_source;              /* dma source address */
+  u32 *dma_dest;                /* dma destination address */
+  u32 *dma_len;                 /* dma length */
+  u32 *dma_burstsize;           /* dma burstsize, <=0x80 */
+  u32 *dma_statbits;            /* optional further status bits */
+  u32 *dma_credits;             /* credits */
+  u32 *dma_counts;              /* counter values */
+  u32 *ram_start;               /* RAM start */
+  u32 *ram_end;                 /* RAM end */
+  dma_addr_t ram_dma_base;      /* RAM start expressed as dma address */
+  dma_addr_t ram_dma_cursor;    /* cursor for next dma to issue start */
+  u32 *trbnet_sender_err[PEXOR_TRB_NUM_CHANNELS];
+  u32 *trbnet_sender_data[PEXOR_TRB_NUM_CHANNELS];
+  u32 *trbnet_receiver_data[PEXOR_TRB_NUM_CHANNELS];
+  u32 *trbnet_sender_ctl[PEXOR_TRB_NUM_CHANNELS];
+  u32 *trbnet_dma_ctl[PEXOR_TRB_NUM_CHANNELS];
+  u32 *trbnet_sender_trigger_info;
+  u32 *dma_debug0;
+  u32 *dma_debug1;
+
+  unsigned char init_done;      /* object is ready flag */
+};
+
+#define DMA_BUFFER_NUM_PAGES ((8 * 1024 * 1024) / PAGE_SIZE)
+#define PEXOR_DMA_MAXPOLLS 10000
+#define PEXOR_DMA_POLLDELAY 0
+#define PEXOR_MEMWRITE_SIZE 128
+
+struct pexor_dma
+{
+  void *buffer;
+  size_t size;
+  int nr_pages;
+  struct scatterlist *sglist;
+  int nr_sglist;
+};
+
+struct pexor_privdata
+{
+  atomic_t state;               /* run state of device */
+  dev_t devno;                  /* device number (major and minor) */
+  int devid;                    /* local id (counter number) */
+  struct pci_dev *pdev;         /* PCI device */
+  struct device *class_dev;     /* Class device */
+  struct cdev cdev;             /* char device struct */
+  struct dev_pexor pexor;       /* mapped pexor address pointers */
+  unsigned long bases[6];       /* contains pci resource bases */
+  unsigned long reglen[6];      /* contains pci resource length */
+  void *iomem[6];               /* points to mapped io memory of the bars */
+  struct semaphore sem;         /* lock semaphore */
+  spinlock_t dma_lock;          /* protects DMA Buffer */
+
+  struct pexor_dma dma;         /* dma buffer */
+  u32 *memwrite_buffer;         /* buffer for register_write_mem */
+  int magic;                    /* magic number to identify irq */
+};
+
+/* ---------------------------------------------------------------------- */
+
+#ifdef PEXOR_DEBUGPRINT
+static unsigned char get_pci_revision(struct pci_dev *dev);
+#endif
+
+ssize_t pexor_sysfs_codeversion_show(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf);
+
+void test_pci(struct pci_dev *dev);
+
+void cleanup_device(struct pexor_privdata *priv);
+
+struct pexor_privdata *get_privdata(struct file *filp);
+
+void set_pexor(struct dev_pexor *pg, void *membase, unsigned long bar);
+
+static int probe(struct pci_dev *dev, const struct pci_device_id *id);
+
+int pexor_open(struct inode *inode, struct file *filp);
+
+int pexor_release(struct inode *inode, struct file *filp);
+
+ssize_t pexor_read(struct file *filp, char __user * buf, size_t count,
+                   loff_t * f_pos);
+
+ssize_t pexor_write(struct file *filp, const char __user * buf, size_t count,
+                    loff_t * f_pos);
+
+loff_t pexor_llseek(struct file *filp, loff_t off, int whence);
+
+int pexor_mmap(struct file *filp, struct vm_area_struct *vma);
+
+int pexor_ioctl_read_register(struct pexor_privdata *priv, unsigned long arg);
+
+int pexor_ioctl_write_register(struct pexor_privdata *priv,
+                               unsigned long arg);
+
+int pexor_ioctl_trbnet_request(struct pexor_privdata *priv,
+                               unsigned long arg);
+
+int pexor_ioctl(struct inode *inode, struct file *filp,
+                unsigned int cmd, unsigned long arg);
+
+static void remove(struct pci_dev *dev);
+
+static int __init pexor_init(void);
+
+static void __exit pexor_exit(void);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
+long pexor_unlocked_ioctl(struct file *filp,
+                          unsigned int cmd, unsigned long arg);
+#endif
+
+static int pexor_alloc_dma_buffer(struct pexor_privdata *priv, size_t size);
+
+static int pexor_free_dma_buffer(struct pexor_privdata *priv);
+
+/* ---------------------------------------------------------------------- */
+
+static struct file_operations pexor_fops = {
+  .owner = THIS_MODULE,
+  .llseek = pexor_llseek,
+  .read = pexor_read,
+  .write = pexor_write,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
+  .unlocked_ioctl = pexor_unlocked_ioctl,
+#else
+  .ioctl = pexor_ioctl,
+#endif
+  .mmap = pexor_mmap,
+  .open = pexor_open,
+  .release = pexor_release,
+};
+
+static struct pci_device_id ids[] = {
+  {PCI_DEVICE(PEXOR_VENDOR_ID, PEXOR_DEVICE_ID),},
+  {0,},
+};
+
+static struct pci_driver pci_driver = {
+  .name = PEXORNAME,
+  .id_table = ids,
+  .probe = probe,
+  .remove = remove,
+};
+
+
+
+
+//static DEVICE_ATTR(freebufs, S_IRUGO, pexor_sysfs_freebuffers_show, NULL);
+//static DEVICE_ATTR(usedbufs, S_IRUGO, pexor_sysfs_usedbuffers_show, NULL);
+//static DEVICE_ATTR(rcvbufs, S_IRUGO, pexor_sysfs_rcvbuffers_show, NULL);
+static DEVICE_ATTR(codeversion, S_IRUGO, pexor_sysfs_codeversion_show, NULL);
+//static DEVICE_ATTR(dmaregs, S_IRUGO, pexor_sysfs_dmaregs_show, NULL);
+
+#ifdef PEXOR_WITH_SFP
+static DEVICE_ATTR(sfpregs, S_IRUGO, pexor_sysfs_sfpregs_show, NULL);
+#endif
+
+static atomic_t pexor_numdevs = ATOMIC_INIT(0);
+
+/* ---------------------------------------------------------------------- */
+
+struct pexor_privdata *get_privdata(struct file *filp)
+{
+  struct pexor_privdata *privdata;
+  privdata = (struct pexor_privdata *)filp->private_data;
+  if (privdata->pexor.init_done == 0) {
+    pexor_dbg(KERN_ERR "*** PEXOR structure was not initialized!\n");
+    return NULL;
+  }
+  return privdata;
+}
+
+#ifdef PEXOR_DEBUGPRINT
+static unsigned char get_pci_revision(struct pci_dev *dev)
+{
+  u8 revision;
+  pci_read_config_byte(dev, PCI_REVISION_ID, &revision);
+  return revision;
+}
+#endif
+
+static void remove(struct pci_dev *dev)
+{
+  struct pexor_privdata *priv = (struct pexor_privdata *)pci_get_drvdata(dev);
+  cleanup_device(priv);
+
+  pexor_free_dma_buffer(priv);
+  if (priv->memwrite_buffer != NULL) {
+    vfree(priv->memwrite_buffer);
+  }
+  pexor_msg(KERN_NOTICE "PEXOR pci driver end remove.\n");
+}
+
+ssize_t pexor_sysfs_codeversion_show(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+  char vstring[1024];
+  ssize_t curs = 0;
+#ifdef PEXOR_WITH_SFP
+  struct dev_pexor *pg;
+#endif
+  struct pexor_privdata *privdata;
+  privdata = (struct pexor_privdata *)dev_get_drvdata(dev);
+  curs = snprintf(vstring, 1024,
+                  "*** This is PEXOR driver version %s build on %s at %s \n\t",
+                  PEXORVERSION, __DATE__, __TIME__);
+#ifdef PEXOR_WITH_SFP
+  pg = &(privdata->pexor);
+  pexor_show_version(&(pg->sfp), vstring + curs);
+#endif
+  return snprintf(buf, PAGE_SIZE, "%s\n", vstring);
+}
+
+
+void test_pci(struct pci_dev *dev)
+{
+  int bar = 0;
+  u32 originalvalue = 0;
+  u32 base = 0;
+  u16 comstat = 0;
+  u8 typ = 0;
+
+  pexor_dbg(KERN_NOTICE "\n test_pci found PCI revision number %x\n",
+            get_pci_revision(dev));
+
+  /*********** test the address regions*/
+  for (bar = 0; bar < 6; bar++) {
+    pexor_dbg(KERN_NOTICE "Resource %d start=%x\n", bar,
+              (unsigned)pci_resource_start(dev, bar));
+    pexor_dbg(KERN_NOTICE "Resource %d end=%x\n", bar,
+              (unsigned)pci_resource_end(dev, bar));
+    pexor_dbg(KERN_NOTICE "Resource %d len=%x\n", bar,
+              (unsigned)pci_resource_len(dev, bar));
+    pexor_dbg(KERN_NOTICE "Resource %d flags=%x\n", bar,
+              (unsigned)pci_resource_flags(dev, bar));
+    if ((pci_resource_flags(dev, bar) & IORESOURCE_IO)) {
+      /* Ressource im IO-Adressraum */
+      pexor_dbg(KERN_NOTICE " - resource is IO\n");
+    }
+    if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM)) {
+      pexor_dbg(KERN_NOTICE " - resource is MEM\n");
+    }
+    if ((pci_resource_flags(dev, bar) & PCI_BASE_ADDRESS_SPACE_IO)) {
+      pexor_dbg(KERN_NOTICE " - resource is PCI IO\n");
+    }
+    if ((pci_resource_flags(dev, bar) & PCI_BASE_ADDRESS_SPACE_MEMORY)) {
+      pexor_dbg(KERN_NOTICE " - resource is PCI MEM\n");
+    }
+    if ((pci_resource_flags(dev, bar) & PCI_BASE_ADDRESS_MEM_PREFETCH)) {
+      pexor_dbg(KERN_NOTICE " - resource prefetch bit is set \n");
+    }
+    if ((pci_resource_flags(dev, bar) & PCI_BASE_ADDRESS_MEM_TYPE_64)) {
+      pexor_dbg(KERN_NOTICE " - resource is 64bit address \n");
+    }
+    if ((pci_resource_flags(dev, bar) & PCI_BASE_ADDRESS_MEM_TYPE_32)) {
+      pexor_dbg(KERN_NOTICE " - resource is 32bit address \n");
+    }
+    if ((pci_resource_flags(dev, bar) & IORESOURCE_PREFETCH)) {
+      pexor_dbg(KERN_NOTICE " - resource is prefetchable \n");
+    }
+    if ((pci_resource_flags(dev, bar) & PCI_BASE_ADDRESS_MEM_PREFETCH)) {
+      pexor_dbg(KERN_NOTICE " - resource is PCI mem prefetchable \n");
+    }
+    if ((pci_resource_flags(dev, bar) & PCI_BASE_ADDRESS_MEM_TYPE_1M)) {
+      pexor_dbg(KERN_NOTICE " - resource is PCI memtype below 1M \n");
+    }
+  }
+
+  pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &originalvalue);
+  pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0xffffffff);
+  pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &base);
+  pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, originalvalue);
+  pexor_dbg("size of base address 0: %i\n", ~base + 1);
+  pci_read_config_dword(dev, PCI_BASE_ADDRESS_1, &originalvalue);
+  pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0xffffffff);
+  pci_read_config_dword(dev, PCI_BASE_ADDRESS_1, &base);
+  pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, originalvalue);
+  pexor_dbg("size of base address 1: %i\n", ~base + 1);
+  pci_read_config_dword(dev, PCI_BASE_ADDRESS_2, &originalvalue);
+  pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, 0xffffffff);
+  pci_read_config_dword(dev, PCI_BASE_ADDRESS_2, &base);
+  pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, originalvalue);
+  pexor_dbg("size of base address 2: %i\n", ~base + 1);
+  pci_read_config_dword(dev, PCI_BASE_ADDRESS_3, &originalvalue);
+  pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, 0xffffffff);
+  pci_read_config_dword(dev, PCI_BASE_ADDRESS_3, &base);
+  pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, originalvalue);
+  pexor_dbg("size of base address 3: %i\n", ~base + 1);
+
+  /***** here tests of configuration/status register:******/
+  pci_read_config_word(dev, PCI_COMMAND, &comstat);
+  pexor_dbg("\n****  Command register is: %d\n", comstat);
+  pci_read_config_word(dev, PCI_STATUS, &comstat);
+  pexor_dbg("\n****  Status register is: %d\n", comstat);
+  pci_read_config_byte(dev, PCI_HEADER_TYPE, &typ);
+  pexor_dbg("\n****  Header type is: %d\n", typ);
+}
+
+void cleanup_device(struct pexor_privdata *priv)
+{
+  int j = 0;
+  struct pci_dev *pcidev;
+
+  if (!priv) {
+    return;
+  }
+
+  /* sysfs device cleanup */
+  if (priv->class_dev) {
+#ifdef PEXOR_WITH_SFP
+    device_remove_file(priv->class_dev, &dev_attr_sfpregs);
+#endif
+    //device_remove_file(priv->class_dev, &dev_attr_dmaregs);
+    device_remove_file(priv->class_dev, &dev_attr_codeversion);
+    //device_remove_file(priv->class_dev, &dev_attr_rcvbufs);
+    //device_remove_file(priv->class_dev, &dev_attr_usedbufs);
+    //device_remove_file(priv->class_dev, &dev_attr_freebufs);
+    device_destroy(pexor_class, priv->devno);
+    priv->class_dev = 0;
+  }
+
+  /* character device cleanup */
+  if (priv->cdev.owner) {
+    cdev_del(&priv->cdev);
+  }
+  if (priv->devid) {
+    atomic_dec(&pexor_numdevs);
+  }
+  pcidev = priv->pdev;
+  if (!pcidev) {
+    return;
+  }
+
+  for (j = 0; j < 6; j++) {
+    if (priv->bases[j] == 0)
+      continue;
+    if ((pci_resource_flags(pcidev, j) & IORESOURCE_IO)) {
+      pexor_dbg(KERN_NOTICE " releasing IO region at:%lx -len:%lx \n",
+                priv->bases[j], priv->reglen[j]);
+      release_region(priv->bases[j], priv->reglen[j]);
+    } else {
+      if (priv->iomem[j] != 0) {
+        pexor_dbg(KERN_NOTICE
+                  " unmapping virtual MEM region at:%lx -len:%lx \n",
+                  (unsigned long)priv->iomem[j], priv->reglen[j]);
+        iounmap(priv->iomem[j]);
+      }
+      pexor_dbg(KERN_NOTICE " releasing MEM region at:%lx -len:%lx \n",
+                priv->bases[j], priv->reglen[j]);
+      release_mem_region(priv->bases[j], priv->reglen[j]);
+    }
+    priv->bases[j] = 0;
+    priv->reglen[j] = 0;
+  }
+  kfree(priv);
+  pci_disable_device(pcidev);
+}
+
+
+void set_pexor(struct dev_pexor *pg, void *membase, unsigned long bar)
+{
+  int i = 0;
+  void *dmabase = 0;
+
+  if (pg == NULL)
+    return;
+  dmabase = membase + PEXOR_DMA_BASE;
+
+#ifdef PEXOR_WITH_SFP
+  set_sfp(&(pg->sfp), membase, bar);
+#endif
+
+  pg->dma_control_stat = (u32 *) (dmabase + (PEXOR_TRB_DMA_CTL << 2));
+  pg->dma_source = (u32 *) (dmabase + 0xff0);
+  pg->dma_dest = (u32 *) (dmabase + (PEXOR_TRB_DMA_ADD << 2));
+  pg->dma_len = (u32 *) (dmabase + (PEXOR_TRB_DMA_LEN << 2));
+  pg->dma_burstsize = (u32 *) (dmabase + (PEXOR_TRB_DMA_BST << 2));
+  pg->dma_statbits = (u32 *) (dmabase + (PEXOR_TRB_DMA_STA << 2));
+  pg->dma_credits = (u32 *) (dmabase + (PEXOR_TRB_DMA_CRE << 2));
+  pg->dma_counts = (u32 *) (dmabase + (PEXOR_TRB_DMA_CNT << 2));
+
+  pg->trbnet_sender_trigger_info =
+    (u32 *) (membase + (PEXOR_TRB_SENDER_TRIGGER_INFO << 2));
+  for (i = 0; i < PEXOR_TRB_NUM_CHANNELS; i++) {
+    pg->trbnet_sender_err[i] = (u32 *)
+      (membase + ((PEXOR_TRB_SENDER_ERROR | ((i * 2 + 1) << 4)) << 2));
+    pg->trbnet_sender_data[i] = (u32 *)
+      (membase + ((PEXOR_TRB_SENDER_DATA | ((i * 2 + 1) << 4)) << 2));
+    pg->trbnet_receiver_data[i] = (u32 *)
+      (membase + ((PEXOR_TRB_RECEIVER_DATA | ((i * 2 + 1) << 4)) << 2));
+    pg->trbnet_sender_ctl[i] = (u32 *)
+      (membase + ((PEXOR_TRB_SENDER_CONTROL | ((i * 2 + 1) << 4)) << 2));
+    pg->trbnet_dma_ctl[i] = (u32 *) (membase + (PEXOR_TRB_DMA_CRE << 2));
+  }
+
+
+  pg->dma_debug0 = (u32 *) (membase + (0xe00 << 2));
+  pg->dma_debug1 = (u32 *) (membase + (0xe01 << 2));
+
+  pg->init_done = 0x1;
+  pexor_dbg(KERN_NOTICE "** Set pexor structure %lx.\n",
+            (long unsigned int)pg);
+}
+
+static int probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+  int err = 0, ix = 0;
+
+  struct pexor_privdata *privdata;
+  pexor_msg(KERN_NOTICE "PEXOR pci driver starts probe...\n");
+  if ((err = pci_enable_device(dev)) != 0) {
+    pexor_msg(KERN_ERR
+              "PEXOR pci driver probe: Error %d enabling PCI device! \n",
+              err);
+    return -ENODEV;
+  }
+  pexor_dbg(KERN_NOTICE "PEXOR Device is enabled.\n");
+
+  /* Set Memory-Write-Invalidate support */
+  if (!pci_set_mwi(dev)) {
+    pexor_dbg(KERN_NOTICE "MWI enabled.\n");
+  } else {
+    pexor_dbg(KERN_NOTICE "MWI not supported.\n");
+  }
+  pci_set_master(dev);          /* NOTE: DMA worked without, but maybe 
+                                   depends on bios */
+
+  test_pci(dev);
+
+  /* Allocate and initialize the private data for this device */
+  privdata = kmalloc(sizeof(struct pexor_privdata), GFP_KERNEL);
+  if (privdata == NULL) {
+    cleanup_device(privdata);
+    return -ENOMEM;
+  }
+  memset(privdata, 0, sizeof(struct pexor_privdata));
+  pci_set_drvdata(dev, privdata);
+  privdata->pdev = dev;
+  privdata->magic = PEXOR_DEVICE_ID;    /* for irq test TODO: what if multiple 
+                                           pexors share same irq? */
+
+  atomic_set(&(privdata->state), PEXOR_STATE_STOPPED);
+
+  for (ix = 0; ix < 6; ix++) {
+    privdata->bases[ix] = pci_resource_start(dev, ix);
+    privdata->reglen[ix] = pci_resource_len(dev, ix);
+    if (privdata->bases[ix] == 0)
+      continue;
+    if ((pci_resource_flags(dev, ix) & IORESOURCE_IO)) {
+
+      pexor_dbg(KERN_NOTICE " - Requesting io ports for bar %d\n", ix);
+      if (request_region(privdata->bases[ix], privdata->reglen[ix],
+                         dev->dev.kobj.name) == NULL) {
+        pexor_dbg(KERN_ERR
+                  "I/O address conflict at bar %d for device \"%s\"\n", ix,
+                  dev->dev.kobj.name);
+        cleanup_device(privdata);
+        return -EIO;
+      }
+      pexor_dbg("requested ioport at %lx with length %lx\n",
+                privdata->bases[ix], privdata->reglen[ix]);
+    } else if ((pci_resource_flags(dev, ix) & IORESOURCE_MEM)) {
+      pexor_dbg(KERN_NOTICE " - Requesting memory region for bar %d\n", ix);
+      if (request_mem_region(privdata->bases[ix], privdata->reglen[ix],
+                             dev->dev.kobj.name) == NULL) {
+        pexor_dbg(KERN_ERR
+                  "Memory address conflict at bar %d for device \"%s\"\n", ix,
+                  dev->dev.kobj.name);
+        cleanup_device(privdata);
+        return -EIO;
+      }
+      pexor_dbg("requested memory at %lx with length %lx\n",
+                privdata->bases[ix], privdata->reglen[ix]);
+      privdata->iomem[ix] =
+        ioremap_nocache(privdata->bases[ix], privdata->reglen[ix]);
+      if (privdata->iomem[ix] == NULL) {
+        pexor_dbg(KERN_ERR
+                  "Could not remap memory  at bar %d for device \"%s\"\n", ix,
+                  dev->dev.kobj.name);
+        cleanup_device(privdata);
+        return -EIO;
+      }
+      pexor_dbg("remapped memory to %lx with length %lx\n",
+                (unsigned long)privdata->iomem[ix], privdata->reglen[ix]);
+    }
+  }                             //for
+  set_pexor(&(privdata->pexor), privdata->iomem[0], privdata->bases[0]);
+
+  //print_pexor(&(privdata->pexor));
+
+  sema_init(&(privdata->sem), 1);
+  spin_lock_init(&(privdata->dma_lock));
+
+  /* TODO may use rw semaphore instead? init_rwsem(struct 
+     rw_semaphore *sem); */
+
+
+  ////////////////// here chardev registering
+  privdata->devid = atomic_inc_return(&pexor_numdevs) - 1;
+  if (privdata->devid >= PEXOR_MAX_DEVS) {
+    pexor_msg(KERN_ERR
+              "Maximum number of devices reached! Increase MAXDEVICES.\n");
+    cleanup_device(privdata);
+    return -ENOMSG;
+  }
+
+  privdata->devno
+    = MKDEV(MAJOR(pexor_devt), MINOR(pexor_devt) + privdata->devid);
+
+  /* Register character device */
+  cdev_init(&(privdata->cdev), &pexor_fops);
+  privdata->cdev.owner = THIS_MODULE;
+  privdata->cdev.ops = &pexor_fops;
+  err = cdev_add(&privdata->cdev, privdata->devno, 1);
+  if (err) {
+    pexor_msg("Couldn't add character device.\n");
+    cleanup_device(privdata);
+    return err;
+  }
+
+  /* TODO: export special things to class in sysfs ? */
+
+
+  if (!IS_ERR(pexor_class)) {
+    /* driver init had successfully created class, now we create device: */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+    privdata->class_dev = device_create(pexor_class, NULL, privdata->devno,
+                                        privdata, PEXORNAMEFMT,
+                                        MINOR(pexor_devt) + privdata->devid);
+#else
+    privdata->class_dev = device_create(pexor_class, NULL, privdata->devno,
+                                        PEXORNAMEFMT,
+                                        MINOR(pexor_devt) + privdata->devid);
+#endif
+    dev_set_drvdata(privdata->class_dev, privdata);
+    pexor_msg(KERN_NOTICE "Added PEXOR device: %s-%d\n",
+              PEXORNAME, MINOR(pexor_devt) + privdata->devid);
+
+#if 0
+    if (device_create_file(privdata->class_dev, &dev_attr_freebufs) != 0) {
+      pexor_msg(KERN_ERR
+                "Could not add device file node for free buffers.\n");
+    }
+    if (device_create_file(privdata->class_dev, &dev_attr_usedbufs) != 0) {
+      pexor_msg(KERN_ERR
+                "Could not add device file node for used buffers.\n");
+    }
+    if (device_create_file(privdata->class_dev, &dev_attr_rcvbufs) != 0) {
+      pexor_msg(KERN_ERR
+                "Could not add device file node for receive buffers.\n");
+    }
+#endif
+    if (device_create_file(privdata->class_dev, &dev_attr_codeversion) != 0) {
+      pexor_msg(KERN_ERR
+                "Could not add device file node for code version.\n");
+    }
+#if 0
+    if (device_create_file(privdata->class_dev, &dev_attr_dmaregs) != 0) {
+      pexor_msg(KERN_ERR
+                "Could not add device file node for dma registers.\n");
+    }
+#endif
+#ifdef PEXOR_WITH_SFP
+    if (device_create_file(privdata->class_dev, &dev_attr_sfpregs) != 0) {
+      pexor_msg(KERN_ERR
+                "Could not add device file node for sfp registers.\n");
+    }
+#endif
+
+  } else {
+    /* something was wrong at class creation, we skip sysfs device 
+       support here: */
+    pexor_msg(KERN_ERR "Could not add PEXOR device node to /dev !");
+  }
+
+  /* init pexor_dma buffer */
+  if (pexor_alloc_dma_buffer(privdata, DMA_BUFFER_NUM_PAGES * PAGE_SIZE) != 0) {
+    pexor_msg(KERN_ERR "ERROR> probe init dma  failed\n");
+    return -EFAULT;
+  }
+
+  /* allocate memwrite_buffer */
+  privdata->memwrite_buffer = vmalloc_32(PEXOR_MEMWRITE_SIZE * 4);
+  if (privdata->memwrite_buffer == NULL) {
+    pexor_msg(KERN_ERR "ERROR> probe allocate memwrite_buffer failed\n");
+    return -ENOMEM;
+  }
+
+  pexor_msg(KERN_NOTICE "probe has finished.\n");
+  return 0;
+}
+
+int pexor_open(struct inode *inode, struct file *filp)
+{
+  struct pexor_privdata *privdata;
+  pexor_dbg(KERN_NOTICE "** starting pexor_open...\n");
+  /* Set the private data area for the file */
+  privdata = container_of(inode->i_cdev, struct pexor_privdata, cdev);
+  filp->private_data = privdata;
+  return 0;
+}
+
+int pexor_release(struct inode *inode, struct file *filp)
+{
+  pexor_dbg(KERN_NOTICE "** starting pexor_release...\n");
+  return 0;
+}
+
+loff_t pexor_llseek(struct file * filp, loff_t off, int whence)
+{
+  return 0;
+}
+
+ssize_t pexor_read(struct file * filp,
+                   char __user * buf, size_t count, loff_t * f_pos)
+{
+  /* here we read from dma buffer */
+  struct pexor_privdata *privdata;
+  ssize_t retval = 0;
+
+  /*  u32 kbuf[lcount]; */
+  pexor_dbg(KERN_NOTICE "** starting pexor_read for f_pos=%d count=%d\n",
+            (int)*f_pos, (int)count);
+  privdata = get_privdata(filp);
+  if (privdata == NULL) {
+    return -EFAULT;
+  }
+  if (count > privdata->dma.size) {
+    return -EFAULT;
+  }
+
+  if (down_interruptible(&privdata->sem) != 0) {
+    return -ERESTARTSYS;
+  }
+  if (copy_to_user(buf, privdata->dma.buffer, count)) {
+    retval = -EFAULT;
+    goto out_read;
+  }
+  *f_pos += count;
+  retval = count;
+
+out_read:
+  up(&privdata->sem);
+  return retval;
+}
+
+ssize_t pexor_write(struct file * filp,
+                    const char __user * buf, size_t count, loff_t * f_pos)
+{
+  /* here we read from dma buffer */
+  struct pexor_privdata *privdata;
+  ssize_t retval = 0;
+
+  /*  u32 kbuf[lcount]; */
+  pexor_dbg(KERN_NOTICE "** starting pexor_write for f_pos=%d count=%d\n",
+            (int)*f_pos, (int)count);
+  privdata = get_privdata(filp);
+  if (privdata == NULL) {
+    return -EFAULT;
+  }
+  if (count > 4 * PEXOR_MEMWRITE_SIZE) {
+    return -EFAULT;
+  }
+
+  if (down_interruptible(&privdata->sem) != 0) {
+    return -ERESTARTSYS;
+  }
+  if (copy_from_user((void *)privdata->memwrite_buffer, buf, count)) {
+    retval = -EFAULT;
+    goto out_read;
+  }
+  *f_pos += count;
+  retval = count;
+
+out_read:
+  up(&privdata->sem);
+  return retval;
+}
+
+int pexor_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+  struct pexor_privdata *privdata;
+  char *vmalloc_area_ptr = NULL;
+  unsigned long size;
+  unsigned long start;
+  unsigned long pfn;
+  int ret = 0;
+
+  privdata = get_privdata(filp);
+  pexor_dbg(KERN_NOTICE "** starting pexor_mmap...\n");
+
+  if (privdata == NULL)
+    return -EFAULT;
+
+  vmalloc_area_ptr = privdata->dma.buffer;
+  start = vma->vm_start;
+  size = (vma->vm_end - vma->vm_start);
+
+  pexor_dbg(KERN_NOTICE
+            "** starting pexor_mmap for s:%lx e:%lx size=%ld\n",
+            vma->vm_start, vma->vm_end, size);
+
+  if (size > privdata->dma.size) {
+    return -EFAULT;
+  }
+
+  while (size > 0) {
+    pfn = vmalloc_to_pfn(vmalloc_area_ptr);
+    if ((ret = remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED)) < 0) {
+      pexor_dbg(KERN_ERR "kmem remap failed: %d (%p)\n",
+                ret, privdata->dma.buffer);
+      return ret;
+    }
+    start += PAGE_SIZE;
+    vmalloc_area_ptr += PAGE_SIZE;
+    size -= PAGE_SIZE;
+  }
+
+#if 0
+  /* map kernel addresses to vma */
+  //  vma->vm_flags |= (VM_RESERVED); /* TODO: do we need this?*/
+  /* der scheiss geht nicht!!! */
+  ret = remap_vmalloc_range(vma, privdata->dma.buffer, 0);
+#endif
+
+  return 0;
+}
+
+int pexor_ioctl_read_register(struct pexor_privdata *priv, unsigned long arg)
+{
+  int retval = 0;
+  u32 *ad = 0;
+  u32 val = 0;
+  int bar = 0;
+  struct pexor_reg_io descriptor;
+  retval =
+    copy_from_user(&descriptor, (void __user *)arg,
+                   sizeof(struct pexor_reg_io));
+  if (retval)
+    return retval;
+  ad = (u32 *) (ptrdiff_t) descriptor.address;
+  pexor_dbg(KERN_NOTICE "** pexor_ioctl_reading from register address %p\n",
+            ad);
+  bar = descriptor.bar;
+  if ((bar > 5) || priv->iomem[bar] == 0) {
+    pexor_msg(KERN_ERR "** pexor_ioctl_read_register: no mapped bar %d\n",
+              bar);
+    return -EIO;
+  }
+  pexor_dbg(KERN_NOTICE
+            "** pexor_ioctl_read_register reads from address %p within "
+            "bar %d \n", ad, bar);
+  if ((unsigned long)ad > priv->reglen[bar]) {
+    pexor_msg(KERN_ERR
+              "** pexor_ioctl_read_register: address %p is exceeding "
+              "length %lx of bar %d\n", ad, priv->reglen[bar], bar);
+    return -EIO;
+  }
+  ad = (u32 *) ((unsigned long)priv->iomem[bar] + (unsigned long)ad);
+  val = ioread32(ad);
+  mb();
+  ndelay(20);
+  pexor_dbg(KERN_NOTICE
+            "** pexor_ioctl_read_register read value %x from mapped "
+            "PCI address %p !\n", val, ad);
+  descriptor.value = val;
+  retval =
+    copy_to_user((void __user *)arg, &descriptor,
+                 sizeof(struct pexor_reg_io));
+  return retval;
+}
+
+int pexor_ioctl_write_register(struct pexor_privdata *priv, unsigned long arg)
+{
+  int retval = 0;
+  u32 *ad = 0;
+  u32 val = 0;
+  int bar = 0;
+  struct pexor_reg_io descriptor;
+  retval =
+    copy_from_user(&descriptor, (void __user *)arg,
+                   sizeof(struct pexor_reg_io));
+  if (retval)
+    return retval;
+  /* here we assume something for this very connection, to be adjusted later */
+  ad = (u32 *) (ptrdiff_t) descriptor.address;
+  val = (u32) descriptor.value;
+  bar = descriptor.bar;
+  if ((bar > 5) || priv->iomem[bar] == 0) {
+    pexor_msg(KERN_ERR "** pexor_ioctl_write_register: no mapped bar %d\n",
+              bar);
+    return -EIO;
+  }
+  pexor_dbg(KERN_NOTICE
+            "** pexor_ioctl_write_register writes value %x to address %p "
+            "within bar %d \n", val, ad, bar);
+  if ((unsigned long)ad > priv->reglen[bar]) {
+    pexor_msg(KERN_ERR
+              "** pexor_ioctl_write_register: address %p is exceeding "
+              "length %lx of bar %d\n", ad, priv->reglen[bar], bar);
+    return -EIO;
+  }
+  ad = (u32 *) ((unsigned long)priv->iomem[bar] + (unsigned long)ad);
+  pexor_dbg(KERN_NOTICE
+            "** pexor_ioctl_write_register writes value %x to mapped "
+            "PCI address %p !\n", val, ad);
+  iowrite32(val, ad);
+  mb();
+  ndelay(20);
+  return retval;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
+long pexor_unlocked_ioctl(struct file *filp,
+                          unsigned int cmd, unsigned long arg)
+{
+  long ret;
+
+  lock_kernel();
+  ret = pexor_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
+  unlock_kernel();
+
+  return ret;
+}
+#endif
+
+int pexor_ioctl(struct inode *inode, struct file *filp,
+                unsigned int cmd, unsigned long arg)
+{
+  struct pexor_privdata *privdata;
+  /* here validity check for magic number etc. */
+
+  privdata = get_privdata(filp);
+  if (!privdata)
+    return -EFAULT;
+  /* Select the appropiate command */
+  switch (cmd) {
+
+    /* first all common ioctls: */
+
+  case PEXOR_IOC_WRITE_REGISTER:
+    pexor_dbg(KERN_NOTICE "** pexor_ioctl write register\n");
+    return pexor_ioctl_write_register(privdata, arg);
+    break;
+
+  case PEXOR_IOC_READ_REGISTER:
+    pexor_dbg(KERN_NOTICE "** pexor_ioctl read register\n");
+    return pexor_ioctl_read_register(privdata, arg);
+    break;
+
+
+    /* special ioctls for different protocol implementations: */
+
+  case PEXOR_IOC_TRBNET_REQUEST:
+    pexor_dbg(KERN_NOTICE "** pexor_ioctl trbnet request \n");
+    return pexor_ioctl_trbnet_request(privdata, arg);
+    break;
+
+  default:
+    return -ENOTTY;
+  }
+  return -ENOTTY;
+}
+
+static int __init pexor_init(void)
+{
+
+  int result;
+  pexor_msg(KERN_NOTICE "pexor driver init...\n");
+
+  pexor_devt = MKDEV(my_major_nr, 0);
+
+  /*
+   * Register your major, and accept a dynamic number.
+   */
+  if (my_major_nr)
+    result = register_chrdev_region(pexor_devt, PEXOR_MAX_DEVS, PEXORNAME);
+  else {
+    result = alloc_chrdev_region(&pexor_devt, 0, PEXOR_MAX_DEVS, PEXORNAME);
+    my_major_nr = MAJOR(pexor_devt);
+  }
+  if (result < 0)
+    return result;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
+  pexor_class = class_create(THIS_MODULE, PEXORNAME);
+  if (IS_ERR(pexor_class)) {
+    pexor_msg(KERN_ALERT "Could not create class for sysfs support!\n");
+  }
+#endif
+
+  if (pci_register_driver(&pci_driver) < 0) {
+    pexor_msg(KERN_ALERT "pci driver could not register!\n");
+    unregister_chrdev_region(pexor_devt, PEXOR_MAX_DEVS);
+    return -EIO;
+  }
+
+  pexor_msg(KERN_NOTICE
+            "\t\tdriver init with registration for major no %d done.\n",
+            my_major_nr);
+  return 0;
+
+  /* note: actual assignment will be done on probe time */
+
+
+}
+
+#if 0
+int __init pexor_init(void)
+{
+  dev_t dev;
+  int result;
+  pexor_msg(KERN_NOTICE "pexor driver init...\n");
+
+  /* Register a dynamic major number */
+  result = alloc_chrdev_region(&dev, 0, PEXOR_MAX_DEVS, PEXORNAME);
+  if (result != 0) {
+    pexor_msg(KERN_ALERT "failed to get a major number for pexor\n");
+    goto out_init;
+  }
+  pexor_major = MAJOR(dev);
+
+  /* create module class */
+  pexor_class = class_create(THIS_MODULE, PEXORNAME);
+  if (IS_ERR(pexor_class)) {
+    result = PTR_ERR(pexor_class);
+    pexor_msg(KERN_ALERT
+              "could not create class for sysfs support, error = %x\n",
+              result);
+    goto out_unreg_chrdev;
+  }
+
+  /* register PCI driver */
+  result = pci_register_driver(&pci_driver);
+  if (result != 0) {
+    pexor_msg(KERN_ALERT "could not register pexor pci driver\n");
+    goto out_unreg_chrdev;
+  }
+
+  pexor_msg(KERN_NOTICE
+            "\t\tdriver init with registration for major no %d done.\n",
+            pexor_major);
+
+  pexor_devt = dev;
+
+  return 0;
+
+  /* note: actual assignment will be done on probe time */
+
+out_unreg_chrdev:
+  unregister_chrdev_region(MKDEV(pexor_major, 0), PEXOR_MAX_DEVS);
+
+out_init:
+  return result;
+}
+#endif
+
+static void __exit pexor_exit(void)
+{
+  pexor_msg(KERN_NOTICE "pexor driver exit...\n");
+
+  pci_unregister_driver(&pci_driver);
+  class_destroy(pexor_class);
+  unregister_chrdev_region(MKDEV(pexor_major, 0), PEXOR_MAX_DEVS);
+
+  pexor_msg(KERN_NOTICE "\t\tdriver exit done.\n");
+}
+
+
+/* ------ TRBNet Specific ----------------------------------------------- */
+
+static int pexor_free_dma_buffer(struct pexor_privdata *priv)
+{
+  /* free sglist */
+  if (priv->dma.sglist != NULL) {
+    if (priv->dma.nr_sglist > 0) {
+      dma_unmap_sg(priv->class_dev,
+                   priv->dma.sglist, priv->dma.nr_pages, DMA_FROM_DEVICE);
+    }
+    kfree(priv->dma.sglist);
+  }
+
+  /* free DMA-Buffer */
+  if (priv->dma.buffer != NULL) {
+    vfree(priv->dma.buffer);
+  }
+
+  priv->dma.buffer = NULL;
+  priv->dma.size = 0;
+  priv->dma.nr_pages = 0;
+  priv->dma.sglist = NULL;
+  priv->dma.nr_sglist = 0;
+
+  pexor_dbg(KERN_NOTICE "INFO> pexor_free_dma_buffer: success\n");
+  return 0;
+}
+
+static int pexor_alloc_dma_buffer(struct pexor_privdata *priv, size_t size)
+{
+  struct page *pg = NULL;
+  unsigned long uaddr = 0;
+  unsigned int i;
+
+  priv->dma.buffer = NULL;
+  priv->dma.size = 0;
+  priv->dma.nr_pages = 0;
+  priv->dma.sglist = NULL;
+  priv->dma.nr_sglist = 0;
+
+  /* allocate DAM-Buffer */
+  priv->dma.buffer = vmalloc_32(size);
+  if (priv->dma.buffer == NULL) {
+    pexor_msg(KERN_ERR
+              "ERROR> pexor_alloc_dma_buffer: vmalloc failed buffer\n");
+    return -ENOMEM;
+  }
+  memset(priv->dma.buffer, 0, size);
+  uaddr = (unsigned long)priv->dma.buffer;
+  priv->dma.nr_pages =
+    ((uaddr + size + PAGE_SIZE - 1) >> PAGE_SHIFT) - (uaddr >> PAGE_SHIFT);
+  priv->dma.size = size;
+
+  /* allocate scatterlist */
+  priv->dma.sglist =
+    kcalloc(priv->dma.nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
+  if (priv->dma.sglist == NULL) {
+    pexor_msg(KERN_ERR
+              "ERROR> pexor_alloc_dma_buffer: kmalloc failed scatterlist\n");
+    pexor_free_dma_buffer(priv);
+    return -ENOMEM;
+  }
+  memset(priv->dma.sglist, 0,
+         sizeof(struct scatterlist) * priv->dma.nr_pages);
+
+  /* fill scatterlist */
+  pexor_msg(KERN_ERR
+            "INFO>  uaddr: %lx, dma.buffer: %p nr_pages: %d\n",
+            uaddr, priv->dma.buffer, priv->dma.nr_pages);
+  for (i = 0; i < priv->dma.nr_pages; i++) {
+    pg = vmalloc_to_page(priv->dma.buffer + i * PAGE_SIZE);
+    if (pg == NULL) {
+      pexor_msg(KERN_ERR
+                "ERROR> pexor_alloc_dma_buffer: vmalloc_to_page failed\n");
+      pexor_free_dma_buffer(priv);
+      return -EFAULT;
+    }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
+    priv->dma.sglist[i].page_link = (unsigned long)pg;
+#else
+    priv->dma.sglist[i].page = pg;
+#endif
+    priv->dma.sglist[i].offset = (i == 0)
+      ? offset_in_page(uaddr)
+      : 0;
+    priv->dma.sglist[i].length = ((i + 1) == priv->dma.nr_pages)
+      ? (uaddr + priv->dma.size) - ((uaddr + priv->dma.size - 1) & PAGE_MASK)
+      : PAGE_SIZE;
+
+#ifdef PEXOR_TRB_DEBUG
+    pexor_msg(KERN_ERR
+              "INFO> sglist[%d]  page: %p, index: %ld, offset: %d, "
+              "length: %d\n",
+              i, pg, pg->index, priv->dma.sglist[i].offset,
+              priv->dma.sglist[i].length);
+#endif
+  }
+  priv->dma.nr_sglist = dma_map_sg(priv->class_dev,
+                                   priv->dma.sglist,
+                                   priv->dma.nr_pages, DMA_FROM_DEVICE);
+  pexor_msg(KERN_ERR "INFO> nr_sglist: %d\n", priv->dma.nr_sglist);
+
+  if (priv->dma.nr_sglist == 0) {
+    pexor_msg(KERN_ERR "ERROR> pexor_alloc_dma_buffer: dma_map_sg failed\n");
+    pexor_free_dma_buffer(priv);
+    return -EFAULT;
+  }
+  pexor_dbg(KERN_NOTICE "INFO> pexor_alloc_dma_buffer: success\n");
+
+  return 0;
+}
+
+#define MASK_FIFO_VALID     (0x01 << 24)
+#define MASK_FIFO_TRB_ACT   (0x01 << 25)
+#define MAX_FIFO_TIMEOUT    5000000
+#define SHIFT_HEADER_TYPE   0x0000
+#define MASK_HEADER_TYPE    (0x0007 << SHIFT_HEADER_TYPE)
+#define HEADER_TRM          0x0003
+
+static int pexor_copy_fifo_to_dma(struct pexor_privdata *priv,
+                                  unsigned int channel)
+{
+  unsigned int sg_ctr;
+  unsigned int sg_length;
+  unsigned int timeout = 0;
+  unsigned int ctr = 0;
+  volatile u32 val = 0;
+  unsigned int i;
+
+  if (channel >= PEXOR_TRB_NUM_CHANNELS)
+    return -1;
+
+  for (sg_ctr = 0; sg_ctr < priv->dma.nr_sglist; sg_ctr++) {
+    /* sync current sg-entry to CPU */
+    dma_sync_single_for_cpu(priv->class_dev,
+                            sg_dma_address(&priv->dma.sglist[sg_ctr]),
+                            sg_dma_len(&priv->dma.sglist[sg_ctr]),
+                            DMA_FROM_DEVICE);
+    sg_length = sg_dma_len(&priv->dma.sglist[sg_ctr]);
+    for (i = 0; i < sg_length; i++) {
+      timeout = 0;
+      do {
+        val = ioread32(priv->pexor.trbnet_receiver_data[channel]);
+        if ((val & MASK_FIFO_TRB_ACT) == 0) {
+          return ctr;
+        }
+      } while (((val & MASK_FIFO_VALID) == 0) &&
+               (++timeout < MAX_FIFO_TIMEOUT));
+      if (timeout >= MAX_FIFO_TIMEOUT) {
+        pexor_msg(KERN_ERR
+                  "ERROR> copy_fifo_to_dma: FIFO Timeout channel %d\n",
+                  channel);
+        pexor_msg(KERN_ERR "ERROR> last val: 0x%08x\n", val);
+
+        /* to be done: flush FIFO here */
+        return -1;
+      }
+      ((u32 *) priv->dma.buffer)[ctr] = val;
+#ifdef PEXOR_TRB_DEBUG
+      pexor_msg(KERN_ERR "FIFO COPY: %d: 0x%08x channel: %d\n",
+                ctr, ((u32 *) priv->dma.buffer)[ctr], channel);
+#endif
+      ctr++;
+    }
+
+  }
+
+  /* should not happen,out of buffers etc */
+  /* to be done: flush FIFO here */
+  return -1;
+}
+
+int pexor_ioctl_trbnet_request(struct pexor_privdata *priv, unsigned long arg)
+{
+  int status = -1;
+  unsigned int channel = 3;
+  int command;
+  volatile u32 dmastat = 0;
+  unsigned int sg_ctr = 0;
+  unsigned int dmaSize = 0;
+  struct pexor_trbnet_io descriptor;
+
+  spin_lock((&(priv->dma_lock)));
+
+  if (copy_from_user(&descriptor,
+                     (void __user *)arg, sizeof(struct pexor_trbnet_io))) {
+    status = -EFAULT;
+    goto OUT_IOCTL;
+  }
+
+  /* execute command */
+  command = descriptor.command;
+
+  switch (command) {
+  case PEXOR_TRBNETCOM_REG_WRITE:
+    // first send trbnet request
+    iowrite32(0x00000000, priv->pexor.trbnet_sender_err[3]);
+    iowrite32(descriptor.reg_address, priv->pexor.trbnet_sender_data[3]);
+    iowrite32((descriptor.arg0 >> 16) & 0xffff,
+              priv->pexor.trbnet_sender_data[3]);
+    iowrite32(descriptor.arg0 & 0xffff, priv->pexor.trbnet_sender_data[3]);
+    iowrite32(0x00000000, priv->pexor.trbnet_sender_data[3]);
+    iowrite32((((u32) descriptor.trb_address << 16) |
+               PEXOR_TRB_CMD_REGISTER_WRITE),
+              priv->pexor.trbnet_sender_ctl[3]);
+    break;
+
+  case PEXOR_TRBNETCOM_REG_WRITE_MEM:
+    {
+      unsigned int i;
+      if (descriptor.arg1 > PEXOR_MEMWRITE_SIZE) {
+        pexor_msg(KERN_ERR "ERROR>  REG_WRITE_MEM: invalid size%x\n", command);
+        status = -EFAULT;
+        goto OUT_IOCTL;
+      }
+      
+      // first send trbnet request
+      iowrite32(0x00000000, priv->pexor.trbnet_sender_err[3]);
+      iowrite32(descriptor.reg_address, priv->pexor.trbnet_sender_data[3]);
+      iowrite32(descriptor.arg0, priv->pexor.trbnet_sender_data[3]);
+      iowrite32(0x00000000, priv->pexor.trbnet_sender_data[3]);
+      iowrite32(0x00000000, priv->pexor.trbnet_sender_data[3]);
+      for (i = 0; (i < descriptor.arg1) && (i < PEXOR_MEMWRITE_SIZE); i++) {
+        iowrite32(0x00000000, priv->pexor.trbnet_sender_data[3]);
+        iowrite32((priv->memwrite_buffer[i] >> 16) & 0xffff,
+                  priv->pexor.trbnet_sender_data[3]);
+        iowrite32(priv->memwrite_buffer[i] & 0xffff,
+                  priv->pexor.trbnet_sender_data[3]);
+        iowrite32(0x00000000, priv->pexor.trbnet_sender_data[3]);
+      }
+      iowrite32((((u32) descriptor.trb_address << 16) |
+                 PEXOR_TRB_CMD_REGISTER_WRITE_MEM),
+                priv->pexor.trbnet_sender_ctl[3]);
+    }
+    break;
+
+  case PEXOR_TRBNETCOM_REG_READ:
+    // first send trbnet request
+    iowrite32(0x00000000, priv->pexor.trbnet_sender_err[3]);
+    iowrite32(descriptor.reg_address, priv->pexor.trbnet_sender_data[3]);
+    iowrite32(0x00000000, priv->pexor.trbnet_sender_data[3]);
+    iowrite32(0x00000000, priv->pexor.trbnet_sender_data[3]);
+    iowrite32(0x00000000, priv->pexor.trbnet_sender_data[3]);
+    iowrite32((((u32) descriptor.trb_address << 16) |
+               PEXOR_TRB_CMD_REGISTER_READ),
+              priv->pexor.trbnet_sender_ctl[3]);
+    break;
+
+  case PEXOR_TRBNETCOM_REG_READ_MEM:
+    // first send trbnet request
+    iowrite32(0x00000000, priv->pexor.trbnet_sender_err[3]);
+    iowrite32(descriptor.reg_address, priv->pexor.trbnet_sender_data[3]);
+    iowrite32(descriptor.arg0, priv->pexor.trbnet_sender_data[3]);
+    iowrite32(0x00000000, priv->pexor.trbnet_sender_data[3]);
+    iowrite32(0x00000000, priv->pexor.trbnet_sender_data[3]);
+    iowrite32((((u32) descriptor.trb_address << 16) |
+               PEXOR_TRB_CMD_REGISTER_READ_MEM),
+              priv->pexor.trbnet_sender_ctl[3]);
+    break;
+
+  case PEXOR_TRBNETCOM_READ_UID:
+    // first send trbnet request
+    iowrite32(0x00000000, priv->pexor.trbnet_sender_err[3]);
+    iowrite32(PEXOR_TRB_NET_READUNIQUEID, priv->pexor.trbnet_sender_data[3]);
+    iowrite32(0x00000000, priv->pexor.trbnet_sender_data[3]);
+    iowrite32(0x00000000, priv->pexor.trbnet_sender_data[3]);
+    iowrite32(0x00000000, priv->pexor.trbnet_sender_data[3]);
+    iowrite32((((u32) descriptor.trb_address << 16) |
+               PEXOR_TRB_CMD_NETADMINISTRATION),
+              priv->pexor.trbnet_sender_ctl[3]);
+    break;
+
+  case PEXOR_TRBNETCOM_SET_ADDRESS:
+    // first send trbnet request
+    iowrite32(0x00000000, priv->pexor.trbnet_sender_err[3]);
+    iowrite32(PEXOR_TRB_NET_SETADDRESS, priv->pexor.trbnet_sender_data[3]);
+    iowrite32(descriptor.arg0 & 0xffff, priv->pexor.trbnet_sender_data[3]);
+    iowrite32(descriptor.arg0 >> 16 & 0xffff,
+              priv->pexor.trbnet_sender_data[3]);
+    iowrite32(descriptor.arg1 & 0xffff, priv->pexor.trbnet_sender_data[3]);
+    iowrite32(descriptor.arg1 >> 16 & 0xffff,
+              priv->pexor.trbnet_sender_data[3]);
+    iowrite32(descriptor.arg2, priv->pexor.trbnet_sender_data[3]);
+    iowrite32(descriptor.trb_address, priv->pexor.trbnet_sender_data[3]);
+    iowrite32(0x00000000, priv->pexor.trbnet_sender_data[3]);
+    iowrite32(0xffff0000 | PEXOR_TRB_CMD_NETADMINISTRATION,
+              priv->pexor.trbnet_sender_ctl[3]);
+    break;
+
+  case PEXOR_TRBNETCOM_IPU_DATA_READ:
+    iowrite32(((descriptor.arg1 & 0xff) << 24) | (descriptor.arg2 & 0xffffff),
+              priv->pexor.trbnet_sender_err[1]);
+    iowrite32((descriptor.arg0 & 0x0f) | PEXOR_TRB_CMD_SHORT_TRANSFER,
+              priv->pexor.trbnet_sender_ctl[1]);
+    channel = 1;
+    break;
+
+  case PEXOR_TRBNETCOM_SEND_TRIGGER:
+    iowrite32(((descriptor.arg1 & 0xff) << 24) | (descriptor.arg2 & 0xffffff),
+              priv->pexor.trbnet_sender_err[0]);
+    iowrite32((descriptor.arg1 >> 8) & 0xffff,
+              priv->pexor.trbnet_sender_trigger_info);
+
+    iowrite32((descriptor.arg0 & 0x0f) | PEXOR_TRB_CMD_SHORT_TRANSFER,
+              priv->pexor.trbnet_sender_ctl[0]);
+    channel = 0;
+    break;
+
+  default:
+    pexor_msg(KERN_ERR "ERROR> invalid request %x\n", command);
+    status = -EFAULT;
+    goto OUT_IOCTL;
+  };
+
+  if (descriptor.dma != 0 && channel == 3) {
+    /* only channel 3 supports DMA */
+    
+    /* Start DMA transfer */
+    pexor_dbg(KERN_ERR "Start DMA transfer\n");
+    for (sg_ctr = 0; sg_ctr < priv->dma.nr_sglist; sg_ctr++) {
+      unsigned int loops = 0;
+      
+      mb();
+      /* do we need this?? */
+      /*
+        dma_sync_single_for_device(priv->class_dev,
+        sg_dma_address(&priv->dma.sglist[sg_ctr]),
+        sg_dma_len(&priv->dma.sglist[sg_ctr]),
+        DMA_FROM_DEVICE);
+      */
+      iowrite32(sg_dma_address(&priv->dma.sglist[sg_ctr]),
+                priv->pexor.dma_dest);
+      iowrite32(sg_dma_len(&priv->dma.sglist[sg_ctr]) / 4,
+                priv->pexor.dma_len);
+      
+      /* wait for dma complete */
+      for (loops = 0; loops < PEXOR_DMA_MAXPOLLS * 100; loops++) {
+        dmastat = ioread32(priv->pexor.dma_control_stat);
+        mb();
+        if (((dmastat & PEXOR_DMA_ENABLED_BIT) == 0) && (dmastat != 0)) {
+          break;
+        }
+        if ((dmastat & PEXOR_TRB_BIT_DMA_MORE) != 0)
+          break;
+      }
+      if (loops == PEXOR_DMA_MAXPOLLS * 100) {
+        pexor_msg(KERN_ERR
+                  "ERROR> wait_dma_complete: polling longer than %d cycles "
+                  "(delay %d ns) for dma complete! Status: 0x%x\n",
+                  PEXOR_DMA_MAXPOLLS, PEXOR_DMA_POLLDELAY,
+                  (unsigned int)dmastat);
+        /* reset DMA */
+        iowrite32(PEXOR_TRB_DMA_RESET, priv->pexor.dma_control_stat);
+        /* do we need to flush the fifo-buffer? */
+        status = -EFAULT;
+        goto OUT_IOCTL;
+      }
+
+      /* sync current sg-entry to CPU */
+      dma_sync_single_for_cpu(priv->class_dev,
+                              sg_dma_address(&priv->dma.sglist[sg_ctr]),
+                              sg_dma_len(&priv->dma.sglist[sg_ctr]),
+                              DMA_FROM_DEVICE);
+      mb();
+      
+      /* check status: do we need another dma for data */
+      if ((dmastat & PEXOR_DMA_ENABLED_BIT) == 0) {
+        dmaSize = dmastat >> 8; //was +=
+        break;
+      }
+      if ((sg_ctr + 1) >= priv->dma.nr_sglist) {
+        pexor_msg(KERN_ERR
+                  "ERROR> no more DMA buffers available, aborting DMA\n");
+        /* reset DMA */
+        iowrite32(PEXOR_TRB_DMA_RESET, priv->pexor.dma_control_stat);
+        /* do we need to flush the fifo-buffer? */
+        status = -EFAULT;
+        goto OUT_IOCTL;
+      }
+    }
+
+    status = dmaSize;
+
+#ifdef PEXOR_TRB_DEBUG
+    {
+      int i;
+      pexor_msg(KERN_ERR "DMA: dmaSize: %d\n", dmaSize);
+      for (i = 0; i < dmaSize + 20; i++) {
+        u32 val = 0;
+        val = ioread32((i % 2 == 0)
+                       ? priv->pexor.dma_debug0 : priv->pexor.dma_debug1);
+        pexor_msg(KERN_ERR "DMA: %d 0x%08x   DEBUG:0x%08x\n", i,
+                  ((u32 *) priv->dma.buffer)[i], val);
+      }
+    }
+#endif
+  } else {
+    /* do FIFO transfer to DMA Buffer */
+    pexor_dbg(KERN_ERR "Start FIFO copy to DMA buffer\n");
+    status = pexor_copy_fifo_to_dma(priv, channel);
+    if (status == -1) {
+      status = -EFAULT;
+      goto OUT_IOCTL;
+    }
+  }
+
+OUT_IOCTL:
+  spin_unlock((&(priv->dma_lock)));
+  return status;
+}
+
+/* ---------------------------------------------------------------------- */
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Joern Adamczewski-Musch / Ludwig Maier");
+MODULE_DESCRIPTION("pexor device driver for HADES TRBNet");
+MODULE_VERSION("2.0.0");
+MODULE_DEVICE_TABLE(pci, ids);
+
+module_init(pexor_init);
+module_exit(pexor_exit);
diff --git a/pexor/kernel-module/pexor_trb.h b/pexor/kernel-module/pexor_trb.h
new file mode 100644 (file)
index 0000000..2f37138
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * pexor_trb.h
+ *
+ *     definitions and functions for pexor with
+ *     HADES trbnet protocol
+ */
+
+#ifndef _PCI_PEXOR_TRB_H_
+#define _PCI_PEXOR_TRB_H_
+
+#define PEXOR_BURST                      0x80
+#define PEXOR_DMA_ENABLED_BIT            0x01
+#define PEXOR_TRB_BIT_DMA_ACTIVE         0x01
+#define PEXOR_TRB_BIT_DMA_MORE           0x02
+#define PEXOR_TRB_DMA_RESET              0x02
+
+#define PEXOR_DRAM                       0x100000       /* TODO: specify meaningful RAM position for fops io functions? */
+
+#define PEXOR_DMA_BASE                  0x00    /* base address of DMA engine */
+
+#define PEXOR_IRQ_CTRL   PEXOR_DMA_BASE /* DUMMY TODO meaningful register for trbnet */
+#define PEXOR_IRQ_STAT   PEXOR_DMA_BASE /* DUMMY TODO meaningful register for trbnet */
+#define PEXOR_IRQ_USER_BIT              0x01    /* DUMMY TODO meaningful register for trbnet */
+
+
+#define PEXOR_TRB_NUM_CHANNELS           4
+#define PEXOR_TRB_SENDER_CONTROL         0x0100
+#define PEXOR_TRB_TARGET_ADDRESS         0x0101
+#define PEXOR_TRB_SENDER_ERROR           0x0102
+#define PEXOR_TRB_SENDER_DATA            0x0103
+#define PEXOR_TRB_SENDER_STATUS          0x010f
+#define PEXOR_TRB_RECEIVER_DATA          0x0203
+#define PEXOR_TRB_RECEIVER_FIFO_STATUS   0x0204
+#define PEXOR_TRB_API_STATUS             0x0300
+
+#define PEXOR_TRB_SENDER_TRIGGER_INFO    0x0115
+
+#define PEXOR_TRB_DMA_ADD                0x0700 /* DMA Start Address */
+#define PEXOR_TRB_DMA_LEN                0x0701 /* (rw) DMA Buffer length in 32 bit words */
+#define PEXOR_TRB_DMA_CTL                0x0702 /*(writing to register is sufficient, no need to clear it before writing)
+                                                   Bit 0: DMA start
+                                                   Bit 1: DMA reset - completely reset the full DMA handler
+
+                                                   (r):
+                                                   Bit 0: DMA active, goes low after TrbNet access has been completed and DMA is finished
+                                                   Bit 1: DMA Buffer full. Buffer provided by CPU is full, waiting for new buffer and DMA start
+                                                   Bit 31..8: DMA Size. Number of written data words to current dma buffer. Only valid when Bit 0 is low or Bit 1 is high */
+
+
+#define PEXOR_TRB_DMA_BST                0x0703 /* Bit 7-0: DMA Burst Length in 32 bit words. Default: 0x1F */
+#define PEXOR_TRB_DMA_STA                0x0704 /* Status Register: Various status bits of DMA engine (t.b.d.) */
+#define PEXOR_TRB_DMA_CRE                0x0705 /* Status Register: Available credits (t.b.d.) */
+#define PEXOR_TRB_DMA_CNT                0x0706 /* Status Register: Counter values (t.b.d.) */
+
+#define PEXOR_TRB_CMD_REGISTER_READ      0x08
+#define PEXOR_TRB_CMD_REGISTER_READ_MEM  0x0a
+#define PEXOR_TRB_CMD_REGISTER_WRITE     0x09
+#define PEXOR_TRB_CMD_REGISTER_WRITE_MEM 0x0b
+#define PEXOR_TRB_CMD_NETADMINISTRATION  0x0f
+#define PEXOR_TRB_CMD_SHORT_TRANSFER     0x0100
+
+#define PEXOR_TRB_NET_READUNIQUEID       0x5e1d
+#define PEXOR_TRB_NET_SETADDRESS         0x5ead
+
+#endif
diff --git a/pexor/kernel-module/pexor_user.h b/pexor/kernel-module/pexor_user.h
new file mode 100644 (file)
index 0000000..a9ed103
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * pexor_user.h
+ *
+ *  Created on: 01.12.2009
+ *      Author: J. Adamczewski-Musch
+ *
+ *      Contains all common definitions for kernel driver and user space library
+ */
+
+#ifndef PEXOR_USER_H_
+#define PEXOR_USER_H_
+
+#include <linux/ioctl.h>
+
+#define PEXORVERSION    "0.995"
+
+/* the ioctl stuff here:*/
+#define PEXOR_IOC_MAGIC  0xE0
+
+#define PEXOR_IOC_RESET  _IO(  PEXOR_IOC_MAGIC, 0)
+#define PEXOR_IOC_FREEBUFFER  _IOW(  PEXOR_IOC_MAGIC, 1, struct pexor_userbuf)
+#define PEXOR_IOC_DELBUFFER   _IOW(  PEXOR_IOC_MAGIC, 2, struct pexor_userbuf)
+#define PEXOR_IOC_WAITBUFFER  _IOR(  PEXOR_IOC_MAGIC, 3, struct pexor_userbuf)
+#define PEXOR_IOC_USEBUFFER   _IOR(  PEXOR_IOC_MAGIC, 4, struct pexor_userbuf)
+#define PEXOR_IOC_SETSTATE    _IOR(  PEXOR_IOC_MAGIC, 5, int)
+#define PEXOR_IOC_TEST            _IOR(  PEXOR_IOC_MAGIC, 6, int)
+#define PEXOR_IOC_CLEAR_RCV_BUFFERS  _IO(  PEXOR_IOC_MAGIC, 7)
+#define PEXOR_IOC_WRITE_BUS   _IOWR(  PEXOR_IOC_MAGIC, 8, struct pexor_bus_io)
+#define PEXOR_IOC_READ_BUS    _IOWR(  PEXOR_IOC_MAGIC, 9, struct pexor_bus_io)
+#define PEXOR_IOC_INIT_BUS    _IOW(  PEXOR_IOC_MAGIC, 10, struct pexor_bus_io)
+#define PEXOR_IOC_WRITE_REGISTER   _IOW(  PEXOR_IOC_MAGIC, 11, struct pexor_reg_io)
+#define PEXOR_IOC_READ_REGISTER    _IOWR(  PEXOR_IOC_MAGIC, 12, struct pexor_reg_io)
+#define PEXOR_IOC_REQUEST_TOKEN    _IOWR(  PEXOR_IOC_MAGIC, 13, struct pexor_token_io)
+#define PEXOR_IOC_WAIT_TOKEN    _IOWR(  PEXOR_IOC_MAGIC, 14, struct pexor_token_io)
+#define PEXOR_IOC_WAIT_TRIGGER    _IO(  PEXOR_IOC_MAGIC, 15)
+#define PEXOR_IOC_SET_TRIXOR    _IOR(  PEXOR_IOC_MAGIC, 16, struct pexor_trixor_set)
+#define PEXOR_IOC_TRBNET_REQUEST _IOWR(  PEXOR_IOC_MAGIC, 17, struct pexor_trbnet_io)
+#define PEXOR_IOC_MAXNR 18
+
+/* the states:*/
+#define PEXOR_STATE_STOPPED 0   /* daq stopped */
+#define PEXOR_STATE_DMA_SINGLE 1        /* trigger a single dma transfer into next free buf */
+#define PEXOR_STATE_DMA_FLOW 2  /* each dma transfer will initiate the next = dataflow or chained DMA */
+#define PEXOR_STATE_DMA_AUTO 3  /* TODO: board fpga will automatically initate next DMA when send fifo is full */
+#define PEXOR_STATE_DMA_SUSPENDED 4     /* used for backpressure until free buffer list is empty no more */
+#define PEXOR_STATE_IR_TEST 5   /* this state is used to test raising an ir manually */
+
+#define PEXOR_TRIGGER_FIRED  0  /* return value from wait trigger to inform that trigger ir was fired reached */
+#define PEXOR_TRIGGER_TIMEOUT 1 /* return value from wait trigger to inform that wait timeout was reached */
+
+#define PEXOR_TRIX_RES          0       /* Command for ioctl set trixor to reset trigger - clear dt flag */
+#define PEXOR_TRIX_GO           1       /* Command for ioctl set trixor to start acquisition  */
+#define PEXOR_TRIX_HALT         2       /* Command for ioctl set trixor to stop  acquisition  */
+#define PEXOR_TRIX_TIMESET         3    /* Command for ioctl set trixor to set trigger time windows */
+
+
+
+struct pexor_userbuf
+{
+  unsigned long addr;           /* user space virtual address (=buffer id) */
+  unsigned long size;           /* allocated size or used size */
+};
+
+
+struct pexor_bus_io
+{
+  unsigned long sfp;            /* sfp link id 0..3 (optional) */
+  unsigned long slave;          /* slave device id at the sfp (optional) */
+  unsigned long address;        /* address on the "field bus" connected to the optical links */
+  unsigned long value;          /* value for read/write at bus address. Contains result status after write */
+};
+
+struct pexor_token_io
+{
+  unsigned char sync;           /* 1:synchronous mode, 0: asynchronous mode */
+  unsigned long sfp;            /* sfp link id 0..3 */
+  unsigned long bufid;          /* switch double buffer id on slave (1 or 0) */
+  struct pexor_userbuf tkbuf;   /* dma buffer with received token data (on synchronous reply) */
+};
+
+
+struct pexor_reg_io
+{
+  unsigned int address;         /* address of a board register, relative to the specified BAR */
+  unsigned int value;           /* value for read/write at register address */
+  unsigned char bar;            /* the BAR where the register is mapped to PCI access. */
+};
+
+
+/* ----------------------------------------------------------------------   */
+
+#define PEXOR_TRBNETCOM_REG_WRITE          0 
+#define PEXOR_TRBNETCOM_REG_WRITE_MEM      1
+#define PEXOR_TRBNETCOM_REG_READ           2
+#define PEXOR_TRBNETCOM_REG_READ_MEM       3
+#define PEXOR_TRBNETCOM_READ_UID           4
+#define PEXOR_TRBNETCOM_SET_ADDRESS        5
+#define PEXOR_TRBNETCOM_IPU_DATA_READ      6
+#define PEXOR_TRBNETCOM_SEND_TRIGGER       7
+
+struct pexor_trbnet_io
+{
+  unsigned int command;         /* command to issue on trbnet */
+  unsigned short trb_address;   /* address of board in trbnet */
+  unsigned int reg_address;     /* address on board           */
+  unsigned short dma;           /* activate DMA-engine        */
+  unsigned int arg0;            /* optional argument 0        */
+  unsigned int arg1;            /* optional argument 1        */
+  unsigned int arg2;            /* optional argument 2        */
+};
+
+
+#endif