HwSpinLock: Pull in the ti.gates.hwspinlock module from omapzoom sysbios-rpmsg.
[ipc/ipcdev.git] / packages / ti / gates / hwspinlock / HwSpinlock.c
1 /*
2  * Copyright (c) 2011-2013, 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  */
32 /*
33  *  ======== HwSpinlock.c ========
34  */
36 #include <xdc/std.h>
37 #include <xdc/runtime/Assert.h>
38 #include <xdc/runtime/Error.h>
39 #include <xdc/runtime/Memory.h>
40 #include <xdc/runtime/IGateProvider.h>
41 #include <xdc/runtime/Log.h>
42 #include <xdc/runtime/Diags.h>
43 #include <xdc/runtime/Gate.h>
45 #include <ti/sysbios/knl/Task.h>
46 #include <ti/sysbios/knl/Clock.h>
48 #include <ti/gates/hwspinlock/HwSpinlock.h>
49 #include "_HwSpinlock.h"
52 static HwSpinlock_Module_State HwSpinlock_module = { 0 };
54 /* Exposed to the Host side to reset hwspinlock if needed */
55 Bits32 ti_gates_HwSpinlock_sharedState
56                             [(HwSpinlock_NUMLOCKS/sizeof(Bits32))] = { 0 };
57 const UInt32 ti_gates_HwSpinlock_numLocks = HwSpinlock_NUMLOCKS;
60 /* Helper functions to set and reset status of a lock */
61 inline Void _HwSpinlock_set(Int hwlockId)
62 {
63     ti_gates_HwSpinlock_sharedState[hwlockId >> 5] |= (1 << (hwlockId % 32));
64 }
66 inline Void _HwSpinlock_clr(Int hwlockId)
67 {
68     ti_gates_HwSpinlock_sharedState[hwlockId >> 5] &= ~(1 << (hwlockId % 32));
69 }
71 /*
72  *************************************************************************
73  *                       Instance functions
74  *************************************************************************
75  */
77 /*
78  *  ======== HwSpinlock_Params_init ========
79  */
80 Void HwSpinlock_Params_init(HwSpinlock_Params *params)
81 {
82     params->id = HwSpinlock_NO_SPINLOCK;
83     params->reqFxn= NULL;
84     params->relFxn= NULL;
85     params->arg1 = NULL;
86     params->arg2 = NULL;
87 }
89 /*
90  *  ======== HwSpinlock_create ========
91  */
92 #define FXNN "HwSpinlock_create"
93 HwSpinlock_Handle HwSpinlock_create(HwSpinlock_Params *params)
94 {
95     HwSpinlock_Handle handle;
96     Int i;
97     IArg key;
99     /* Call request hook fxn, return (NULL handle) if the hook fxn fails */
100     if (params->reqFxn) {
101         if (params->reqFxn(params)) {
102             return NULL;
103         }
104     }
106     /* Check for a valid hwspinlock id */
107     if ((params->id < 0) || (params->id >= HwSpinlock_NUMLOCKS)) {
108         Log_error0(FXNN": HwSpinlock Id is not valid");
109         return NULL;
110     }
112     /* Return handle if already created */
113     key = Gate_enterSystem();
114     handle = HwSpinlock_module.locks[params->id];
115     if (handle) {
116         handle->refCnt++;
117         Gate_leaveSystem(key);
118         return handle;
119     }
121     /* Allocate handle */
122     handle = Memory_alloc(NULL, sizeof(*handle), 0, NULL);
123     if (!handle) {
124         Log_error0(FXNN": Unable to allocate handle");
125         Gate_leaveSystem(key);
126         return NULL;
127     }
129     /* Create the preemption gates */
130     for (i = 0; i < HwSpinlock_NUMPREEMPTGATES; i++) {
131         handle->preemptGates[i] = (IGateProvider_Handle)
132                                     HwSpinlock_GateFxns[i].create(NULL, NULL);
133     }
134     /* Create the local gate */
135     handle->mutex = GateMutexPri_create(NULL, NULL);
137     /* Store private info in the handle */
138     handle->params = *params;
139     handle->baseAddr = (volatile UInt32 *)HwSpinlock_BASEADDR;
140     handle->refCnt = 1;
141     handle->state = HwSpinlock_STATE_FREE;
143     /* Store the created handle */
144     HwSpinlock_module.locks[params->id] = handle;
145     Gate_leaveSystem(key);
147     return handle;
149 #undef FXNN
151 /*
152  *  ======== HwSpinlock_delete ========
153  */
154 #define FXNN "HwSpinlock_delete"
155 Int HwSpinlock_delete(HwSpinlock_Handle handle)
157     Int i;
158     IArg key;
160     Assert_isTrue(handle, NULL);
161     key = Gate_enterSystem();
163     /* Decrement reference counter */
164     if (handle->refCnt) {
165         handle->refCnt--;
166     }
168     if (!handle->refCnt) {
169         /* Return error if trying to delete before unlock */
170         if (handle->state == HwSpinlock_STATE_TAKEN) {
171             Log_error0(FXNN": Error: HwSpinlock still in use");
172             Gate_leaveSystem(key);
173             return HwSpinlock_STILL_IN_USE;
174         }
175         /* Call release hook fxn if exists */
176         if (handle->params.relFxn) {
177             handle->params.relFxn(&handle->params);
178          }
180         /* Delete and reset the preemption gates */
181         for (i = 0; i < HwSpinlock_NUMPREEMPTGATES; i++) {
182             HwSpinlock_GateFxns[i].delete(&handle->preemptGates[i]);
183             handle->preemptGates[i] = NULL;
184         }
185         /* Delete and reset the local gate */
186         GateMutexPri_delete(&handle->mutex);
187         handle->mutex = NULL;
189         /* Remove the handle from the module */
190         HwSpinlock_module.locks[handle->params.id] = NULL;
192         /* Release the allocated memory for the handle */
193         Memory_free(NULL, handle, sizeof(*handle));
194         handle = NULL;
195     }
196     Gate_leaveSystem(key);
198     return HwSpinlock_S_SUCCESS;
200 #undef FXNN
202 /*
203  *  ======== HwSpinlock_enter ========
204  */
205 Int HwSpinlock_enter(HwSpinlock_Handle handle, HwSpinlock_PreemptGate pType,
206                      UInt timeout, HwSpinlock_Key *hkey)
208     UInt start, elapsed;
210     Assert_isTrue(handle, NULL);
212     /* Store Start TimeStamp */
213     if (timeout != HwSpinlock_WAIT_FOREVER) {
214         start = Clock_getTicks();
215     }
217     while(1) {
218         /* Enter the localGate protection */
219         handle->mkey = GateMutexPri_enter(handle->mutex);
221         /* Try to get the hwspinlock */
222         if (handle->baseAddr[handle->params.id] == 0) {
223             handle->state = HwSpinlock_STATE_TAKEN;
224             /* Disable preemption of pType and store the type in handle */
225             hkey->key = IGateProvider_enter(handle->preemptGates[pType]);
226             hkey->valid = TRUE;
227             handle->pType = pType;
228             _HwSpinlock_set(handle->params.id);
229             return (HwSpinlock_S_SUCCESS);
230         }
232         /* If is already taken undo localGate protection */
233         GateMutexPri_leave(handle->mutex, handle->mkey);
235         /* Check if timeout has elapsed */
236         if (timeout != HwSpinlock_WAIT_FOREVER) {
237             elapsed = Clock_getTicks() - start;
238             if (elapsed > timeout) {
239                 /* Mark key as invalid */
240                 hkey->valid = FALSE;
241                 return (HwSpinlock_E_TIMEOUT);
242             }
243         }
244     }
247 /*
248  *  ======== HwSpinlock_leave ========
249  */
250 Void HwSpinlock_leave(HwSpinlock_Handle handle, HwSpinlock_Key *hkey)
252     Assert_isTrue(handle, NULL);
254     /* Only unlock hwspinlock if it was really acquired and isa valid key */
255     if (handle->state == HwSpinlock_STATE_TAKEN && hkey->valid) {
256        /* Leave the spinlock */
257         handle->baseAddr[handle->params.id] = 0;
258         handle->state = HwSpinlock_STATE_FREE;
259         _HwSpinlock_clr(handle->params.id);
261         /* Restore Preemption of pType */
262         IGateProvider_leave(handle->preemptGates[handle->pType], hkey->key);
263         hkey->valid = FALSE;
265         /* Leave the mutex */
266         GateMutexPri_leave(handle->mutex, handle->mkey);
267     }
270 /*
271  *  ======== HwSpinlock_getId ========
272  */
273 Int HwSpinlock_getId(HwSpinlock_Handle handle)
275     Assert_isTrue(handle, NULL);
276     return (handle->params.id);
279 /*
280  *  ======== HwSpinlock_getState ========
281  */
282 HwSpinlock_State HwSpinlock_getState(HwSpinlock_Handle handle)
284     Assert_isTrue(handle, NULL);
285     return (handle->state);