1 /*
2  * Copyright (c) 2018 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <string.h>
9 #include "wrapper.h"
10 
11 #define TIME_OUT_TICKS  10
12 
13 K_MEM_SLAB_DEFINE(cv2_mem_slab, sizeof(struct cv2_mslab),
14 		  CONFIG_CMSIS_V2_MEM_SLAB_MAX_COUNT, 4);
15 
16 static const osMemoryPoolAttr_t init_mslab_attrs = {
17 	.name = "ZephyrMemPool",
18 	.attr_bits = 0,
19 	.cb_mem = NULL,
20 	.cb_size = 0,
21 	.mp_mem = NULL,
22 	.mp_size = 0,
23 };
24 
25 /**
26  * @brief Create and Initialize a memory pool.
27  */
osMemoryPoolNew(uint32_t block_count,uint32_t block_size,const osMemoryPoolAttr_t * attr)28 osMemoryPoolId_t osMemoryPoolNew(uint32_t block_count, uint32_t block_size,
29 				 const osMemoryPoolAttr_t *attr)
30 {
31 	struct cv2_mslab *mslab;
32 
33 	BUILD_ASSERT(CONFIG_HEAP_MEM_POOL_SIZE >=
34 		     CONFIG_CMSIS_V2_MEM_SLAB_MAX_DYNAMIC_SIZE,
35 		     "heap must be configured to be at least the max dynamic size");
36 
37 	if (k_is_in_isr()) {
38 		return NULL;
39 	}
40 
41 	if ((attr != NULL) && (attr->mp_size < block_count * block_size)) {
42 		return NULL;
43 	}
44 
45 	if (attr == NULL) {
46 		attr = &init_mslab_attrs;
47 	}
48 
49 	if (k_mem_slab_alloc(&cv2_mem_slab, (void **)&mslab, K_MSEC(100)) == 0) {
50 		(void)memset(mslab, 0, sizeof(struct cv2_mslab));
51 	} else {
52 		return NULL;
53 	}
54 
55 	if (attr->mp_mem == NULL) {
56 		__ASSERT((block_count * block_size) <=
57 			 CONFIG_CMSIS_V2_MEM_SLAB_MAX_DYNAMIC_SIZE,
58 			 "memory slab/pool size exceeds dynamic maximum");
59 
60 		mslab->pool = k_calloc(block_count, block_size);
61 		if (mslab->pool == NULL) {
62 			k_mem_slab_free(&cv2_mem_slab, (void *)mslab);
63 			return NULL;
64 		}
65 		mslab->is_dynamic_allocation = TRUE;
66 	} else {
67 		mslab->pool = attr->mp_mem;
68 		mslab->is_dynamic_allocation = FALSE;
69 	}
70 
71 	int rc = k_mem_slab_init(&mslab->z_mslab, mslab->pool, block_size, block_count);
72 
73 	if (rc != 0) {
74 		k_mem_slab_free(&cv2_mem_slab, (void *)mslab);
75 		if (attr->mp_mem == NULL) {
76 			k_free(mslab->pool);
77 		}
78 		return NULL;
79 	}
80 
81 	if (attr->name == NULL) {
82 		strncpy(mslab->name, init_mslab_attrs.name,
83 			sizeof(mslab->name) - 1);
84 	} else {
85 		strncpy(mslab->name, attr->name, sizeof(mslab->name) - 1);
86 	}
87 
88 	return (osMemoryPoolId_t)mslab;
89 }
90 
91 /**
92  * @brief Allocate a memory block from a memory pool.
93  */
osMemoryPoolAlloc(osMemoryPoolId_t mp_id,uint32_t timeout)94 void *osMemoryPoolAlloc(osMemoryPoolId_t mp_id, uint32_t timeout)
95 {
96 	struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id;
97 	int retval;
98 	void *ptr;
99 
100 	if (mslab == NULL) {
101 		return NULL;
102 	}
103 
104 	/* Can be called from ISRs only if timeout is set to 0 */
105 	if (timeout > 0 && k_is_in_isr()) {
106 		return NULL;
107 	}
108 
109 	if (timeout == 0U) {
110 		retval = k_mem_slab_alloc(
111 			(struct k_mem_slab *)(&mslab->z_mslab),
112 			(void **)&ptr, K_NO_WAIT);
113 	} else if (timeout == osWaitForever) {
114 		retval = k_mem_slab_alloc(
115 			(struct k_mem_slab *)(&mslab->z_mslab),
116 			(void **)&ptr, K_FOREVER);
117 	} else {
118 		retval = k_mem_slab_alloc(
119 			(struct k_mem_slab *)(&mslab->z_mslab),
120 			(void **)&ptr, K_TICKS(timeout));
121 	}
122 
123 	if (retval == 0) {
124 		return ptr;
125 	} else {
126 		return NULL;
127 	}
128 }
129 
130 /**
131  * @brief Return an allocated memory block back to a specific memory pool.
132  */
osMemoryPoolFree(osMemoryPoolId_t mp_id,void * block)133 osStatus_t osMemoryPoolFree(osMemoryPoolId_t mp_id, void *block)
134 {
135 	struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id;
136 
137 	if (mslab == NULL) {
138 		return osErrorParameter;
139 	}
140 
141 	/* Note: Below error code is not supported.
142 	 *       osErrorResource: the memory pool specified by parameter mp_id
143 	 *       is in an invalid memory pool state.
144 	 */
145 
146 	k_mem_slab_free((struct k_mem_slab *)(&mslab->z_mslab), (void *)block);
147 
148 	return osOK;
149 }
150 
151 /**
152  * @brief Get name of a Memory Pool object.
153  */
osMemoryPoolGetName(osMemoryPoolId_t mp_id)154 const char *osMemoryPoolGetName(osMemoryPoolId_t mp_id)
155 {
156 	struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id;
157 
158 	if (!k_is_in_isr() && (mslab != NULL)) {
159 		return mslab->name;
160 	} else {
161 		return NULL;
162 	}
163 }
164 
165 /**
166  * @brief Get maximum number of memory blocks in a Memory Pool.
167  */
osMemoryPoolGetCapacity(osMemoryPoolId_t mp_id)168 uint32_t osMemoryPoolGetCapacity(osMemoryPoolId_t mp_id)
169 {
170 	struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id;
171 
172 	if (mslab == NULL) {
173 		return 0;
174 	} else {
175 		return mslab->z_mslab.info.num_blocks;
176 	}
177 }
178 
179 /**
180  * @brief Get memory block size in a Memory Pool.
181  */
osMemoryPoolGetBlockSize(osMemoryPoolId_t mp_id)182 uint32_t osMemoryPoolGetBlockSize(osMemoryPoolId_t mp_id)
183 {
184 	struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id;
185 
186 	if (mslab == NULL) {
187 		return 0;
188 	} else {
189 		return mslab->z_mslab.info.block_size;
190 	}
191 }
192 
193 /**
194  * @brief Get number of memory blocks used in a Memory Pool.
195  */
osMemoryPoolGetCount(osMemoryPoolId_t mp_id)196 uint32_t osMemoryPoolGetCount(osMemoryPoolId_t mp_id)
197 {
198 	struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id;
199 
200 	if (mslab == NULL) {
201 		return 0;
202 	} else {
203 		return k_mem_slab_num_used_get(&mslab->z_mslab);
204 	}
205 }
206 
207 /**
208  * @brief Get number of memory blocks available in a Memory Pool.
209  */
osMemoryPoolGetSpace(osMemoryPoolId_t mp_id)210 uint32_t osMemoryPoolGetSpace(osMemoryPoolId_t mp_id)
211 {
212 	struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id;
213 
214 	if (mslab == NULL) {
215 		return 0;
216 	} else {
217 		return k_mem_slab_num_free_get(&mslab->z_mslab);
218 	}
219 }
220 
221 /**
222  * @brief Delete a Memory Pool object.
223  */
osMemoryPoolDelete(osMemoryPoolId_t mp_id)224 osStatus_t osMemoryPoolDelete(osMemoryPoolId_t mp_id)
225 {
226 	struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id;
227 
228 	if (mslab == NULL) {
229 		return osErrorParameter;
230 	}
231 
232 	if (k_is_in_isr()) {
233 		return osErrorISR;
234 	}
235 
236 	/* The status code "osErrorResource" (the memory pool specified by
237 	 * parameter mp_id is in an invalid memory pool state) is not
238 	 * supported in Zephyr.
239 	 */
240 
241 	if (mslab->is_dynamic_allocation) {
242 		k_free(mslab->pool);
243 	}
244 	k_mem_slab_free(&cv2_mem_slab, (void *)mslab);
245 
246 	return osOK;
247 }
248