From b0353f9f87a43c592da5ddd9e79bbacc68799ed7 Mon Sep 17 00:00:00 2001
From: Alessandro Rubini <rubini@gnudd.com>
Date: Wed, 25 Jul 2012 00:46:44 +0200
Subject: [PATCH] added reprogram method, with some shake up

---
 kernel/spec-fmc.c |  9 ++++++++-
 kernel/spec-pci.c | 44 ++++++++++++++++++++++++--------------------
 kernel/spec.h     |  3 +++
 3 files changed, 35 insertions(+), 21 deletions(-)

diff --git a/kernel/spec-fmc.c b/kernel/spec-fmc.c
index 684f963..62bf7ba 100644
--- a/kernel/spec-fmc.c
+++ b/kernel/spec-fmc.c
@@ -18,6 +18,13 @@ module_param_named(test_irq, spec_test_irq, int, 0444);
 
 /* The main role of this file is offering the fmc_operations for the spec */
 
+static int spec_reprogram(struct fmc_device *fmc, void *data, int len)
+{
+	struct spec_dev *spec = fmc->carrier_data;
+
+	return spec_load_fpga(spec, data, len); /* spec-pci.c */
+}
+
 static int spec_irq_request(struct fmc_device *fmc, irq_handler_t handler,
 			    char *name, int flags)
 {
@@ -86,7 +93,7 @@ static int spec_write_ee(struct fmc_device *fmc, int pos,
 
 static struct fmc_operations spec_fmc_operations = {
 	/* no readl/writel because we have the base pointer */
-	/* FIXME: reprogram */
+	.reprogram =		spec_reprogram,
 	.irq_request =		spec_irq_request,
 	.irq_ack =		spec_irq_ack,
 	.irq_free =		spec_irq_free,
diff --git a/kernel/spec-pci.c b/kernel/spec-pci.c
index 9feee95..f82c692 100644
--- a/kernel/spec-pci.c
+++ b/kernel/spec-pci.c
@@ -28,25 +28,15 @@ static char *spec_fw_name = "fmc/spec-init.bin";
 module_param_named(fw_name, spec_fw_name, charp, 0444);
 
 /* Load the FPGA. This bases on loader-ll.c, a kernel/user space thing */
-static int spec_load_fpga(struct spec_dev *spec)
+int spec_load_fpga(struct spec_dev *spec, const void *data, int size)
 {
-	const struct firmware *fw;
 	struct device *dev = &spec->pdev->dev;
+	int i, wrote;
 	unsigned long j;
-	int i, err = 0, wrote;
-	char *name = spec_fw_name; /* FIXME: temporary hack */
-
-	err = request_firmware(&fw, name, dev);
-	if (err < 0) {
-		dev_err(dev, "request firmware \"%s\": error %i\n", name, err);
-		return err;
-	}
-	dev_info(dev, "got file \"%s\", %i (0x%x) bytes\n",
-		 spec_fw_name, fw->size, fw->size);
 
 	/* loader_low_level is designed to run from user space too */
 	wrote = loader_low_level(0 /* unused fd */,
-				 spec->remap[2], fw->data, fw->size);
+				 spec->remap[2], data, size);
 	j = jiffies + 2 * HZ;
 	/* Wait for DONE interrupt  */
 	while(1) {
@@ -54,23 +44,37 @@ static int spec_load_fpga(struct spec_dev *spec)
 		i = readl(spec->remap[2] + FCL_IRQ);
 		if (i & 0x8) {
 			dev_info(dev, "FPGA programming sucessful\n");
-			goto out;
+			return 0;
 		}
 
 		if(i & 0x4) {
 			dev_err(dev, "FPGA program error after %i writes\n",
 				wrote);
-			err = -ETIMEDOUT;
-			goto out;
+			return -ETIMEDOUT;
 		}
 
 		if (time_after(jiffies, j)) {
 			dev_err(dev, "FPGA timeout after %i writes\n", wrote);
-			err = -ETIMEDOUT;
-			goto out;
+			return -ETIMEDOUT;
 		}
 	}
-out:
+}
+
+int spec_load_fpga_file(struct spec_dev *spec, char *name)
+{
+	struct device *dev = &spec->pdev->dev;
+	const struct firmware *fw;
+	int err = 0;
+
+	err = request_firmware(&fw, name, dev);
+	if (err < 0) {
+		dev_err(dev, "request firmware \"%s\": error %i\n", name, err);
+		return err;
+	}
+	dev_info(dev, "got file \"%s\", %i (0x%x) bytes\n",
+		 spec_fw_name, fw->size, fw->size);
+
+	err = spec_load_fpga(spec, fw->data, fw->size);
 	release_firmware(fw);
         return err;
 }
@@ -114,7 +118,7 @@ static int __devinit spec_probe(struct pci_dev *pdev,
 
 
 	/* Load the golden FPGA binary to read the eeprom */
-	ret = spec_load_fpga(spec);
+	ret = spec_load_fpga_file(spec, spec_fw_name);
 	if (ret)
 		goto out_unmap;
 
diff --git a/kernel/spec.h b/kernel/spec.h
index c50a598..4304659 100644
--- a/kernel/spec.h
+++ b/kernel/spec.h
@@ -115,6 +115,9 @@ static inline void gennum_mask_val(struct spec_dev *spec,
 	gennum_writel(spec, v, reg);
 }
 
+/* Functions in spec-pci.c */
+extern int spec_load_fpga(struct spec_dev *spec, const void *data, int size);
+extern int spec_load_fpga_file(struct spec_dev *spec, char *name);
 
 /* Functions in spec-fmc.c, used by spec-pci.c */
 extern int spec_fmc_create(struct spec_dev *spec);
-- 
GitLab