From f9065e5ea9d2324a41c04671a6bd2f1062a6c201 Mon Sep 17 00:00:00 2001 From: Alessandro Rubini <rubini@gnudd.com> Date: Tue, 17 Jul 2012 01:02:13 +0200 Subject: [PATCH] initial fmc-core.c and header --- kernel/Makefile | 7 +- kernel/fmc-core.c | 137 +++++++++++++++++++++++++++++ kernel/include/linux/fmc.h | 57 ++++++++++++ kernel/{spec-wr-nic.c => wr-nic.c} | 0 4 files changed, 199 insertions(+), 2 deletions(-) create mode 100644 kernel/fmc-core.c create mode 100644 kernel/include/linux/fmc.h rename kernel/{spec-wr-nic.c => wr-nic.c} (100%) diff --git a/kernel/Makefile b/kernel/Makefile index 806c602..554bd63 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,8 +1,11 @@ LINUX ?= /lib/modules/$(shell uname -r)/build -obj-m = spec.o -obj-m += spec-wr-nic.o +ccflags-y = -I$M/include + +obj-m = fmc-core.o +obj-m += spec.o +obj-m += wr-nic.o spec-objs = spec-core.o loader-ll.o diff --git a/kernel/fmc-core.c b/kernel/fmc-core.c new file mode 100644 index 0000000..b8705fb --- /dev/null +++ b/kernel/fmc-core.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2012 CERN (www.cern.ch) + * Author: Alessandro Rubini <rubini@gnudd.com> + * + * Released according to the GNU GPL, version 2 or any later version. + * + * This work is part of the White Rabbit project, a research effort led + * by CERN, the European Institute for Nuclear Research. + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/fmc.h> +#include "spec.h" + +static int fmc_match(struct device *dev, struct device_driver *drv) +{ + struct fmc_driver *fdrv = to_fmc_driver(drv); + struct fmc_device *fdev = to_fmc_device(dev); + const struct fmc_device_id *t = fdrv->id_table; + + /* Currently, return 1 every time, until we define policies */ + return 1; +} + +static int fmc_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct fmc_device *fdev = to_fmc_device(dev); + + /* FIXME: The MODALIAS */ + add_uevent_var(env, "MODALIAS=%s", "fmc"); + return 0; +} + +static int fmc_probe(struct device *dev) +{ + struct fmc_driver *fdrv = to_fmc_driver(dev->driver); + struct fmc_device *fdev = to_fmc_device(dev); + + return fdrv->probe(fdev); +} + +static int fmc_remove(struct device *dev) +{ + struct fmc_driver *fdrv = to_fmc_driver(dev->driver); + struct fmc_device *fdev = to_fmc_device(dev); + + return fdrv->remove(fdev); +} + +static void fmc_shutdown(struct device *dev) +{ + /* not implemented but mandatory */ +} + +static struct bus_type fmc_bus_type = { + .name = "fmc", + .match = fmc_match, + .uevent = fmc_uevent, + .probe = fmc_probe, + .remove = fmc_remove, + .shutdown = fmc_shutdown, +}; + +/* Every device must have a release method: provide a default */ +static void __fmc_release(struct device *dev){ } + +/* This is needed as parent for our devices and dir in sysfs */ +struct device fmc_bus = { + .release = __fmc_release, + .init_name = "fmc", +}; + +/* Functions for client modules */ +int fmc_driver_register(struct fmc_driver *drv) +{ + drv->driver.bus = &fmc_bus_type; + return driver_register(&drv->driver); +} +EXPORT_SYMBOL(fmc_driver_register); + +void fmc_driver_unregister(struct fmc_driver *drv) +{ + driver_unregister(&drv->driver); +} +EXPORT_SYMBOL(fmc_driver_unregister); + +int fmc_device_register(struct fmc_device *fdev) +{ + device_initialize(&fdev->dev); + if (!fdev->dev.release) + fdev->dev.release = __fmc_release; + if (!fdev->dev.parent) + fdev->dev.parent = &fmc_bus; + fdev->dev.bus = &fmc_bus_type; + { + static int i; + + /* FIXME: the name */ + dev_set_name(&fdev->dev, "fmc-%04x", i++); + } + return device_add(&fdev->dev); +} +EXPORT_SYMBOL(fmc_device_register); + +void fmc_device_unregister(struct fmc_device *fdev) +{ + device_del(&fdev->dev); + put_device(&fdev->dev); +} +EXPORT_SYMBOL(fmc_device_unregister); + +/* Init and exit are trivial */ +static int fmc_init(void) +{ + int err; + + err = device_register(&fmc_bus); + if (err) + return err; + err = bus_register(&fmc_bus_type); + if (err) + device_unregister(&fmc_bus); + return err; +} + +static void fmc_exit(void) +{ + bus_unregister(&fmc_bus_type); + device_unregister(&fmc_bus); +} + +module_init(fmc_init); +module_exit(fmc_exit); + +MODULE_LICENSE("GPL"); diff --git a/kernel/include/linux/fmc.h b/kernel/include/linux/fmc.h new file mode 100644 index 0000000..a91cc6c --- /dev/null +++ b/kernel/include/linux/fmc.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012 CERN (www.cern.ch) + * Author: Alessandro Rubini <rubini@gnudd.com> + * + * Released according to the GNU GPL, version 2 or any later version. + * + * This work is part of the White Rabbit project, a research effort led + * by CERN, the European Institute for Nuclear Research. + */ +#ifndef __LINUX_FMC_H__ +#define __LINUX_FMC_H__ + +struct fmc_device; +struct fmc_driver; + +struct fmc_device_id { + /* FIXME: the device ID must be defined according to eeprom contents */ + uint64_t unique_id; +}; + +/* The driver is a pretty simple thing */ +struct fmc_driver { + struct device_driver driver; + int (*probe)(struct fmc_device *); + int (*remove)(struct fmc_device *); + const struct fmc_device_id *id_table; + +}; +#define to_fmc_driver(x) container_of((x), struct fmc_driver, driver) + +/* To be carrier-independent, we need to abstract hardware access */ +struct fmc_operations { + uint32_t (*readl)(struct fmc_device *d, int offset); + uint32_t (*writel)(struct fmc_device *d, int offset, uint32_t value); + void (*irq_ack)(struct fmc_device *d); +}; + +/* The device reports all information needed to access hw */ +struct fmc_device { + struct fmc_device_id id; + struct fmc_operations *op; + int irq; + int eeprom_len; + uint8_t *eeprom; + char *carrier_name; + void *carrier_data; + __iomem void *base; + struct device dev; +}; +#define to_fmc_device(x) container_of((x), struct fmc_device, dev) + +extern int fmc_driver_register(struct fmc_driver *drv); +extern void fmc_driver_unregister(struct fmc_driver *drv); +extern int fmc_device_register(struct fmc_device *tdev); +extern void fmc_device_unregister(struct fmc_device *tdev); + +#endif /* __LINUX_FMC_H__ */ diff --git a/kernel/spec-wr-nic.c b/kernel/wr-nic.c similarity index 100% rename from kernel/spec-wr-nic.c rename to kernel/wr-nic.c -- GitLab