Commit d3d45d25 authored by Federico Vaga's avatar Federico Vaga

program fpga from userspace

parents 92b2ad31 4abad220
......@@ -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)
......@@ -656,7 +660,7 @@ static void svec_prepare_description(struct svec_dev *svec)
* via module parameters) or when the configuration is assigned through
* sysfs. Reconfiguration implies re-loading the FMCs.
*/
int svec_reconfigure(struct svec_dev *svec)
int svec_reconfigure(struct svec_dev *svec, struct fmc_gateware *gw)
{
int error;
......@@ -691,7 +695,7 @@ int svec_reconfigure(struct svec_dev *svec)
/* FMC initialization enabled? Start up the FMC drivers. */
if (svec->cfg_cur.use_fmc) {
error = svec_fmc_create(svec);
error = svec_fmc_create(svec, gw);
if (error) {
dev_err(svec->dev, "error creating fmc devices\n");
goto failed_unmap;
......@@ -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);
svec_reconfigure(svec, NULL);
return 0;
failed_misc:
svec_remove_sysfs_files(svec);
failed:
kfree(svec);
......
......@@ -33,6 +33,41 @@ static void svec_writel(struct fmc_device *fmc, uint32_t val, int offset)
iowrite32be(val, fmc->fpga_base + offset);
}
static int svec_reprogram_raw(struct fmc_device *fmc, struct fmc_driver *drv,
void *gw, unsigned long len)
{
struct svec_dev *svec = fmc->carrier_data;
struct device *dev = fmc->hwdev;
int ret;
if (!gw || !len) {
dev_err(dev, "Invalid firmware buffer - buf: %p len: %ld\n",
gw, len);
return -EINVAL;
}
if (!drv)
dev_info(dev, "Carrier FPGA re-program\n");
fmc_free_sdb_tree(fmc);
fmc->flags &= ~FMC_DEVICE_HAS_GOLDEN;
/* load the firmware */
ret = svec_load_fpga(svec, gw, len);
if (ret < 0) {
dev_err(dev, "error %i programming firmware\n", ret);
return ret;
}
/* Configure & activate CSR functions depending on chosen AM */
svec_setup_csr(svec);
fmc->flags |= FMC_DEVICE_HAS_CUSTOM;
return 0;
}
static int svec_reprogram(struct fmc_device *fmc, struct fmc_driver *drv,
char *gw)
{
......@@ -67,23 +102,10 @@ static int svec_reprogram(struct fmc_device *fmc, struct fmc_driver *drv,
dev_warn(dev, "request firmware \"%s\": error %i\n", gw, ret);
return ret;
}
fmc_free_sdb_tree(fmc);
fmc->flags &= ~FMC_DEVICE_HAS_GOLDEN;
/* load the firmware */
ret = svec_load_fpga(svec, fw->data, fw->size);
if (ret < 0) {
dev_err(dev, "error %i programming firmware \"%s\"\n", ret, gw);
goto out;
}
/* Configure & activate CSR functions depending on chosen AM */
svec_setup_csr(svec);
fmc->flags |= FMC_DEVICE_HAS_CUSTOM;
/* Re-Program FPGA */
ret = svec_reprogram_raw(fmc, drv, (void *)fw->data, fw->size);
out:
release_firmware(fw);
if (ret < 0)
dev_err(dev, "svec reprogram failed while loading %s\n", gw);
......@@ -120,6 +142,7 @@ static int svec_write_ee(struct fmc_device *fmc, int pos,
static struct fmc_operations svec_fmc_operations = {
.read32 = svec_readl,
.write32 = svec_writel,
.reprogram_raw = svec_reprogram_raw,
.reprogram = svec_reprogram,
.irq_request = svec_irq_request,
.irq_ack = svec_irq_ack,
......@@ -231,7 +254,7 @@ int svec_fmc_prepare(struct svec_dev *svec, unsigned int fmc_slot)
return ret;
}
int svec_fmc_create(struct svec_dev *svec)
int svec_fmc_create(struct svec_dev *svec, struct fmc_gateware *gw)
{
int i;
int error = 0;
......@@ -244,7 +267,7 @@ int svec_fmc_create(struct svec_dev *svec)
}
/* fmc device creation */
error = fmc_device_register_n(svec->fmcs, svec->fmcs_n);
error = fmc_device_register_n_gw(svec->fmcs, svec->fmcs_n, gw);
if (error) {
dev_err(svec->dev, "Error registering fmc devices\n");
goto failed;
......@@ -274,7 +297,7 @@ void svec_fmc_destroy(struct svec_dev *svec)
fmc_device_unregister_n(svec->fmcs, svec->fmcs_n);
WARN(test_bit(SVEC_FLAG_IRQS_REQUESTED, &svec->flags) || svec->vic,
"A Mezzanine driver didn't release all its IRQ handlers (VIC %p, FLAG 0x%x)\n",
"A Mezzanine driver didn't release all its IRQ handlers (VIC %p, FLAG 0x%lx)\n",
svec->vic, svec->flags);
memset(svec->fmcs, 0, sizeof(struct fmc_devices *) * SVEC_N_SLOTS);
......
......@@ -57,22 +57,23 @@ static int svec_fw_cmd_reset(struct svec_dev *card)
static int svec_fw_cmd_program(struct svec_dev *card)
{
int err;
struct fmc_gateware gw = {card->fw_buffer, card->fw_length};
int err = 0;
if (!card->fw_buffer || !card->fw_length)
return -EINVAL;
err = svec_load_fpga(card, card->fw_buffer, card->fw_length);
vfree(card->fw_buffer);
if (err)
goto out;
card->fw_buffer = NULL;
card->fw_length = 0;
if (err < 0)
return err;
svec_reconfigure(card);
return 0;
svec_reconfigure(card, &gw);
out:
vfree(card->fw_buffer);
return err;
}
......@@ -401,7 +402,7 @@ ATTR_STORE_CALLBACK(configured)
card->cfg_new.configured = 1;
card->cfg_cur = card->cfg_new;
error = svec_reconfigure(card);
error = svec_reconfigure(card, NULL);
if (error)
return error;
......
......@@ -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];
......@@ -104,7 +106,7 @@ extern int svec_map_window(struct svec_dev *svec, enum svec_map_win map_type);
extern char *svec_fw_name;
/* Functions in svec-fmc.c, used by svec-vme.c */
extern int svec_fmc_create(struct svec_dev *svec);
extern int svec_fmc_create(struct svec_dev *svec, struct fmc_gateware *gw);
extern void svec_fmc_destroy(struct svec_dev *svec);
/* Functions in svec-i2c.c, used by svec-fmc.c */
......@@ -138,7 +140,7 @@ int svec_dma_read(struct svec_dev *svec, uint32_t addr, int am, size_t size,
void *buf, int is_fifo);
int svec_reconfigure(struct svec_dev *svec);
int svec_reconfigure(struct svec_dev *svec, struct fmc_gateware *gw);
int svec_setup_csr(struct svec_dev *svec);
int svec_validate_configuration(struct device *pdev, struct svec_config *cfg);
......
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