aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFernando Guzman Lugo <fernando.lugo@ti.com>2012-08-30 14:26:12 -0400
committerOhad Ben-Cohen <ohad@wizery.com>2012-09-18 05:53:22 -0400
commit8afd519c3470f685f964deebd61aa51d83cde90a (patch)
treee5262256de6e9636594118a5e85cffcc2572040b
parenta1a7e0a33ade47d65abc07cddf015b5c576cd772 (diff)
remoteproc: add rproc_report_crash function to notify rproc crashes
Allow low-level remoteproc drivers to report rproc crashes by exporting a new rproc_report_crash() function (invoking this from non-rproc drivers is probably wrong, and should be carefully scrutinized if ever needed). rproc_report_crash() can be called from any context; it offloads the tasks of handling the crash to a separate thread. Handling the crash from a separate thread is helpful because: - Ability to call invoke rproc_report_crash() from atomic context, due to the fact that many crashes trigger an interrupt, so this function can be called directly from ISR context. - Avoiding deadlocks which could happen if rproc_report_crash() is called from a function which indirectly holds the rproc lock. Handling the crash might involve: - Remoteproc register dump - Remoteproc stack dump - Remoteproc core dump - Saving Remoteproc traces so they can be read after the crash - Reseting the remoteproc in order to make it functional again (hard recovery) Right now, we only print the crash type which was detected, and only the mmufault type is supported. Remoteproc low-level drivers can add more types when needed. Signed-off-by: Fernando Guzman Lugo <fernando.lugo@ti.com> [ohad: some commentary, white space and commit log changes] Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
-rw-r--r--Documentation/remoteproc.txt7
-rw-r--r--drivers/remoteproc/remoteproc_core.c79
-rw-r--r--include/linux/remoteproc.h18
3 files changed, 100 insertions, 4 deletions
diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
index 23a09b884bc7..e6469fdcf89a 100644
--- a/Documentation/remoteproc.txt
+++ b/Documentation/remoteproc.txt
@@ -129,6 +129,13 @@ int dummy_rproc_example(struct rproc *my_rproc)
129 129
130 Returns 0 on success and -EINVAL if @rproc isn't valid. 130 Returns 0 on success and -EINVAL if @rproc isn't valid.
131 131
132 void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type)
133 - Report a crash in a remoteproc
134 This function must be called every time a crash is detected by the
135 platform specific rproc implementation. This should not be called from a
136 non-remoteproc driver. This function can be called from atomic/interrupt
137 context.
138
1325. Implementation callbacks 1395. Implementation callbacks
133 140
134These callbacks should be provided by platform-specific remoteproc 141These callbacks should be provided by platform-specific remoteproc
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index d5c2dbfc7443..93e2b3526543 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -50,6 +50,18 @@ typedef int (*rproc_handle_resource_t)(struct rproc *rproc, void *, int avail);
50/* Unique indices for remoteproc devices */ 50/* Unique indices for remoteproc devices */
51static DEFINE_IDA(rproc_dev_index); 51static DEFINE_IDA(rproc_dev_index);
52 52
53static const char * const rproc_crash_names[] = {
54 [RPROC_MMUFAULT] = "mmufault",
55};
56
57/* translate rproc_crash_type to string */
58static const char *rproc_crash_to_string(enum rproc_crash_type type)
59{
60 if (type < ARRAY_SIZE(rproc_crash_names))
61 return rproc_crash_names[type];
62 return "unkown";
63}
64
53/* 65/*
54 * This is the IOMMU fault handler we register with the IOMMU API 66 * This is the IOMMU fault handler we register with the IOMMU API
55 * (when relevant; not all remote processors access memory through 67 * (when relevant; not all remote processors access memory through
@@ -57,18 +69,19 @@ static DEFINE_IDA(rproc_dev_index);
57 * 69 *
58 * IOMMU core will invoke this handler whenever the remote processor 70 * IOMMU core will invoke this handler whenever the remote processor
59 * will try to access an unmapped device address. 71 * will try to access an unmapped device address.
60 *
61 * Currently this is mostly a stub, but it will be later used to trigger
62 * the recovery of the remote processor.
63 */ 72 */
64static int rproc_iommu_fault(struct iommu_domain *domain, struct device *dev, 73static int rproc_iommu_fault(struct iommu_domain *domain, struct device *dev,
65 unsigned long iova, int flags, void *token) 74 unsigned long iova, int flags, void *token)
66{ 75{
76 struct rproc *rproc = token;
77
67 dev_err(dev, "iommu fault: da 0x%lx flags 0x%x\n", iova, flags); 78 dev_err(dev, "iommu fault: da 0x%lx flags 0x%x\n", iova, flags);
68 79
80 rproc_report_crash(rproc, RPROC_MMUFAULT);
81
69 /* 82 /*
70 * Let the iommu core know we're not really handling this fault; 83 * Let the iommu core know we're not really handling this fault;
71 * we just plan to use this as a recovery trigger. 84 * we just used it as a recovery trigger.
72 */ 85 */
73 return -ENOSYS; 86 return -ENOSYS;
74} 87}
@@ -872,6 +885,36 @@ out:
872} 885}
873 886
874/** 887/**
888 * rproc_crash_handler_work() - handle a crash
889 *
890 * This function needs to handle everything related to a crash, like cpu
891 * registers and stack dump, information to help to debug the fatal error, etc.
892 */
893static void rproc_crash_handler_work(struct work_struct *work)
894{
895 struct rproc *rproc = container_of(work, struct rproc, crash_handler);
896 struct device *dev = &rproc->dev;
897
898 dev_dbg(dev, "enter %s\n", __func__);
899
900 mutex_lock(&rproc->lock);
901
902 if (rproc->state == RPROC_CRASHED || rproc->state == RPROC_OFFLINE) {
903 /* handle only the first crash detected */
904 mutex_unlock(&rproc->lock);
905 return;
906 }
907
908 rproc->state = RPROC_CRASHED;
909 dev_err(dev, "handling crash #%u in %s\n", ++rproc->crash_cnt,
910 rproc->name);
911
912 mutex_unlock(&rproc->lock);
913
914 /* TODO: handle crash */
915}
916
917/**
875 * rproc_boot() - boot a remote processor 918 * rproc_boot() - boot a remote processor
876 * @rproc: handle of a remote processor 919 * @rproc: handle of a remote processor
877 * 920 *
@@ -1165,6 +1208,8 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
1165 INIT_LIST_HEAD(&rproc->traces); 1208 INIT_LIST_HEAD(&rproc->traces);
1166 INIT_LIST_HEAD(&rproc->rvdevs); 1209 INIT_LIST_HEAD(&rproc->rvdevs);
1167 1210
1211 INIT_WORK(&rproc->crash_handler, rproc_crash_handler_work);
1212
1168 rproc->state = RPROC_OFFLINE; 1213 rproc->state = RPROC_OFFLINE;
1169 1214
1170 return rproc; 1215 return rproc;
@@ -1221,6 +1266,32 @@ int rproc_del(struct rproc *rproc)
1221} 1266}
1222EXPORT_SYMBOL(rproc_del); 1267EXPORT_SYMBOL(rproc_del);
1223 1268
1269/**
1270 * rproc_report_crash() - rproc crash reporter function
1271 * @rproc: remote processor
1272 * @type: crash type
1273 *
1274 * This function must be called every time a crash is detected by the low-level
1275 * drivers implementing a specific remoteproc. This should not be called from a
1276 * non-remoteproc driver.
1277 *
1278 * This function can be called from atomic/interrupt context.
1279 */
1280void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type)
1281{
1282 if (!rproc) {
1283 pr_err("NULL rproc pointer\n");
1284 return;
1285 }
1286
1287 dev_err(&rproc->dev, "crash detected in %s: type %s\n",
1288 rproc->name, rproc_crash_to_string(type));
1289
1290 /* create a new task to handle the error */
1291 schedule_work(&rproc->crash_handler);
1292}
1293EXPORT_SYMBOL(rproc_report_crash);
1294
1224static int __init remoteproc_init(void) 1295static int __init remoteproc_init(void)
1225{ 1296{
1226 rproc_init_debugfs(); 1297 rproc_init_debugfs();
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 131b53957b9f..a46ed2723803 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -361,6 +361,19 @@ enum rproc_state {
361}; 361};
362 362
363/** 363/**
364 * enum rproc_crash_type - remote processor crash types
365 * @RPROC_MMUFAULT: iommu fault
366 *
367 * Each element of the enum is used as an array index. So that, the value of
368 * the elements should be always something sane.
369 *
370 * Feel free to add more types when needed.
371 */
372enum rproc_crash_type {
373 RPROC_MMUFAULT,
374};
375
376/**
364 * struct rproc - represents a physical remote processor device 377 * struct rproc - represents a physical remote processor device
365 * @node: klist node of this rproc object 378 * @node: klist node of this rproc object
366 * @domain: iommu domain 379 * @domain: iommu domain
@@ -383,6 +396,8 @@ enum rproc_state {
383 * @rvdevs: list of remote virtio devices 396 * @rvdevs: list of remote virtio devices
384 * @notifyids: idr for dynamically assigning rproc-wide unique notify ids 397 * @notifyids: idr for dynamically assigning rproc-wide unique notify ids
385 * @index: index of this rproc device 398 * @index: index of this rproc device
399 * @crash_handler: workqueue for handling a crash
400 * @crash_cnt: crash counter
386 */ 401 */
387struct rproc { 402struct rproc {
388 struct klist_node node; 403 struct klist_node node;
@@ -406,6 +421,8 @@ struct rproc {
406 struct list_head rvdevs; 421 struct list_head rvdevs;
407 struct idr notifyids; 422 struct idr notifyids;
408 int index; 423 int index;
424 struct work_struct crash_handler;
425 unsigned crash_cnt;
409}; 426};
410 427
411/* we currently support only two vrings per rvdev */ 428/* we currently support only two vrings per rvdev */
@@ -460,6 +477,7 @@ int rproc_del(struct rproc *rproc);
460 477
461int rproc_boot(struct rproc *rproc); 478int rproc_boot(struct rproc *rproc);
462void rproc_shutdown(struct rproc *rproc); 479void rproc_shutdown(struct rproc *rproc);
480void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type);
463 481
464static inline struct rproc_vdev *vdev_to_rvdev(struct virtio_device *vdev) 482static inline struct rproc_vdev *vdev_to_rvdev(struct virtio_device *vdev)
465{ 483{