diff --git a/Driver/pcie40_driver/main_emu.c b/Driver/pcie40_driver/main_emu.c new file mode 100644 index 0000000000000000000000000000000000000000..178befe09b976a17831342383dd420eeb1eb33dd --- /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