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 /* Socket Utils */
56 #include <_lad.h>
57 #include <ladclient.h>
59 /* Linux headers */
60 #include <assert.h>
61 #include <fcntl.h>
62 #include <string.h>
63 #include <stdlib.h>
64 #include <sys/mman.h>
65 #include <sys/stat.h>
67 /* =============================================================================
68 * Structures & Enums
69 * =============================================================================
70 */
71 /* GateHWSpinlock Module Local State */
72 typedef struct {
73 Int32 fd; /* spinlock device handle */
74 UInt32 * baseAddr; /* base addr lock registers */
75 GateMutex_Handle gmHandle; /* handle to gate mutex */
76 } GateHWSpinlock_Module_State;
78 /* GateHWSpinlock instance object */
79 struct GateHWSpinlock_Object {
80 IGateProvider_SuperObject; /* For inheritance from IGateProvider */
81 UInt lockNum;
82 UInt nested;
83 IGateProvider_Handle localGate;
84 int token; /* HWSpinlock token */
85 };
88 /* =============================================================================
89 * Globals
90 * =============================================================================
91 */
92 GateHWSpinlock_Config _GateHWSpinlock_cfgParams;
94 static GateHWSpinlock_Module_State GateHWSpinlock_state =
95 {
96 .fd = -1,
97 .baseAddr = NULL,
98 .gmHandle = NULL
99 };
101 static GateHWSpinlock_Module_State *Mod = &GateHWSpinlock_state;
103 static GateHWSpinlock_Params GateHWSpinlock_defInstParams =
104 {
105 .resourceId = 0,
106 .openFlag = FALSE,
107 .regionId = 0,
108 .sharedAddr = NULL
109 };
111 /* traces in this file are controlled via _GateHWSpinlock_verbose */
112 Bool _GateHWSpinlock_verbose = FALSE;
113 #define verbose _GateHWSpinlock_verbose
115 /* =============================================================================
116 * APIS
117 * =============================================================================
118 */
119 /* Function to get configuration address & sizes for the GateHWSpinlock module.
120 *
121 */
122 Void GateHWSpinlock_getConfig (GateHWSpinlock_Config * cfgParams)
123 {
124 Int status;
125 LAD_ClientHandle handle;
126 struct LAD_CommandObj cmd;
127 union LAD_ResponseObj rsp;
129 assert (cfgParams != NULL);
131 handle = LAD_findHandle();
132 if (handle == LAD_MAXNUMCLIENTS) {
133 PRINTVERBOSE0(
134 "GateHWSpinlock_getConfig: can't find connection to daemon for pid")
135 PRINTVERBOSE1("%d\n", getpid())
137 return;
138 }
140 cmd.cmd = LAD_GATEHWSPINLOCK_GETCONFIG;
141 cmd.clientId = handle;
143 if ((status = LAD_putCommand(&cmd)) != LAD_SUCCESS) {
144 PRINTVERBOSE1(
145 "GateHWSpinlock_getConfig: sending LAD command failed, status=%d\n",
146 status)
147 return;
148 }
150 if ((status = LAD_getResponse(handle, &rsp)) != LAD_SUCCESS) {
151 PRINTVERBOSE1("GateHWSpinlock_getConfig: no LAD response, status=%d\n",
152 status)
153 return;
154 }
155 status = rsp.gateHWSpinlockGetConfig.status;
157 PRINTVERBOSE2(
158 "GateHWSpinlock_getConfig: got LAD response for client %d, status=%d\n",
159 handle, status)
161 memcpy(cfgParams, &rsp.gateHWSpinlockGetConfig.cfgParams,
162 sizeof(*cfgParams));
164 return;
165 }
168 /*
169 * Function to start the GateHWSpinlock module.
170 */
171 Int32 GateHWSpinlock_start(Void)
172 {
173 Int32 status = GateHWSpinlock_S_SUCCESS;
174 UInt32 dst;
175 int flags;
177 Mod->fd = open ("/dev/mem", O_RDWR | O_SYNC);
178 if (Mod->fd < 0){
179 PRINTVERBOSE0("GateHWSpinlock_start: failed to open the /dev/mem");
180 status = GateHWSpinlock_E_OSFAILURE;
181 }
183 /* make sure /dev/mem fd doesn't exist for 'fork() -> exec*()'ed child */
184 flags = fcntl(Mod->fd, F_GETFD);
185 if (flags != -1) {
186 fcntl(Mod->fd, F_SETFD, flags | FD_CLOEXEC);
187 }
189 /* map the hardware lock registers into the local address space */
190 if (status == GateHWSpinlock_S_SUCCESS) {
191 dst = (UInt32)mmap(NULL, _GateHWSpinlock_cfgParams.size,
192 (PROT_READ | PROT_WRITE),
193 (MAP_SHARED), Mod->fd,
194 (off_t)_GateHWSpinlock_cfgParams.baseAddr);
196 if (dst == (UInt32)MAP_FAILED) {
197 PRINTVERBOSE0("GateHWSpinlock_start: Memory map failed")
198 status = GateHWSpinlock_E_OSFAILURE;
199 close(Mod->fd);
200 Mod->fd = -1;
201 }
202 else {
203 Mod->baseAddr = (UInt32 *)(dst + _GateHWSpinlock_cfgParams.offset);
204 status = GateHWSpinlock_S_SUCCESS;
205 }
206 }
208 /* create GateMutex for local protection*/
209 if (status == GateHWSpinlock_S_SUCCESS) {
210 Mod->gmHandle = GateMutex_create(NULL, NULL);
212 if (Mod->gmHandle == NULL) {
213 PRINTVERBOSE0("GateHWSpinlock_start: GateMutex create failed")
214 status = GateHWSpinlock_E_FAIL;
215 GateHWSpinlock_stop();
216 }
217 }
219 return (status);
220 }
222 /*
223 * Function to stop the GateHWSpinlock module.
224 */
225 Int GateHWSpinlock_stop(Void)
226 {
227 Int32 status = GateHWSpinlock_S_SUCCESS;
229 /* delete GateMutex */
230 if (Mod->gmHandle != NULL) {
231 status = GateMutex_delete(&Mod->gmHandle);
232 }
234 /* release lock register mapping */
235 if (Mod->baseAddr != NULL) {
236 munmap((void *)_GateHWSpinlock_cfgParams.baseAddr,
237 _GateHWSpinlock_cfgParams.size);
238 }
240 /* close the spinlock device file */
241 if (Mod->fd >= 0) {
242 close(Mod->fd);
243 Mod->fd = -1;
244 }
246 return(status);
247 }
249 /*
250 * Initialize parameter structure
251 */
252 Void GateHWSpinlock_Params_init(GateHWSpinlock_Params *params)
253 {
254 assert(params != NULL);
256 memcpy(params, &GateHWSpinlock_defInstParams,
257 sizeof(GateHWSpinlock_Params));
258 }
260 /*
261 * Create a GateHWSpinlock instance
262 */
263 /* TODO: change the function to accept a local gate. Do this on all platforms */
264 GateHWSpinlock_Handle GateHWSpinlock_create(GateHWSpinlock_LocalProtect
265 localProtect, const GateHWSpinlock_Params * params)
266 {
267 GateHWSpinlock_Object * obj = (GateHWSpinlock_Object *)calloc(1,
268 sizeof (GateHWSpinlock_Object));
270 if (!obj) {
271 PRINTVERBOSE0("GateHWSpinlock_create: memory allocation failure")
272 return NULL;
273 }
275 IGateProvider_ObjectInitializer(obj, GateHWSpinlock);
276 /* TODO: handle more local protection types */
277 obj->localGate = (IGateProvider_Handle)Mod->gmHandle;
278 obj->lockNum = params->resourceId;
279 obj->nested = 0;
281 return (GateHWSpinlock_Handle)obj;
282 }
284 /*
285 * Delete a GateHWSpinlock instance
286 */
287 Int GateHWSpinlock_delete (GateHWSpinlock_Handle * handle)
288 {
289 GateHWSpinlock_Object * obj;
290 Int status = GateHWSpinlock_S_SUCCESS;
292 if (handle == NULL) {
293 return GateHWSpinlock_E_INVALIDARG;
294 }
295 if (*handle == NULL) {
296 return GateHWSpinlock_E_INVALIDARG;
297 }
299 obj = (GateHWSpinlock_Object *)(*handle);
301 free(obj);
302 *handle = NULL;
304 return (status);
305 }
307 /*
308 * Enter a GateHWSpinlock instance
309 */
310 IArg GateHWSpinlock_enter(GateHWSpinlock_Object *obj)
311 {
312 volatile UInt32 *baseAddr = Mod->baseAddr;
313 IArg key;
315 key = IGateProvider_enter(obj->localGate);
317 /* if gate already entered, just return with current key */
318 obj->nested++;
319 if (obj->nested > 1) {
320 return(key);
321 }
323 /* enter the spinlock */
324 while (1) {
325 /* read the spinlock, returns non-zero when we get it */
326 if (baseAddr[obj->lockNum] == 0) {
327 break;
328 }
329 obj->nested--;
330 IGateProvider_leave(obj->localGate, key);
331 key = IGateProvider_enter(obj->localGate);
332 obj->nested++; /* re-nest the gate */
333 }
335 return (key);
336 }
338 /*
339 * Leave a GateHWSpinlock instance
340 */
341 Int GateHWSpinlock_leave(GateHWSpinlock_Object *obj, IArg key)
342 {
343 volatile UInt32 *baseAddr = Mod->baseAddr;
345 obj->nested--;
347 /* release the spinlock if not nested */
348 if (obj->nested == 0) {
349 baseAddr[obj->lockNum] = 0;
350 }
352 IGateProvider_leave(obj->localGate, key);
354 return GateHWSpinlock_S_SUCCESS;
355 }