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 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