1 /***************************************************************************
2  * Copyright (c) 2024 Microsoft Corporation
3  * Copyright (c) 2024 Intel Corporation
4  *
5  * This program and the accompanying materials are made available under the
6  * terms of the MIT License which is available at
7  * https://opensource.org/licenses/MIT.
8  *
9  * SPDX-License-Identifier: MIT
10  **************************************************************************/
11 
12 /**************************************************************************/
13 /**************************************************************************/
14 /**                                                                       */
15 /** Thread-Metric Component                                               */
16 /**                                                                       */
17 /**   Porting Layer (Must be completed with RTOS specifics)               */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 /* Include necessary files.  */
23 
24 #include "tm_api.h"
25 
26 #include <zephyr/kernel.h>
27 
28 #define TM_TEST_NUM_THREADS        10
29 #define TM_TEST_STACK_SIZE         1024
30 #define TM_TEST_NUM_SEMAPHORES     4
31 #define TM_TEST_NUM_MESSAGE_QUEUES 4
32 #define TM_TEST_NUM_SLABS          4
33 
34 #if (CONFIG_MP_MAX_NUM_CPUS > 1)
35 #error "*** Tests are only designed for single processor systems! ***"
36 #endif
37 
38 static struct k_thread test_thread[TM_TEST_NUM_THREADS];
39 static K_THREAD_STACK_ARRAY_DEFINE(test_stack, TM_TEST_NUM_THREADS, TM_TEST_STACK_SIZE);
40 
41 static struct k_sem test_sem[TM_TEST_NUM_SEMAPHORES];
42 
43 static struct k_msgq test_msgq[TM_TEST_NUM_MESSAGE_QUEUES];
44 static char test_msgq_buffer[TM_TEST_NUM_MESSAGE_QUEUES][8][16];
45 
46 static struct k_mem_slab test_slab[TM_TEST_NUM_SLABS];
47 static char __aligned(4) test_slab_buffer[TM_TEST_NUM_SLABS][8 * 128];
48 
49 /*
50  * This function called from main performs basic RTOS initialization,
51  * calls the test initialization function, and then starts the RTOS function.
52  */
tm_initialize(void (* test_initialization_function)(void))53 void tm_initialize(void (*test_initialization_function)(void))
54 {
55 	test_initialization_function();
56 }
57 
58 /*
59  * This function takes a thread ID and priority and attempts to create the
60  * file in the underlying RTOS.  Valid priorities range from 1 through 31,
61  * where 1 is the highest priority and 31 is the lowest. If successful,
62  * the function should return TM_SUCCESS. Otherwise, TM_ERROR should be returned.
63  */
tm_thread_create(int thread_id,int priority,void (* entry_function)(void *,void *,void *))64 int tm_thread_create(int thread_id, int priority, void (*entry_function)(void *, void *, void *))
65 {
66 	k_tid_t tid;
67 
68 	tid = k_thread_create(&test_thread[thread_id], test_stack[thread_id],
69 			      TM_TEST_STACK_SIZE, entry_function,
70 			      NULL, NULL, NULL, priority, 0, K_FOREVER);
71 
72 	/* Thread started in sleeping state. Switch to suspended state */
73 
74 	k_thread_suspend(&test_thread[thread_id]);
75 	k_wakeup(&test_thread[thread_id]);
76 
77 	return (tid == &test_thread[thread_id]) ? TM_SUCCESS : TM_ERROR;
78 }
79 
80 /*
81  * This function resumes the specified thread.  If successful, the function should
82  * return TM_SUCCESS. Otherwise, TM_ERROR should be returned.
83  */
tm_thread_resume(int thread_id)84 int tm_thread_resume(int thread_id)
85 {
86 	k_thread_resume(&test_thread[thread_id]);
87 
88 	return TM_SUCCESS;
89 }
90 
91 /*
92  * This function suspends the specified thread.  If successful, the function should
93  * return TM_SUCCESS. Otherwise, TM_ERROR should be returned.
94  */
tm_thread_suspend(int thread_id)95 int tm_thread_suspend(int thread_id)
96 {
97 	k_thread_suspend(&test_thread[thread_id]);
98 
99 	return TM_SUCCESS;
100 }
101 
102 /*
103  * This function relinquishes to other ready threads at the same
104  * priority.
105  */
tm_thread_relinquish(void)106 void tm_thread_relinquish(void)
107 {
108 	k_yield();
109 }
110 
111 /*
112  * This function suspends the specified thread for the specified number
113  * of seconds.
114  */
tm_thread_sleep(int seconds)115 void tm_thread_sleep(int seconds)
116 {
117 	k_sleep(K_SECONDS(seconds));
118 }
119 
120 /*
121  * This function creates the specified queue.  If successful, the function should
122  * return TM_SUCCESS. Otherwise, TM_ERROR should be returned.
123  */
tm_queue_create(int queue_id)124 int tm_queue_create(int queue_id)
125 {
126 	k_msgq_init(&test_msgq[queue_id], &test_msgq_buffer[queue_id][0][0], 16, 8);
127 
128 	return TM_SUCCESS;
129 }
130 
131 /*
132  * This function sends a 16-byte message to the specified queue.  If successful,
133  * the function should return TM_SUCCESS. Otherwise, TM_ERROR should be returned.
134  */
tm_queue_send(int queue_id,unsigned long * message_ptr)135 int tm_queue_send(int queue_id, unsigned long *message_ptr)
136 {
137 	return k_msgq_put(&test_msgq[queue_id], message_ptr, K_FOREVER);
138 }
139 
140 /*
141  * This function receives a 16-byte message from the specified queue.  If successful,
142  * the function should return TM_SUCCESS. Otherwise, TM_ERROR should be returned.
143  */
tm_queue_receive(int queue_id,unsigned long * message_ptr)144 int tm_queue_receive(int queue_id, unsigned long *message_ptr)
145 {
146 	return k_msgq_get(&test_msgq[queue_id], message_ptr, K_FOREVER);
147 }
148 
149 /*
150  * This function creates the specified semaphore.  If successful, the function should
151  * return TM_SUCCESS. Otherwise, TM_ERROR should be returned.
152  */
tm_semaphore_create(int semaphore_id)153 int tm_semaphore_create(int semaphore_id)
154 {
155 	/* Create an available semaphore with max count of 1 */
156 	return k_sem_init(&test_sem[semaphore_id], 1, 1);
157 }
158 
159 /*
160  * This function gets the specified semaphore.  If successful, the function should
161  * return TM_SUCCESS. Otherwise, TM_ERROR should be returned.
162  */
tm_semaphore_get(int semaphore_id)163 int tm_semaphore_get(int semaphore_id)
164 {
165 	return k_sem_take(&test_sem[semaphore_id], K_NO_WAIT);
166 }
167 
168 /*
169  * This function puts the specified semaphore.  If successful, the function should
170  * return TM_SUCCESS. Otherwise, TM_ERROR should be returned.
171  */
tm_semaphore_put(int semaphore_id)172 int tm_semaphore_put(int semaphore_id)
173 {
174 	k_sem_give(&test_sem[semaphore_id]);
175 	return TM_SUCCESS;
176 }
177 
178 /* This function is defined by the benchmark. */
179 extern void tm_interrupt_handler(const void *);
180 
tm_cause_interrupt(void)181 void tm_cause_interrupt(void)
182 {
183 	irq_offload(tm_interrupt_handler, NULL);
184 }
185 
186 /*
187  * This function creates the specified memory pool that can support one or more
188  * allocations of 128 bytes.  If successful, the function should
189  * return TM_SUCCESS. Otherwise, TM_ERROR should be returned.
190  */
tm_memory_pool_create(int pool_id)191 int tm_memory_pool_create(int pool_id)
192 {
193 	int status;
194 
195 	status = k_mem_slab_init(&test_slab[pool_id], &test_slab_buffer[pool_id][0], 128, 8);
196 
197 	return (status == 0) ? TM_SUCCESS : TM_ERROR;
198 }
199 
200 /*
201  * This function allocates a 128 byte block from the specified memory pool.
202  * If successful, the function should return TM_SUCCESS. Otherwise, TM_ERROR
203  * should be returned.
204  */
tm_memory_pool_allocate(int pool_id,unsigned char ** memory_ptr)205 int tm_memory_pool_allocate(int pool_id, unsigned char **memory_ptr)
206 {
207 	int status;
208 
209 	status = k_mem_slab_alloc(&test_slab[pool_id], (void **)memory_ptr, K_NO_WAIT);
210 
211 	return (status == 0) ? TM_SUCCESS : TM_ERROR;
212 }
213 
214 /*
215  * This function releases a previously allocated 128 byte block from the specified
216  * memory pool. If successful, the function should return TM_SUCCESS. Otherwise, TM_ERROR
217  * should be returned.
218  */
tm_memory_pool_deallocate(int pool_id,unsigned char * memory_ptr)219 int tm_memory_pool_deallocate(int pool_id, unsigned char *memory_ptr)
220 {
221 	k_mem_slab_free(&test_slab[pool_id], (void *)memory_ptr);
222 
223 	return TM_SUCCESS;
224 }
225