[RFC 5/6] remoteproc: Support custom firmware handlers

From: sjur . brandeland
Date: Tue May 22 2012 - 09:27:10 EST


From: Sjur BrÃndeland <sjur.brandeland@xxxxxxxxxxxxxx>

Make the firmware handling customizable by creating
a rproc_fw_ops structure. Expose the existing
Elf firmware handling in rproc_elf_fw_ops.

Signed-off-by: Sjur BrÃndeland <sjur.brandeland@xxxxxxxxxxxxxx>
---
drivers/remoteproc/omap_remoteproc.c | 1 +
drivers/remoteproc/remoteproc_core.c | 26 +++++++++++++++++---------
drivers/remoteproc/remoteproc_elf_loader.c | 11 +++++++++--
include/linux/remoteproc.h | 23 ++++++++++++++++++-----
4 files changed, 45 insertions(+), 16 deletions(-)

diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c
index 69425c4..53ceaab 100644
--- a/drivers/remoteproc/omap_remoteproc.c
+++ b/drivers/remoteproc/omap_remoteproc.c
@@ -171,6 +171,7 @@ static struct rproc_ops omap_rproc_ops = {
.start = omap_rproc_start,
.stop = omap_rproc_stop,
.kick = omap_rproc_kick,
+ .fw = &rproc_elf_fw_ops
};

static int __devinit omap_rproc_probe(struct platform_device *pdev)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 33384e6..75984ad 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -36,7 +36,6 @@
#include <linux/remoteproc.h>
#include <linux/iommu.h>
#include <linux/klist.h>
-#include <linux/elf.h>
#include <linux/virtio_ids.h>
#include <linux/virtio_ring.h>
#include <asm/byteorder.h>
@@ -781,12 +780,13 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
{
struct device *dev = rproc->dev;
const char *name = rproc->firmware;
- struct elf32_hdr *ehdr;
struct resource_table *table;
int ret, tablesz;

- ehdr = (struct elf32_hdr *)fw->data;
-
+ if (!rproc->ops->fw_ops || !try_module_get(rproc->ops->fw_ops->owner)) {
+ dev_err(dev, "%s: can't get fw_ops->owner\n", __func__);
+ ret = -EINVAL;
+ }
dev_info(dev, "Booting fw image %s, size %zd\n", name, fw->size);

/*
@@ -796,11 +796,11 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
ret = rproc_enable_iommu(rproc);
if (ret) {
dev_err(dev, "can't enable iommu: %d\n", ret);
- return ret;
+ goto out;
}

/* look for the resource table */
- table = rproc_find_rsc_table(rproc, fw, &tablesz);
+ table = rproc->ops->fw_ops->find_rsc_table(rproc, fw, &tablesz);
if (!table) {
ret = -EINVAL;
goto clean_up;
@@ -813,8 +813,8 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
goto clean_up;
}

- /* load the ELF segments to memory */
- ret = rproc_load_segments(rproc, fw);
+ /* load the firmware to memory */
+ ret = rproc->ops->fw_ops->load_fw(rproc, fw);
if (ret) {
dev_err(dev, "Failed to load program segments: %d\n", ret);
goto clean_up;
@@ -836,6 +836,8 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
clean_up:
rproc_resource_cleanup(rproc);
rproc_disable_iommu(rproc);
+out:
+ module_put(rproc->ops->fw_ops->owner);
return ret;
}

@@ -853,8 +855,13 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context)
struct resource_table *table;
int ret, tablesz;

+ if (!rproc->ops->fw_ops || !try_module_get(rproc->ops->fw_ops->owner)) {
+ dev_err(rproc->dev, "%s: can't get fw_ops->owner\n", __func__);
+ return;
+ }
+
/* look for the resource table */
- table = rproc_find_rsc_table(rproc, fw, &tablesz);
+ table = rproc->ops->fw_ops->find_rsc_table(rproc, fw, &tablesz);
if (!table)
goto out;

@@ -864,6 +871,7 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context)
goto out;

out:
+ module_put(rproc->ops->fw_ops->owner);
if (fw)
release_firmware(fw);
/* allow rproc_unregister() contexts, if any, to proceed */
diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
index 3a1ae83..b90aeff 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -117,7 +117,7 @@ rproc_fw_sanity_check(struct rproc *rproc, const struct firmware *fw)
* directly allocate memory for every segment/resource. This is not yet
* supported, though.
*/
-int
+static int
rproc_load_segments(struct rproc *rproc, const struct firmware *fw)
{
struct device *dev = rproc->dev;
@@ -198,7 +198,7 @@ rproc_load_segments(struct rproc *rproc, const struct firmware *fw)
* size into @tablesz. If a valid table isn't found, NULL is returned
* (and @tablesz isn't set).
*/
-struct resource_table *
+static struct resource_table *
rproc_find_rsc_table(struct rproc *rproc, const struct firmware *fw,
int *tablesz)
{
@@ -271,3 +271,10 @@ rproc_find_rsc_table(struct rproc *rproc, const struct firmware *fw,

return table;
}
+
+struct rproc_fw_ops rproc_elf_fw_ops = {
+ .load_fw = rproc_load_segments,
+ .find_rsc_table = rproc_find_rsc_table,
+ .owner = THIS_MODULE
+};
+EXPORT_SYMBOL(rproc_elf_fw_ops);
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 372d1a8..7ebb1ef 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -327,22 +327,33 @@ struct rproc_mem_entry {

struct rproc;

-int
-rproc_load_segments(struct rproc *rproc, const struct firmware *fw);
-struct resource_table *
-rproc_find_rsc_table(struct rproc *rproc, const struct firmware *fw,
- int *tablesz);
+/**
+ * struct rproc_fw_ops - firmware format specific operations.
+ * @find_rsc_table: finds the resource table inside the firmware image.
+ * @load_fw: load firmeware to memory, where the remote processor
+ * expects to find it.
+ * @owner: module owning the operations.
+ */
+struct rproc_fw_ops {
+ struct resource_table *(*find_rsc_table) (struct rproc *rproc,
+ const struct firmware *fw,
+ int *tablesz);
+ int (*load_fw)(struct rproc *rproc, const struct firmware *fw);
+ struct module *owner;
+};

/**
* struct rproc_ops - platform-specific device handlers
* @start: power on the device and boot it
* @stop: power off the device
* @kick: kick a virtqueue (virtqueue id given as a parameter)
+ * @fw_ops: firmware operations for the remote processor
*/
struct rproc_ops {
int (*start)(struct rproc *rproc);
int (*stop)(struct rproc *rproc);
void (*kick)(struct rproc *rproc, int vqid);
+ struct rproc_fw_ops *fw_ops;
};

/**
@@ -483,4 +494,6 @@ static inline struct rproc *vdev_to_rproc(struct virtio_device *vdev)
return rvdev->rproc;
}

+extern struct rproc_fw_ops rproc_elf_fw_ops;
+
#endif /* REMOTEPROC_H */
--
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/