xref: /btstack/port/renesas-tb-s1ja-cc256x/template/btstack_example/synergy/ssp/src/bsp/mcu/all/bsp_locking.c (revision 3b5c872a8c45689e8cc17891f01530f5aa5e911c)
1 /***********************************************************************************************************************
2  * Copyright [2015-2017] Renesas Electronics Corporation and/or its licensors. All Rights Reserved.
3  *
4  * This file is part of Renesas SynergyTM Software Package (SSP)
5  *
6  * The contents of this file (the "contents") are proprietary and confidential to Renesas Electronics Corporation
7  * and/or its licensors ("Renesas") and subject to statutory and contractual protections.
8  *
9  * This file is subject to a Renesas SSP license agreement. Unless otherwise agreed in an SSP license agreement with
10  * Renesas: 1) you may not use, copy, modify, distribute, display, or perform the contents; 2) you may not use any name
11  * or mark of Renesas for advertising or publicity purposes or in connection with your use of the contents; 3) RENESAS
12  * MAKES NO WARRANTY OR REPRESENTATIONS ABOUT THE SUITABILITY OF THE CONTENTS FOR ANY PURPOSE; THE CONTENTS ARE PROVIDED
13  * "AS IS" WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
14  * PARTICULAR PURPOSE, AND NON-INFRINGEMENT; AND 4) RENESAS SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, OR
15  * CONSEQUENTIAL DAMAGES, INCLUDING DAMAGES RESULTING FROM LOSS OF USE, DATA, OR PROJECTS, WHETHER IN AN ACTION OF
16  * CONTRACT OR TORT, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE CONTENTS. Third-party contents
17  * included in this file may be subject to different terms.
18  **********************************************************************************************************************/
19 /***********************************************************************************************************************
20 * File Name    : bsp_locking.c
21 * Description  : This module implements atomic locking
22 ***********************************************************************************************************************/
23 
24 /***********************************************************************************************************************
25 Includes   <System Includes> , "Project Includes"
26 ***********************************************************************************************************************/
27 #include "bsp_api.h"
28 
29 /***********************************************************************************************************************
30 Macro definitions
31 ***********************************************************************************************************************/
32 /* Return options from store-exclusive instruction. */
33 #define BSP_PRV_STREX_SUCCESS           (0x00000000U)
34 #define BSP_PRV_STREX_FAILURE           (0x00000001U)
35 
36 /* The macros __CORE__ , __ARM7EM__ and __ARM_ARCH_8M_BASE__ are undefined for GCC, but defined(__IAR_SYSTEMS_ICC__) is false for GCC, so
37  * the left half of the || expression evaluates to false for GCC regardless of the values of these macros. */
38 /*LDRA_INSPECTED 337 S *//*LDRA_INSPECTED 337 S *//*LDRA_INSPECTED 337 S */
39 #if (defined(__IAR_SYSTEMS_ICC__) && (__CORE__ == __ARM7EM__)) || defined(__ARM_ARCH_7EM__) // CM4
40 #define BSP_PRIV_CORE_CM4
41 #elif(defined(__IAR_SYSTEMS_ICC__) && defined(__ARM_ARCH_8M_BASE__)) // CM23
42 #define BSP_PRIV_CORE_CM23
43 #else
44 #define BSP_PRIV_CORE_CM0PLUS
45 #endif
46 
47 /***********************************************************************************************************************
48 Typedef definitions
49 ***********************************************************************************************************************/
50 
51 /***********************************************************************************************************************
52 Exported global variables (to be accessed by other files)
53 ***********************************************************************************************************************/
54 
55 /***********************************************************************************************************************
56 Private global variables and functions
57 ***********************************************************************************************************************/
58 /** Array of HW locks. */
59 static bsp_lock_t * gp_bsp_locks = NULL;
60 
61 /** Array of HW lock lookup data. */
62 static ssp_feature_t * gp_bsp_lock_lookup = NULL;
63 
64 /** Size of HW lock lookup data. */
65 static uint32_t g_bsp_lock_lookup_size = 0;
66 
67 #if defined(BSP_PRIV_CORE_CM4) || defined(BSP_PRIV_CORE_CM23)
68 static inline ssp_err_t r_bsp_software_lock_cm4(bsp_lock_t * p_lock);
69 #endif
70 #ifdef BSP_PRIV_CORE_CM0PLUS
71 static inline ssp_err_t r_bsp_software_lock_cm0plus(bsp_lock_t * p_lock);
72 #endif
73 
74 /*******************************************************************************************************************//**
75  * @addtogroup BSP_MCU_LOCKING
76  *
77  * @{
78  **********************************************************************************************************************/
79 
80 /*******************************************************************************************************************//**
81  * @brief Attempt to acquire the lock that has been sent in.
82  *
83  * @param[in] p_lock Pointer to the structure which contains the lock to be acquired.
84  *
85  * @retval SSP_SUCCESS          Lock was acquired
86  * @retval SSP_ERR_IN_USE       Lock was not acquired
87  **********************************************************************************************************************/
R_BSP_SoftwareLock(bsp_lock_t * p_lock)88 ssp_err_t R_BSP_SoftwareLock(bsp_lock_t * p_lock)
89 {
90     ssp_err_t err = SSP_SUCCESS;
91 #if defined(BSP_PRIV_CORE_CM4) || defined(BSP_PRIV_CORE_CM23)
92     err = r_bsp_software_lock_cm4(p_lock);
93 #endif
94 #ifdef BSP_PRIV_CORE_CM0PLUS
95     err = r_bsp_software_lock_cm0plus(p_lock);
96 #endif
97     return err;
98 }
99 
100 #if defined(BSP_PRIV_CORE_CM4) || defined(BSP_PRIV_CORE_CM23)
101 /*******************************************************************************************************************//**
102  * @brief Attempt to acquire the lock that has been sent in (CM4 and CM23 implementation).
103  *
104  * @param[in] p_lock Pointer to the structure which contains the lock to be acquired.
105  *
106  * @retval SSP_SUCCESS          Lock was acquired
107  * @retval SSP_ERR_IN_USE       Lock was not acquired
108  **********************************************************************************************************************/
r_bsp_software_lock_cm4(bsp_lock_t * p_lock)109 static inline ssp_err_t r_bsp_software_lock_cm4(bsp_lock_t * p_lock)
110 {
111     ssp_err_t err;
112     uint8_t   lock;
113     bool      retry;
114 
115     err = SSP_ERR_IN_USE;
116 
117     /* The Load-Exclusive and Store-Exclusive instructions are being used to perform an exclusive read-modify-write
118      * on the input lock. This process is:
119      * 1) Use a load-exclusive to read the value of the lock
120      * 2) If the lock is available, then modify the lock value so it is reserved. If not available, then issue CLREX.
121      * 3) Use a store-exclusive to attempt to write the new value back to memory
122      * 4) Test the returned status bit to see if the write was performed or not.
123      */
124 
125     do
126     {
127         /* Only perform retry if needed. See why a retry would occur in the comments below. */
128         retry = false;
129 
130         /* Issue load-exclusive on lock. */
131         lock = __LDREXB(&p_lock->lock);
132 
133         /* Check if lock is available. */
134         if (BSP_LOCK_UNLOCKED == lock)
135         {
136             /* Lock is available. Attempt to lock it. */
137             if (BSP_PRV_STREX_SUCCESS == __STREXB(BSP_LOCK_LOCKED, &p_lock->lock))
138             {
139                 err = SSP_SUCCESS;
140             }
141             else
142             {
143                 /* If this path is taken it means that the lock was originally available but the STREX did not
144                  * complete successfully. There are 2 reasons this could happen. A context switch could have occurred
145                  * between the load and store and another task could have taken the lock. If this happened then we
146                  * will retry one more time and on the next loop the lock will not be available so CLREX will be
147                  * called and an error will be returned. The STREX will be cancelled on any context switch so there
148                  * could also have been a context switch and the lock could still be available. If this is the case
149                  * then the lock will be detected as available in the next loop iteration and a STREX will be
150                  * attempted again.
151                  */
152                 retry = true;
153             }
154         }
155         else
156         {
157             /* Lock was already taken, clear exclusive hold. */
158             __CLREX();
159         }
160     } while (retry == true);
161 
162     return err;
163 }
164 #endif
165 
166 #ifdef BSP_PRIV_CORE_CM0PLUS
167 /*******************************************************************************************************************//**
168  * @brief Attempt to acquire the lock that has been sent in (CM0+ implementation).
169  *
170  * @param[in] p_lock Pointer to the structure which contains the lock to be acquired.
171  *
172  * @retval SSP_SUCCESS          Lock was acquired
173  * @retval SSP_ERR_IN_USE       Lock was not acquired
174  **********************************************************************************************************************/
r_bsp_software_lock_cm0plus(bsp_lock_t * p_lock)175 static inline ssp_err_t r_bsp_software_lock_cm0plus(bsp_lock_t * p_lock)
176 {
177     ssp_err_t err = SSP_ERR_IN_USE;
178 
179     SSP_CRITICAL_SECTION_DEFINE;
180     SSP_CRITICAL_SECTION_ENTER;
181 
182     /* Check if lock is available. */
183     if (BSP_LOCK_UNLOCKED == p_lock->lock)
184     {
185         /* Lock is available. Lock it. */
186         p_lock->lock = BSP_LOCK_LOCKED;
187         err = SSP_SUCCESS;
188     }
189 
190     SSP_CRITICAL_SECTION_EXIT;
191 
192     return err;
193 }
194 #endif
195 
196 /*******************************************************************************************************************//**
197  * @brief Release hold on lock.
198  *
199  * @param[in] p_lock Pointer to the structure which contains the lock to unlock.
200  **********************************************************************************************************************/
R_BSP_SoftwareUnlock(bsp_lock_t * p_lock)201 void R_BSP_SoftwareUnlock(bsp_lock_t * p_lock)
202 {
203     /* Set lock back to unlocked. */
204     p_lock->lock = BSP_LOCK_UNLOCKED;
205 }
206 
207 /*******************************************************************************************************************//**
208  * @brief Attempt to reserve a hardware resource lock.
209  *
210  * @param[in] p_feature Pointer to the module specific feature information.
211  *
212  * @retval SSP_SUCCESS          Lock was acquired
213  * @retval SSP_ERR_IN_USE       Lock was not acquired
214  **********************************************************************************************************************/
R_BSP_HardwareLock(ssp_feature_t const * const p_feature)215 ssp_err_t R_BSP_HardwareLock(ssp_feature_t const * const p_feature)
216 {
217     for (uint32_t i = 0U; i < g_bsp_lock_lookup_size; i++)
218     {
219         if (p_feature->word == gp_bsp_lock_lookup[i].word)
220         {
221             /* Pass actual lock to software lock function. */
222             return R_BSP_SoftwareLock(&gp_bsp_locks[i]);
223         }
224     }
225 
226     return SSP_ERR_INVALID_ARGUMENT;
227 }
228 
229 /*******************************************************************************************************************//**
230  * @brief Release hold on lock.
231  *
232  * @param[in] p_feature Pointer to the module specific feature information.
233  **********************************************************************************************************************/
R_BSP_HardwareUnlock(ssp_feature_t const * const p_feature)234 void R_BSP_HardwareUnlock(ssp_feature_t const * const p_feature)
235 {
236     for (uint32_t i = 0U; i < g_bsp_lock_lookup_size; i++)
237     {
238         if (p_feature->word == gp_bsp_lock_lookup[i].word)
239         {
240             /* Pass actual lock to software unlock function. */
241             R_BSP_SoftwareUnlock(&gp_bsp_locks[i]);
242             return;
243         }
244     }
245 }
246 
247 
248 
249 /*******************************************************************************************************************//**
250  * @brief Initialize all of the hardware locks to BSP_LOCK_UNLOCKED.
251  *
252  **********************************************************************************************************************/
bsp_init_hardware_locks(void)253 void bsp_init_hardware_locks(void)
254 {
255 #if defined(__GNUC__)
256     /*LDRA_INSPECTED 219 S This is defined by the linker script, so the use of underscore is acceptable. */
257     extern uint32_t __Lock_Start;
258     gp_bsp_locks = (bsp_lock_t *) &__Lock_Start;
259 
260     /*LDRA_INSPECTED 219 S This is defined by the linker script, so the use of underscore is acceptable. */
261     extern uint32_t __Lock_Lookup_Start;
262     /*LDRA_INSPECTED 219 S This is defined by the linker script, so the use of underscore is acceptable. */
263     extern uint32_t __Lock_Lookup_End;
264 
265     gp_bsp_lock_lookup = (ssp_feature_t *) &__Lock_Lookup_Start;
266     g_bsp_lock_lookup_size = ((uint32_t) &__Lock_Lookup_End - (uint32_t) &__Lock_Lookup_Start) / sizeof(ssp_feature_t);
267 
268 #endif
269 #if defined(__ICCARM__)               /* IAR Compiler */
270 #pragma section="HW_LOCK"
271     gp_bsp_locks = __section_begin("HW_LOCK");
272 
273 #pragma section="LOCK_LOOKUP"
274     gp_bsp_lock_lookup = __section_begin("LOCK_LOOKUP");
275     g_bsp_lock_lookup_size = __section_size("LOCK_LOOKUP") / sizeof(ssp_feature_t);
276 #endif
277 
278     for (uint32_t i = 0U; i < g_bsp_lock_lookup_size; i++)
279     {
280         /* Set each Lock to Unlocked. */
281         R_BSP_HardwareUnlock(&gp_bsp_lock_lookup[i]);
282     }
283 }
284 
285 /*******************************************************************************************************************//**
286  * @brief Initialize lock value to be unlocked.
287  *
288  * @param[in] p_lock Pointer to the structure which contains the lock to initialize.
289  **********************************************************************************************************************/
R_BSP_SoftwareLockInit(bsp_lock_t * p_lock)290 void R_BSP_SoftwareLockInit(bsp_lock_t * p_lock)
291 {
292     p_lock->lock = BSP_LOCK_UNLOCKED;
293 }
294 
295 
296 /** @} (end addtogroup BSP_MCU_LOCKING) */
297