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

Add driver files

parent ab799193
Branches
Tags
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.
Please register or to comment