All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/5] Update kernel to latest FMC bus release
@ 2017-06-30 16:15 Pat Riehecky
  2017-06-30 16:15 ` [PATCH 1/5] drivers/fmc: remove unused variable Pat Riehecky
                   ` (5 more replies)
  0 siblings, 6 replies; 16+ messages in thread
From: Pat Riehecky @ 2017-06-30 16:15 UTC (permalink / raw)
  To: linux-kernel; +Cc: rubini, drivers_other, gregkh, federico.vaga, Pat Riehecky

The following patches sync up the mainline kernel's FMC bus with the upstream release tagged v2017-06.

Commits (written by Federico Vaga) have been squashed into logical units.

These patches address kernel bug 195653.

These specific changes have been live within the FMC repo since 2015 and in active use by FMC projects since then.

The patches include 1 bugfix and 4 enhancements:

Bugfix:
0001-fmc-remove-unused-variable.patch  -  remove an unused int

Enhancement:
0002-fmc-hide-fmc-operations-behind-helpers.patch - user helper functions to hide internal semantics
0003-fmc-The-only-way-to-dump-the-SDB-is-from-debugfs.patch - use debugfs to dump the device
0004-fmc-change-registration-prototype.patch - add a second prototype for device registration
0005-fmc-carrier-can-program-FPGA-on-registration.patch - permit programming the FPGA on registration


Upstream git repo: http://www.ohwr.org/projects/fmc-bus/repository/show?rev=fmc-bus-v2017-06


FMC maintainer: Alessandro Rubini <rubini@gnudd.com>
Initial approver of FMC: Greg KH <gregkh@linuxfoundation.org>
Bugzilla assigned to: drivers_other@kernel-bugs.osdl.org


Federico Vaga (5):
  drivers/fmc: remove unused variable
  drivers/fmc: hide fmc operations behind helpers
  drivers/fmc: The only way to dump the SDB is from debugfs
  drivers/fmc: change registration prototype
  drivers/fmc: carrier can program FPGA on registration

 drivers/fmc/Makefile           |   1 +
 drivers/fmc/fmc-chardev.c      |   3 +-
 drivers/fmc/fmc-core.c         |  95 ++++++++++++++++++++--
 drivers/fmc/fmc-debug.c        | 173 +++++++++++++++++++++++++++++++++++++++++
 drivers/fmc/fmc-dump.c         |  41 ----------
 drivers/fmc/fmc-match.c        |   2 +-
 drivers/fmc/fmc-private.h      |   9 +++
 drivers/fmc/fmc-sdb.c          | 119 ++++++----------------------
 drivers/fmc/fmc-trivial.c      |  20 ++---
 drivers/fmc/fmc-write-eeprom.c |   8 +-
 drivers/fmc/fru-parse.c        |   3 +-
 include/linux/fmc.h            |  39 +++++++++-
 12 files changed, 349 insertions(+), 164 deletions(-)
 create mode 100644 drivers/fmc/fmc-debug.c
 create mode 100644 drivers/fmc/fmc-private.h

--
1.8.3.1

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 1/5] drivers/fmc: remove unused variable
  2017-06-30 16:15 [PATCH 0/5] Update kernel to latest FMC bus release Pat Riehecky
@ 2017-06-30 16:15 ` Pat Riehecky
  2017-06-30 16:15 ` [PATCH 2/5] drivers/fmc: hide fmc operations behind helpers Pat Riehecky
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Pat Riehecky @ 2017-06-30 16:15 UTC (permalink / raw)
  To: linux-kernel; +Cc: rubini, drivers_other, gregkh, federico.vaga, Pat Riehecky

Signed-off-by: Federico Vaga <federico.vaga@cern.ch>
---
 drivers/fmc/fru-parse.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/fmc/fru-parse.c b/drivers/fmc/fru-parse.c
index cb46263..eb21480 100644
--- a/drivers/fmc/fru-parse.c
+++ b/drivers/fmc/fru-parse.c
@@ -31,12 +31,11 @@ static char *__fru_alloc_get_tl(struct fru_common_header *header, int nr)
 {
 	struct fru_type_length *tl;
 	char *res;
-	int len;

 	tl = __fru_get_board_tl(header, nr);
 	if (!tl)
 		return NULL;
-	len = fru_strlen(tl);
+
 	res = fru_alloc(fru_strlen(tl) + 1);
 	if (!res)
 		return NULL;
--
1.8.3.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 2/5] drivers/fmc: hide fmc operations behind helpers
  2017-06-30 16:15 [PATCH 0/5] Update kernel to latest FMC bus release Pat Riehecky
  2017-06-30 16:15 ` [PATCH 1/5] drivers/fmc: remove unused variable Pat Riehecky
@ 2017-06-30 16:15 ` Pat Riehecky
  2017-06-30 16:15 ` [PATCH 3/5] drivers/fmc: The only way to dump the SDB is from debugfs Pat Riehecky
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Pat Riehecky @ 2017-06-30 16:15 UTC (permalink / raw)
  To: linux-kernel; +Cc: rubini, drivers_other, gregkh, federico.vaga, Pat Riehecky

This gave us more freedom to change/add/remove operations without
recompiling all device driver.

Typically, Carrier board implement the fmc operations, so they will not
use these helpers.

Signed-off-by: Federico Vaga <federico.vaga@cern.ch>
---
 drivers/fmc/fmc-chardev.c      |  3 +--
 drivers/fmc/fmc-core.c         | 55 ++++++++++++++++++++++++++++++++++++++++++
 drivers/fmc/fmc-match.c        |  2 +-
 drivers/fmc/fmc-trivial.c      | 20 ++++++---------
 drivers/fmc/fmc-write-eeprom.c |  8 +++---
 include/linux/fmc.h            | 18 ++++++++++++++
 6 files changed, 87 insertions(+), 19 deletions(-)

diff --git a/drivers/fmc/fmc-chardev.c b/drivers/fmc/fmc-chardev.c
index ace6ef2..5ecf409 100644
--- a/drivers/fmc/fmc-chardev.c
+++ b/drivers/fmc/fmc-chardev.c
@@ -129,8 +129,7 @@ static int fc_probe(struct fmc_device *fmc)

 	struct fc_instance *fc;

-	if (fmc->op->validate)
-		index = fmc->op->validate(fmc, &fc_drv);
+	index = fmc_validate(fmc, &fc_drv);
 	if (index < 0)
 		return -EINVAL; /* not our device: invalid */

diff --git a/drivers/fmc/fmc-core.c b/drivers/fmc/fmc-core.c
index 353fc54..5263d06 100644
--- a/drivers/fmc/fmc-core.c
+++ b/drivers/fmc/fmc-core.c
@@ -118,6 +118,61 @@ static ssize_t fmc_write_eeprom(struct file *file, struct kobject *kobj,
 	.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
  */
diff --git a/drivers/fmc/fmc-match.c b/drivers/fmc/fmc-match.c
index 104a5ef..a0956d1 100644
--- a/drivers/fmc/fmc-match.c
+++ b/drivers/fmc/fmc-match.c
@@ -63,7 +63,7 @@ int fmc_fill_id_info(struct fmc_device *fmc)
 		if (!fmc->eeprom)
 			return -ENOMEM;
 		allocated = 1;
-		ret = fmc->op->read_ee(fmc, 0, fmc->eeprom, fmc->eeprom_len);
+		ret = fmc_read_ee(fmc, 0, fmc->eeprom, fmc->eeprom_len);
 		if (ret < 0)
 			goto out;
 	}
diff --git a/drivers/fmc/fmc-trivial.c b/drivers/fmc/fmc-trivial.c
index 6c590f5..8defdee 100644
--- a/drivers/fmc/fmc-trivial.c
+++ b/drivers/fmc/fmc-trivial.c
@@ -24,7 +24,7 @@ static irqreturn_t t_handler(int irq, void *dev_id)
 {
 	struct fmc_device *fmc = dev_id;

-	fmc->op->irq_ack(fmc);
+	fmc_irq_ack(fmc);
 	dev_info(&fmc->dev, "received irq %i\n", irq);
 	return IRQ_HANDLED;
 }
@@ -46,25 +46,21 @@ static int t_probe(struct fmc_device *fmc)
 	int ret;
 	int index = 0;

-	if (fmc->op->validate)
-		index = fmc->op->validate(fmc, &t_drv);
+	index = fmc_validate(fmc, &t_drv);
 	if (index < 0)
 		return -EINVAL; /* not our device: invalid */

-	ret = fmc->op->irq_request(fmc, t_handler, "fmc-trivial", IRQF_SHARED);
+	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->op->gpio_config(fmc, t_gpio, ARRAY_SIZE(t_gpio));
+	fmc_gpio_config(fmc, t_gpio, ARRAY_SIZE(t_gpio));

-	/* Reprogram, if asked to. ESRCH == no filename specified */
-	ret = -ESRCH;
-	if (fmc->op->reprogram)
-		ret = fmc->op->reprogram(fmc, &t_drv, "");
-	if (ret == -ESRCH)
+	ret = fmc_reprogram(fmc, &t_drv, "", 0);
+	if (ret == -EPERM) /* programming not supported */
 		ret = 0;
 	if (ret < 0)
-		fmc->op->irq_free(fmc);
+		fmc_irq_free(fmc);

 	/* FIXME: reprogram LM32 too */
 	return ret;
@@ -72,7 +68,7 @@ static int t_probe(struct fmc_device *fmc)

 static int t_remove(struct fmc_device *fmc)
 {
-	fmc->op->irq_free(fmc);
+	fmc_irq_free(fmc);
 	return 0;
 }

diff --git a/drivers/fmc/fmc-write-eeprom.c b/drivers/fmc/fmc-write-eeprom.c
index 9bb2cbd..3eb81bb 100644
--- a/drivers/fmc/fmc-write-eeprom.c
+++ b/drivers/fmc/fmc-write-eeprom.c
@@ -50,7 +50,7 @@ static int fwe_run_tlv(struct fmc_device *fmc, const struct firmware *fw,
 		if (write) {
 			dev_info(&fmc->dev, "write %i bytes at 0x%04x\n",
 				 thislen, thisaddr);
-			err = fmc->op->write_ee(fmc, thisaddr, p + 5, thislen);
+			err = fmc_write_ee(fmc, thisaddr, p + 5, thislen);
 		}
 		if (err < 0) {
 			dev_err(&fmc->dev, "write failure @0x%04x\n",
@@ -70,7 +70,7 @@ 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->op->write_ee(fmc, 0, (void *)fw->data, 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;
@@ -115,8 +115,8 @@ static int fwe_probe(struct fmc_device *fmc)
 			KBUILD_MODNAME);
 		return -ENODEV;
 	}
-	if (fmc->op->validate)
-		index = fmc->op->validate(fmc, &fwe_drv);
+
+	index = fmc_validate(fmc, &fwe_drv);
 	if (index < 0) {
 		pr_err("%s: refusing device \"%s\"\n", KBUILD_MODNAME,
 		       dev_name(dev));
diff --git a/include/linux/fmc.h b/include/linux/fmc.h
index a5f0aa5..8bb4a15 100644
--- a/include/linux/fmc.h
+++ b/include/linux/fmc.h
@@ -234,4 +234,22 @@ static inline void fmc_set_drvdata(struct fmc_device *fmc, void *data)
 extern void fmc_dump_eeprom(const struct fmc_device *fmc);
 extern void fmc_dump_sdb(const struct fmc_device *fmc);

+/* helpers for FMC operations */
+extern int fmc_irq_request(struct fmc_device *fmc, irq_handler_t h,
+			   char *name, int flags);
+extern void fmc_irq_free(struct fmc_device *fmc);
+extern void fmc_irq_ack(struct fmc_device *fmc);
+extern int fmc_validate(struct fmc_device *fmc, struct fmc_driver *drv);
+extern int fmc_gpio_config(struct fmc_device *fmc, struct fmc_gpio *gpio,
+			   int ngpio);
+extern int fmc_read_ee(struct fmc_device *fmc, int pos, void *d, int l);
+extern int fmc_write_ee(struct fmc_device *fmc, int pos, const void *d, int l);
+
+/* helpers for FMC operations */
+extern int fmc_irq_request(struct fmc_device *fmc, irq_handler_t h,
+			   char *name, int flags);
+extern void fmc_irq_free(struct fmc_device *fmc);
+extern void fmc_irq_ack(struct fmc_device *fmc);
+extern int fmc_validate(struct fmc_device *fmc, struct fmc_driver *drv);
+
 #endif /* __LINUX_FMC_H__ */
--
1.8.3.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 3/5] drivers/fmc: The only way to dump the SDB is from debugfs
  2017-06-30 16:15 [PATCH 0/5] Update kernel to latest FMC bus release Pat Riehecky
  2017-06-30 16:15 ` [PATCH 1/5] drivers/fmc: remove unused variable Pat Riehecky
  2017-06-30 16:15 ` [PATCH 2/5] drivers/fmc: hide fmc operations behind helpers Pat Riehecky
@ 2017-06-30 16:15 ` Pat Riehecky
  2017-06-30 16:15 ` [PATCH 4/5] drivers/fmc: change registration prototype Pat Riehecky
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Pat Riehecky @ 2017-06-30 16:15 UTC (permalink / raw)
  To: linux-kernel; +Cc: rubini, drivers_other, gregkh, federico.vaga, Pat Riehecky

Driver should not call fmc_sdb_dump() anymore. (actually they can but the
operation is not supported, so it will print an error message)

Signed-off-by: Federico Vaga <federico.vaga@cern.ch>
---
 drivers/fmc/Makefile      |   1 +
 drivers/fmc/fmc-core.c    |   7 +-
 drivers/fmc/fmc-debug.c   | 173 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/fmc/fmc-dump.c    |  41 -----------
 drivers/fmc/fmc-private.h |   9 +++
 drivers/fmc/fmc-sdb.c     |  99 +-------------------------
 include/linux/fmc.h       |   4 +-
 7 files changed, 195 insertions(+), 139 deletions(-)
 create mode 100644 drivers/fmc/fmc-debug.c
 create mode 100644 drivers/fmc/fmc-private.h

diff --git a/drivers/fmc/Makefile b/drivers/fmc/Makefile
index b945291..e809322 100644
--- a/drivers/fmc/Makefile
+++ b/drivers/fmc/Makefile
@@ -6,6 +6,7 @@ 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
diff --git a/drivers/fmc/fmc-core.c b/drivers/fmc/fmc-core.c
index 5263d06..ef6d8ac 100644
--- a/drivers/fmc/fmc-core.c
+++ b/drivers/fmc/fmc-core.c
@@ -13,6 +13,9 @@
 #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)
 {
@@ -289,7 +292,7 @@ int fmc_device_register_n(struct fmc_device **devs, int n)
 		}
 		/* This device went well, give information to the user */
 		fmc_dump_eeprom(fmc);
-		fmc_dump_sdb(fmc);
+		fmc_debug_init(fmc);
 	}
 	return 0;

@@ -301,6 +304,7 @@ int fmc_device_register_n(struct fmc_device **devs, int n)

 	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]);
@@ -328,6 +332,7 @@ void fmc_device_unregister_n(struct fmc_device **devs, int n)
 	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]);
diff --git a/drivers/fmc/fmc-debug.c b/drivers/fmc/fmc-debug.c
new file mode 100644
index 0000000..3293072
--- /dev/null
+++ b/drivers/fmc/fmc-debug.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2015 CERN (www.cern.ch)
+ * Author: Federico Vaga <federico.vaga@cern.ch>
+ *
+ * Released according to the GNU GPL, version 2 or any later version.
+ */
+
+#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
index c91afd6..cd1df47 100644
--- a/drivers/fmc/fmc-dump.c
+++ b/drivers/fmc/fmc-dump.c
@@ -15,8 +15,6 @@

 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

@@ -59,42 +57,3 @@ void fmc_dump_eeprom(const struct fmc_device *fmc)
 	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;
-}
diff --git a/drivers/fmc/fmc-private.h b/drivers/fmc/fmc-private.h
new file mode 100644
index 0000000..1e51366
--- /dev/null
+++ b/drivers/fmc/fmc-private.h
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2015 CERN (www.cern.ch)
+ * Author: Federico Vaga <federico.vaga@cern.ch>
+ *
+ * Released according to the GNU GPL, version 2 or any later version.
+ */
+
+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
index 4603fdb..89e37a6 100644
--- a/drivers/fmc/fmc-sdb.c
+++ b/drivers/fmc/fmc-sdb.c
@@ -145,108 +145,15 @@ int fmc_reprogram(struct fmc_device *fmc, struct fmc_driver *d, char *gw,
 			sdb_entry);
 		return -ENODEV;
 	}
-	fmc_dump_sdb(fmc);
+
 	return 0;
 }
 EXPORT_SYMBOL(fmc_reprogram);

-static char *__strip_trailing_space(char *buf, char *str, int len)
-{
-	int i = len - 1;
-
-	memcpy(buf, str, len);
-	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));	\
-		})
-
-static void __fmc_show_sdb_tree(const struct fmc_device *fmc,
-				const struct sdb_array *arr)
-{
-	unsigned long base = arr->baseaddr;
-	int i, j, n = arr->len, level = arr->level;
-	char buf[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;
-
-		dev_info(&fmc->dev, "SDB: ");
-
-		for (j = 0; j < level; j++)
-			printk(KERN_CONT "   ");
-		switch (r->empty.record_type) {
-		case sdb_type_interconnect:
-			printk(KERN_CONT "%08llx:%08x %.19s\n",
-			       __be64_to_cpu(p->vendor_id),
-			       __be32_to_cpu(p->device_id),
-			       p->name);
-			break;
-		case sdb_type_device:
-			printk(KERN_CONT "%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:
-			printk(KERN_CONT "%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])) {
-				dev_info(&fmc->dev, "SDB: (bridge error %li)\n",
-					 PTR_ERR(arr->subtree[i]));
-				break;
-			}
-			__fmc_show_sdb_tree(fmc, arr->subtree[i]);
-			break;
-		case sdb_type_integration:
-			printk(KERN_CONT "integration\n");
-			break;
-		case sdb_type_repo_url:
-			printk(KERN_CONT "Synthesis repository: %s\n",
-			       __sdb_string(buf, r->repo_url.repo_url));
-			break;
-		case sdb_type_synthesis:
-			printk(KERN_CONT "Bitstream '%s' ",
-			       __sdb_string(buf, r->synthesis.syn_name));
-			printk(KERN_CONT "synthesized %08x by %s ",
-			       __be32_to_cpu(r->synthesis.date),
-			       __sdb_string(buf, r->synthesis.user_name));
-			printk(KERN_CONT "(%s version %x), ",
-			       __sdb_string(buf, r->synthesis.tool_name),
-			       __be32_to_cpu(r->synthesis.tool_version));
-			printk(KERN_CONT "commit %pm\n",
-			       r->synthesis.commit_id);
-			break;
-		case sdb_type_empty:
-			printk(KERN_CONT "empty\n");
-			break;
-		default:
-			printk(KERN_CONT "UNKNOWN TYPE 0x%02x\n",
-			       r->empty.record_type);
-			break;
-		}
-	}
-}
-
 void fmc_show_sdb_tree(const struct fmc_device *fmc)
 {
-	if (!fmc->sdb)
-		return;
-	__fmc_show_sdb_tree(fmc, fmc->sdb);
+	pr_err("%s: not supported anymore, use debugfs to dump SDB\n",
+		__func__);
 }
 EXPORT_SYMBOL(fmc_show_sdb_tree);

diff --git a/include/linux/fmc.h b/include/linux/fmc.h
index 8bb4a15..5c8df0c 100644
--- a/include/linux/fmc.h
+++ b/include/linux/fmc.h
@@ -180,6 +180,9 @@ struct fmc_device {
 	uint32_t device_id;		/* Filled by the device */
 	char *mezzanine_name;		/* Defaults to ``fmc'' */
 	void *mezzanine_data;
+
+	struct dentry *dbg_dir;
+	struct dentry *dbg_sdb_dump;
 };
 #define to_fmc_device(x) container_of((x), struct fmc_device, dev)

@@ -232,7 +235,6 @@ static inline void fmc_set_drvdata(struct fmc_device *fmc, void *data)
 extern int fmc_fill_id_info(struct fmc_device *fmc);
 extern void fmc_free_id_info(struct fmc_device *fmc);
 extern void fmc_dump_eeprom(const struct fmc_device *fmc);
-extern void fmc_dump_sdb(const struct fmc_device *fmc);

 /* helpers for FMC operations */
 extern int fmc_irq_request(struct fmc_device *fmc, irq_handler_t h,
--
1.8.3.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 4/5] drivers/fmc: change registration prototype
  2017-06-30 16:15 [PATCH 0/5] Update kernel to latest FMC bus release Pat Riehecky
                   ` (2 preceding siblings ...)
  2017-06-30 16:15 ` [PATCH 3/5] drivers/fmc: The only way to dump the SDB is from debugfs Pat Riehecky
@ 2017-06-30 16:15 ` Pat Riehecky
  2017-06-30 16:15 ` [PATCH 5/5] drivers/fmc: carrier can program FPGA on registration Pat Riehecky
  2017-07-05 10:27 ` [PATCH 0/5] Update kernel to latest FMC bus release Alessandro Rubini
  5 siblings, 0 replies; 16+ messages in thread
From: Pat Riehecky @ 2017-06-30 16:15 UTC (permalink / raw)
  To: linux-kernel; +Cc: rubini, drivers_other, gregkh, federico.vaga, Pat Riehecky

Permit use of either fmc_device_register_n or fmc_device_register_n_gw
depending on the type of device in use.

Signed-off-by: Federico Vaga <federico.vaga@cern.ch>
---
 drivers/fmc/fmc-core.c | 15 ++++++++++++++-
 include/linux/fmc.h    | 13 +++++++++++--
 2 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/drivers/fmc/fmc-core.c b/drivers/fmc/fmc-core.c
index ef6d8ac..eabeac0 100644
--- a/drivers/fmc/fmc-core.c
+++ b/drivers/fmc/fmc-core.c
@@ -199,7 +199,8 @@ void fmc_driver_unregister(struct fmc_driver *drv)
  * When a device set is registered, all eeproms must be read
  * and all FRUs must be parsed
  */
-int fmc_device_register_n(struct fmc_device **devs, int n)
+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;
@@ -313,8 +314,20 @@ int fmc_device_register_n(struct fmc_device **devs, int n)
 	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);
diff --git a/include/linux/fmc.h b/include/linux/fmc.h
index 5c8df0c..b6c73d5 100644
--- a/include/linux/fmc.h
+++ b/include/linux/fmc.h
@@ -220,14 +220,23 @@ static inline void fmc_set_drvdata(struct fmc_device *fmc, void *data)
 	dev_set_drvdata(&fmc->dev, data);
 }

-/* The 4 access points */
+struct fmc_gateware {
+	void *bitstream;
+	unsigned long len;
+};
+
+/* The 5 access points */
 extern int fmc_driver_register(struct fmc_driver *drv);
 extern void fmc_driver_unregister(struct fmc_driver *drv);
 extern int fmc_device_register(struct fmc_device *tdev);
+extern int fmc_device_register_gw(struct fmc_device *tdev,
+				  struct fmc_gateware *gw);
 extern void fmc_device_unregister(struct fmc_device *tdev);

-/* Two more for device sets, all driven by the same FPGA */
+/* Three more for device sets, all driven by the same FPGA */
 extern int fmc_device_register_n(struct fmc_device **devs, int n);
+extern int fmc_device_register_n_gw(struct fmc_device **devs, int n,
+				    struct fmc_gateware *gw);
 extern void fmc_device_unregister_n(struct fmc_device **devs, int n);

 /* Internal cross-calls between files; not exported to other modules */
--
1.8.3.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 5/5] drivers/fmc: carrier can program FPGA on registration
  2017-06-30 16:15 [PATCH 0/5] Update kernel to latest FMC bus release Pat Riehecky
                   ` (3 preceding siblings ...)
  2017-06-30 16:15 ` [PATCH 4/5] drivers/fmc: change registration prototype Pat Riehecky
@ 2017-06-30 16:15 ` Pat Riehecky
  2017-07-05 10:27 ` [PATCH 0/5] Update kernel to latest FMC bus release Alessandro Rubini
  5 siblings, 0 replies; 16+ messages in thread
From: Pat Riehecky @ 2017-06-30 16:15 UTC (permalink / raw)
  To: linux-kernel; +Cc: rubini, drivers_other, gregkh, federico.vaga, Pat Riehecky

The initial FPGA may require programming before it is useful.

Signed-off-by: Federico Vaga <federico.vaga@cern.ch>
---
 drivers/fmc/fmc-core.c | 18 +++++++++++++++---
 drivers/fmc/fmc-sdb.c  | 24 ++++++++++++++++++++++++
 include/linux/fmc.h    |  4 ++++
 3 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/drivers/fmc/fmc-core.c b/drivers/fmc/fmc-core.c
index eabeac0..cec3b8d 100644
--- a/drivers/fmc/fmc-core.c
+++ b/drivers/fmc/fmc-core.c
@@ -280,6 +280,21 @@ int fmc_device_register_n_gw(struct fmc_device **devs, int n,
 		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 "
@@ -300,9 +315,6 @@ int fmc_device_register_n_gw(struct fmc_device **devs, int n,
 out1:
 	device_del(&fmc->dev);
 out:
-	fmc_free_id_info(fmc);
-	put_device(&fmc->dev);
-
 	kfree(devarray);
 	for (i--; i >= 0; i--) {
 		fmc_debug_exit(devs[i]);
diff --git a/drivers/fmc/fmc-sdb.c b/drivers/fmc/fmc-sdb.c
index 89e37a6..ffdc176 100644
--- a/drivers/fmc/fmc-sdb.c
+++ b/drivers/fmc/fmc-sdb.c
@@ -127,6 +127,30 @@ int fmc_free_sdb_tree(struct fmc_device *fmc)
 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)
 {
diff --git a/include/linux/fmc.h b/include/linux/fmc.h
index b6c73d5..3dc8a1b 100644
--- a/include/linux/fmc.h
+++ b/include/linux/fmc.h
@@ -132,6 +132,8 @@ struct fmc_operations {
 	uint32_t (*read32)(struct fmc_device *fmc, int offset);
 	void (*write32)(struct fmc_device *fmc, uint32_t value, int offset);
 	int (*validate)(struct fmc_device *fmc, struct fmc_driver *drv);
+	int (*reprogram_raw)(struct fmc_device *f, struct fmc_driver *d,
+			     void *gw, unsigned long len);
 	int (*reprogram)(struct fmc_device *f, struct fmc_driver *d, char *gw);
 	int (*irq_request)(struct fmc_device *fmc, irq_handler_t h,
 			   char *name, int flags);
@@ -144,6 +146,8 @@ struct fmc_operations {
 };

 /* Prefer this helper rather than calling of fmc->reprogram directly */
+int fmc_reprogram_raw(struct fmc_device *fmc, struct fmc_driver *d,
+		      void *gw, unsigned long len, int sdb_entry);
 extern int fmc_reprogram(struct fmc_device *f, struct fmc_driver *d, char *gw,
 		     int sdb_entry);

--
1.8.3.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/5] Update kernel to latest FMC bus release
  2017-06-30 16:15 [PATCH 0/5] Update kernel to latest FMC bus release Pat Riehecky
                   ` (4 preceding siblings ...)
  2017-06-30 16:15 ` [PATCH 5/5] drivers/fmc: carrier can program FPGA on registration Pat Riehecky
@ 2017-07-05 10:27 ` Alessandro Rubini
  2017-07-05 14:22   ` [PATCH v2 00/05] " Pat Riehecky
  5 siblings, 1 reply; 16+ messages in thread
From: Alessandro Rubini @ 2017-07-05 10:27 UTC (permalink / raw)
  To: riehecky; +Cc: linux-kernel, drivers_other, gregkh, federico.vaga

Hello.

Thank you Pat for taking care of these patches.

> Federico Vaga (5):
>   drivers/fmc: remove unused variable
>   drivers/fmc: hide fmc operations behind helpers
>   drivers/fmc: The only way to dump the SDB is from debugfs
>   drivers/fmc: change registration prototype
>   drivers/fmc: carrier can program FPGA on registration

The main problem with your patches, as submitted, is that they miss
the "From:" line to attribute Federico as author.  Then I think you
might add your own "Tested-by:".

I want to ack them but I'd love to run them first to have a second
check.  I should definitely manage it in a pair of days
more. Meanwhile, if you want to post V2 with the fixes above that
would be great. If needed, you can write me offlist.

thankyou for your submission and your patience
/alessandro

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v2 00/05] Update kernel to latest FMC bus release
  2017-07-05 10:27 ` [PATCH 0/5] Update kernel to latest FMC bus release Alessandro Rubini
@ 2017-07-05 14:22   ` Pat Riehecky
  2017-07-05 14:22     ` [PATCH v2 01/05] drivers/fmc: remove unused variable Pat Riehecky
                       ` (4 more replies)
  0 siblings, 5 replies; 16+ messages in thread
From: Pat Riehecky @ 2017-07-05 14:22 UTC (permalink / raw)
  To: linux-kernel; +Cc: rubini, federico.vaga, gregkh, drivers_other

The version 2 patch set includes correct From: and Tested-by: entries.

The following patches sync up the mainline kernel's FMC bus with the upstream release tagged v2017-06.

Commits (written by Federico Vaga) have been squashed into logical units.

These patches address kernel bug 195653.

These specific changes have been live within the FMC repo since 2015 and in active use by FMC projects since then.

The patches include 1 bugfix and 4 enhancements:

Bugfix:
0001-fmc-remove-unused-variable.patch  -  remove an unused int

Enhancement:
0002-fmc-hide-fmc-operations-behind-helpers.patch - user helper functions to hide internal semantics
0003-fmc-The-only-way-to-dump-the-SDB-is-from-debugfs.patch - use debugfs to dump the device
0004-fmc-change-registration-prototype.patch - add a second prototype for device registration
0005-fmc-carrier-can-program-FPGA-on-registration.patch - permit programming the FPGA on registration


Upstream git repo: http://www.ohwr.org/projects/fmc-bus/repository/show?rev=fmc-bus-v2017-06


FMC maintainer: Alessandro Rubini <rubini@gnudd.com>
Initial approver of FMC: Greg KH <gregkh@linuxfoundation.org>
Bugzilla assigned to: drivers_other@kernel-bugs.osdl.org

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v2 01/05] drivers/fmc: remove unused variable
  2017-07-05 14:22   ` [PATCH v2 00/05] " Pat Riehecky
@ 2017-07-05 14:22     ` Pat Riehecky
  2017-07-17 14:29       ` Greg KH
  2017-07-05 14:22     ` [PATCH v2 02/05] drivers/fmc: hide fmc operations behind helpers Pat Riehecky
                       ` (3 subsequent siblings)
  4 siblings, 1 reply; 16+ messages in thread
From: Pat Riehecky @ 2017-07-05 14:22 UTC (permalink / raw)
  To: linux-kernel; +Cc: rubini, federico.vaga, gregkh, drivers_other, Pat Riehecky

From: Federico Vaga <federico.vaga@cern.ch>
Signed-off-by: Federico Vaga <federico.vaga@cern.ch>
Tested-by: Pat Riehecky <riehecky@fnal.gov>
---
 drivers/fmc/fru-parse.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/fmc/fru-parse.c b/drivers/fmc/fru-parse.c
index cb46263..eb21480 100644
--- a/drivers/fmc/fru-parse.c
+++ b/drivers/fmc/fru-parse.c
@@ -31,12 +31,11 @@ static char *__fru_alloc_get_tl(struct fru_common_header *header, int nr)
 {
 	struct fru_type_length *tl;
 	char *res;
-	int len;

 	tl = __fru_get_board_tl(header, nr);
 	if (!tl)
 		return NULL;
-	len = fru_strlen(tl);
+
 	res = fru_alloc(fru_strlen(tl) + 1);
 	if (!res)
 		return NULL;
--
1.8.3.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 02/05] drivers/fmc: hide fmc operations behind helpers
  2017-07-05 14:22   ` [PATCH v2 00/05] " Pat Riehecky
  2017-07-05 14:22     ` [PATCH v2 01/05] drivers/fmc: remove unused variable Pat Riehecky
@ 2017-07-05 14:22     ` Pat Riehecky
  2017-07-05 14:22     ` [PATCH v2 03/05] drivers/fmc: The only way to dump the SDB is from debugfs Pat Riehecky
                       ` (2 subsequent siblings)
  4 siblings, 0 replies; 16+ messages in thread
From: Pat Riehecky @ 2017-07-05 14:22 UTC (permalink / raw)
  To: linux-kernel; +Cc: rubini, federico.vaga, gregkh, drivers_other, Pat Riehecky

This gave us more freedom to change/add/remove operations without
recompiling all device driver.

Typically, Carrier board implement the fmc operations, so they will not
use these helpers.

From: Federico Vaga <federico.vaga@cern.ch>
Signed-off-by: Federico Vaga <federico.vaga@cern.ch>
Tested-by: Pat Riehecky <riehecky@fnal.gov>
---
 drivers/fmc/fmc-chardev.c       |  3 +--
 drivers/fmc/fmc-core.c          | 55 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/fmc/fmc-match.c         |  2 +-
 drivers/fmc/fmc-trivial.c       | 20 +++++++----------
 drivers/fmc/fmc-write-eeprom.c  |  8 +++----
 include/linux/fmc.h | 18 +++++++++++++++
 6 files changed, 87 insertions(+), 19 deletions(-)

diff --git a/drivers/fmc/fmc-chardev.c b/drivers/fmc/fmc-chardev.c
index 38aa7c4..b3eb6a2 100644
--- a/drivers/fmc/fmc-chardev.c
+++ b/drivers/fmc/fmc-chardev.c
@@ -129,8 +129,7 @@ static int fc_probe(struct fmc_device *fmc)

 	struct fc_instance *fc;

-	if (fmc->op->validate)
-		index = fmc->op->validate(fmc, &fc_drv);
+	index = fmc_validate(fmc, &fc_drv);
 	if (index < 0)
 		return -EINVAL; /* not our device: invalid */

diff --git a/drivers/fmc/fmc-core.c b/drivers/fmc/fmc-core.c
index 0189518..60e568d 100644
--- a/drivers/fmc/fmc-core.c
+++ b/drivers/fmc/fmc-core.c
@@ -118,6 +118,61 @@ static struct bin_attribute fmc_eeprom_attr = {
 	.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
  */
diff --git a/drivers/fmc/fmc-match.c b/drivers/fmc/fmc-match.c
index 104a5ef..a0956d1 100644
--- a/drivers/fmc/fmc-match.c
+++ b/drivers/fmc/fmc-match.c
@@ -63,7 +63,7 @@ int fmc_fill_id_info(struct fmc_device *fmc)
 		if (!fmc->eeprom)
 			return -ENOMEM;
 		allocated = 1;
-		ret = fmc->op->read_ee(fmc, 0, fmc->eeprom, fmc->eeprom_len);
+		ret = fmc_read_ee(fmc, 0, fmc->eeprom, fmc->eeprom_len);
 		if (ret < 0)
 			goto out;
 	}
diff --git a/drivers/fmc/fmc-trivial.c b/drivers/fmc/fmc-trivial.c
index d26a174..7c03946 100644
--- a/drivers/fmc/fmc-trivial.c
+++ b/drivers/fmc/fmc-trivial.c
@@ -18,7 +18,7 @@ static irqreturn_t t_handler(int irq, void *dev_id)
 {
 	struct fmc_device *fmc = dev_id;

-	fmc->op->irq_ack(fmc);
+	fmc_irq_ack(fmc);
 	dev_info(&fmc->dev, "received irq %i\n", irq);
 	return IRQ_HANDLED;
 }
@@ -40,25 +40,21 @@ static int t_probe(struct fmc_device *fmc)
 	int ret;
 	int index = 0;

-	if (fmc->op->validate)
-		index = fmc->op->validate(fmc, &t_drv);
+	index = fmc_validate(fmc, &t_drv);
 	if (index < 0)
 		return -EINVAL; /* not our device: invalid */

-	ret = fmc->op->irq_request(fmc, t_handler, "fmc-trivial", IRQF_SHARED);
+	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->op->gpio_config(fmc, t_gpio, ARRAY_SIZE(t_gpio));
+	fmc_gpio_config(fmc, t_gpio, ARRAY_SIZE(t_gpio));

-	/* Reprogram, if asked to. ESRCH == no filename specified */
-	ret = -ESRCH;
-	if (fmc->op->reprogram)
-		ret = fmc->op->reprogram(fmc, &t_drv, "");
-	if (ret == -ESRCH)
+	ret = fmc_reprogram(fmc, &t_drv, "", 0);
+	if (ret == -EPERM) /* programming not supported */
 		ret = 0;
 	if (ret < 0)
-		fmc->op->irq_free(fmc);
+		fmc_irq_free(fmc);

 	/* FIXME: reprogram LM32 too */
 	return ret;
@@ -66,7 +62,7 @@ static int t_probe(struct fmc_device *fmc)

 static int t_remove(struct fmc_device *fmc)
 {
-	fmc->op->irq_free(fmc);
+	fmc_irq_free(fmc);
 	return 0;
 }

diff --git a/drivers/fmc/fmc-write-eeprom.c b/drivers/fmc/fmc-write-eeprom.c
index aa88f02..de1c113 100644
--- a/drivers/fmc/fmc-write-eeprom.c
+++ b/drivers/fmc/fmc-write-eeprom.c
@@ -50,7 +50,7 @@ static int fwe_run_tlv(struct fmc_device *fmc, const struct firmware *fw,
 		if (write) {
 			dev_info(&fmc->dev, "write %i bytes at 0x%04x\n",
 				 thislen, thisaddr);
-			err = fmc->op->write_ee(fmc, thisaddr, p + 5, thislen);
+			err = fmc_write_ee(fmc, thisaddr, p + 5, thislen);
 		}
 		if (err < 0) {
 			dev_err(&fmc->dev, "write failure @0x%04x\n",
@@ -70,7 +70,7 @@ 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->op->write_ee(fmc, 0, (void *)fw->data, 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;
@@ -115,8 +115,8 @@ int fwe_probe(struct fmc_device *fmc)
 			KBUILD_MODNAME);
 		return -ENODEV;
 	}
-	if (fmc->op->validate)
-		index = fmc->op->validate(fmc, &fwe_drv);
+
+	index = fmc_validate(fmc, &fwe_drv);
 	if (index < 0) {
 		pr_err("%s: refusing device \"%s\"\n", KBUILD_MODNAME,
 		       dev_name(dev));
diff --git a/include/linux/fmc.h b/include/linux/fmc.h
index a5f0aa5..8bb4a15 100644
--- a/include/linux/fmc.h
+++ b/include/linux/fmc.h
@@ -234,4 +234,22 @@ extern void fmc_free_id_info(struct fmc_device *fmc);
 extern void fmc_dump_eeprom(const struct fmc_device *fmc);
 extern void fmc_dump_sdb(const struct fmc_device *fmc);

+/* helpers for FMC operations */
+extern int fmc_irq_request(struct fmc_device *fmc, irq_handler_t h,
+			   char *name, int flags);
+extern void fmc_irq_free(struct fmc_device *fmc);
+extern void fmc_irq_ack(struct fmc_device *fmc);
+extern int fmc_validate(struct fmc_device *fmc, struct fmc_driver *drv);
+extern int fmc_gpio_config(struct fmc_device *fmc, struct fmc_gpio *gpio,
+			   int ngpio);
+extern int fmc_read_ee(struct fmc_device *fmc, int pos, void *d, int l);
+extern int fmc_write_ee(struct fmc_device *fmc, int pos, const void *d, int l);
+
+/* helpers for FMC operations */
+extern int fmc_irq_request(struct fmc_device *fmc, irq_handler_t h,
+			   char *name, int flags);
+extern void fmc_irq_free(struct fmc_device *fmc);
+extern void fmc_irq_ack(struct fmc_device *fmc);
+extern int fmc_validate(struct fmc_device *fmc, struct fmc_driver *drv);
+
 #endif /* __LINUX_FMC_H__ */
--
1.8.3.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 03/05] drivers/fmc: The only way to dump the SDB is from debugfs
  2017-07-05 14:22   ` [PATCH v2 00/05] " Pat Riehecky
  2017-07-05 14:22     ` [PATCH v2 01/05] drivers/fmc: remove unused variable Pat Riehecky
  2017-07-05 14:22     ` [PATCH v2 02/05] drivers/fmc: hide fmc operations behind helpers Pat Riehecky
@ 2017-07-05 14:22     ` Pat Riehecky
  2017-07-05 14:22     ` [PATCH v2 04/05] drivers/fmc: change registration prototype Pat Riehecky
  2017-07-05 14:22     ` [PATCH v2 05/05] drivers/fmc: carrier can program FPGA on registration Pat Riehecky
  4 siblings, 0 replies; 16+ messages in thread
From: Pat Riehecky @ 2017-07-05 14:22 UTC (permalink / raw)
  To: linux-kernel; +Cc: rubini, federico.vaga, gregkh, drivers_other, Pat Riehecky

Driver should not call fmc_sdb_dump() anymore. (actually they can but the
operation is not supported, so it will print an error message)

From: Federico Vaga <federico.vaga@cern.ch>
Signed-off-by: Federico Vaga <federico.vaga@cern.ch>
Tested-by: Pat Riehecky <riehecky@fnal.gov>
---
 drivers/fmc/Makefile                |   2 +
 drivers/fmc/fmc-core.c              |   7 +-
 drivers/fmc/fmc-debug.c             | 171 +++++++++++++++++++++++++++++++++++++++++
 drivers/fmc/fmc-dump.c              |  41 ----------
 drivers/fmc/fmc-private.h           |   9 +++
 drivers/fmc/fmc-sdb.c               |  99 +-----------------------
 include/linux/fmc-sdb.h |   1 +
 include/linux/fmc.h     |   4 +-
 8 files changed, 195 insertions(+), 139 deletions(-)
 create mode 100644 drivers/fmc/fmc-debug.c
 create mode 100644 drivers/fmc/fmc-private.h

diff --git a/drivers/fmc/Makefile b/drivers/fmc/Makefile
index bb6efcd..6e2ad7b 100644
--- a/drivers/fmc/Makefile
+++ b/drivers/fmc/Makefile
@@ -6,6 +6,7 @@ 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
diff --git a/drivers/fmc/fmc-core.c b/drivers/fmc/fmc-core.c
index 60e568d..50e18ba 100644
--- a/drivers/fmc/fmc-core.c
+++ b/drivers/fmc/fmc-core.c
@@ -13,6 +13,9 @@
 #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)
 {
@@ -289,7 +292,7 @@ int fmc_device_register_n(struct fmc_device **devs, int n)
 		}
 		/* This device went well, give information to the user */
 		fmc_dump_eeprom(fmc);
-		fmc_dump_sdb(fmc);
+		fmc_debug_init(fmc);
 	}
 	return 0;

@@ -301,6 +304,7 @@ 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]);
@@ -328,6 +332,7 @@ void fmc_device_unregister_n(struct fmc_device **devs, int n)
 	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]);
diff --git a/drivers/fmc/fmc-debug.c b/drivers/fmc/fmc-debug.c
new file mode 100644
index 0000000..33fca9c
--- /dev/null
+++ b/drivers/fmc/fmc-debug.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2015 CERN (www.cern.ch)
+ * Author: Federico Vaga <federico.vaga@cern.ch>
+ *
+ * Released according to the GNU GPL, version 2 or any later version.
+ */
+
+#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
index c91afd6..cd1df47 100644
--- a/drivers/fmc/fmc-dump.c
+++ b/drivers/fmc/fmc-dump.c
@@ -15,8 +15,6 @@

 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

@@ -59,42 +57,3 @@ void fmc_dump_eeprom(const struct fmc_device *fmc)
 	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;
-}
diff --git a/drivers/fmc/fmc-private.h b/drivers/fmc/fmc-private.h
new file mode 100644
index 0000000..1e51366
--- /dev/null
+++ b/drivers/fmc/fmc-private.h
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2015 CERN (www.cern.ch)
+ * Author: Federico Vaga <federico.vaga@cern.ch>
+ *
+ * Released according to the GNU GPL, version 2 or any later version.
+ */
+
+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
index 4603fdb..89e37a6 100644
--- a/drivers/fmc/fmc-sdb.c
+++ b/drivers/fmc/fmc-sdb.c
@@ -145,108 +145,15 @@ int fmc_reprogram(struct fmc_device *fmc, struct fmc_driver *d, char *gw,
 			sdb_entry);
 		return -ENODEV;
 	}
-	fmc_dump_sdb(fmc);
+
 	return 0;
 }
 EXPORT_SYMBOL(fmc_reprogram);

-static char *__strip_trailing_space(char *buf, char *str, int len)
-{
-	int i = len - 1;
-
-	memcpy(buf, str, len);
-	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));	\
-		})
-
-static void __fmc_show_sdb_tree(const struct fmc_device *fmc,
-				const struct sdb_array *arr)
-{
-	unsigned long base = arr->baseaddr;
-	int i, j, n = arr->len, level = arr->level;
-	char buf[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;
-
-		dev_info(&fmc->dev, "SDB: ");
-
-		for (j = 0; j < level; j++)
-			printk(KERN_CONT "   ");
-		switch (r->empty.record_type) {
-		case sdb_type_interconnect:
-			printk(KERN_CONT "%08llx:%08x %.19s\n",
-			       __be64_to_cpu(p->vendor_id),
-			       __be32_to_cpu(p->device_id),
-			       p->name);
-			break;
-		case sdb_type_device:
-			printk(KERN_CONT "%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:
-			printk(KERN_CONT "%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])) {
-				dev_info(&fmc->dev, "SDB: (bridge error %li)\n",
-					 PTR_ERR(arr->subtree[i]));
-				break;
-			}
-			__fmc_show_sdb_tree(fmc, arr->subtree[i]);
-			break;
-		case sdb_type_integration:
-			printk(KERN_CONT "integration\n");
-			break;
-		case sdb_type_repo_url:
-			printk(KERN_CONT "Synthesis repository: %s\n",
-			       __sdb_string(buf, r->repo_url.repo_url));
-			break;
-		case sdb_type_synthesis:
-			printk(KERN_CONT "Bitstream '%s' ",
-			       __sdb_string(buf, r->synthesis.syn_name));
-			printk(KERN_CONT "synthesized %08x by %s ",
-			       __be32_to_cpu(r->synthesis.date),
-			       __sdb_string(buf, r->synthesis.user_name));
-			printk(KERN_CONT "(%s version %x), ",
-			       __sdb_string(buf, r->synthesis.tool_name),
-			       __be32_to_cpu(r->synthesis.tool_version));
-			printk(KERN_CONT "commit %pm\n",
-			       r->synthesis.commit_id);
-			break;
-		case sdb_type_empty:
-			printk(KERN_CONT "empty\n");
-			break;
-		default:
-			printk(KERN_CONT "UNKNOWN TYPE 0x%02x\n",
-			       r->empty.record_type);
-			break;
-		}
-	}
-}
-
 void fmc_show_sdb_tree(const struct fmc_device *fmc)
 {
-	if (!fmc->sdb)
-		return;
-	__fmc_show_sdb_tree(fmc, fmc->sdb);
+	pr_err("%s: not supported anymore, use debugfs to dump SDB\n",
+		__func__);
 }
 EXPORT_SYMBOL(fmc_show_sdb_tree);

diff --git a/include/linux/fmc.h b/include/linux/fmc.h
index 8bb4a15..5c8df0c 100644
--- a/include/linux/fmc.h
+++ b/include/linux/fmc.h
@@ -180,6 +180,9 @@ struct fmc_device {
 	uint32_t device_id;		/* Filled by the device */
 	char *mezzanine_name;		/* Defaults to ``fmc'' */
 	void *mezzanine_data;
+
+	struct dentry *dbg_dir;
+	struct dentry *dbg_sdb_dump;
 };
 #define to_fmc_device(x) container_of((x), struct fmc_device, dev)

@@ -232,7 +235,6 @@ extern int fmc_match(struct device *dev, struct device_driver *drv);
 extern int fmc_fill_id_info(struct fmc_device *fmc);
 extern void fmc_free_id_info(struct fmc_device *fmc);
 extern void fmc_dump_eeprom(const struct fmc_device *fmc);
-extern void fmc_dump_sdb(const struct fmc_device *fmc);

 /* helpers for FMC operations */
 extern int fmc_irq_request(struct fmc_device *fmc, irq_handler_t h,
--
1.8.3.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 04/05] drivers/fmc: change registration prototype
  2017-07-05 14:22   ` [PATCH v2 00/05] " Pat Riehecky
                       ` (2 preceding siblings ...)
  2017-07-05 14:22     ` [PATCH v2 03/05] drivers/fmc: The only way to dump the SDB is from debugfs Pat Riehecky
@ 2017-07-05 14:22     ` Pat Riehecky
  2017-07-05 14:22     ` [PATCH v2 05/05] drivers/fmc: carrier can program FPGA on registration Pat Riehecky
  4 siblings, 0 replies; 16+ messages in thread
From: Pat Riehecky @ 2017-07-05 14:22 UTC (permalink / raw)
  To: linux-kernel; +Cc: rubini, federico.vaga, gregkh, drivers_other, Pat Riehecky

Permit use of either fmc_device_register_n or fmc_device_register_n_gw
depending on the type of device in use.

From: Federico Vaga <federico.vaga@cern.ch>
Signed-off-by: Federico Vaga <federico.vaga@cern.ch>
Tested-by: Pat Riehecky <riehecky@fnal.gov>
---
 drivers/fmc/fmc-core.c          | 15 ++++++++++++++-
 include/linux/fmc.h | 13 +++++++++++--
 2 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/drivers/fmc/fmc-core.c b/drivers/fmc/fmc-core.c
index 50e18ba..be411e3 100644
--- a/drivers/fmc/fmc-core.c
+++ b/drivers/fmc/fmc-core.c
@@ -199,7 +199,8 @@ 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(struct fmc_device **devs, int n)
+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;
@@ -313,8 +314,20 @@ out:
 	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);
diff --git a/include/linux/fmc.h b/include/linux/fmc.h
index 5c8df0c..b6c73d5 100644
--- a/include/linux/fmc.h
+++ b/include/linux/fmc.h
@@ -220,14 +220,23 @@ static inline void fmc_set_drvdata(struct fmc_device *fmc, void *data)
 	dev_set_drvdata(&fmc->dev, data);
 }

-/* The 4 access points */
+struct fmc_gateware {
+	void *bitstream;
+	unsigned long len;
+};
+
+/* The 5 access points */
 extern int fmc_driver_register(struct fmc_driver *drv);
 extern void fmc_driver_unregister(struct fmc_driver *drv);
 extern int fmc_device_register(struct fmc_device *tdev);
+extern int fmc_device_register_gw(struct fmc_device *tdev,
+				  struct fmc_gateware *gw);
 extern void fmc_device_unregister(struct fmc_device *tdev);

-/* Two more for device sets, all driven by the same FPGA */
+/* Three more for device sets, all driven by the same FPGA */
 extern int fmc_device_register_n(struct fmc_device **devs, int n);
+extern int fmc_device_register_n_gw(struct fmc_device **devs, int n,
+				    struct fmc_gateware *gw);
 extern void fmc_device_unregister_n(struct fmc_device **devs, int n);

 /* Internal cross-calls between files; not exported to other modules */
--
1.8.3.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v2 05/05] drivers/fmc: carrier can program FPGA on registration
  2017-07-05 14:22   ` [PATCH v2 00/05] " Pat Riehecky
                       ` (3 preceding siblings ...)
  2017-07-05 14:22     ` [PATCH v2 04/05] drivers/fmc: change registration prototype Pat Riehecky
@ 2017-07-05 14:22     ` Pat Riehecky
  2017-07-17 14:30       ` Greg KH
  2017-07-17 14:33       ` Alessandro Rubini
  4 siblings, 2 replies; 16+ messages in thread
From: Pat Riehecky @ 2017-07-05 14:22 UTC (permalink / raw)
  To: linux-kernel; +Cc: rubini, federico.vaga, gregkh, drivers_other, Pat Riehecky

The initial FPGA may require programming before it is useful.

From: Federico Vaga <federico.vaga@cern.ch>
Signed-off-by: Federico Vaga <federico.vaga@cern.ch>
Tested-by: Pat Riehecky <riehecky@fnal.gov>
---
 drivers/fmc/fmc-core.c | 18 +++++++++++++++---
 drivers/fmc/fmc-sdb.c  | 24 ++++++++++++++++++++++++
 include/linux/fmc.h    |  4 ++++
 3 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/drivers/fmc/fmc-core.c b/drivers/fmc/fmc-core.c
index eabeac0..cec3b8d 100644
--- a/drivers/fmc/fmc-core.c
+++ b/drivers/fmc/fmc-core.c
@@ -280,6 +280,21 @@ int fmc_device_register_n_gw(struct fmc_device **devs, int n,
 		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 "
@@ -300,9 +315,6 @@ int fmc_device_register_n_gw(struct fmc_device **devs, int n,
 out1:
 	device_del(&fmc->dev);
 out:
-	fmc_free_id_info(fmc);
-	put_device(&fmc->dev);
-
 	kfree(devarray);
 	for (i--; i >= 0; i--) {
 		fmc_debug_exit(devs[i]);
diff --git a/drivers/fmc/fmc-sdb.c b/drivers/fmc/fmc-sdb.c
index 89e37a6..ffdc176 100644
--- a/drivers/fmc/fmc-sdb.c
+++ b/drivers/fmc/fmc-sdb.c
@@ -127,6 +127,30 @@ int fmc_free_sdb_tree(struct fmc_device *fmc)
 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)
 {
diff --git a/include/linux/fmc.h b/include/linux/fmc.h
index b6c73d5..3dc8a1b 100644
--- a/include/linux/fmc.h
+++ b/include/linux/fmc.h
@@ -132,6 +132,8 @@ struct fmc_operations {
 	uint32_t (*read32)(struct fmc_device *fmc, int offset);
 	void (*write32)(struct fmc_device *fmc, uint32_t value, int offset);
 	int (*validate)(struct fmc_device *fmc, struct fmc_driver *drv);
+	int (*reprogram_raw)(struct fmc_device *f, struct fmc_driver *d,
+			     void *gw, unsigned long len);
 	int (*reprogram)(struct fmc_device *f, struct fmc_driver *d, char *gw);
 	int (*irq_request)(struct fmc_device *fmc, irq_handler_t h,
 			   char *name, int flags);
@@ -144,6 +146,8 @@ struct fmc_operations {
 };

 /* Prefer this helper rather than calling of fmc->reprogram directly */
+int fmc_reprogram_raw(struct fmc_device *fmc, struct fmc_driver *d,
+		      void *gw, unsigned long len, int sdb_entry);
 extern int fmc_reprogram(struct fmc_device *f, struct fmc_driver *d, char *gw,
 		     int sdb_entry);

--
1.8.3.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 01/05] drivers/fmc: remove unused variable
  2017-07-05 14:22     ` [PATCH v2 01/05] drivers/fmc: remove unused variable Pat Riehecky
@ 2017-07-17 14:29       ` Greg KH
  0 siblings, 0 replies; 16+ messages in thread
From: Greg KH @ 2017-07-17 14:29 UTC (permalink / raw)
  To: Pat Riehecky; +Cc: linux-kernel, rubini, federico.vaga, drivers_other

On Wed, Jul 05, 2017 at 09:22:06AM -0500, Pat Riehecky wrote:
> From: Federico Vaga <federico.vaga@cern.ch>
> Signed-off-by: Federico Vaga <federico.vaga@cern.ch>
> Tested-by: Pat Riehecky <riehecky@fnal.gov>
> ---
>  drivers/fmc/fru-parse.c | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)

I will not accept patches with no changelog comments, sorry.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 05/05] drivers/fmc: carrier can program FPGA on registration
  2017-07-05 14:22     ` [PATCH v2 05/05] drivers/fmc: carrier can program FPGA on registration Pat Riehecky
@ 2017-07-17 14:30       ` Greg KH
  2017-07-17 14:33       ` Alessandro Rubini
  1 sibling, 0 replies; 16+ messages in thread
From: Greg KH @ 2017-07-17 14:30 UTC (permalink / raw)
  To: Pat Riehecky; +Cc: linux-kernel, rubini, federico.vaga, drivers_other

On Wed, Jul 05, 2017 at 09:22:10AM -0500, Pat Riehecky wrote:
> The initial FPGA may require programming before it is useful.
> 
> From: Federico Vaga <federico.vaga@cern.ch>
> Signed-off-by: Federico Vaga <federico.vaga@cern.ch>
> Tested-by: Pat Riehecky <riehecky@fnal.gov>
> ---

This is not how the "From:" line works, please read SubmittingPatches
for the correct usage...

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2 05/05] drivers/fmc: carrier can program FPGA on registration
  2017-07-05 14:22     ` [PATCH v2 05/05] drivers/fmc: carrier can program FPGA on registration Pat Riehecky
  2017-07-17 14:30       ` Greg KH
@ 2017-07-17 14:33       ` Alessandro Rubini
  1 sibling, 0 replies; 16+ messages in thread
From: Alessandro Rubini @ 2017-07-17 14:33 UTC (permalink / raw)
  To: gregkh; +Cc: riehecky, linux-kernel, federico.vaga, drivers_other

> This is not how the "From:" line works, please read SubmittingPatches
> for the correct usage...

I'm submitting V3 with the correct From line, and my acked-by, since
now I managed to actually test them. It will happen later today.

Thanks greg for considering the patches.

/alessandro

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2017-07-17 14:33 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-30 16:15 [PATCH 0/5] Update kernel to latest FMC bus release Pat Riehecky
2017-06-30 16:15 ` [PATCH 1/5] drivers/fmc: remove unused variable Pat Riehecky
2017-06-30 16:15 ` [PATCH 2/5] drivers/fmc: hide fmc operations behind helpers Pat Riehecky
2017-06-30 16:15 ` [PATCH 3/5] drivers/fmc: The only way to dump the SDB is from debugfs Pat Riehecky
2017-06-30 16:15 ` [PATCH 4/5] drivers/fmc: change registration prototype Pat Riehecky
2017-06-30 16:15 ` [PATCH 5/5] drivers/fmc: carrier can program FPGA on registration Pat Riehecky
2017-07-05 10:27 ` [PATCH 0/5] Update kernel to latest FMC bus release Alessandro Rubini
2017-07-05 14:22   ` [PATCH v2 00/05] " Pat Riehecky
2017-07-05 14:22     ` [PATCH v2 01/05] drivers/fmc: remove unused variable Pat Riehecky
2017-07-17 14:29       ` Greg KH
2017-07-05 14:22     ` [PATCH v2 02/05] drivers/fmc: hide fmc operations behind helpers Pat Riehecky
2017-07-05 14:22     ` [PATCH v2 03/05] drivers/fmc: The only way to dump the SDB is from debugfs Pat Riehecky
2017-07-05 14:22     ` [PATCH v2 04/05] drivers/fmc: change registration prototype Pat Riehecky
2017-07-05 14:22     ` [PATCH v2 05/05] drivers/fmc: carrier can program FPGA on registration Pat Riehecky
2017-07-17 14:30       ` Greg KH
2017-07-17 14:33       ` Alessandro Rubini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.