blob: bde0803558a78c6840036d8c4672905d6da7d038 [file] [log] [blame]
Kristofer Jonssonf5b98c92022-03-14 16:09:12 +01001/*
2 * Copyright (c) 2022 Arm Limited.
3 *
4 * This program is free software and is provided to you under the terms of the
5 * GNU General Public License version 2 as published by the Free Software
6 * Foundation, and any use by you of this program is subject to the terms
7 * of such GNU licence.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, you can access it online at
16 * http://www.gnu.org/licenses/gpl-2.0.html.
17 *
18 * SPDX-License-Identifier: GPL-2.0-only
19 */
20
21/****************************************************************************
22 * Includes
23 ****************************************************************************/
24
25#include "ethosu_watchdog.h"
26
27#include <linux/device.h>
28#include <linux/jiffies.h>
29#include <linux/moduleparam.h>
30#include <linux/version.h>
31
32/****************************************************************************
33 * Variables
34 ****************************************************************************/
35
36static unsigned long watchdog_timeout_ms = 3000;
37module_param(watchdog_timeout_ms, ulong, 0664);
38MODULE_PARM_DESC(watchdog_timeout_ms,
39 "Watchdog timeout in milliseconds for unresponsive firmware.");
40
41/****************************************************************************
42 * Functions
43 ****************************************************************************/
44
45static void ethosu_watchdog_update(struct ethosu_watchdog *wdog)
46{
47 int ret;
48
49 ret = mod_timer(&wdog->timer,
50 jiffies + msecs_to_jiffies(watchdog_timeout_ms));
51
52 dev_info(wdog->dev,
53 "Wdog: Update watchdog timeout. ret=%d, timeout_ms=%lu, refcount=%u", ret,
54 watchdog_timeout_ms, atomic_read(&wdog->refcount));
55}
56
57static void ethosu_watchdog_work(struct work_struct *work)
58{
59 struct ethosu_watchdog *wdog =
60 container_of(work, struct ethosu_watchdog, work);
61
62 dev_info(wdog->dev, "Wdog: Watchdog timeout. refcount=%u",
63 atomic_read(&wdog->refcount));
64
65 wdog->callback(wdog);
66}
67
68static void ethosu_watchdog_timeout(struct timer_list *timer)
69{
70 struct ethosu_watchdog *wdog =
71 container_of(timer, struct ethosu_watchdog, timer);
72
73 queue_work(system_unbound_wq, &wdog->work);
74}
75
76#if KERNEL_VERSION(4, 14, 0) > LINUX_VERSION_CODE
77static void ethosu_watchdog_timeout_legacy(unsigned long data)
78{
79 ethosu_watchdog_timeout((struct timer_list *)data);
80}
81
82#endif
83
84int ethosu_watchdog_init(struct ethosu_watchdog *wdog,
85 struct device *dev,
86 ethosu_watchdog_cb callback)
87{
88 wdog->dev = dev;
89 wdog->callback = callback;
90 atomic_set(&wdog->refcount, 0);
91 INIT_WORK(&wdog->work, ethosu_watchdog_work);
92
93#if KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE
94 timer_setup(&wdog->timer, ethosu_watchdog_timeout, 0);
95#else
96 setup_timer(&wdog->timer, ethosu_watchdog_timeout_legacy,
97 (unsigned long)&wdog->timer);
98#endif
99
100 return 0;
101}
102
103void ethosu_watchdog_deinit(struct ethosu_watchdog *wdog)
104{
105 del_timer(&wdog->timer);
106}
107
108int ethosu_watchdog_reset(struct ethosu_watchdog *wdog)
109{
110 del_timer(&wdog->timer);
111 atomic_set(&wdog->refcount, 0);
112
113 return 0;
114}
115
116void ethosu_watchdog_inc(struct ethosu_watchdog *wdog)
117{
118 atomic_inc(&wdog->refcount);
119 ethosu_watchdog_update(wdog);
120}
121
122void ethosu_watchdog_dec(struct ethosu_watchdog *wdog)
123{
124 if (atomic_dec_and_test(&wdog->refcount)) {
125 dev_info(wdog->dev, "Wdog: Cancel watchdog timeout");
126 del_timer(&wdog->timer);
127 } else {
128 ethosu_watchdog_update(wdog);
129 }
130}