Commit 6edffd1c authored by Federico Vaga's avatar Federico Vaga

Merge branch 'develop'

parents 5e972983 3f8b3d4a
......@@ -5,14 +5,9 @@ REPO_PARENT ?= $(shell /bin/pwd)/../..
LINUX ?= /lib/modules/$(shell uname -r)/build
FMC_ABS ?= $(abspath $(FMC))
I2C_ABS ?= $(abspath $(I2C))
CONFIG_FPGA_MGR_BACKPORT_PATH_ABS ?= $(abspath $(CONFIG_FPGA_MGR_BACKPORT_PATH))
GIT_VERSION = $(shell git describe --dirty --long --tags)
export GIT_VERSION
all: modules
......
......@@ -3,6 +3,8 @@
* Copyright (C) 2017 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*/
#include <linux/kallsyms.h>
#include <linux/module.h>
#include <linux/fpga/fpga-mgr.h>
#include <linux/version.h>
#include "spec-compat.h"
......@@ -93,3 +95,96 @@ void compat_fpga_mgr_unregister(struct fpga_manager *mgr)
fpga_mgr_unregister(mgr);
}
#endif
#if KERNEL_VERSION(4,10,0) > LINUX_VERSION_CODE
struct fpga_manager *__fpga_mgr_get(struct device *dev)
{
struct fpga_manager *mgr;
int ret = -ENODEV;
mgr = to_fpga_manager(dev);
if (!mgr)
goto err_dev;
/* Get exclusive use of fpga manager */
if (!mutex_trylock(&mgr->ref_mutex)) {
ret = -EBUSY;
goto err_dev;
}
if (!try_module_get(dev->parent->driver->owner))
goto err_ll_mod;
return mgr;
err_ll_mod:
mutex_unlock(&mgr->ref_mutex);
err_dev:
put_device(dev);
return ERR_PTR(ret);
}
static int fpga_mgr_dev_match(struct device *dev, const void *data)
{
return dev->parent == data;
}
/**
* fpga_mgr_get - get an exclusive reference to a fpga mgr
* @dev:parent device that fpga mgr was registered with
*
* Given a device, get an exclusive reference to a fpga mgr.
*
* Return: fpga manager struct or IS_ERR() condition containing error code.
*/
struct fpga_manager *fpga_mgr_get(struct device *dev)
{
void *fpga_mgr_class = (void*) kallsyms_lookup_name("fpga_mgr_class");
struct device *mgr_dev = class_find_device(fpga_mgr_class, NULL, dev,
fpga_mgr_dev_match);
if (!mgr_dev)
return ERR_PTR(-ENODEV);
return __fpga_mgr_get(mgr_dev);
}
#endif
static int __compat_spec_fw_load(struct fpga_manager *mgr, const char *name)
{
#if KERNEL_VERSION(4,16,0) > LINUX_VERSION_CODE && !defined(CONFIG_FPGA_MGR_BACKPORT)
#if KERNEL_VERSION(4,10,0) > LINUX_VERSION_CODE
return fpga_mgr_firmware_load(mgr, 0, name);
#else
struct fpga_image_info image;
memset(&image, 0, sizeof(image));
return fpga_mgr_firmware_load(mgr, &image, name);
#endif
#else
struct fpga_image_info image;
memset(&image, 0, sizeof(image));
image.firmware_name = (char *)name;
image.dev = mgr->dev.parent;
return fpga_mgr_load(mgr, &image);
#endif
}
int compat_spec_fw_load(struct spec_dev *spec, const char *name)
{
struct fpga_manager *mgr;
int err;
mgr = fpga_mgr_get(&spec->dev);
if (IS_ERR(mgr))
return -ENODEV;
err = __compat_spec_fw_load(mgr, name);
fpga_mgr_put(mgr);
return err;
}
......@@ -6,6 +6,7 @@
#include <linux/fpga/fpga-mgr.h>
#include <linux/types.h>
#include <linux/version.h>
#include "spec.h"
#if KERNEL_VERSION(4,10,0) <= LINUX_VERSION_CODE
#if KERNEL_VERSION(4,16,0) > LINUX_VERSION_CODE
......@@ -54,3 +55,19 @@ struct fpga_manager *compat_fpga_mgr_create(struct device *dev,
void compat_fpga_mgr_free(struct fpga_manager *mgr);
int compat_fpga_mgr_register(struct fpga_manager *mgr);
void compat_fpga_mgr_unregister(struct fpga_manager *mgr);
int compat_spec_fw_load(struct spec_dev *spec, const char *name);
#if KERNEL_VERSION(3, 11, 0) > LINUX_VERSION_CODE
#define __ATTR_RW(_name) __ATTR(_name, (S_IWUSR | S_IRUGO), \
_name##_show, _name##_store)
#define __ATTR_WO(_name) { \
.attr = { .name = __stringify(_name), .mode = S_IWUSR }, \
.store = _name##_store, \
}
#define DEVICE_ATTR_RW(_name) \
struct device_attribute dev_attr_##_name = __ATTR_RW(_name)
#define DEVICE_ATTR_RO(_name) \
struct device_attribute dev_attr_##_name = __ATTR_RO(_name)
#define DEVICE_ATTR_WO(_name) \
struct device_attribute dev_attr_##_name = __ATTR_WO(_name)
#endif
......@@ -11,14 +11,123 @@
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/firmware.h>
#include <linux/moduleparam.h>
#include "spec.h"
#include "spec-compat.h"
static char *spec_fw_name_45t = "spec-init-45T.bin";
static char *spec_fw_name_100t = "spec-init-100T.bin";
static char *spec_fw_name_150t = "spec-init-150T.bin";
char *spec_fw_name = "";
module_param_named(fw_name, spec_fw_name, charp, 0444);
/**
* Return the SPEC defult FPGA firmware name based on PCI ID
* @spec: SPEC device
*
* Return: FPGA firmware name
*/
static const char *spec_fw_name_init_get(struct spec_dev *spec)
{
struct pci_dev *pdev = to_pci_dev(spec->dev.parent);
if (strlen(spec_fw_name) > 0)
return spec_fw_name;
switch (pdev->device) {
case PCI_DEVICE_ID_SPEC_45T:
return spec_fw_name_45t;
case PCI_DEVICE_ID_SPEC_100T:
return spec_fw_name_100t;
case PCI_DEVICE_ID_SPEC_150T:
return spec_fw_name_150t;
default:
return NULL;
}
}
/**
* Load FPGA code
* @spec: SPEC device
* @name: FPGA bitstream file name
*
* Return: 0 on success, otherwise a negative error number
*/
static int spec_fw_load(struct spec_dev *spec, const char *name)
{
pr_info("%s:%d %s\n", __func__, __LINE__, name);
return compat_spec_fw_load(spec, name);
}
/**
* Return: True if the FPGA is programmed, otherwise false
*/
static bool spec_fw_is_pre_programmed(struct spec_dev *spec)
{
return false;
}
/**
* Load default FPGA code
* @spec: SPEC device
*
* Return: 0 on success, otherwise a negative error number
*/
static int spec_fw_load_init(struct spec_dev *spec)
{
if (spec_fw_is_pre_programmed(spec))
return 0;
return spec_fw_load(spec, spec_fw_name_init_get(spec));
}
static ssize_t fpga_load_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int err;
err = spec_fw_load(to_spec_dev(dev), buf);
return err ? err : count;
}
static DEVICE_ATTR_WO(fpga_load);
static struct attribute *spec_attrs[] = {
&dev_attr_fpga_load.attr,
NULL,
};
static struct attribute_group spec_attr_group = {
.attrs = spec_attrs,
};
static const struct attribute_group *spec_attr_groups[] = {
&spec_attr_group,
NULL,
};
static void spec_release(struct device *dev)
{
}
static int spec_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return 0;
}
static const struct device_type spec_dev_type = {
.name = "spec",
.release = spec_release,
.groups = spec_attr_groups,
.uevent = spec_uevent,
};
static int spec_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
......@@ -52,7 +161,7 @@ static int spec_probe(struct pci_dev *pdev,
goto err_remap;
spec->dev.parent = &pdev->dev;
spec->dev.release = spec_release;
spec->dev.type = &spec_dev_type;
err = dev_set_name(&spec->dev, "spec-%s", dev_name(&pdev->dev));
if (err)
goto err_name;
......@@ -60,6 +169,8 @@ static int spec_probe(struct pci_dev *pdev,
err = device_register(&spec->dev);
if (err)
goto err_dev;
/* This virtual device is assciated with this driver */
spec->dev.driver = pdev->dev.driver;
err = spec_fpga_init(spec);
if (err)
......@@ -69,10 +180,17 @@ static int spec_probe(struct pci_dev *pdev,
if (err)
goto err_irq;
err = spec_fw_load_init(spec);
if (err)
goto err_fw;
pci_set_drvdata(pdev, spec);
dev_info(spec->dev.parent, "Spec registered devptr=0x%p\n", spec->dev.parent);
return 0;
err_fw:
spec_irq_exit(spec);
err_irq:
spec_fpga_exit(spec);
err_fpga:
......
......@@ -6,8 +6,8 @@
*
* Driver for SPEC (Simple PCI FMC carrier) board.
*/
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
......
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