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 UInt32 * baseAddr; /* base addr lock registers */
74 GateMutex_Handle gmHandle; /* handle to gate mutex */
75 } GateHWSpinlock_Module_State;
77 /* GateHWSpinlock instance object */
78 struct GateHWSpinlock_Object {
79 IGateProvider_SuperObject; /* For inheritance from IGateProvider */
80 UInt lockNum;
81 UInt nested;
82 IGateProvider_Handle localGate;
83 int token; /* HWSpinlock token */
84 };
87 /* =============================================================================
88 * Globals
89 * =============================================================================
90 */
91 GateHWSpinlock_Config _GateHWSpinlock_cfgParams;
93 static GateHWSpinlock_Module_State GateHWSpinlock_state =
94 {
95 .baseAddr = NULL,
96 .gmHandle = NULL
97 };
99 static GateHWSpinlock_Module_State *Mod = &GateHWSpinlock_state;
101 static GateHWSpinlock_Params GateHWSpinlock_defInstParams =
102 {
103 .resourceId = 0,
104 .openFlag = FALSE,
105 .regionId = 0,
106 .sharedAddr = NULL
107 };
109 /* traces in this file are controlled via _GateHWSpinlock_verbose */
110 Bool _GateHWSpinlock_verbose = FALSE;
111 #define verbose _GateHWSpinlock_verbose
113 /* =============================================================================
114 * APIS
115 * =============================================================================
116 */
117 /* Function to get configuration address & sizes for the GateHWSpinlock module.
118 *
119 */
120 Void GateHWSpinlock_getConfig (GateHWSpinlock_Config * cfgParams)
121 {
122 Int status;
123 LAD_ClientHandle handle;
124 struct LAD_CommandObj cmd;
125 union LAD_ResponseObj rsp;
127 assert (cfgParams != NULL);
129 handle = LAD_findHandle();
130 if (handle == LAD_MAXNUMCLIENTS) {
131 PRINTVERBOSE0(
132 "GateHWSpinlock_getConfig: can't find connection to daemon for pid")
133 PRINTVERBOSE1("%d\n", getpid())
135 return;
136 }
138 cmd.cmd = LAD_GATEHWSPINLOCK_GETCONFIG;
139 cmd.clientId = handle;
141 if ((status = LAD_putCommand(&cmd)) != LAD_SUCCESS) {
142 PRINTVERBOSE1(
143 "GateHWSpinlock_getConfig: sending LAD command failed, status=%d\n",
144 status)
145 return;
146 }
148 if ((status = LAD_getResponse(handle, &rsp)) != LAD_SUCCESS) {
149 PRINTVERBOSE1("GateHWSpinlock_getConfig: no LAD response, status=%d\n",
150 status)
151 return;
152 }
153 status = rsp.gateHWSpinlockGetConfig.status;
155 PRINTVERBOSE2(
156 "GateHWSpinlock_getConfig: got LAD response for client %d, status=%d\n",
157 handle, status)
159 memcpy(cfgParams, &rsp.gateHWSpinlockGetConfig.cfgParams,
160 sizeof(*cfgParams));
162 return;
163 }
166 /*
167 * Function to start the GateHWSpinlock module.
168 */
169 Int32 GateHWSpinlock_start(Void)
170 {
171 Int32 status = GateHWSpinlock_S_SUCCESS;
172 UInt32 dst;
173 Int32 fdMem;
174 int flags;
176 fdMem = open ("/dev/mem", O_RDWR | O_SYNC);
178 if (fdMem < 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(fdMem, F_GETFD);
185 if (flags != -1) {
186 fcntl(fdMem, 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), fdMem,
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 }
200 else {
201 Mod->baseAddr = (UInt32 *)(dst + _GateHWSpinlock_cfgParams.offset);
202 status = GateHWSpinlock_S_SUCCESS;
203 }
204 }
206 /* create GateMutex for local protection*/
207 if (status == GateHWSpinlock_S_SUCCESS) {
208 Mod->gmHandle = GateMutex_create(NULL, NULL);
210 if (Mod->gmHandle == NULL) {
211 PRINTVERBOSE0("GateHWSpinlock_start: GateMutex create failed")
212 status = GateHWSpinlock_E_FAIL;
213 GateHWSpinlock_stop();
214 }
215 }
217 return (status);
218 }
220 /*
221 * Function to stop the GateHWSpinlock module.
222 */
223 Int GateHWSpinlock_stop(Void)
224 {
225 Int32 status = GateHWSpinlock_S_SUCCESS;
227 /* delete GateMutex */
228 if (Mod->gmHandle != NULL) {
229 status = GateMutex_delete(&Mod->gmHandle);
230 }
232 /* release lock register mapping */
233 if (Mod->baseAddr != NULL) {
234 munmap((void *)_GateHWSpinlock_cfgParams.baseAddr,
235 _GateHWSpinlock_cfgParams.size);
236 }
238 return(status);
239 }
241 /*
242 * Initialize parameter structure
243 */
244 Void GateHWSpinlock_Params_init(GateHWSpinlock_Params *params)
245 {
246 assert(params != NULL);
248 memcpy(params, &GateHWSpinlock_defInstParams,
249 sizeof(GateHWSpinlock_Params));
250 }
252 /*
253 * Create a GateHWSpinlock instance
254 */
255 /* TODO: change the function to accept a local gate. Do this on all platforms */
256 GateHWSpinlock_Handle GateHWSpinlock_create(GateHWSpinlock_LocalProtect
257 localProtect, const GateHWSpinlock_Params * params)
258 {
259 GateHWSpinlock_Object * obj = (GateHWSpinlock_Object *)calloc(1,
260 sizeof (GateHWSpinlock_Object));
262 if (!obj) {
263 PRINTVERBOSE0("GateHWSpinlock_create: memory allocation failure")
264 return NULL;
265 }
267 IGateProvider_ObjectInitializer(obj, GateHWSpinlock);
268 /* TODO: handle more local protection types */
269 obj->localGate = (IGateProvider_Handle)Mod->gmHandle;
270 obj->lockNum = params->resourceId;
271 obj->nested = 0;
273 return (GateHWSpinlock_Handle)obj;
274 }
276 /*
277 * Delete a GateHWSpinlock instance
278 */
279 Int GateHWSpinlock_delete (GateHWSpinlock_Handle * handle)
280 {
281 GateHWSpinlock_Object * obj;
282 Int status = GateHWSpinlock_S_SUCCESS;
284 if (handle == NULL) {
285 return GateHWSpinlock_E_INVALIDARG;
286 }
287 if (*handle == NULL) {
288 return GateHWSpinlock_E_INVALIDARG;
289 }
291 obj = (GateHWSpinlock_Object *)(*handle);
293 free(obj);
294 *handle = NULL;
296 return (status);
297 }
299 /*
300 * Enter a GateHWSpinlock instance
301 */
302 IArg GateHWSpinlock_enter(GateHWSpinlock_Object *obj)
303 {
304 volatile UInt32 *baseAddr = Mod->baseAddr;
305 IArg key;
307 key = IGateProvider_enter(obj->localGate);
309 /* if gate already entered, just return with current key */
310 obj->nested++;
311 if (obj->nested > 1) {
312 return(key);
313 }
315 /* enter the spinlock */
316 while (1) {
317 /* read the spinlock, returns non-zero when we get it */
318 if (baseAddr[obj->lockNum] == 0) {
319 break;
320 }
321 obj->nested--;
322 IGateProvider_leave(obj->localGate, key);
323 key = IGateProvider_enter(obj->localGate);
324 obj->nested++; /* re-nest the gate */
325 }
327 return (key);
328 }
330 /*
331 * Leave a GateHWSpinlock instance
332 */
333 Int GateHWSpinlock_leave(GateHWSpinlock_Object *obj, IArg key)
334 {
335 volatile UInt32 *baseAddr = Mod->baseAddr;
337 obj->nested--;
339 /* release the spinlock if not nested */
340 if (obj->nested == 0) {
341 baseAddr[obj->lockNum] = 0;
342 }
344 IGateProvider_leave(obj->localGate, key);
346 return GateHWSpinlock_S_SUCCESS;
347 }