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/mman.h>
64 #include <sys/stat.h>
66 /* =============================================================================
67 * Structures & Enums
68 * =============================================================================
69 */
70 /* GateHWSpinlock Module Local State */
71 typedef struct {
72 UInt32 * baseAddr; /* base addr lock registers */
73 GateMutex_Handle gmHandle; /* handle to gate mutex */
74 } GateHWSpinlock_Module_State;
76 /* GateHWSpinlock instance object */
77 struct GateHWSpinlock_Object {
78 IGateProvider_SuperObject; /* For inheritance from IGateProvider */
79 UInt lockNum;
80 UInt nested;
81 IGateProvider_Handle localGate;
82 int token; /* HWSpinlock token */
83 };
86 /* =============================================================================
87 * Globals
88 * =============================================================================
89 */
90 GateHWSpinlock_Config _GateHWSpinlock_cfgParams;
92 static GateHWSpinlock_Module_State GateHWSpinlock_state =
93 {
94 .baseAddr = NULL,
95 .gmHandle = NULL
96 };
98 static GateHWSpinlock_Module_State *Mod = &GateHWSpinlock_state;
100 static GateHWSpinlock_Params GateHWSpinlock_defInstParams =
101 {
102 .resourceId = 0,
103 .openFlag = FALSE,
104 .regionId = 0,
105 .sharedAddr = NULL
106 };
108 /* =============================================================================
109 * APIS
110 * =============================================================================
111 */
112 /*
113 * Function to start the GateHWSpinlock module.
114 */
115 Int32 GateHWSpinlock_start(Void)
116 {
117 Int32 status = GateHWSpinlock_S_SUCCESS;
118 UInt32 dst;
119 Int32 fdMem;
121 fdMem = open ("/dev/mem", O_RDWR | O_SYNC);
123 if (fdMem < 0){
124 LOG0("GateHWSpinlock_start: failed to open the /dev/mem");
125 status = GateHWSpinlock_E_OSFAILURE;
126 }
128 /* map the hardware lock registers into the local address space */
129 if (status == GateHWSpinlock_S_SUCCESS) {
130 dst = (UInt32)mmap(NULL, _GateHWSpinlock_cfgParams.size,
131 (PROT_READ | PROT_WRITE),
132 (MAP_SHARED), fdMem,
133 (off_t)_GateHWSpinlock_cfgParams.baseAddr);
135 if (dst == (UInt32)MAP_FAILED) {
136 LOG0("GateHWSpinlock_start: Memory map failed")
137 status = GateHWSpinlock_E_OSFAILURE;
138 }
139 else {
140 Mod->baseAddr = (UInt32 *)(dst + _GateHWSpinlock_cfgParams.offset);
141 status = GateHWSpinlock_S_SUCCESS;
142 }
143 }
145 /* create GateMutex for local protection*/
146 if (status == GateHWSpinlock_S_SUCCESS) {
147 Mod->gmHandle = GateMutex_create(NULL, NULL);
149 if (Mod->gmHandle == NULL) {
150 LOG0("GateHWSpinlock_start: GateMutex create failed")
151 status = GateHWSpinlock_E_FAIL;
152 GateHWSpinlock_stop();
153 }
154 }
156 return (status);
157 }
159 /*
160 * Function to stop the GateHWSpinlock module.
161 */
162 Int GateHWSpinlock_stop(Void)
163 {
164 Int32 status = GateHWSpinlock_S_SUCCESS;
166 /* delete GateMutex */
167 if (Mod->gmHandle != NULL) {
168 status = GateMutex_delete(&Mod->gmHandle);
169 }
171 /* release lock register mapping */
172 if (Mod->baseAddr != NULL) {
173 munmap((void *)_GateHWSpinlock_cfgParams.baseAddr,
174 _GateHWSpinlock_cfgParams.size);
175 }
177 return(status);
178 }
180 /*
181 * Initialize parameter structure
182 */
183 Void GateHWSpinlock_Params_init(GateHWSpinlock_Params *params)
184 {
185 assert(params != NULL);
187 memcpy(params, &GateHWSpinlock_defInstParams,
188 sizeof(GateHWSpinlock_Params));
189 }
191 /*
192 * Create a GateHWSpinlock instance
193 */
194 /* TODO: change the function to accept a local gate. Do this on all platforms */
195 GateHWSpinlock_Handle GateHWSpinlock_create(GateHWSpinlock_LocalProtect
196 localProtect, const GateHWSpinlock_Params * params)
197 {
198 GateHWSpinlock_Object * obj = (GateHWSpinlock_Object *)calloc(1,
199 sizeof (GateHWSpinlock_Object));
201 if (!obj) {
202 LOG0("GateHWSpinlock_create: memory allocation failure")
203 return NULL;
204 }
206 IGateProvider_ObjectInitializer(obj, GateHWSpinlock);
207 /* TODO: handle more local protection types */
208 obj->localGate = (IGateProvider_Handle)Mod->gmHandle;
209 obj->lockNum = params->resourceId;
210 obj->nested = 0;
212 return (GateHWSpinlock_Handle)obj;
213 }
215 /*
216 * Delete a GateHWSpinlock instance
217 */
218 Int GateHWSpinlock_delete (GateHWSpinlock_Handle * handle)
219 {
220 GateHWSpinlock_Object * obj;
221 Int status = GateHWSpinlock_S_SUCCESS;
223 if (handle == NULL) {
224 return GateHWSpinlock_E_INVALIDARG;
225 }
226 if (*handle == NULL) {
227 return GateHWSpinlock_E_INVALIDARG;
228 }
230 obj = (GateHWSpinlock_Object *)(*handle);
232 free(obj);
233 *handle = NULL;
235 return (status);
236 }
238 /*
239 * Enter a GateHWSpinlock instance
240 */
241 IArg GateHWSpinlock_enter(GateHWSpinlock_Object *obj)
242 {
243 volatile UInt32 *baseAddr = Mod->baseAddr;
244 IArg key;
246 key = IGateProvider_enter(obj->localGate);
248 /* if gate already entered, just return with current key */
249 obj->nested++;
250 if (obj->nested > 1) {
251 return(key);
252 }
254 /* enter the spinlock */
255 while (1) {
256 /* read the spinlock, returns non-zero when we get it */
257 if (baseAddr[obj->lockNum] == 0) {
258 break;
259 }
260 obj->nested--;
261 IGateProvider_leave(obj->localGate, key);
262 key = IGateProvider_enter(obj->localGate);
263 obj->nested++; /* re-nest the gate */
264 }
266 return (key);
267 }
269 /*
270 * Leave a GateHWSpinlock instance
271 */
272 Int GateHWSpinlock_leave(GateHWSpinlock_Object *obj, IArg key)
273 {
274 volatile UInt32 *baseAddr = Mod->baseAddr;
276 obj->nested--;
278 /* release the spinlock if not nested */
279 if (obj->nested == 0) {
280 baseAddr[obj->lockNum] = 0;
281 }
283 IGateProvider_leave(obj->localGate, key);
285 return GateHWSpinlock_S_SUCCESS;
286 }