diff options
author | Subramaniam Chanderashekarapuram <subramaniam.ca@ti.com> | 2012-06-25 17:43:49 -0500 |
---|---|---|
committer | Andy Green <andy.green@linaro.org> | 2012-09-07 13:05:52 +0800 |
commit | 4560dd7b8f6028c98f33920ed5f14fa96d972dcf (patch) | |
tree | d91c6e15b2c64f24ab2e9585ec2079cd742be2ad /drivers | |
parent | e59d076a77e700513a6f26a12ff41071e202c227 (diff) |
remoteproc: implement last trace for remoteproc
The last trace is a way of preserving the remoteproc traces past
remoteproc recovery. This is achieved by creating a new last_trace
debugfs entry during a crash for each trace entry, and copying the
trace buffer contents into the corresponding last trace entry. This
copy can then be read out using a debugfs entry. The trace entries
themselves are cleaned up after the copy and are recreated during
recovery.
Something like,
cat <debugfs root>/remoteproc/remoteprocX/traceX_last
should give the traces that were printed out just before the recovery
happened.
Change-Id: I2d6879421022a895dc34dfcc5c003ff33779128c
Signed-off-by: Subramaniam Chanderashekarapuram <subramaniam.ca@ti.com>
Signed-off-by: Suman Anna <s-anna@ti.com>
Signed-off-by: Fernando Guzman Lugo <fernando.lugo@ti.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/remoteproc/remoteproc_core.c | 138 |
1 files changed, 137 insertions, 1 deletions
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 4e4c4807f5e7..2fc457bebe90 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -43,6 +43,7 @@ #include <linux/pm_runtime.h> #include <linux/kthread.h> #include <linux/delay.h> +#include <linux/vmalloc.h> #include "remoteproc_internal.h" @@ -710,6 +711,103 @@ free_rvdev: } /** + * rproc_handle_last_trace() - setup a buffer to capture the trace snapshot + * before recovery + * @rproc: the remote processor + * @trace: the trace resource descriptor + * @count: the index of the trace under process + * + * The last trace is allocated and the contents of the trace buffer are + * copied during a recovery cleanup. Once, the contents get copied, the + * trace buffers are cleaned up for re-use. + * + * It might also happen that the remoteproc binary changes between the + * time that it was loaded and the time that it crashed. In this case, + * the trace descriptors might have changed too. The last traces are + * re-built as required in this case. + * + * Returns 0 on success, or an appropriate error code otherwise + */ +static int rproc_handle_last_trace(struct rproc *rproc, + struct rproc_mem_entry *trace, int count) +{ + struct rproc_mem_entry *trace_last, *tmp_trace; + struct device *dev = &rproc->dev; + char name[15]; + int i = 0; + bool new_trace = false; + + if (!rproc || !trace) + return -EINVAL; + + /* we need a new trace in this case */ + if (count > rproc->num_last_traces) { + new_trace = true; + /* + * make sure snprintf always null terminates, even if truncating + */ + snprintf(name, sizeof(name), "trace%d_last", (count - 1)); + trace_last = kzalloc(sizeof *trace_last, GFP_KERNEL); + if (!trace_last) { + dev_err(dev, "kzalloc failed for trace%d_last\n", + count); + return -ENOMEM; + } + } else { + /* try to reuse buffers here */ + list_for_each_entry_safe(trace_last, tmp_trace, + &rproc->last_traces, node) { + if (++i == count) + break; + } + + /* if we can reuse the trace, copy buffer and exit */ + if (trace_last->len == trace->len) + goto copy_and_exit; + + /* can reuse the trace struct but not the buffer */ + vfree(trace_last->va); + trace_last->va = NULL; + trace_last->len = 0; + } + + trace_last->len = trace->len; + trace_last->va = vmalloc(sizeof(u32) * trace_last->len); + if (!trace_last->va) { + dev_err(dev, "vmalloc failed for trace%d_last\n", count); + if (!new_trace) { + list_del(&trace_last->node); + rproc->num_last_traces--; + } + kfree(trace_last); + return -ENOMEM; + } + + /* create the debugfs entry */ + if (new_trace) { + trace_last->priv = rproc_create_trace_file(name, rproc, + trace_last); + if (!trace_last->priv) { + dev_err(dev, "trace%d_last create debugfs failed\n", + count); + vfree(trace_last->va); + kfree(trace_last); + return -EINVAL; + } + + /* add it to the trace list */ + list_add_tail(&trace_last->node, &rproc->last_traces); + rproc->num_last_traces++; + } + +copy_and_exit: + /* copy the trace to last trace */ + memcpy(trace_last->va, trace->va, trace->len); + + return 0; +} + +/** * rproc_handle_trace() - handle a shared trace buffer resource * @rproc: the remote processor * @rsc: the trace resource descriptor @@ -1253,6 +1351,18 @@ rproc_find_fw_version_section(struct rproc *rproc, const u8 *elf_data, } /** + * rproc_free_last_trace() - helper function to cleanup a last trace entry + * @trace: the last trace element to be cleaned up + */ +static void rproc_free_last_trace(struct rproc_mem_entry *trace) +{ + rproc_remove_trace_file(trace->priv); + list_del(&trace->node); + vfree(trace->va); + kfree(trace); +} + +/** * rproc_resource_cleanup() - clean up and free all acquired resources * @rproc: rproc handle * @@ -1263,14 +1373,32 @@ static void rproc_resource_cleanup(struct rproc *rproc) { struct rproc_mem_entry *entry, *tmp; struct device *dev = &rproc->dev; + int count = 0, i = rproc->num_traces; /* clean up debugfs trace entries */ list_for_each_entry_safe(entry, tmp, &rproc->traces, node) { + /* handle last trace here */ + if (rproc->state == RPROC_CRASHED) + rproc_handle_last_trace(rproc, entry, ++count); + rproc_remove_trace_file(entry->priv); - rproc->num_traces--; list_del(&entry->node); kfree(entry); } + rproc->num_traces = 0; + + /* + * clean up debugfs last trace entries. This either deletes all last + * trace entries during cleanup or just the remaining entries, if any, + * in case of a crash. + */ + list_for_each_entry_safe(entry, tmp, &rproc->last_traces, node) { + /* skip the valid traces */ + if ((i--) && (rproc->state == RPROC_CRASHED)) + continue; + rproc_free_last_trace(entry); + rproc->num_last_traces--; + } /* clean up carveout allocations */ list_for_each_entry_safe(entry, tmp, &rproc->carveouts, node) { @@ -1662,6 +1790,13 @@ EXPORT_SYMBOL(rproc_shutdown); void rproc_release(struct kref *kref) { struct rproc *rproc = container_of(kref, struct rproc, refcount); + struct rproc_mem_entry *entry, *tmp; + + /* clean up debugfs last trace entries */ + list_for_each_entry_safe(entry, tmp, &rproc->last_traces, node) { + rproc_free_last_trace(entry); + rproc->num_last_traces--; + } dev_info(&rproc->dev, "removing %s\n", rproc->name); @@ -2041,6 +2176,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name, INIT_LIST_HEAD(&rproc->carveouts); INIT_LIST_HEAD(&rproc->mappings); INIT_LIST_HEAD(&rproc->traces); + INIT_LIST_HEAD(&rproc->last_traces); INIT_LIST_HEAD(&rproc->rvdevs); INIT_WORK(&rproc->error_handler, rproc_error_handler_work); |