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)17enum 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