xref: /optee_os/core/tests/notif_test_wd.c (revision af3fb62410645ac9636d27c3d1db72c0c9fca913)
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