summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSjur Brændeland <sjur.brandeland@stericsson.com>2013-01-22 10:54:19 +0100
committerSjur Brændeland <sjur@brendeland.net>2013-02-12 17:23:22 +0100
commitc68dc8d45b3145942d6c7000cd3b9c504604ea10 (patch)
tree8a6d573f6a3d44b86fd194361ab454facd84b9c1
parentc6567a9aebd6f4e3875bfb99c77932d5008f73a3 (diff)
remoteproc: Always perserve resource table data
Copy resource table from first to second firmware loading. After firmware is loaded to memory, update the vdevs resource pointer to the resource table kept in device memory. Signed-off-by: Sjur Brændeland <sjur.brandeland@stericsson.com>
-rw-r--r--drivers/remoteproc/remoteproc_core.c61
-rw-r--r--include/linux/remoteproc.h3
2 files changed, 53 insertions, 11 deletions
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 14f40eb03061..13dc7b49f760 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -694,17 +694,16 @@ static rproc_handle_resource_t rproc_handle_notifyid_rsc[RSC_LAST] = {
/* handle firmware resource entries before booting the remote processor */
static int
-rproc_handle_resource(struct rproc *rproc, struct resource_table *table,
- int len,
- rproc_handle_resource_t handlers[RSC_LAST])
+rproc_handle_resource(struct rproc *rproc, int len,
+ rproc_handle_resource_t handlers[RSC_LAST])
{
struct device *dev = &rproc->dev;
rproc_handle_resource_t handler;
int ret = 0, i;
- for (i = 0; i < table->num; i++) {
- int offset = table->offset[i];
- struct fw_rsc_hdr *hdr = (void *)table + offset;
+ for (i = 0; i < rproc->rsc->num; i++) {
+ int offset = rproc->rsc->offset[i];
+ struct fw_rsc_hdr *hdr = (void *)rproc->rsc + offset;
int avail = len - offset - sizeof(*hdr);
void *rsc = (void *)hdr + sizeof(*hdr);
@@ -783,9 +782,13 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
{
struct device *dev = &rproc->dev;
const char *name = rproc->firmware;
- struct resource_table *table;
+ struct rproc_vdev *rvdev;
+ struct resource_table *table, *devmem_rsc, *tmp;
int ret, tablesz;
+ if (!rproc->rsc)
+ return -ENOMEM;
+
ret = rproc_fw_sanity_check(rproc, fw);
if (ret)
return ret;
@@ -811,8 +814,17 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
goto clean_up;
}
+ /* Verify that resource table in loaded fw is unchanged */
+ if (rproc->rsc_csum != ip_compute_csum(table, tablesz)) {
+ dev_err(dev, "resource checksum failed, fw changed?\n");
+ ret = -EINVAL;
+ goto clean_up;
+ }
+
+
/* handle fw resources which are required to boot rproc */
- ret = rproc_handle_resource(rproc, table, tablesz, rproc_handle_rsc);
+ ret = rproc_handle_resource(rproc, tablesz,
+ rproc_handle_rsc);
if (ret) {
dev_err(dev, "Failed to process resources: %d\n", ret);
goto clean_up;
@@ -825,6 +837,26 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
goto clean_up;
}
+ /* Get the resource table address in device memory */
+ devmem_rsc = rproc_get_rsctab_addr(rproc, fw);
+
+ /* Copy the updated resource table to device memory */
+ memcpy(devmem_rsc, rproc->rsc, tablesz);
+
+ /* Free the copy of the resource table */
+ tmp = rproc->rsc;
+ rproc->rsc = devmem_rsc;
+ kfree(tmp);
+
+ /* Update the vdev rsc address */
+ list_for_each_entry(rvdev, &rproc->rvdevs, node) {
+ int offset = (void *)rvdev->rsc - (void *)tmp;
+ rvdev->rsc = (void *)devmem_rsc + offset;
+ }
+
+ /* Other virtio drivers will see the rsc table in device memory */
+ rproc->rsc = devmem_rsc;
+
/* power up the remote processor */
ret = rproc->ops->start(rproc);
if (ret) {
@@ -866,14 +898,21 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context)
if (!table)
goto out;
- rproc->max_notifyid = 0;
+ rproc->rsc_csum = ip_compute_csum(table, tablesz);
/* count the numbe of notify-ids */
- ret = rproc_handle_resource(rproc, table, tablesz,
+ rproc->max_notifyid = 0;
+ rproc->rsc = table;
+ ret = rproc_handle_resource(rproc, tablesz,
rproc_handle_notifyid_rsc);
+ /* Copy resource table containing vdev config info */
+ rproc->rsc = kmalloc(tablesz, GFP_KERNEL);
+ if (rproc->rsc)
+ memcpy(rproc->rsc, table, tablesz);
+
/* look for virtio devices and register them */
- ret = rproc_handle_resource(rproc, table, tablesz,
+ ret = rproc_handle_resource(rproc, tablesz,
rproc_handle_vdev_rsc);
if (ret)
goto out;
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index c0c363c7c3f1..07deff4982d0 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -41,6 +41,7 @@
#include <linux/virtio.h>
#include <linux/completion.h>
#include <linux/idr.h>
+#include <asm/checksum.h>
/**
* struct resource_table - firmware resource table header
@@ -429,6 +430,8 @@ struct rproc {
struct completion crash_comp;
bool recovery_disabled;
int max_notifyid;
+ struct resource_table *rsc;
+ __sum16 rsc_csum;
};
/* we currently support only two vrings per rvdev */