xref: /optee_os/core/tests/notif_test_wd.c (revision 47bcc886c285b4682fc756ecf5a28f35bed637e9)
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 
62 static void wd_ndrv_yielding_cb(struct notif_driver *ndrv __unused,
63 				enum notif_event ev)
64 {
65 	if (ev == NOTIF_EVENT_DO_BOTTOM_HALF) {
66 		struct wd_data *wd = get_wd_data();
67 
68 		if (wd->pending && wd->call_count < 10)
69 			DMSG("Clearing pending");
70 		wd->pending = false;
71 	}
72 }
73 
74 struct notif_driver wd_ndrv __nex_data = {
75 	.atomic_cb = wd_ndrv_atomic_cb,
76 	.yielding_cb = wd_ndrv_yielding_cb,
77 };
78 
79 static TEE_Result nex_init_test_wd(void)
80 {
81 	notif_register_driver(&wd_ndrv);
82 
83 	return TEE_SUCCESS;
84 }
85 
86 nex_early_init(nex_init_test_wd);
87 
88 struct periodic_data {
89 	unsigned int count;
90 	struct callout callout;
91 };
92 
93 static bool periodic_callback(struct callout *co)
94 {
95 	struct periodic_data *d = container_of(co, struct periodic_data,
96 					       callout);
97 	TEE_Time t = { };
98 
99 	if (tee_time_get_sys_time(&t))
100 		panic();
101 	d->count++;
102 	DMSG("seconds %"PRIu32" millis %"PRIu32" count %u",
103 	     t.seconds, t.millis, d->count);
104 
105 	if (d->count > 20) {
106 		DMSG("Disabling periodic callout");
107 		return false;
108 	}
109 
110 	return true;
111 }
112 
113 static TEE_Result nex_init_periodic_callback(void)
114 {
115 	struct periodic_data *d = nex_calloc(1, sizeof(*d));
116 
117 	if (!d)
118 		return TEE_ERROR_OUT_OF_MEMORY;
119 
120 	DMSG("Adding a periodic callout");
121 	callout_add(&d->callout, periodic_callback, TEST_WD_TIMER_PERIOD_MS);
122 
123 	return TEE_SUCCESS;
124 }
125 
126 nex_early_init(nex_init_periodic_callback);
127