1 /*
2 * Copyright (c) 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 */
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 <ti/syslink/inc/GateHWSpinlock.h>
46 #include <ti/syslink/utils/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 <ti/syslink/utils/GateMutex.h>
55 /* Module level headers */
56 #include <ti/syslink/utils/String.h>
58 #include <_IpcLog.h>
60 #include <assert.h>
61 #include <string.h>
62 #include <stdlib.h>
63 #include <sys/mman.h>
65 /*
66 * TODO: Hardcoding these for now. In daemon, we should ideally pass these in
67 * through config in GateHWSpinlock_setup and user lib can query the daemon.
68 */
69 #define HWSPINLOCK_BASE 0x4A0F6000
70 #define HWSPINLOCK_SIZE 0x1000
71 #define HWSPINLOCK_OFFSET 0x800
74 /* =============================================================================
75 * Structures & Enums
76 * =============================================================================
77 */
78 /* GateHWSpinlock Module Local State */
79 typedef struct {
80 UInt32 * baseAddr; /* base addr lock registers */
81 GateMutex_Handle gmHandle; /* handle to gate mutex */
82 } GateHWSpinlock_Module_State;
84 /* GateHWSpinlock instance object */
85 struct GateHWSpinlock_Object {
86 IGateProvider_SuperObject; /* For inheritance from IGateProvider */
87 UInt lockNum;
88 UInt nested;
89 IGateProvider_Handle localGate;
90 int token; /* HWSpinlock token */
91 };
94 /* =============================================================================
95 * Globals
96 * =============================================================================
97 */
98 static GateHWSpinlock_Module_State GateHWSpinlock_state =
99 {
100 .baseAddr = NULL,
101 .gmHandle = NULL
102 };
104 static GateHWSpinlock_Module_State *Mod = &GateHWSpinlock_state;
106 static GateHWSpinlock_Params GateHWSpinlock_defInstParams =
107 {
108 .resourceId = 0,
109 .openFlag = FALSE,
110 .regionId = 0,
111 .sharedAddr = NULL
112 };
114 static Bool verbose = FALSE;
116 /* =============================================================================
117 * APIS
118 * =============================================================================
119 */
120 /*
121 * Function to start the GateHWSpinlock module.
122 */
123 Int32 GateHWSpinlock_start(Void)
124 {
125 Int32 status = GateHWSpinlock_S_SUCCESS;
126 UInt32 dst;
128 /* map the hardware lock registers into the local address space */
129 if (status == GateHWSpinlock_S_SUCCESS) {
130 dst = (UInt32)mmap(NULL, HWSPINLOCK_SIZE,
131 (PROT_READ | PROT_WRITE | PROT_NOCACHE),
132 (MAP_PHYS|MAP_SHARED), NOFD,
133 (off_t)HWSPINLOCK_BASE);
135 if (dst == (UInt32)MAP_FAILED) {
136 PRINTVERBOSE0("GateHWSpinlock_start: Memory map failed")
137 status = GateHWSpinlock_E_OSFAILURE;
138 }
139 else {
140 Mod->baseAddr = (UInt32 *)(dst + HWSPINLOCK_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 PRINTVERBOSE0("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 *)HWSPINLOCK_BASE, HWSPINLOCK_SIZE);
174 }
176 return(status);
177 }
179 /*
180 * Initialize parameter structure
181 */
182 Void GateHWSpinlock_Params_init(GateHWSpinlock_Params *params)
183 {
184 assert(params != NULL);
186 memcpy(params, &GateHWSpinlock_defInstParams,
187 sizeof(GateHWSpinlock_Params));
188 }
190 /*
191 * Create a GateHWSpinlock instance
192 */
193 /* TODO: change the function to accept a local gate. Do this on all platforms */
194 GateHWSpinlock_Handle GateHWSpinlock_create(GateHWSpinlock_LocalProtect
195 localProtect, const GateHWSpinlock_Params * params)
196 {
197 GateHWSpinlock_Object * obj = (GateHWSpinlock_Object *)calloc(1,
198 sizeof (GateHWSpinlock_Object));
200 if (!obj) {
201 PRINTVERBOSE0("GateHWSpinlock_create: memory allocation failure")
202 return NULL;
203 }
205 IGateProvider_ObjectInitializer(obj, GateHWSpinlock);
206 /* TODO: handle more local protection types */
207 obj->localGate = (IGateProvider_Handle)Mod->gmHandle;
208 obj->lockNum = params->resourceId;
209 obj->nested = 0;
211 return (GateHWSpinlock_Handle)obj;
212 }
214 /*
215 * Delete a GateHWSpinlock instance
216 */
217 Int GateHWSpinlock_delete (GateHWSpinlock_Handle * handle)
218 {
219 GateHWSpinlock_Object * obj;
220 Int status = GateHWSpinlock_S_SUCCESS;
222 if (handle == NULL) {
223 return GateHWSpinlock_E_INVALIDARG;
224 }
225 if (*handle == NULL) {
226 return GateHWSpinlock_E_INVALIDARG;
227 }
229 obj = (GateHWSpinlock_Object *)(*handle);
231 free(obj);
232 *handle = NULL;
234 return (status);
235 }
237 /*
238 * Enter a GateHWSpinlock instance
239 */
240 IArg GateHWSpinlock_enter(GateHWSpinlock_Object *obj)
241 {
242 volatile UInt32 *baseAddr = Mod->baseAddr;
243 IArg key;
245 key = IGateProvider_enter(obj->localGate);
247 /* if gate already entered, just return with current key */
248 obj->nested++;
249 if (obj->nested > 1) {
250 return(key);
251 }
253 /* enter the spinlock */
254 while (1) {
255 /* read the spinlock, returns non-zero when we get it */
256 if (baseAddr[obj->lockNum] == 0) {
257 break;
258 }
259 obj->nested--;
260 IGateProvider_leave(obj->localGate, key);
261 key = IGateProvider_enter(obj->localGate);
262 obj->nested++; /* re-nest the gate */
263 }
265 return (key);
266 }
268 /*
269 * Leave a GateHWSpinlock instance
270 */
271 Int GateHWSpinlock_leave(GateHWSpinlock_Object *obj, IArg key)
272 {
273 volatile UInt32 *baseAddr = Mod->baseAddr;
275 obj->nested--;
277 /* release the spinlock if not nested */
278 if (obj->nested == 0) {
279 baseAddr[obj->lockNum] = 0;
280 }
282 IGateProvider_leave(obj->localGate, key);
284 return GateHWSpinlock_S_SUCCESS;
285 }