blob: 40e6e0cca286ccb8dc2da0cedd5c9c3b2bbb3946 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/uaccess.h>
16#include <linux/module.h>
17#include <linux/fs.h>
18#include <linux/proc_fs.h>
19#include <linux/delay.h>
20#include <linux/list.h>
21#include <linux/io.h>
22#include <linux/kthread.h>
Vikram Mulukutla96aecfc2011-07-28 18:18:42 -070023#include <linux/time.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070024
25#include <asm/current.h>
26
27#include <mach/peripheral-loader.h>
28#include <mach/scm.h>
29#include <mach/socinfo.h>
30#include <mach/subsystem_notif.h>
31#include <mach/subsystem_restart.h>
32
33#include "smd_private.h"
34
35#if defined(SUBSYS_RESTART_DEBUG)
36#define dprintk(msg...) printk(msg)
37#else
38#define dprintk(msg...)
39#endif
40
41struct subsys_soc_restart_order {
42 const char * const *subsystem_list;
43 int count;
44
45 struct mutex shutdown_lock;
46 struct mutex powerup_lock;
47 struct subsys_data *subsys_ptrs[];
48};
49
50struct restart_thread_data {
51 struct subsys_data *subsys;
52 int coupled;
53};
54
Vikram Mulukutla96aecfc2011-07-28 18:18:42 -070055struct restart_log {
56 struct timeval time;
57 struct subsys_data *subsys;
58 struct list_head list;
59};
60
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070061static int restart_level;
62static int enable_ramdumps;
63
Vikram Mulukutla96aecfc2011-07-28 18:18:42 -070064static LIST_HEAD(restart_log_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070065static LIST_HEAD(subsystem_list);
66static DEFINE_MUTEX(subsystem_list_lock);
67static DEFINE_MUTEX(soc_order_reg_lock);
Vikram Mulukutla96aecfc2011-07-28 18:18:42 -070068static DEFINE_MUTEX(restart_log_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070069
70/* SOC specific restart orders go here */
71
72#define DEFINE_SINGLE_RESTART_ORDER(name, order) \
73 static struct subsys_soc_restart_order __##name = { \
74 .subsystem_list = order, \
75 .count = ARRAY_SIZE(order), \
76 .subsys_ptrs = {[ARRAY_SIZE(order)] = NULL} \
77 }; \
78 static struct subsys_soc_restart_order *name[] = { \
79 &__##name, \
80 }
81
82/* MSM 8x60 restart ordering info */
83static const char * const _order_8x60_all[] = {
84 "external_modem", "modem", "lpass"
85};
86DEFINE_SINGLE_RESTART_ORDER(orders_8x60_all, _order_8x60_all);
87
88static const char * const _order_8x60_modems[] = {"external_modem", "modem"};
89DEFINE_SINGLE_RESTART_ORDER(orders_8x60_modems, _order_8x60_modems);
90
91/* MSM 8960 restart ordering info */
92static const char * const order_8960[] = {"modem", "lpass"};
93
94static struct subsys_soc_restart_order restart_orders_8960_one = {
95 .subsystem_list = order_8960,
96 .count = ARRAY_SIZE(order_8960),
97 .subsys_ptrs = {[ARRAY_SIZE(order_8960)] = NULL}
98 };
99
100static struct subsys_soc_restart_order *restart_orders_8960[] = {
101 &restart_orders_8960_one,
102};
103
104/* These will be assigned to one of the sets above after
105 * runtime SoC identification.
106 */
107static struct subsys_soc_restart_order **restart_orders;
108static int n_restart_orders;
109
110module_param(enable_ramdumps, int, S_IRUGO | S_IWUSR);
111
112static struct subsys_soc_restart_order *_update_restart_order(
113 struct subsys_data *subsys);
114
115int get_restart_level()
116{
117 return restart_level;
118}
119EXPORT_SYMBOL(get_restart_level);
120
121static void restart_level_changed(void)
122{
123 struct subsys_data *subsys;
124
125 if (cpu_is_msm8x60() && restart_level == RESET_SUBSYS_COUPLED) {
126 restart_orders = orders_8x60_all;
127 n_restart_orders = ARRAY_SIZE(orders_8x60_all);
128 }
129
130 if (cpu_is_msm8x60() && restart_level == RESET_SUBSYS_MIXED) {
131 restart_orders = orders_8x60_modems;
132 n_restart_orders = ARRAY_SIZE(orders_8x60_modems);
133 }
134
135 mutex_lock(&subsystem_list_lock);
136 list_for_each_entry(subsys, &subsystem_list, list)
137 subsys->restart_order = _update_restart_order(subsys);
138 mutex_unlock(&subsystem_list_lock);
139}
140
141static int restart_level_set(const char *val, struct kernel_param *kp)
142{
143 int ret;
144 int old_val = restart_level;
145
146 ret = param_set_int(val, kp);
147 if (ret)
148 return ret;
149
150 switch (restart_level) {
151
152 case RESET_SOC:
153 case RESET_SUBSYS_COUPLED:
154 case RESET_SUBSYS_INDEPENDENT:
155 pr_info("Subsystem Restart: Phase %d behavior activated.\n",
156 restart_level);
157 break;
158
159 case RESET_SUBSYS_MIXED:
160 pr_info("Subsystem Restart: Phase 2+ behavior activated.\n");
161 break;
162
163 default:
164 restart_level = old_val;
165 return -EINVAL;
166 break;
167
168 }
169
170 if (restart_level != old_val)
171 restart_level_changed();
172
173 return 0;
174}
175
176module_param_call(restart_level, restart_level_set, param_get_int,
177 &restart_level, 0644);
178
179static struct subsys_data *_find_subsystem(const char *subsys_name)
180{
181 struct subsys_data *subsys;
182
183 mutex_lock(&subsystem_list_lock);
184 list_for_each_entry(subsys, &subsystem_list, list)
185 if (!strncmp(subsys->name, subsys_name,
186 SUBSYS_NAME_MAX_LENGTH)) {
187 mutex_unlock(&subsystem_list_lock);
188 return subsys;
189 }
190 mutex_unlock(&subsystem_list_lock);
191
192 return NULL;
193}
194
195static struct subsys_soc_restart_order *_update_restart_order(
196 struct subsys_data *subsys)
197{
198 int i, j;
199
200 if (!subsys)
201 return NULL;
202
203 if (!subsys->name)
204 return NULL;
205
206 mutex_lock(&soc_order_reg_lock);
207 for (j = 0; j < n_restart_orders; j++) {
208 for (i = 0; i < restart_orders[j]->count; i++)
209 if (!strncmp(restart_orders[j]->subsystem_list[i],
210 subsys->name, SUBSYS_NAME_MAX_LENGTH)) {
211
212 restart_orders[j]->subsys_ptrs[i] =
213 subsys;
214 mutex_unlock(&soc_order_reg_lock);
215 return restart_orders[j];
216 }
217 }
218
219 mutex_unlock(&soc_order_reg_lock);
220
221 return NULL;
222}
223
224static void _send_notification_to_order(struct subsys_data
225 **restart_list, int count,
226 enum subsys_notif_type notif_type)
227{
228 int i;
229
230 for (i = 0; i < count; i++)
231 if (restart_list[i])
232 subsys_notif_queue_notification(
233 restart_list[i]->notif_handle, notif_type);
234}
235
Vikram Mulukutla96aecfc2011-07-28 18:18:42 -0700236static int max_restarts;
237module_param(max_restarts, int, 0644);
238
239static long max_history_time = 3600;
240module_param(max_history_time, long, 0644);
241
242static void do_epoch_check(struct subsys_data *subsys)
243{
244 int n = 0;
245 struct timeval *time_first, *curr_time;
246 struct restart_log *r_log, *temp;
247 static int max_restarts_check;
248 static long max_history_time_check;
249
250 mutex_lock(&restart_log_mutex);
251
252 max_restarts_check = max_restarts;
253 max_history_time_check = max_history_time;
254
255 /* Check if epoch checking is enabled */
256 if (!max_restarts_check)
257 return;
258
259 r_log = kmalloc(sizeof(struct restart_log), GFP_KERNEL);
260 r_log->subsys = subsys;
261 do_gettimeofday(&r_log->time);
262 curr_time = &r_log->time;
263 INIT_LIST_HEAD(&r_log->list);
264
265 list_add_tail(&r_log->list, &restart_log_list);
266
267 list_for_each_entry_safe(r_log, temp, &restart_log_list, list) {
268
269 if ((curr_time->tv_sec - r_log->time.tv_sec) >
270 max_history_time_check) {
271
272 pr_debug("Deleted node with restart_time = %ld\n",
273 r_log->time.tv_sec);
274 list_del(&r_log->list);
275 kfree(r_log);
276 continue;
277 }
278 if (!n) {
279 time_first = &r_log->time;
280 pr_debug("time_first: %ld", time_first->tv_sec);
281 }
282 n++;
283 pr_debug("restart_time: %ld\n", r_log->time.tv_sec);
284 }
285
286 if (n >= max_restarts_check) {
287 if ((curr_time->tv_sec - time_first->tv_sec) <
288 max_history_time_check)
289 panic("Subsystems have crashed %d times in less than "
290 "%ld seconds!", max_restarts_check,
291 max_history_time_check);
292 }
293
294 mutex_unlock(&restart_log_mutex);
295}
296
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700297static int subsystem_restart_thread(void *data)
298{
299 struct restart_thread_data *r_work = data;
300 struct subsys_data **restart_list;
301 struct subsys_data *subsys = r_work->subsys;
302 struct subsys_soc_restart_order *soc_restart_order = NULL;
303
304 struct mutex *powerup_lock;
305 struct mutex *shutdown_lock;
306
307 int i;
308 int restart_list_count = 0;
309
310 if (r_work->coupled)
311 soc_restart_order = subsys->restart_order;
312
313 /* It's OK to not take the registration lock at this point.
314 * This is because the subsystem list inside the relevant
315 * restart order is not being traversed.
316 */
317 if (!soc_restart_order) {
318 restart_list = subsys->single_restart_list;
319 restart_list_count = 1;
320 powerup_lock = &subsys->powerup_lock;
321 shutdown_lock = &subsys->shutdown_lock;
322 } else {
323 restart_list = soc_restart_order->subsys_ptrs;
324 restart_list_count = soc_restart_order->count;
325 powerup_lock = &soc_restart_order->powerup_lock;
326 shutdown_lock = &soc_restart_order->shutdown_lock;
327 }
328
329 dprintk("%s[%p]: Attempting to get shutdown lock!\n", __func__,
330 current);
331
332 /* Try to acquire shutdown_lock. If this fails, these subsystems are
333 * already being restarted - return.
334 */
335 if (!mutex_trylock(shutdown_lock)) {
336 kfree(data);
337 do_exit(0);
338 }
339
340 dprintk("%s[%p]: Attempting to get powerup lock!\n", __func__,
341 current);
342
343 /* Now that we've acquired the shutdown lock, either we're the first to
344 * restart these subsystems or some other thread is doing the powerup
345 * sequence for these subsystems. In the latter case, panic and bail
346 * out, since a subsystem died in its powerup sequence.
347 */
348 if (!mutex_trylock(powerup_lock))
349 panic("%s: Subsystem died during powerup!", __func__);
350
Vikram Mulukutla96aecfc2011-07-28 18:18:42 -0700351 do_epoch_check(subsys);
352
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700353 /* Now it is necessary to take the registration lock. This is because
354 * the subsystem list in the SoC restart order will be traversed
355 * and it shouldn't be changed until _this_ restart sequence completes.
356 */
357 mutex_lock(&soc_order_reg_lock);
358
359 dprintk("%s: Starting restart sequence for %s\n", __func__,
360 r_work->subsys->name);
361
362 _send_notification_to_order(restart_list,
363 restart_list_count,
364 SUBSYS_BEFORE_SHUTDOWN);
365
366 for (i = 0; i < restart_list_count; i++) {
367
368 if (!restart_list[i])
369 continue;
370
371 pr_info("subsys-restart: Shutting down %s\n",
372 restart_list[i]->name);
373
374 if (restart_list[i]->shutdown(subsys) < 0)
375 panic("%s: Failed to shutdown %s!\n", __func__,
376 restart_list[i]->name);
377 }
378
379 _send_notification_to_order(restart_list, restart_list_count,
380 SUBSYS_AFTER_SHUTDOWN);
381
382 /* Now that we've finished shutting down these subsystems, release the
383 * shutdown lock. If a subsystem restart request comes in for a
384 * subsystem in _this_ restart order after the unlock below, and
385 * before the powerup lock is released, panic and bail out.
386 */
387 mutex_unlock(shutdown_lock);
388
389 /* Collect ram dumps for all subsystems in order here */
390 for (i = 0; i < restart_list_count; i++) {
391 if (!restart_list[i])
392 continue;
393
394 if (restart_list[i]->ramdump)
395 if (restart_list[i]->ramdump(enable_ramdumps,
396 subsys) < 0)
397 pr_warn("%s(%s): Ramdump failed.", __func__,
398 restart_list[i]->name);
399 }
400
401 _send_notification_to_order(restart_list,
402 restart_list_count,
403 SUBSYS_BEFORE_POWERUP);
404
405 for (i = restart_list_count - 1; i >= 0; i--) {
406
407 if (!restart_list[i])
408 continue;
409
410 pr_info("subsys-restart: Powering up %s\n",
411 restart_list[i]->name);
412
413 if (restart_list[i]->powerup(subsys) < 0)
414 panic("%s: Failed to powerup %s!", __func__,
415 restart_list[i]->name);
416 }
417
418 _send_notification_to_order(restart_list,
419 restart_list_count,
420 SUBSYS_AFTER_POWERUP);
421
422 pr_info("%s: Restart sequence for %s completed.", __func__,
423 r_work->subsys->name);
424
425 mutex_unlock(powerup_lock);
426
427 mutex_unlock(&soc_order_reg_lock);
428
429 dprintk("%s: Released powerup lock!\n", __func__);
430
431 kfree(data);
432 do_exit(0);
433}
434
435int subsystem_restart(const char *subsys_name)
436{
437 struct subsys_data *subsys;
438 struct task_struct *tsk;
439 struct restart_thread_data *data = NULL;
440
441 if (!subsys_name) {
442 pr_err("%s: Invalid subsystem name.", __func__);
443 return -EINVAL;
444 }
445
446 pr_info("Subsystem Restart: Restart sequence requested for %s\n",
447 subsys_name);
448
449 /* List of subsystems is protected by a lock. New subsystems can
450 * still come in.
451 */
452 subsys = _find_subsystem(subsys_name);
453
454 if (!subsys) {
455 pr_warn("%s: Unregistered subsystem %s!", __func__,
456 subsys_name);
457 return -EINVAL;
458 }
459
460 if (restart_level != RESET_SOC) {
461 data = kzalloc(sizeof(struct restart_thread_data), GFP_KERNEL);
462 if (!data) {
463 restart_level = RESET_SOC;
464 pr_warn("%s: Failed to alloc restart data. Resetting.",
465 __func__);
466 } else {
467 if (restart_level == RESET_SUBSYS_COUPLED ||
468 restart_level == RESET_SUBSYS_MIXED)
469 data->coupled = 1;
470 else
471 data->coupled = 0;
472
473 data->subsys = subsys;
474 }
475 }
476
477 switch (restart_level) {
478
479 case RESET_SUBSYS_COUPLED:
480 case RESET_SUBSYS_MIXED:
481 case RESET_SUBSYS_INDEPENDENT:
482 dprintk("%s: Restarting %s [level=%d]!\n", __func__,
483 subsys_name, restart_level);
484
485 /* Let the kthread handle the actual restarting. Using a
486 * workqueue will not work since all restart requests are
487 * serialized and it prevents the short circuiting of
488 * restart requests for subsystems already in a restart
489 * sequence.
490 */
491 tsk = kthread_run(subsystem_restart_thread, data,
492 "subsystem_subsystem_restart_thread");
493 if (IS_ERR(tsk))
494 panic("%s: Unable to create thread to restart %s",
495 __func__, subsys->name);
496
497 break;
498
499 case RESET_SOC:
500
501 mutex_lock(&subsystem_list_lock);
502 list_for_each_entry(subsys, &subsystem_list, list)
503 if (subsys->crash_shutdown)
504 subsys->crash_shutdown(subsys);
505 mutex_unlock(&subsystem_list_lock);
506
507 panic("Resetting the SOC");
508 break;
509
510 default:
511 panic("subsys-restart: Unknown restart level!\n");
512 break;
513
514 }
515
516 return 0;
517}
518EXPORT_SYMBOL(subsystem_restart);
519
520int ssr_register_subsystem(struct subsys_data *subsys)
521{
522 if (!subsys)
523 goto err;
524
525 if (!subsys->name)
526 goto err;
527
528 if (!subsys->powerup || !subsys->shutdown)
529 goto err;
530
531 subsys->notif_handle = subsys_notif_add_subsys(subsys->name);
532 subsys->restart_order = _update_restart_order(subsys);
533 subsys->single_restart_list[0] = subsys;
534
535 mutex_init(&subsys->shutdown_lock);
536 mutex_init(&subsys->powerup_lock);
537
538 mutex_lock(&subsystem_list_lock);
539 list_add(&subsys->list, &subsystem_list);
540 mutex_unlock(&subsystem_list_lock);
541
542 return 0;
543
544err:
545 return -EINVAL;
546}
547EXPORT_SYMBOL(ssr_register_subsystem);
548
549static int __init ssr_init_soc_restart_orders(void)
550{
551 int i;
552
553 if (cpu_is_msm8x60()) {
554 for (i = 0; i < ARRAY_SIZE(orders_8x60_all); i++) {
555 mutex_init(&orders_8x60_all[i]->powerup_lock);
556 mutex_init(&orders_8x60_all[i]->shutdown_lock);
557 }
558
559 for (i = 0; i < ARRAY_SIZE(orders_8x60_modems); i++) {
560 mutex_init(&orders_8x60_modems[i]->powerup_lock);
561 mutex_init(&orders_8x60_modems[i]->shutdown_lock);
562 }
563
564 restart_orders = orders_8x60_all;
565 n_restart_orders = ARRAY_SIZE(orders_8x60_all);
566 }
567
568 if (cpu_is_msm8960()) {
569 restart_orders = restart_orders_8960;
570 n_restart_orders = ARRAY_SIZE(restart_orders_8960);
571 }
572
573 if (restart_orders == NULL || n_restart_orders < 1) {
574 WARN_ON(1);
575 return -EINVAL;
576 }
577
578 return 0;
579}
580
581static int __init subsys_restart_init(void)
582{
583 int ret = 0;
584
585 restart_level = RESET_SOC;
586
587 ret = ssr_init_soc_restart_orders();
588
589 return ret;
590}
591
592arch_initcall(subsys_restart_init);
593
594MODULE_DESCRIPTION("Subsystem Restart Driver");
595MODULE_LICENSE("GPL v2");