blob: c3fd8c5357c6453363ded559302ce416092f392a [file] [log] [blame]
Rohit Vaswanid0fb4182012-03-19 18:07:59 -07001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
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
Vikram Mulukutlaa5dd6112011-09-14 14:12:33 -070013#define pr_fmt(fmt) "subsys-restart: %s(): " fmt, __func__
14
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070015#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/uaccess.h>
18#include <linux/module.h>
19#include <linux/fs.h>
20#include <linux/proc_fs.h>
21#include <linux/delay.h>
22#include <linux/list.h>
23#include <linux/io.h>
24#include <linux/kthread.h>
Vikram Mulukutla96aecfc2011-07-28 18:18:42 -070025#include <linux/time.h>
Vikram Mulukutlaf6349ae2012-02-24 12:21:15 -080026#include <linux/wakelock.h>
27#include <linux/suspend.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070028
29#include <asm/current.h>
30
31#include <mach/peripheral-loader.h>
32#include <mach/scm.h>
33#include <mach/socinfo.h>
34#include <mach/subsystem_notif.h>
35#include <mach/subsystem_restart.h>
36
37#include "smd_private.h"
38
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039struct subsys_soc_restart_order {
40 const char * const *subsystem_list;
41 int count;
42
43 struct mutex shutdown_lock;
44 struct mutex powerup_lock;
45 struct subsys_data *subsys_ptrs[];
46};
47
48struct restart_thread_data {
49 struct subsys_data *subsys;
Vikram Mulukutlaf6349ae2012-02-24 12:21:15 -080050 struct wake_lock ssr_wake_lock;
51 char wakelockname[64];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070052 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
Rohit Vaswani56dd22a2011-11-11 16:21:28 -0800146 if (cpu_is_msm9615()) {
147 pr_err("Only Phase 1 subsystem restart is supported\n");
148 return -EINVAL;
149 }
150
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700151 ret = param_set_int(val, kp);
152 if (ret)
153 return ret;
154
155 switch (restart_level) {
156
157 case RESET_SOC:
158 case RESET_SUBSYS_COUPLED:
159 case RESET_SUBSYS_INDEPENDENT:
Vikram Mulukutlaa5dd6112011-09-14 14:12:33 -0700160 pr_info("Phase %d behavior activated.\n", restart_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700161 break;
162
163 case RESET_SUBSYS_MIXED:
Vikram Mulukutlaa5dd6112011-09-14 14:12:33 -0700164 pr_info("Phase 2+ behavior activated.\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700165 break;
166
167 default:
168 restart_level = old_val;
169 return -EINVAL;
170 break;
171
172 }
173
174 if (restart_level != old_val)
175 restart_level_changed();
176
177 return 0;
178}
179
180module_param_call(restart_level, restart_level_set, param_get_int,
181 &restart_level, 0644);
182
183static struct subsys_data *_find_subsystem(const char *subsys_name)
184{
185 struct subsys_data *subsys;
186
187 mutex_lock(&subsystem_list_lock);
188 list_for_each_entry(subsys, &subsystem_list, list)
189 if (!strncmp(subsys->name, subsys_name,
190 SUBSYS_NAME_MAX_LENGTH)) {
191 mutex_unlock(&subsystem_list_lock);
192 return subsys;
193 }
194 mutex_unlock(&subsystem_list_lock);
195
196 return NULL;
197}
198
199static struct subsys_soc_restart_order *_update_restart_order(
200 struct subsys_data *subsys)
201{
202 int i, j;
203
204 if (!subsys)
205 return NULL;
206
207 if (!subsys->name)
208 return NULL;
209
210 mutex_lock(&soc_order_reg_lock);
211 for (j = 0; j < n_restart_orders; j++) {
212 for (i = 0; i < restart_orders[j]->count; i++)
213 if (!strncmp(restart_orders[j]->subsystem_list[i],
214 subsys->name, SUBSYS_NAME_MAX_LENGTH)) {
215
216 restart_orders[j]->subsys_ptrs[i] =
217 subsys;
218 mutex_unlock(&soc_order_reg_lock);
219 return restart_orders[j];
220 }
221 }
222
223 mutex_unlock(&soc_order_reg_lock);
224
225 return NULL;
226}
227
228static void _send_notification_to_order(struct subsys_data
229 **restart_list, int count,
230 enum subsys_notif_type notif_type)
231{
232 int i;
233
234 for (i = 0; i < count; i++)
235 if (restart_list[i])
236 subsys_notif_queue_notification(
237 restart_list[i]->notif_handle, notif_type);
238}
239
Vikram Mulukutla96aecfc2011-07-28 18:18:42 -0700240static int max_restarts;
241module_param(max_restarts, int, 0644);
242
243static long max_history_time = 3600;
244module_param(max_history_time, long, 0644);
245
246static void do_epoch_check(struct subsys_data *subsys)
247{
248 int n = 0;
Jordan Crouse75a25ca2011-09-09 12:49:57 -0600249 struct timeval *time_first = NULL, *curr_time;
Vikram Mulukutla96aecfc2011-07-28 18:18:42 -0700250 struct restart_log *r_log, *temp;
251 static int max_restarts_check;
252 static long max_history_time_check;
253
254 mutex_lock(&restart_log_mutex);
255
256 max_restarts_check = max_restarts;
257 max_history_time_check = max_history_time;
258
259 /* Check if epoch checking is enabled */
260 if (!max_restarts_check)
Vikram Mulukutla7a289092011-09-14 10:08:36 -0700261 goto out;
Vikram Mulukutla96aecfc2011-07-28 18:18:42 -0700262
263 r_log = kmalloc(sizeof(struct restart_log), GFP_KERNEL);
Matt Wagantalleecca342011-11-10 20:12:05 -0800264 if (!r_log)
265 goto out;
Vikram Mulukutla96aecfc2011-07-28 18:18:42 -0700266 r_log->subsys = subsys;
267 do_gettimeofday(&r_log->time);
268 curr_time = &r_log->time;
269 INIT_LIST_HEAD(&r_log->list);
270
271 list_add_tail(&r_log->list, &restart_log_list);
272
273 list_for_each_entry_safe(r_log, temp, &restart_log_list, list) {
274
275 if ((curr_time->tv_sec - r_log->time.tv_sec) >
276 max_history_time_check) {
277
278 pr_debug("Deleted node with restart_time = %ld\n",
279 r_log->time.tv_sec);
280 list_del(&r_log->list);
281 kfree(r_log);
282 continue;
283 }
284 if (!n) {
285 time_first = &r_log->time;
Vikram Mulukutlaa5dd6112011-09-14 14:12:33 -0700286 pr_debug("Time_first: %ld\n", time_first->tv_sec);
Vikram Mulukutla96aecfc2011-07-28 18:18:42 -0700287 }
288 n++;
Vikram Mulukutlaa5dd6112011-09-14 14:12:33 -0700289 pr_debug("Restart_time: %ld\n", r_log->time.tv_sec);
Vikram Mulukutla96aecfc2011-07-28 18:18:42 -0700290 }
291
Jordan Crouse75a25ca2011-09-09 12:49:57 -0600292 if (time_first && n >= max_restarts_check) {
Vikram Mulukutla96aecfc2011-07-28 18:18:42 -0700293 if ((curr_time->tv_sec - time_first->tv_sec) <
294 max_history_time_check)
295 panic("Subsystems have crashed %d times in less than "
296 "%ld seconds!", max_restarts_check,
297 max_history_time_check);
298 }
299
Vikram Mulukutla7a289092011-09-14 10:08:36 -0700300out:
Vikram Mulukutla96aecfc2011-07-28 18:18:42 -0700301 mutex_unlock(&restart_log_mutex);
302}
303
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700304static int subsystem_restart_thread(void *data)
305{
306 struct restart_thread_data *r_work = data;
307 struct subsys_data **restart_list;
308 struct subsys_data *subsys = r_work->subsys;
309 struct subsys_soc_restart_order *soc_restart_order = NULL;
310
311 struct mutex *powerup_lock;
312 struct mutex *shutdown_lock;
313
314 int i;
315 int restart_list_count = 0;
316
317 if (r_work->coupled)
318 soc_restart_order = subsys->restart_order;
319
320 /* It's OK to not take the registration lock at this point.
321 * This is because the subsystem list inside the relevant
322 * restart order is not being traversed.
323 */
324 if (!soc_restart_order) {
325 restart_list = subsys->single_restart_list;
326 restart_list_count = 1;
327 powerup_lock = &subsys->powerup_lock;
328 shutdown_lock = &subsys->shutdown_lock;
329 } else {
330 restart_list = soc_restart_order->subsys_ptrs;
331 restart_list_count = soc_restart_order->count;
332 powerup_lock = &soc_restart_order->powerup_lock;
333 shutdown_lock = &soc_restart_order->shutdown_lock;
334 }
335
Vikram Mulukutlaa5dd6112011-09-14 14:12:33 -0700336 pr_debug("[%p]: Attempting to get shutdown lock!\n", current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700337
338 /* Try to acquire shutdown_lock. If this fails, these subsystems are
339 * already being restarted - return.
340 */
Vikram Mulukutlaf6349ae2012-02-24 12:21:15 -0800341 if (!mutex_trylock(shutdown_lock))
342 goto out;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700343
Vikram Mulukutlaa5dd6112011-09-14 14:12:33 -0700344 pr_debug("[%p]: Attempting to get powerup lock!\n", current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700345
346 /* Now that we've acquired the shutdown lock, either we're the first to
347 * restart these subsystems or some other thread is doing the powerup
348 * sequence for these subsystems. In the latter case, panic and bail
349 * out, since a subsystem died in its powerup sequence.
350 */
351 if (!mutex_trylock(powerup_lock))
Vikram Mulukutlaa5dd6112011-09-14 14:12:33 -0700352 panic("%s[%p]: Subsystem died during powerup!",
353 __func__, current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700354
Vikram Mulukutla96aecfc2011-07-28 18:18:42 -0700355 do_epoch_check(subsys);
356
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700357 /* Now it is necessary to take the registration lock. This is because
358 * the subsystem list in the SoC restart order will be traversed
359 * and it shouldn't be changed until _this_ restart sequence completes.
360 */
361 mutex_lock(&soc_order_reg_lock);
362
Vikram Mulukutlaa5dd6112011-09-14 14:12:33 -0700363 pr_debug("[%p]: Starting restart sequence for %s\n", current,
364 r_work->subsys->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700365
366 _send_notification_to_order(restart_list,
367 restart_list_count,
368 SUBSYS_BEFORE_SHUTDOWN);
369
370 for (i = 0; i < restart_list_count; i++) {
371
372 if (!restart_list[i])
373 continue;
374
Vikram Mulukutlaa5dd6112011-09-14 14:12:33 -0700375 pr_info("[%p]: Shutting down %s\n", current,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700376 restart_list[i]->name);
377
378 if (restart_list[i]->shutdown(subsys) < 0)
Vikram Mulukutlaa5dd6112011-09-14 14:12:33 -0700379 panic("subsys-restart: %s[%p]: Failed to shutdown %s!",
380 __func__, current, restart_list[i]->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700381 }
382
383 _send_notification_to_order(restart_list, restart_list_count,
384 SUBSYS_AFTER_SHUTDOWN);
385
386 /* Now that we've finished shutting down these subsystems, release the
387 * shutdown lock. If a subsystem restart request comes in for a
388 * subsystem in _this_ restart order after the unlock below, and
389 * before the powerup lock is released, panic and bail out.
390 */
391 mutex_unlock(shutdown_lock);
392
393 /* Collect ram dumps for all subsystems in order here */
394 for (i = 0; i < restart_list_count; i++) {
395 if (!restart_list[i])
396 continue;
397
398 if (restart_list[i]->ramdump)
399 if (restart_list[i]->ramdump(enable_ramdumps,
400 subsys) < 0)
Vikram Mulukutlaa5dd6112011-09-14 14:12:33 -0700401 pr_warn("%s[%p]: Ramdump failed.\n",
402 restart_list[i]->name, current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700403 }
404
405 _send_notification_to_order(restart_list,
406 restart_list_count,
407 SUBSYS_BEFORE_POWERUP);
408
409 for (i = restart_list_count - 1; i >= 0; i--) {
410
411 if (!restart_list[i])
412 continue;
413
Vikram Mulukutlaa5dd6112011-09-14 14:12:33 -0700414 pr_info("[%p]: Powering up %s\n", current,
415 restart_list[i]->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700416
417 if (restart_list[i]->powerup(subsys) < 0)
Vikram Mulukutlaa5dd6112011-09-14 14:12:33 -0700418 panic("%s[%p]: Failed to powerup %s!", __func__,
419 current, restart_list[i]->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700420 }
421
422 _send_notification_to_order(restart_list,
423 restart_list_count,
424 SUBSYS_AFTER_POWERUP);
425
Vikram Mulukutlaa5dd6112011-09-14 14:12:33 -0700426 pr_info("[%p]: Restart sequence for %s completed.\n",
427 current, r_work->subsys->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700428
429 mutex_unlock(powerup_lock);
430
431 mutex_unlock(&soc_order_reg_lock);
432
Vikram Mulukutlaa5dd6112011-09-14 14:12:33 -0700433 pr_debug("[%p]: Released powerup lock!\n", current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700434
Vikram Mulukutlaf6349ae2012-02-24 12:21:15 -0800435out:
436 wake_unlock(&r_work->ssr_wake_lock);
437 wake_lock_destroy(&r_work->ssr_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700438 kfree(data);
439 do_exit(0);
440}
441
442int subsystem_restart(const char *subsys_name)
443{
444 struct subsys_data *subsys;
445 struct task_struct *tsk;
446 struct restart_thread_data *data = NULL;
447
448 if (!subsys_name) {
Vikram Mulukutlaa5dd6112011-09-14 14:12:33 -0700449 pr_err("Invalid subsystem name.\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700450 return -EINVAL;
451 }
452
Vikram Mulukutla3b24c8c2011-12-02 15:12:53 -0800453 pr_info("Restart sequence requested for %s, restart_level = %d.\n",
454 subsys_name, restart_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700455
456 /* List of subsystems is protected by a lock. New subsystems can
457 * still come in.
458 */
459 subsys = _find_subsystem(subsys_name);
460
461 if (!subsys) {
Vikram Mulukutlaa5dd6112011-09-14 14:12:33 -0700462 pr_warn("Unregistered subsystem %s!\n", subsys_name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700463 return -EINVAL;
464 }
465
466 if (restart_level != RESET_SOC) {
467 data = kzalloc(sizeof(struct restart_thread_data), GFP_KERNEL);
468 if (!data) {
469 restart_level = RESET_SOC;
Vikram Mulukutlaa5dd6112011-09-14 14:12:33 -0700470 pr_warn("Failed to alloc restart data. Resetting.\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700471 } else {
472 if (restart_level == RESET_SUBSYS_COUPLED ||
473 restart_level == RESET_SUBSYS_MIXED)
474 data->coupled = 1;
475 else
476 data->coupled = 0;
477
478 data->subsys = subsys;
479 }
480 }
481
482 switch (restart_level) {
483
484 case RESET_SUBSYS_COUPLED:
485 case RESET_SUBSYS_MIXED:
486 case RESET_SUBSYS_INDEPENDENT:
Vikram Mulukutlaa5dd6112011-09-14 14:12:33 -0700487 pr_debug("Restarting %s [level=%d]!\n", subsys_name,
488 restart_level);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700489
Vikram Mulukutlaf6349ae2012-02-24 12:21:15 -0800490 snprintf(data->wakelockname, sizeof(data->wakelockname),
491 "ssr(%s)", subsys_name);
492 wake_lock_init(&data->ssr_wake_lock, WAKE_LOCK_SUSPEND,
493 data->wakelockname);
494 wake_lock(&data->ssr_wake_lock);
495
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700496 /* Let the kthread handle the actual restarting. Using a
497 * workqueue will not work since all restart requests are
498 * serialized and it prevents the short circuiting of
499 * restart requests for subsystems already in a restart
500 * sequence.
501 */
502 tsk = kthread_run(subsystem_restart_thread, data,
Vikram Mulukutlaa5dd6112011-09-14 14:12:33 -0700503 "subsystem_restart_thread");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700504 if (IS_ERR(tsk))
505 panic("%s: Unable to create thread to restart %s",
506 __func__, subsys->name);
507
508 break;
509
510 case RESET_SOC:
Vikram Mulukutla3b24c8c2011-12-02 15:12:53 -0800511 panic("subsys-restart: Resetting the SoC - %s crashed.",
512 subsys->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700513 break;
514
515 default:
516 panic("subsys-restart: Unknown restart level!\n");
517 break;
518
519 }
520
521 return 0;
522}
523EXPORT_SYMBOL(subsystem_restart);
524
525int ssr_register_subsystem(struct subsys_data *subsys)
526{
527 if (!subsys)
528 goto err;
529
530 if (!subsys->name)
531 goto err;
532
533 if (!subsys->powerup || !subsys->shutdown)
534 goto err;
535
536 subsys->notif_handle = subsys_notif_add_subsys(subsys->name);
537 subsys->restart_order = _update_restart_order(subsys);
538 subsys->single_restart_list[0] = subsys;
539
540 mutex_init(&subsys->shutdown_lock);
541 mutex_init(&subsys->powerup_lock);
542
543 mutex_lock(&subsystem_list_lock);
544 list_add(&subsys->list, &subsystem_list);
545 mutex_unlock(&subsystem_list_lock);
546
547 return 0;
548
549err:
550 return -EINVAL;
551}
552EXPORT_SYMBOL(ssr_register_subsystem);
553
Vikram Mulukutla2a7ea7e2011-09-06 11:38:47 -0700554static int ssr_panic_handler(struct notifier_block *this,
555 unsigned long event, void *ptr)
556{
557 struct subsys_data *subsys;
558
559 list_for_each_entry(subsys, &subsystem_list, list)
560 if (subsys->crash_shutdown)
561 subsys->crash_shutdown(subsys);
562 return NOTIFY_DONE;
563}
564
565static struct notifier_block panic_nb = {
566 .notifier_call = ssr_panic_handler,
567};
568
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700569static int __init ssr_init_soc_restart_orders(void)
570{
571 int i;
572
Vikram Mulukutla2a7ea7e2011-09-06 11:38:47 -0700573 atomic_notifier_chain_register(&panic_notifier_list,
574 &panic_nb);
575
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700576 if (cpu_is_msm8x60()) {
577 for (i = 0; i < ARRAY_SIZE(orders_8x60_all); i++) {
578 mutex_init(&orders_8x60_all[i]->powerup_lock);
579 mutex_init(&orders_8x60_all[i]->shutdown_lock);
580 }
581
582 for (i = 0; i < ARRAY_SIZE(orders_8x60_modems); i++) {
583 mutex_init(&orders_8x60_modems[i]->powerup_lock);
584 mutex_init(&orders_8x60_modems[i]->shutdown_lock);
585 }
586
587 restart_orders = orders_8x60_all;
588 n_restart_orders = ARRAY_SIZE(orders_8x60_all);
589 }
590
Rohit Vaswanid0fb4182012-03-19 18:07:59 -0700591 if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm9615() ||
592 cpu_is_apq8064()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700593 restart_orders = restart_orders_8960;
594 n_restart_orders = ARRAY_SIZE(restart_orders_8960);
595 }
596
597 if (restart_orders == NULL || n_restart_orders < 1) {
598 WARN_ON(1);
599 return -EINVAL;
600 }
601
602 return 0;
603}
604
605static int __init subsys_restart_init(void)
606{
607 int ret = 0;
608
609 restart_level = RESET_SOC;
610
611 ret = ssr_init_soc_restart_orders();
612
613 return ret;
614}
615
616arch_initcall(subsys_restart_init);
617
618MODULE_DESCRIPTION("Subsystem Restart Driver");
619MODULE_LICENSE("GPL v2");