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 static Bool verbose = FALSE;
111 /* =============================================================================
112 * APIS
113 * =============================================================================
114 */
115 /* Function to get configuration address & sizes for the GateHWSpinlock module.
116 *
117 */
118 Void GateHWSpinlock_getConfig (GateHWSpinlock_Config * cfgParams)
119 {
120 Int status;
121 LAD_ClientHandle handle;
122 struct LAD_CommandObj cmd;
123 union LAD_ResponseObj rsp;
125 assert (cfgParams != NULL);
127 handle = LAD_findHandle();
128 if (handle == LAD_MAXNUMCLIENTS) {
129 PRINTVERBOSE0(
130 "GateHWSpinlock_getConfig: can't find connection to daemon for pid")
131 PRINTVERBOSE1("%d\n", getpid())
133 return;
134 }
136 cmd.cmd = LAD_GATEHWSPINLOCK_GETCONFIG;
137 cmd.clientId = handle;
139 if ((status = LAD_putCommand(&cmd)) != LAD_SUCCESS) {
140 PRINTVERBOSE1(
141 "GateHWSpinlock_getConfig: sending LAD command failed, status=%d\n",
142 status)
143 return;
144 }
146 if ((status = LAD_getResponse(handle, &rsp)) != LAD_SUCCESS) {
147 PRINTVERBOSE1("GateHWSpinlock_getConfig: no LAD response, status=%d\n",
148 status)
149 return;
150 }
151 status = rsp.gateHWSpinlockGetConfig.status;
153 PRINTVERBOSE2(
154 "GateHWSpinlock_getConfig: got LAD response for client %d, status=%d\n",
155 handle, status)
157 memcpy(cfgParams, &rsp.gateHWSpinlockGetConfig.cfgParams,
158 sizeof(*cfgParams));
160 return;
161 }
164 /*
165 * Function to start the GateHWSpinlock module.
166 */
167 Int32 GateHWSpinlock_start(Void)
168 {
169 Int32 status = GateHWSpinlock_S_SUCCESS;
170 UInt32 dst;
171 Int32 fdMem;
173 fdMem = open ("/dev/mem", O_RDWR | O_SYNC);
175 if (fdMem < 0){
176 PRINTVERBOSE0("GateHWSpinlock_start: failed to open the /dev/mem");
177 status = GateHWSpinlock_E_OSFAILURE;
178 }
180 /* map the hardware lock registers into the local address space */
181 if (status == GateHWSpinlock_S_SUCCESS) {
182 dst = (UInt32)mmap(NULL, _GateHWSpinlock_cfgParams.size,
183 (PROT_READ | PROT_WRITE),
184 (MAP_SHARED), fdMem,
185 (off_t)_GateHWSpinlock_cfgParams.baseAddr);
187 if (dst == (UInt32)MAP_FAILED) {
188 PRINTVERBOSE0("GateHWSpinlock_start: Memory map failed")
189 status = GateHWSpinlock_E_OSFAILURE;
190 }
191 else {
192 Mod->baseAddr = (UInt32 *)(dst + _GateHWSpinlock_cfgParams.offset);
193 status = GateHWSpinlock_S_SUCCESS;
194 }
195 }
197 /* create GateMutex for local protection*/
198 if (status == GateHWSpinlock_S_SUCCESS) {
199 Mod->gmHandle = GateMutex_create(NULL, NULL);
201 if (Mod->gmHandle == NULL) {
202 PRINTVERBOSE0("GateHWSpinlock_start: GateMutex create failed")
203 status = GateHWSpinlock_E_FAIL;
204 GateHWSpinlock_stop();
205 }
206 }
208 return (status);
209 }
211 /*
212 * Function to stop the GateHWSpinlock module.
213 */
214 Int GateHWSpinlock_stop(Void)
215 {
216 Int32 status = GateHWSpinlock_S_SUCCESS;
218 /* delete GateMutex */
219 if (Mod->gmHandle != NULL) {
220 status = GateMutex_delete(&Mod->gmHandle);
221 }
223 /* release lock register mapping */
224 if (Mod->baseAddr != NULL) {
225 munmap((void *)_GateHWSpinlock_cfgParams.baseAddr,
226 _GateHWSpinlock_cfgParams.size);
227 }
229 return(status);
230 }
232 /*
233 * Initialize parameter structure
234 */
235 Void GateHWSpinlock_Params_init(GateHWSpinlock_Params *params)
236 {
237 assert(params != NULL);
239 memcpy(params, &GateHWSpinlock_defInstParams,
240 sizeof(GateHWSpinlock_Params));
241 }
243 /*
244 * Create a GateHWSpinlock instance
245 */
246 /* TODO: change the function to accept a local gate. Do this on all platforms */
247 GateHWSpinlock_Handle GateHWSpinlock_create(GateHWSpinlock_LocalProtect
248 localProtect, const GateHWSpinlock_Params * params)
249 {
250 GateHWSpinlock_Object * obj = (GateHWSpinlock_Object *)calloc(1,
251 sizeof (GateHWSpinlock_Object));
253 if (!obj) {
254 PRINTVERBOSE0("GateHWSpinlock_create: memory allocation failure")
255 return NULL;
256 }
258 IGateProvider_ObjectInitializer(obj, GateHWSpinlock);
259 /* TODO: handle more local protection types */
260 obj->localGate = (IGateProvider_Handle)Mod->gmHandle;
261 obj->lockNum = params->resourceId;
262 obj->nested = 0;
264 return (GateHWSpinlock_Handle)obj;
265 }
267 /*
268 * Delete a GateHWSpinlock instance
269 */
270 Int GateHWSpinlock_delete (GateHWSpinlock_Handle * handle)
271 {
272 GateHWSpinlock_Object * obj;
273 Int status = GateHWSpinlock_S_SUCCESS;
275 if (handle == NULL) {
276 return GateHWSpinlock_E_INVALIDARG;
277 }
278 if (*handle == NULL) {
279 return GateHWSpinlock_E_INVALIDARG;
280 }
282 obj = (GateHWSpinlock_Object *)(*handle);
284 free(obj);
285 *handle = NULL;
287 return (status);
288 }
290 /*
291 * Enter a GateHWSpinlock instance
292 */
293 IArg GateHWSpinlock_enter(GateHWSpinlock_Object *obj)
294 {
295 volatile UInt32 *baseAddr = Mod->baseAddr;
296 IArg key;
298 key = IGateProvider_enter(obj->localGate);
300 /* if gate already entered, just return with current key */
301 obj->nested++;
302 if (obj->nested > 1) {
303 return(key);
304 }
306 /* enter the spinlock */
307 while (1) {
308 /* read the spinlock, returns non-zero when we get it */
309 if (baseAddr[obj->lockNum] == 0) {
310 break;
311 }
312 obj->nested--;
313 IGateProvider_leave(obj->localGate, key);
314 key = IGateProvider_enter(obj->localGate);
315 obj->nested++; /* re-nest the gate */
316 }
318 return (key);
319 }
321 /*
322 * Leave a GateHWSpinlock instance
323 */
324 Int GateHWSpinlock_leave(GateHWSpinlock_Object *obj, IArg key)
325 {
326 volatile UInt32 *baseAddr = Mod->baseAddr;
328 obj->nested--;
330 /* release the spinlock if not nested */
331 if (obj->nested == 0) {
332 baseAddr[obj->lockNum] = 0;
333 }
335 IGateProvider_leave(obj->localGate, key);
337 return GateHWSpinlock_S_SUCCESS;
338 }