1 /***************************************************************************//**
2 * \file cy_ipc_sema.c
3 * \version 1.60
4 *
5 * Description:
6 * IPC Semaphore Driver - This source file contains the source code for the
7 * semaphore level APIs for the IPC interface.
8 *
9 ********************************************************************************
10 * Copyright 2016-2020 Cypress Semiconductor Corporation
11 * SPDX-License-Identifier: Apache-2.0
12 *
13 * Licensed under the Apache License, Version 2.0 (the "License");
14 * you may not use this file except in compliance with the License.
15 * You may obtain a copy of the License at
16 *
17 * http://www.apache.org/licenses/LICENSE-2.0
18 *
19 * Unless required by applicable law or agreed to in writing, software
20 * distributed under the License is distributed on an "AS IS" BASIS,
21 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 * See the License for the specific language governing permissions and
23 * limitations under the License.
24 *******************************************************************************/
25
26 #include "cy_device.h"
27
28 #if defined (CY_IP_M4CPUSS)
29
30 #include "cy_ipc_drv.h"
31 #include "cy_ipc_sema.h"
32 #include "cy_syslib.h"
33 #include <string.h> /* The memset() definition */
34
35 /* Defines a mask to Check if semaphore count is a multiple of 32 */
36 #define CY_IPC_SEMA_PER_WORD_MASK (CY_IPC_SEMA_PER_WORD - 1UL)
37
38 /* Pointer to IPC structure used for semaphores */
39 static IPC_STRUCT_Type* cy_semaIpcStruct;
40
41
42 /*******************************************************************************
43 * Function Name: Cy_IPC_Sema_Init
44 ****************************************************************************//**
45 *
46 * This function initializes the semaphores subsystem. The user must create an
47 * array of unsigned 32-bit words to hold the semaphore bits. The number
48 * of semaphores will be the size of the array * 32. The total semaphores count
49 * will always be a multiple of 32.
50 *
51 * \note In a multi-CPU system this init function should be called with all
52 * initialized parameters on one CPU only to provide a pointer to SRAM that can
53 * be shared between all the CPUs in the system that will use semaphores.
54 * On other CPUs user must specify the IPC semaphores channel and pass 0 / NULL
55 * to count and memPtr parameters correspondingly.
56 *
57 * \param ipcChannel
58 * The IPC channel number used for semaphores
59 *
60 * \param count
61 * The maximum number of semaphores to be supported (multiple of 32).
62 *
63 * \param memPtr
64 * This points to the array of (count/32) words that contain the semaphore data.
65 *
66 * \return Status of the operation
67 * \retval CY_IPC_SEMA_SUCCESS: Successfully initialized
68 * \retval CY_IPC_SEMA_BAD_PARAM: Memory pointer is NULL and count is not zero,
69 * or count not multiple of 32
70 * \retval CY_IPC_SEMA_ERROR_LOCKED: Could not acquire semaphores IPC channel
71 *
72 * \funcusage
73 * \snippet ipc/snippet/main.c snippet_Cy_IPC_Sema_Init
74 *
75 *******************************************************************************/
Cy_IPC_Sema_Init(uint32_t ipcChannel,uint32_t count,uint32_t memPtr[])76 cy_en_ipcsema_status_t Cy_IPC_Sema_Init(uint32_t ipcChannel,
77 uint32_t count, uint32_t memPtr[])
78 {
79 /* Structure containing semaphores control data */
80 CY_SECTION_SHAREDMEM
81 static cy_stc_ipc_sema_t cy_semaData;
82
83 cy_en_ipcsema_status_t retStatus = CY_IPC_SEMA_BAD_PARAM;
84
85 if( (NULL == memPtr) && (0u == count))
86 {
87 cy_semaIpcStruct = Cy_IPC_Drv_GetIpcBaseAddress(ipcChannel);
88
89 retStatus = CY_IPC_SEMA_SUCCESS;
90 }
91
92 /* Check for non Null pointers and count value */
93 else if ((NULL != memPtr) && (0u != count))
94 {
95 cy_semaData.maxSema = count;
96 cy_semaData.arrayPtr = memPtr;
97
98 retStatus = Cy_IPC_Sema_InitExt(ipcChannel, &cy_semaData);
99 }
100
101 else
102 {
103 retStatus = CY_IPC_SEMA_BAD_PARAM;
104 }
105
106 return(retStatus);
107 }
108
109
110 /*******************************************************************************
111 * Function Name: Cy_IPC_Sema_InitExt
112 ****************************************************************************//**
113 * This function initializes the semaphores subsystem. The user must create an
114 * array of unsigned 32-bit words to hold the semaphore bits. The number
115 * of semaphores will be the size of the array * 32. The total semaphores count
116 * will always be a multiple of 32.
117 *
118 * \note In a multi-CPU system this init function should be called with all
119 * initialized parameters on one CPU only to provide a pointer to SRAM that can
120 * be shared between all the CPUs in the system that will use semaphores.
121 * On other CPUs user must specify the IPC semaphores channel and pass 0 / NULL
122 * to count and memPtr parameters correspondingly.
123 *
124 * \param ipcChannel
125 * The IPC channel number used for semaphores
126 *
127 * \param ipcSema
128 * This is configuration structure of the IPC semaphore.
129 * See \ref cy_stc_ipc_sema_t.
130 *
131 * \return Status of the operation
132 * \retval CY_IPC_SEMA_SUCCESS: Successfully initialized
133 * \retval CY_IPC_SEMA_BAD_PARAM: Memory pointer is NULL and count is not zero,
134 * or count not multiple of 32
135 * \retval CY_IPC_SEMA_ERROR_LOCKED: Could not acquire semaphores IPC channel
136 *
137 *******************************************************************************/
Cy_IPC_Sema_InitExt(uint32_t ipcChannel,cy_stc_ipc_sema_t * ipcSema)138 cy_en_ipcsema_status_t Cy_IPC_Sema_InitExt(uint32_t ipcChannel, cy_stc_ipc_sema_t *ipcSema)
139 {
140 cy_en_ipcsema_status_t retStatus = CY_IPC_SEMA_BAD_PARAM;
141
142 if (ipcChannel >= CY_IPC_CHANNELS)
143 {
144 retStatus = CY_IPC_SEMA_BAD_PARAM;
145 }
146 else
147 {
148 if(NULL != ipcSema)
149 {
150 /* Check if semaphore count is a multiple of 32 */
151 if( 0UL == (ipcSema->maxSema & CY_IPC_SEMA_PER_WORD_MASK))
152 {
153 cy_semaIpcStruct = Cy_IPC_Drv_GetIpcBaseAddress(ipcChannel);
154
155 /* Initialize all semaphores to released */
156 (void)memset(ipcSema->arrayPtr, 0, (ipcSema->maxSema /8u));
157
158 /* Make sure semaphores start out released. */
159 /* Ignore the return value since it is OK if it was already released. */
160 (void) Cy_IPC_Drv_LockRelease (cy_semaIpcStruct, CY_IPC_NO_NOTIFICATION);
161
162 /* Set the IPC Data with the pointer to the array. */
163 if( CY_IPC_DRV_SUCCESS == Cy_IPC_Drv_SendMsgPtr (cy_semaIpcStruct, CY_IPC_NO_NOTIFICATION, ipcSema))
164 {
165 if(CY_IPC_DRV_SUCCESS == Cy_IPC_Drv_LockRelease (cy_semaIpcStruct, CY_IPC_NO_NOTIFICATION))
166 {
167 retStatus = CY_IPC_SEMA_SUCCESS;
168 }
169 else
170 {
171 /* IPC channel not released, still semaphored */
172 retStatus = CY_IPC_SEMA_ERROR_LOCKED;
173 }
174 }
175 else
176 {
177 /* Could not acquire semaphore channel */
178 retStatus = CY_IPC_SEMA_ERROR_LOCKED;
179 }
180 }
181 else
182 {
183 retStatus = CY_IPC_SEMA_BAD_PARAM;
184 }
185 }
186 else
187 {
188 retStatus = CY_IPC_SEMA_BAD_PARAM;
189 }
190 }
191
192 return(retStatus);
193 }
194
195
196 /*******************************************************************************
197 * Function Name: Cy_IPC_Sema_Set
198 ****************************************************************************//**
199 *
200 * This function tries to acquire a semaphore. If the
201 * semaphore is not available, this function returns immediately with
202 * CY_IPC_SEMA_LOCKED.
203 *
204 * It first acquires the IPC channel that is used for all the semaphores, sets
205 * the semaphore if it is cleared, then releases the IPC channel used for the
206 * semaphore.
207 *
208 * \param semaNumber
209 * The semaphore number to acquire.
210 *
211 * \param preemptable
212 * When this parameter is enabled the function can be preempted by another
213 * task or other forms of context switching in an RTOS environment.
214 *
215 * \note
216 * If <b>preemptable</b> is enabled (true), the user must ensure that there are
217 * no deadlocks in the system, which can be caused by an interrupt that occurs
218 * after the IPC channel is locked. Unless the user is ready to handle IPC
219 * channel locks correctly at the application level, set <b>preemptable</b> to
220 * false.
221 *
222 * \return Status of the operation
223 * \retval CY_IPC_SEMA_SUCCESS: The semaphore was set successfully
224 * \retval CY_IPC_SEMA_LOCKED: The semaphore channel is busy or locked
225 * by another process
226 * \retval CY_IPC_SEMA_NOT_ACQUIRED: Semaphore was already set
227 * \retval CY_IPC_SEMA_OUT_OF_RANGE: The semaphore number is not valid
228 *
229 * \funcusage
230 * \snippet ipc/snippet/main.c snippet_Cy_IPC_Sema_Set
231 *
232 *******************************************************************************/
Cy_IPC_Sema_Set(uint32_t semaNumber,bool preemptable)233 cy_en_ipcsema_status_t Cy_IPC_Sema_Set(uint32_t semaNumber, bool preemptable)
234 {
235 uint32_t semaIndex;
236 uint32_t semaMask;
237 uint32_t interruptState = 0UL;
238
239 cy_stc_ipc_sema_t *semaStruct;
240 cy_en_ipcsema_status_t retStatus = CY_IPC_SEMA_LOCKED;
241
242 /* Get pointer to structure */
243 semaStruct = (cy_stc_ipc_sema_t *)Cy_IPC_Drv_ReadDataValue(cy_semaIpcStruct);
244
245 if (semaNumber < semaStruct->maxSema)
246 {
247 semaIndex = semaNumber / CY_IPC_SEMA_PER_WORD;
248 semaMask = (uint32_t)(1UL << (semaNumber - (semaIndex * CY_IPC_SEMA_PER_WORD) ));
249
250 if (!preemptable)
251 {
252 interruptState = Cy_SysLib_EnterCriticalSection();
253 }
254
255 /* Check to make sure the IPC channel is released
256 If so, check if specific channel can be locked. */
257 if(CY_IPC_DRV_SUCCESS == Cy_IPC_Drv_LockAcquire (cy_semaIpcStruct))
258 {
259 if((semaStruct->arrayPtr[semaIndex] & semaMask) == 0UL)
260 {
261 semaStruct->arrayPtr[semaIndex] |= semaMask;
262 retStatus = CY_IPC_SEMA_SUCCESS;
263 }
264 else
265 {
266 retStatus = CY_IPC_SEMA_NOT_ACQUIRED;
267 }
268
269 /* Release, but do not trigger a release event */
270 (void) Cy_IPC_Drv_LockRelease (cy_semaIpcStruct, CY_IPC_NO_NOTIFICATION);
271 }
272
273 if (!preemptable)
274 {
275 Cy_SysLib_ExitCriticalSection(interruptState);
276 }
277 }
278 else
279 {
280 retStatus = CY_IPC_SEMA_OUT_OF_RANGE;
281 }
282
283 return(retStatus);
284 }
285
286
287 /*******************************************************************************
288 * Function Name: Cy_IPC_Sema_Clear
289 ****************************************************************************//**
290 *
291 * This functions tries to releases a semaphore.
292 *
293 * It first acquires the IPC channel that is used for all the semaphores, clears
294 * the semaphore if it is set, then releases the IPC channel used for the
295 * semaphores.
296 *
297 * \param semaNumber
298 * The index of the semaphore to release.
299 *
300 * \param preemptable
301 * When this parameter is enabled the function can be preempted by another
302 * task or other forms of context switching in an RTOS environment.
303 *
304 * \note
305 * If <b>preemptable</b> is enabled (true), the user must ensure that there are
306 * no deadlocks in the system, which can be caused by an interrupt that occurs
307 * after the IPC channel is locked. Unless the user is ready to handle IPC
308 * channel locks correctly at the application level, set <b>preemptable</b> to
309 * false.
310 *
311 * \return Status of the operation
312 * \retval CY_IPC_SEMA_SUCCESS: The semaphore was cleared successfully
313 * \retval CY_IPC_SEMA_NOT_ACQUIRED: The semaphore was already cleared
314 * \retval CY_IPC_SEMA_LOCKED: The semaphore channel was semaphored or busy
315 * \retval CY_IPC_SEMA_OUT_OF_RANGE: The semaphore number is not valid
316 *
317 * \funcusage
318 * \snippet ipc/snippet/main.c snippet_Cy_IPC_Sema_Clear
319 *
320 *******************************************************************************/
Cy_IPC_Sema_Clear(uint32_t semaNumber,bool preemptable)321 cy_en_ipcsema_status_t Cy_IPC_Sema_Clear(uint32_t semaNumber, bool preemptable)
322 {
323 uint32_t semaIndex;
324 uint32_t semaMask;
325 uint32_t interruptState = 0UL;
326
327 cy_stc_ipc_sema_t *semaStruct;
328 cy_en_ipcsema_status_t retStatus = CY_IPC_SEMA_LOCKED;
329
330 /* Get pointer to structure */
331 semaStruct = (cy_stc_ipc_sema_t *)Cy_IPC_Drv_ReadDataValue(cy_semaIpcStruct);
332
333 if (semaNumber < semaStruct->maxSema)
334 {
335 semaIndex = semaNumber / CY_IPC_SEMA_PER_WORD;
336 semaMask = (uint32_t)(1UL << (semaNumber - (semaIndex * CY_IPC_SEMA_PER_WORD) ));
337
338 if (!preemptable)
339 {
340 interruptState = Cy_SysLib_EnterCriticalSection();
341 }
342
343 /* Check to make sure the IPC channel is released
344 If so, check if specific channel can be locked. */
345 if(CY_IPC_DRV_SUCCESS == Cy_IPC_Drv_LockAcquire (cy_semaIpcStruct))
346 {
347 if((semaStruct->arrayPtr[semaIndex] & semaMask) != 0UL)
348 {
349 semaStruct->arrayPtr[semaIndex] &= ~semaMask;
350 retStatus = CY_IPC_SEMA_SUCCESS;
351 }
352 else
353 {
354 retStatus = CY_IPC_SEMA_NOT_ACQUIRED;
355 }
356
357 /* Release, but do not trigger a release event */
358 (void) Cy_IPC_Drv_LockRelease (cy_semaIpcStruct, CY_IPC_NO_NOTIFICATION);
359 }
360
361 if (!preemptable)
362 {
363 Cy_SysLib_ExitCriticalSection(interruptState);
364 }
365 }
366 else
367 {
368 retStatus = CY_IPC_SEMA_OUT_OF_RANGE;
369 }
370 return(retStatus);
371 }
372
373
374 /*******************************************************************************
375 * Function Name: Cy_IPC_Sema_Status
376 ****************************************************************************//**
377 *
378 * This function returns the status of the semaphore.
379 *
380 * \param semaNumber
381 * The index of the semaphore to return status.
382 *
383 * \return Status of the operation
384 * \retval CY_IPC_SEMA_STATUS_LOCKED: The semaphore is in the set state.
385 * \retval CY_IPC_SEMA_STATUS_UNLOCKED: The semaphore is in the cleared state.
386 * \retval CY_IPC_SEMA_OUT_OF_RANGE: The semaphore number is not valid
387 *
388 * \funcusage
389 * \snippet ipc/snippet/main.c snippet_Cy_IPC_Sema_Status
390 *
391 *******************************************************************************/
Cy_IPC_Sema_Status(uint32_t semaNumber)392 cy_en_ipcsema_status_t Cy_IPC_Sema_Status(uint32_t semaNumber)
393 {
394 cy_en_ipcsema_status_t retStatus;
395 uint32_t semaIndex;
396 uint32_t semaMask;
397 cy_stc_ipc_sema_t *semaStruct;
398
399 /* Get pointer to structure */
400 semaStruct = (cy_stc_ipc_sema_t *)Cy_IPC_Drv_ReadDataValue(cy_semaIpcStruct);
401
402 if (semaNumber < semaStruct->maxSema)
403 {
404 /* Get the index into the semaphore array and calculate the mask */
405 semaIndex = semaNumber / CY_IPC_SEMA_PER_WORD;
406 semaMask = (uint32_t)(1UL << (semaNumber - (semaIndex * CY_IPC_SEMA_PER_WORD) ));
407
408 if((semaStruct->arrayPtr[semaIndex] & semaMask) != 0UL)
409 {
410 retStatus = CY_IPC_SEMA_STATUS_LOCKED;
411 }
412 else
413 {
414 retStatus = CY_IPC_SEMA_STATUS_UNLOCKED;
415 }
416 }
417 else
418 {
419 retStatus = CY_IPC_SEMA_OUT_OF_RANGE;
420 }
421 return(retStatus);
422 }
423
424
425 /*******************************************************************************
426 * Function Name: Cy_IPC_Sema_GetMaxSems
427 ****************************************************************************//**
428 *
429 * This function returns the number of semaphores in the semaphores subsystem.
430 *
431 * \return
432 * Returns the semaphores quantity.
433 *
434 * \funcusage
435 * \snippet ipc/snippet/main.c snippet_Cy_IPC_Sema_GetMaxSems
436 *
437 *******************************************************************************/
Cy_IPC_Sema_GetMaxSems(void)438 uint32_t Cy_IPC_Sema_GetMaxSems(void)
439 {
440 cy_stc_ipc_sema_t *semaStruct;
441
442 /* Get pointer to structure */
443 semaStruct = (cy_stc_ipc_sema_t *)Cy_IPC_Drv_ReadDataValue(cy_semaIpcStruct);
444
445 return (semaStruct->maxSema);
446 }
447
448 #endif
449
450 /* [] END OF FILE */
451