Skip to content
Snippets Groups Projects
Commit c07a2d68 authored by Patrick Robbe's avatar Patrick Robbe
Browse files

Add driver files

parent ab799193
No related branches found
No related tags found
No related merge requests found
//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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment