xref: /optee_os/core/drivers/wdt/watchdog_sm.c (revision a7f2d4bd86327253733ce88d2160e4d02b8349b7)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright 2022 Microchip
4  */
5 
6 #include <drivers/wdt.h>
7 #include <kernel/spinlock.h>
8 #include <sm/optee_smc.h>
9 #include <sm/psci.h>
10 #include <sm/watchdog_smc.h>
11 
12 static unsigned long wdt_min_timeout;
13 static unsigned long wdt_max_timeout;
14 /* Lock for timeout variables */
15 static unsigned int wdt_lock = SPINLOCK_UNLOCK;
16 
__wdt_sm_handler(struct thread_smc_args * args)17 enum sm_handler_ret __wdt_sm_handler(struct thread_smc_args *args)
18 {
19 	TEE_Result res = TEE_ERROR_GENERIC;
20 	uint32_t exceptions = 0;
21 	unsigned long min_timeout = 0;
22 	unsigned long max_timeout = 0;
23 	unsigned long timeleft = 0;
24 	bool is_started = false;
25 
26 	switch (args->a1) {
27 	case SMCWD_INIT:
28 		exceptions = cpu_spin_lock_xsave(&wdt_lock);
29 		res = watchdog_init(&wdt_min_timeout, &wdt_max_timeout);
30 		cpu_spin_unlock_xrestore(&wdt_lock, exceptions);
31 
32 		if (res) {
33 			args->a0 = PSCI_RET_INTERNAL_FAILURE;
34 		} else {
35 			args->a0 = PSCI_RET_SUCCESS;
36 			args->a1 = wdt_min_timeout;
37 			args->a2 = wdt_max_timeout;
38 		}
39 		break;
40 	case SMCWD_SET_TIMEOUT:
41 		exceptions = cpu_spin_lock_xsave(&wdt_lock);
42 		min_timeout = wdt_min_timeout;
43 		max_timeout = wdt_max_timeout;
44 		cpu_spin_unlock_xrestore(&wdt_lock, exceptions);
45 
46 		if (args->a2 < min_timeout || args->a2 > max_timeout) {
47 			args->a0 = PSCI_RET_INVALID_PARAMETERS;
48 			break;
49 		}
50 
51 		watchdog_settimeout(args->a2);
52 		args->a0 = PSCI_RET_SUCCESS;
53 		break;
54 	case SMCWD_ENABLE:
55 		if (args->a2 == 0) {
56 			watchdog_stop();
57 			args->a0 = PSCI_RET_SUCCESS;
58 		} else if (args->a2 == 1) {
59 			watchdog_start();
60 			args->a0 = PSCI_RET_SUCCESS;
61 		} else {
62 			args->a0 = PSCI_RET_INVALID_PARAMETERS;
63 		}
64 		break;
65 	case SMCWD_PET:
66 		watchdog_ping();
67 		args->a0 = PSCI_RET_SUCCESS;
68 		break;
69 	/* SMCWD_GET_TIMELEFT is optional */
70 	case SMCWD_GET_TIMELEFT:
71 		res = watchdog_gettimeleft(&is_started, &timeleft);
72 		if (res == TEE_ERROR_NOT_SUPPORTED) {
73 			args->a0 = PSCI_RET_NOT_SUPPORTED;
74 		} else if (res) {
75 			args->a0 = PSCI_RET_INTERNAL_FAILURE;
76 		} else if (!is_started) {
77 			args->a0 = PSCI_RET_DISABLED;
78 		} else {
79 			args->a0 = PSCI_RET_SUCCESS;
80 			args->a1 = timeleft;
81 		}
82 		break;
83 	default:
84 		args->a0 = PSCI_RET_NOT_SUPPORTED;
85 	}
86 
87 	return SM_HANDLER_SMC_HANDLED;
88 }
89