1 /*
2 * Copyright (c) 2013-2014, Texas Instruments Incorporated
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of Texas Instruments Incorporated nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
33 /*
34 * ======== GateHWSpinlock.c ========
35 */
37 /* Standard headers */
38 #include <ti/ipc/Std.h>
40 /* Utilities & OSAL headers */
41 #include <ti/ipc/MultiProc.h>
42 #include <ti/ipc/GateMP.h>
44 #include <GateHWSpinlock.h>
46 #include <IGateProvider.h>
48 /*
49 * TODO: does this belong in ti/ipc/Std.h? We should consider getting rid of
50 * error blocks from the GateMutex.h interface.
51 */
52 typedef UInt32 Error_Block;
53 #include <GateMutex.h>
55 /* Module level headers */
56 #include <_lad.h>
58 /* Linux headers */
59 #include <assert.h>
60 #include <fcntl.h>
61 #include <string.h>
62 #include <stdlib.h>
63 #include <sys/ioctl.h>
64 #include <sys/mman.h>
65 #include <sys/stat.h>
67 #include <linux/hwspinlock_user.h>
69 /* =============================================================================
70 * Structures & Enums
71 * =============================================================================
72 */
73 /* GateHWSpinlock Module Local State */
74 typedef struct {
75 Int32 fd; /* spinlock device handle */
76 UInt32 * baseAddr; /* base addr lock registers */
77 GateMutex_Handle gmHandle; /* handle to gate mutex */
78 Bool useHwlockDrv; /* use the hwspinlock driver */
79 } GateHWSpinlock_Module_State;
81 /* GateHWSpinlock instance object */
82 struct GateHWSpinlock_Object {
83 IGateProvider_SuperObject; /* For inheritance from IGateProvider */
84 UInt lockNum;
85 UInt nested;
86 IGateProvider_Handle localGate;
87 int token; /* HWSpinlock token */
88 };
91 /* =============================================================================
92 * Globals
93 * =============================================================================
94 */
95 GateHWSpinlock_Config _GateHWSpinlock_cfgParams;
97 static GateHWSpinlock_Module_State GateHWSpinlock_state =
98 {
99 .fd = -1,
100 .baseAddr = NULL,
101 .gmHandle = NULL,
102 .useHwlockDrv = false,
103 };
105 static GateHWSpinlock_Module_State *Mod = &GateHWSpinlock_state;
107 static GateHWSpinlock_Params GateHWSpinlock_defInstParams =
108 {
109 .resourceId = 0,
110 .openFlag = FALSE,
111 .regionId = 0,
112 .sharedAddr = NULL
113 };
115 /* =============================================================================
116 * APIS
117 * =============================================================================
118 */
119 /*
120 * Function to start the GateHWSpinlock module.
121 */
122 Int32 GateHWSpinlock_start(Void)
123 {
124 Int32 status = GateHWSpinlock_S_SUCCESS;
125 UInt32 dst;
127 /* Fall back to /dev/mem if hwspinlock_user driver is not supported */
128 Mod->fd = open("/dev/hwspinlock", O_RDWR);
129 if (Mod->fd < 0) {
130 Mod->fd = open ("/dev/mem", O_RDWR | O_SYNC);
131 }
132 else {
133 Mod->useHwlockDrv = true;
134 }
136 if (Mod->fd < 0){
137 LOG0("GateHWSpinlock_start: failed to open the spinlock device");
138 status = GateHWSpinlock_E_OSFAILURE;
139 }
141 /* map the hardware lock registers into the local address space */
142 if (!Mod->useHwlockDrv && status == GateHWSpinlock_S_SUCCESS) {
143 dst = (UInt32)mmap(NULL, _GateHWSpinlock_cfgParams.size,
144 (PROT_READ | PROT_WRITE),
145 (MAP_SHARED), Mod->fd,
146 (off_t)_GateHWSpinlock_cfgParams.baseAddr);
148 if (dst == (UInt32)MAP_FAILED) {
149 LOG0("GateHWSpinlock_start: Memory map failed")
150 status = GateHWSpinlock_E_OSFAILURE;
151 close(Mod->fd);
152 Mod->fd = -1;
153 }
154 else {
155 Mod->baseAddr = (UInt32 *)(dst + _GateHWSpinlock_cfgParams.offset);
156 status = GateHWSpinlock_S_SUCCESS;
157 }
158 }
160 /* create GateMutex for local protection*/
161 if (status == GateHWSpinlock_S_SUCCESS) {
162 Mod->gmHandle = GateMutex_create(NULL, NULL);
164 if (Mod->gmHandle == NULL) {
165 LOG0("GateHWSpinlock_start: GateMutex create failed")
166 status = GateHWSpinlock_E_FAIL;
167 GateHWSpinlock_stop();
168 }
169 }
171 return (status);
172 }
174 /*
175 * Function to stop the GateHWSpinlock module.
176 */
177 Int GateHWSpinlock_stop(Void)
178 {
179 Int32 status = GateHWSpinlock_S_SUCCESS;
181 /* delete GateMutex */
182 if (Mod->gmHandle != NULL) {
183 status = GateMutex_delete(&Mod->gmHandle);
184 }
186 /* release lock register mapping */
187 if (!Mod->useHwlockDrv && (Mod->baseAddr != NULL)) {
188 munmap((void *)_GateHWSpinlock_cfgParams.baseAddr,
189 _GateHWSpinlock_cfgParams.size);
190 }
192 /* close the spinlock device file */
193 if (Mod->fd >= 0) {
194 close(Mod->fd);
195 Mod->fd = -1;
196 }
198 return(status);
199 }
201 /*
202 * Initialize parameter structure
203 */
204 Void GateHWSpinlock_Params_init(GateHWSpinlock_Params *params)
205 {
206 assert(params != NULL);
208 memcpy(params, &GateHWSpinlock_defInstParams,
209 sizeof(GateHWSpinlock_Params));
210 }
212 /*
213 * Create a GateHWSpinlock instance
214 */
215 /* TODO: change the function to accept a local gate. Do this on all platforms */
216 GateHWSpinlock_Handle GateHWSpinlock_create(GateMP_LocalProtect
217 localProtect, const GateHWSpinlock_Params * params)
218 {
219 GateHWSpinlock_Object * obj = (GateHWSpinlock_Object *)calloc(1,
220 sizeof (GateHWSpinlock_Object));
221 (Void)localProtect;
223 if (!obj) {
224 LOG0("GateHWSpinlock_create: memory allocation failure")
225 return NULL;
226 }
228 IGateProvider_ObjectInitializer(obj, GateHWSpinlock);
229 /* TODO: handle more local protection types */
230 obj->localGate = (IGateProvider_Handle)Mod->gmHandle;
231 obj->lockNum = params->resourceId;
232 obj->nested = 0;
234 return (GateHWSpinlock_Handle)obj;
235 }
237 /*
238 * Delete a GateHWSpinlock instance
239 */
240 Int GateHWSpinlock_delete (GateHWSpinlock_Handle * handle)
241 {
242 GateHWSpinlock_Object * obj;
243 Int status = GateHWSpinlock_S_SUCCESS;
245 if (handle == NULL) {
246 return GateHWSpinlock_E_INVALIDARG;
247 }
248 if (*handle == NULL) {
249 return GateHWSpinlock_E_INVALIDARG;
250 }
252 obj = (GateHWSpinlock_Object *)(*handle);
254 free(obj);
255 *handle = NULL;
257 return (status);
258 }
260 /*
261 * Enter a GateHWSpinlock instance
262 */
263 IArg GateHWSpinlock_enter(GateHWSpinlock_Object *obj)
264 {
265 volatile UInt32 *baseAddr = Mod->baseAddr;
266 struct hwspinlock_user_lock data = {
267 .id = obj->lockNum,
268 .timeout = 10,
269 };
270 IArg key;
271 Bool locked;
273 key = IGateProvider_enter(obj->localGate);
275 /* if gate already entered, just return with current key */
276 obj->nested++;
277 if (obj->nested > 1) {
278 return(key);
279 }
281 /* enter the spinlock */
282 while (1) {
283 if (Mod->useHwlockDrv) {
284 locked = !ioctl(Mod->fd, HWSPINLOCK_USER_LOCK, &data);
285 }
286 else {
287 /* read the spinlock, returns non-zero when we get it */
288 locked = (baseAddr[obj->lockNum] == 0);
289 }
291 if (locked) {
292 break;
293 }
295 obj->nested--;
296 IGateProvider_leave(obj->localGate, key);
297 key = IGateProvider_enter(obj->localGate);
298 obj->nested++; /* re-nest the gate */
299 }
301 return (key);
302 }
304 /*
305 * Leave a GateHWSpinlock instance
306 */
307 Int GateHWSpinlock_leave(GateHWSpinlock_Object *obj, IArg key)
308 {
309 volatile UInt32 *baseAddr = Mod->baseAddr;
310 struct hwspinlock_user_unlock data = {
311 .id = obj->lockNum,
312 };
314 obj->nested--;
316 /* release the spinlock if not nested */
317 if (obj->nested == 0) {
318 if (Mod->useHwlockDrv) {
319 ioctl(Mod->fd, HWSPINLOCK_USER_UNLOCK, &data);
320 }
321 else {
322 baseAddr[obj->lockNum] = 0;
323 }
324 }
326 IGateProvider_leave(obj->localGate, key);
328 return GateHWSpinlock_S_SUCCESS;
329 }