Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b8105def authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "soc: qcom: watchdog_v2: use rt task to pet watchdog"

parents 3297dc3a 37be3f4f
Loading
Loading
Loading
Loading
+53 −66
Original line number Diff line number Diff line
@@ -14,9 +14,9 @@
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
@@ -49,7 +49,6 @@
#define SCM_SVC_SEC_WDOG_DIS	0x7
#define MAX_CPU_CTX_SIZE	2048

static struct workqueue_struct *wdog_wq;
static struct msm_watchdog_data *wdog_data;

static int cpu_idle_pc_state[NR_CPUS];
@@ -72,12 +71,13 @@ struct msm_watchdog_data {
	void *scm_regsave;
	cpumask_t alive_mask;
	struct mutex disable_lock;
	struct work_struct init_dogwork_struct;
	struct delayed_work dogwork_struct;
	bool irq_ppi;
	struct msm_watchdog_data __percpu **wdog_cpu_dd;
	struct notifier_block panic_blk;
	bool enabled;
	struct task_struct *watchdog_task;
	struct timer_list pet_timer;
	struct completion pet_complete;
};

/*
@@ -104,9 +104,6 @@ module_param(WDT_HZ, long, 0);
static int ipi_opt_en;
module_param(ipi_opt_en, int, 0);

static void pet_watchdog_work(struct work_struct *work);
static void init_watchdog_work(struct work_struct *work);

static void dump_cpu_alive_mask(struct msm_watchdog_data *wdog_dd)
{
	static char alive_mask_buf[MASK_SIZE];
@@ -188,7 +185,7 @@ static void wdog_disable(struct msm_watchdog_data *wdog_dd)
	smp_mb();
	atomic_notifier_chain_unregister(&panic_notifier_list,
						&wdog_dd->panic_blk);
	cancel_delayed_work_sync(&wdog_dd->dogwork_struct);
	del_timer_sync(&wdog_dd->pet_timer);
	/* may be suspended after the first write above */
	__raw_writel(0, wdog_dd->base + WDT0_EN);
	mb();
@@ -196,20 +193,6 @@ static void wdog_disable(struct msm_watchdog_data *wdog_dd)
	pr_info("MSM Apps Watchdog deactivated.\n");
}

struct wdog_disable_work_data {
	struct work_struct work;
	struct completion complete;
	struct msm_watchdog_data *wdog_dd;
};

static void wdog_disable_work(struct work_struct *work)
{
	struct wdog_disable_work_data *work_data =
		container_of(work, struct wdog_disable_work_data, work);
	wdog_disable(work_data->wdog_dd);
	complete(&work_data->complete);
}

static ssize_t wdog_disable_get(struct device *dev,
				struct device_attribute *attr, char *buf)
{
@@ -228,7 +211,6 @@ static ssize_t wdog_disable_set(struct device *dev,
{
	int ret;
	u8 disable;
	struct wdog_disable_work_data work_data;
	struct msm_watchdog_data *wdog_dd = dev_get_drvdata(dev);

	ret = kstrtou8(buf, 10, &disable);
@@ -260,11 +242,7 @@ static ssize_t wdog_disable_set(struct device *dev,
			mutex_unlock(&wdog_dd->disable_lock);
			return -EIO;
		}
		work_data.wdog_dd = wdog_dd;
		init_completion(&work_data.complete);
		INIT_WORK_ONSTACK(&work_data.work, wdog_disable_work);
		queue_work(wdog_wq, &work_data.work);
		wait_for_completion(&work_data.complete);
		wdog_disable(wdog_dd);
		mutex_unlock(&wdog_dd->disable_lock);
	} else {
		pr_err("invalid operation, only disable = 1 supported\n");
@@ -325,24 +303,37 @@ static void ping_other_cpus(struct msm_watchdog_data *wdog_dd)
	}
}

static void pet_watchdog_work(struct work_struct *work)
static void pet_task_wakeup(unsigned long data)
{
	struct msm_watchdog_data *wdog_dd =
		(struct msm_watchdog_data *)data;
	complete(&wdog_dd->pet_complete);
}

static __ref int watchdog_kthread(void *arg)
{
	struct msm_watchdog_data *wdog_dd =
		(struct msm_watchdog_data *)arg;
	unsigned long delay_time;
	struct delayed_work *delayed_work = to_delayed_work(work);
	struct msm_watchdog_data *wdog_dd = container_of(delayed_work,
						struct msm_watchdog_data,
							dogwork_struct);
	delay_time = msecs_to_jiffies(wdog_dd->pet_time);
	struct sched_param param = {.sched_priority = MAX_RT_PRIO-1};

	sched_setscheduler(current, SCHED_FIFO, &param);
	while (!kthread_should_stop()) {
		while (wait_for_completion_interruptible(
			&wdog_dd->pet_complete) != 0)
			;
		reinit_completion(&wdog_dd->pet_complete);
		if (enable) {
			delay_time = msecs_to_jiffies(wdog_dd->pet_time);
			if (wdog_dd->do_ipi_ping)
				ping_other_cpus(wdog_dd);
			pet_watchdog(wdog_dd);
		}
		/* Check again before scheduling *
		 * Could have been changed on other cpu */
	if (enable)
		queue_delayed_work(wdog_wq,
				&wdog_dd->dogwork_struct, delay_time);
		mod_timer(&wdog_dd->pet_timer, jiffies + delay_time);
	}
	return 0;
}

static int wdog_cpu_pm_notify(struct notifier_block *self,
@@ -371,7 +362,6 @@ static struct notifier_block wdog_cpu_pm_nb = {

static int msm_watchdog_remove(struct platform_device *pdev)
{
	struct wdog_disable_work_data work_data;
	struct msm_watchdog_data *wdog_dd =
			(struct msm_watchdog_data *)platform_get_drvdata(pdev);

@@ -380,18 +370,15 @@ static int msm_watchdog_remove(struct platform_device *pdev)

	mutex_lock(&wdog_dd->disable_lock);
	if (enable) {
		work_data.wdog_dd = wdog_dd;
		init_completion(&work_data.complete);
		INIT_WORK_ONSTACK(&work_data.work, wdog_disable_work);
		queue_work(wdog_wq, &work_data.work);
		wait_for_completion(&work_data.complete);
		wdog_disable(wdog_dd);
	}
	mutex_unlock(&wdog_dd->disable_lock);
	device_remove_file(wdog_dd->dev, &dev_attr_disable);
	if (wdog_dd->irq_ppi)
		free_percpu(wdog_dd->wdog_cpu_dd);
	printk(KERN_INFO "MSM Watchdog Exit - Deactivated\n");
	destroy_workqueue(wdog_wq);
	del_timer_sync(&wdog_dd->pet_timer);
	kthread_stop(wdog_dd->watchdog_task);
	kfree(wdog_dd);
	return 0;
}
@@ -532,11 +519,8 @@ out0:
}


static void init_watchdog_work(struct work_struct *work)
static void init_watchdog_data(struct msm_watchdog_data *wdog_dd)
{
	struct msm_watchdog_data *wdog_dd = container_of(work,
						struct msm_watchdog_data,
							init_dogwork_struct);
	unsigned long delay_time;
	uint32_t val;
	int error;
@@ -586,8 +570,14 @@ static void init_watchdog_work(struct work_struct *work)
	atomic_notifier_chain_register(&panic_notifier_list,
				       &wdog_dd->panic_blk);
	mutex_init(&wdog_dd->disable_lock);
	queue_delayed_work(wdog_wq, &wdog_dd->dogwork_struct,
			delay_time);
	init_completion(&wdog_dd->pet_complete);
	wake_up_process(wdog_dd->watchdog_task);
	init_timer(&wdog_dd->pet_timer);
	wdog_dd->pet_timer.data = (unsigned long)wdog_dd;
	wdog_dd->pet_timer.function = pet_task_wakeup;
	wdog_dd->pet_timer.expires = jiffies + delay_time;
	add_timer(&wdog_dd->pet_timer);

	val = BIT(EN);
	if (wdog_dd->wakeup_irq_enable)
		val |= BIT(UNMASKED_INT_EN);
@@ -697,12 +687,6 @@ static int msm_watchdog_probe(struct platform_device *pdev)
	int ret;
	struct msm_watchdog_data *wdog_dd;

	wdog_wq = alloc_workqueue("wdog", WQ_HIGHPRI, 0);
	if (!wdog_wq) {
		pr_err("Failed to allocate watchdog workqueue\n");
		return -EIO;
	}

	if (!pdev->dev.of_node || !enable)
		return -ENODEV;
	wdog_dd = kzalloc(sizeof(struct msm_watchdog_data), GFP_KERNEL);
@@ -716,12 +700,15 @@ static int msm_watchdog_probe(struct platform_device *pdev)
	wdog_dd->dev = &pdev->dev;
	platform_set_drvdata(pdev, wdog_dd);
	cpumask_clear(&wdog_dd->alive_mask);
	INIT_WORK(&wdog_dd->init_dogwork_struct, init_watchdog_work);
	INIT_DELAYED_WORK(&wdog_dd->dogwork_struct, pet_watchdog_work);
	queue_work(wdog_wq, &wdog_dd->init_dogwork_struct);
	wdog_dd->watchdog_task = kthread_create(watchdog_kthread, wdog_dd,
			"msm_watchdog");
	if (IS_ERR(wdog_dd->watchdog_task)) {
		ret = PTR_ERR(wdog_dd->watchdog_task);
		goto err;
	}
	init_watchdog_data(wdog_dd);
	return 0;
err:
	destroy_workqueue(wdog_wq);
	kzfree(wdog_dd);
	return ret;
}