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