1 /*
2 * Copyright (c) 2022-2023, Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Arm SiP services service ID manager and ID mapping table force
7 * clients and transactions.
8 */
9
10 #include <zephyr/kernel.h>
11 #include <zephyr/drivers/sip_svc/sip_svc_proto.h>
12 #include "sip_svc_id_mgr.h"
13
14 /**
15 * Create a id key pool using size variable 0..size-1, where we can
16 * track the allocated id.
17 */
sip_svc_id_mgr_create(uint32_t size)18 struct sip_svc_id_pool *sip_svc_id_mgr_create(uint32_t size)
19 {
20 struct sip_svc_id_pool *id_pool = NULL;
21 uint32_t mask_size = 0;
22 uint32_t i = 0;
23
24 if (size == SIP_SVC_ID_INVALID) {
25 return NULL;
26 }
27
28 /* Allocate memory for ID pool */
29 id_pool = k_malloc(sizeof(struct sip_svc_id_pool));
30 if (!id_pool) {
31 return NULL;
32 }
33 id_pool->size = size;
34
35 id_pool->id_list = k_malloc(size * sizeof(uint32_t));
36 if (!id_pool->id_list) {
37 k_free(id_pool);
38 return NULL;
39 }
40
41 mask_size = size / sizeof(uint32_t);
42 if (size % sizeof(uint32_t)) {
43 mask_size++;
44 }
45
46 id_pool->id_mask = k_malloc(mask_size * sizeof(uint32_t));
47 if (!id_pool->id_mask) {
48 k_free(id_pool->id_list);
49 k_free(id_pool);
50 return NULL;
51 }
52
53 /* Initialize ID */
54 for (i = 0; i < size; i++) {
55 id_pool->id_list[i] = i;
56 }
57
58 /* ID pool is full during initialization */
59 id_pool->head = 0;
60 id_pool->tail = size - 1;
61
62 /* Initialize ID in use flags */
63 for (i = 0; i < mask_size; i++) {
64 id_pool->id_mask[i] = 0;
65 }
66
67 return id_pool;
68 }
69
70 /* Delete a created id pool*/
sip_svc_id_mgr_delete(struct sip_svc_id_pool * id_pool)71 void sip_svc_id_mgr_delete(struct sip_svc_id_pool *id_pool)
72 {
73 if (id_pool) {
74 k_free(id_pool->id_mask);
75 k_free(id_pool->id_list);
76 k_free(id_pool);
77 }
78 }
79
80 /* Retrieve an id from the id pool*/
sip_svc_id_mgr_alloc(struct sip_svc_id_pool * id_pool)81 uint32_t sip_svc_id_mgr_alloc(struct sip_svc_id_pool *id_pool)
82 {
83 uint32_t id;
84 uint32_t row;
85 uint32_t col;
86
87 if (!id_pool) {
88 return SIP_SVC_ID_INVALID;
89 }
90
91 if (id_pool->head == SIP_SVC_ID_INVALID) {
92 return SIP_SVC_ID_INVALID;
93 }
94
95 id = id_pool->id_list[id_pool->head];
96
97 /* Calculate the mask bit position in id mask array*/
98 row = id / sizeof(uint32_t);
99 col = id % sizeof(uint32_t);
100 id_pool->id_mask[row] |= (1 << col);
101
102 if (id_pool->head == id_pool->tail) {
103 id_pool->head = SIP_SVC_ID_INVALID;
104 id_pool->tail = SIP_SVC_ID_INVALID;
105 } else {
106 id_pool->head++;
107 if (id_pool->head == id_pool->size) {
108 id_pool->head = 0;
109 }
110 }
111
112 return id;
113 }
114
115 /* Free the id that was allocated from the id_pool*/
sip_svc_id_mgr_free(struct sip_svc_id_pool * id_pool,uint32_t id)116 void sip_svc_id_mgr_free(struct sip_svc_id_pool *id_pool, uint32_t id)
117 {
118 uint32_t row;
119 uint32_t col;
120
121 if (!id_pool) {
122 return;
123 }
124
125 if (id >= id_pool->size) {
126 return;
127 }
128
129 row = id / sizeof(uint32_t);
130 col = id % sizeof(uint32_t);
131
132 /* check if the id was allocated earlier*/
133 if (!(id_pool->id_mask[row] & (1 << col))) {
134 return;
135 }
136
137 /* Clear the id mask bit */
138 id_pool->id_mask[row] &= ~(1 << col);
139
140 if (id_pool->head == SIP_SVC_ID_INVALID) {
141 id_pool->head = 0;
142 id_pool->tail = 0;
143 } else {
144 id_pool->tail++;
145 if (id_pool->tail == id_pool->size) {
146 id_pool->tail = 0;
147 }
148 if (id_pool->head == id_pool->tail) {
149 return;
150 }
151 }
152
153 id_pool->id_list[id_pool->tail] = id;
154 }
155
156 /* Allocate database to store values */
sip_svc_id_map_create(uint32_t size)157 struct sip_svc_id_map *sip_svc_id_map_create(uint32_t size)
158 {
159 struct sip_svc_id_map *id_map = NULL;
160 uint32_t items_size = (sizeof(struct sip_svc_id_map_item)) * size;
161 int i;
162
163 id_map = k_malloc(sizeof(struct sip_svc_id_map));
164 if (!id_map) {
165 return NULL;
166 }
167
168 id_map->items = k_malloc(items_size);
169 if (!id_map->items) {
170 k_free(id_map);
171 return NULL;
172 }
173
174 id_map->size = size;
175 for (i = 0; i < size; i++) {
176 id_map->items[i].id = SIP_SVC_ID_INVALID;
177 id_map->items[i].arg1 = NULL;
178 id_map->items[i].arg2 = NULL;
179 id_map->items[i].arg3 = NULL;
180 id_map->items[i].arg4 = NULL;
181 id_map->items[i].arg5 = NULL;
182 id_map->items[i].arg6 = NULL;
183 }
184
185 return id_map;
186 }
187
188
189 /* Delete a created database */
sip_svc_id_map_delete(struct sip_svc_id_map * id_map)190 void sip_svc_id_map_delete(struct sip_svc_id_map *id_map)
191 {
192 if (id_map) {
193 k_free(id_map->items);
194 k_free(id_map);
195 }
196 }
197
198 /* Retrieve index from from database with key(id)*/
sip_svc_id_map_get_idx(struct sip_svc_id_map * id_map,uint32_t id)199 static int sip_svc_id_map_get_idx(struct sip_svc_id_map *id_map, uint32_t id)
200 {
201 int i;
202
203 if (!id_map) {
204 return -EINVAL;
205 }
206
207 for (i = 0; i < id_map->size; i++) {
208 if (id_map->items[i].id == id) {
209 return i;
210 }
211 }
212
213 return -EINVAL;
214 }
215
216 /* Insert an entry into database with key as id*/
sip_svc_id_map_insert_item(struct sip_svc_id_map * id_map,uint32_t id,void * arg1,void * arg2,void * arg3,void * arg4,void * arg5,void * arg6)217 int sip_svc_id_map_insert_item(struct sip_svc_id_map *id_map, uint32_t id, void *arg1, void *arg2,
218 void *arg3, void *arg4, void *arg5, void *arg6)
219 {
220 int i;
221
222 if (!id_map) {
223 return -EINVAL;
224 }
225
226 i = sip_svc_id_map_get_idx(id_map, SIP_SVC_ID_INVALID);
227 if (i < 0) {
228 return -EINVAL;
229 }
230
231 id_map->items[i].id = id;
232 id_map->items[i].arg1 = arg1;
233 id_map->items[i].arg2 = arg2;
234 id_map->items[i].arg3 = arg3;
235 id_map->items[i].arg4 = arg4;
236 id_map->items[i].arg5 = arg5;
237 id_map->items[i].arg6 = arg6;
238
239 return 0;
240 }
241
242 /* Remove an entry with key id */
sip_svc_id_map_remove_item(struct sip_svc_id_map * id_map,uint32_t id)243 int sip_svc_id_map_remove_item(struct sip_svc_id_map *id_map, uint32_t id)
244 {
245 int i;
246
247 if (!id_map) {
248 return -EINVAL;
249 }
250
251 i = sip_svc_id_map_get_idx(id_map, id);
252 if (i < 0) {
253 return -EINVAL;
254 }
255
256 id_map->items[i].id = SIP_SVC_ID_INVALID;
257 id_map->items[i].arg1 = NULL;
258 id_map->items[i].arg2 = NULL;
259 id_map->items[i].arg3 = NULL;
260 id_map->items[i].arg4 = NULL;
261 id_map->items[i].arg5 = NULL;
262 id_map->items[i].arg6 = NULL;
263
264 return 0;
265 }
266
267 /* Query an entry from database using key id*/
sip_svc_id_map_query_item(struct sip_svc_id_map * id_map,uint32_t id)268 struct sip_svc_id_map_item *sip_svc_id_map_query_item(struct sip_svc_id_map *id_map, uint32_t id)
269 {
270 int i;
271
272 if (!id_map) {
273 return NULL;
274 }
275
276 i = sip_svc_id_map_get_idx(id_map, id);
277 if (i < 0) {
278 return NULL;
279 }
280
281 return &id_map->items[i];
282 }
283