aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuman Anna2017-04-28 16:46:12 -0500
committerSuman Anna2019-03-11 11:59:48 -0500
commit10f1ce98200ec692c9c6381814a551abe20e27e2 (patch)
tree09b22532fbd263ef1f79f74b88722d7420d1e79c
parent418ad4b211e9723bc6344167543f98f0fe5944ab (diff)
downloadremoteproc-10f1ce98200ec692c9c6381814a551abe20e27e2.tar.gz
remoteproc-10f1ce98200ec692c9c6381814a551abe20e27e2.tar.xz
remoteproc-10f1ce98200ec692c9c6381814a551abe20e27e2.zip
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 traceY_last debugfs entry during a crash for each trace entry, and copying the trace buffer contents into the corresponding last trace entry. This copied contents can then be read out using a debugfs entry. The trace entries themselves are cleaned up after the copy and are recreated during a recovery reload. Eg: cat <debugfs_root>/remoteproc/remoteprocX/traceY_last should give the traces that were printed out just before the recovery happened on remoteproc X for trace Y. Signed-off-by: Subramaniam Chanderashekarapuram <subramaniam.ca@ti.com> Signed-off-by: Suman Anna <s-anna@ti.com>
-rw-r--r--drivers/remoteproc/remoteproc_core.c139
-rw-r--r--include/linux/remoteproc.h4
2 files changed, 142 insertions, 1 deletions
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 7e4ff372f2fa..30e02198bb30 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -41,6 +41,7 @@
41#include <linux/crc32.h> 41#include <linux/crc32.h>
42#include <linux/virtio_ids.h> 42#include <linux/virtio_ids.h>
43#include <linux/virtio_ring.h> 43#include <linux/virtio_ring.h>
44#include <linux/vmalloc.h>
44#include <linux/of.h> 45#include <linux/of.h>
45#include <linux/platform_device.h> 46#include <linux/platform_device.h>
46#include <asm/byteorder.h> 47#include <asm/byteorder.h>
@@ -496,6 +497,103 @@ void rproc_vdev_release(struct kref *ref)
496} 497}
497 498
498/** 499/**
500 * rproc_handle_last_trace() - setup a buffer to capture the trace snapshot
501 * before recovery
502 * @rproc: the remote processor
503 * @trace: the trace resource descriptor
504 * @count: the index of the trace under process
505 *
506 * The last trace is allocated and the contents of the trace buffer are
507 * copied during a recovery cleanup. Once, the contents get copied, the
508 * trace buffers are cleaned up for re-use.
509 *
510 * It might also happen that the remoteproc binary changes between the
511 * time that it was loaded and the time that it crashed. In this case,
512 * the trace descriptors might have changed too. The last traces are
513 * re-built as required in this case.
514 *
515 * Returns 0 on success, or an appropriate error code otherwise
516 */
517static int rproc_handle_last_trace(struct rproc *rproc,
518 struct rproc_mem_entry *trace, int count)
519{
520 struct rproc_mem_entry *trace_last, *tmp_trace;
521 struct device *dev = &rproc->dev;
522 char name[15];
523 int i = 0;
524 bool new_trace = false;
525
526 if (!rproc || !trace)
527 return -EINVAL;
528
529 /* we need a new trace in this case */
530 if (count > rproc->num_last_traces) {
531 new_trace = true;
532 /*
533 * make sure snprintf always null terminates, even if truncating
534 */
535 snprintf(name, sizeof(name), "trace%d_last", (count - 1));
536 trace_last = kzalloc(sizeof(*trace_last), GFP_KERNEL);
537 if (!trace_last) {
538 dev_err(dev, "kzalloc failed for trace%d_last\n",
539 count);
540 return -ENOMEM;
541 }
542 } else {
543 /* try to reuse buffers here */
544 list_for_each_entry_safe(trace_last, tmp_trace,
545 &rproc->last_traces, node) {
546 if (++i == count)
547 break;
548 }
549
550 /* if we can reuse the trace, copy buffer and exit */
551 if (trace_last->len == trace->len)
552 goto copy_and_exit;
553
554 /* can reuse the trace struct but not the buffer */
555 vfree(trace_last->va);
556 trace_last->va = NULL;
557 trace_last->len = 0;
558 }
559
560 trace_last->len = trace->len;
561 trace_last->va = vmalloc(sizeof(u32) * trace_last->len);
562 if (!trace_last->va) {
563 dev_err(dev, "vmalloc failed for trace%d_last\n", count);
564 if (!new_trace) {
565 list_del(&trace_last->node);
566 rproc->num_last_traces--;
567 }
568 kfree(trace_last);
569 return -ENOMEM;
570 }
571
572 /* create the debugfs entry */
573 if (new_trace) {
574 trace_last->priv = rproc_create_trace_file(name, rproc,
575 trace_last);
576 if (!trace_last->priv) {
577 dev_err(dev, "trace%d_last create debugfs failed\n",
578 count);
579 vfree(trace_last->va);
580 kfree(trace_last);
581 return -EINVAL;
582 }
583
584 /* add it to the trace list */
585 list_add_tail(&trace_last->node, &rproc->last_traces);
586 rproc->num_last_traces++;
587 }
588
589copy_and_exit:
590 /* copy the trace to last trace */
591 memcpy(trace_last->va, trace->va, trace->len);
592
593 return 0;
594}
595
596/**
499 * rproc_handle_trace() - handle a shared trace buffer resource 597 * rproc_handle_trace() - handle a shared trace buffer resource
500 * @rproc: the remote processor 598 * @rproc: the remote processor
501 * @rsc: the trace resource descriptor 599 * @rsc: the trace resource descriptor
@@ -964,6 +1062,18 @@ static void rproc_coredump_cleanup(struct rproc *rproc)
964} 1062}
965 1063
966/** 1064/**
1065 * rproc_free_last_trace() - helper function to cleanup a last trace entry
1066 * @trace: the last trace element to be cleaned up
1067 */
1068static void rproc_free_last_trace(struct rproc_mem_entry *trace)
1069{
1070 rproc_remove_trace_file(trace->priv);
1071 list_del(&trace->node);
1072 vfree(trace->va);
1073 kfree(trace);
1074}
1075
1076/**
967 * rproc_resource_cleanup() - clean up and free all acquired resources 1077 * rproc_resource_cleanup() - clean up and free all acquired resources
968 * @rproc: rproc handle 1078 * @rproc: rproc handle
969 * 1079 *
@@ -975,14 +1085,32 @@ static void rproc_resource_cleanup(struct rproc *rproc)
975 struct rproc_mem_entry *entry, *tmp; 1085 struct rproc_mem_entry *entry, *tmp;
976 struct rproc_vdev *rvdev, *rvtmp; 1086 struct rproc_vdev *rvdev, *rvtmp;
977 struct device *dev = &rproc->dev; 1087 struct device *dev = &rproc->dev;
1088 int count = 0, i = rproc->num_traces;
978 1089
979 /* clean up debugfs trace entries */ 1090 /* clean up debugfs trace entries */
980 list_for_each_entry_safe(entry, tmp, &rproc->traces, node) { 1091 list_for_each_entry_safe(entry, tmp, &rproc->traces, node) {
1092 /* handle last trace here */
1093 if (rproc->state == RPROC_CRASHED)
1094 rproc_handle_last_trace(rproc, entry, ++count);
1095
981 rproc_remove_trace_file(entry->priv); 1096 rproc_remove_trace_file(entry->priv);
982 rproc->num_traces--;
983 list_del(&entry->node); 1097 list_del(&entry->node);
984 kfree(entry); 1098 kfree(entry);
985 } 1099 }
1100 rproc->num_traces = 0;
1101
1102 /*
1103 * clean up debugfs last trace entries. This either deletes all last
1104 * trace entries during cleanup or just the remaining entries, if any,
1105 * in case of a crash.
1106 */
1107 list_for_each_entry_safe(entry, tmp, &rproc->last_traces, node) {
1108 /* skip the valid traces */
1109 if ((i--) && rproc->state == RPROC_CRASHED)
1110 continue;
1111 rproc_free_last_trace(entry);
1112 rproc->num_last_traces--;
1113 }
986 1114
987 /* clean up iommu mapping entries */ 1115 /* clean up iommu mapping entries */
988 list_for_each_entry_safe(entry, tmp, &rproc->mappings, node) { 1116 list_for_each_entry_safe(entry, tmp, &rproc->mappings, node) {
@@ -1752,6 +1880,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
1752 INIT_LIST_HEAD(&rproc->carveouts); 1880 INIT_LIST_HEAD(&rproc->carveouts);
1753 INIT_LIST_HEAD(&rproc->mappings); 1881 INIT_LIST_HEAD(&rproc->mappings);
1754 INIT_LIST_HEAD(&rproc->traces); 1882 INIT_LIST_HEAD(&rproc->traces);
1883 INIT_LIST_HEAD(&rproc->last_traces);
1755 INIT_LIST_HEAD(&rproc->rvdevs); 1884 INIT_LIST_HEAD(&rproc->rvdevs);
1756 INIT_LIST_HEAD(&rproc->subdevs); 1885 INIT_LIST_HEAD(&rproc->subdevs);
1757 INIT_LIST_HEAD(&rproc->dump_segments); 1886 INIT_LIST_HEAD(&rproc->dump_segments);
@@ -1813,6 +1942,8 @@ EXPORT_SYMBOL(rproc_put);
1813 */ 1942 */
1814int rproc_del(struct rproc *rproc) 1943int rproc_del(struct rproc *rproc)
1815{ 1944{
1945 struct rproc_mem_entry *entry, *tmp;
1946
1816 if (!rproc) 1947 if (!rproc)
1817 return -EINVAL; 1948 return -EINVAL;
1818 1949
@@ -1825,6 +1956,12 @@ int rproc_del(struct rproc *rproc)
1825 rproc->state = RPROC_DELETED; 1956 rproc->state = RPROC_DELETED;
1826 mutex_unlock(&rproc->lock); 1957 mutex_unlock(&rproc->lock);
1827 1958
1959 /* clean up debugfs last trace entries */
1960 list_for_each_entry_safe(entry, tmp, &rproc->last_traces, node) {
1961 rproc_free_last_trace(entry);
1962 rproc->num_last_traces--;
1963 }
1964
1828 rproc_delete_debug_dir(rproc); 1965 rproc_delete_debug_dir(rproc);
1829 1966
1830 /* the rproc is downref'ed as soon as it's removed from the klist */ 1967 /* the rproc is downref'ed as soon as it's removed from the klist */
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index ed33b09ff0ce..5c9519283fea 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -467,6 +467,8 @@ struct rproc_dump_segment {
467 * @dbg_dir: debugfs directory of this rproc device 467 * @dbg_dir: debugfs directory of this rproc device
468 * @traces: list of trace buffers 468 * @traces: list of trace buffers
469 * @num_traces: number of trace buffers 469 * @num_traces: number of trace buffers
470 * @last_traces: list of last trace buffers
471 * @num_last_traces: number of last trace buffers
470 * @carveouts: list of physically contiguous memory allocations 472 * @carveouts: list of physically contiguous memory allocations
471 * @mappings: list of iommu mappings we initiated, needed on shutdown 473 * @mappings: list of iommu mappings we initiated, needed on shutdown
472 * @bootaddr: address of first instruction to boot rproc with (optional) 474 * @bootaddr: address of first instruction to boot rproc with (optional)
@@ -503,6 +505,8 @@ struct rproc {
503 struct dentry *dbg_dir; 505 struct dentry *dbg_dir;
504 struct list_head traces; 506 struct list_head traces;
505 int num_traces; 507 int num_traces;
508 struct list_head last_traces;
509 int num_last_traces;
506 struct list_head carveouts; 510 struct list_head carveouts;
507 struct list_head mappings; 511 struct list_head mappings;
508 u32 bootaddr; 512 u32 bootaddr;