1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2024, Linaro Limited 4 */ 5 6 #include <initcall.h> 7 #include <kernel/callout.h> 8 #include <kernel/notif.h> 9 #include <kernel/panic.h> 10 #include <kernel/tee_time.h> 11 #include <kernel/virtualization.h> 12 #include <types_ext.h> 13 14 #define TEST_WD_TIMER_PERIOD_MS 1000 15 16 struct wd_data { 17 bool pending; 18 bool enabled; 19 unsigned int timeout_count; 20 unsigned int call_count; 21 struct callout callout; 22 }; 23 24 static struct wd_data default_wd_data; 25 26 static struct wd_data *get_wd_data(void) 27 { 28 return &default_wd_data; 29 } 30 31 static bool test_wd_callback(struct callout *co) 32 { 33 struct wd_data *wd = container_of(co, struct wd_data, callout); 34 35 if (wd->pending) 36 wd->timeout_count++; 37 wd->call_count++; 38 if (wd->call_count < 10 || !(wd->call_count % 60) || wd->pending) 39 DMSG("WD call_count %u, timeout_count %u", 40 wd->call_count, wd->timeout_count); 41 wd->pending = true; 42 notif_send_async(NOTIF_VALUE_DO_BOTTOM_HALF); 43 44 return true; 45 } 46 47 static void wd_ndrv_atomic_cb(struct notif_driver *ndrv __unused, 48 enum notif_event ev) 49 { 50 if (ev == NOTIF_EVENT_STARTED) { 51 struct wd_data *wd = get_wd_data(); 52 53 if (!wd->enabled) { 54 callout_add(&wd->callout, test_wd_callback, 55 TEST_WD_TIMER_PERIOD_MS); 56 57 wd->enabled = true; 58 } 59 } 60 } 61 DECLARE_KEEP_PAGER(wd_ndrv_atomic_cb); 62 63 static void wd_ndrv_yielding_cb(struct notif_driver *ndrv __unused, 64 enum notif_event ev) 65 { 66 if (ev == NOTIF_EVENT_DO_BOTTOM_HALF) { 67 struct wd_data *wd = get_wd_data(); 68 69 if (wd->pending && wd->call_count < 10) 70 DMSG("Clearing pending"); 71 wd->pending = false; 72 } 73 } 74 75 struct notif_driver wd_ndrv __nex_data = { 76 .atomic_cb = wd_ndrv_atomic_cb, 77 .yielding_cb = wd_ndrv_yielding_cb, 78 }; 79 80 static TEE_Result nex_init_test_wd(void) 81 { 82 notif_register_driver(&wd_ndrv); 83 84 return TEE_SUCCESS; 85 } 86 87 nex_early_init(nex_init_test_wd); 88 89 struct periodic_data { 90 unsigned int count; 91 struct callout callout; 92 }; 93 94 static bool periodic_callback(struct callout *co) 95 { 96 struct periodic_data *d = container_of(co, struct periodic_data, 97 callout); 98 TEE_Time t = { }; 99 100 if (tee_time_get_sys_time(&t)) 101 panic(); 102 d->count++; 103 DMSG("seconds %"PRIu32" millis %"PRIu32" count %u", 104 t.seconds, t.millis, d->count); 105 106 if (d->count > 20) { 107 DMSG("Disabling periodic callout"); 108 return false; 109 } 110 111 return true; 112 } 113 DECLARE_KEEP_PAGER(periodic_callback); 114 115 static TEE_Result nex_init_periodic_callback(void) 116 { 117 struct periodic_data *d = nex_calloc(1, sizeof(*d)); 118 119 if (!d) 120 return TEE_ERROR_OUT_OF_MEMORY; 121 122 DMSG("Adding a periodic callout"); 123 callout_add(&d->callout, periodic_callback, TEST_WD_TIMER_PERIOD_MS); 124 125 return TEE_SUCCESS; 126 } 127 128 nex_early_init(nex_init_periodic_callback); 129