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/ioctl.h>
65 #include <sys/mman.h>
66 #include <sys/stat.h>
68 #include <linux/hwspinlock_user.h>
70 /* =============================================================================
71 * Structures & Enums
72 * =============================================================================
73 */
74 /* GateHWSpinlock Module Local State */
75 typedef struct {
76 Int32 fd; /* spinlock device handle */
77 UInt32 * baseAddr; /* base addr lock registers */
78 GateMutex_Handle gmHandle; /* handle to gate mutex */
79 Bool useHwlockDrv; /* use the hwspinlock driver */
80 } GateHWSpinlock_Module_State;
82 /* GateHWSpinlock instance object */
83 struct GateHWSpinlock_Object {
84 IGateProvider_SuperObject; /* For inheritance from IGateProvider */
85 UInt lockNum;
86 UInt nested;
87 IGateProvider_Handle localGate;
88 int token; /* HWSpinlock token */
89 };
92 /* =============================================================================
93 * Globals
94 * =============================================================================
95 */
96 GateHWSpinlock_Config _GateHWSpinlock_cfgParams;
98 static GateHWSpinlock_Module_State GateHWSpinlock_state =
99 {
100 .fd = -1,
101 .baseAddr = NULL,
102 .gmHandle = NULL,
103 .useHwlockDrv = false,
104 };
106 static GateHWSpinlock_Module_State *Mod = &GateHWSpinlock_state;
108 static GateHWSpinlock_Params GateHWSpinlock_defInstParams =
109 {
110 .resourceId = 0,
111 .openFlag = FALSE,
112 .regionId = 0,
113 .sharedAddr = NULL
114 };
116 /* traces in this file are controlled via _GateHWSpinlock_verbose */
117 Bool _GateHWSpinlock_verbose = FALSE;
118 #define verbose _GateHWSpinlock_verbose
120 /* =============================================================================
121 * APIS
122 * =============================================================================
123 */
124 /* Function to get configuration address & sizes for the GateHWSpinlock module.
125 *
126 */
127 Void GateHWSpinlock_getConfig (GateHWSpinlock_Config * cfgParams)
128 {
129 Int status;
130 LAD_ClientHandle handle;
131 struct LAD_CommandObj cmd;
132 union LAD_ResponseObj rsp;
134 assert (cfgParams != NULL);
136 handle = LAD_findHandle();
137 if (handle == LAD_MAXNUMCLIENTS) {
138 PRINTVERBOSE0(
139 "GateHWSpinlock_getConfig: can't find connection to daemon for pid")
140 PRINTVERBOSE1("%d\n", getpid())
142 return;
143 }
145 cmd.cmd = LAD_GATEHWSPINLOCK_GETCONFIG;
146 cmd.clientId = handle;
148 if ((status = LAD_putCommand(&cmd)) != LAD_SUCCESS) {
149 PRINTVERBOSE1(
150 "GateHWSpinlock_getConfig: sending LAD command failed, status=%d\n",
151 status)
152 return;
153 }
155 if ((status = LAD_getResponse(handle, &rsp)) != LAD_SUCCESS) {
156 PRINTVERBOSE1("GateHWSpinlock_getConfig: no LAD response, status=%d\n",
157 status)
158 return;
159 }
160 status = rsp.gateHWSpinlockGetConfig.status;
162 PRINTVERBOSE2(
163 "GateHWSpinlock_getConfig: got LAD response for client %d, status=%d\n",
164 handle, status)
166 memcpy(cfgParams, &rsp.gateHWSpinlockGetConfig.cfgParams,
167 sizeof(*cfgParams));
169 return;
170 }
173 /*
174 * Function to start the GateHWSpinlock module.
175 */
176 Int32 GateHWSpinlock_start(Void)
177 {
178 Int32 status = GateHWSpinlock_S_SUCCESS;
179 UInt32 dst;
180 int flags;
182 /* Fall back to /dev/mem if hwspinlock_user driver is not supported */
183 Mod->fd = open("/dev/hwspinlock", O_RDWR);
184 if (Mod->fd < 0) {
185 Mod->fd = open ("/dev/mem", O_RDWR | O_SYNC);
186 }
187 else {
188 Mod->useHwlockDrv = true;
189 }
191 if (Mod->fd < 0){
192 PRINTVERBOSE0("GateHWSpinlock_start: failed to open the spinlock device");
193 status = GateHWSpinlock_E_OSFAILURE;
194 }
196 if (!Mod->useHwlockDrv) {
197 /* make sure /dev/mem fd doesn't exist for 'fork() -> exec*()'ed child */
198 flags = fcntl(Mod->fd, F_GETFD);
199 if (flags != -1) {
200 fcntl(Mod->fd, F_SETFD, flags | FD_CLOEXEC);
201 }
203 /* map the hardware lock registers into the local address space */
204 if (status == GateHWSpinlock_S_SUCCESS) {
205 dst = (UInt32)mmap(NULL, _GateHWSpinlock_cfgParams.size,
206 (PROT_READ | PROT_WRITE),
207 (MAP_SHARED), Mod->fd,
208 (off_t)_GateHWSpinlock_cfgParams.baseAddr);
210 if (dst == (UInt32)MAP_FAILED) {
211 PRINTVERBOSE0("GateHWSpinlock_start: Memory map failed")
212 status = GateHWSpinlock_E_OSFAILURE;
213 close(Mod->fd);
214 Mod->fd = -1;
215 }
216 else {
217 Mod->baseAddr = (UInt32 *)(dst + _GateHWSpinlock_cfgParams.offset);
218 status = GateHWSpinlock_S_SUCCESS;
219 }
220 }
221 }
223 /* create GateMutex for local protection*/
224 if (status == GateHWSpinlock_S_SUCCESS) {
225 Mod->gmHandle = GateMutex_create(NULL, NULL);
227 if (Mod->gmHandle == NULL) {
228 PRINTVERBOSE0("GateHWSpinlock_start: GateMutex create failed")
229 status = GateHWSpinlock_E_FAIL;
230 GateHWSpinlock_stop();
231 }
232 }
234 return (status);
235 }
237 /*
238 * Function to stop the GateHWSpinlock module.
239 */
240 Int GateHWSpinlock_stop(Void)
241 {
242 Int32 status = GateHWSpinlock_S_SUCCESS;
244 /* delete GateMutex */
245 if (Mod->gmHandle != NULL) {
246 status = GateMutex_delete(&Mod->gmHandle);
247 }
249 /* release lock register mapping */
250 if (!Mod->useHwlockDrv && (Mod->baseAddr != NULL)) {
251 munmap((void *)_GateHWSpinlock_cfgParams.baseAddr,
252 _GateHWSpinlock_cfgParams.size);
253 }
255 /* close the spinlock device file */
256 if (Mod->fd >= 0) {
257 close(Mod->fd);
258 Mod->fd = -1;
259 }
261 return(status);
262 }
264 /*
265 * Initialize parameter structure
266 */
267 Void GateHWSpinlock_Params_init(GateHWSpinlock_Params *params)
268 {
269 assert(params != NULL);
271 memcpy(params, &GateHWSpinlock_defInstParams,
272 sizeof(GateHWSpinlock_Params));
273 }
275 /*
276 * Create a GateHWSpinlock instance
277 */
278 /* TODO: change the function to accept a local gate. Do this on all platforms */
279 GateHWSpinlock_Handle GateHWSpinlock_create(GateHWSpinlock_LocalProtect
280 localProtect, const GateHWSpinlock_Params * params)
281 {
282 GateHWSpinlock_Object * obj = (GateHWSpinlock_Object *)calloc(1,
283 sizeof (GateHWSpinlock_Object));
285 if (!obj) {
286 PRINTVERBOSE0("GateHWSpinlock_create: memory allocation failure")
287 return NULL;
288 }
290 IGateProvider_ObjectInitializer(obj, GateHWSpinlock);
291 /* TODO: handle more local protection types */
292 obj->localGate = (IGateProvider_Handle)Mod->gmHandle;
293 obj->lockNum = params->resourceId;
294 obj->nested = 0;
296 return (GateHWSpinlock_Handle)obj;
297 }
299 /*
300 * Delete a GateHWSpinlock instance
301 */
302 Int GateHWSpinlock_delete (GateHWSpinlock_Handle * handle)
303 {
304 GateHWSpinlock_Object * obj;
305 Int status = GateHWSpinlock_S_SUCCESS;
307 if (handle == NULL) {
308 return GateHWSpinlock_E_INVALIDARG;
309 }
310 if (*handle == NULL) {
311 return GateHWSpinlock_E_INVALIDARG;
312 }
314 obj = (GateHWSpinlock_Object *)(*handle);
316 free(obj);
317 *handle = NULL;
319 return (status);
320 }
322 /*
323 * Enter a GateHWSpinlock instance
324 */
325 IArg GateHWSpinlock_enter(GateHWSpinlock_Object *obj)
326 {
327 volatile UInt32 *baseAddr = Mod->baseAddr;
328 struct hwspinlock_user_lock data = {
329 .id = obj->lockNum,
330 .timeout = 10,
331 };
332 IArg key;
333 Bool locked;
335 key = IGateProvider_enter(obj->localGate);
337 /* if gate already entered, just return with current key */
338 obj->nested++;
339 if (obj->nested > 1) {
340 return(key);
341 }
343 /* enter the spinlock */
344 while (1) {
345 if (Mod->useHwlockDrv) {
346 locked = !ioctl(Mod->fd, HWSPINLOCK_USER_LOCK, &data);
347 }
348 else {
349 /* read the spinlock, returns non-zero when we get it */
350 locked = (baseAddr[obj->lockNum] == 0);
351 }
353 if (locked) {
354 break;
355 }
357 obj->nested--;
358 IGateProvider_leave(obj->localGate, key);
359 key = IGateProvider_enter(obj->localGate);
360 obj->nested++; /* re-nest the gate */
361 }
363 return (key);
364 }
366 /*
367 * Leave a GateHWSpinlock instance
368 */
369 Int GateHWSpinlock_leave(GateHWSpinlock_Object *obj, IArg key)
370 {
371 volatile UInt32 *baseAddr = Mod->baseAddr;
372 struct hwspinlock_user_unlock data = {
373 .id = obj->lockNum,
374 };
376 obj->nested--;
378 /* release the spinlock if not nested */
379 if (obj->nested == 0) {
380 if (Mod->useHwlockDrv) {
381 ioctl(Mod->fd, HWSPINLOCK_USER_UNLOCK, &data);
382 }
383 else {
384 baseAddr[obj->lockNum] = 0;
385 }
386 }
388 IGateProvider_leave(obj->localGate, key);
390 return GateHWSpinlock_S_SUCCESS;
391 }