diff options
Diffstat (limited to 'drivers/staging/greybus/svc_watchdog.c')
-rw-r--r-- | drivers/staging/greybus/svc_watchdog.c | 197 |
1 files changed, 0 insertions, 197 deletions
diff --git a/drivers/staging/greybus/svc_watchdog.c b/drivers/staging/greybus/svc_watchdog.c deleted file mode 100644 index 7868ad8211c5..000000000000 --- a/drivers/staging/greybus/svc_watchdog.c +++ /dev/null @@ -1,197 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * SVC Greybus "watchdog" driver. - * - * Copyright 2016 Google Inc. - */ - -#include <linux/delay.h> -#include <linux/suspend.h> -#include <linux/workqueue.h> -#include "greybus.h" - -#define SVC_WATCHDOG_PERIOD (2 * HZ) - -struct gb_svc_watchdog { - struct delayed_work work; - struct gb_svc *svc; - bool enabled; - struct notifier_block pm_notifier; -}; - -static struct delayed_work reset_work; - -static int svc_watchdog_pm_notifier(struct notifier_block *notifier, - unsigned long pm_event, void *unused) -{ - struct gb_svc_watchdog *watchdog = - container_of(notifier, struct gb_svc_watchdog, pm_notifier); - - switch (pm_event) { - case PM_SUSPEND_PREPARE: - gb_svc_watchdog_disable(watchdog->svc); - break; - case PM_POST_SUSPEND: - gb_svc_watchdog_enable(watchdog->svc); - break; - default: - break; - } - - return NOTIFY_DONE; -} - -static void greybus_reset(struct work_struct *work) -{ - static char const start_path[] = "/system/bin/start"; - static char *envp[] = { - "HOME=/", - "PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin", - NULL, - }; - static char *argv[] = { - (char *)start_path, - "unipro_reset", - NULL, - }; - - pr_err("svc_watchdog: calling \"%s %s\" to reset greybus network!\n", - argv[0], argv[1]); - call_usermodehelper(start_path, argv, envp, UMH_WAIT_EXEC); -} - -static void do_work(struct work_struct *work) -{ - struct gb_svc_watchdog *watchdog; - struct gb_svc *svc; - int retval; - - watchdog = container_of(work, struct gb_svc_watchdog, work.work); - svc = watchdog->svc; - - dev_dbg(&svc->dev, "%s: ping.\n", __func__); - retval = gb_svc_ping(svc); - if (retval) { - /* - * Something went really wrong, let's warn userspace and then - * pull the plug and reset the whole greybus network. - * We need to do this outside of this workqueue as we will be - * tearing down the svc device itself. So queue up - * yet-another-callback to do that. - */ - dev_err(&svc->dev, - "SVC ping has returned %d, something is wrong!!!\n", - retval); - - if (svc->action == GB_SVC_WATCHDOG_BITE_PANIC_KERNEL) { - panic("SVC is not responding\n"); - } else if (svc->action == GB_SVC_WATCHDOG_BITE_RESET_UNIPRO) { - dev_err(&svc->dev, "Resetting the greybus network, watch out!!!\n"); - - INIT_DELAYED_WORK(&reset_work, greybus_reset); - schedule_delayed_work(&reset_work, HZ / 2); - - /* - * Disable ourselves, we don't want to trip again unless - * userspace wants us to. - */ - watchdog->enabled = false; - } - } - - /* resubmit our work to happen again, if we are still "alive" */ - if (watchdog->enabled) - schedule_delayed_work(&watchdog->work, SVC_WATCHDOG_PERIOD); -} - -int gb_svc_watchdog_create(struct gb_svc *svc) -{ - struct gb_svc_watchdog *watchdog; - int retval; - - if (svc->watchdog) - return 0; - - watchdog = kmalloc(sizeof(*watchdog), GFP_KERNEL); - if (!watchdog) - return -ENOMEM; - - watchdog->enabled = false; - watchdog->svc = svc; - INIT_DELAYED_WORK(&watchdog->work, do_work); - svc->watchdog = watchdog; - - watchdog->pm_notifier.notifier_call = svc_watchdog_pm_notifier; - retval = register_pm_notifier(&watchdog->pm_notifier); - if (retval) { - dev_err(&svc->dev, "error registering pm notifier(%d)\n", - retval); - goto svc_watchdog_create_err; - } - - retval = gb_svc_watchdog_enable(svc); - if (retval) { - dev_err(&svc->dev, "error enabling watchdog (%d)\n", retval); - unregister_pm_notifier(&watchdog->pm_notifier); - goto svc_watchdog_create_err; - } - return retval; - -svc_watchdog_create_err: - svc->watchdog = NULL; - kfree(watchdog); - - return retval; -} - -void gb_svc_watchdog_destroy(struct gb_svc *svc) -{ - struct gb_svc_watchdog *watchdog = svc->watchdog; - - if (!watchdog) - return; - - unregister_pm_notifier(&watchdog->pm_notifier); - gb_svc_watchdog_disable(svc); - svc->watchdog = NULL; - kfree(watchdog); -} - -bool gb_svc_watchdog_enabled(struct gb_svc *svc) -{ - if (!svc || !svc->watchdog) - return false; - return svc->watchdog->enabled; -} - -int gb_svc_watchdog_enable(struct gb_svc *svc) -{ - struct gb_svc_watchdog *watchdog; - - if (!svc->watchdog) - return -ENODEV; - - watchdog = svc->watchdog; - if (watchdog->enabled) - return 0; - - watchdog->enabled = true; - schedule_delayed_work(&watchdog->work, SVC_WATCHDOG_PERIOD); - return 0; -} - -int gb_svc_watchdog_disable(struct gb_svc *svc) -{ - struct gb_svc_watchdog *watchdog; - - if (!svc->watchdog) - return -ENODEV; - - watchdog = svc->watchdog; - if (!watchdog->enabled) - return 0; - - watchdog->enabled = false; - cancel_delayed_work_sync(&watchdog->work); - return 0; -} |