Linux: GateHWSpinlock: Fix Compiler Warnings
[ipc/ipcdev.git] / linux / src / daemon / GateHWSpinlock.c
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 /* Module level headers */
56 #include <_lad.h>
58 /* Linux headers */
59 #include <assert.h>
60 #include <fcntl.h>
61 #include <string.h>
62 #include <stdlib.h>
63 #include <sys/ioctl.h>
64 #include <sys/mman.h>
65 #include <sys/stat.h>
67 #include <linux/hwspinlock_user.h>
69 /* =============================================================================
70  * Structures & Enums
71  * =============================================================================
72  */
73 /* GateHWSpinlock Module Local State */
74 typedef struct {
75     Int32                           fd;         /* spinlock device handle */
76     UInt32 *                        baseAddr;   /* base addr lock registers */
77     GateMutex_Handle                gmHandle;   /* handle to gate mutex */
78     Bool                            useHwlockDrv; /* use the hwspinlock driver */
79 } GateHWSpinlock_Module_State;
81 /* GateHWSpinlock instance object */
82 struct GateHWSpinlock_Object {
83     IGateProvider_SuperObject; /* For inheritance from IGateProvider */
84     UInt                        lockNum;
85     UInt                        nested;
86     IGateProvider_Handle        localGate;
87     int                         token;  /* HWSpinlock token */
88 };
91 /* =============================================================================
92  * Globals
93  * =============================================================================
94  */
95 GateHWSpinlock_Config _GateHWSpinlock_cfgParams;
97 static GateHWSpinlock_Module_State GateHWSpinlock_state =
98 {
99     .fd = -1,
100     .baseAddr = NULL,
101     .gmHandle = NULL,
102     .useHwlockDrv = false,
103 };
105 static GateHWSpinlock_Module_State *Mod = &GateHWSpinlock_state;
107 static GateHWSpinlock_Params GateHWSpinlock_defInstParams =
109     .resourceId = 0,
110     .openFlag   = FALSE,
111     .regionId   = 0,
112     .sharedAddr = NULL
113 };
115 /* =============================================================================
116  * APIS
117  * =============================================================================
118  */
119 /*
120  *  Function to start the GateHWSpinlock module.
121  */
122 Int32 GateHWSpinlock_start(Void)
124     Int32               status = GateHWSpinlock_S_SUCCESS;
125     UInt32              dst;
127     /* Fall back to /dev/mem if hwspinlock_user driver is not supported */
128     Mod->fd = open("/dev/hwspinlock", O_RDWR);
129     if (Mod->fd < 0) {
130         Mod->fd = open ("/dev/mem", O_RDWR | O_SYNC);
131     }
132     else {
133         Mod->useHwlockDrv = true;
134     }
136     if (Mod->fd < 0){
137         LOG0("GateHWSpinlock_start: failed to open the spinlock device");
138         status = GateHWSpinlock_E_OSFAILURE;
139     }
141     /* map the hardware lock registers into the local address space */
142     if (!Mod->useHwlockDrv && status == GateHWSpinlock_S_SUCCESS) {
143         dst = (UInt32)mmap(NULL, _GateHWSpinlock_cfgParams.size,
144                             (PROT_READ | PROT_WRITE),
145                             (MAP_SHARED), Mod->fd,
146                             (off_t)_GateHWSpinlock_cfgParams.baseAddr);
148         if (dst == (UInt32)MAP_FAILED) {
149             LOG0("GateHWSpinlock_start: Memory map failed")
150             status = GateHWSpinlock_E_OSFAILURE;
151             close(Mod->fd);
152             Mod->fd = -1;
153         }
154         else {
155             Mod->baseAddr = (UInt32 *)(dst + _GateHWSpinlock_cfgParams.offset);
156             status = GateHWSpinlock_S_SUCCESS;
157         }
158     }
160     /* create GateMutex for local protection*/
161     if (status == GateHWSpinlock_S_SUCCESS) {
162         Mod->gmHandle = GateMutex_create(NULL, NULL);
164         if (Mod->gmHandle == NULL) {
165             LOG0("GateHWSpinlock_start: GateMutex create failed")
166             status = GateHWSpinlock_E_FAIL;
167             GateHWSpinlock_stop();
168         }
169     }
171     return (status);
174 /*
175  *  Function to stop the GateHWSpinlock module.
176  */
177 Int GateHWSpinlock_stop(Void)
179     Int32               status = GateHWSpinlock_S_SUCCESS;
181     /* delete GateMutex */
182     if (Mod->gmHandle != NULL) {
183         status = GateMutex_delete(&Mod->gmHandle);
184     }
186     /* release lock register mapping */
187     if (!Mod->useHwlockDrv && (Mod->baseAddr != NULL)) {
188         munmap((void *)_GateHWSpinlock_cfgParams.baseAddr,
189            _GateHWSpinlock_cfgParams.size);
190     }
192     /* close the spinlock device file */
193     if (Mod->fd >= 0) {
194         close(Mod->fd);
195         Mod->fd = -1;
196     }
198     return(status);
201 /*
202  *  Initialize parameter structure
203  */
204 Void GateHWSpinlock_Params_init(GateHWSpinlock_Params *params)
206     assert(params != NULL);
208     memcpy(params, &GateHWSpinlock_defInstParams,
209         sizeof(GateHWSpinlock_Params));
212 /*
213  * Create a GateHWSpinlock instance
214  */
215 /* TODO: change the function to accept a local gate. Do this on all platforms */
216 GateHWSpinlock_Handle GateHWSpinlock_create(GateHWSpinlock_LocalProtect
217     localProtect, const GateHWSpinlock_Params * params)
219     GateHWSpinlock_Object * obj = (GateHWSpinlock_Object *)calloc(1,
220         sizeof (GateHWSpinlock_Object));
222     if (!obj) {
223         LOG0("GateHWSpinlock_create: memory allocation failure")
224         return NULL;
225     }
227     IGateProvider_ObjectInitializer(obj, GateHWSpinlock);
228     /* TODO: handle more local protection types */
229     obj->localGate = (IGateProvider_Handle)Mod->gmHandle;
230     obj->lockNum = params->resourceId;
231     obj->nested = 0;
233     return (GateHWSpinlock_Handle)obj;
236 /*
237  * Delete a GateHWSpinlock instance
238  */
239 Int GateHWSpinlock_delete (GateHWSpinlock_Handle * handle)
241     GateHWSpinlock_Object * obj;
242     Int  status = GateHWSpinlock_S_SUCCESS;
244     if (handle == NULL) {
245         return GateHWSpinlock_E_INVALIDARG;
246     }
247     if (*handle == NULL) {
248         return GateHWSpinlock_E_INVALIDARG;
249     }
251     obj = (GateHWSpinlock_Object *)(*handle);
253     free(obj);
254     *handle = NULL;
256     return (status);
259 /*
260  *  Enter a GateHWSpinlock instance
261  */
262 IArg GateHWSpinlock_enter(GateHWSpinlock_Object *obj)
264     volatile UInt32 *baseAddr = Mod->baseAddr;
265     struct hwspinlock_user_lock data = {
266         .id = obj->lockNum,
267         .timeout = 10,
268     };
269     IArg key;
270     Bool locked;
272     key = IGateProvider_enter(obj->localGate);
274     /* if gate already entered, just return with current key */
275     obj->nested++;
276     if (obj->nested > 1) {
277         return(key);
278     }
280     /* enter the spinlock */
281     while (1) {
282         if (Mod->useHwlockDrv) {
283             locked = !ioctl(Mod->fd, HWSPINLOCK_USER_LOCK, &data);
284         }
285         else {
286             /* read the spinlock, returns non-zero when we get it */
287             locked = (baseAddr[obj->lockNum] == 0);
288         }
290         if (locked) {
291             break;
292         }
294         obj->nested--;
295         IGateProvider_leave(obj->localGate, key);
296         key = IGateProvider_enter(obj->localGate);
297         obj->nested++; /* re-nest the gate */
298     }
300     return (key);
303 /*
304  *  Leave a GateHWSpinlock instance
305  */
306 Int GateHWSpinlock_leave(GateHWSpinlock_Object *obj, IArg key)
308     volatile UInt32 *baseAddr = Mod->baseAddr;
309     struct hwspinlock_user_unlock data = {
310         .id = obj->lockNum,
311     };
313     obj->nested--;
315     /* release the spinlock if not nested */
316     if (obj->nested == 0) {
317         if (Mod->useHwlockDrv) {
318             ioctl(Mod->fd, HWSPINLOCK_USER_UNLOCK, &data);
319         }
320         else {
321             baseAddr[obj->lockNum] = 0;
322         }
323     }
325     IGateProvider_leave(obj->localGate, key);
327     return GateHWSpinlock_S_SUCCESS;