1 /*
2 * Copyright (c) 2012-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 * ======== GatePeterson.c ========
34 */
36 #include <xdc/std.h>
37 #include <xdc/runtime/Error.h>
38 #include <xdc/runtime/Assert.h>
39 #include <xdc/runtime/IGateProvider.h>
40 #include <xdc/runtime/Gate.h>
41 #include <xdc/runtime/Log.h>
43 #include <ti/sdo/ipc/interfaces/IGateMPSupport.h>
45 #include <ti/sysbios/hal/Cache.h>
47 #include "package/internal/GatePeterson.xdc.h"
49 #include <ti/sdo/ipc/_Ipc.h>
50 #include <ti/sdo/utils/_MultiProc.h>
51 #include <ti/sdo/ipc/_SharedRegion.h>
53 /*
54 *************************************************************************
55 * Instance functions
56 *************************************************************************
57 */
59 /*
60 * ======== GatePeterson_Instance_init ========
61 */
62 Int GatePeterson_Instance_init(GatePeterson_Object *obj,
63 IGateProvider_Handle localGate,
64 const GatePeterson_Params *params,
65 Error_Block *eb)
66 {
67 Assert_isTrue(params->sharedAddr != NULL, ti_sdo_ipc_Ipc_A_invParam);
68 Assert_isTrue(GatePeterson_numInstances != NULL, ti_sdo_ipc_Ipc_A_invParam);
70 obj->localGate = localGate;
71 obj->cacheEnabled = SharedRegion_isCacheEnabled(params->regionId);
72 obj->cacheLineSize = SharedRegion_getCacheLineSize(params->regionId);
74 /* Settings for both the creator and opener */
75 if (obj->cacheLineSize > sizeof(GatePeterson_Attrs)) {
76 obj->attrs = params->sharedAddr;
77 obj->flag[0] = (Bits16 *)((UArg)(obj->attrs) + obj->cacheLineSize);
78 obj->flag[1] = (Bits16 *)((UArg)(obj->flag[0]) + obj->cacheLineSize);
79 obj->turn = (Bits16 *)((UArg)(obj->flag[1]) + obj->cacheLineSize);
80 }
81 else {
82 obj->attrs = params->sharedAddr;
83 obj->flag[0] = (Bits16 *)((UArg)(obj->attrs) +
84 sizeof(GatePeterson_Attrs));
85 obj->flag[1] = (Bits16 *)((UArg)(obj->flag[0]) + sizeof(Bits16));
86 obj->turn = (Bits16 *)((UArg)(obj->flag[1]) + sizeof(Bits16));
87 }
88 obj->nested = 0;
90 if (!params->openFlag) {
91 /* Creating. */
92 obj->selfId = 0;
93 obj->otherId = 1;
94 obj->objType = ti_sdo_ipc_Ipc_ObjType_CREATEDYNAMIC;
95 GatePeterson_postInit(obj);
96 }
97 else {
98 /* Opening. */
99 obj->objType = ti_sdo_ipc_Ipc_ObjType_OPENDYNAMIC;
101 Cache_inv((Ptr)obj->attrs, sizeof(GatePeterson_Attrs), Cache_Type_ALL,
102 TRUE);
104 if (obj->attrs->creatorProcId == MultiProc_self()) {
105 /* Opening locally */
106 obj->selfId = 0;
107 obj->otherId = 1;
108 }
109 else {
110 /* Trying to open a gate remotely */
111 obj->selfId = 1;
112 obj->otherId = 0;
113 if (obj->attrs->openerProcId == MultiProc_INVALIDID) {
114 /* Opening remotely for the first time */
115 obj->attrs->openerProcId = MultiProc_self();
116 }
117 else if (obj->attrs->openerProcId != MultiProc_self()) {
118 Error_raise(eb, GatePeterson_E_gateRemotelyOpened,
119 obj->attrs->creatorProcId,
120 obj->attrs->openerProcId);
121 }
123 if (obj->cacheEnabled) {
124 Cache_wbInv((Ptr)obj->attrs, sizeof(GatePeterson_Attrs),
125 Cache_Type_ALL, TRUE);
126 }
127 }
128 }
130 return (0);
131 }
133 /*
134 * ======== GatePeterson_Instance_finalize ========
135 */
136 Void GatePeterson_Instance_finalize(GatePeterson_Object *obj, Int status)
137 {
138 if (!status) {
139 /* Modify shared memory */
140 if (obj->objType == ti_sdo_ipc_Ipc_ObjType_OPENDYNAMIC) {
141 obj->attrs->openerProcId = MultiProc_INVALIDID;
142 Cache_wbInv(obj->attrs, sizeof(GatePeterson_Attrs), Cache_Type_ALL,
143 TRUE);
144 }
145 }
146 }
148 /*
149 * ======== GatePeterson_enter ========
150 */
151 IArg GatePeterson_enter(GatePeterson_Object *obj)
152 {
153 IArg key;
155 /* Enter local gate */
156 key = IGateProvider_enter(obj->localGate);
158 /* If the gate object has already been entered, return the key */
159 obj->nested++;
160 if (obj->nested > 1) {
161 return (key);
162 }
164 /* Indicate that we need to use the resource. */
165 *(obj->flag[obj->selfId]) = GatePeterson_BUSY ;
166 if (obj->cacheEnabled) {
167 Cache_wbInv((Ptr)obj->flag[obj->selfId], obj->cacheLineSize,
168 Cache_Type_ALL, TRUE);
169 }
171 /* Give away the turn. */
172 *(obj->turn) = obj->otherId;
174 if (obj->cacheEnabled) {
175 Cache_wbInv((Ptr)obj->turn, obj->cacheLineSize, Cache_Type_ALL, TRUE);
176 Cache_inv((Ptr)obj->flag[obj->otherId], obj->cacheLineSize,
177 Cache_Type_ALL, TRUE);
178 }
180 /* Wait while other process is using the resource and has the turn. */
181 while ((*(obj->flag[obj->otherId]) == GatePeterson_BUSY) &&
182 (*(obj->turn) == obj->otherId)) {
183 if (obj->cacheEnabled) {
184 Cache_inv((Ptr)obj->flag[obj->otherId], obj->cacheLineSize,
185 Cache_Type_ALL, FALSE);
186 Cache_inv((Ptr)obj->turn, obj->cacheLineSize, Cache_Type_ALL, TRUE);
187 }
188 }
190 return (key);
191 }
193 /*
194 * ======== GatePeterson_leave ========
195 */
196 Void GatePeterson_leave(GatePeterson_Object *obj, IArg key)
197 {
198 /* Release the resource and leave system gate. */
199 obj->nested--;
200 if (obj->nested == 0) {
201 *(obj->flag[obj->selfId]) = GatePeterson_FREE;
202 if (obj->cacheEnabled) {
203 Cache_wbInv((Ptr)obj->flag[obj->selfId], obj->cacheLineSize,
204 Cache_Type_ALL, TRUE);
205 }
206 }
208 /* Leave local gate */
209 IGateProvider_leave(obj->localGate, key);
210 }
212 /*
213 *************************************************************************
214 * Module functions
215 *************************************************************************
216 */
218 /*
219 * ======== GatePeterson_getReservedMask ========
220 */
221 Bits32 *GatePeterson_getReservedMask()
222 {
223 /* This gate doesn't allow reserving resources */
224 return (NULL);
225 }
227 /*
228 * ======== GatePeterson_sharedMemReq ========
229 */
230 SizeT GatePeterson_sharedMemReq(const IGateMPSupport_Params *params)
231 {
232 SizeT memReq;
234 if (SharedRegion_getCacheLineSize(params->regionId) >=
235 sizeof(GatePeterson_Attrs)) {
236 /*! 4 Because shared of shared memory usage (see GatePeterson.xdc) */
237 memReq = 4 * SharedRegion_getCacheLineSize(params->regionId);
238 }
239 else {
240 memReq = sizeof(GatePeterson_Attrs) + sizeof(Bits16) * 3;
241 }
243 return(memReq);
244 }
246 /*
247 * ======== GatePeterson_query ========
248 */
249 Bool GatePeterson_query(Int qual)
250 {
251 Bool rc;
253 switch (qual) {
254 case IGateProvider_Q_BLOCKING:
255 /* GatePeterson is never blocking */
256 rc = FALSE;
257 break;
258 case IGateProvider_Q_PREEMPTING:
259 /* Depends on gate proxy? */
260 rc = TRUE;
261 break;
262 default:
263 rc = FALSE;
264 break;
265 }
267 return (rc);
268 }
270 /*
271 *************************************************************************
272 * Internal functions
273 *************************************************************************
274 */
275 /*
276 * ======== GatePeterson_postInit ========
277 * Function to be called during
278 * 1. module startup to complete the initialization of all static instances
279 * 2. instance_init to complete the initialization of a dynamic instance
280 *
281 * Main purpose is to set up shared memory
282 */
283 Void GatePeterson_postInit(GatePeterson_Object *obj)
284 {
285 /* Set up shared memory */
286 *(obj->turn) = 0;
287 *(obj->flag[0]) = 0;
288 *(obj->flag[1]) = 0;
289 obj->attrs->creatorProcId = MultiProc_self();
290 obj->attrs->openerProcId = MultiProc_INVALIDID;
292 /*
293 * Write everything back to memory. This assumes that obj->attrs is equal
294 * to the shared memory base address
295 */
296 if (obj->cacheEnabled) {
297 Cache_wbInv((Ptr)obj->attrs, sizeof(GatePeterson_Attrs), Cache_Type_ALL,
298 FALSE);
299 Cache_wbInv((Ptr)(obj->flag[0]), obj->cacheLineSize * 3, Cache_Type_ALL,
300 TRUE);
301 }
302 }