1 /*
2 * Copyright (c) 2020-2023 Huawei Device Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include "watchdog_core.h"
10 #include "hdf_log.h"
11 #include "watchdog_if.h"
12 #include "platform_trace.h"
13
14 #define WATCHDOG_TRACE_BASIC_PARAM_NUM 1
15 #define WATCHDOG_TRACE_PARAM_STOP_NUM 1
16 #define HDF_LOG_TAG watchdog_core
17
18 static int32_t WatchdogIoDispatch(struct HdfDeviceIoClient *client, int cmd,
19 struct HdfSBuf *data, struct HdfSBuf *reply);
WatchdogCntlrAdd(struct WatchdogCntlr * cntlr)20 int32_t WatchdogCntlrAdd(struct WatchdogCntlr *cntlr)
21 {
22 int32_t ret;
23
24 if (cntlr == NULL) {
25 return HDF_ERR_INVALID_OBJECT;
26 }
27
28 if (cntlr->device == NULL) {
29 HDF_LOGE("WatchdogCntlrAdd: no device associated!");
30 return HDF_ERR_INVALID_OBJECT;
31 }
32
33 if (cntlr->ops == NULL) {
34 HDF_LOGE("WatchdogCntlrAdd: no ops supplied!");
35 return HDF_ERR_INVALID_OBJECT;
36 }
37
38 ret = OsalSpinInit(&cntlr->lock);
39 if (ret != HDF_SUCCESS) {
40 HDF_LOGE("WatchdogCntlrAdd: spinlock init fail!");
41 return ret;
42 }
43
44 cntlr->device->service = &cntlr->service;
45 cntlr->device->service->Dispatch = WatchdogIoDispatch;
46 return HDF_SUCCESS;
47 }
48
WatchdogCntlrRemove(struct WatchdogCntlr * cntlr)49 void WatchdogCntlrRemove(struct WatchdogCntlr *cntlr)
50 {
51 if (cntlr == NULL) {
52 HDF_LOGE("WatchdogCntlrRemove: cntlr is null!");
53 return;
54 }
55
56 if (cntlr->device == NULL) {
57 HDF_LOGE("WatchdogCntlrRemove: no device associated!");
58 return;
59 }
60
61 cntlr->device->service = NULL;
62 (void)OsalSpinDestroy(&cntlr->lock);
63 }
64
WatchdogGetPrivData(struct WatchdogCntlr * cntlr)65 int32_t WatchdogGetPrivData(struct WatchdogCntlr *cntlr)
66 {
67 if (cntlr == NULL || cntlr->ops == NULL) {
68 HDF_LOGE("WatchdogGetPrivData: cntlr or ops is null!");
69 return HDF_ERR_INVALID_OBJECT;
70 }
71 if (cntlr->ops->getPriv != NULL) {
72 return cntlr->ops->getPriv(cntlr);
73 }
74 return HDF_SUCCESS;
75 }
76
WatchdogReleasePriv(struct WatchdogCntlr * cntlr)77 int32_t WatchdogReleasePriv(struct WatchdogCntlr *cntlr)
78 {
79 if (cntlr == NULL || cntlr->ops == NULL) {
80 HDF_LOGE("WatchdogReleasePriv: cntlr or ops is null!");
81 return HDF_SUCCESS;
82 }
83 if (cntlr->ops->releasePriv != NULL) {
84 cntlr->ops->releasePriv(cntlr);
85 }
86 return HDF_SUCCESS;
87 }
88
WatchdogCntlrGetStatus(struct WatchdogCntlr * cntlr,int32_t * status)89 int32_t WatchdogCntlrGetStatus(struct WatchdogCntlr *cntlr, int32_t *status)
90 {
91 int32_t ret;
92 uint32_t flags;
93
94 if (cntlr == NULL) {
95 HDF_LOGE("WatchdogCntlrGetStatus: cntlr is null!");
96 return HDF_ERR_INVALID_OBJECT;
97 }
98 if (cntlr->ops == NULL || cntlr->ops->getStatus == NULL) {
99 HDF_LOGE("WatchdogCntlrGetStatus: ops or getStatus is null!");
100 return HDF_ERR_NOT_SUPPORT;
101 }
102 if (status == NULL) {
103 HDF_LOGE("WatchdogCntlrGetStatus: status is null!");
104 return HDF_ERR_INVALID_PARAM;
105 }
106
107 if (OsalSpinLockIrqSave(&cntlr->lock, &flags) != HDF_SUCCESS) {
108 HDF_LOGE("WatchdogCntlrGetStatus: osal spin lock irq save fail!");
109 return HDF_ERR_DEVICE_BUSY;
110 }
111 ret = cntlr->ops->getStatus(cntlr, status);
112 if (ret != HDF_SUCCESS) {
113 HDF_LOGE("WatchdogCntlrGetStatus: getStatus fail!");
114 return ret;
115 }
116 (void)OsalSpinUnlockIrqRestore(&cntlr->lock, &flags);
117 return ret;
118 }
119
WatchdogCntlrStart(struct WatchdogCntlr * cntlr)120 int32_t WatchdogCntlrStart(struct WatchdogCntlr *cntlr)
121 {
122 int32_t ret;
123 uint32_t flags;
124
125 if (cntlr == NULL) {
126 HDF_LOGE("WatchdogCntlrStart: cntlr is null!");
127 return HDF_ERR_INVALID_OBJECT;
128 }
129 if (cntlr->ops == NULL || cntlr->ops->start == NULL) {
130 HDF_LOGE("WatchdogCntlrStart: ops or start is null!");
131 return HDF_ERR_NOT_SUPPORT;
132 }
133
134 if (OsalSpinLockIrqSave(&cntlr->lock, &flags) != HDF_SUCCESS) {
135 HDF_LOGE("WatchdogCntlrStart: osal spin lock irq save fail!");
136 return HDF_ERR_DEVICE_BUSY;
137 }
138 ret = cntlr->ops->start(cntlr);
139 if (PlatformTraceStart() == HDF_SUCCESS) {
140 unsigned int infos[WATCHDOG_TRACE_BASIC_PARAM_NUM];
141 infos[PLATFORM_TRACE_UINT_PARAM_SIZE_1 - 1] = cntlr->wdtId;
142 PlatformTraceAddUintMsg(PLATFORM_TRACE_MODULE_WATCHDOG, PLATFORM_TRACE_MODULE_WATCHDOG_FUN_START,
143 infos, WATCHDOG_TRACE_BASIC_PARAM_NUM);
144 PlatformTraceStop();
145 }
146 (void)OsalSpinUnlockIrqRestore(&cntlr->lock, &flags);
147 return ret;
148 }
149
WatchdogCntlrStop(struct WatchdogCntlr * cntlr)150 int32_t WatchdogCntlrStop(struct WatchdogCntlr *cntlr)
151 {
152 int32_t ret;
153 uint32_t flags;
154
155 if (cntlr == NULL) {
156 HDF_LOGE("WatchdogCntlrStop: cntlr is null!");
157 return HDF_ERR_INVALID_OBJECT;
158 }
159 if (cntlr->ops == NULL || cntlr->ops->stop == NULL) {
160 HDF_LOGE("WatchdogCntlrStop: ops or stop is null!");
161 return HDF_ERR_NOT_SUPPORT;
162 }
163
164 if (OsalSpinLockIrqSave(&cntlr->lock, &flags) != HDF_SUCCESS) {
165 HDF_LOGE("WatchdogCntlrStop: osal spin lock irq save fail!");
166 return HDF_ERR_DEVICE_BUSY;
167 }
168 ret = cntlr->ops->stop(cntlr);
169 if (PlatformTraceStart() == HDF_SUCCESS) {
170 unsigned int infos[WATCHDOG_TRACE_PARAM_STOP_NUM];
171 infos[PLATFORM_TRACE_UINT_PARAM_SIZE_1 - 1] = cntlr->wdtId;
172 PlatformTraceAddUintMsg(PLATFORM_TRACE_MODULE_WATCHDOG, PLATFORM_TRACE_MODULE_WATCHDOG_FUN_STOP,
173 infos, WATCHDOG_TRACE_PARAM_STOP_NUM);
174 PlatformTraceStop();
175 PlatformTraceInfoDump();
176 }
177 (void)OsalSpinUnlockIrqRestore(&cntlr->lock, &flags);
178 return ret;
179 }
180
WatchdogCntlrSetTimeout(struct WatchdogCntlr * cntlr,uint32_t seconds)181 int32_t WatchdogCntlrSetTimeout(struct WatchdogCntlr *cntlr, uint32_t seconds)
182 {
183 int32_t ret;
184 uint32_t flags;
185
186 if (cntlr == NULL) {
187 HDF_LOGE("WatchdogCntlrSetTimeout: cntlr is null!");
188 return HDF_ERR_INVALID_OBJECT;
189 }
190 if (cntlr->ops == NULL || cntlr->ops->setTimeout == NULL) {
191 HDF_LOGE("WatchdogCntlrSetTimeout: ops or setTimeout is null!");
192 return HDF_ERR_NOT_SUPPORT;
193 }
194
195 if (OsalSpinLockIrqSave(&cntlr->lock, &flags) != HDF_SUCCESS) {
196 HDF_LOGE("WatchdogCntlrSetTimeout: osal spin lock irq save fail!");
197 return HDF_ERR_DEVICE_BUSY;
198 }
199 ret = cntlr->ops->setTimeout(cntlr, seconds);
200 (void)OsalSpinUnlockIrqRestore(&cntlr->lock, &flags);
201 return ret;
202 }
203
WatchdogCntlrGetTimeout(struct WatchdogCntlr * cntlr,uint32_t * seconds)204 int32_t WatchdogCntlrGetTimeout(struct WatchdogCntlr *cntlr, uint32_t *seconds)
205 {
206 int32_t ret;
207 uint32_t flags;
208
209 if (cntlr == NULL) {
210 HDF_LOGE("WatchdogCntlrGetTimeout: cntlr is null!");
211 return HDF_ERR_INVALID_OBJECT;
212 }
213 if (cntlr->ops == NULL || cntlr->ops->getTimeout == NULL) {
214 HDF_LOGE("WatchdogCntlrGetTimeout: ops or getTimeout is null!");
215 return HDF_ERR_NOT_SUPPORT;
216 }
217 if (seconds == NULL) {
218 HDF_LOGE("WatchdogCntlrGetTimeout: seconds is null!");
219 return HDF_ERR_INVALID_PARAM;
220 }
221
222 if (OsalSpinLockIrqSave(&cntlr->lock, &flags) != HDF_SUCCESS) {
223 HDF_LOGE("WatchdogCntlrGetTimeout: osal spin lock irq save fail!");
224 return HDF_ERR_DEVICE_BUSY;
225 }
226 ret = cntlr->ops->getTimeout(cntlr, seconds);
227 (void)OsalSpinUnlockIrqRestore(&cntlr->lock, &flags);
228 return ret;
229 }
230
WatchdogCntlrFeed(struct WatchdogCntlr * cntlr)231 int32_t WatchdogCntlrFeed(struct WatchdogCntlr *cntlr)
232 {
233 int32_t ret;
234 uint32_t flags;
235
236 if (cntlr == NULL) {
237 HDF_LOGE("WatchdogCntlrFeed: cntlr is null!");
238 return HDF_ERR_INVALID_OBJECT;
239 }
240 if (cntlr->ops == NULL || cntlr->ops->feed == NULL) {
241 HDF_LOGE("WatchdogCntlrFeed: ops or feed is null!");
242 return HDF_ERR_NOT_SUPPORT;
243 }
244
245 if (OsalSpinLockIrqSave(&cntlr->lock, &flags) != HDF_SUCCESS) {
246 HDF_LOGE("OsalSpinLockIrqSave: osal spin lock irq save fail!");
247 return HDF_ERR_DEVICE_BUSY;
248 }
249 ret = cntlr->ops->feed(cntlr);
250 (void)OsalSpinUnlockIrqRestore(&cntlr->lock, &flags);
251 return ret;
252 }
253
WatchdogUserGetPrivData(struct WatchdogCntlr * cntlr,struct HdfSBuf * reply)254 static int32_t WatchdogUserGetPrivData(struct WatchdogCntlr *cntlr, struct HdfSBuf *reply)
255 {
256 int32_t ret;
257
258 if (reply == NULL) {
259 HDF_LOGE("WatchdogUserGetPrivData: reply is null!");
260 return HDF_ERR_INVALID_OBJECT;
261 }
262 ret = WatchdogGetPrivData(cntlr);
263 if (!HdfSbufWriteInt32(reply, ret)) {
264 HDF_LOGE("WatchdogUserGetPrivData: sbuf write buffer fail!");
265 return HDF_ERR_IO;
266 }
267 return HDF_SUCCESS;
268 }
269
WatchdogUserGetStatus(struct WatchdogCntlr * cntlr,struct HdfSBuf * reply)270 static int32_t WatchdogUserGetStatus(struct WatchdogCntlr *cntlr, struct HdfSBuf *reply)
271 {
272 int32_t ret;
273 int32_t status;
274
275 if (reply == NULL) {
276 HDF_LOGE("WatchdogUserGetStatus:reply is null!");
277 return HDF_ERR_INVALID_OBJECT;
278 }
279 ret = WatchdogCntlrGetStatus(cntlr, &status);
280 if (ret != HDF_SUCCESS) {
281 HDF_LOGE("WatchdogUserGetStatus: watchdog cntlr get status fail, ret: %d!", ret);
282 return ret;
283 }
284 if (!HdfSbufWriteInt32(reply, status)) {
285 HDF_LOGE("WatchdogUserGetStatus: sbuf write status fail!");
286 return HDF_ERR_IO;
287 }
288 return HDF_SUCCESS;
289 }
290
WatchdogUserSetTimeout(struct WatchdogCntlr * cntlr,struct HdfSBuf * data)291 static int32_t WatchdogUserSetTimeout(struct WatchdogCntlr *cntlr, struct HdfSBuf *data)
292 {
293 uint32_t seconds;
294
295 if (data == NULL) {
296 HDF_LOGE("WatchdogUserSetTimeout: data is null!");
297 return HDF_ERR_INVALID_OBJECT;
298 }
299
300 if (!HdfSbufReadUint32(data, &seconds)) {
301 HDF_LOGE("WatchdogUserSetTimeout: sbuf read seconds fail!");
302 return HDF_ERR_IO;
303 }
304
305 return WatchdogCntlrSetTimeout(cntlr, seconds);
306 }
307
WatchdogUserGetTimeout(struct WatchdogCntlr * cntlr,struct HdfSBuf * reply)308 static int32_t WatchdogUserGetTimeout(struct WatchdogCntlr *cntlr, struct HdfSBuf *reply)
309 {
310 int32_t ret;
311 uint32_t seconds;
312
313 if (reply == NULL) {
314 HDF_LOGE("WatchdogUserGetTimeout: reply is null!");
315 return HDF_ERR_INVALID_OBJECT;
316 }
317 ret = WatchdogCntlrGetTimeout(cntlr, &seconds);
318 if (ret != HDF_SUCCESS) {
319 HDF_LOGE("WatchdogUserGetTimeout: watchdog cntlr get timeout fail, ret: %d!", ret);
320 return ret;
321 }
322
323 if (!HdfSbufWriteUint32(reply, seconds)) {
324 HDF_LOGE("WatchdogUserGetTimeout: sbuf write buffer fail!");
325 return HDF_ERR_IO;
326 }
327 return HDF_SUCCESS;
328 }
329
WatchdogIoDispatch(struct HdfDeviceIoClient * client,int cmd,struct HdfSBuf * data,struct HdfSBuf * reply)330 static int32_t WatchdogIoDispatch(struct HdfDeviceIoClient *client, int cmd,
331 struct HdfSBuf *data, struct HdfSBuf *reply)
332 {
333 struct WatchdogCntlr *cntlr = NULL;
334
335 if (client == NULL) {
336 HDF_LOGE("WatchdogIoDispatch: client is null!");
337 return HDF_ERR_INVALID_OBJECT;
338 }
339 if (client->device == NULL) {
340 HDF_LOGE("WatchdogIoDispatch: client->device is null!");
341 return HDF_ERR_INVALID_OBJECT;
342 }
343 if (client->device->service == NULL) {
344 HDF_LOGE("WatchdogIoDispatch: client->device->service is null!");
345 return HDF_ERR_INVALID_OBJECT;
346 }
347
348 cntlr = (struct WatchdogCntlr *)client->device->service;
349 switch (cmd) {
350 case WATCHDOG_IO_GET_PRIV:
351 return WatchdogUserGetPrivData(cntlr, reply);
352 case WATCHDOG_IO_RELEASE_PRIV:
353 return WatchdogReleasePriv(cntlr);
354 case WATCHDOG_IO_GET_STATUS:
355 return WatchdogUserGetStatus(cntlr, reply);
356 case WATCHDOG_IO_START:
357 return WatchdogCntlrStart(cntlr);
358 case WATCHDOG_IO_STOP:
359 return WatchdogCntlrStop(cntlr);
360 case WATCHDOG_IO_SET_TIMEOUT:
361 return WatchdogUserSetTimeout(cntlr, data);
362 case WATCHDOG_IO_GET_TIMEOUT:
363 return WatchdogUserGetTimeout(cntlr, reply);
364 case WATCHDOG_IO_FEED:
365 return WatchdogCntlrFeed(cntlr);
366 default:
367 HDF_LOGE("WatchdogIoDispatch: cmd %d is not support!", cmd);
368 return HDF_ERR_NOT_SUPPORT;
369 }
370 }
371