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;
175 fdMem = open ("/dev/mem", O_RDWR | O_SYNC);
177 if (fdMem < 0){
178 PRINTVERBOSE0("GateHWSpinlock_start: failed to open the /dev/mem");
179 status = GateHWSpinlock_E_OSFAILURE;
180 }
182 /* map the hardware lock registers into the local address space */
183 if (status == GateHWSpinlock_S_SUCCESS) {
184 dst = (UInt32)mmap(NULL, _GateHWSpinlock_cfgParams.size,
185 (PROT_READ | PROT_WRITE),
186 (MAP_SHARED), fdMem,
187 (off_t)_GateHWSpinlock_cfgParams.baseAddr);
189 if (dst == (UInt32)MAP_FAILED) {
190 PRINTVERBOSE0("GateHWSpinlock_start: Memory map failed")
191 status = GateHWSpinlock_E_OSFAILURE;
192 }
193 else {
194 Mod->baseAddr = (UInt32 *)(dst + _GateHWSpinlock_cfgParams.offset);
195 status = GateHWSpinlock_S_SUCCESS;
196 }
197 }
199 /* create GateMutex for local protection*/
200 if (status == GateHWSpinlock_S_SUCCESS) {
201 Mod->gmHandle = GateMutex_create(NULL, NULL);
203 if (Mod->gmHandle == NULL) {
204 PRINTVERBOSE0("GateHWSpinlock_start: GateMutex create failed")
205 status = GateHWSpinlock_E_FAIL;
206 GateHWSpinlock_stop();
207 }
208 }
210 return (status);
211 }
213 /*
214 * Function to stop the GateHWSpinlock module.
215 */
216 Int GateHWSpinlock_stop(Void)
217 {
218 Int32 status = GateHWSpinlock_S_SUCCESS;
220 /* delete GateMutex */
221 if (Mod->gmHandle != NULL) {
222 status = GateMutex_delete(&Mod->gmHandle);
223 }
225 /* release lock register mapping */
226 if (Mod->baseAddr != NULL) {
227 munmap((void *)_GateHWSpinlock_cfgParams.baseAddr,
228 _GateHWSpinlock_cfgParams.size);
229 }
231 return(status);
232 }
234 /*
235 * Initialize parameter structure
236 */
237 Void GateHWSpinlock_Params_init(GateHWSpinlock_Params *params)
238 {
239 assert(params != NULL);
241 memcpy(params, &GateHWSpinlock_defInstParams,
242 sizeof(GateHWSpinlock_Params));
243 }
245 /*
246 * Create a GateHWSpinlock instance
247 */
248 /* TODO: change the function to accept a local gate. Do this on all platforms */
249 GateHWSpinlock_Handle GateHWSpinlock_create(GateHWSpinlock_LocalProtect
250 localProtect, const GateHWSpinlock_Params * params)
251 {
252 GateHWSpinlock_Object * obj = (GateHWSpinlock_Object *)calloc(1,
253 sizeof (GateHWSpinlock_Object));
255 if (!obj) {
256 PRINTVERBOSE0("GateHWSpinlock_create: memory allocation failure")
257 return NULL;
258 }
260 IGateProvider_ObjectInitializer(obj, GateHWSpinlock);
261 /* TODO: handle more local protection types */
262 obj->localGate = (IGateProvider_Handle)Mod->gmHandle;
263 obj->lockNum = params->resourceId;
264 obj->nested = 0;
266 return (GateHWSpinlock_Handle)obj;
267 }
269 /*
270 * Delete a GateHWSpinlock instance
271 */
272 Int GateHWSpinlock_delete (GateHWSpinlock_Handle * handle)
273 {
274 GateHWSpinlock_Object * obj;
275 Int status = GateHWSpinlock_S_SUCCESS;
277 if (handle == NULL) {
278 return GateHWSpinlock_E_INVALIDARG;
279 }
280 if (*handle == NULL) {
281 return GateHWSpinlock_E_INVALIDARG;
282 }
284 obj = (GateHWSpinlock_Object *)(*handle);
286 free(obj);
287 *handle = NULL;
289 return (status);
290 }
292 /*
293 * Enter a GateHWSpinlock instance
294 */
295 IArg GateHWSpinlock_enter(GateHWSpinlock_Object *obj)
296 {
297 volatile UInt32 *baseAddr = Mod->baseAddr;
298 IArg key;
300 key = IGateProvider_enter(obj->localGate);
302 /* if gate already entered, just return with current key */
303 obj->nested++;
304 if (obj->nested > 1) {
305 return(key);
306 }
308 /* enter the spinlock */
309 while (1) {
310 /* read the spinlock, returns non-zero when we get it */
311 if (baseAddr[obj->lockNum] == 0) {
312 break;
313 }
314 obj->nested--;
315 IGateProvider_leave(obj->localGate, key);
316 key = IGateProvider_enter(obj->localGate);
317 obj->nested++; /* re-nest the gate */
318 }
320 return (key);
321 }
323 /*
324 * Leave a GateHWSpinlock instance
325 */
326 Int GateHWSpinlock_leave(GateHWSpinlock_Object *obj, IArg key)
327 {
328 volatile UInt32 *baseAddr = Mod->baseAddr;
330 obj->nested--;
332 /* release the spinlock if not nested */
333 if (obj->nested == 0) {
334 baseAddr[obj->lockNum] = 0;
335 }
337 IGateProvider_leave(obj->localGate, key);
339 return GateHWSpinlock_S_SUCCESS;
340 }