Linux: Close spinlock device after gate is stopped
[ipc/ipcdev.git] / linux / src / api / gates / 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 /* 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     Int32                           fd;         /* spinlock device handle */
74     UInt32 *                        baseAddr;   /* base addr lock registers */
75     GateMutex_Handle                gmHandle;   /* handle to gate mutex */
76 } GateHWSpinlock_Module_State;
78 /* GateHWSpinlock instance object */
79 struct GateHWSpinlock_Object {
80     IGateProvider_SuperObject; /* For inheritance from IGateProvider */
81     UInt                        lockNum;
82     UInt                        nested;
83     IGateProvider_Handle        localGate;
84     int                         token;  /* HWSpinlock token */
85 };
88 /* =============================================================================
89  * Globals
90  * =============================================================================
91  */
92 GateHWSpinlock_Config _GateHWSpinlock_cfgParams;
94 static GateHWSpinlock_Module_State GateHWSpinlock_state =
95 {
96     .fd = -1,
97     .baseAddr = NULL,
98     .gmHandle = NULL
99 };
101 static GateHWSpinlock_Module_State *Mod = &GateHWSpinlock_state;
103 static GateHWSpinlock_Params GateHWSpinlock_defInstParams =
105     .resourceId = 0,
106     .openFlag   = FALSE,
107     .regionId   = 0,
108     .sharedAddr = NULL
109 };
111 /* traces in this file are controlled via _GateHWSpinlock_verbose */
112 Bool _GateHWSpinlock_verbose = FALSE;
113 #define verbose _GateHWSpinlock_verbose
115 /* =============================================================================
116  * APIS
117  * =============================================================================
118  */
119 /* Function to get configuration address & sizes for the GateHWSpinlock module.
120  *
121  */
122 Void GateHWSpinlock_getConfig (GateHWSpinlock_Config * cfgParams)
124     Int status;
125     LAD_ClientHandle handle;
126     struct LAD_CommandObj cmd;
127     union LAD_ResponseObj rsp;
129     assert (cfgParams != NULL);
131     handle = LAD_findHandle();
132     if (handle == LAD_MAXNUMCLIENTS) {
133         PRINTVERBOSE0(
134           "GateHWSpinlock_getConfig: can't find connection to daemon for pid")
135         PRINTVERBOSE1("%d\n", getpid())
137         return;
138     }
140     cmd.cmd = LAD_GATEHWSPINLOCK_GETCONFIG;
141     cmd.clientId = handle;
143     if ((status = LAD_putCommand(&cmd)) != LAD_SUCCESS) {
144         PRINTVERBOSE1(
145           "GateHWSpinlock_getConfig: sending LAD command failed, status=%d\n",
146           status)
147         return;
148     }
150     if ((status = LAD_getResponse(handle, &rsp)) != LAD_SUCCESS) {
151         PRINTVERBOSE1("GateHWSpinlock_getConfig: no LAD response, status=%d\n",
152         status)
153         return;
154     }
155     status = rsp.gateHWSpinlockGetConfig.status;
157     PRINTVERBOSE2(
158       "GateHWSpinlock_getConfig: got LAD response for client %d, status=%d\n",
159       handle, status)
161     memcpy(cfgParams, &rsp.gateHWSpinlockGetConfig.cfgParams,
162         sizeof(*cfgParams));
164     return;
168 /*
169  *  Function to start the GateHWSpinlock module.
170  */
171 Int32 GateHWSpinlock_start(Void)
173     Int32               status = GateHWSpinlock_S_SUCCESS;
174     UInt32              dst;
175     int                 flags;
177     Mod->fd = open ("/dev/mem", O_RDWR | O_SYNC);
178     if (Mod->fd < 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(Mod->fd, F_GETFD);
185     if (flags != -1) {
186         fcntl(Mod->fd, 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), Mod->fd,
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             close(Mod->fd);
200             Mod->fd = -1;
201         }
202         else {
203             Mod->baseAddr = (UInt32 *)(dst + _GateHWSpinlock_cfgParams.offset);
204             status = GateHWSpinlock_S_SUCCESS;
205         }
206     }
208     /* create GateMutex for local protection*/
209     if (status == GateHWSpinlock_S_SUCCESS) {
210         Mod->gmHandle = GateMutex_create(NULL, NULL);
212         if (Mod->gmHandle == NULL) {
213             PRINTVERBOSE0("GateHWSpinlock_start: GateMutex create failed")
214             status = GateHWSpinlock_E_FAIL;
215             GateHWSpinlock_stop();
216         }
217     }
219     return (status);
222 /*
223  *  Function to stop the GateHWSpinlock module.
224  */
225 Int GateHWSpinlock_stop(Void)
227     Int32               status = GateHWSpinlock_S_SUCCESS;
229     /* delete GateMutex */
230     if (Mod->gmHandle != NULL) {
231         status = GateMutex_delete(&Mod->gmHandle);
232     }
234     /* release lock register mapping */
235     if (Mod->baseAddr != NULL) {
236         munmap((void *)_GateHWSpinlock_cfgParams.baseAddr,
237            _GateHWSpinlock_cfgParams.size);
238     }
240     /* close the spinlock device file */
241     if (Mod->fd >= 0) {
242         close(Mod->fd);
243         Mod->fd = -1;
244     }
246     return(status);
249 /*
250  *  Initialize parameter structure
251  */
252 Void GateHWSpinlock_Params_init(GateHWSpinlock_Params *params)
254     assert(params != NULL);
256     memcpy(params, &GateHWSpinlock_defInstParams,
257         sizeof(GateHWSpinlock_Params));
260 /*
261  * Create a GateHWSpinlock instance
262  */
263 /* TODO: change the function to accept a local gate. Do this on all platforms */
264 GateHWSpinlock_Handle GateHWSpinlock_create(GateHWSpinlock_LocalProtect
265     localProtect, const GateHWSpinlock_Params * params)
267     GateHWSpinlock_Object * obj = (GateHWSpinlock_Object *)calloc(1,
268         sizeof (GateHWSpinlock_Object));
270     if (!obj) {
271         PRINTVERBOSE0("GateHWSpinlock_create: memory allocation failure")
272         return NULL;
273     }
275     IGateProvider_ObjectInitializer(obj, GateHWSpinlock);
276     /* TODO: handle more local protection types */
277     obj->localGate = (IGateProvider_Handle)Mod->gmHandle;
278     obj->lockNum = params->resourceId;
279     obj->nested = 0;
281     return (GateHWSpinlock_Handle)obj;
284 /*
285  * Delete a GateHWSpinlock instance
286  */
287 Int GateHWSpinlock_delete (GateHWSpinlock_Handle * handle)
289     GateHWSpinlock_Object * obj;
290     Int  status = GateHWSpinlock_S_SUCCESS;
292     if (handle == NULL) {
293         return GateHWSpinlock_E_INVALIDARG;
294     }
295     if (*handle == NULL) {
296         return GateHWSpinlock_E_INVALIDARG;
297     }
299     obj = (GateHWSpinlock_Object *)(*handle);
301     free(obj);
302     *handle = NULL;
304     return (status);
307 /*
308  *  Enter a GateHWSpinlock instance
309  */
310 IArg GateHWSpinlock_enter(GateHWSpinlock_Object *obj)
312     volatile UInt32 *baseAddr = Mod->baseAddr;
313     IArg key;
315     key = IGateProvider_enter(obj->localGate);
317     /* if gate already entered, just return with current key */
318     obj->nested++;
319     if (obj->nested > 1) {
320         return(key);
321     }
323     /* enter the spinlock */
324     while (1) {
325         /* read the spinlock, returns non-zero when we get it */
326         if (baseAddr[obj->lockNum] == 0) {
327             break;
328         }
329         obj->nested--;
330         IGateProvider_leave(obj->localGate, key);
331         key = IGateProvider_enter(obj->localGate);
332         obj->nested++; /* re-nest the gate */
333     }
335     return (key);
338 /*
339  *  Leave a GateHWSpinlock instance
340  */
341 Int GateHWSpinlock_leave(GateHWSpinlock_Object *obj, IArg key)
343     volatile UInt32 *baseAddr = Mod->baseAddr;
345     obj->nested--;
347     /* release the spinlock if not nested */
348     if (obj->nested == 0) {
349         baseAddr[obj->lockNum] = 0;
350     }
352     IGateProvider_leave(obj->localGate, key);
354     return GateHWSpinlock_S_SUCCESS;