aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-exynos/subsystem_restart.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-exynos/subsystem_restart.c')
-rw-r--r--arch/arm/mach-exynos/subsystem_restart.c389
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;
}