From c68dc8d45b3145942d6c7000cd3b9c504604ea10 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Sjur=20Br=C3=A6ndeland?= Date: Tue, 22 Jan 2013 10:54:19 +0100 Subject: [PATCH] remoteproc: Always perserve resource table data MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 --- drivers/remoteproc/remoteproc_core.c | 61 +++++++++++++++++++++++----- include/linux/remoteproc.h | 3 ++ 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 #include #include +#include /** * 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 */ -- 2.39.5