Commit 143f6398 authored by Federico Vaga's avatar Federico Vaga

kernel: program FPGA from char device

Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent f2dc22af
......@@ -16,6 +16,7 @@
#include <linux/firmware.h>
#include <linux/delay.h>
#include <linux/jhash.h>
#include <linux/fmc-sdb.h>
#include "svec.h"
#include "hw/xloader_regs.h"
......@@ -40,6 +41,8 @@ static int vme_size[SVEC_MAX_DEVICES] = SVEC_DEFAULT_VME_SIZE;
static unsigned int vme_size_num;
static int verbose;
static void svec_destroy_misc_device(struct svec_dev *svec);
module_param_array(slot, int, &slot_num, S_IRUGO);
MODULE_PARM_DESC(slot, "Slot where SVEC card is installed");
module_param_array(lun, int, &lun_num, S_IRUGO);
......@@ -382,6 +385,7 @@ static int svec_remove(struct device *pdev, unsigned int ndev)
svec_unmap_window(svec, MAP_CR_CSR);
svec_unmap_window(svec, MAP_REG);
svec_destroy_misc_device(svec);
svec_remove_sysfs_files(svec);
if (svec->verbose)
......@@ -723,6 +727,73 @@ int svec_load_golden(struct svec_dev *svec)
return 0;
}
/* * * * * * MISC DEVICE * * * * * */
static int svec_mdev_simple_open(struct inode *inode, struct file *file)
{
struct miscdevice *mdev_ptr = file->private_data;
file->private_data = container_of(mdev_ptr, struct svec_dev, mdev);
return 0;
}
static ssize_t svec_mdev_write_raw(struct file *f, const char __user *buf,
size_t count, loff_t *offp)
{
struct svec_dev *svec = f->private_data;
struct fmc_gateware gw;
int err = 0;
if (!count)
return -EINVAL;
/* Copy FPGA bitstream to kernel space */
gw.len = count;
gw.bitstream = vmalloc(count);
if (!gw.bitstream)
return -ENOMEM;
if (copy_from_user(gw.bitstream, buf, gw.len)) {
err = -EFAULT;
goto out;
}
/* Program FPGA */
err = svec_reconfigure(svec, &gw);
if (err)
dev_err(svec->dev,
"Manually program FPGA bitstream from buffer: fail\n");
else
dev_info(svec->dev,
"Manually program FPGA bitstream from buffer: success\n");
out:
vfree(gw.bitstream);
return err ? err : count;
}
static const struct file_operations svec_fops = {
.owner = THIS_MODULE,
.open = svec_mdev_simple_open,
.write = svec_mdev_write_raw,
};
static int svec_create_misc_device(struct svec_dev *svec)
{
svec->mdev.minor = MISC_DYNAMIC_MINOR;
svec->mdev.fops = &svec_fops;
svec->mdev.name = svec->name;
return misc_register(&svec->mdev);
}
static void svec_destroy_misc_device(struct svec_dev *svec)
{
misc_deregister(&svec->mdev);
}
/* * * * * * END MISC DEVICE * * * * */
static int svec_probe(struct device *pdev, unsigned int ndev)
{
struct svec_dev *svec;
......@@ -800,11 +871,19 @@ static int svec_probe(struct device *pdev, unsigned int ndev)
goto failed;
}
error = svec_create_misc_device(svec);
if (error) {
dev_err(pdev, "Error creating misc device\n");
goto failed_misc;
}
/* Map user address space & give control to the FMCs */
svec_reconfigure(svec, NULL);
return 0;
failed_misc:
svec_remove_sysfs_files(svec);
failed:
kfree(svec);
......
......@@ -10,6 +10,7 @@
#ifndef __SVEC_H__
#define __SVEC_H__
#include <linux/miscdevice.h>
#include <linux/firmware.h>
#include <linux/fmc.h>
#include "vmebus.h"
......@@ -74,6 +75,7 @@ struct svec_dev {
uint32_t fw_hash;
struct vme_mapping *map[__MAX_MAP];
struct svec_config cfg_cur, cfg_new;
struct miscdevice mdev;
struct fmc_device *fmcs[SVEC_N_SLOTS];
irq_handler_t fmc_handlers[SVEC_N_SLOTS];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment