Commit 29c35f2a authored by Federico Vaga's avatar Federico Vaga

Merge branch 'release/v0.3'

parents 3dc5715e 1bf3ef45
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
REPO_PARENT ?= $(shell /bin/pwd)/.. REPO_PARENT ?= $(shell /bin/pwd)/..
-include $(REPO_PARENT)/parent_common.mk -include $(REPO_PARENT)/parent_common.mk
DIRS = kernel doc DIRS = kernel
.PHONY: all clean modules install modules_install $(DIRS) .PHONY: all clean modules install modules_install $(DIRS)
......
...@@ -9,20 +9,21 @@ endif ...@@ -9,20 +9,21 @@ endif
ccflags-y += -DADDITIONAL_VERSIONS="$(SUBMODULE_VERSIONS)" ccflags-y += -DADDITIONAL_VERSIONS="$(SUBMODULE_VERSIONS)"
ccflags-y += -DGIT_VERSION=\"$(GIT_VERSION)\" ccflags-y += -DGIT_VERSION=\"$(GIT_VERSION)\"
ccflags-y += -I$(FPGA_MGR_ABS)/include
ccflags-y += -I$(FMC_ABS)/include
ccflags-y += -I$(I2C_ABS)/include
ccflags-y += -Wall -Werror ccflags-y += -Wall -Werror
# priority to I2C headers from our sources ccflags-$(CONFIG_FPGA_MGR_BACKPORT) += -DCONFIG_FPGA_MGR_BACKPORT
LINUXINCLUDE := -I$(FMC_MGR_ABS)/include -I$(FMC_MGR_ABS)/include/linux -I$(FMC_ABS)/include -I$(FMC_ABS)/include/linux -I$(I2C_ABS)/include -I$(I2C_ABS)/include/linux $(LINUXINCLUDE) ccflags-$(CONFIG_FPGA_MGR_BACKPORT) += -I$(CONFIG_FPGA_MGR_BACKPORT_PATH_ABS)/include
KBUILD_EXTRA_SYMBOLS += $(FPGA_MGR_ABS)/drivers/fpga/Module.symvers ifeq ($(CONFIG_FPGA_MGR_BACKPORT), y)
KBUILD_EXTRA_SYMBOLS += $(FMC_ABS)/drivers/fmc/Module.symvers CONFIG_FPGA_MGR_BACKPORT_INCLUDE := -I$(CONFIG_FPGA_MGR_BACKPORT_PATH_ABS)/include
CONFIG_FPGA_MGR_BACKPORT_INCLUDE += -I$(CONFIG_FPGA_MGR_BACKPORT_PATH_ABS)/include/linux
LINUXINCLUDE := $(CONFIG_FPGA_MGR_BACKPORT_INCLUDE) $(LINUXINCLUDE)
KBUILD_EXTRA_SYMBOLS += $(CONFIG_FPGA_MGR_BACKPORT_PATH_ABS)/drivers/fpga/Module.symvers
endif
obj-m := spec.o obj-m := spec.o
spec-objs := spec-core.o spec-objs := spec-core.o
spec-objs += spec-fpga.o spec-objs += spec-fpga.o
spec-objs += spec-fmc.o
spec-objs += spec-irq.o spec-objs += spec-irq.o
spec-objs += spec-compat.o
...@@ -5,12 +5,12 @@ REPO_PARENT ?= $(shell /bin/pwd)/../.. ...@@ -5,12 +5,12 @@ REPO_PARENT ?= $(shell /bin/pwd)/../..
LINUX ?= /lib/modules/$(shell uname -r)/build LINUX ?= /lib/modules/$(shell uname -r)/build
FPGA_MGR_ABS ?= $(abspath $(FPGA_MGR))
FMC_ABS ?= $(abspath $(FMC)) FMC_ABS ?= $(abspath $(FMC))
I2C_ABS ?= $(abspath $(I2C)) I2C_ABS ?= $(abspath $(I2C))
CONFIG_FPGA_MGR_BACKPORT_PATH_ABS ?= $(abspath $(CONFIG_FPGA_MGR_BACKPORT_PATH))
GIT_VERSION = $(shell git describe --dirty --long --tags) GIT_VERSION = $(shell git describe --dirty --long --tags)
export GIT_VERSION export GIT_VERSION
...@@ -19,7 +19,7 @@ all: modules ...@@ -19,7 +19,7 @@ all: modules
.PHONY: all modules clean help install modules_install .PHONY: all modules clean help install modules_install
modules help install modules_install: modules help install modules_install:
$(MAKE) -C $(LINUX) M=$(shell pwd) GIT_VERSION=$(GIT_VERSION) FPGA_MGR_ABS=$(FPGA_MGR_ABS) FMC_ABS=$(FMC_ABS) I2C_ABS=$(I2C_ABS) $@ $(MAKE) -C $(LINUX) M=$(shell pwd) GIT_VERSION=$(GIT_VERSION) CONFIG_FPGA_MGR_BACKPORT_PATH_ABS=$(CONFIG_FPGA_MGR_BACKPORT_PATH_ABS) CONFIG_FPGA_MGR_BACKPORT=$(CONFIG_FPGA_MGR_BACKPORT) $@
# be able to run the "clean" rule even if $(LINUX) is not valid # be able to run the "clean" rule even if $(LINUX) is not valid
clean: clean:
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2017 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*/
#include <linux/fpga/fpga-mgr.h>
#include <linux/version.h>
#include "spec-compat.h"
int compat_get_fpga_last_word_size(struct fpga_image_info *info, size_t count)
{
#if KERNEL_VERSION(4,16,0) > LINUX_VERSION_CODE && !defined(CONFIG_FPGA_MGR_BACKPORT)
return count;
#else
return info ? info->count : count;
#endif
}
#if KERNEL_VERSION(4,10,0) > LINUX_VERSION_CODE && !defined(CONFIG_FPGA_MGR_BACKPORT)
int compat_spec_fpga_write_init(struct fpga_manager *mgr,
u32 flags,
const char *buf, size_t count)
{
return spec_fpga_write_init(mgr, NULL, buf, count);
}
int compat_spec_fpga_write_complete(struct fpga_manager *mgr,
u32 flags)
{
return spec_fpga_write_complete(mgr, NULL);
}
#else
int compat_spec_fpga_write_init(struct fpga_manager *mgr,
struct fpga_image_info *info,
const char *buf, size_t count)
{
return spec_fpga_write_init(mgr, info, buf, count);
}
int compat_spec_fpga_write_complete(struct fpga_manager *mgr,
struct fpga_image_info *info)
{
return spec_fpga_write_complete(mgr, info);
}
#endif
#if KERNEL_VERSION(4,18,0) > LINUX_VERSION_CODE && !defined(CONFIG_FPGA_MGR_BACKPORT)
struct fpga_manager *compat_fpga_mgr_create(struct device *dev, const char *name,
const struct fpga_manager_ops *mops,
void *priv)
{
int err;
err = fpga_mgr_register(dev, name, mops, priv);
if (err)
return NULL;
return (struct fpga_manager *)dev;
}
void compat_fpga_mgr_free(struct fpga_manager *mgr)
{
fpga_mgr_unregister((struct device *)mgr);
}
int compat_fpga_mgr_register(struct fpga_manager *mgr)
{
return mgr ? 0 : 1;
}
void compat_fpga_mgr_unregister(struct fpga_manager *mgr)
{
fpga_mgr_unregister((struct device *)mgr);
}
#else
struct fpga_manager *compat_fpga_mgr_create(struct device *dev,
const char *name,
const struct fpga_manager_ops *mops,
void *priv)
{
return fpga_mgr_create(dev, name, mops, priv);
}
void compat_fpga_mgr_free(struct fpga_manager *mgr)
{
fpga_mgr_free(mgr);
}
int compat_fpga_mgr_register(struct fpga_manager *mgr)
{
return fpga_mgr_register(mgr);
}
void compat_fpga_mgr_unregister(struct fpga_manager *mgr)
{
fpga_mgr_unregister(mgr);
}
#endif
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2017 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*/
#include <linux/fpga/fpga-mgr.h>
#include <linux/types.h>
#include <linux/version.h>
#if KERNEL_VERSION(4,10,0) <= LINUX_VERSION_CODE
#if KERNEL_VERSION(4,16,0) > LINUX_VERSION_CODE
/* So that we select the buffer size because smaller */
#define compat_fpga_ops_initial_header_size .initial_header_size = 0xFFFFFFFF,
#else
#define compat_fpga_ops_initial_header_size .initial_header_size = 0,
#endif
#else
#define compat_fpga_ops_initial_header_size
#endif
#if KERNEL_VERSION(4,16,0) > LINUX_VERSION_CODE && ! defined(CONFIG_FPGA_MGR_BACKPORT)
#define compat_fpga_ops_groups
#else
#define compat_fpga_ops_groups .groups = NULL,
#endif
#if KERNEL_VERSION(4,10,0) > LINUX_VERSION_CODE && ! defined(CONFIG_FPGA_MGR_BACKPORT)
struct fpga_image_info;
#endif
int spec_fpga_write_init(struct fpga_manager *mgr,
struct fpga_image_info *info,
const char *buf, size_t count);
int spec_fpga_write_complete(struct fpga_manager *mgr,
struct fpga_image_info *info);
#if KERNEL_VERSION(4,10,0) > LINUX_VERSION_CODE && ! defined(CONFIG_FPGA_MGR_BACKPORT)
int compat_spec_fpga_write_init(struct fpga_manager *mgr, u32 flags,
const char *buf, size_t count);
int compat_spec_fpga_write_complete(struct fpga_manager *mgr, u32 flags);
#else
int compat_spec_fpga_write_init(struct fpga_manager *mgr,
struct fpga_image_info *info,
const char *buf, size_t count);
int compat_spec_fpga_write_complete(struct fpga_manager *mgr,
struct fpga_image_info *info);
#endif
int compat_get_fpga_last_word_size(struct fpga_image_info *info,
size_t count);
struct fpga_manager *compat_fpga_mgr_create(struct device *dev,
const char *name,
const struct fpga_manager_ops *mops,
void *priv);
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);
...@@ -14,6 +14,10 @@ ...@@ -14,6 +14,10 @@
#include "spec.h" #include "spec.h"
static void spec_release(struct device *dev)
{
}
static int spec_probe(struct pci_dev *pdev, static int spec_probe(struct pci_dev *pdev,
const struct pci_device_id *id) const struct pci_device_id *id)
...@@ -21,11 +25,9 @@ static int spec_probe(struct pci_dev *pdev, ...@@ -21,11 +25,9 @@ static int spec_probe(struct pci_dev *pdev,
struct spec_dev *spec; struct spec_dev *spec;
int err, i; int err, i;
spec = kzalloc(sizeof(struct spec_dev), GFP_KERNEL); spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec) if (!spec)
return -ENOMEM; return -ENOMEM;
spec->pdev = pdev;
pci_set_drvdata(pdev, spec);
err = pci_enable_device(pdev); err = pci_enable_device(pdev);
if (err) if (err)
...@@ -49,30 +51,37 @@ static int spec_probe(struct pci_dev *pdev, ...@@ -49,30 +51,37 @@ static int spec_probe(struct pci_dev *pdev,
if (err) if (err)
goto err_remap; goto err_remap;
err = spec_fpga_init(spec); spec->dev.parent = &pdev->dev;
spec->dev.release = spec_release;
err = dev_set_name(&spec->dev, "spec-%s", dev_name(&pdev->dev));
if (err) if (err)
goto err_fpga; goto err_name;
err = device_register(&spec->dev);
if (err)
goto err_dev;
err = spec_fmc_init(spec); err = spec_fpga_init(spec);
if (err) if (err)
goto err_fmc; goto err_fpga;
err = spec_irq_init(spec); err = spec_irq_init(spec);
if (err) if (err)
goto err_irq; goto err_irq;
pci_set_drvdata(pdev, spec);
return 0; return 0;
err_irq: err_irq:
spec_fmc_exit(spec);
err_fmc:
spec_fpga_exit(spec); spec_fpga_exit(spec);
err_fpga: err_fpga:
pci_set_drvdata(pdev, NULL); device_unregister(&spec->dev);
err_dev:
err_name:
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
if (spec->remap[i]) if (spec->remap[i])
iounmap(spec->remap[i]); iounmap(spec->remap[i]);
spec->remap[i] = NULL;
} }
err_remap: err_remap:
pci_disable_device(pdev); pci_disable_device(pdev);
...@@ -87,17 +96,14 @@ static void spec_remove(struct pci_dev *pdev) ...@@ -87,17 +96,14 @@ static void spec_remove(struct pci_dev *pdev)
struct spec_dev *spec = pci_get_drvdata(pdev); struct spec_dev *spec = pci_get_drvdata(pdev);
int i; int i;
pci_set_drvdata(pdev, NULL);
spec_irq_exit(spec); spec_irq_exit(spec);
spec_fmc_exit(spec);
spec_fpga_exit(spec); spec_fpga_exit(spec);
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++)
if (spec->remap[i]) if (spec->remap[i])
iounmap(spec->remap[i]); iounmap(spec->remap[i]);
spec->remap[i] = NULL; device_unregister(&spec->dev);
}
pci_disable_device(pdev); pci_disable_device(pdev);
kfree(spec); kfree(spec);
} }
......
/*
* Copyright (C) 2017 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <linux/kernel.h>
#include <linux/platform_data/i2c-ocores.h>
#include "spec.h"
static int spec_fmc_is_present(struct fmc_carrier *carrier,
struct fmc_slot *slot)
{
/* TODO implement me */
return 0;
}
static const struct fmc_carrier_operations spec_fmc_ops = {
.is_present = spec_fmc_is_present,
};
static const struct ocores_i2c_platform_data pdata = {
.reg_shift = 0,
.reg_io_width = 4,
.clock_khz = 62500,
.big_endian = 0,
.num_devices = 0,
.devices = NULL,
};
static int spec_i2c_find_adapter(struct device *dev, void *data)
{
struct spec_dev *spec = data;
struct i2c_adapter *adap, *adap_parent;
if (dev->type != &i2c_adapter_type)
return 0;
adap = to_i2c_adapter(dev);
adap_parent = i2c_parent_is_i2c_adapter(adap);
if (!adap_parent)
return 0;
if (&spec->i2c_pdev->dev != adap_parent->dev.parent)
return 0;
/* Found! */
return i2c_adapter_id(adap);
}
/**
* Get the I2C adapter associated with an FMC slot
* @spec: SPEC instance
*
* Return: the I2C bus to be used
*/
static int spec_i2c_get_bus(struct spec_dev *spec)
{
return i2c_for_each_dev(spec, spec_i2c_find_adapter);
}
static int id;
/**
* It builds the platform_device_info necessary to register the
* I2C master device.
* @spec the SPEC instance
*
* Return: an array of I2C master devices
*/
static int spec_i2c_add(struct spec_dev *spec)
{
struct resource res = {
.name = "i2c-ocores-mem",
.flags = IORESOURCE_MEM,
};
int err;
/* VME function 1 */
res.start = pci_resource_start(to_pci_dev(spec->pdev->dev.parent), 0);
res.start += SPEC_I2C_MASTER_ADDR;
res.end = res.start + SPEC_I2C_MASTER_SIZE;
/* FIXME find better ID */
spec->i2c_pdev = platform_device_register_resndata(&spec->pdev->dev,
"ocores-i2c", id++,
&res, 1,
&pdata,
sizeof(pdata));
if (!spec->i2c_pdev)
return -ENODEV;
err = i2c_for_each_dev(spec, spec_i2c_find_adapter);
if (err <= 0)
goto err;
return 0;
err:
platform_device_unregister(spec->i2c_pdev);
return -ENODEV;
}
static void spec_i2c_del(struct spec_dev *spec)
{
platform_device_unregister(spec->i2c_pdev);
if (spec->i2c_adapter)
i2c_put_adapter(spec->i2c_adapter);
}
int spec_fmc_init(struct spec_dev *spec)
{
int err;
return 0; /* UNTIL WE TEST IT */
if (!spec)
return -EINVAL;
err = spec_i2c_add(spec);
if (err)
goto err_i2c;
spec->slot_info.i2c_bus_nr = spec_i2c_get_bus(spec);
if (spec->slot_info.i2c_bus_nr <= 0)
goto err_i2c_bus;
spec->slot_info.ga = 0;
spec->slot_info.lun = 0;
err = fmc_carrier_register(&spec->pdev->dev, &spec_fmc_ops,
SPEC_FMC_SLOTS, &spec->slot_info, spec);
if (err)
goto err_fmc;
return 0;
err_fmc:
err_i2c_bus:
spec_i2c_del(spec);
err_i2c:
return err;
}
void spec_fmc_exit(struct spec_dev *spec)
{
return; /* UNTIL WE TEST IT */
if (!spec)
return;
fmc_carrier_unregister(&spec->pdev->dev);
spec_i2c_del(spec);
}
...@@ -4,10 +4,11 @@ ...@@ -4,10 +4,11 @@
* *
* SPDX-License-Identifier: GPL-2.0-or-later * SPDX-License-Identifier: GPL-2.0-or-later
*/ */
#include <linux/fpga/fpga-mgr.h>
#include <linux/delay.h> #include <linux/delay.h>
#include "spec.h" #include "spec.h"
#include "spec-compat.h"
static inline uint8_t reverse_bits8(uint8_t x) static inline uint8_t reverse_bits8(uint8_t x)
{ {
...@@ -240,15 +241,16 @@ static enum fpga_mgr_states spec_fpga_state(struct fpga_manager *mgr) ...@@ -240,15 +241,16 @@ static enum fpga_mgr_states spec_fpga_state(struct fpga_manager *mgr)
} }
static int spec_fpga_write_init(struct fpga_manager *mgr, int spec_fpga_write_init(struct fpga_manager *mgr,
struct fpga_image_info *info, struct fpga_image_info *info,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct spec_dev *spec = mgr->priv; struct spec_dev *spec = mgr->priv;
int err = 0; int err = 0, last_word_size;
gn4124_fpga_gpio_config(spec); gn4124_fpga_gpio_config(spec);
err = gn4124_fpga_fcl_init(spec, info->count & 0x3); last_word_size = compat_get_fpga_last_word_size(info, count) & 0x3;
err = gn4124_fpga_fcl_init(spec, last_word_size);
if (err < 0) if (err < 0)
goto err; goto err;
...@@ -259,7 +261,6 @@ err: ...@@ -259,7 +261,6 @@ err:
return err; return err;
} }
static int spec_fpga_write(struct fpga_manager *mgr, const char *buf, size_t count) static int spec_fpga_write(struct fpga_manager *mgr, const char *buf, size_t count)
{ {
struct spec_dev *spec = mgr->priv; struct spec_dev *spec = mgr->priv;
...@@ -268,8 +269,8 @@ static int spec_fpga_write(struct fpga_manager *mgr, const char *buf, size_t cou ...@@ -268,8 +269,8 @@ static int spec_fpga_write(struct fpga_manager *mgr, const char *buf, size_t cou
} }
static int spec_fpga_write_complete(struct fpga_manager *mgr, int spec_fpga_write_complete(struct fpga_manager *mgr,
struct fpga_image_info *info) struct fpga_image_info *info)
{ {
struct spec_dev *spec = mgr->priv; struct spec_dev *spec = mgr->priv;
int err; int err;
...@@ -292,15 +293,15 @@ static void spec_fpga_remove(struct fpga_manager *mgr) ...@@ -292,15 +293,15 @@ static void spec_fpga_remove(struct fpga_manager *mgr)
/* do nothing */ /* do nothing */
} }
static const struct fpga_manager_ops spec_fpga_ops = { static const struct fpga_manager_ops spec_fpga_ops = {
.initial_header_size = 0, compat_fpga_ops_initial_header_size
compat_fpga_ops_groups
.state = spec_fpga_state, .state = spec_fpga_state,
.write_init = spec_fpga_write_init, .write_init = compat_spec_fpga_write_init,
.write = spec_fpga_write, .write = spec_fpga_write,
.write_complete = spec_fpga_write_complete, .write_complete = compat_spec_fpga_write_complete,
.fpga_remove = spec_fpga_remove, .fpga_remove = spec_fpga_remove,
.groups = NULL,
}; };
...@@ -308,18 +309,15 @@ int spec_fpga_init(struct spec_dev *spec) ...@@ -308,18 +309,15 @@ int spec_fpga_init(struct spec_dev *spec)
{ {
int err; int err;
if (!spec) spec->mgr = compat_fpga_mgr_create(&spec->dev,
return -EINVAL; dev_name(&spec->dev),
&spec_fpga_ops, spec);
spec->mgr = fpga_mgr_create(&spec->pdev->dev, if (!spec || !spec->mgr)
dev_name(&spec->pdev->dev),
&spec_fpga_ops, spec);
if (!spec->mgr)
return -EPERM; return -EPERM;
err = fpga_mgr_register(spec->mgr); err = compat_fpga_mgr_register(spec->mgr);
if (err) { if (err) {
fpga_mgr_free(spec->mgr); compat_fpga_mgr_free(spec->mgr);
return err; return err;
} }
...@@ -328,7 +326,7 @@ int spec_fpga_init(struct spec_dev *spec) ...@@ -328,7 +326,7 @@ int spec_fpga_init(struct spec_dev *spec)
void spec_fpga_exit(struct spec_dev *spec) void spec_fpga_exit(struct spec_dev *spec)
{ {
if (!spec || !spec->mgr) if (!spec)
return; return;
fpga_mgr_unregister(spec->mgr); compat_fpga_mgr_unregister(spec->mgr);
} }
...@@ -36,9 +36,9 @@ static int spec_irq_dbg_info(struct seq_file *s, void *offset) ...@@ -36,9 +36,9 @@ static int spec_irq_dbg_info(struct seq_file *s, void *offset)
struct spec_dev *spec = s->private; struct spec_dev *spec = s->private;
int i; int i;
seq_printf(s, "'%s':\n",dev_name(&spec->pdev->dev)); seq_printf(s, "'%s':\n",dev_name(spec->dev.parent));
seq_printf(s, " redirect: %d\n", spec->pdev->irq); seq_printf(s, " redirect: %d\n", to_pci_dev(spec->dev.parent)->irq);
seq_printf(s, " irq-mapping:\n"); seq_printf(s, " irq-mapping:\n");
for (i = 0; i < GN4124_GPIO_IRQ_MAX; ++i) { for (i = 0; i < GN4124_GPIO_IRQ_MAX; ++i) {
seq_printf(s, " - hardware: %d\n", i); seq_printf(s, " - hardware: %d\n", i);
...@@ -73,9 +73,9 @@ static const struct file_operations spec_irq_dbg_info_ops = { ...@@ -73,9 +73,9 @@ static const struct file_operations spec_irq_dbg_info_ops = {
*/ */
static int spec_irq_debug_init(struct spec_dev *spec) static int spec_irq_debug_init(struct spec_dev *spec)
{ {
spec->dbg_dir = debugfs_create_dir(dev_name(&spec->pdev->dev), NULL); spec->dbg_dir = debugfs_create_dir(dev_name(&spec->dev), NULL);
if (IS_ERR_OR_NULL(spec->dbg_dir)) { if (IS_ERR_OR_NULL(spec->dbg_dir)) {
dev_err(&spec->pdev->dev, dev_err(&spec->dev,
"Cannot create debugfs directory (%ld)\n", "Cannot create debugfs directory (%ld)\n",
PTR_ERR(spec->dbg_dir)); PTR_ERR(spec->dbg_dir));
return PTR_ERR(spec->dbg_dir); return PTR_ERR(spec->dbg_dir);
...@@ -85,7 +85,7 @@ static int spec_irq_debug_init(struct spec_dev *spec) ...@@ -85,7 +85,7 @@ static int spec_irq_debug_init(struct spec_dev *spec)
spec->dbg_dir, spec, spec->dbg_dir, spec,
&spec_irq_dbg_info_ops); &spec_irq_dbg_info_ops);
if (IS_ERR_OR_NULL(spec->dbg_info)) { if (IS_ERR_OR_NULL(spec->dbg_info)) {
dev_err(&spec->pdev->dev, dev_err(&spec->dev,
"Cannot create debugfs file \"%s\" (%ld)\n", "Cannot create debugfs file \"%s\" (%ld)\n",
SPEC_DBG_INFO_NAME, PTR_ERR(spec->dbg_info)); SPEC_DBG_INFO_NAME, PTR_ERR(spec->dbg_info));
return PTR_ERR(spec->dbg_info); return PTR_ERR(spec->dbg_info);
...@@ -101,8 +101,7 @@ static int spec_irq_debug_init(struct spec_dev *spec) ...@@ -101,8 +101,7 @@ static int spec_irq_debug_init(struct spec_dev *spec)
*/ */
static void spec_irq_debug_exit(struct spec_dev *spec) static void spec_irq_debug_exit(struct spec_dev *spec)
{ {
if (spec->dbg_dir) debugfs_remove_recursive(spec->dbg_dir);
debugfs_remove_recursive(spec->dbg_dir);
} }
...@@ -139,7 +138,8 @@ static int spec_irq_gpio_set_type(struct irq_data *d, unsigned int flow_type) ...@@ -139,7 +138,8 @@ static int spec_irq_gpio_set_type(struct irq_data *d, unsigned int flow_type)
*/ */
if ((flow_type & IRQ_TYPE_LEVEL_MASK) && if ((flow_type & IRQ_TYPE_LEVEL_MASK) &&
(flow_type & IRQ_TYPE_EDGE_BOTH)) { (flow_type & IRQ_TYPE_EDGE_BOTH)) {
dev_err(&spec->pdev->dev, "Impossible to set GPIO IRQ %ld to both LEVEL and EDGE (0x%x)\n", dev_err(&spec->dev,
"Impossible to set GPIO IRQ %ld to both LEVEL and EDGE (0x%x)\n",
d->hwirq, flow_type); d->hwirq, flow_type);
return -EINVAL; return -EINVAL;
} }
...@@ -215,27 +215,6 @@ static struct irq_chip spec_irq_gpio_chip = { ...@@ -215,27 +215,6 @@ static struct irq_chip spec_irq_gpio_chip = {
.irq_set_type = spec_irq_gpio_set_type, .irq_set_type = spec_irq_gpio_set_type,
}; };
/**
* It match a given device with the irq_domain. `struct device_node *` is just
* a convention. actually it can be anything (I do not understand why kernel
* people did not use `void *`)
*
* In our case here we expect a string because we identify this domain by
* name
*/
static int spec_irq_gpio_domain_match(struct irq_domain *d, struct device_node *node)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0)
char *name = (char *)node;
if (strcmp(d->name, name) == 0)
return 1;
#endif
return 0;
}
/** /**
* Given the hardware IRQ and the Linux IRQ number (virtirq), configure the * Given the hardware IRQ and the Linux IRQ number (virtirq), configure the
* Linux IRQ number in order to handle properly the incoming interrupts * Linux IRQ number in order to handle properly the incoming interrupts
...@@ -258,7 +237,6 @@ static int spec_irq_gpio_domain_map(struct irq_domain *h, ...@@ -258,7 +237,6 @@ static int spec_irq_gpio_domain_map(struct irq_domain *h,
static struct irq_domain_ops spec_irq_gpio_domain_ops = { static struct irq_domain_ops spec_irq_gpio_domain_ops = {
.match = spec_irq_gpio_domain_match,
.map = spec_irq_gpio_domain_map, .map = spec_irq_gpio_domain_map,
}; };
...@@ -370,7 +348,7 @@ static int spec_irq_gpio_init(struct spec_dev *spec) ...@@ -370,7 +348,7 @@ static int spec_irq_gpio_init(struct spec_dev *spec)
return -ENOMEM; return -ENOMEM;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0)
spec->gpio_domain->name = kasprintf(GFP_KERNEL, "%s-gn4124-gpio-irq", spec->gpio_domain->name = kasprintf(GFP_KERNEL, "%s-gn4124-gpio-irq",
dev_name(&spec->pdev->dev)); dev_name(&spec->dev));
#endif #endif
...@@ -449,7 +427,7 @@ static int spec_irq_sw_test(struct spec_dev *spec) ...@@ -449,7 +427,7 @@ static int spec_irq_sw_test(struct spec_dev *spec)
msecs_to_jiffies(10000)); msecs_to_jiffies(10000));
if (ret == 0) { if (ret == 0) {
gennum_writel(spec, 0x0000, GNINT_STAT); /* disable */ gennum_writel(spec, 0x0000, GNINT_STAT); /* disable */
dev_err(&spec->pdev->dev, "Cannot receive interrupts\n"); dev_err(&spec->dev, "Cannot receive interrupts\n");
return -EINVAL; return -EINVAL;
} }
return 0; return 0;
...@@ -463,6 +441,7 @@ static int spec_irq_sw_test(struct spec_dev *spec) ...@@ -463,6 +441,7 @@ static int spec_irq_sw_test(struct spec_dev *spec)
*/ */
int spec_irq_init(struct spec_dev *spec) int spec_irq_init(struct spec_dev *spec)
{ {
int irq = to_pci_dev(spec->dev.parent)->irq;
int err; int err;
int i; int i;
...@@ -481,22 +460,21 @@ int spec_irq_init(struct spec_dev *spec) ...@@ -481,22 +460,21 @@ int spec_irq_init(struct spec_dev *spec)
goto err_sw; goto err_sw;
#if CHAIN #if CHAIN
irq_set_chained_handler(spec->pdev->irq, spec_irq_chain_handler); irq_set_chained_handler(irq, spec_irq_chain_handler);
irq_set_handler_data(spec->pdev->irq, spec); irq_set_handler_data(irq, spec);
#else #else
/* /*
* It depends on the platform and on the IRQ on which we are connecting to * It depends on the platform and on the IRQ on which we are connecting to
* but most likely our interrupt handler will be a thread. * but most likely our interrupt handler will be a thread.
*/ */
err = request_threaded_irq(spec->pdev->irq, err = request_threaded_irq(irq,
spec_irq_handler, spec_irq_handler,
spec_irq_gpio_handler, spec_irq_gpio_handler,
IRQF_SHARED, IRQF_SHARED,
dev_name(&spec->pdev->dev), dev_name(&spec->dev),
spec); spec);
if (err) { if (err) {
dev_err(&spec->pdev->dev, "Can't request IRQ %d (%d)\n", dev_err(&spec->dev, "Can't request IRQ %d (%d)\n", irq, err);
spec->pdev->irq, err);
goto err_req; goto err_req;
} }
#endif #endif
...@@ -510,7 +488,7 @@ int spec_irq_init(struct spec_dev *spec) ...@@ -510,7 +488,7 @@ int spec_irq_init(struct spec_dev *spec)
err_test: err_test:
spec_irq_debug_exit(spec); spec_irq_debug_exit(spec);
free_irq(spec->pdev->irq, spec); free_irq(irq, spec);
err_req: err_req:
spec_irq_sw_exit(spec); spec_irq_sw_exit(spec);
err_sw: err_sw:
...@@ -522,6 +500,7 @@ err_gpio: ...@@ -522,6 +500,7 @@ err_gpio:
void spec_irq_exit(struct spec_dev *spec) void spec_irq_exit(struct spec_dev *spec)
{ {
int i; int i;
int irq = to_pci_dev(spec->dev.parent)->irq;
if (!spec) if (!spec)
return; return;
...@@ -529,8 +508,9 @@ void spec_irq_exit(struct spec_dev *spec) ...@@ -529,8 +508,9 @@ void spec_irq_exit(struct spec_dev *spec)
/* disable all source of interrupts */ /* disable all source of interrupts */
for (i = 0; i < 7; i++) for (i = 0; i < 7; i++)
gennum_writel(spec, 0, GNINT_CFG(i)); gennum_writel(spec, 0, GNINT_CFG(i));
spec_irq_debug_exit(spec); spec_irq_debug_exit(spec);
free_irq(spec->pdev->irq, spec); free_irq(irq, spec);
spec_irq_sw_exit(spec); spec_irq_sw_exit(spec);
spec_irq_gpio_exit(spec); spec_irq_gpio_exit(spec);
} }
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/fmc.h>
#include <linux/fpga/fpga-mgr.h> #include <linux/fpga/fpga-mgr.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
...@@ -119,7 +118,7 @@ enum { ...@@ -119,7 +118,7 @@ enum {
* @compl: for IRQ testing * @compl: for IRQ testing
*/ */
struct spec_dev { struct spec_dev {
struct pci_dev *pdev; struct device dev;
struct irq_domain *gpio_domain; struct irq_domain *gpio_domain;
...@@ -128,10 +127,6 @@ struct spec_dev { ...@@ -128,10 +127,6 @@ struct spec_dev {
DECLARE_BITMAP(flags, SPEC_FLAG_BITS); DECLARE_BITMAP(flags, SPEC_FLAG_BITS);
void __iomem *remap[3]; /* ioremap of bar 0, 2, 4 */ void __iomem *remap[3]; /* ioremap of bar 0, 2, 4 */
struct fmc_slot_info slot_info;
struct platform_device *i2c_pdev;
struct i2c_adapter *i2c_adapter;
struct dentry *dbg_dir; struct dentry *dbg_dir;
#define SPEC_DBG_INFO_NAME "info" #define SPEC_DBG_INFO_NAME "info"
struct dentry *dbg_info; struct dentry *dbg_info;
...@@ -140,6 +135,11 @@ struct spec_dev { ...@@ -140,6 +135,11 @@ struct spec_dev {
}; };
static inline struct spec_dev *to_spec_dev(struct device *_dev)
{
return container_of(_dev, struct spec_dev, dev);
}
/** /**
* It reads a 32bit register from the gennum chip * It reads a 32bit register from the gennum chip
* @spec spec device instance * @spec spec device instance
...@@ -184,9 +184,6 @@ static inline void gennum_mask_val(struct spec_dev *spec, ...@@ -184,9 +184,6 @@ static inline void gennum_mask_val(struct spec_dev *spec,
extern int spec_fpga_init(struct spec_dev *spec); extern int spec_fpga_init(struct spec_dev *spec);
extern void spec_fpga_exit(struct spec_dev *spec); extern void spec_fpga_exit(struct spec_dev *spec);
extern int spec_fmc_init(struct spec_dev *spec);
extern void spec_fmc_exit(struct spec_dev *spec);
extern int spec_irq_init(struct spec_dev *spec); extern int spec_irq_init(struct spec_dev *spec);
extern void spec_irq_exit(struct spec_dev *spec); extern void spec_irq_exit(struct spec_dev *spec);
......
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