From c07a2d6829465c3c19fcd2c5a3e9f6d71c1d0d2e Mon Sep 17 00:00:00 2001
From: ROBBE Patrick <robbe@lal.in2p3.fr>
Date: Sun, 27 Jan 2019 17:44:28 +0100
Subject: [PATCH] Add driver files

---
 Driver/pcie40_driver/main_emu.c | 226 ++++++++++++++++++++++++++++++++
 1 file changed, 226 insertions(+)
 create mode 100644 Driver/pcie40_driver/main_emu.c

diff --git a/Driver/pcie40_driver/main_emu.c b/Driver/pcie40_driver/main_emu.c
new file mode 100644
index 0000000..178befe
--- /dev/null
+++ b/Driver/pcie40_driver/main_emu.c
@@ -0,0 +1,226 @@
+//ug`pcie40_driver_emu.description`
+// ``lhcb_pcie40_emu.ko`` is a driver emulating the PCIe40 data acquisition card.
+
+#define P40_FMT "P40emu:%s(): "
+#define PCIE40_EMU
+
+#include "common.h"
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/stat.h>
+#include <linux/vmalloc.h>
+
+//ug`pcie40_driver_emu.synopsis`
+// modprobe *lhcb_pcie40_emu* [ mainmibs=_M_ ] [ metamibs=_M_ ] [ baseid=_I_ ] [ numboards=_N_ ] [ mpf=_M_ ]
+
+static LIST_HEAD(pcie40_emu_inst_list);
+
+//ug`pcie40_driver_emu.options`baseid *baseid* = _I_::
+// First interface ID for emulated boards (0 by default, increase to avoid conflicts with real boards already detected in the machine).
+int baseid = 0;
+module_param(baseid, int, S_IRUSR | S_IRGRP | S_IROTH);
+MODULE_PARM_DESC(baseid, "First interface ID for emulated boards");
+
+//ug`pcie40_driver_emu.options`numboards *numboards* = _N_::
+// Number of PCIe40 boards to emulate (1 by default). Two DAQ interfaces will be instantiated for each emulated board.
+int numboards = 1;
+module_param(numboards, int, S_IRUSR | S_IRGRP | S_IROTH);
+MODULE_PARM_DESC(numboards, "Number of PCIe40 boards to emulate");
+
+//ug`pcie40_driver_emu.options`mpf *mpf* = _M_::
+// Packing factor for metadata blocks (10000 by default).
+int mpf = 10000;
+module_param(mpf, int, S_IRUSR | S_IRGRP | S_IROTH);
+MODULE_PARM_DESC(mpf, "Packing factor for metadata blocks");
+
+int pcie40_ecs_init(void);
+void pcie40_ecs_exit(void);
+
+int pcie40_ecs_emu_probe(struct pcie40_state *common);
+void pcie40_ecs_emu_remove(struct pcie40_state *common);
+
+int pcie40_daq_init(void);
+void pcie40_daq_exit(void);
+
+int pcie40_daq_emu_probe(struct pcie40_state *common);
+void pcie40_daq_emu_remove(struct pcie40_state *common);
+
+static int pcie40_emu_probe(int link_id)
+{
+  int rc = 0;
+  struct pcie40_state *state = NULL, *li;
+
+  printk(P40_DIAG "creating emulated PCIe40 interface (link %d)", P40_PARM, link_id);
+
+  state = kzalloc(sizeof(struct pcie40_state), GFP_KERNEL);
+  if (IS_ERR(state)) {
+    printk(P40_ERR "kzalloc()\n", P40_PARM);
+    rc = PTR_ERR(state);
+    goto err_kzalloc;
+  }
+  printk(P40_DIAG "state = 0x%p\n", P40_PARM, state);
+
+  INIT_LIST_HEAD(&state->list);
+
+  printk(P40_INFO "initializing BARs\n", P40_PARM);
+
+  if (link_id == 0) {
+    state->bar_start[0] = 0;
+    state->bar_size[0] = 32 * 1024 * 1024;
+  }
+  state->bar_start[1] = 0;
+  state->bar_size[1] = 256 * 1024;
+  if (link_id == 0) {
+    state->bar_start[2] = 0;
+    state->bar_size[2] = 32 * 1024 * 1024;
+  }
+  //TODO: print BAR information
+
+  if (state->bar_size[0]) {
+    printk(P40_INFO "allocating fake BAR0 (%lu bytes)\n", P40_PARM, state->bar_size[0]);
+    state->bar0_regs = vzalloc(state->bar_size[0]);
+    if (state->bar0_regs == NULL) {
+      rc = -1;
+      goto err_bar0_alloc;
+    }
+  }
+
+  if (state->bar_size[1]) {
+    printk(P40_INFO "allocating fake BAR1 (%lu bytes)\n", P40_PARM, state->bar_size[1]);
+    state->bar1_regs = vzalloc(state->bar_size[1]);
+    if (state->bar1_regs == NULL) {
+      rc = -1;
+      goto err_bar1_alloc;
+    }
+  }
+
+  if (state->bar_size[2]) {
+    printk(P40_INFO "allocating fake BAR2 (%lu bytes)\n", P40_PARM, state->bar_size[2]);
+    state->bar2_regs = vzalloc(state->bar_size[2]);
+    if (state->bar2_regs == NULL) {
+      rc = -1;
+      goto err_bar2_alloc;
+    }
+  }
+
+  //Fill fake BAR1 with plausible values
+  pcie40_write32_ctrl(state, P40_DMA_CTRL_OFF_RWTEST, 0xCE40FACC);
+  pcie40_write32_ctrl(state, P40_DMA_CTRL_OFF_REGMAP, P40_DMA_REGMAP_VERSION);
+  pcie40_write32_ctrl(state, P40_DMA_CTRL_OFF_VERSION, 0x0400FACC);
+  pcie40_write32_ctrl(state, P40_DMA_CTRL_OFF_LINK_ID, link_id);
+  pcie40_write32_ctrl(state, P40_DMA_CTRL_OFF_MAIN_GEN_FIXED, 0x6243484C);
+  pcie40_write32_ctrl(state, P40_DMA_CTRL_OFF_META_PACKING, 13);
+  pcie40_write32_ctrl(state, P40_DMA_CTRL_OFF_PCIE_GEN, 3);
+
+  state->link_id = link_id;
+  if (state->link_id == 0) {
+    state->dev_id = baseid; // This device will get an even id
+  } else {
+    state->dev_id = baseid + 1; // This device will get an odd id
+  }
+  list_for_each_entry(li, &pcie40_emu_inst_list, list) {
+    if ((state->link_id == 0 && li->dev_id % 2 == 0)
+    || (state->link_id != 0 && li->dev_id % 2 != 0)) {
+      if (li->dev_id >= state->dev_id) {
+        state->dev_id = li->dev_id + 2;
+      }
+    }
+  }
+  list_add(&state->list, &pcie40_emu_inst_list);
+
+  pcie40_write32_ctrl(state, P40_DMA_CTRL_OFF_CHIP_ID_HI, 0x00CE40);
+  pcie40_write32_ctrl(state, P40_DMA_CTRL_OFF_CHIP_ID_LO, state->dev_id / 2 + 1);
+
+  rc |= pcie40_ecs_emu_probe(state);
+  rc |= pcie40_daq_emu_probe(state);
+
+  return rc;
+
+  //if (state->bar_size[1]) {
+  //  kfree(state->bar1_regs);
+  //  state->bar1_regs = NULL;
+  //}
+
+err_bar2_alloc:
+  if (state->bar_size[1]) {
+    vfree(state->bar1_regs);
+    state->bar1_regs = NULL;
+  }
+err_bar1_alloc:
+  if (state->bar_size[0]) {
+    vfree(state->bar0_regs);
+    state->bar0_regs = NULL;
+  }
+err_bar0_alloc:
+  kfree(state);
+err_kzalloc:
+  return rc;
+}
+
+static void pcie40_emu_remove(struct pcie40_state *state)
+{
+  list_del(&state->list);
+
+  pcie40_ecs_emu_remove(state);
+  pcie40_daq_emu_remove(state);
+
+  if (state->bar_size[0]) {
+    vfree(state->bar0_regs);
+    state->bar0_regs = NULL;
+  }
+  if (state->bar_size[1]) {
+    vfree(state->bar1_regs);
+    state->bar1_regs = NULL;
+  }
+  if (state->bar_size[2]) {
+    vfree(state->bar2_regs);
+    state->bar2_regs = NULL;
+  }
+
+  kfree(state);
+}
+
+static int __init pcie40_emu_init(void)
+{
+  int rc = 0;
+  int i;
+
+  baseid &= ~1; // the base Device ID must be even
+
+  rc = pcie40_ecs_init();
+  if (rc < 0)
+    return rc;
+
+  rc = pcie40_daq_init();
+  if (rc < 0)
+    return rc;
+
+  for (i = 0; i < numboards; ++i) {
+    pcie40_emu_probe(0);
+    pcie40_emu_probe(1);
+  }
+
+  return rc;
+}
+
+static void __exit pcie40_emu_exit(void)
+{
+  struct pcie40_state *li, *ln;
+
+  list_for_each_entry_safe(li, ln, &pcie40_emu_inst_list, list) {
+    pcie40_emu_remove(li);
+  }
+
+  pcie40_daq_exit();
+  pcie40_ecs_exit();
+}
+
+module_init(pcie40_emu_init);
+module_exit(pcie40_emu_exit);
+
+MODULE_VERSION(DAQ40_VER_REL);
+MODULE_LICENSE("GPL");
+//TODO: MODULE_AUTHOR
+//TODO: MODULE_DESCRIPTION
-- 
GitLab