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 */
32 /*
33 * ======== GatePetersonN.c ========
34 */
36 #include <xdc/std.h>
37 #include <xdc/runtime/Error.h>
38 #include <xdc/runtime/Memory.h>
39 #include <xdc/runtime/Assert.h>
40 #include <xdc/runtime/IGateProvider.h>
41 #include <xdc/runtime/Gate.h>
42 #include <xdc/runtime/Log.h>
44 #include <ti/sdo/ipc/interfaces/IGateMPSupport.h>
46 #include <ti/sysbios/hal/Cache.h>
48 #include "package/internal/GatePetersonN.xdc.h"
50 #include <ti/sdo/ipc/_Ipc.h>
51 #include <ti/sdo/utils/_MultiProc.h>
52 #include <ti/sdo/ipc/_SharedRegion.h>
54 #define ROUND_UP(a, b) (SizeT)((((UInt32) a) + ((b) - 1)) & ~((b) - 1))
56 /*
57 *************************************************************************
58 * Instance functions
59 *************************************************************************
60 */
62 /*
63 * ======== GatePetersonN_Instance_init ========
64 */
65 Int GatePetersonN_Instance_init(GatePetersonN_Object *obj,
66 IGateProvider_Handle localGate,
67 const GatePetersonN_Params *params,
68 Error_Block *eb)
69 {
70 SizeT offset;
71 SizeT minAlign = Memory_getMaxDefaultTypeAlign();
72 SizeT i;
74 if (SharedRegion_getCacheLineSize(params->regionId) > minAlign) {
75 minAlign = SharedRegion_getCacheLineSize(params->regionId);
76 }
78 Assert_isTrue(params->sharedAddr != NULL, ti_sdo_ipc_Ipc_A_invParam);
79 Assert_isTrue(GatePetersonN_numInstances != NULL,ti_sdo_ipc_Ipc_A_invParam);
81 obj->localGate = localGate;
82 obj->cacheEnabled = SharedRegion_isCacheEnabled(params->regionId);
83 obj->cacheLineSize = SharedRegion_getCacheLineSize(params->regionId);
84 obj->nested = 0;
86 /* This is not cluster aware:
87 * obj->numProcessors = MultiProc_getNumProcessors();
88 * obj->selfId = MultiProc_self();
89 */
91 /* Cluster aware initialization */
92 obj->numProcessors = MultiProc_getNumProcsInCluster();
94 /* set selfId to 0-based offset within cluster. */
95 obj->selfId = MultiProc_self() - MultiProc_getBaseIdOfCluster();
97 /* Assign shared memory addresses for the protocol state variables */
99 offset = 0;
101 for (i=0; i < obj->numProcessors; i++) {
102 obj->enteredStage[i] = (Int32 *)((UArg)(params->sharedAddr) + offset);
103 offset += minAlign;
104 }
106 for (i=0; i < obj->numProcessors - 1; i++) {
107 obj->lastProcEnteringStage[i] = (Int32 *)((UArg)(params->sharedAddr)
108 + offset);
109 offset += minAlign;
110 }
112 if (!params->openFlag) {
113 /* Creating. */
114 obj->objType = ti_sdo_ipc_Ipc_ObjType_CREATEDYNAMIC;
115 GatePetersonN_postInit(obj);
116 }
117 else {
118 /* Opening. */
119 obj->objType = ti_sdo_ipc_Ipc_ObjType_OPENDYNAMIC;
120 }
122 return (0);
123 }
125 /*
126 * ======== GatePetersonN_Instance_finalize ========
127 */
128 Void GatePetersonN_Instance_finalize(GatePetersonN_Object *obj, Int status)
129 {
130 }
132 /*
133 * ======== GatePetersonN_enter ========
134 */
135 IArg GatePetersonN_enter(GatePetersonN_Object *obj)
136 {
137 IArg key;
138 SizeT numProcessors;
139 SizeT myProcId;
140 Int32 curStage;
141 SizeT proc;
143 /* Enter local gate */
144 key = IGateProvider_enter(obj->localGate);
146 /* If the gate object has already been entered, return the key */
147 obj->nested++;
148 if (obj->nested > 1) {
149 return (key);
150 }
151 numProcessors = obj->numProcessors;
152 myProcId = obj->selfId;
154 for (curStage=0; curStage < (numProcessors - 1); curStage++) {
156 *(obj->enteredStage[myProcId]) = curStage;
157 *(obj->lastProcEnteringStage[curStage]) = myProcId;
159 if (obj->cacheEnabled) {
161 Cache_wbInv((Ptr)obj->enteredStage[myProcId], obj->cacheLineSize,
162 Cache_Type_ALL, FALSE);
163 Cache_wbInv((Ptr)obj->lastProcEnteringStage[curStage],
164 obj->cacheLineSize, Cache_Type_ALL, TRUE);
165 }
167 for (proc=0; proc < numProcessors; proc++) {
169 if (proc != myProcId) {
171 if (obj->cacheEnabled) {
173 Cache_inv((Ptr)obj->enteredStage[proc],
174 obj->cacheLineSize, Cache_Type_ALL, FALSE);
175 Cache_inv((Ptr)obj->lastProcEnteringStage[curStage],
176 obj->cacheLineSize, Cache_Type_ALL, TRUE);
177 }
179 while ((*(obj->enteredStage[proc]) >= curStage) &&
180 (*(obj->lastProcEnteringStage[curStage]) == myProcId)) {
182 /* wait till 'proc' leaves or another 'proc' enters stage */
183 if (obj->cacheEnabled) {
185 Cache_inv((Ptr)obj->enteredStage[proc],
186 obj->cacheLineSize, Cache_Type_ALL, FALSE);
187 Cache_inv((Ptr)obj->lastProcEnteringStage[curStage],
188 obj->cacheLineSize, Cache_Type_ALL, TRUE);
189 }
190 }
191 }
192 }
194 } /* stages */
196 return (key);
197 }
199 /*
200 * ======== GatePetersonN_leave ========
201 */
202 Void GatePetersonN_leave(GatePetersonN_Object *obj, IArg key)
203 {
204 /* Release the resource and leave system gate. */
205 obj->nested--;
206 if (obj->nested == 0) {
208 *(obj->enteredStage[obj->selfId]) = GatePetersonN_NOT_INTERESTED;
210 if (obj->cacheEnabled) {
211 Cache_wbInv((Ptr)obj->enteredStage[obj->selfId], obj->cacheLineSize,
212 Cache_Type_ALL, TRUE);
213 }
214 }
216 /* Leave local gate */
217 IGateProvider_leave(obj->localGate, key);
218 }
220 /*
221 *************************************************************************
222 * Module functions
223 *************************************************************************
224 */
226 /*
227 * ======== GatePetersonN_getReservedMask ========
228 */
229 Bits32 *GatePetersonN_getReservedMask()
230 {
231 /* This gate doesn't allow reserving resources */
232 return (NULL);
233 }
235 /*
236 * ======== GatePetersonN_sharedMemReq ========
237 */
238 SizeT GatePetersonN_sharedMemReq(const IGateMPSupport_Params *params)
239 {
240 SizeT memReq;
241 UInt16 numProcessors = MultiProc_getNumProcsInCluster(); /* Cluster aware */
242 SizeT minAlign = Memory_getMaxDefaultTypeAlign();
244 if (SharedRegion_getCacheLineSize(params->regionId) > minAlign) {
245 minAlign = SharedRegion_getCacheLineSize(params->regionId);
246 }
248 /* Allocate aligned memory for shared state variables used in protocol
249 * enteredStage[NUM_PROCESSORS]
250 * lastProcEnteringStage[NUM_STAGES]
251 */
252 memReq = ((2 * numProcessors) - 1) *
253 SharedRegion_getCacheLineSize(params->regionId);
255 return(memReq);
256 }
258 /*
259 * ======== GatePetersonN_query ========
260 */
261 Bool GatePetersonN_query(Int qual)
262 {
263 Bool rc;
265 switch (qual) {
266 case IGateProvider_Q_BLOCKING:
267 /* GatePeterson is never blocking */
268 rc = FALSE;
269 break;
270 case IGateProvider_Q_PREEMPTING:
271 /* Depends on gate proxy? */
272 rc = TRUE;
273 break;
274 default:
275 rc = FALSE;
276 break;
277 }
279 return (rc);
280 }
282 /*
283 *************************************************************************
284 * Internal functions
285 *************************************************************************
286 */
287 /*
288 * ======== GatePetersonN_postInit ========
289 * Function to be called during
290 * 1. module startup to complete the initialization of all static instances
291 * 2. instance_init to complete the initialization of a dynamic instance
292 *
293 * Main purpose is to set up shared memory
294 */
295 Void GatePetersonN_postInit(GatePetersonN_Object *obj)
296 {
297 UInt16 i;
299 /* Set up shared memory */
300 for (i=0; i < obj->numProcessors; i++) {
301 *(obj->enteredStage[i]) = GatePetersonN_NOT_INTERESTED;
302 }
304 for (i=0; i < obj->numProcessors - 1; i++) {
305 *(obj->lastProcEnteringStage[i]) = 0;
306 }
308 /*
309 * Write everything back to shared memory.
310 */
311 if (obj->cacheEnabled) {
312 Cache_wbInv((Ptr)(obj->enteredStage[0]), obj->cacheLineSize *
313 obj->numProcessors, Cache_Type_ALL, FALSE);
314 Cache_wbInv((Ptr)(obj->lastProcEnteringStage[0]), obj->cacheLineSize *
315 obj->numProcessors-1, Cache_Type_ALL, TRUE);
316 }
317 }