diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2019-06-10 16:04:39 +0200 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2019-06-12 14:23:50 +0200 |
commit | 6a80b30086b861b2591ba2a953042abd08c498e3 (patch) | |
tree | 25bec5e0b2eeeda3d5ef16f534b1e07187cc8561 /drivers | |
parent | 754dfd7992653ca2e2d6f69fcbf0e9ad3f9ba281 (diff) | |
download | linux-6a80b30086b861b2591ba2a953042abd08c498e3.tar.bz2 |
fmc: Delete the FMC subsystem
The FMC subsystem was created in 2012 with the ambition to
drive development of drivers for this hardware upstream.
The current implementation has architectural flaws and would
need to be revamped using real hardware to something that can
reuse existing kernel abstractions in the subsystems for e.g.
I2C, FPGA and GPIO.
We have concluded that for the mainline kernel it will be
better to delete the subsystem and start over with a clean
slate when/if an active maintainer steps up.
For details see:
https://lkml.org/lkml/2018/10/29/534
Suggested-by: Federico Vaga <federico.vaga@cern.ch>
Cc: Pat Riehecky <riehecky@fnal.gov>
Acked-by: Alessandro Rubini <rubini@gnudd.com>
Signed-off-by: Federico Vaga <federico.vaga@cern.ch>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/Kconfig | 2 | ||||
-rw-r--r-- | drivers/Makefile | 1 | ||||
-rw-r--r-- | drivers/fmc/Kconfig | 52 | ||||
-rw-r--r-- | drivers/fmc/Makefile | 15 | ||||
-rw-r--r-- | drivers/fmc/fmc-chardev.c | 199 | ||||
-rw-r--r-- | drivers/fmc/fmc-core.c | 388 | ||||
-rw-r--r-- | drivers/fmc/fmc-debug.c | 172 | ||||
-rw-r--r-- | drivers/fmc/fmc-dump.c | 58 | ||||
-rw-r--r-- | drivers/fmc/fmc-fakedev.c | 355 | ||||
-rw-r--r-- | drivers/fmc/fmc-match.c | 113 | ||||
-rw-r--r-- | drivers/fmc/fmc-private.h | 8 | ||||
-rw-r--r-- | drivers/fmc/fmc-sdb.c | 219 | ||||
-rw-r--r-- | drivers/fmc/fmc-trivial.c | 102 | ||||
-rw-r--r-- | drivers/fmc/fmc-write-eeprom.c | 175 | ||||
-rw-r--r-- | drivers/fmc/fru-parse.c | 80 |
15 files changed, 0 insertions, 1939 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index e8231663f201..61cf4ea2c229 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -188,8 +188,6 @@ source "drivers/ipack/Kconfig" source "drivers/reset/Kconfig" -source "drivers/fmc/Kconfig" - source "drivers/phy/Kconfig" source "drivers/powercap/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 28b030d7988d..6d37564e783c 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -168,7 +168,6 @@ obj-$(CONFIG_IIO) += iio/ obj-$(CONFIG_VME_BUS) += vme/ obj-$(CONFIG_IPACK_BUS) += ipack/ obj-$(CONFIG_NTB) += ntb/ -obj-$(CONFIG_FMC) += fmc/ obj-$(CONFIG_POWERCAP) += powercap/ obj-$(CONFIG_MCB) += mcb/ obj-$(CONFIG_PERF_EVENTS) += perf/ diff --git a/drivers/fmc/Kconfig b/drivers/fmc/Kconfig deleted file mode 100644 index ae3d7f634932..000000000000 --- a/drivers/fmc/Kconfig +++ /dev/null @@ -1,52 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# FMC (ANSI-VITA 57.1) bus support -# - -menuconfig FMC - tristate "FMC support" - help - - FMC (FPGA Mezzanine Carrier) is a mechanical and electrical - standard for mezzanine cards that plug into a carrier board. - This kernel subsystem supports the matching between carrier - and mezzanine based on identifiers stored in the internal I2C - EEPROM, as well as having carrier-independent drivers. - - The framework was born outside of the kernel and at this time - the off-tree code base is more complete. Code and documentation - is at git://ohwr.org/fmc-projects/fmc-bus.git . - -if FMC - -config FMC_FAKEDEV - tristate "FMC fake device (software testing)" - help - This is a fake carrier, bringing a default EEPROM content - that can be rewritten at run time and usef for matching - mezzanines. - -config FMC_TRIVIAL - tristate "FMC trivial mezzanine driver (software testing)" - help - This is a fake mezzanine driver, to show how FMC works and test it. - The driver also handles interrupts (we used it with a real carrier - before the mezzanines were produced) - -config FMC_WRITE_EEPROM - tristate "FMC mezzanine driver to write I2C EEPROM" - help - This driver matches every mezzanine device and can write the - internal EEPROM of the PCB, using the firmware loader to get - its binary and the function carrier->reprogram to actually do it. - It is useful when the mezzanines are produced. - -config FMC_CHARDEV - tristate "FMC mezzanine driver that registers a char device" - help - This driver matches every mezzanine device and allows user - space to read and write registers using a char device. It - can be used to write user-space drivers, or just get - acquainted with a mezzanine before writing its specific driver. - -endif # FMC diff --git a/drivers/fmc/Makefile b/drivers/fmc/Makefile deleted file mode 100644 index e3da6192cf39..000000000000 --- a/drivers/fmc/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -obj-$(CONFIG_FMC) += fmc.o - -fmc-y = fmc-core.o -fmc-y += fmc-match.o -fmc-y += fmc-sdb.o -fmc-y += fru-parse.o -fmc-y += fmc-dump.o -fmc-y += fmc-debug.o - -obj-$(CONFIG_FMC_FAKEDEV) += fmc-fakedev.o -obj-$(CONFIG_FMC_TRIVIAL) += fmc-trivial.o -obj-$(CONFIG_FMC_WRITE_EEPROM) += fmc-write-eeprom.o -obj-$(CONFIG_FMC_CHARDEV) += fmc-chardev.o diff --git a/drivers/fmc/fmc-chardev.c b/drivers/fmc/fmc-chardev.c deleted file mode 100644 index 7d2091b5e978..000000000000 --- a/drivers/fmc/fmc-chardev.c +++ /dev/null @@ -1,199 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2012 CERN (www.cern.ch) - * Author: Alessandro Rubini <rubini@gnudd.com> - * - * This work is part of the White Rabbit project, a research effort led - * by CERN, the European Institute for Nuclear Research. - */ -#include <linux/module.h> -#include <linux/init.h> -#include <linux/list.h> -#include <linux/slab.h> -#include <linux/fs.h> -#include <linux/miscdevice.h> -#include <linux/spinlock.h> -#include <linux/fmc.h> -#include <linux/uaccess.h> - -static LIST_HEAD(fc_devices); -static DEFINE_SPINLOCK(fc_lock); - -struct fc_instance { - struct list_head list; - struct fmc_device *fmc; - struct miscdevice misc; -}; - -/* at open time, we must identify our device */ -static int fc_open(struct inode *ino, struct file *f) -{ - struct fmc_device *fmc; - struct fc_instance *fc; - int minor = iminor(ino); - - list_for_each_entry(fc, &fc_devices, list) - if (fc->misc.minor == minor) - break; - if (fc->misc.minor != minor) - return -ENODEV; - fmc = fc->fmc; - if (try_module_get(fmc->owner) == 0) - return -ENODEV; - - f->private_data = fmc; - return 0; -} - -static int fc_release(struct inode *ino, struct file *f) -{ - struct fmc_device *fmc = f->private_data; - module_put(fmc->owner); - return 0; -} - -/* read and write are simple after the default llseek has been used */ -static ssize_t fc_read(struct file *f, char __user *buf, size_t count, - loff_t *offp) -{ - struct fmc_device *fmc = f->private_data; - unsigned long addr; - uint32_t val; - - if (count < sizeof(val)) - return -EINVAL; - count = sizeof(val); - - addr = *offp; - if (addr > fmc->memlen) - return -ESPIPE; /* Illegal seek */ - val = fmc_readl(fmc, addr); - if (copy_to_user(buf, &val, count)) - return -EFAULT; - *offp += count; - return count; -} - -static ssize_t fc_write(struct file *f, const char __user *buf, size_t count, - loff_t *offp) -{ - struct fmc_device *fmc = f->private_data; - unsigned long addr; - uint32_t val; - - if (count < sizeof(val)) - return -EINVAL; - count = sizeof(val); - - addr = *offp; - if (addr > fmc->memlen) - return -ESPIPE; /* Illegal seek */ - if (copy_from_user(&val, buf, count)) - return -EFAULT; - fmc_writel(fmc, val, addr); - *offp += count; - return count; -} - -static const struct file_operations fc_fops = { - .owner = THIS_MODULE, - .open = fc_open, - .release = fc_release, - .llseek = generic_file_llseek, - .read = fc_read, - .write = fc_write, -}; - - -/* Device part .. */ -static int fc_probe(struct fmc_device *fmc); -static int fc_remove(struct fmc_device *fmc); - -static struct fmc_driver fc_drv = { - .version = FMC_VERSION, - .driver.name = KBUILD_MODNAME, - .probe = fc_probe, - .remove = fc_remove, - /* no table: we want to match everything */ -}; - -/* We accept the generic busid parameter */ -FMC_PARAM_BUSID(fc_drv); - -/* probe and remove must allocate and release a misc device */ -static int fc_probe(struct fmc_device *fmc) -{ - int ret; - int index = 0; - - struct fc_instance *fc; - - index = fmc_validate(fmc, &fc_drv); - if (index < 0) - return -EINVAL; /* not our device: invalid */ - - /* Create a char device: we want to create it anew */ - fc = kzalloc(sizeof(*fc), GFP_KERNEL); - if (!fc) - return -ENOMEM; - fc->fmc = fmc; - fc->misc.minor = MISC_DYNAMIC_MINOR; - fc->misc.fops = &fc_fops; - fc->misc.name = kstrdup(dev_name(&fmc->dev), GFP_KERNEL); - - ret = misc_register(&fc->misc); - if (ret < 0) - goto out; - spin_lock(&fc_lock); - list_add(&fc->list, &fc_devices); - spin_unlock(&fc_lock); - dev_info(&fc->fmc->dev, "Created misc device \"%s\"\n", - fc->misc.name); - return 0; - -out: - kfree(fc->misc.name); - kfree(fc); - return ret; -} - -static int fc_remove(struct fmc_device *fmc) -{ - struct fc_instance *fc; - - list_for_each_entry(fc, &fc_devices, list) - if (fc->fmc == fmc) - break; - if (fc->fmc != fmc) { - dev_err(&fmc->dev, "remove called but not found\n"); - return -ENODEV; - } - - spin_lock(&fc_lock); - list_del(&fc->list); - spin_unlock(&fc_lock); - misc_deregister(&fc->misc); - kfree(fc->misc.name); - kfree(fc); - - return 0; -} - - -static int fc_init(void) -{ - int ret; - - ret = fmc_driver_register(&fc_drv); - return ret; -} - -static void fc_exit(void) -{ - fmc_driver_unregister(&fc_drv); -} - -module_init(fc_init); -module_exit(fc_exit); - -MODULE_LICENSE("GPL"); diff --git a/drivers/fmc/fmc-core.c b/drivers/fmc/fmc-core.c deleted file mode 100644 index 573f5471f680..000000000000 --- a/drivers/fmc/fmc-core.c +++ /dev/null @@ -1,388 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2012 CERN (www.cern.ch) - * Author: Alessandro Rubini <rubini@gnudd.com> - * - * 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/slab.h> -#include <linux/init.h> -#include <linux/device.h> -#include <linux/fmc.h> -#include <linux/fmc-sdb.h> - -#include "fmc-private.h" - -static int fmc_check_version(unsigned long version, const char *name) -{ - if (__FMC_MAJOR(version) != FMC_MAJOR) { - pr_err("%s: \"%s\" has wrong major (has %li, expected %i)\n", - __func__, name, __FMC_MAJOR(version), FMC_MAJOR); - return -EINVAL; - } - - if (__FMC_MINOR(version) != FMC_MINOR) - pr_info("%s: \"%s\" has wrong minor (has %li, expected %i)\n", - __func__, name, __FMC_MINOR(version), FMC_MINOR); - return 0; -} - -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, -}; - -static void fmc_release(struct device *dev) -{ - struct fmc_device *fmc = container_of(dev, struct fmc_device, dev); - - kfree(fmc); -} - -/* - * The eeprom is exported in sysfs, through a binary attribute - */ - -static ssize_t fmc_read_eeprom(struct file *file, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct device *dev; - struct fmc_device *fmc; - int eelen; - - dev = container_of(kobj, struct device, kobj); - fmc = container_of(dev, struct fmc_device, dev); - eelen = fmc->eeprom_len; - if (off > eelen) - return -ESPIPE; - if (off == eelen) - return 0; /* EOF */ - if (off + count > eelen) - count = eelen - off; - memcpy(buf, fmc->eeprom + off, count); - return count; -} - -static ssize_t fmc_write_eeprom(struct file *file, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct device *dev; - struct fmc_device *fmc; - - dev = container_of(kobj, struct device, kobj); - fmc = container_of(dev, struct fmc_device, dev); - return fmc->op->write_ee(fmc, off, buf, count); -} - -static struct bin_attribute fmc_eeprom_attr = { - .attr = { .name = "eeprom", .mode = S_IRUGO | S_IWUSR, }, - .size = 8192, /* more or less standard */ - .read = fmc_read_eeprom, - .write = fmc_write_eeprom, -}; - -int fmc_irq_request(struct fmc_device *fmc, irq_handler_t h, - char *name, int flags) -{ - if (fmc->op->irq_request) - return fmc->op->irq_request(fmc, h, name, flags); - return -EPERM; -} -EXPORT_SYMBOL(fmc_irq_request); - -void fmc_irq_free(struct fmc_device *fmc) -{ - if (fmc->op->irq_free) - fmc->op->irq_free(fmc); -} -EXPORT_SYMBOL(fmc_irq_free); - -void fmc_irq_ack(struct fmc_device *fmc) -{ - if (likely(fmc->op->irq_ack)) - fmc->op->irq_ack(fmc); -} -EXPORT_SYMBOL(fmc_irq_ack); - -int fmc_validate(struct fmc_device *fmc, struct fmc_driver *drv) -{ - if (fmc->op->validate) - return fmc->op->validate(fmc, drv); - return -EPERM; -} -EXPORT_SYMBOL(fmc_validate); - -int fmc_gpio_config(struct fmc_device *fmc, struct fmc_gpio *gpio, int ngpio) -{ - if (fmc->op->gpio_config) - return fmc->op->gpio_config(fmc, gpio, ngpio); - return -EPERM; -} -EXPORT_SYMBOL(fmc_gpio_config); - -int fmc_read_ee(struct fmc_device *fmc, int pos, void *d, int l) -{ - if (fmc->op->read_ee) - return fmc->op->read_ee(fmc, pos, d, l); - return -EPERM; -} -EXPORT_SYMBOL(fmc_read_ee); - -int fmc_write_ee(struct fmc_device *fmc, int pos, const void *d, int l) -{ - if (fmc->op->write_ee) - return fmc->op->write_ee(fmc, pos, d, l); - return -EPERM; -} -EXPORT_SYMBOL(fmc_write_ee); - -/* - * Functions for client modules follow - */ - -int fmc_driver_register(struct fmc_driver *drv) -{ - if (fmc_check_version(drv->version, drv->driver.name)) - return -EINVAL; - 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); - -/* - * When a device set is registered, all eeproms must be read - * and all FRUs must be parsed - */ -int fmc_device_register_n_gw(struct fmc_device **devs, int n, - struct fmc_gateware *gw) -{ - struct fmc_device *fmc, **devarray; - uint32_t device_id; - int i, ret = 0; - - if (n < 1) - return 0; - - /* Check the version of the first data structure (function prints) */ - if (fmc_check_version(devs[0]->version, devs[0]->carrier_name)) - return -EINVAL; - - devarray = kmemdup(devs, n * sizeof(*devs), GFP_KERNEL); - if (!devarray) - return -ENOMEM; - - /* Make all other checks before continuing, for all devices */ - for (i = 0; i < n; i++) { - fmc = devarray[i]; - if (!fmc->hwdev) { - pr_err("%s: device nr. %i has no hwdev pointer\n", - __func__, i); - ret = -EINVAL; - break; - } - if (fmc->flags & FMC_DEVICE_NO_MEZZANINE) { - dev_info(fmc->hwdev, "absent mezzanine in slot %d\n", - fmc->slot_id); - continue; - } - if (!fmc->eeprom) { - dev_err(fmc->hwdev, "no eeprom provided for slot %i\n", - fmc->slot_id); - ret = -EINVAL; - } - if (!fmc->eeprom_addr) { - dev_err(fmc->hwdev, "no eeprom_addr for slot %i\n", - fmc->slot_id); - ret = -EINVAL; - } - if (!fmc->carrier_name || !fmc->carrier_data || - !fmc->device_id) { - dev_err(fmc->hwdev, - "device nr %i: carrier name, " - "data or dev_id not set\n", i); - ret = -EINVAL; - } - if (ret) - break; - - } - if (ret) { - kfree(devarray); - return ret; - } - - /* Validation is ok. Now init and register the devices */ - for (i = 0; i < n; i++) { - fmc = devarray[i]; - - fmc->nr_slots = n; /* each slot must know how many are there */ - fmc->devarray = devarray; - - device_initialize(&fmc->dev); - fmc->dev.release = fmc_release; - fmc->dev.parent = fmc->hwdev; - - /* Fill the identification stuff (may fail) */ - fmc_fill_id_info(fmc); - - fmc->dev.bus = &fmc_bus_type; - - /* Name from mezzanine info or carrier info. Or 0,1,2.. */ - device_id = fmc->device_id; - if (!fmc->mezzanine_name) - dev_set_name(&fmc->dev, "fmc-%04x", device_id); - else - dev_set_name(&fmc->dev, "%s-%04x", fmc->mezzanine_name, - device_id); - - if (gw) { - /* - * The carrier already know the bitstream to load - * for this set of FMC mezzanines. - */ - ret = fmc->op->reprogram_raw(fmc, NULL, - gw->bitstream, gw->len); - if (ret) { - dev_warn(fmc->hwdev, - "Invalid gateware for FMC mezzanine\n"); - goto out; - } - } - - ret = device_add(&fmc->dev); - if (ret < 0) { - dev_err(fmc->hwdev, "Slot %i: Failed in registering " - "\"%s\"\n", fmc->slot_id, fmc->dev.kobj.name); - goto out; - } - ret = sysfs_create_bin_file(&fmc->dev.kobj, &fmc_eeprom_attr); - if (ret < 0) { - dev_err(&fmc->dev, "Failed in registering eeprom\n"); - goto out1; - } - /* This device went well, give information to the user */ - fmc_dump_eeprom(fmc); - fmc_debug_init(fmc); - } - return 0; - -out1: - device_del(&fmc->dev); -out: - kfree(devarray); - for (i--; i >= 0; i--) { - fmc_debug_exit(devs[i]); - sysfs_remove_bin_file(&devs[i]->dev.kobj, &fmc_eeprom_attr); - device_del(&devs[i]->dev); - fmc_free_id_info(devs[i]); - put_device(&devs[i]->dev); - } - return ret; - -} -EXPORT_SYMBOL(fmc_device_register_n_gw); - -int fmc_device_register_n(struct fmc_device **devs, int n) -{ - return fmc_device_register_n_gw(devs, n, NULL); -} -EXPORT_SYMBOL(fmc_device_register_n); - -int fmc_device_register_gw(struct fmc_device *fmc, struct fmc_gateware *gw) -{ - return fmc_device_register_n_gw(&fmc, 1, gw); -} -EXPORT_SYMBOL(fmc_device_register_gw); - -int fmc_device_register(struct fmc_device *fmc) -{ - return fmc_device_register_n(&fmc, 1); -} -EXPORT_SYMBOL(fmc_device_register); - -void fmc_device_unregister_n(struct fmc_device **devs, int n) -{ - int i; - - if (n < 1) - return; - - /* Free devarray first, not used by the later loop */ - kfree(devs[0]->devarray); - - for (i = 0; i < n; i++) { - fmc_debug_exit(devs[i]); - sysfs_remove_bin_file(&devs[i]->dev.kobj, &fmc_eeprom_attr); - device_del(&devs[i]->dev); - fmc_free_id_info(devs[i]); - put_device(&devs[i]->dev); - } -} -EXPORT_SYMBOL(fmc_device_unregister_n); - -void fmc_device_unregister(struct fmc_device *fmc) -{ - fmc_device_unregister_n(&fmc, 1); -} -EXPORT_SYMBOL(fmc_device_unregister); - -/* Init and exit are trivial */ -static int fmc_init(void) -{ - return bus_register(&fmc_bus_type); -} - -static void fmc_exit(void) -{ - bus_unregister(&fmc_bus_type); -} - -module_init(fmc_init); -module_exit(fmc_exit); - -MODULE_LICENSE("GPL"); diff --git a/drivers/fmc/fmc-debug.c b/drivers/fmc/fmc-debug.c deleted file mode 100644 index 1734c7cf0e76..000000000000 --- a/drivers/fmc/fmc-debug.c +++ /dev/null @@ -1,172 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2015 CERN (www.cern.ch) - * Author: Federico Vaga <federico.vaga@cern.ch> - */ - -#include <linux/module.h> -#include <linux/device.h> -#include <linux/init.h> -#include <linux/fs.h> -#include <linux/debugfs.h> -#include <linux/seq_file.h> -#include <asm/byteorder.h> - -#include <linux/fmc.h> -#include <linux/sdb.h> -#include <linux/fmc-sdb.h> - -#define FMC_DBG_SDB_DUMP "dump_sdb" - -static char *__strip_trailing_space(char *buf, char *str, int len) -{ - int i = len - 1; - - memcpy(buf, str, len); - buf[len] = '\0'; - while (i >= 0 && buf[i] == ' ') - buf[i--] = '\0'; - return buf; -} - -#define __sdb_string(buf, field) ({ \ - BUILD_BUG_ON(sizeof(buf) < sizeof(field)); \ - __strip_trailing_space(buf, (void *)(field), sizeof(field)); \ - }) - -/** - * We do not check seq_printf() errors because we want to see things in any case - */ -static void fmc_sdb_dump_recursive(struct fmc_device *fmc, struct seq_file *s, - const struct sdb_array *arr) -{ - unsigned long base = arr->baseaddr; - int i, j, n = arr->len, level = arr->level; - char tmp[64]; - - for (i = 0; i < n; i++) { - union sdb_record *r; - struct sdb_product *p; - struct sdb_component *c; - - r = &arr->record[i]; - c = &r->dev.sdb_component; - p = &c->product; - - for (j = 0; j < level; j++) - seq_printf(s, " "); - switch (r->empty.record_type) { - case sdb_type_interconnect: - seq_printf(s, "%08llx:%08x %.19s\n", - __be64_to_cpu(p->vendor_id), - __be32_to_cpu(p->device_id), - p->name); - break; - case sdb_type_device: - seq_printf(s, "%08llx:%08x %.19s (%08llx-%08llx)\n", - __be64_to_cpu(p->vendor_id), - __be32_to_cpu(p->device_id), - p->name, - __be64_to_cpu(c->addr_first) + base, - __be64_to_cpu(c->addr_last) + base); - break; - case sdb_type_bridge: - seq_printf(s, "%08llx:%08x %.19s (bridge: %08llx)\n", - __be64_to_cpu(p->vendor_id), - __be32_to_cpu(p->device_id), - p->name, - __be64_to_cpu(c->addr_first) + base); - if (IS_ERR(arr->subtree[i])) { - seq_printf(s, "SDB: (bridge error %li)\n", - PTR_ERR(arr->subtree[i])); - break; - } - fmc_sdb_dump_recursive(fmc, s, arr->subtree[i]); - break; - case sdb_type_integration: - seq_printf(s, "integration\n"); - break; - case sdb_type_repo_url: - seq_printf(s, "Synthesis repository: %s\n", - __sdb_string(tmp, r->repo_url.repo_url)); - break; - case sdb_type_synthesis: - seq_printf(s, "Bitstream '%s' ", - __sdb_string(tmp, r->synthesis.syn_name)); - seq_printf(s, "synthesized %08x by %s ", - __be32_to_cpu(r->synthesis.date), - __sdb_string(tmp, r->synthesis.user_name)); - seq_printf(s, "(%s version %x), ", - __sdb_string(tmp, r->synthesis.tool_name), - __be32_to_cpu(r->synthesis.tool_version)); - seq_printf(s, "commit %pm\n", - r->synthesis.commit_id); - break; - case sdb_type_empty: - seq_printf(s, "empty\n"); - break; - default: - seq_printf(s, "UNKNOWN TYPE 0x%02x\n", - r->empty.record_type); - break; - } - } -} - -static int fmc_sdb_dump(struct seq_file *s, void *offset) -{ - struct fmc_device *fmc = s->private; - - if (!fmc->sdb) { - seq_printf(s, "no SDB information\n"); - return 0; - } - - seq_printf(s, "FMC: %s (%s), slot %i, device %s\n", dev_name(fmc->hwdev), - fmc->carrier_name, fmc->slot_id, dev_name(&fmc->dev)); - /* Dump SDB information */ - fmc_sdb_dump_recursive(fmc, s, fmc->sdb); - - return 0; -} - - -static int fmc_sdb_dump_open(struct inode *inode, struct file *file) -{ - struct fmc_device *fmc = inode->i_private; - - return single_open(file, fmc_sdb_dump, fmc); -} - - -const struct file_operations fmc_dbgfs_sdb_dump = { - .owner = THIS_MODULE, - .open = fmc_sdb_dump_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -int fmc_debug_init(struct fmc_device *fmc) -{ - fmc->dbg_dir = debugfs_create_dir(dev_name(&fmc->dev), NULL); - if (IS_ERR_OR_NULL(fmc->dbg_dir)) { - pr_err("FMC: Cannot create debugfs\n"); - return PTR_ERR(fmc->dbg_dir); - } - - fmc->dbg_sdb_dump = debugfs_create_file(FMC_DBG_SDB_DUMP, 0444, - fmc->dbg_dir, fmc, - &fmc_dbgfs_sdb_dump); - if (IS_ERR_OR_NULL(fmc->dbg_sdb_dump)) - pr_err("FMC: Cannot create debugfs file %s\n", - FMC_DBG_SDB_DUMP); - - return 0; -} - -void fmc_debug_exit(struct fmc_device *fmc) -{ - if (fmc->dbg_dir) - debugfs_remove_recursive(fmc->dbg_dir); -} diff --git a/drivers/fmc/fmc-dump.c b/drivers/fmc/fmc-dump.c deleted file mode 100644 index 6c81dbde1d16..000000000000 --- a/drivers/fmc/fmc-dump.c +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2013 CERN (www.cern.ch) - * Author: Alessandro Rubini <rubini@gnudd.com> - * - * 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/moduleparam.h> -#include <linux/device.h> -#include <linux/fmc.h> -#include <linux/fmc-sdb.h> - -static int fmc_must_dump_eeprom; -module_param_named(dump_eeprom, fmc_must_dump_eeprom, int, 0644); - -#define LINELEN 16 - -/* Dumping 8k takes oh so much: avoid duplicate lines */ -static const uint8_t *dump_line(int addr, const uint8_t *line, - const uint8_t *prev) -{ - int i; - - if (!prev || memcmp(line, prev, LINELEN)) { - pr_info("%04x: ", addr); - for (i = 0; i < LINELEN; ) { - printk(KERN_CONT "%02x", line[i]); - i++; - printk(i & 3 ? " " : i & (LINELEN - 1) ? " " : "\n"); - } - return line; - } - /* repeated line */ - if (line == prev + LINELEN) - pr_info("[...]\n"); - return prev; -} - -void fmc_dump_eeprom(const struct fmc_device *fmc) -{ - const uint8_t *line, *prev; - int i; - - if (!fmc_must_dump_eeprom) - return; - - pr_info("FMC: %s (%s), slot %i, device %s\n", dev_name(fmc->hwdev), - fmc->carrier_name, fmc->slot_id, dev_name(&fmc->dev)); - pr_info("FMC: dumping eeprom 0x%x (%i) bytes\n", fmc->eeprom_len, - fmc->eeprom_len); - - line = fmc->eeprom; - prev = NULL; - for (i = 0; i < fmc->eeprom_len; i += LINELEN, line += LINELEN) - prev = dump_line(i, line, prev); -} diff --git a/drivers/fmc/fmc-fakedev.c b/drivers/fmc/fmc-fakedev.c deleted file mode 100644 index 941d0930969a..000000000000 --- a/drivers/fmc/fmc-fakedev.c +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Copyright (C) 2012 CERN (www.cern.ch) - * Author: Alessandro Rubini <rubini@gnudd.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * The software is provided "as is"; the copyright holders disclaim - * all warranties and liabilities, to the extent permitted by - * applicable law. - */ -#include <linux/module.h> -#include <linux/init.h> -#include <linux/string.h> -#include <linux/device.h> -#include <linux/slab.h> -#include <linux/firmware.h> -#include <linux/workqueue.h> -#include <linux/err.h> -#include <linux/fmc.h> - -#define FF_EEPROM_SIZE 8192 /* The standard eeprom size */ -#define FF_MAX_MEZZANINES 4 /* Fakes a multi-mezzanine carrier */ - -/* The user can pass up to 4 names of eeprom images to load */ -static char *ff_eeprom[FF_MAX_MEZZANINES]; -static int ff_nr_eeprom; -module_param_array_named(eeprom, ff_eeprom, charp, &ff_nr_eeprom, 0444); - -/* The user can ask for a multi-mezzanine carrier, with the default eeprom */ -static int ff_nr_dev = 1; -module_param_named(ndev, ff_nr_dev, int, 0444); - - -/* Lazily, don't support the "standard" module parameters */ - -/* - * Eeprom built from these commands: - - ../fru-generator -v fake-vendor -n fake-design-for-testing \ - -s 01234 -p none > IPMI-FRU - - gensdbfs . ../fake-eeprom.bin -*/ -static char ff_eeimg[FF_MAX_MEZZANINES][FF_EEPROM_SIZE] = { - { - 0x01, 0x00, 0x00, 0x01, 0x00, 0x0c, 0x00, 0xf2, 0x01, 0x0b, 0x00, 0xb2, - 0x86, 0x87, 0xcb, 0x66, 0x61, 0x6b, 0x65, 0x2d, 0x76, 0x65, 0x6e, 0x64, - 0x6f, 0x72, 0xd7, 0x66, 0x61, 0x6b, 0x65, 0x2d, 0x64, 0x65, 0x73, 0x69, - 0x67, 0x6e, 0x2d, 0x66, 0x6f, 0x72, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x69, - 0x6e, 0x67, 0xc5, 0x30, 0x31, 0x32, 0x33, 0x34, 0xc4, 0x6e, 0x6f, 0x6e, - 0x65, 0xda, 0x32, 0x30, 0x31, 0x32, 0x2d, 0x31, 0x31, 0x2d, 0x31, 0x39, - 0x20, 0x32, 0x32, 0x3a, 0x34, 0x32, 0x3a, 0x33, 0x30, 0x2e, 0x30, 0x37, - 0x34, 0x30, 0x35, 0x35, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, - 0x02, 0x02, 0x0d, 0xf7, 0xf8, 0x02, 0xb0, 0x04, 0x74, 0x04, 0xec, 0x04, - 0x00, 0x00, 0x00, 0x00, 0xe8, 0x03, 0x02, 0x02, 0x0d, 0x5c, 0x93, 0x01, - 0x4a, 0x01, 0x39, 0x01, 0x5a, 0x01, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x0b, - 0x02, 0x02, 0x0d, 0x63, 0x8c, 0x00, 0xfa, 0x00, 0xed, 0x00, 0x06, 0x01, - 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0f, 0x01, 0x02, 0x0d, 0xfb, 0xf5, 0x05, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x02, 0x0d, 0xfc, 0xf4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x0d, 0xfd, 0xf3, 0x03, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfa, 0x82, 0x0b, 0xea, 0x8f, 0xa2, 0x12, 0x00, 0x00, 0x1e, 0x44, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x53, 0x44, 0x42, 0x2d, 0x00, 0x03, 0x01, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0xc4, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61, - 0x2e, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x2e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 0x46, 0x69, 0x6c, 0x65, - 0x44, 0x61, 0x74, 0x61, 0x6e, 0x61, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, - 0x46, 0x69, 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61, 0x49, 0x50, 0x4d, 0x49, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x49, 0x50, 0x4d, 0x49, - 0x2d, 0x46, 0x52, 0x55, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x01, 0x66, 0x61, 0x6b, 0x65, 0x0a, - }, -}; - -struct ff_dev { - struct fmc_device *fmc[FF_MAX_MEZZANINES]; - struct device dev; -}; - -static struct ff_dev *ff_current_dev; /* We have 1 carrier, 1 slot */ - -static int ff_reprogram(struct fmc_device *fmc, struct fmc_driver *drv, - char *gw) -{ - const struct firmware *fw; - int ret; - - if (!gw) { - /* program golden: success */ - fmc->flags &= ~FMC_DEVICE_HAS_CUSTOM; - fmc->flags |= FMC_DEVICE_HAS_GOLDEN; - return 0; - } - - dev_info(&fmc->dev, "reprogramming with %s\n", gw); - ret = request_firmware(&fw, gw, &fmc->dev); - if (ret < 0) { - dev_warn(&fmc->dev, "request firmware \"%s\": error %i\n", - gw, ret); - goto out; - } - fmc->flags &= ~FMC_DEVICE_HAS_GOLDEN; - fmc->flags |= FMC_DEVICE_HAS_CUSTOM; - -out: - release_firmware(fw); - return ret; -} - -static int ff_irq_request(struct fmc_device *fmc, irq_handler_t handler, - char *name, int flags) -{ - return -EOPNOTSUPP; -} - -/* FIXME: should also have some fake FMC GPIO mapping */ - - -/* - * This work function is called when we changed the eeprom. It removes the - * current fmc device and registers a new one, with different identifiers. - */ -static struct ff_dev *ff_dev_create(void); /* defined later */ - -static void ff_work_fn(struct work_struct *work) -{ - struct ff_dev *ff = ff_current_dev; - int ret; - - fmc_device_unregister_n(ff->fmc, ff_nr_dev); - device_unregister(&ff->dev); - ff_current_dev = NULL; - - ff = ff_dev_create(); - if (IS_ERR(ff)) { - pr_warning("%s: can't re-create FMC devices\n", __func__); - return; - } - ret = fmc_device_register_n(ff->fmc, ff_nr_dev); - if (ret < 0) { - dev_warn(&ff->dev, "can't re-register FMC devices\n"); - device_unregister(&ff->dev); - return; - } - - ff_current_dev = ff; -} - -static DECLARE_DELAYED_WORK(ff_work, ff_work_fn); - - -/* low-level i2c */ -static int ff_eeprom_read(struct fmc_device *fmc, uint32_t offset, - void *buf, size_t size) -{ - if (offset > FF_EEPROM_SIZE) - return -EINVAL; - if (offset + size > FF_EEPROM_SIZE) - size = FF_EEPROM_SIZE - offset; - memcpy(buf, fmc->eeprom + offset, size); - return size; -} - -static int ff_eeprom_write(struct fmc_device *fmc, uint32_t offset, - const void *buf, size_t size) -{ - if (offset > FF_EEPROM_SIZE) - return -EINVAL; - if (offset + size > FF_EEPROM_SIZE) - size = FF_EEPROM_SIZE - offset; - dev_info(&fmc->dev, "write_eeprom: offset %i, size %zi\n", - (int)offset, size); - memcpy(fmc->eeprom + offset, buf, size); - schedule_delayed_work(&ff_work, HZ * 2); /* remove, replug, in 2s */ - return size; -} - -/* i2c operations for fmc */ -static int ff_read_ee(struct fmc_device *fmc, int pos, void *data, int len) -{ - if (!(fmc->flags & FMC_DEVICE_HAS_GOLDEN)) - return -EOPNOTSUPP; - return ff_eeprom_read(fmc, pos, data, len); -} - -static int ff_write_ee(struct fmc_device *fmc, int pos, - const void *data, int len) -{ - if (!(fmc->flags & FMC_DEVICE_HAS_GOLDEN)) - return -EOPNOTSUPP; - return ff_eeprom_write(fmc, pos, data, len); -} - -/* readl and writel do not do anything. Don't waste RAM with "base" */ -static uint32_t ff_readl(struct fmc_device *fmc, int offset) -{ - return 0; -} - -static void ff_writel(struct fmc_device *fmc, uint32_t value, int offset) -{ - return; -} - -/* validate is useful so fmc-write-eeprom will not reprogram every 2 seconds */ -static int ff_validate(struct fmc_device *fmc, struct fmc_driver *drv) -{ - int i; - - if (!drv->busid_n) - return 0; /* everyhing is valid */ - for (i = 0; i < drv->busid_n; i++) - if (drv->busid_val[i] == fmc->device_id) - return i; - return -ENOENT; -} - - - -static struct fmc_operations ff_fmc_operations = { - .read32 = ff_readl, - .write32 = ff_writel, - .reprogram = ff_reprogram, - .irq_request = ff_irq_request, - .read_ee = ff_read_ee, - .write_ee = ff_write_ee, - .validate = ff_validate, -}; - -/* This device is kmalloced: release it */ -static void ff_dev_release(struct device *dev) -{ - struct ff_dev *ff = container_of(dev, struct ff_dev, dev); - kfree(ff); -} - -static struct fmc_device ff_template_fmc = { - .version = FMC_VERSION, - .owner = THIS_MODULE, - .carrier_name = "fake-fmc-carrier", - .device_id = 0xf001, /* fool */ - .eeprom_len = sizeof(ff_eeimg[0]), - .memlen = 0x1000, /* 4k, to show something */ - .op = &ff_fmc_operations, - .hwdev = NULL, /* filled at creation time */ - .flags = FMC_DEVICE_HAS_GOLDEN, -}; - -static struct ff_dev *ff_dev_create(void) -{ - struct ff_dev *ff; - struct fmc_device *fmc; - int i, ret; - - ff = kzalloc(sizeof(*ff), GFP_KERNEL); - if (!ff) - return ERR_PTR(-ENOMEM); - dev_set_name(&ff->dev, "fake-fmc-carrier"); - ff->dev.release = ff_dev_release; - - ret = device_register(&ff->dev); - if (ret < 0) { - put_device(&ff->dev); - return ERR_PTR(ret); - } - - /* Create fmc structures that refer to this new "hw" device */ - for (i = 0; i < ff_nr_dev; i++) { - fmc = kmemdup(&ff_template_fmc, sizeof(ff_template_fmc), - GFP_KERNEL); - fmc->hwdev = &ff->dev; - fmc->carrier_data = ff; - fmc->nr_slots = ff_nr_dev; - /* the following fields are different for each slot */ - fmc->eeprom = ff_eeimg[i]; - fmc->eeprom_addr = 0x50 + 2 * i; - fmc->slot_id = i; - ff->fmc[i] = fmc; - /* increment the identifier, each must be different */ - ff_template_fmc.device_id++; - } - return ff; -} - -/* init and exit */ -static int ff_init(void) -{ - struct ff_dev *ff; - const struct firmware *fw; - int i, len, ret = 0; - - /* Replicate the default eeprom for the max number of mezzanines */ - for (i = 1; i < FF_MAX_MEZZANINES; i++) - memcpy(ff_eeimg[i], ff_eeimg[0], sizeof(ff_eeimg[0])); - - if (ff_nr_eeprom > ff_nr_dev) - ff_nr_dev = ff_nr_eeprom; - - ff = ff_dev_create(); - if (IS_ERR(ff)) - return PTR_ERR(ff); - - /* If the user passed "eeprom=" as a parameter, fetch them */ - for (i = 0; i < ff_nr_eeprom; i++) { - if (!strlen(ff_eeprom[i])) - continue; - ret = request_firmware(&fw, ff_eeprom[i], &ff->dev); - if (ret < 0) { - dev_err(&ff->dev, "Mezzanine %i: can't load \"%s\" " - "(error %i)\n", i, ff_eeprom[i], -ret); - } else { - len = min_t(size_t, fw->size, (size_t)FF_EEPROM_SIZE); - memcpy(ff_eeimg[i], fw->data, len); - release_firmware(fw); - dev_info(&ff->dev, "Mezzanine %i: eeprom \"%s\"\n", i, - ff_eeprom[i]); - } - } - - ret = fmc_device_register_n(ff->fmc, ff_nr_dev); - if (ret) { - device_unregister(&ff->dev); - return ret; - } - ff_current_dev = ff; - return ret; -} - -static void ff_exit(void) -{ - if (ff_current_dev) { - fmc_device_unregister_n(ff_current_dev->fmc, ff_nr_dev); - device_unregister(&ff_current_dev->dev); - } - cancel_delayed_work_sync(&ff_work); -} - -module_init(ff_init); -module_exit(ff_exit); - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/fmc/fmc-match.c b/drivers/fmc/fmc-match.c deleted file mode 100644 index 995bd6041a67..000000000000 --- a/drivers/fmc/fmc-match.c +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2012 CERN (www.cern.ch) - * Author: Alessandro Rubini <rubini@gnudd.com> - * - * 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/slab.h> -#include <linux/fmc.h> -#include <linux/ipmi-fru.h> - -/* The fru parser is both user and kernel capable: it needs alloc */ -void *fru_alloc(size_t size) -{ - return kzalloc(size, GFP_KERNEL); -} - -/* The actual match function */ -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); - struct fmc_fru_id *fid; - int i, matched = 0; - - /* This currently only matches the EEPROM (FRU id) */ - fid = fdrv->id_table.fru_id; - if (!fid) { - dev_warn(&fdev->dev, "Driver has no ID: matches all\n"); - matched = 1; - } else { - if (!fdev->id.manufacturer || !fdev->id.product_name) - return 0; /* the device has no FRU information */ - for (i = 0; i < fdrv->id_table.fru_id_nr; i++, fid++) { - if (fid->manufacturer && - strcmp(fid->manufacturer, fdev->id.manufacturer)) - continue; - if (fid->product_name && - strcmp(fid->product_name, fdev->id.product_name)) - continue; - matched = 1; - break; - } - } - - /* FIXME: match SDB contents */ - return matched; -} - -/* This function creates ID info for a newly registered device */ -int fmc_fill_id_info(struct fmc_device *fmc) -{ - struct fru_common_header *h; - struct fru_board_info_area *bia; - int ret, allocated = 0; - - /* If we know the eeprom length, try to read it off the device */ - if (fmc->eeprom_len && !fmc->eeprom) { - fmc->eeprom = kzalloc(fmc->eeprom_len, GFP_KERNEL); - if (!fmc->eeprom) - return -ENOMEM; - allocated = 1; - ret = fmc_read_ee(fmc, 0, fmc->eeprom, fmc->eeprom_len); - if (ret < 0) - goto out; - } - - /* If no eeprom, continue with other matches */ - if (!fmc->eeprom) - return 0; - - dev_info(fmc->hwdev, "mezzanine %i\n", fmc->slot_id); /* header */ - - /* So we have the eeprom: parse the FRU part (if any) */ - h = (void *)fmc->eeprom; - if (h->format != 1) { - pr_info(" EEPROM has no FRU information\n"); - goto out; - } - if (!fru_header_cksum_ok(h)) { - pr_info(" FRU: wrong header checksum\n"); - goto out; - } - bia = fru_get_board_area(h); - if (!fru_bia_cksum_ok(bia)) { - pr_info(" FRU: wrong board area checksum\n"); - goto out; - } - fmc->id.manufacturer = fru_get_board_manufacturer(h); - fmc->id.product_name = fru_get_product_name(h); - pr_info(" Manufacturer: %s\n", fmc->id.manufacturer); - pr_info(" Product name: %s\n", fmc->id.product_name); - - /* Create the short name (FIXME: look in sdb as well) */ - fmc->mezzanine_name = kstrdup(fmc->id.product_name, GFP_KERNEL); - -out: - if (allocated) { - kfree(fmc->eeprom); - fmc->eeprom = NULL; - } - return 0; /* no error: let other identification work */ -} - -/* Some ID data is allocated using fru_alloc() above, so release it */ -void fmc_free_id_info(struct fmc_device *fmc) -{ - kfree(fmc->mezzanine_name); - kfree(fmc->id.manufacturer); - kfree(fmc->id.product_name); -} diff --git a/drivers/fmc/fmc-private.h b/drivers/fmc/fmc-private.h deleted file mode 100644 index 93cb8030f764..000000000000 --- a/drivers/fmc/fmc-private.h +++ /dev/null @@ -1,8 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2015 CERN (www.cern.ch) - * Author: Federico Vaga <federico.vaga@cern.ch> - */ - -extern int fmc_debug_init(struct fmc_device *fmc); -extern void fmc_debug_exit(struct fmc_device *fmc); diff --git a/drivers/fmc/fmc-sdb.c b/drivers/fmc/fmc-sdb.c deleted file mode 100644 index 14758db1a5fb..000000000000 --- a/drivers/fmc/fmc-sdb.c +++ /dev/null @@ -1,219 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2012 CERN (www.cern.ch) - * Author: Alessandro Rubini <rubini@gnudd.com> - * - * This work is part of the White Rabbit project, a research effort led - * by CERN, the European Institute for Nuclear Research. - */ -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/fmc.h> -#include <linux/sdb.h> -#include <linux/err.h> -#include <linux/fmc-sdb.h> -#include <asm/byteorder.h> - -static uint32_t __sdb_rd(struct fmc_device *fmc, unsigned long address, - int convert) -{ - uint32_t res = fmc_readl(fmc, address); - if (convert) - return __be32_to_cpu(res); - return res; -} - -static struct sdb_array *__fmc_scan_sdb_tree(struct fmc_device *fmc, - unsigned long sdb_addr, - unsigned long reg_base, int level) -{ - uint32_t onew; - int i, j, n, convert = 0; - struct sdb_array *arr, *sub; - - onew = fmc_readl(fmc, sdb_addr); - if (onew == SDB_MAGIC) { - /* Uh! If we are little-endian, we must convert */ - if (SDB_MAGIC != __be32_to_cpu(SDB_MAGIC)) - convert = 1; - } else if (onew == __be32_to_cpu(SDB_MAGIC)) { - /* ok, don't convert */ - } else { - return ERR_PTR(-ENOENT); - } - /* So, the magic was there: get the count from offset 4*/ - onew = __sdb_rd(fmc, sdb_addr + 4, convert); - n = __be16_to_cpu(*(uint16_t *)&onew); - arr = kzalloc(sizeof(*arr), GFP_KERNEL); - if (!arr) - return ERR_PTR(-ENOMEM); - arr->record = kcalloc(n, sizeof(arr->record[0]), GFP_KERNEL); - arr->subtree = kcalloc(n, sizeof(arr->subtree[0]), GFP_KERNEL); - if (!arr->record || !arr->subtree) { - kfree(arr->record); - kfree(arr->subtree); - kfree(arr); - return ERR_PTR(-ENOMEM); - } - - arr->len = n; - arr->level = level; - arr->fmc = fmc; - for (i = 0; i < n; i++) { - union sdb_record *r; - - for (j = 0; j < sizeof(arr->record[0]); j += 4) { - *(uint32_t *)((void *)(arr->record + i) + j) = - __sdb_rd(fmc, sdb_addr + (i * 64) + j, convert); - } - r = &arr->record[i]; - arr->subtree[i] = ERR_PTR(-ENODEV); - if (r->empty.record_type == sdb_type_bridge) { - struct sdb_component *c = &r->bridge.sdb_component; - uint64_t subaddr = __be64_to_cpu(r->bridge.sdb_child); - uint64_t newbase = __be64_to_cpu(c->addr_first); - - subaddr += reg_base; - newbase += reg_base; - sub = __fmc_scan_sdb_tree(fmc, subaddr, newbase, - level + 1); - arr->subtree[i] = sub; /* may be error */ - if (IS_ERR(sub)) - continue; - sub->parent = arr; - sub->baseaddr = newbase; - } - } - return arr; -} - -int fmc_scan_sdb_tree(struct fmc_device *fmc, unsigned long address) -{ - struct sdb_array *ret; - if (fmc->sdb) - return -EBUSY; - ret = __fmc_scan_sdb_tree(fmc, address, 0 /* regs */, 0); - if (IS_ERR(ret)) - return PTR_ERR(ret); - fmc->sdb = ret; - return 0; -} -EXPORT_SYMBOL(fmc_scan_sdb_tree); - -static void __fmc_sdb_free(struct sdb_array *arr) -{ - int i, n; - - if (!arr) - return; - n = arr->len; - for (i = 0; i < n; i++) { - if (IS_ERR(arr->subtree[i])) - continue; - __fmc_sdb_free(arr->subtree[i]); - } - kfree(arr->record); - kfree(arr->subtree); - kfree(arr); -} - -int fmc_free_sdb_tree(struct fmc_device *fmc) -{ - __fmc_sdb_free(fmc->sdb); - fmc->sdb = NULL; - return 0; -} -EXPORT_SYMBOL(fmc_free_sdb_tree); - -/* This helper calls reprogram and inizialized sdb as well */ -int fmc_reprogram_raw(struct fmc_device *fmc, struct fmc_driver *d, - void *gw, unsigned long len, int sdb_entry) -{ - int ret; - - ret = fmc->op->reprogram_raw(fmc, d, gw, len); - if (ret < 0) - return ret; - if (sdb_entry < 0) - return ret; - - /* We are required to find SDB at a given offset */ - ret = fmc_scan_sdb_tree(fmc, sdb_entry); - if (ret < 0) { - dev_err(&fmc->dev, "Can't find SDB at address 0x%x\n", - sdb_entry); - return -ENODEV; - } - - return 0; -} -EXPORT_SYMBOL(fmc_reprogram_raw); - -/* This helper calls reprogram and inizialized sdb as well */ -int fmc_reprogram(struct fmc_device *fmc, struct fmc_driver *d, char *gw, - int sdb_entry) -{ - int ret; - - ret = fmc->op->reprogram(fmc, d, gw); - if (ret < 0) - return ret; - if (sdb_entry < 0) - return ret; - - /* We are required to find SDB at a given offset */ - ret = fmc_scan_sdb_tree(fmc, sdb_entry); - if (ret < 0) { - dev_err(&fmc->dev, "Can't find SDB at address 0x%x\n", - sdb_entry); - return -ENODEV; - } - - return 0; -} -EXPORT_SYMBOL(fmc_reprogram); - -void fmc_show_sdb_tree(const struct fmc_device *fmc) -{ - pr_err("%s: not supported anymore, use debugfs to dump SDB\n", - __func__); -} -EXPORT_SYMBOL(fmc_show_sdb_tree); - -signed long fmc_find_sdb_device(struct sdb_array *tree, - uint64_t vid, uint32_t did, unsigned long *sz) -{ - signed long res = -ENODEV; - union sdb_record *r; - struct sdb_product *p; - struct sdb_component *c; - int i, n = tree->len; - uint64_t last, first; - - /* FIXME: what if the first interconnect is not at zero? */ - for (i = 0; i < n; i++) { - r = &tree->record[i]; - c = &r->dev.sdb_component; - p = &c->product; - - if (!IS_ERR(tree->subtree[i])) - res = fmc_find_sdb_device(tree->subtree[i], - vid, did, sz); - if (res >= 0) - return res + tree->baseaddr; - if (r->empty.record_type != sdb_type_device) - continue; - if (__be64_to_cpu(p->vendor_id) != vid) - continue; - if (__be32_to_cpu(p->device_id) != did) - continue; - /* found */ - last = __be64_to_cpu(c->addr_last); - first = __be64_to_cpu(c->addr_first); - if (sz) - *sz = (typeof(*sz))(last + 1 - first); - return first + tree->baseaddr; - } - return res; -} -EXPORT_SYMBOL(fmc_find_sdb_device); diff --git a/drivers/fmc/fmc-trivial.c b/drivers/fmc/fmc-trivial.c deleted file mode 100644 index b99dbc7ee203..000000000000 --- a/drivers/fmc/fmc-trivial.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2012 CERN (www.cern.ch) - * Author: Alessandro Rubini <rubini@gnudd.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * The software is provided "as is"; the copyright holders disclaim - * all warranties and liabilities, to the extent permitted by - * applicable law. - */ - -/* A trivial fmc driver that can load a gateware file and reports interrupts */ -#include <linux/module.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/fmc.h> - -static struct fmc_driver t_drv; /* initialized later */ - -static irqreturn_t t_handler(int irq, void *dev_id) -{ - struct fmc_device *fmc = dev_id; - - fmc_irq_ack(fmc); - dev_info(&fmc->dev, "received irq %i\n", irq); - return IRQ_HANDLED; -} - -static struct fmc_gpio t_gpio[] = { - { - .gpio = FMC_GPIO_IRQ(0), - .mode = GPIOF_DIR_IN, - .irqmode = IRQF_TRIGGER_RISING, - }, { - .gpio = FMC_GPIO_IRQ(1), - .mode = GPIOF_DIR_IN, - .irqmode = IRQF_TRIGGER_RISING, - } -}; - -static int t_probe(struct fmc_device *fmc) -{ - int ret; - int index = 0; - - index = fmc_validate(fmc, &t_drv); - if (index < 0) - return -EINVAL; /* not our device: invalid */ - - ret = fmc_irq_request(fmc, t_handler, "fmc-trivial", IRQF_SHARED); - if (ret < 0) - return ret; - /* ignore error code of call below, we really don't care */ - fmc_gpio_config(fmc, t_gpio, ARRAY_SIZE(t_gpio)); - - ret = fmc_reprogram(fmc, &t_drv, "", 0); - if (ret == -EPERM) /* programming not supported */ - ret = 0; - if (ret < 0) - fmc_irq_free(fmc); - - /* FIXME: reprogram LM32 too */ - return ret; -} - -static int t_remove(struct fmc_device *fmc) -{ - fmc_irq_free(fmc); - return 0; -} - -static struct fmc_driver t_drv = { - .version = FMC_VERSION, - .driver.name = KBUILD_MODNAME, - .probe = t_probe, - .remove = t_remove, - /* no table, as the current match just matches everything */ -}; - - /* We accept the generic parameters */ -FMC_PARAM_BUSID(t_drv); -FMC_PARAM_GATEWARE(t_drv); - -static int t_init(void) -{ - int ret; - - ret = fmc_driver_register(&t_drv); - return ret; -} - -static void t_exit(void) -{ - fmc_driver_unregister(&t_drv); -} - -module_init(t_init); -module_exit(t_exit); - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/fmc/fmc-write-eeprom.c b/drivers/fmc/fmc-write-eeprom.c deleted file mode 100644 index 1c7826e3f526..000000000000 --- a/drivers/fmc/fmc-write-eeprom.c +++ /dev/null @@ -1,175 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2012 CERN (www.cern.ch) - * Author: Alessandro Rubini <rubini@gnudd.com> - * - * This work is part of the White Rabbit project, a research effort led - * by CERN, the European Institute for Nuclear Research. - */ -#include <linux/module.h> -#include <linux/string.h> -#include <linux/firmware.h> -#include <linux/init.h> -#include <linux/fmc.h> -#include <asm/unaligned.h> - -/* - * This module uses the firmware loader to program the whole or part - * of the FMC eeprom. The meat is in the _run functions. However, no - * default file name is provided, to avoid accidental mishaps. Also, - * you must pass the busid argument - */ -static struct fmc_driver fwe_drv; - -FMC_PARAM_BUSID(fwe_drv); - -/* The "file=" is like the generic "gateware=" used elsewhere */ -static char *fwe_file[FMC_MAX_CARDS]; -static int fwe_file_n; -module_param_array_named(file, fwe_file, charp, &fwe_file_n, 0444); - -static int fwe_run_tlv(struct fmc_device *fmc, const struct firmware *fw, - int write) -{ - const uint8_t *p = fw->data; - int len = fw->size; - uint16_t thislen, thisaddr; - int err; - - /* format is: 'w' addr16 len16 data... */ - while (len > 5) { - thisaddr = get_unaligned_le16(p+1); - thislen = get_unaligned_le16(p+3); - if (p[0] != 'w' || thislen + 5 > len) { - dev_err(&fmc->dev, "invalid tlv at offset %ti\n", - p - fw->data); - return -EINVAL; - } - err = 0; - if (write) { - dev_info(&fmc->dev, "write %i bytes at 0x%04x\n", - thislen, thisaddr); - err = fmc_write_ee(fmc, thisaddr, p + 5, thislen); - } - if (err < 0) { - dev_err(&fmc->dev, "write failure @0x%04x\n", - thisaddr); - return err; - } - p += 5 + thislen; - len -= 5 + thislen; - } - if (write) - dev_info(&fmc->dev, "write_eeprom: success\n"); - return 0; -} - -static int fwe_run_bin(struct fmc_device *fmc, const struct firmware *fw) -{ - int ret; - - dev_info(&fmc->dev, "programming %zi bytes\n", fw->size); - ret = fmc_write_ee(fmc, 0, (void *)fw->data, fw->size); - if (ret < 0) { - dev_info(&fmc->dev, "write_eeprom: error %i\n", ret); - return ret; - } - dev_info(&fmc->dev, "write_eeprom: success\n"); - return 0; -} - -static int fwe_run(struct fmc_device *fmc, const struct firmware *fw, char *s) -{ - char *last4 = s + strlen(s) - 4; - int err; - - if (!strcmp(last4, ".bin")) - return fwe_run_bin(fmc, fw); - if (!strcmp(last4, ".tlv")) { - err = fwe_run_tlv(fmc, fw, 0); - if (!err) - err = fwe_run_tlv(fmc, fw, 1); - return err; - } - dev_err(&fmc->dev, "invalid file name \"%s\"\n", s); - return -EINVAL; -} - -/* - * Programming is done at probe time. Morever, only those listed with - * busid= are programmed. - * card is probed for, only one is programmed. Unfortunately, it's - * difficult to know in advance when probing the first card if others - * are there. - */ -static int fwe_probe(struct fmc_device *fmc) -{ - int err, index = 0; - const struct firmware *fw; - struct device *dev = &fmc->dev; - char *s; - - if (!fwe_drv.busid_n) { - dev_err(dev, "%s: no busid passed, refusing all cards\n", - KBUILD_MODNAME); - return -ENODEV; - } - - index = fmc_validate(fmc, &fwe_drv); - if (index < 0) { - pr_err("%s: refusing device \"%s\"\n", KBUILD_MODNAME, - dev_name(dev)); - return -ENODEV; - } - if (index >= fwe_file_n) { - pr_err("%s: no filename for device index %i\n", - KBUILD_MODNAME, index); - return -ENODEV; - } - s = fwe_file[index]; - if (!s) { - pr_err("%s: no filename for \"%s\" not programming\n", - KBUILD_MODNAME, dev_name(dev)); - return -ENOENT; - } - err = request_firmware(&fw, s, dev); - if (err < 0) { - dev_err(&fmc->dev, "request firmware \"%s\": error %i\n", - s, err); - return err; - } - fwe_run(fmc, fw, s); - release_firmware(fw); - return 0; -} - -static int fwe_remove(struct fmc_device *fmc) -{ - return 0; -} - -static struct fmc_driver fwe_drv = { - .version = FMC_VERSION, - .driver.name = KBUILD_MODNAME, - .probe = fwe_probe, - .remove = fwe_remove, - /* no table, as the current match just matches everything */ -}; - -static int fwe_init(void) -{ - int ret; - - ret = fmc_driver_register(&fwe_drv); - return ret; -} - -static void fwe_exit(void) -{ - fmc_driver_unregister(&fwe_drv); -} - -module_init(fwe_init); -module_exit(fwe_exit); - -MODULE_LICENSE("GPL"); diff --git a/drivers/fmc/fru-parse.c b/drivers/fmc/fru-parse.c deleted file mode 100644 index f551b81f4fd9..000000000000 --- a/drivers/fmc/fru-parse.c +++ /dev/null @@ -1,80 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2012 CERN (www.cern.ch) - * Author: Alessandro Rubini <rubini@gnudd.com> - * - * This work is part of the White Rabbit project, a research effort led - * by CERN, the European Institute for Nuclear Research. - */ -#include <linux/ipmi-fru.h> - -/* Some internal helpers */ -static struct fru_type_length * -__fru_get_board_tl(struct fru_common_header *header, int nr) -{ - struct fru_board_info_area *bia; - struct fru_type_length *tl; - - bia = fru_get_board_area(header); - tl = bia->tl; - while (nr > 0 && !fru_is_eof(tl)) { - tl = fru_next_tl(tl); - nr--; - } - if (fru_is_eof(tl)) - return NULL; - return tl; -} - -static char *__fru_alloc_get_tl(struct fru_common_header *header, int nr) -{ - struct fru_type_length *tl; - char *res; - - tl = __fru_get_board_tl(header, nr); - if (!tl) - return NULL; - - res = fru_alloc(fru_strlen(tl) + 1); - if (!res) - return NULL; - return fru_strcpy(res, tl); -} - -/* Public checksum verifiers */ -int fru_header_cksum_ok(struct fru_common_header *header) -{ - uint8_t *ptr = (void *)header; - int i, sum; - - for (i = sum = 0; i < sizeof(*header); i++) - sum += ptr[i]; - return (sum & 0xff) == 0; -} -int fru_bia_cksum_ok(struct fru_board_info_area *bia) -{ - uint8_t *ptr = (void *)bia; - int i, sum; - - for (i = sum = 0; i < 8 * bia->area_len; i++) - sum += ptr[i]; - return (sum & 0xff) == 0; -} - -/* Get various stuff, trivial */ -char *fru_get_board_manufacturer(struct fru_common_header *header) -{ - return __fru_alloc_get_tl(header, 0); -} -char *fru_get_product_name(struct fru_common_header *header) -{ - return __fru_alloc_get_tl(header, 1); -} -char *fru_get_serial_number(struct fru_common_header *header) -{ - return __fru_alloc_get_tl(header, 2); -} -char *fru_get_part_number(struct fru_common_header *header) -{ - return __fru_alloc_get_tl(header, 3); -} |