summaryrefslogtreecommitdiff
path: root/drivers/fmc/fmc-dump.c
diff options
context:
space:
mode:
authorAlessandro Rubini <rubini@gnudd.com>2013-06-18 23:47:13 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-06-18 15:36:56 -0700
commit77864f2e0a824a92bd93b4c9ad22c31d28ff55a6 (patch)
tree04748bc59eebcb9c127c33b897a7abb216044a3b /drivers/fmc/fmc-dump.c
parent7b175c46720f8e6b92801bb634c93d1016f80c62 (diff)
FMC: add core bus driver
This module offers registration services for both carriers (i.e. devices) and mezzanines (i.e. drivers). The matching for devices and drivers is performed according to the IPMI standard for FRU devices (Field Replaceable Units). The code includes support for parsing an SDB tree if present in the FPGA, and dumping it for diagnostics. SDB is not mandatory. Files in this commit correspond to commit ab23167f in the master branch of the project hosted on ohwr.org. Signed-off-by: Alessandro Rubini <rubini@gnudd.com> Acked-by: Juan David Gonzalez Cobas <dcobas@cern.ch> Acked-by: Emilio G. Cota <cota@braap.org> Acked-by: Samuel Iglesias Gonsalvez <siglesias@igalia.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/fmc/fmc-dump.c')
-rw-r--r--drivers/fmc/fmc-dump.c100
1 files changed, 100 insertions, 0 deletions
diff --git a/drivers/fmc/fmc-dump.c b/drivers/fmc/fmc-dump.c
new file mode 100644
index 000000000000..c91afd6388f6
--- /dev/null
+++ b/drivers/fmc/fmc-dump.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2013 CERN (www.cern.ch)
+ * Author: Alessandro Rubini <rubini@gnudd.com>
+ *
+ * Released according to the GNU GPL, version 2 or any later version.
+ *
+ * This work is part of the White Rabbit project, a research effort led
+ * by CERN, the European Institute for Nuclear Research.
+ */
+#include <linux/kernel.h>
+#include <linux/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);
+static int fmc_must_dump_sdb;
+module_param_named(dump_sdb, fmc_must_dump_sdb, 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);
+}
+
+void fmc_dump_sdb(const struct fmc_device *fmc)
+{
+ const uint8_t *line, *prev;
+ int i, len;
+
+ if (!fmc->sdb)
+ return;
+ if (!fmc_must_dump_sdb)
+ return;
+
+ /* If the argument is not-zero, do simple dump (== show) */
+ if (fmc_must_dump_sdb > 0)
+ fmc_show_sdb_tree(fmc);
+
+ if (fmc_must_dump_sdb == 1)
+ return;
+
+ /* If bigger than 1, dump it seriously, to help debugging */
+
+ /*
+ * Here we should really use libsdbfs (which is designed to
+ * work in kernel space as well) , but it doesn't support
+ * directories yet, and it requires better intergration (it
+ * should be used instead of fmc-specific code).
+ *
+ * So, lazily, just dump the top-level array
+ */
+ 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: poor dump of sdb first level:\n");
+
+ len = fmc->sdb->len * sizeof(union sdb_record);
+ line = (void *)fmc->sdb->record;
+ prev = NULL;
+ for (i = 0; i < len; i += LINELEN, line += LINELEN)
+ prev = dump_line(i, line, prev);
+ return;
+}