diff options
author | Fernando Guzman Lugo <fernando.lugo@ti.com> | 2012-09-18 05:26:35 -0400 |
---|---|---|
committer | Ohad Ben-Cohen <ohad@wizery.com> | 2012-09-18 05:53:41 -0400 |
commit | 2e37abb89a2ef13c524b0728bb9893f996a10b6b (patch) | |
tree | 11e760251317566b19cd9053608afa67cab88576 | |
parent | 70b85ef83ce3523f709b622d2c4cb31778686338 (diff) |
remoteproc: create a 'recovery' debugfs entry
Add a 'recovery' debugfs entry to dynamically disable/enable recovery
at runtime. This is useful when one is trying to debug an rproc crash;
without it, a recovery will immediately take place, making it harder
to debug the crash.
Contributions from Subramaniam Chanderashekarapuram.
Examples:
- disabling recovery:
$ echo disabled > <debugfs>/remoteproc/remoteproc0/recovery
- in case you want to recover a crash, but keep recovery disabled
(useful in debugging sessions when you expect additional crashes
you want to debug):
$ echo recover > <debugfs>/remoteproc/remoteproc0/recovery
- enabling recovery:
$ echo enabled > <debugfs>/remoteproc/remoteproc0/recovery
Signed-off-by: Fernando Guzman Lugo <fernando.lugo@ti.com>
[ohad: some white space, commentary and commit log changes]
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
-rw-r--r-- | drivers/remoteproc/remoteproc_core.c | 3 | ||||
-rw-r--r-- | drivers/remoteproc/remoteproc_debugfs.c | 81 | ||||
-rw-r--r-- | include/linux/remoteproc.h | 2 |
3 files changed, 85 insertions, 1 deletions
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 5000d7589cf5..29fc8236cac9 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c | |||
@@ -965,7 +965,8 @@ static void rproc_crash_handler_work(struct work_struct *work) | |||
965 | 965 | ||
966 | mutex_unlock(&rproc->lock); | 966 | mutex_unlock(&rproc->lock); |
967 | 967 | ||
968 | rproc_trigger_recovery(rproc); | 968 | if (!rproc->recovery_disabled) |
969 | rproc_trigger_recovery(rproc); | ||
969 | } | 970 | } |
970 | 971 | ||
971 | /** | 972 | /** |
diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c index 03833850f214..10a38258e31d 100644 --- a/drivers/remoteproc/remoteproc_debugfs.c +++ b/drivers/remoteproc/remoteproc_debugfs.c | |||
@@ -28,6 +28,9 @@ | |||
28 | #include <linux/debugfs.h> | 28 | #include <linux/debugfs.h> |
29 | #include <linux/remoteproc.h> | 29 | #include <linux/remoteproc.h> |
30 | #include <linux/device.h> | 30 | #include <linux/device.h> |
31 | #include <linux/uaccess.h> | ||
32 | |||
33 | #include "remoteproc_internal.h" | ||
31 | 34 | ||
32 | /* remoteproc debugfs parent dir */ | 35 | /* remoteproc debugfs parent dir */ |
33 | static struct dentry *rproc_dbg; | 36 | static struct dentry *rproc_dbg; |
@@ -111,6 +114,82 @@ static const struct file_operations rproc_name_ops = { | |||
111 | .llseek = generic_file_llseek, | 114 | .llseek = generic_file_llseek, |
112 | }; | 115 | }; |
113 | 116 | ||
117 | /* expose recovery flag via debugfs */ | ||
118 | static ssize_t rproc_recovery_read(struct file *filp, char __user *userbuf, | ||
119 | size_t count, loff_t *ppos) | ||
120 | { | ||
121 | struct rproc *rproc = filp->private_data; | ||
122 | char *buf = rproc->recovery_disabled ? "disabled\n" : "enabled\n"; | ||
123 | |||
124 | return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); | ||
125 | } | ||
126 | |||
127 | /* | ||
128 | * By writing to the 'recovery' debugfs entry, we control the behavior of the | ||
129 | * recovery mechanism dynamically. The default value of this entry is "enabled". | ||
130 | * | ||
131 | * The 'recovery' debugfs entry supports these commands: | ||
132 | * | ||
133 | * enabled: When enabled, the remote processor will be automatically | ||
134 | * recovered whenever it crashes. Moreover, if the remote | ||
135 | * processor crashes while recovery is disabled, it will | ||
136 | * be automatically recovered too as soon as recovery is enabled. | ||
137 | * | ||
138 | * disabled: When disabled, a remote processor will remain in a crashed | ||
139 | * state if it crashes. This is useful for debugging purposes; | ||
140 | * without it, debugging a crash is substantially harder. | ||
141 | * | ||
142 | * recover: This function will trigger an immediate recovery if the | ||
143 | * remote processor is in a crashed state, without changing | ||
144 | * or checking the recovery state (enabled/disabled). | ||
145 | * This is useful during debugging sessions, when one expects | ||
146 | * additional crashes to happen after enabling recovery. In this | ||
147 | * case, enabling recovery will make it hard to debug subsequent | ||
148 | * crashes, so it's recommended to keep recovery disabled, and | ||
149 | * instead use the "recover" command as needed. | ||
150 | */ | ||
151 | static ssize_t | ||
152 | rproc_recovery_write(struct file *filp, const char __user *user_buf, | ||
153 | size_t count, loff_t *ppos) | ||
154 | { | ||
155 | struct rproc *rproc = filp->private_data; | ||
156 | char buf[10]; | ||
157 | int ret; | ||
158 | |||
159 | if (count > sizeof(buf)) | ||
160 | return count; | ||
161 | |||
162 | ret = copy_from_user(buf, user_buf, count); | ||
163 | if (ret) | ||
164 | return ret; | ||
165 | |||
166 | /* remove end of line */ | ||
167 | if (buf[count - 1] == '\n') | ||
168 | buf[count - 1] = '\0'; | ||
169 | |||
170 | if (!strncmp(buf, "enabled", count)) { | ||
171 | rproc->recovery_disabled = false; | ||
172 | /* if rproc has crashed, trigger recovery */ | ||
173 | if (rproc->state == RPROC_CRASHED) | ||
174 | rproc_trigger_recovery(rproc); | ||
175 | } else if (!strncmp(buf, "disabled", count)) { | ||
176 | rproc->recovery_disabled = true; | ||
177 | } else if (!strncmp(buf, "recover", count)) { | ||
178 | /* if rproc has crashed, trigger recovery */ | ||
179 | if (rproc->state == RPROC_CRASHED) | ||
180 | rproc_trigger_recovery(rproc); | ||
181 | } | ||
182 | |||
183 | return count; | ||
184 | } | ||
185 | |||
186 | static const struct file_operations rproc_recovery_ops = { | ||
187 | .read = rproc_recovery_read, | ||
188 | .write = rproc_recovery_write, | ||
189 | .open = simple_open, | ||
190 | .llseek = generic_file_llseek, | ||
191 | }; | ||
192 | |||
114 | void rproc_remove_trace_file(struct dentry *tfile) | 193 | void rproc_remove_trace_file(struct dentry *tfile) |
115 | { | 194 | { |
116 | debugfs_remove(tfile); | 195 | debugfs_remove(tfile); |
@@ -154,6 +233,8 @@ void rproc_create_debug_dir(struct rproc *rproc) | |||
154 | rproc, &rproc_name_ops); | 233 | rproc, &rproc_name_ops); |
155 | debugfs_create_file("state", 0400, rproc->dbg_dir, | 234 | debugfs_create_file("state", 0400, rproc->dbg_dir, |
156 | rproc, &rproc_state_ops); | 235 | rproc, &rproc_state_ops); |
236 | debugfs_create_file("recovery", 0400, rproc->dbg_dir, | ||
237 | rproc, &rproc_recovery_ops); | ||
157 | } | 238 | } |
158 | 239 | ||
159 | void __init rproc_init_debugfs(void) | 240 | void __init rproc_init_debugfs(void) |
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index 0c1a2f95be76..2ccc3fe2046d 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h | |||
@@ -399,6 +399,7 @@ enum rproc_crash_type { | |||
399 | * @crash_handler: workqueue for handling a crash | 399 | * @crash_handler: workqueue for handling a crash |
400 | * @crash_cnt: crash counter | 400 | * @crash_cnt: crash counter |
401 | * @crash_comp: completion used to sync crash handler and the rproc reload | 401 | * @crash_comp: completion used to sync crash handler and the rproc reload |
402 | * @recovery_disabled: flag that state if recovery was disabled | ||
402 | */ | 403 | */ |
403 | struct rproc { | 404 | struct rproc { |
404 | struct klist_node node; | 405 | struct klist_node node; |
@@ -425,6 +426,7 @@ struct rproc { | |||
425 | struct work_struct crash_handler; | 426 | struct work_struct crash_handler; |
426 | unsigned crash_cnt; | 427 | unsigned crash_cnt; |
427 | struct completion crash_comp; | 428 | struct completion crash_comp; |
429 | bool recovery_disabled; | ||
428 | }; | 430 | }; |
429 | 431 | ||
430 | /* we currently support only two vrings per rvdev */ | 432 | /* we currently support only two vrings per rvdev */ |