Once this patch-set has been applied; platform-specific remoteproc
drivers will be able to amend existing resource table entries,
provide new entries to be appended to an existing resource table
(if one already exists), start a new resource table (if one does
not already exist), and dump out resource table contents during
development/debugging. It will also be possible to start remote
processors which do not require a resource table without being
forced to provide a fake one.
We're also taking the liberty to provide some simple fix-ups.
V2 is rebased on "auto-boot" series. It also includes following addons:
- associate an action to the resource request. This allows platform-specific
driver to verify firmware resources, update or append resources in firmware
resource table or create a local resource table.
- introduce spare resource to define room for resource table extension
- centralize resource table sanity checks.
V3 is rebased on remoteproc kernel 4.9 pull request. It integrates following
modifications:
- split patches per features
- fix Lee Jones's comments
- remove local resource management
Lee Jones (5):
remoteproc: core: New API to add new resources to the resource table
remoteproc: core: Add function to amend an existing resource table
entry
remoteproc: core: Add function to append a new resource table entry
remoteproc: core: Add function to over-ride current resource table
remoteproc: core: Support empty resource tables
Loic Pallardy (15):
remoteproc: core: Add function to dump resource table
remoteproc: core: Associate action to resource request
remoteproc: core: Add RSC_VDEV support to rproc_request_resource
remoteproc: core: Complete VDEV support in rproc_dump_resource_table
function
remoteproc: core: Unify rproc_dump_resource_table debug messages
remoteproc: core: Call rproc_dump_resource_table only if debug is
activated
remoteproc: core: Correction carveout name comparison in
rproc_update_resource_table_entry
remoteproc: core: Add function to verify an existing resource in rsc
table
remoteproc: core: Add vdev support to resource amending function
remoteproc: core: Add force mode to resource amending function
remoteproc: core: Append resource only if .resource_table section is
large enough
remoteproc: core: Add resource request action support
remoteproc: core: Add function to verify resource table consistency
remoteproc: core: Clean-up resource table sanity checks
remotecore: core: Add resource table pointer argument to
rproc_handle_resource
drivers/remoteproc/remoteproc_core.c | 575 ++++++++++++++++++++++++++++++++---
include/linux/remoteproc.h | 42 +++
2 files changed, 569 insertions(+), 48 deletions(-)
--
1.9.1
From: Lee Jones <[email protected]>
In order to amend or add a new resource table entry we need a method
for a platform-specific to submit them. rproc_request_resource() is a
new public API which provides this functionality.
It is to be called between rproc_alloc() and rproc_add().
Signed-off-by: Lee Jones <[email protected]>
Signed-off-by: Loic Pallardy <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 40 ++++++++++++++++++++++++++++++++++++
include/linux/remoteproc.h | 21 +++++++++++++++++++
2 files changed, 61 insertions(+)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index c6bfb349..67633ee 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -785,6 +785,45 @@ static void rproc_resource_cleanup(struct rproc *rproc)
rproc_remove_virtio_dev(rvdev);
}
+int rproc_request_resource(struct rproc *rproc, u32 type, void *resource)
+{
+ struct device *dev = &rproc->dev;
+ struct rproc_request_resource *request;
+ int size;
+
+ request = devm_kzalloc(dev, sizeof(*request), GFP_KERNEL);
+ if (!request)
+ return -ENOMEM;
+
+ switch (type) {
+ case RSC_CARVEOUT:
+ size = sizeof(struct fw_rsc_carveout);
+ break;
+ case RSC_DEVMEM:
+ size = sizeof(struct fw_rsc_devmem);
+ break;
+ case RSC_TRACE:
+ size = sizeof(struct fw_rsc_trace);
+ break;
+ default:
+ dev_err(dev, "Unsupported resource type: %d\n", type);
+ return -EINVAL;
+ }
+
+ request->resource = devm_kzalloc(dev, size, GFP_KERNEL);
+ if (!request->resource)
+ return -ENOMEM;
+
+ memcpy(request->resource, resource, size);
+ request->type = type;
+ request->size = size;
+
+ list_add_tail(&request->node, &rproc->override_resources);
+
+ return 0;
+}
+EXPORT_SYMBOL(rproc_request_resource);
+
/*
* take a firmware and boot a remote processor with it.
*/
@@ -1370,6 +1409,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
INIT_LIST_HEAD(&rproc->mappings);
INIT_LIST_HEAD(&rproc->traces);
INIT_LIST_HEAD(&rproc->rvdevs);
+ INIT_LIST_HEAD(&rproc->override_resources);
INIT_WORK(&rproc->crash_handler, rproc_crash_handler_work);
init_completion(&rproc->crash_comp);
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 930023b..dd29776 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -323,6 +323,25 @@ struct rproc_mem_entry {
struct list_head node;
};
+/**
+ * struct rproc_requested_resources - add a resource to the resource table
+ *
+ * @resource: pointer to a 'struct fw_rsc_*' resource
+ * @type: 'fw_resource_type' resource type
+ * @size: size of resource
+ * @node: list node
+ *
+ * Resources can be added by platform-specific rproc drivers calling
+ * rproc_request_resource()
+ *
+ */
+struct rproc_request_resource {
+ void *resource;
+ u32 type;
+ u32 size;
+ struct list_head node;
+};
+
struct rproc;
/**
@@ -428,6 +447,7 @@ struct rproc {
int num_traces;
struct list_head carveouts;
struct list_head mappings;
+ struct list_head override_resources;
struct completion firmware_loading_complete;
u32 bootaddr;
struct list_head rvdevs;
@@ -486,6 +506,7 @@ struct rproc_vdev {
u32 rsc_offset;
};
+int rproc_request_resource(struct rproc *rproc, u32 type, void *res);
struct rproc *rproc_get_by_phandle(phandle phandle);
struct rproc *rproc_alloc(struct device *dev, const char *name,
const struct rproc_ops *ops,
--
1.9.1
Firmware can be loaded with a resource table, which details
resources needed by coprocessor like carevout memory, virtual
device, trace log buffer etc.
Until now, no method exists to display resource table content.
This function adds the capability to display the different
resources associated to a firmware if DEBUG is enabled.
Signed-off-by: Lee Jones <[email protected]>
Signed-off-by: Loic Pallardy <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 85 ++++++++++++++++++++++++++++++++++++
1 file changed, 85 insertions(+)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 67633ee..3c8395b 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -785,6 +785,91 @@ static void rproc_resource_cleanup(struct rproc *rproc)
rproc_remove_virtio_dev(rvdev);
}
+static void rproc_dump_resource_table(struct rproc *rproc,
+ struct resource_table *table, int size)
+{
+ static const char *types[] = {"carveout", "devmem", "trace", "vdev"};
+ struct device *dev = &rproc->dev;
+ struct fw_rsc_carveout *c;
+ struct fw_rsc_devmem *d;
+ struct fw_rsc_trace *t;
+ struct fw_rsc_vdev *v;
+ int i, j;
+
+ if (!table) {
+ dev_dbg(dev, "No resource table found\n");
+ return;
+ }
+
+ dev_dbg(dev, "Resource Table: Version %d with %d entries [size: %x]\n",
+ table->ver, table->num, size);
+
+ for (i = 0; i < table->num; i++) {
+ int offset = table->offset[i];
+ struct fw_rsc_hdr *hdr = (void *)table + offset;
+ void *rsc = (void *)hdr + sizeof(*hdr);
+
+ switch (hdr->type) {
+ case RSC_CARVEOUT:
+ c = rsc;
+ dev_dbg(dev, "Entry %d is of type %s\n", i, types[hdr->type]);
+ dev_dbg(dev, " Device Address 0x%x\n", c->da);
+ dev_dbg(dev, " Physical Address 0x%x\n", c->pa);
+ dev_dbg(dev, " Length 0x%x Bytes\n", c->len);
+ dev_dbg(dev, " Flags 0x%x\n", c->flags);
+ dev_dbg(dev, " Reserved (should be zero) [%d]\n", c->reserved);
+ dev_dbg(dev, " Name %s\n\n", c->name);
+ break;
+ case RSC_DEVMEM:
+ d = rsc;
+ dev_dbg(dev, "Entry %d is of type %s\n", i, types[hdr->type]);
+ dev_dbg(dev, " Device Address 0x%x\n", d->da);
+ dev_dbg(dev, " Physical Address 0x%x\n", d->pa);
+ dev_dbg(dev, " Length 0x%x Bytes\n", d->len);
+ dev_dbg(dev, " Flags 0x%x\n", d->flags);
+ dev_dbg(dev, " Reserved (should be zero) [%d]\n", d->reserved);
+ dev_dbg(dev, " Name %s\n\n", d->name);
+ break;
+ case RSC_TRACE:
+ t = rsc;
+ dev_dbg(dev, "Entry %d is of type %s\n", i, types[hdr->type]);
+ dev_dbg(dev, " Device Address 0x%x\n", t->da);
+ dev_dbg(dev, " Length 0x%x Bytes\n", t->len);
+ dev_dbg(dev, " Reserved (should be zero) [%d]\n", t->reserved);
+ dev_dbg(dev, " Name %s\n\n", t->name);
+ break;
+ case RSC_VDEV:
+ v = rsc;
+ dev_dbg(dev, "Entry %d is of type %s\n", i, types[hdr->type]);
+
+ dev_dbg(dev, " ID %d\n", v->id);
+ dev_dbg(dev, " Notify ID %d\n", v->notifyid);
+ dev_dbg(dev, " Device features 0x%x\n", v->dfeatures);
+ dev_dbg(dev, " Guest features 0x%x\n", v->gfeatures);
+ dev_dbg(dev, " Config length 0x%x\n", v->config_len);
+ dev_dbg(dev, " Status 0x%x\n", v->status);
+ dev_dbg(dev, " Number of vrings %d\n", v->num_of_vrings);
+ dev_dbg(dev, " Reserved (should be zero) [%d][%d]\n\n",
+ v->reserved[0], v->reserved[1]);
+
+ for (j = 0; j < v->num_of_vrings; j++) {
+ dev_dbg(dev, " Vring %d\n", j);
+ dev_dbg(dev, " Device Address 0x%x\n", v->vring[j].da);
+ dev_dbg(dev, " Alignment %d\n", v->vring[j].align);
+ dev_dbg(dev, " Number of buffers %d\n", v->vring[j].num);
+ dev_dbg(dev, " Notify ID %d\n", v->vring[j].notifyid);
+ dev_dbg(dev, " Physical Address 0x%x\n\n",
+ v->vring[j].pa);
+ }
+ break;
+ default:
+ dev_dbg(dev, "Invalid resource type found: %d [hdr: %p]\n",
+ hdr->type, hdr);
+ return;
+ }
+ }
+}
+
int rproc_request_resource(struct rproc *rproc, u32 type, void *resource)
{
struct device *dev = &rproc->dev;
--
1.9.1
As resource table could be parsed several times, at different times,
to avoid sanity check duplication, let's introduce a new function
to verify the complete integrity of one resource table.
This new function is called before copying it in cache and
accessing it.
Signed-off-by: Loic Pallardy <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 70 ++++++++++++++++++++++++++++++++++++
1 file changed, 70 insertions(+)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 559a63b..849460e 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -785,6 +785,69 @@ static void rproc_resource_cleanup(struct rproc *rproc)
rproc_remove_virtio_dev(rvdev);
}
+static int rproc_resource_table_sanity_check(struct rproc *rproc,
+ struct resource_table *table_ptr, int len)
+{
+ struct device *dev = &rproc->dev;
+ int i;
+
+ if (len < sizeof(*table_ptr))
+ goto out;
+
+ for (i = 0; i < table_ptr->num; i++) {
+ int offset = table_ptr->offset[i];
+ struct fw_rsc_hdr *hdr = (void *)table_ptr + offset;
+ int avail = len - offset - sizeof(*hdr);
+ void *rsc = (void *)hdr + sizeof(*hdr);
+ struct fw_rsc_vdev *v;
+
+ /* Make sure table isn't truncated */
+ if (avail < 0)
+ goto out;
+
+ if (offset == FW_RSC_ADDR_ANY || offset == 0) {
+ dev_err(dev, "Entry %d: bad offset value %x\n", i, offset);
+ return -EINVAL;
+ }
+
+ dev_dbg(dev, "rsc: type %d\n", hdr->type);
+
+ switch (hdr->type) {
+ case RSC_CARVEOUT:
+ avail -= sizeof(struct fw_rsc_carveout);
+ break;
+ case RSC_DEVMEM:
+ avail -= sizeof(struct fw_rsc_devmem);
+ break;
+ case RSC_TRACE:
+ avail -= sizeof(struct fw_rsc_trace);
+ break;
+ case RSC_VDEV:
+ v = rsc;
+ avail -= sizeof(struct fw_rsc_vdev);
+ if (avail < 0)
+ goto out;
+
+ avail -= v->num_of_vrings * sizeof(struct fw_rsc_vdev_vring)
+ + v->config_len;
+ break;
+ default:
+ dev_err(&rproc->dev, "Unsupported resource type: %d\n",
+ hdr->type);
+ return -EINVAL;
+ }
+ if (avail < 0)
+ goto out;
+ }
+
+ return 0;
+
+out:
+ dev_err(dev, "Invalid resource table format\n");
+ dump_stack();
+ return -EINVAL;
+}
+
static void rproc_dump_resource_table(struct rproc *rproc,
struct resource_table *table, int size)
{
@@ -1246,6 +1309,13 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
goto clean_up;
}
+ /* Verify resource table consistency */
+ ret = rproc_resource_table_sanity_check(rproc, table, tablesz);
+ if (ret) {
+ dev_err(dev, "Failed to get valid resource table,%d\n", ret);
+ goto clean_up;
+ }
+
/*
* Create a copy of the resource table. When a virtio device starts
* and calls vring_new_virtqueue() the address of the allocated vring
--
1.9.1
From: Lee Jones <[email protected]>
A new function now exists to pull in and amend and existing resource
table entry. But what if we wish to provide a new resource? This
function provides functionality to append a brand new resource entry
onto the resource table. All complexity related to shuffling parts
of the table around, providing new offsets and incriminating number
of entries in the resource table's top-level header is taken care of
here.
Signed-off-by: Lee Jones <[email protected]>
Signed-off-by: Loic Pallardy <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 55 ++++++++++++++++++++++++++++++++++++
1 file changed, 55 insertions(+)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index c3830b4..3a26d4e 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -972,6 +972,61 @@ static int rproc_update_resource_table_entry(struct rproc *rproc,
return !updated;
}
+static struct resource_table*
+rproc_add_resource_table_entry(struct rproc *rproc,
+ struct rproc_request_resource *request,
+ struct resource_table *old_table, int *tablesz)
+{
+ struct resource_table *table;
+ struct fw_rsc_hdr h;
+ void *new_rsc_loc;
+ void *fw_header_loc;
+ void *start_of_rscs;
+ int new_rsc_offset;
+ int size = *tablesz;
+ int i;
+
+ h.type = request->type;
+
+ new_rsc_offset = size;
+
+ /*
+ * Allocate another contiguous chunk of memory, large enough to
+ * contain the new, expanded resource table.
+ *
+ * The +4 is for the extra offset[] element in the top level header
+ */
+ size += sizeof(struct fw_rsc_hdr) + request->size + 4;
+ table = devm_kmemdup(&rproc->dev, old_table, size, GFP_KERNEL);
+ if (!table)
+ return ERR_PTR(-ENOMEM);
+
+ /* Shunt table by 4 Bytes to account for the extra offset[] element */
+ start_of_rscs = (void *)table + table->offset[0];
+ memmove(start_of_rscs + 4,
+ start_of_rscs, new_rsc_offset - table->offset[0]);
+ new_rsc_offset += 4;
+
+ /* Update existing resource entry's offsets */
+ for (i = 0; i < table->num; i++)
+ table->offset[i] += 4;
+
+ /* Update the top level 'resource table' header */
+ table->offset[table->num] = new_rsc_offset;
+ table->num++;
+
+ /* Copy new firmware header into table */
+ fw_header_loc = (void *)table + new_rsc_offset;
+ memcpy(fw_header_loc, &h, sizeof(h));
+
+ /* Copy new resource entry into table */
+ new_rsc_loc = (void *)fw_header_loc + sizeof(h);
+ memcpy(new_rsc_loc, request->resource, request->size);
+
+ *tablesz = size;
+ return table;
+}
+
/*
* take a firmware and boot a remote processor with it.
*/
--
1.9.1
From: Lee Jones <[email protected]>
Sometimes the firmware does not know best.
When a firmware is built, it can be loaded with a resource table, usually
detailing shared; memory, virtual device, trace log information etc.
However, some vendors require this hard-coded information to be amended
with new/improved information obtained from Device Tree for instance.
Until now, no method exists which allows the resource table to be amended.
The addition of this function changes that. It is now possible to pull in
a resource table and amend it before it is finally shared with the remote
device.
Signed-off-by: Lee Jones <[email protected]>
Signed-off-by: Loic Pallardy <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 63 ++++++++++++++++++++++++++++++++++++
1 file changed, 63 insertions(+)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 3c8395b..c3830b4 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -909,6 +909,69 @@ int rproc_request_resource(struct rproc *rproc, u32 type, void *resource)
}
EXPORT_SYMBOL(rproc_request_resource);
+static int rproc_update_resource_table_entry(struct rproc *rproc,
+ struct rproc_request_resource *request,
+ struct resource_table *table, int size)
+{
+ struct fw_rsc_carveout *tblc, *newc;
+ struct fw_rsc_devmem *tbld, *newd;
+ struct fw_rsc_trace *tblt, *newt;
+ int updated = true;
+ int i;
+
+ for (i = 0; i < table->num; i++) {
+ int offset = table->offset[i];
+ struct fw_rsc_hdr *hdr = (void *)table + offset;
+ void *rsc = (void *)hdr + sizeof(*hdr);
+
+ if (request->type != hdr->type)
+ continue;
+
+ switch (hdr->type) {
+ case RSC_CARVEOUT:
+ tblc = rsc;
+ newc = request->resource;
+
+ if (strncmp(newc->name, tblc->name,
+ sizeof(*tblc->name)))
+ break;
+
+ memcpy(tblc, newc, request->size);
+
+ return updated;
+ case RSC_DEVMEM:
+ tbld = rsc;
+ newd = request->resource;
+
+ if (strncmp(newd->name, tbld->name,
+ sizeof(*tbld->name)))
+ break;
+
+ memcpy(tbld, newd, request->size);
+
+ return updated;
+ case RSC_TRACE:
+ tblt = rsc;
+ newt = request->resource;
+
+ if (strncmp(newt->name, tblt->name,
+ sizeof(*tblt->name)))
+ break;
+
+ memcpy(tblt, newt, request->size);
+
+ return updated;
+ default:
+ dev_err(&rproc->dev,
+ "Unsupported resource type: %d\n",
+ hdr->type);
+ return -EINVAL;
+ }
+ }
+
+ return !updated;
+}
+
/*
* take a firmware and boot a remote processor with it.
*/
--
1.9.1
From: Lee Jones <[email protected]>
Currently, when a remote processor does not require resources, the
platform-specific remoteproc driver has to create a fake resource
table in order to by-pass the strict checking. But there is no hard
requirement for a remote processor so require or support shared
resources. This patch removes the strict checking and skips
resource table related operations if none is provided.
Signed-off-by: Lee Jones <[email protected]>
Signed-off-by: Loic Pallardy <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index a6062e7..f83109d 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -679,6 +679,9 @@ static int rproc_handle_resources(struct rproc *rproc, struct resource_table *ta
rproc_handle_resource_t handler;
int ret = 0, i;
+ if (!table_ptr)
+ return ret;
+
for (i = 0; i < table_ptr->num; i++) {
int offset = table_ptr->offset[i];
struct fw_rsc_hdr *hdr = (void *)table_ptr + offset;
@@ -1272,8 +1275,8 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
/* look for the resource table */
table = rproc_find_rsc_table(rproc, fw, &tablesz);
if (!table) {
- dev_err(dev, "Failed to find resource table\n");
- goto clean_up;
+ rproc->cached_table = table;
+ goto skip_resources;
}
/* Verify resource table consistency */
@@ -1293,6 +1296,7 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
if (!rproc->cached_table)
goto clean_up;
+skip_resources:
rproc->table_ptr = rproc->cached_table;
if (!list_empty(&rproc->override_resources)) {
--
1.9.1
Add the possibility for platform specific driver to submit resource
request related to VDEV.
Signed-off-by: Loic Pallardy <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 4c6314e..ce62546 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -874,6 +874,7 @@ int rproc_request_resource(struct rproc *rproc, u32 type, u32 action, void *reso
{
struct device *dev = &rproc->dev;
struct rproc_request_resource *request;
+ struct fw_rsc_vdev *v;
int size;
request = devm_kzalloc(dev, sizeof(*request), GFP_KERNEL);
@@ -893,6 +894,12 @@ int rproc_request_resource(struct rproc *rproc, u32 type, u32 action, void *reso
case RSC_TRACE:
size = sizeof(struct fw_rsc_trace);
break;
+ case RSC_VDEV:
+ v = resource;
+ size = sizeof(struct fw_rsc_vdev);
+ size += v->num_of_vrings * sizeof(struct fw_rsc_vdev_vring);
+ size += v->config_len;
+ break;
default:
dev_err(dev, "Unsupported resource type: %d\n", type);
return -EINVAL;
--
1.9.1
Add dump of cfg field of vdev struct.
Signed-off-by: Loic Pallardy <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index ce62546..ae8e934 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -808,6 +808,8 @@ static void rproc_dump_resource_table(struct rproc *rproc,
int offset = table->offset[i];
struct fw_rsc_hdr *hdr = (void *)table + offset;
void *rsc = (void *)hdr + sizeof(*hdr);
+ unsigned char *cfg;
+ int len;
switch (hdr->type) {
case RSC_CARVEOUT:
@@ -861,6 +863,17 @@ static void rproc_dump_resource_table(struct rproc *rproc,
dev_dbg(dev, " Physical Address 0x%x\n\n",
v->vring[j].pa);
}
+
+ dev_dbg(dev, " Config table\n");
+ cfg = (unsigned char *)(&v->vring[v->num_of_vrings]);
+ len = 0;
+ do {
+ j = min(16, (int)(v->config_len - len));
+ dev_dbg(dev, " Config[%2d-%2d] = %*phC\n",
+ len, len + j - 1, j, cfg + len);
+ len += j;
+ } while (len < v->config_len);
+
break;
default:
dev_dbg(dev, "Invalid resource type found: %d [hdr: %p]\n",
--
1.9.1
To reduce CPU usage, limit rproc_dump_resource_table calls only when
DEBUG or CONFIG_DYNAMIC_DEBUG flags are activated.
Signed-off-by: Loic Pallardy <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 7bc3cd4..4a61dc1 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -1066,7 +1066,8 @@ rproc_apply_resource_overrides(struct rproc *rproc,
}
- rproc_dump_resource_table(rproc, table, size);
+ if (IS_ENABLED(DEBUG) || IS_ENABLED(CONFIG_DYNAMIC_DEBUG))
+ rproc_dump_resource_table(rproc, table, size);
if (!table) {
size = sizeof(*table);
@@ -1100,7 +1101,8 @@ rproc_apply_resource_overrides(struct rproc *rproc,
*orig_table = table;
}
- rproc_dump_resource_table(rproc, table, size);
+ if (IS_ENABLED(DEBUG) || IS_ENABLED(CONFIG_DYNAMIC_DEBUG))
+ rproc_dump_resource_table(rproc, table, size);
*tablesz = size;
--
1.9.1
For coherency with the rest of the function, mention the resource
table entry when an invalid resource is detected.
Signed-off-by: Loic Pallardy <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index ae8e934..7bc3cd4 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -876,8 +876,8 @@ static void rproc_dump_resource_table(struct rproc *rproc,
break;
default:
- dev_dbg(dev, "Invalid resource type found: %d [hdr: %p]\n",
- hdr->type, hdr);
+ dev_dbg(dev, "Entry %d: Invalid resource type found: %d [hdr: %p]\n",
+ i, hdr->type, hdr);
return;
}
}
--
1.9.1
When a firmware is build, it can be loaded with a resource
usually detailing shared; memory, virtual device, trace log
information etc.
However, some SoCs or platforms require some hard-coded information.
Information may be fixed on both sides: firmware and rproc.
Until now, no method exists which allows to compare resource table
fixed resources and rproc driver configuration.
This new function changes that performing comparison between resources.
Only carveout resource supported for the moment.
It is rproc driver responsibility to provide list of resources to
verify during boot.
Signed-off-by: Loic Pallardy <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 45 ++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 96692c2..4297ee7 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -933,6 +933,51 @@ int rproc_request_resource(struct rproc *rproc, u32 type, u32 action, void *reso
}
EXPORT_SYMBOL(rproc_request_resource);
+static int rproc_verify_resource_table_entry(struct rproc *rproc,
+ struct rproc_request_resource *request,
+ struct resource_table *table, int size)
+{
+ struct fw_rsc_carveout *tblc, *newc;
+ int i;
+
+ for (i = 0; i < table->num; i++) {
+ int offset = table->offset[i];
+ struct fw_rsc_hdr *hdr = (void *)table + offset;
+ void *rsc = (void *)hdr + sizeof(*hdr);
+
+ if (request->type != hdr->type)
+ continue;
+
+ switch (hdr->type) {
+ case RSC_CARVEOUT:
+ tblc = rsc;
+ newc = request->resource;
+
+ if (strncmp(newc->name, tblc->name, 32))
+ break;
+
+ /* Verify firmware resource is part of rproc one. */
+ if (tblc->pa != FW_RSC_ADDR_ANY) {
+ int pa_offset = tblc->pa - newc->pa;
+
+ if (pa_offset < 0)
+ return -EINVAL;
+
+ if (pa_offset + tblc->len > newc->len)
+ return -EINVAL;
+ }
+ return 0;
+ default:
+ dev_err(&rproc->dev,
+ "Unsupported resource type: %d\n",
+ hdr->type);
+ return -EINVAL;
+ }
+ }
+
+ return -EINVAL;
+}
+
static int rproc_update_resource_table_entry(struct rproc *rproc,
struct rproc_request_resource *request,
struct resource_table *table, int size)
--
1.9.1
This patch adds force mode to rproc_update_resource_table_entry function.
When force is unset, resource will be updated only if no specific
addresses are requested by firmware.
When force is set, resource is directly overwritten.
Signed-off-by: Loic Pallardy <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 26fc647..3847fd4 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -980,7 +980,8 @@ static int rproc_verify_resource_table_entry(struct rproc *rproc,
static int rproc_update_resource_table_entry(struct rproc *rproc,
struct rproc_request_resource *request,
- struct resource_table *table, int size)
+ struct resource_table *table, int size,
+ bool force)
{
struct fw_rsc_carveout *tblc, *newc;
struct fw_rsc_devmem *tbld, *newd;
@@ -1005,7 +1006,8 @@ static int rproc_update_resource_table_entry(struct rproc *rproc,
if (strncmp(newc->name, tblc->name, 32))
break;
- memcpy(tblc, newc, request->size);
+ if (tblc->pa == FW_RSC_ADDR_ANY || force)
+ memcpy(tblc, newc, request->size);
return updated;
case RSC_DEVMEM:
@@ -1143,7 +1145,7 @@ rproc_apply_resource_overrides(struct rproc *rproc,
/* If we already have a table, update it with the new values. */
updated = rproc_update_resource_table_entry(rproc, resource,
- table, size);
+ table, size, false);
if (updated < 0) {
table = ERR_PTR(updated);
goto out;
--
1.9.1
As old and new carveout name length may be different and the two
names may have a common part, name comparison must cover the complete
name field.
Limit strncmp to carveout name length, i.e. 32 Bytes.
Signed-off-by: Loic Pallardy <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 4a61dc1..96692c2 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -956,8 +956,7 @@ static int rproc_update_resource_table_entry(struct rproc *rproc,
tblc = rsc;
newc = request->resource;
- if (strncmp(newc->name, tblc->name,
- sizeof(*tblc->name)))
+ if (strncmp(newc->name, tblc->name, 32))
break;
memcpy(tblc, newc, request->size);
--
1.9.1
To guarantee remoteproc won't overwrite firmware data when copying
back modified resource table, rproc_add_resource_table_entry verifies
first that .resource_table elf section is large enough to support new
resource appending.
Signed-off-by: Loic Pallardy <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 81 +++++++++++++++++++++++++-----------
1 file changed, 56 insertions(+), 25 deletions(-)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 3847fd4..f4a02f0 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -1057,39 +1057,73 @@ static int rproc_update_resource_table_entry(struct rproc *rproc,
return !updated;
}
-static struct resource_table*
-rproc_add_resource_table_entry(struct rproc *rproc,
+static int rproc_add_resource_table_entry(struct rproc *rproc,
struct rproc_request_resource *request,
- struct resource_table *old_table, int *tablesz)
+ struct resource_table *table, int tablesz)
{
- struct resource_table *table;
- struct fw_rsc_hdr h;
+ struct fw_rsc_hdr *hdr, h;
void *new_rsc_loc;
void *fw_header_loc;
void *start_of_rscs;
int new_rsc_offset;
- int size = *tablesz;
- int i;
+ struct fw_rsc_vdev *v;
+ int i, spare_len = 0, size;
+ unsigned int min_offset, max_offset = 0;
+
h.type = request->type;
- new_rsc_offset = size;
+ /* Check available spare size to integrate new resource */
+ for (i = 0; i < table->num; i++)
+ max_offset = max(max_offset, table->offset[i]);
+
+ hdr = (void *)table + max_offset;
+
+ switch (hdr->type) {
+ case RSC_CARVEOUT:
+ size = sizeof(struct fw_rsc_carveout);
+ break;
+ case RSC_DEVMEM:
+ size = sizeof(struct fw_rsc_devmem);
+ break;
+ case RSC_TRACE:
+ size = sizeof(struct fw_rsc_trace);
+ break;
+ case RSC_VDEV:
+ v = (void *)hdr + sizeof(*hdr);
+ size = sizeof(*v);
+ size += v->num_of_vrings * sizeof(struct fw_rsc_vdev_vring);
+ size += v->config_len;
+ break;
+ default:
+ dev_err(&rproc->dev, "Unsupported resource type: %d\n",
+ hdr->type);
+ return -EINVAL;
+ }
+
+ new_rsc_offset = max_offset + size;
+ spare_len = tablesz - new_rsc_offset;
/*
- * Allocate another contiguous chunk of memory, large enough to
- * contain the new, expanded resource table.
- *
- * The +4 is for the extra offset[] element in the top level header
+ * Available space must be greater or equal to :
+ * new offset entry size (4Bytes)
+ * + resource header size
+ * + new resource size
*/
- size += sizeof(struct fw_rsc_hdr) + request->size + 4;
- table = devm_kmemdup(&rproc->dev, old_table, size, GFP_KERNEL);
- if (!table)
- return ERR_PTR(-ENOMEM);
+ if (spare_len < (4 + sizeof(h) + request->size))
+ return -ENOSPC;
+
+ /* Find the lowest resource table entry */
+ min_offset = table->offset[0];
+ for (i = 1; i < table->num; i++)
+ min_offset = min(min_offset, table->offset[i]);
+
/* Shunt table by 4 Bytes to account for the extra offset[] element */
- start_of_rscs = (void *)table + table->offset[0];
+ start_of_rscs = (void *)table + min_offset;
memmove(start_of_rscs + 4,
- start_of_rscs, new_rsc_offset - table->offset[0]);
+ start_of_rscs, new_rsc_offset - min_offset);
+
new_rsc_offset += 4;
/* Update existing resource entry's offsets */
@@ -1108,8 +1142,7 @@ rproc_add_resource_table_entry(struct rproc *rproc,
new_rsc_loc = (void *)fw_header_loc + sizeof(h);
memcpy(new_rsc_loc, request->resource, request->size);
- *tablesz = size;
- return table;
+ return 0;
}
static struct resource_table*
@@ -1154,12 +1187,10 @@ rproc_apply_resource_overrides(struct rproc *rproc,
continue;
/* Didn't find matching resource entry -- creating a new one. */
- table = rproc_add_resource_table_entry(rproc, resource,
- table, &size);
- if (IS_ERR(table))
+ updated = rproc_add_resource_table_entry(rproc, resource,
+ table, size);
+ if (updated)
goto out;
-
- *orig_table = table;
}
if (IS_ENABLED(DEBUG) || IS_ENABLED(CONFIG_DYNAMIC_DEBUG))
--
1.9.1
With new rproc_request_resource API, rproc driver has now the
capability to provide resources to remoteproc in order to modify
firmware resource table.
But in some cases, other operations are needed like compatibility
check between resources defined at firmware level and those handled
by rproc driver, or remoteproc local resource management when firmware
has no resource table.
This patch associates action to each resource request to:
- verify a resource
- update/amend a resource in firmware resource table
Signed-off-by: Loic Pallardy <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 6 +++++-
include/linux/remoteproc.h | 23 ++++++++++++++++++++++-
2 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 9bf48ba..4c6314e 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -870,7 +870,7 @@ static void rproc_dump_resource_table(struct rproc *rproc,
}
}
-int rproc_request_resource(struct rproc *rproc, u32 type, void *resource)
+int rproc_request_resource(struct rproc *rproc, u32 type, u32 action, void *resource)
{
struct device *dev = &rproc->dev;
struct rproc_request_resource *request;
@@ -880,6 +880,9 @@ int rproc_request_resource(struct rproc *rproc, u32 type, void *resource)
if (!request)
return -ENOMEM;
+ if (action >= RSC_ACT_LAST)
+ return -EINVAL;
+
switch (type) {
case RSC_CARVEOUT:
size = sizeof(struct fw_rsc_carveout);
@@ -902,6 +905,7 @@ int rproc_request_resource(struct rproc *rproc, u32 type, void *resource)
memcpy(request->resource, resource, size);
request->type = type;
request->size = size;
+ request->action = action;
list_add_tail(&request->node, &rproc->override_resources);
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index dd29776..760f29b 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -324,11 +324,31 @@ struct rproc_mem_entry {
};
/**
+ * enum rproc_request_action - types of actions associated to a resource
+ * request
+ *
+ * @RSC_ACT_CHECK: request to verify this resource with firmware one
+ * @RSC_ACT_UPDATE: request to update firmware resource table with associated
+ * resource if possible
+ * @RSC_ACT_FORCE_UPDATE: force firmware resource table update with associated
+ * resource
+ * @RSC_ACT_LAST: just keep this one at the end
+ *
+ */
+enum rproc_request_action {
+ RSC_ACT_VERIFY = 0,
+ RSC_ACT_UPDATE = 1,
+ RSC_ACT_FORCE_UPDATE = 2,
+ RSC_ACT_LAST = 3,
+};
+
+/**
* struct rproc_requested_resources - add a resource to the resource table
*
* @resource: pointer to a 'struct fw_rsc_*' resource
* @type: 'fw_resource_type' resource type
* @size: size of resource
+ * @action: action associated the resource
* @node: list node
*
* Resources can be added by platform-specific rproc drivers calling
@@ -339,6 +359,7 @@ struct rproc_request_resource {
void *resource;
u32 type;
u32 size;
+ u32 action;
struct list_head node;
};
@@ -506,7 +527,7 @@ struct rproc_vdev {
u32 rsc_offset;
};
-int rproc_request_resource(struct rproc *rproc, u32 type, void *res);
+int rproc_request_resource(struct rproc *rproc, u32 type, u32 action, void *res);
struct rproc *rproc_get_by_phandle(phandle phandle);
struct rproc *rproc_alloc(struct device *dev, const char *name,
const struct rproc_ops *ops,
--
1.9.1
From: Lee Jones <[email protected]>
Most of the new resource table handling function are now in place, so
it's time to put it all together. Once new resource table information
has been requested, the structures will be held in a holding pen until
boot-time. During boot-time rproc_apply_resource_overrides() will be
invoked which in turn will pull the new information out of the holding
pen and edit the table accordingly.
Signed-off-by: Lee Jones <[email protected]>
Signed-off-by: Loic Pallardy <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 63 ++++++++++++++++++++++++++++++++++++
1 file changed, 63 insertions(+)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 3a26d4e..9bf48ba 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -1027,6 +1027,63 @@ rproc_add_resource_table_entry(struct rproc *rproc,
return table;
}
+static struct resource_table*
+rproc_apply_resource_overrides(struct rproc *rproc,
+ struct resource_table **orig_table,
+ int *tablesz)
+{
+ struct rproc_request_resource *resource;
+ struct resource_table *table = *orig_table;
+ int size = *tablesz;
+
+ if (!table && size != 0) {
+ dev_err(&rproc->dev, "No table present but table size is set\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+
+ rproc_dump_resource_table(rproc, table, size);
+
+ if (!table) {
+ size = sizeof(*table);
+ table = devm_kzalloc(&rproc->dev, size, GFP_KERNEL);
+ if (!table) {
+ table = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+ table->ver = 1;
+ }
+
+ list_for_each_entry(resource, &rproc->override_resources, node) {
+ int updated = 0;
+
+ /* If we already have a table, update it with the new values. */
+ updated = rproc_update_resource_table_entry(rproc, resource,
+ table, size);
+ if (updated < 0) {
+ table = ERR_PTR(updated);
+ goto out;
+ }
+ if (updated)
+ continue;
+
+ /* Didn't find matching resource entry -- creating a new one. */
+ table = rproc_add_resource_table_entry(rproc, resource,
+ table, &size);
+ if (IS_ERR(table))
+ goto out;
+
+ *orig_table = table;
+ }
+
+ rproc_dump_resource_table(rproc, table, size);
+
+ *tablesz = size;
+
+ out:
+ return table;
+}
+
/*
* take a firmware and boot a remote processor with it.
*/
@@ -1063,6 +1120,12 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
goto clean_up;
}
+ if (!list_empty(&rproc->override_resources)) {
+ table = rproc_apply_resource_overrides(rproc, &table, &tablesz);
+ if (IS_ERR(table))
+ goto clean_up;
+ }
+
/*
* Create a copy of the resource table. When a virtio device starts
* and calls vring_new_virtqueue() the address of the allocated vring
--
1.9.1
This patch offers the capability to amend existing RSC_VDEV resource
in an existing resource table.
Signed-off-by: Loic Pallardy <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 4297ee7..26fc647 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -985,6 +985,7 @@ static int rproc_update_resource_table_entry(struct rproc *rproc,
struct fw_rsc_carveout *tblc, *newc;
struct fw_rsc_devmem *tbld, *newd;
struct fw_rsc_trace *tblt, *newt;
+ struct fw_rsc_vdev *tblv, *newv;
int updated = true;
int i;
@@ -1029,6 +1030,20 @@ static int rproc_update_resource_table_entry(struct rproc *rproc,
memcpy(tblt, newt, request->size);
return updated;
+ case RSC_VDEV:
+ tblv = rsc;
+ newv = request->resource;
+ if (newv->id != tblv->id)
+ break;
+
+ if (request->size > (sizeof(*tblv) +
+ tblv->num_of_vrings * sizeof(struct fw_rsc_vdev_vring) +
+ tblv->config_len))
+ return -ENOSPC;
+
+ memcpy(tblv, newv, request->size);
+
+ return updated;
default:
dev_err(&rproc->dev,
"Unsupported resource type: %d\n",
--
1.9.1
In current version, rproc_handle_resource use rproc->table_ptr
as default resource table, fixing table to handle.
This patch adds resource table as function argument to have more
flexibility and be able to handle resources from any table.
Signed-off-by: Loic Pallardy <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index ee2dc8d..a6062e7 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -672,16 +672,16 @@ static rproc_handle_resource_t rproc_vdev_handler[RSC_LAST] = {
};
/* handle firmware resource entries before booting the remote processor */
-static int rproc_handle_resources(struct rproc *rproc, int len,
- rproc_handle_resource_t handlers[RSC_LAST])
+static int rproc_handle_resources(struct rproc *rproc, struct resource_table *table_ptr,
+ 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 < rproc->table_ptr->num; i++) {
- int offset = rproc->table_ptr->offset[i];
- struct fw_rsc_hdr *hdr = (void *)rproc->table_ptr + offset;
+ for (i = 0; i < table_ptr->num; i++) {
+ int offset = table_ptr->offset[i];
+ struct fw_rsc_hdr *hdr = (void *)table_ptr + offset;
void *rsc = (void *)hdr + sizeof(*hdr);
dev_dbg(dev, "rsc: type %d\n", hdr->type);
@@ -1309,14 +1309,16 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
rproc->max_notifyid = -1;
/* look for virtio devices and register them */
- ret = rproc_handle_resources(rproc, tablesz, rproc_vdev_handler);
+ ret = rproc_handle_resources(rproc, rproc->cached_table, tablesz,
+ rproc_vdev_handler);
if (ret) {
dev_err(dev, "Failed to handle vdev resources: %d\n", ret);
goto clean_up;
}
/* handle fw resources which are required to boot rproc */
- ret = rproc_handle_resources(rproc, tablesz, rproc_loading_handlers);
+ ret = rproc_handle_resources(rproc, rproc->cached_table, tablesz,
+ rproc_loading_handlers);
if (ret) {
dev_err(dev, "Failed to process resources: %d\n", ret);
goto clean_up_resources;
--
1.9.1
As resource table has been verified after just loading,
the different sanity checks done when accessing resources
are no more needed.
Signed-off-by: Loic Pallardy <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 47 ++++++------------------------------
1 file changed, 7 insertions(+), 40 deletions(-)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 849460e..ee2dc8d 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -50,7 +50,7 @@ static LIST_HEAD(rproc_list);
typedef int (*rproc_handle_resources_t)(struct rproc *rproc,
struct resource_table *table, int len);
typedef int (*rproc_handle_resource_t)(struct rproc *rproc,
- void *, int offset, int avail);
+ void *, int offset);
/* Unique indices for remoteproc devices */
static DEFINE_IDA(rproc_dev_index);
@@ -300,7 +300,6 @@ void rproc_free_vring(struct rproc_vring *rvring)
* rproc_handle_vdev() - handle a vdev fw resource
* @rproc: the remote processor
* @rsc: the vring resource descriptor
- * @avail: size of available data (for sanity checking the image)
*
* This resource entry requests the host to statically register a virtio
* device (vdev), and setup everything needed to support it. It contains
@@ -324,19 +323,12 @@ void rproc_free_vring(struct rproc_vring *rvring)
* Returns 0 on success, or an appropriate error code otherwise
*/
static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
- int offset, int avail)
+ int offset)
{
struct device *dev = &rproc->dev;
struct rproc_vdev *rvdev;
int i, ret;
- /* make sure resource isn't truncated */
- if (sizeof(*rsc) + rsc->num_of_vrings * sizeof(struct fw_rsc_vdev_vring)
- + rsc->config_len > avail) {
- dev_err(dev, "vdev rsc is truncated\n");
- return -EINVAL;
- }
-
/* make sure reserved bytes are zeroes */
if (rsc->reserved[0] || rsc->reserved[1]) {
dev_err(dev, "vdev rsc has non zero reserved bytes\n");
@@ -388,7 +380,6 @@ free_rvdev:
* rproc_handle_trace() - handle a shared trace buffer resource
* @rproc: the remote processor
* @rsc: the trace resource descriptor
- * @avail: size of available data (for sanity checking the image)
*
* In case the remote processor dumps trace logs into memory,
* export it via debugfs.
@@ -401,18 +392,13 @@ free_rvdev:
* Returns 0 on success, or an appropriate error code otherwise
*/
static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
- int offset, int avail)
+ int offset)
{
struct rproc_mem_entry *trace;
struct device *dev = &rproc->dev;
void *ptr;
char name[15];
- if (sizeof(*rsc) > avail) {
- dev_err(dev, "trace rsc is truncated\n");
- return -EINVAL;
- }
-
/* make sure reserved bytes are zeroes */
if (rsc->reserved) {
dev_err(dev, "trace rsc has non zero reserved bytes\n");
@@ -459,7 +445,6 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
* rproc_handle_devmem() - handle devmem resource entry
* @rproc: remote processor handle
* @rsc: the devmem resource entry
- * @avail: size of available data (for sanity checking the image)
*
* Remote processors commonly need to access certain on-chip peripherals.
*
@@ -481,7 +466,7 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
* are outside those ranges.
*/
static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc,
- int offset, int avail)
+ int offset)
{
struct rproc_mem_entry *mapping;
struct device *dev = &rproc->dev;
@@ -491,11 +476,6 @@ static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc,
if (!rproc->domain)
return -EINVAL;
- if (sizeof(*rsc) > avail) {
- dev_err(dev, "devmem rsc is truncated\n");
- return -EINVAL;
- }
-
/* make sure reserved bytes are zeroes */
if (rsc->reserved) {
dev_err(dev, "devmem rsc has non zero reserved bytes\n");
@@ -537,7 +517,6 @@ out:
* rproc_handle_carveout() - handle phys contig memory allocation requests
* @rproc: rproc handle
* @rsc: the resource entry
- * @avail: size of available data (for image validation)
*
* This function will handle firmware requests for allocation of physically
* contiguous memory regions.
@@ -553,7 +532,7 @@ out:
*/
static int rproc_handle_carveout(struct rproc *rproc,
struct fw_rsc_carveout *rsc,
- int offset, int avail)
+ int offset)
{
struct rproc_mem_entry *carveout, *mapping;
struct device *dev = &rproc->dev;
@@ -561,11 +540,6 @@ static int rproc_handle_carveout(struct rproc *rproc,
void *va;
int ret;
- if (sizeof(*rsc) > avail) {
- dev_err(dev, "carveout rsc is truncated\n");
- return -EINVAL;
- }
-
/* make sure reserved bytes are zeroes */
if (rsc->reserved) {
dev_err(dev, "carveout rsc has non zero reserved bytes\n");
@@ -674,7 +648,7 @@ free_carv:
}
static int rproc_count_vrings(struct rproc *rproc, struct fw_rsc_vdev *rsc,
- int offset, int avail)
+ int offset)
{
/* Summarize the number of notification IDs */
rproc->max_notifyid += rsc->num_of_vrings;
@@ -708,15 +682,8 @@ static int rproc_handle_resources(struct rproc *rproc, int len,
for (i = 0; i < rproc->table_ptr->num; i++) {
int offset = rproc->table_ptr->offset[i];
struct fw_rsc_hdr *hdr = (void *)rproc->table_ptr + offset;
- int avail = len - offset - sizeof(*hdr);
void *rsc = (void *)hdr + sizeof(*hdr);
- /* make sure table isn't truncated */
- if (avail < 0) {
- dev_err(dev, "rsc table is truncated\n");
- return -EINVAL;
- }
-
dev_dbg(dev, "rsc: type %d\n", hdr->type);
if (hdr->type >= RSC_LAST) {
@@ -728,7 +695,7 @@ static int rproc_handle_resources(struct rproc *rproc, int len,
if (!handler)
continue;
- ret = handler(rproc, rsc, offset + sizeof(*hdr), avail);
+ ret = handler(rproc, rsc, offset + sizeof(*hdr));
if (ret)
break;
}
--
1.9.1
Handle resource requests according to associated action.
Signed-off-by: Loic Pallardy <[email protected]>
---
drivers/remoteproc/remoteproc_core.c | 98 ++++++++++++++++++++----------------
1 file changed, 55 insertions(+), 43 deletions(-)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index f4a02f0..559a63b 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -1145,61 +1145,69 @@ static int rproc_add_resource_table_entry(struct rproc *rproc,
return 0;
}
-static struct resource_table*
-rproc_apply_resource_overrides(struct rproc *rproc,
- struct resource_table **orig_table,
- int *tablesz)
+static int rproc_apply_resource_overrides(struct rproc *rproc,
+ struct resource_table *table,
+ int tablesz)
{
struct rproc_request_resource *resource;
- struct resource_table *table = *orig_table;
- int size = *tablesz;
+ int ret = 0, size = tablesz;
if (!table && size != 0) {
dev_err(&rproc->dev, "No table present but table size is set\n");
- return ERR_PTR(-EINVAL);
+ ret = -EINVAL;
+ goto out;
}
-
if (IS_ENABLED(DEBUG) || IS_ENABLED(CONFIG_DYNAMIC_DEBUG))
- rproc_dump_resource_table(rproc, table, size);
-
- if (!table) {
- size = sizeof(*table);
- table = devm_kzalloc(&rproc->dev, size, GFP_KERNEL);
- if (!table) {
- table = ERR_PTR(-ENOMEM);
- goto out;
- }
- table->ver = 1;
- }
+ rproc_dump_resource_table(rproc, table, tablesz);
list_for_each_entry(resource, &rproc->override_resources, node) {
- int updated = 0;
+ switch (resource->action) {
+ case RSC_ACT_VERIFY:
+ ret = rproc_verify_resource_table_entry(rproc, resource,
+ table, size);
+ if (ret) {
+ ret = -EINVAL;
+ goto out;
+ }
+ break;
+ case RSC_ACT_UPDATE:
+ /* If we already have a table, update it with the new values. */
+ ret = rproc_update_resource_table_entry(rproc, resource,
+ table, size, false);
+ if (ret < 0)
+ goto out;
+ break;
+ case RSC_ACT_FORCE_UPDATE:
+ /* If we already have a table, update it with the new values. */
+ ret = rproc_update_resource_table_entry(rproc, resource,
+ table, size, true);
+ if (ret < 0)
+ goto out;
+
+ if (ret)
+ break;
- /* If we already have a table, update it with the new values. */
- updated = rproc_update_resource_table_entry(rproc, resource,
- table, size, false);
- if (updated < 0) {
- table = ERR_PTR(updated);
- goto out;
- }
- if (updated)
- continue;
+ /* Didn't find matching resource entry -- creating a new one. */
+ ret = rproc_add_resource_table_entry(rproc, resource,
+ table, size);
+ if (ret)
+ goto out;
- /* Didn't find matching resource entry -- creating a new one. */
- updated = rproc_add_resource_table_entry(rproc, resource,
- table, size);
- if (updated)
+ break;
+ default:
+ dev_err(&rproc->dev, "Unsupported resource action: %d\n",
+ resource->action);
+ ret = -EINVAL;
goto out;
+ };
}
if (IS_ENABLED(DEBUG) || IS_ENABLED(CONFIG_DYNAMIC_DEBUG))
- rproc_dump_resource_table(rproc, table, size);
-
- *tablesz = size;
+ rproc_dump_resource_table(rproc, table, tablesz);
out:
- return table;
+ return ret;
}
/*
@@ -1238,12 +1246,6 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
goto clean_up;
}
- if (!list_empty(&rproc->override_resources)) {
- table = rproc_apply_resource_overrides(rproc, &table, &tablesz);
- if (IS_ERR(table))
- goto clean_up;
- }
-
/*
* Create a copy of the resource table. When a virtio device starts
* and calls vring_new_virtqueue() the address of the allocated vring
@@ -1256,6 +1258,16 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
rproc->table_ptr = rproc->cached_table;
+ if (!list_empty(&rproc->override_resources)) {
+ ret = rproc_apply_resource_overrides(rproc, rproc->cached_table,
+ tablesz);
+ if (ret < 0) {
+ dev_err(dev, "Failed to apply overrides resources\n");
+ goto clean_up;
+ }
+
+ }
+
/* reset max_notifyid */
rproc->max_notifyid = -1;
--
1.9.1
Hi Loic,
On 12/10/16 17:00, Loic Pallardy wrote:
> Firmware can be loaded with a resource table, which details
> resources needed by coprocessor like carevout memory, virtual
> device, trace log buffer etc.
>
> Until now, no method exists to display resource table content.
> This function adds the capability to display the different
> resources associated to a firmware if DEBUG is enabled.
How about instead adding this to a debugfs entry such that one can
always access it rather than having to find it in the kernel log, only
if DEBUG was enabled?
Thanks,
Matt
>
> Signed-off-by: Lee Jones <[email protected]>
> Signed-off-by: Loic Pallardy <[email protected]>
> ---
> drivers/remoteproc/remoteproc_core.c | 85 ++++++++++++++++++++++++++++++++++++
> 1 file changed, 85 insertions(+)
>
> diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> index 67633ee..3c8395b 100644
> --- a/drivers/remoteproc/remoteproc_core.c
> +++ b/drivers/remoteproc/remoteproc_core.c
> @@ -785,6 +785,91 @@ static void rproc_resource_cleanup(struct rproc *rproc)
> rproc_remove_virtio_dev(rvdev);
> }
>
> +static void rproc_dump_resource_table(struct rproc *rproc,
> + struct resource_table *table, int size)
> +{
> + static const char *types[] = {"carveout", "devmem", "trace", "vdev"};
> + struct device *dev = &rproc->dev;
> + struct fw_rsc_carveout *c;
> + struct fw_rsc_devmem *d;
> + struct fw_rsc_trace *t;
> + struct fw_rsc_vdev *v;
> + int i, j;
> +
> + if (!table) {
> + dev_dbg(dev, "No resource table found\n");
> + return;
> + }
> +
> + dev_dbg(dev, "Resource Table: Version %d with %d entries [size: %x]\n",
> + table->ver, table->num, size);
> +
> + for (i = 0; i < table->num; i++) {
> + int offset = table->offset[i];
> + struct fw_rsc_hdr *hdr = (void *)table + offset;
> + void *rsc = (void *)hdr + sizeof(*hdr);
> +
> + switch (hdr->type) {
> + case RSC_CARVEOUT:
> + c = rsc;
> + dev_dbg(dev, "Entry %d is of type %s\n", i, types[hdr->type]);
> + dev_dbg(dev, " Device Address 0x%x\n", c->da);
> + dev_dbg(dev, " Physical Address 0x%x\n", c->pa);
> + dev_dbg(dev, " Length 0x%x Bytes\n", c->len);
> + dev_dbg(dev, " Flags 0x%x\n", c->flags);
> + dev_dbg(dev, " Reserved (should be zero) [%d]\n", c->reserved);
> + dev_dbg(dev, " Name %s\n\n", c->name);
> + break;
> + case RSC_DEVMEM:
> + d = rsc;
> + dev_dbg(dev, "Entry %d is of type %s\n", i, types[hdr->type]);
> + dev_dbg(dev, " Device Address 0x%x\n", d->da);
> + dev_dbg(dev, " Physical Address 0x%x\n", d->pa);
> + dev_dbg(dev, " Length 0x%x Bytes\n", d->len);
> + dev_dbg(dev, " Flags 0x%x\n", d->flags);
> + dev_dbg(dev, " Reserved (should be zero) [%d]\n", d->reserved);
> + dev_dbg(dev, " Name %s\n\n", d->name);
> + break;
> + case RSC_TRACE:
> + t = rsc;
> + dev_dbg(dev, "Entry %d is of type %s\n", i, types[hdr->type]);
> + dev_dbg(dev, " Device Address 0x%x\n", t->da);
> + dev_dbg(dev, " Length 0x%x Bytes\n", t->len);
> + dev_dbg(dev, " Reserved (should be zero) [%d]\n", t->reserved);
> + dev_dbg(dev, " Name %s\n\n", t->name);
> + break;
> + case RSC_VDEV:
> + v = rsc;
> + dev_dbg(dev, "Entry %d is of type %s\n", i, types[hdr->type]);
> +
> + dev_dbg(dev, " ID %d\n", v->id);
> + dev_dbg(dev, " Notify ID %d\n", v->notifyid);
> + dev_dbg(dev, " Device features 0x%x\n", v->dfeatures);
> + dev_dbg(dev, " Guest features 0x%x\n", v->gfeatures);
> + dev_dbg(dev, " Config length 0x%x\n", v->config_len);
> + dev_dbg(dev, " Status 0x%x\n", v->status);
> + dev_dbg(dev, " Number of vrings %d\n", v->num_of_vrings);
> + dev_dbg(dev, " Reserved (should be zero) [%d][%d]\n\n",
> + v->reserved[0], v->reserved[1]);
> +
> + for (j = 0; j < v->num_of_vrings; j++) {
> + dev_dbg(dev, " Vring %d\n", j);
> + dev_dbg(dev, " Device Address 0x%x\n", v->vring[j].da);
> + dev_dbg(dev, " Alignment %d\n", v->vring[j].align);
> + dev_dbg(dev, " Number of buffers %d\n", v->vring[j].num);
> + dev_dbg(dev, " Notify ID %d\n", v->vring[j].notifyid);
> + dev_dbg(dev, " Physical Address 0x%x\n\n",
> + v->vring[j].pa);
> + }
> + break;
> + default:
> + dev_dbg(dev, "Invalid resource type found: %d [hdr: %p]\n",
> + hdr->type, hdr);
> + return;
> + }
> + }
> +}
> +
> int rproc_request_resource(struct rproc *rproc, u32 type, void *resource)
> {
> struct device *dev = &rproc->dev;
On 10/14/2016 10:37 AM, Matt Redfearn wrote:
> Hi Loic,
>
Hi Matt,
>
> On 12/10/16 17:00, Loic Pallardy wrote:
>> Firmware can be loaded with a resource table, which details
>> resources needed by coprocessor like carevout memory, virtual
>> device, trace log buffer etc.
>>
>> Until now, no method exists to display resource table content.
>> This function adds the capability to display the different
>> resources associated to a firmware if DEBUG is enabled.
>
> How about instead adding this to a debugfs entry such that one can
> always access it rather than having to find it in the kernel log, only
> if DEBUG was enabled?
It was one of my remarks on V1, but Lee prefers to have this change on
the top of this series.
Both functions are their interest:
- current function help to analyse changes done during boot sequence
between original and modified resource table
- debugfs function will allow to display resource table provided to
coprocessor and understand what could be wrong in case of error.
I propose to add a patch on the top of the series to support debugfs
interface like mentioned previously by Lee.
Regards,
Loic
>
> Thanks,
> Matt
>
>>
>> Signed-off-by: Lee Jones <[email protected]>
>> Signed-off-by: Loic Pallardy <[email protected]>
>> ---
>> drivers/remoteproc/remoteproc_core.c | 85
>> ++++++++++++++++++++++++++++++++++++
>> 1 file changed, 85 insertions(+)
>>
>> diff --git a/drivers/remoteproc/remoteproc_core.c
>> b/drivers/remoteproc/remoteproc_core.c
>> index 67633ee..3c8395b 100644
>> --- a/drivers/remoteproc/remoteproc_core.c
>> +++ b/drivers/remoteproc/remoteproc_core.c
>> @@ -785,6 +785,91 @@ static void rproc_resource_cleanup(struct rproc
>> *rproc)
>> rproc_remove_virtio_dev(rvdev);
>> }
>> +static void rproc_dump_resource_table(struct rproc *rproc,
>> + struct resource_table *table, int size)
>> +{
>> + static const char *types[] = {"carveout", "devmem", "trace",
>> "vdev"};
>> + struct device *dev = &rproc->dev;
>> + struct fw_rsc_carveout *c;
>> + struct fw_rsc_devmem *d;
>> + struct fw_rsc_trace *t;
>> + struct fw_rsc_vdev *v;
>> + int i, j;
>> +
>> + if (!table) {
>> + dev_dbg(dev, "No resource table found\n");
>> + return;
>> + }
>> +
>> + dev_dbg(dev, "Resource Table: Version %d with %d entries [size:
>> %x]\n",
>> + table->ver, table->num, size);
>> +
>> + for (i = 0; i < table->num; i++) {
>> + int offset = table->offset[i];
>> + struct fw_rsc_hdr *hdr = (void *)table + offset;
>> + void *rsc = (void *)hdr + sizeof(*hdr);
>> +
>> + switch (hdr->type) {
>> + case RSC_CARVEOUT:
>> + c = rsc;
>> + dev_dbg(dev, "Entry %d is of type %s\n", i,
>> types[hdr->type]);
>> + dev_dbg(dev, " Device Address 0x%x\n", c->da);
>> + dev_dbg(dev, " Physical Address 0x%x\n", c->pa);
>> + dev_dbg(dev, " Length 0x%x Bytes\n", c->len);
>> + dev_dbg(dev, " Flags 0x%x\n", c->flags);
>> + dev_dbg(dev, " Reserved (should be zero) [%d]\n",
>> c->reserved);
>> + dev_dbg(dev, " Name %s\n\n", c->name);
>> + break;
>> + case RSC_DEVMEM:
>> + d = rsc;
>> + dev_dbg(dev, "Entry %d is of type %s\n", i,
>> types[hdr->type]);
>> + dev_dbg(dev, " Device Address 0x%x\n", d->da);
>> + dev_dbg(dev, " Physical Address 0x%x\n", d->pa);
>> + dev_dbg(dev, " Length 0x%x Bytes\n", d->len);
>> + dev_dbg(dev, " Flags 0x%x\n", d->flags);
>> + dev_dbg(dev, " Reserved (should be zero) [%d]\n",
>> d->reserved);
>> + dev_dbg(dev, " Name %s\n\n", d->name);
>> + break;
>> + case RSC_TRACE:
>> + t = rsc;
>> + dev_dbg(dev, "Entry %d is of type %s\n", i,
>> types[hdr->type]);
>> + dev_dbg(dev, " Device Address 0x%x\n", t->da);
>> + dev_dbg(dev, " Length 0x%x Bytes\n", t->len);
>> + dev_dbg(dev, " Reserved (should be zero) [%d]\n",
>> t->reserved);
>> + dev_dbg(dev, " Name %s\n\n", t->name);
>> + break;
>> + case RSC_VDEV:
>> + v = rsc;
>> + dev_dbg(dev, "Entry %d is of type %s\n", i,
>> types[hdr->type]);
>> +
>> + dev_dbg(dev, " ID %d\n", v->id);
>> + dev_dbg(dev, " Notify ID %d\n", v->notifyid);
>> + dev_dbg(dev, " Device features 0x%x\n", v->dfeatures);
>> + dev_dbg(dev, " Guest features 0x%x\n", v->gfeatures);
>> + dev_dbg(dev, " Config length 0x%x\n", v->config_len);
>> + dev_dbg(dev, " Status 0x%x\n", v->status);
>> + dev_dbg(dev, " Number of vrings %d\n", v->num_of_vrings);
>> + dev_dbg(dev, " Reserved (should be zero) [%d][%d]\n\n",
>> + v->reserved[0], v->reserved[1]);
>> +
>> + for (j = 0; j < v->num_of_vrings; j++) {
>> + dev_dbg(dev, " Vring %d\n", j);
>> + dev_dbg(dev, " Device Address 0x%x\n",
>> v->vring[j].da);
>> + dev_dbg(dev, " Alignment %d\n", v->vring[j].align);
>> + dev_dbg(dev, " Number of buffers %d\n",
>> v->vring[j].num);
>> + dev_dbg(dev, " Notify ID %d\n",
>> v->vring[j].notifyid);
>> + dev_dbg(dev, " Physical Address 0x%x\n\n",
>> + v->vring[j].pa);
>> + }
>> + break;
>> + default:
>> + dev_dbg(dev, "Invalid resource type found: %d [hdr: %p]\n",
>> + hdr->type, hdr);
>> + return;
>> + }
>> + }
>> +}
>> +
>> int rproc_request_resource(struct rproc *rproc, u32 type, void
>> *resource)
>> {
>> struct device *dev = &rproc->dev;
>