diff options
Diffstat (limited to 'drivers/fmc')
-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 | 103 | ||||
-rw-r--r-- | drivers/fmc/fmc-write-eeprom.c | 175 | ||||
-rw-r--r-- | drivers/fmc/fru-parse.c | 80 |
13 files changed, 0 insertions, 1937 deletions
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 8defdee3e3a3..000000000000 --- a/drivers/fmc/fmc-trivial.c +++ /dev/null @@ -1,103 +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/gpio.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); -} |