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