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         (void)OsalSpinUnlockIrqRestore(&cntlr->lock, &flags);
115         return ret;
116     }
117     (void)OsalSpinUnlockIrqRestore(&cntlr->lock, &flags);
118     return ret;
119 }
120 
WatchdogCntlrStart(struct WatchdogCntlr * cntlr)121 int32_t WatchdogCntlrStart(struct WatchdogCntlr *cntlr)
122 {
123     int32_t ret;
124     uint32_t flags;
125 
126     if (cntlr == NULL) {
127         HDF_LOGE("WatchdogCntlrStart: cntlr is null!");
128         return HDF_ERR_INVALID_OBJECT;
129     }
130     if (cntlr->ops == NULL || cntlr->ops->start == NULL) {
131         HDF_LOGE("WatchdogCntlrStart: ops or start is null!");
132         return HDF_ERR_NOT_SUPPORT;
133     }
134 
135     if (OsalSpinLockIrqSave(&cntlr->lock, &flags) != HDF_SUCCESS) {
136         HDF_LOGE("WatchdogCntlrStart: osal spin lock irq save fail!");
137         return HDF_ERR_DEVICE_BUSY;
138     }
139     ret = cntlr->ops->start(cntlr);
140     if (PlatformTraceStart() == HDF_SUCCESS) {
141         unsigned int infos[WATCHDOG_TRACE_BASIC_PARAM_NUM];
142         infos[PLATFORM_TRACE_UINT_PARAM_SIZE_1 - 1] = cntlr->wdtId;
143         PlatformTraceAddUintMsg(PLATFORM_TRACE_MODULE_WATCHDOG, PLATFORM_TRACE_MODULE_WATCHDOG_FUN_START,
144             infos, WATCHDOG_TRACE_BASIC_PARAM_NUM);
145         PlatformTraceStop();
146     }
147     (void)OsalSpinUnlockIrqRestore(&cntlr->lock, &flags);
148     return ret;
149 }
150 
WatchdogCntlrStop(struct WatchdogCntlr * cntlr)151 int32_t WatchdogCntlrStop(struct WatchdogCntlr *cntlr)
152 {
153     int32_t ret;
154     uint32_t flags;
155 
156     if (cntlr == NULL) {
157         HDF_LOGE("WatchdogCntlrStop: cntlr is null!");
158         return HDF_ERR_INVALID_OBJECT;
159     }
160     if (cntlr->ops == NULL || cntlr->ops->stop == NULL) {
161         HDF_LOGE("WatchdogCntlrStop: ops or stop is null!");
162         return HDF_ERR_NOT_SUPPORT;
163     }
164 
165     if (OsalSpinLockIrqSave(&cntlr->lock, &flags) != HDF_SUCCESS) {
166         HDF_LOGE("WatchdogCntlrStop: osal spin lock irq save fail!");
167         return HDF_ERR_DEVICE_BUSY;
168     }
169     ret = cntlr->ops->stop(cntlr);
170     if (PlatformTraceStart() == HDF_SUCCESS) {
171         unsigned int infos[WATCHDOG_TRACE_PARAM_STOP_NUM];
172         infos[PLATFORM_TRACE_UINT_PARAM_SIZE_1 - 1] = cntlr->wdtId;
173         PlatformTraceAddUintMsg(PLATFORM_TRACE_MODULE_WATCHDOG, PLATFORM_TRACE_MODULE_WATCHDOG_FUN_STOP,
174             infos, WATCHDOG_TRACE_PARAM_STOP_NUM);
175         PlatformTraceStop();
176         PlatformTraceInfoDump();
177     }
178     (void)OsalSpinUnlockIrqRestore(&cntlr->lock, &flags);
179     return ret;
180 }
181 
WatchdogCntlrSetTimeout(struct WatchdogCntlr * cntlr,uint32_t seconds)182 int32_t WatchdogCntlrSetTimeout(struct WatchdogCntlr *cntlr, uint32_t seconds)
183 {
184     int32_t ret;
185     uint32_t flags;
186 
187     if (cntlr == NULL) {
188         HDF_LOGE("WatchdogCntlrSetTimeout: cntlr is null!");
189         return HDF_ERR_INVALID_OBJECT;
190     }
191     if (cntlr->ops == NULL || cntlr->ops->setTimeout == NULL) {
192         HDF_LOGE("WatchdogCntlrSetTimeout: ops or setTimeout is null!");
193         return HDF_ERR_NOT_SUPPORT;
194     }
195 
196     if (OsalSpinLockIrqSave(&cntlr->lock, &flags) != HDF_SUCCESS) {
197         HDF_LOGE("WatchdogCntlrSetTimeout: osal spin lock irq save fail!");
198         return HDF_ERR_DEVICE_BUSY;
199     }
200     ret = cntlr->ops->setTimeout(cntlr, seconds);
201     (void)OsalSpinUnlockIrqRestore(&cntlr->lock, &flags);
202     return ret;
203 }
204 
WatchdogCntlrGetTimeout(struct WatchdogCntlr * cntlr,uint32_t * seconds)205 int32_t WatchdogCntlrGetTimeout(struct WatchdogCntlr *cntlr, uint32_t *seconds)
206 {
207     int32_t ret;
208     uint32_t flags;
209 
210     if (cntlr == NULL) {
211         HDF_LOGE("WatchdogCntlrGetTimeout: cntlr is null!");
212         return HDF_ERR_INVALID_OBJECT;
213     }
214     if (cntlr->ops == NULL || cntlr->ops->getTimeout == NULL) {
215         HDF_LOGE("WatchdogCntlrGetTimeout: ops or getTimeout is null!");
216         return HDF_ERR_NOT_SUPPORT;
217     }
218     if (seconds == NULL) {
219         HDF_LOGE("WatchdogCntlrGetTimeout: seconds is null!");
220         return HDF_ERR_INVALID_PARAM;
221     }
222 
223     if (OsalSpinLockIrqSave(&cntlr->lock, &flags) != HDF_SUCCESS) {
224         HDF_LOGE("WatchdogCntlrGetTimeout: osal spin lock irq save fail!");
225         return HDF_ERR_DEVICE_BUSY;
226     }
227     ret = cntlr->ops->getTimeout(cntlr, seconds);
228     (void)OsalSpinUnlockIrqRestore(&cntlr->lock, &flags);
229     return ret;
230 }
231 
WatchdogCntlrFeed(struct WatchdogCntlr * cntlr)232 int32_t WatchdogCntlrFeed(struct WatchdogCntlr *cntlr)
233 {
234     int32_t ret;
235     uint32_t flags;
236 
237     if (cntlr == NULL) {
238         HDF_LOGE("WatchdogCntlrFeed: cntlr is null!");
239         return HDF_ERR_INVALID_OBJECT;
240     }
241     if (cntlr->ops == NULL || cntlr->ops->feed == NULL) {
242         HDF_LOGE("WatchdogCntlrFeed: ops or feed is null!");
243         return HDF_ERR_NOT_SUPPORT;
244     }
245 
246     if (OsalSpinLockIrqSave(&cntlr->lock, &flags) != HDF_SUCCESS) {
247         HDF_LOGE("OsalSpinLockIrqSave: osal spin lock irq save fail!");
248         return HDF_ERR_DEVICE_BUSY;
249     }
250     ret = cntlr->ops->feed(cntlr);
251     (void)OsalSpinUnlockIrqRestore(&cntlr->lock, &flags);
252     return ret;
253 }
254 
WatchdogUserGetPrivData(struct WatchdogCntlr * cntlr,struct HdfSBuf * reply)255 static int32_t WatchdogUserGetPrivData(struct WatchdogCntlr *cntlr, struct HdfSBuf *reply)
256 {
257     int32_t ret;
258 
259     if (reply == NULL) {
260         HDF_LOGE("WatchdogUserGetPrivData: reply is null!");
261         return HDF_ERR_INVALID_OBJECT;
262     }
263     ret = WatchdogGetPrivData(cntlr);
264     if (!HdfSbufWriteInt32(reply, ret)) {
265         HDF_LOGE("WatchdogUserGetPrivData: sbuf write buffer fail!");
266         return HDF_ERR_IO;
267     }
268     return HDF_SUCCESS;
269 }
270 
WatchdogUserGetStatus(struct WatchdogCntlr * cntlr,struct HdfSBuf * reply)271 static int32_t WatchdogUserGetStatus(struct WatchdogCntlr *cntlr, struct HdfSBuf *reply)
272 {
273     int32_t ret;
274     int32_t status;
275 
276     if (reply == NULL) {
277         HDF_LOGE("WatchdogUserGetStatus:reply is null!");
278         return HDF_ERR_INVALID_OBJECT;
279     }
280     ret = WatchdogCntlrGetStatus(cntlr, &status);
281     if (ret != HDF_SUCCESS) {
282         HDF_LOGE("WatchdogUserGetStatus: watchdog cntlr get status fail, ret: %d!", ret);
283         return ret;
284     }
285     if (!HdfSbufWriteInt32(reply, status)) {
286         HDF_LOGE("WatchdogUserGetStatus: sbuf write status fail!");
287         return HDF_ERR_IO;
288     }
289     return HDF_SUCCESS;
290 }
291 
WatchdogUserSetTimeout(struct WatchdogCntlr * cntlr,struct HdfSBuf * data)292 static int32_t WatchdogUserSetTimeout(struct WatchdogCntlr *cntlr, struct HdfSBuf *data)
293 {
294     uint32_t seconds;
295 
296     if (data == NULL) {
297         HDF_LOGE("WatchdogUserSetTimeout: data is null!");
298         return HDF_ERR_INVALID_OBJECT;
299     }
300 
301     if (!HdfSbufReadUint32(data, &seconds)) {
302         HDF_LOGE("WatchdogUserSetTimeout: sbuf read seconds fail!");
303         return HDF_ERR_IO;
304     }
305 
306     return WatchdogCntlrSetTimeout(cntlr, seconds);
307 }
308 
WatchdogUserGetTimeout(struct WatchdogCntlr * cntlr,struct HdfSBuf * reply)309 static int32_t WatchdogUserGetTimeout(struct WatchdogCntlr *cntlr, struct HdfSBuf *reply)
310 {
311     int32_t ret;
312     uint32_t seconds;
313 
314     if (reply == NULL) {
315         HDF_LOGE("WatchdogUserGetTimeout: reply is null!");
316         return HDF_ERR_INVALID_OBJECT;
317     }
318     ret = WatchdogCntlrGetTimeout(cntlr, &seconds);
319     if (ret != HDF_SUCCESS) {
320         HDF_LOGE("WatchdogUserGetTimeout: watchdog cntlr get timeout fail, ret: %d!", ret);
321         return ret;
322     }
323 
324     if (!HdfSbufWriteUint32(reply, seconds)) {
325         HDF_LOGE("WatchdogUserGetTimeout: sbuf write buffer fail!");
326         return HDF_ERR_IO;
327     }
328     return HDF_SUCCESS;
329 }
330 
WatchdogIoDispatch(struct HdfDeviceIoClient * client,int cmd,struct HdfSBuf * data,struct HdfSBuf * reply)331 static int32_t WatchdogIoDispatch(struct HdfDeviceIoClient *client, int cmd,
332     struct HdfSBuf *data, struct HdfSBuf *reply)
333 {
334     struct WatchdogCntlr *cntlr = NULL;
335 
336     if (client == NULL) {
337         HDF_LOGE("WatchdogIoDispatch: client is null!");
338         return HDF_ERR_INVALID_OBJECT;
339     }
340     if (client->device == NULL) {
341         HDF_LOGE("WatchdogIoDispatch: client->device is null!");
342         return HDF_ERR_INVALID_OBJECT;
343     }
344     if (client->device->service == NULL) {
345         HDF_LOGE("WatchdogIoDispatch: client->device->service is null!");
346         return HDF_ERR_INVALID_OBJECT;
347     }
348 
349     cntlr = (struct WatchdogCntlr *)client->device->service;
350     switch (cmd) {
351         case WATCHDOG_IO_GET_PRIV:
352             return WatchdogUserGetPrivData(cntlr, reply);
353         case WATCHDOG_IO_RELEASE_PRIV:
354             return WatchdogReleasePriv(cntlr);
355         case WATCHDOG_IO_GET_STATUS:
356             return WatchdogUserGetStatus(cntlr, reply);
357         case WATCHDOG_IO_START:
358             return WatchdogCntlrStart(cntlr);
359         case WATCHDOG_IO_STOP:
360             return WatchdogCntlrStop(cntlr);
361         case WATCHDOG_IO_SET_TIMEOUT:
362             return WatchdogUserSetTimeout(cntlr, data);
363         case WATCHDOG_IO_GET_TIMEOUT:
364             return WatchdogUserGetTimeout(cntlr, reply);
365         case WATCHDOG_IO_FEED:
366             return WatchdogCntlrFeed(cntlr);
367         default:
368             HDF_LOGE("WatchdogIoDispatch: cmd %d is not support!", cmd);
369             return HDF_ERR_NOT_SUPPORT;
370     }
371 }
372