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 	k_mem_slab_init(&mslab->z_mslab, mslab->pool, block_size, block_count);
72 
73 	if (attr->name == NULL) {
74 		strncpy(mslab->name, init_mslab_attrs.name,
75 			sizeof(mslab->name) - 1);
76 	} else {
77 		strncpy(mslab->name, attr->name, sizeof(mslab->name) - 1);
78 	}
79 
80 	return (osMemoryPoolId_t)mslab;
81 }
82 
83 /**
84  * @brief Allocate a memory block from a memory pool.
85  */
osMemoryPoolAlloc(osMemoryPoolId_t mp_id,uint32_t timeout)86 void *osMemoryPoolAlloc(osMemoryPoolId_t mp_id, uint32_t timeout)
87 {
88 	struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id;
89 	int retval;
90 	void *ptr;
91 
92 	if (mslab == NULL) {
93 		return NULL;
94 	}
95 
96 	/* Can be called from ISRs only if timeout is set to 0 */
97 	if (timeout > 0 && k_is_in_isr()) {
98 		return NULL;
99 	}
100 
101 	if (timeout == 0U) {
102 		retval = k_mem_slab_alloc(
103 			(struct k_mem_slab *)(&mslab->z_mslab),
104 			(void **)&ptr, K_NO_WAIT);
105 	} else if (timeout == osWaitForever) {
106 		retval = k_mem_slab_alloc(
107 			(struct k_mem_slab *)(&mslab->z_mslab),
108 			(void **)&ptr, K_FOREVER);
109 	} else {
110 		retval = k_mem_slab_alloc(
111 			(struct k_mem_slab *)(&mslab->z_mslab),
112 			(void **)&ptr, K_TICKS(timeout));
113 	}
114 
115 	if (retval == 0) {
116 		return ptr;
117 	} else {
118 		return NULL;
119 	}
120 }
121 
122 /**
123  * @brief Return an allocated memory block back to a specific memory pool.
124  */
osMemoryPoolFree(osMemoryPoolId_t mp_id,void * block)125 osStatus_t osMemoryPoolFree(osMemoryPoolId_t mp_id, void *block)
126 {
127 	struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id;
128 
129 	if (mslab == NULL) {
130 		return osErrorParameter;
131 	}
132 
133 	/* Note: Below error code is not supported.
134 	 *       osErrorResource: the memory pool specified by parameter mp_id
135 	 *       is in an invalid memory pool state.
136 	 */
137 
138 	k_mem_slab_free((struct k_mem_slab *)(&mslab->z_mslab), (void *)&block);
139 
140 	return osOK;
141 }
142 
143 /**
144  * @brief Get name of a Memory Pool object.
145  */
osMemoryPoolGetName(osMemoryPoolId_t mp_id)146 const char *osMemoryPoolGetName(osMemoryPoolId_t mp_id)
147 {
148 	struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id;
149 
150 	if (!k_is_in_isr() && (mslab != NULL)) {
151 		return mslab->name;
152 	} else {
153 		return NULL;
154 	}
155 }
156 
157 /**
158  * @brief Get maximum number of memory blocks in a Memory Pool.
159  */
osMemoryPoolGetCapacity(osMemoryPoolId_t mp_id)160 uint32_t osMemoryPoolGetCapacity(osMemoryPoolId_t mp_id)
161 {
162 	struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id;
163 
164 	if (mslab == NULL) {
165 		return 0;
166 	} else {
167 		return mslab->z_mslab.num_blocks;
168 	}
169 }
170 
171 /**
172  * @brief Get memory block size in a Memory Pool.
173  */
osMemoryPoolGetBlockSize(osMemoryPoolId_t mp_id)174 uint32_t osMemoryPoolGetBlockSize(osMemoryPoolId_t mp_id)
175 {
176 	struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id;
177 
178 	if (mslab == NULL) {
179 		return 0;
180 	} else {
181 		return mslab->z_mslab.block_size;
182 	}
183 }
184 
185 /**
186  * @brief Get number of memory blocks used in a Memory Pool.
187  */
osMemoryPoolGetCount(osMemoryPoolId_t mp_id)188 uint32_t osMemoryPoolGetCount(osMemoryPoolId_t mp_id)
189 {
190 	struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id;
191 
192 	if (mslab == NULL) {
193 		return 0;
194 	} else {
195 		return k_mem_slab_num_used_get(&mslab->z_mslab);
196 	}
197 }
198 
199 /**
200  * @brief Get number of memory blocks available in a Memory Pool.
201  */
osMemoryPoolGetSpace(osMemoryPoolId_t mp_id)202 uint32_t osMemoryPoolGetSpace(osMemoryPoolId_t mp_id)
203 {
204 	struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id;
205 
206 	if (mslab == NULL) {
207 		return 0;
208 	} else {
209 		return k_mem_slab_num_free_get(&mslab->z_mslab);
210 	}
211 }
212 
213 /**
214  * @brief Delete a Memory Pool object.
215  */
osMemoryPoolDelete(osMemoryPoolId_t mp_id)216 osStatus_t osMemoryPoolDelete(osMemoryPoolId_t mp_id)
217 {
218 	struct cv2_mslab *mslab = (struct cv2_mslab *)mp_id;
219 
220 	if (mslab == NULL) {
221 		return osErrorParameter;
222 	}
223 
224 	if (k_is_in_isr()) {
225 		return osErrorISR;
226 	}
227 
228 	/* The status code "osErrorResource" (the memory pool specified by
229 	 * parameter mp_id is in an invalid memory pool state) is not
230 	 * supported in Zephyr.
231 	 */
232 
233 	if (mslab->is_dynamic_allocation) {
234 		k_free(mslab->pool);
235 	}
236 	k_mem_slab_free(&cv2_mem_slab, (void *)&mslab);
237 
238 	return osOK;
239 }
240