diff options
Diffstat (limited to 'arch/arm/mach-exynos/subsystem_restart.c')
-rw-r--r-- | arch/arm/mach-exynos/subsystem_restart.c | 389 |
1 files changed, 15 insertions, 374 deletions
diff --git a/arch/arm/mach-exynos/subsystem_restart.c b/arch/arm/mach-exynos/subsystem_restart.c index 0a76ab3..a68804f 100644 --- a/arch/arm/mach-exynos/subsystem_restart.c +++ b/arch/arm/mach-exynos/subsystem_restart.c @@ -14,31 +14,16 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/uaccess.h> +#include <linux/slab.h> #include <linux/module.h> -#include <linux/fs.h> -#include <linux/proc_fs.h> #include <linux/delay.h> #include <linux/list.h> #include <linux/io.h> -#include <linux/kthread.h> #include <linux/time.h> #include <linux/wakelock.h> #include <linux/suspend.h> - -#include <asm/current.h> -#ifndef CONFIG_ARCH_EXYNOS -#include <mach/peripheral-loader.h> -#include <mach/scm.h> -#include <mach/socinfo.h> -#endif -#include <mach/subsystem_notif.h> #include <mach/subsystem_restart.h> -#ifndef CONFIG_ARCH_EXYNOS -#include "smd_private.h" -#endif - struct subsys_soc_restart_order { const char * const *subsystem_list; int count; @@ -63,7 +48,7 @@ struct restart_log { }; static int restart_level; -static int enable_ramdumps = 1; +static int mdm_dump = 1; struct workqueue_struct *ssr_wq; static LIST_HEAD(restart_log_list); @@ -72,130 +57,11 @@ static DEFINE_MUTEX(subsystem_list_lock); static DEFINE_MUTEX(soc_order_reg_lock); static DEFINE_MUTEX(restart_log_mutex); -/* SOC specific restart orders go here */ - -#define DEFINE_SINGLE_RESTART_ORDER(name, order) \ - static struct subsys_soc_restart_order __##name = { \ - .subsystem_list = order, \ - .count = ARRAY_SIZE(order), \ - .subsys_ptrs = {[ARRAY_SIZE(order)] = NULL} \ - }; \ - static struct subsys_soc_restart_order *name[] = { \ - &__##name, \ - } - -#ifndef CONFIG_ARCH_EXYNOS -/* MSM 8x60 restart ordering info */ -static const char * const _order_8x60_all[] = { - "external_modem", "modem", "lpass" -}; -DEFINE_SINGLE_RESTART_ORDER(orders_8x60_all, _order_8x60_all); - -static const char * const _order_8x60_modems[] = {"external_modem", "modem"}; -DEFINE_SINGLE_RESTART_ORDER(orders_8x60_modems, _order_8x60_modems); -#else /* CONFIG_ARCH_EXYNOS */ -/* MSM 8x60 restart ordering info */ -static const char * const _order_8x60_all[] = { - "external_modem", -}; -DEFINE_SINGLE_RESTART_ORDER(orders_8x60_all, _order_8x60_all); - -static const char * const _order_8x60_modems[] = {"external_modem"}; -DEFINE_SINGLE_RESTART_ORDER(orders_8x60_modems, _order_8x60_modems); -#endif - -/* MSM 8960 restart ordering info */ -static const char * const order_8960[] = {"modem", "lpass"}; - -static struct subsys_soc_restart_order restart_orders_8960_one = { - .subsystem_list = order_8960, - .count = ARRAY_SIZE(order_8960), - .subsys_ptrs = {[ARRAY_SIZE(order_8960)] = NULL} - }; - -static struct subsys_soc_restart_order *restart_orders_8960[] = { - &restart_orders_8960_one, -}; /* These will be assigned to one of the sets above after * runtime SoC identification. */ -static struct subsys_soc_restart_order **restart_orders; -static int n_restart_orders; - -module_param(enable_ramdumps, int, S_IRUGO | S_IWUSR); - -static struct subsys_soc_restart_order *_update_restart_order( - struct subsys_data *subsys); - -#ifndef CONFIG_ARCH_EXYNOS -int get_restart_level() -{ - return restart_level; -} -EXPORT_SYMBOL(get_restart_level); - -static void restart_level_changed(void) -{ - struct subsys_data *subsys; - - if (cpu_is_msm8x60() && restart_level == RESET_SUBSYS_COUPLED) { - restart_orders = orders_8x60_all; - n_restart_orders = ARRAY_SIZE(orders_8x60_all); - } - - if (cpu_is_msm8x60() && restart_level == RESET_SUBSYS_MIXED) { - restart_orders = orders_8x60_modems; - n_restart_orders = ARRAY_SIZE(orders_8x60_modems); - } - - mutex_lock(&subsystem_list_lock); - list_for_each_entry(subsys, &subsystem_list, list) - subsys->restart_order = _update_restart_order(subsys); - mutex_unlock(&subsystem_list_lock); -} - -static int restart_level_set(const char *val, struct kernel_param *kp) -{ - int ret; - int old_val = restart_level; - - if (cpu_is_msm9615()) { - pr_err("Only Phase 1 subsystem restart is supported\n"); - return -EINVAL; - } - - ret = param_set_int(val, kp); - if (ret) - return ret; - - switch (restart_level) { - - case RESET_SOC: - case RESET_SUBSYS_COUPLED: - case RESET_SUBSYS_INDEPENDENT: - pr_info("Phase %d behavior activated.\n", restart_level); - break; - - case RESET_SUBSYS_MIXED: - pr_info("Phase 2+ behavior activated.\n"); - break; - - default: - restart_level = old_val; - return -EINVAL; - break; +module_param(mdm_dump, int, S_IRUGO | S_IWUSR); - } - - if (restart_level != old_val) - restart_level_changed(); - - return 0; -} - -module_param_call(restart_level, restart_level_set, param_get_int, - &restart_level, 0644); -#endif static struct subsys_data *_find_subsystem(const char *subsys_name) { struct subsys_data *subsys; @@ -212,118 +78,18 @@ static struct subsys_data *_find_subsystem(const char *subsys_name) return NULL; } -static struct subsys_soc_restart_order *_update_restart_order( - struct subsys_data *subsys) -{ - int i, j; - - if (!subsys) - return NULL; - - if (!subsys->name) - return NULL; - - mutex_lock(&soc_order_reg_lock); - for (j = 0; j < n_restart_orders; j++) { - for (i = 0; i < restart_orders[j]->count; i++) - if (!strncmp(restart_orders[j]->subsystem_list[i], - subsys->name, SUBSYS_NAME_MAX_LENGTH)) { - - restart_orders[j]->subsys_ptrs[i] = - subsys; - mutex_unlock(&soc_order_reg_lock); - return restart_orders[j]; - } - } - - mutex_unlock(&soc_order_reg_lock); - - return NULL; -} - -static void _send_notification_to_order(struct subsys_data - **restart_list, int count, - enum subsys_notif_type notif_type) -{ - int i; - - for (i = 0; i < count; i++) - if (restart_list[i]) - subsys_notif_queue_notification( - restart_list[i]->notif_handle, notif_type); -} - static int max_restarts; module_param(max_restarts, int, 0644); static long max_history_time = 3600; module_param(max_history_time, long, 0644); -static void do_epoch_check(struct subsys_data *subsys) -{ - int n = 0; - struct timeval *time_first = NULL, *curr_time; - struct restart_log *r_log, *temp; - static int max_restarts_check; - static long max_history_time_check; - - mutex_lock(&restart_log_mutex); - - max_restarts_check = max_restarts; - max_history_time_check = max_history_time; - - /* Check if epoch checking is enabled */ - if (!max_restarts_check) - goto out; - - r_log = kmalloc(sizeof(struct restart_log), GFP_KERNEL); - if (!r_log) - goto out; - r_log->subsys = subsys; - do_gettimeofday(&r_log->time); - curr_time = &r_log->time; - INIT_LIST_HEAD(&r_log->list); - - list_add_tail(&r_log->list, &restart_log_list); - - list_for_each_entry_safe(r_log, temp, &restart_log_list, list) { - - if ((curr_time->tv_sec - r_log->time.tv_sec) > - max_history_time_check) { - - pr_debug("Deleted node with restart_time = %ld\n", - r_log->time.tv_sec); - list_del(&r_log->list); - kfree(r_log); - continue; - } - if (!n) { - time_first = &r_log->time; - pr_debug("Time_first: %ld\n", time_first->tv_sec); - } - n++; - pr_debug("Restart_time: %ld\n", r_log->time.tv_sec); - } - - if (time_first && n >= max_restarts_check) { - if ((curr_time->tv_sec - time_first->tv_sec) < - max_history_time_check) - panic("Subsystems have crashed %d times in less than " - "%ld seconds!", max_restarts_check, - max_history_time_check); - } - -out: - mutex_unlock(&restart_log_mutex); -} - static void subsystem_restart_wq_func(struct work_struct *work) { struct restart_wq_data *r_work = container_of(work, struct restart_wq_data, work); struct subsys_data **restart_list; struct subsys_data *subsys = r_work->subsys; - struct subsys_soc_restart_order *soc_restart_order = NULL; struct mutex *powerup_lock; struct mutex *shutdown_lock; @@ -331,26 +97,14 @@ static void subsystem_restart_wq_func(struct work_struct *work) int i; int restart_list_count = 0; - if (r_work->coupled) - soc_restart_order = subsys->restart_order; - /* It's OK to not take the registration lock at this point. * This is because the subsystem list inside the relevant * restart order is not being traversed. */ - if (!soc_restart_order) { - pr_info("i am here\n"); - restart_list = subsys->single_restart_list; - restart_list_count = 1; - powerup_lock = &subsys->powerup_lock; - shutdown_lock = &subsys->shutdown_lock; - } else { - pr_info("i am here, 2nd\n"); - restart_list = soc_restart_order->subsys_ptrs; - restart_list_count = soc_restart_order->count; - powerup_lock = &soc_restart_order->powerup_lock; - shutdown_lock = &soc_restart_order->shutdown_lock; - } + restart_list = subsys->single_restart_list; + restart_list_count = 1; + powerup_lock = &subsys->powerup_lock; + shutdown_lock = &subsys->shutdown_lock; pr_info("subsys[%p], powerup lock[%p], shutdown_lock[%p]\n", subsys, powerup_lock, shutdown_lock); @@ -373,8 +127,6 @@ static void subsystem_restart_wq_func(struct work_struct *work) panic("%s[%p]: Subsystem died during powerup!", __func__, current); - do_epoch_check(subsys); - /* Now it is necessary to take the registration lock. This is because * the subsystem list in the SoC restart order will be traversed * and it shouldn't be changed until _this_ restart sequence completes. @@ -384,10 +136,6 @@ static void subsystem_restart_wq_func(struct work_struct *work) pr_info("[%p]: Starting restart sequence for %s\n", current, r_work->subsys->name); - _send_notification_to_order(restart_list, - restart_list_count, - SUBSYS_BEFORE_SHUTDOWN); - for (i = 0; i < restart_list_count; i++) { if (!restart_list[i]) @@ -401,9 +149,6 @@ static void subsystem_restart_wq_func(struct work_struct *work) __func__, current, restart_list[i]->name); } - _send_notification_to_order(restart_list, restart_list_count, - SUBSYS_AFTER_SHUTDOWN); - /* Now that we've finished shutting down these subsystems, release the * shutdown lock. If a subsystem restart request comes in for a * subsystem in _this_ restart order after the unlock below, and @@ -417,16 +162,11 @@ static void subsystem_restart_wq_func(struct work_struct *work) continue; if (restart_list[i]->ramdump) - if (restart_list[i]->ramdump(enable_ramdumps, - subsys) < 0) + if (restart_list[i]->ramdump(mdm_dump, subsys) < 0) pr_warn("%s[%p]: Ramdump failed.\n", restart_list[i]->name, current); } - _send_notification_to_order(restart_list, - restart_list_count, - SUBSYS_BEFORE_POWERUP); - for (i = restart_list_count - 1; i >= 0; i--) { if (!restart_list[i]) @@ -440,10 +180,6 @@ static void subsystem_restart_wq_func(struct work_struct *work) current, restart_list[i]->name); } - _send_notification_to_order(restart_list, - restart_list_count, - SUBSYS_AFTER_POWERUP); - pr_info("[%p]: Restart sequence for %s completed.\n", current, r_work->subsys->name); @@ -457,6 +193,7 @@ out: wake_unlock(&r_work->ssr_wake_lock); wake_lock_destroy(&r_work->ssr_wake_lock); kfree(r_work); + subsys->ongoing = false; } int subsystem_restart(const char *subsys_name) @@ -483,59 +220,15 @@ int subsystem_restart(const char *subsys_name) return -EINVAL; } -#ifndef CONFIG_ARCH_EXYNOS - if (restart_level != RESET_SOC) { - data = kzalloc(sizeof(struct restart_wq_data), GFP_KERNEL); - if (!data) { - restart_level = RESET_SOC; - pr_warn("Failed to alloc restart data. Resetting.\n"); - } else { - if (restart_level == RESET_SUBSYS_COUPLED || - restart_level == RESET_SUBSYS_MIXED) - data->coupled = 1; - else - data->coupled = 0; - - data->subsys = subsys; - } + if (subsys->ongoing) { + pr_warn("subsys-restart: already requested, return busy\n"); + return -EBUSY; } - switch (restart_level) { - - case RESET_SUBSYS_COUPLED: - case RESET_SUBSYS_MIXED: - case RESET_SUBSYS_INDEPENDENT: - pr_debug("Restarting %s [level=%d]!\n", subsys_name, - restart_level); + subsys->ongoing = true; - snprintf(data->wakelockname, sizeof(data->wakelockname), - "ssr(%s)", subsys_name); - wake_lock_init(&data->ssr_wake_lock, WAKE_LOCK_SUSPEND, - data->wakelockname); - wake_lock(&data->ssr_wake_lock); - - INIT_WORK(&data->work, subsystem_restart_wq_func); - rc = schedule_work(&data->work); - - if (rc < 0) - panic("%s: Unable to schedule work to restart %s", - __func__, subsys->name); - break; - - case RESET_SOC: - panic("subsys-restart: Resetting the SoC - %s crashed.", - subsys->name); - break; - - default: - panic("subsys-restart: Unknown restart level!\n"); - break; - - } -#else /* CONFIG_ARCH_EXYNOS */ data = kzalloc(sizeof(struct restart_wq_data), GFP_KERNEL); if (!data) { - restart_level = RESET_SOC; pr_warn("Failed to alloc restart data. Resetting.\n"); panic("subsys-restart: Resetting the SoC - %s crashed.", subsys->name); @@ -553,11 +246,9 @@ int subsystem_restart(const char *subsys_name) INIT_WORK(&data->work, subsystem_restart_wq_func); rc = schedule_work(&data->work); - if (rc < 0) panic("%s: Unable to schedule work to restart %s", __func__, subsys->name); -#endif return 0; } EXPORT_SYMBOL(subsystem_restart); @@ -574,8 +265,6 @@ int ssr_register_subsystem(struct subsys_data *subsys) if (!subsys->powerup || !subsys->shutdown) goto err; - subsys->notif_handle = subsys_notif_add_subsys(subsys->name); - subsys->restart_order = _update_restart_order(subsys); subsys->single_restart_list[0] = subsys; mutex_init(&subsys->shutdown_lock); @@ -607,55 +296,6 @@ static struct notifier_block panic_nb = { .notifier_call = ssr_panic_handler, }; -static int __init ssr_init_soc_restart_orders(void) -{ - int i; - - atomic_notifier_chain_register(&panic_notifier_list, - &panic_nb); -#ifndef CONFIG_ARCH_EXYNOS - if (cpu_is_msm8x60()) { - for (i = 0; i < ARRAY_SIZE(orders_8x60_all); i++) { - mutex_init(&orders_8x60_all[i]->powerup_lock); - mutex_init(&orders_8x60_all[i]->shutdown_lock); - } - - for (i = 0; i < ARRAY_SIZE(orders_8x60_modems); i++) { - mutex_init(&orders_8x60_modems[i]->powerup_lock); - mutex_init(&orders_8x60_modems[i]->shutdown_lock); - } - - restart_orders = orders_8x60_all; - n_restart_orders = ARRAY_SIZE(orders_8x60_all); - } - - if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm9615() || - cpu_is_apq8064()) { - restart_orders = restart_orders_8960; - n_restart_orders = ARRAY_SIZE(restart_orders_8960); - } -#else - for (i = 0; i < ARRAY_SIZE(orders_8x60_all); i++) { - mutex_init(&orders_8x60_all[i]->powerup_lock); - mutex_init(&orders_8x60_all[i]->shutdown_lock); - } - - for (i = 0; i < ARRAY_SIZE(orders_8x60_modems); i++) { - mutex_init(&orders_8x60_modems[i]->powerup_lock); - mutex_init(&orders_8x60_modems[i]->shutdown_lock); - } - - restart_orders = orders_8x60_all; - n_restart_orders = ARRAY_SIZE(orders_8x60_all); -#endif - if (restart_orders == NULL || n_restart_orders < 1) { - WARN_ON(1); - return -EINVAL; - } - - return 0; -} - static int __init subsys_restart_init(void) { int ret = 0; @@ -669,7 +309,8 @@ static int __init subsys_restart_init(void) if (!ssr_wq) panic("Couldn't allocate workqueue for subsystem restart.\n"); - ret = ssr_init_soc_restart_orders(); + atomic_notifier_chain_register(&panic_notifier_list, + &panic_nb); return ret; } |