1 /*
2 * Copyright (c) 2008-2014, Texas Instruments Incorporated
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * * Neither the name of Texas Instruments Incorporated nor the names of
16 * its contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
33 /* ----------------------------------- Standard headers */
34 #include <ti/syslink/Std.h>
36 /* ----------------------------------- SysLink IPC module Headers */
37 #include <ti/ipc/Ipc.h>
38 #include <_Ipc.h>
39 #include <IpcKnl.h>
40 #include <Platform.h>
41 #include <Bitops.h>
42 #include <RscTable.h>
43 #include <_MessageQCopy.h>
44 #include <ti/ipc/MessageQCopy.h>
46 #if defined(SYSLINK_PLATFORM_VAYU)
47 #include <gptimers.h>
48 #endif
50 /* ----------------------------------- SysLink utils Headers */
51 #include <ti/syslink/inc/_MultiProc.h>
52 #include <ti/ipc/MultiProc.h>
53 #include <ti/syslink/utils/Gate.h>
54 #include <ti/syslink/utils/Trace.h>
55 #include <ti/syslink/utils/Cache.h>
56 #include <ti/syslink/utils/Memory.h>
58 #if defined(SYSLINK_USE_IPU_PM)
59 #include <ipu_pm.h>
60 #endif
62 #if defined (__cplusplus)
63 extern "C" {
64 #endif
67 /* =============================================================================
68 * Macros
69 * =============================================================================
70 */
71 /* Macro to make a correct module magic number with refCount */
72 #define Ipc_MAKE_MAGICSTAMP(x) ((SharedRegion_MODULEID << 16u) | (x))
75 /* =============================================================================
76 * Enums & Structures
77 * =============================================================================
78 */
80 /* The structure used for reserving memory in SharedRegion */
81 typedef struct Ipc_Reserved {
82 volatile Bits32 startedKey;
83 // SharedRegion_SRPtr ipu_pm_sr_ptr; //Ramesh: Port from WinCe.
84 } Ipc_Reserved;
87 /*!
88 * head of the config list
89 */
90 typedef struct Ipc_ConfigHead {
91 volatile Bits32 first;
92 /* Address of first config entry */
93 } Ipc_ConfigHead;
96 /*!
97 * This structure captures Configuration details of a module/instance
98 * written by a slave to synchornize with a remote slave/HOST
99 */
100 typedef struct Ipc_ConfigEntry {
101 volatile Bits32 remoteProcId;
102 /* Remote processor identifier */
103 volatile Bits32 localProcId;
104 /* Config Entry owner processor identifier */
105 volatile Bits32 tag;
106 /* Unique tag to distinguish config from other config entries */
107 volatile Bits32 size;
108 /* Size of the config pointer */
109 volatile Bits32 next;
110 /* Address of next config entry (In SRPtr format) */
111 } Ipc_ConfigEntry;
113 /*
114 * This structure defines the fields that are to be configured
115 * between the executing processor and a remote processor.
116 */
117 typedef struct Ipc_Entry {
118 UInt16 remoteProcId; /* the remote processor id */
119 Bool setup_ipu_pm; //Ramesh: port from WinCE
120 } Ipc_Entry;
122 /*!
123 * Ipc instance structure.
124 */
125 typedef struct Ipc_ProcEntry {
126 Ptr localConfigList;
127 Ptr remoteConfigList;
128 Ptr userObj;
129 Bool slave;
130 Ipc_Entry entry;
131 Bool isAttached;
132 } Ipc_ProcEntry;
135 /*!
136 * Module state structure
137 */
138 typedef struct Ipc_Module_State {
139 Int32 refCount;
140 Ipc_Config cfg;
141 Ipc_ProcEntry procEntry [MultiProc_MAXPROCESSORS];
142 } Ipc_Module_State;
145 /* =============================================================================
146 * Globals
147 * =============================================================================
148 */
149 static Ipc_Module_State Ipc_module_state = {
150 .refCount = 0,
151 };
152 static Ipc_Module_State * Ipc_module = &Ipc_module_state;
155 /* =============================================================================
156 * APIs
157 * =============================================================================
158 */
160 /* attaches to a remote processor */
161 Int Ipc_attach (UInt16 remoteProcId)
162 {
163 Int status = 0;
164 IArg key;
165 UInt32 numVrings = 0;
166 UInt32 vringAddr = 0;
167 ProcMgr_Handle procHandle = NULL;
169 GT_1trace (curTrace, GT_ENTER, "Ipc_attach", remoteProcId);
171 GT_assert(curTrace,remoteProcId < MultiProc_INVALIDID);
172 GT_assert(curTrace,remoteProcId != MultiProc_self());
174 key = Gate_enterSystem ();
175 /* Make sure its not already attached */
176 if (Ipc_module->procEntry[remoteProcId].isAttached) {
177 Ipc_module->procEntry[remoteProcId].isAttached++;
178 Gate_leaveSystem (key);
179 status = Ipc_S_ALREADYSETUP;
180 }
181 else {
182 Gate_leaveSystem (key);
184 status = ProcMgr_open(&procHandle, remoteProcId);
185 if (status >= 0) {
186 /* get IPC VRING information */
187 status = RscTable_getInfo(remoteProcId, TYPE_VDEV, 0, NULL,
188 NULL, &numVrings);
189 if (status >= 0) {
190 status = RscTable_getInfo(remoteProcId, TYPE_VDEV, 1,
191 &vringAddr, NULL, NULL);
192 if (status >= 0) {
193 status = MessageQCopy_attach(remoteProcId,
194 (Ptr)vringAddr, 0);
195 if (status >= 0) {
196 status = RscTable_setStatus(remoteProcId, 7);
197 }
198 }
199 }
201 if (status >= 0) {
202 /* flush the resource table to device memory */
203 status = RscTable_update(remoteProcId, procHandle);
204 }
205 ProcMgr_close(&procHandle);
206 }
208 #if defined(SYSLINK_USE_IPU_PM) && defined(SYSLINK_PLATFORM_OMAP5430)
209 if (status >= 0) {
210 status = ipu_pm_attach(remoteProcId);
211 if (status < 0) {
212 MessageQCopy_detach(remoteProcId);
213 }
214 }
215 #endif
217 #if !defined(IPC_DISABLE_WATCHDOG) && defined(SYSLINK_PLATFORM_VAYU)
218 if (status >= 0) {
219 status = gpt_wdt_attach(remoteProcId);
220 if (status < 0) {
221 MessageQCopy_detach(remoteProcId);
222 }
223 }
224 #endif
226 if (status >= 0) {
227 key = Gate_enterSystem ();
228 Ipc_module->procEntry[remoteProcId].isAttached++;
229 Gate_leaveSystem (key);
230 }
231 }
232 GT_1trace (curTrace, GT_LEAVE, "Ipc_attach", status);
234 return (status);
235 }
238 /* detaches from a remote processor */
239 Int Ipc_detach (UInt16 remoteProcId)
240 {
241 Int status = 0;
242 IArg key;
243 GT_1trace (curTrace, GT_ENTER, "Ipc_detach", remoteProcId);
245 key = Gate_enterSystem ();
246 if (Ipc_module->procEntry[remoteProcId].isAttached > 1) {
247 /* Only detach if attach count reaches 1 */
248 Ipc_module->procEntry[remoteProcId].isAttached--;
249 Gate_leaveSystem (key);
250 status = Ipc_S_BUSY;
251 }
252 else if (Ipc_module->procEntry[remoteProcId].isAttached == 0) {
253 /* If already detached, then return fail */
254 Gate_leaveSystem (key);
255 status = Ipc_E_FAIL;
256 }
257 else {
258 Gate_leaveSystem (key);
260 #if defined(SYSLINK_USE_IPU_PM) && defined(SYSLINK_PLATFORM_OMAP5430)
261 status = ipu_pm_detach (remoteProcId);
262 #endif
264 #if !defined(IPC_DISABLE_WATCHDOG) && defined(SYSLINK_PLATFORM_VAYU)
265 status = gpt_wdt_detach(remoteProcId);
266 #endif
268 status = MessageQCopy_detach (remoteProcId);
270 key = Gate_enterSystem ();
271 Ipc_module->procEntry[remoteProcId].isAttached--;
272 Gate_leaveSystem (key);
273 }
275 GT_1trace (curTrace, GT_LEAVE, "Ipc_detach", status);
277 return (status);
278 }
280 /*
281 * ======== Ipc_getConfig ========
282 */
283 Void Ipc_getConfig (Ipc_Config * cfgParams)
284 {
285 IArg key;
287 GT_1trace (curTrace, GT_ENTER, "Ipc_getConfig", cfgParams);
289 GT_assert (curTrace, (cfgParams != NULL));
291 #if !defined(SYSLINK_BUILD_OPTIMIZE)
292 if (cfgParams == NULL) {
293 /* No retVal since this is a Void function. */
294 GT_setFailureReason (curTrace,
295 GT_4CLASS,
296 "Ipc_getConfig",
297 Ipc_E_INVALIDARG,
298 "Argument of type (Ipc_Config *) passed "
299 "is null!");
300 }
301 else {
302 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
303 key = Gate_enterSystem ();
304 if (Ipc_module->refCount != 0) {
305 Memory_copy ((Ptr) cfgParams,
306 (Ptr) &Ipc_module->cfg,
307 sizeof (Ipc_Config));
308 }
309 Gate_leaveSystem (key);
310 #if !defined(SYSLINK_BUILD_OPTIMIZE)
311 }
312 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
314 GT_0trace (curTrace, GT_LEAVE, "Ipc_getConfig");
315 }
318 /* Sets up Ipc for this processor. */
319 Int Ipc_setup (const Ipc_Config * cfg)
320 {
321 Int status = Ipc_S_SUCCESS;
322 Ipc_Config tmpCfg;
323 IArg key;
324 Int i;
326 GT_1trace (curTrace, GT_ENTER, "Ipc_setup", cfg);
328 key = Gate_enterSystem ();
329 Ipc_module->refCount++;
331 /* This sets the refCount variable is not initialized, upper 16 bits is
332 * written with module Id to ensure correctness of refCount variable.
333 */
334 if (Ipc_module->refCount > 1) {
335 status = Ipc_S_ALREADYSETUP;
336 GT_0trace (curTrace,
337 GT_2CLASS,
338 "Ipc Module already initialized!");
339 Gate_leaveSystem (key);
340 }
341 else {
342 Gate_leaveSystem (key);
343 if (cfg == NULL) {
344 Ipc_getConfig (&tmpCfg);
345 cfg = &tmpCfg;
346 }
348 /* Copy the cfg */
349 Memory_copy ((Ptr) &Ipc_module->cfg,
350 (Ptr) cfg,
351 sizeof (Ipc_Config));
353 status = Platform_setup ((Ipc_Config *)cfg);
354 if (status < 0) {
355 key = Gate_enterSystem ();
356 Ipc_module->refCount--;
357 Gate_leaveSystem (key);
358 status = Ipc_E_FAIL;
359 GT_setFailureReason (curTrace,
360 GT_4CLASS,
361 "Ipc_setup",
362 status,
363 "Platform_setup failed!");
364 }
366 /* Following can be done regardless of status */
367 for (i = 0; i < MultiProc_getNumProcessors (); i++) {
368 Ipc_module->procEntry [i].isAttached = FALSE;
369 }
370 }
372 GT_1trace (curTrace, GT_LEAVE, "Ipc_setup", status);
374 /*! @retval Ipc_S_SUCCESS Operation successful */
375 return status;
376 }
379 /* Destroys Ipc for this processor. */
380 Int
381 Ipc_destroy (Void)
382 {
383 Int status = Ipc_S_SUCCESS;
384 IArg key;
386 GT_0trace (curTrace, GT_ENTER, "Ipc_destroy");
388 key = Gate_enterSystem ();
389 Ipc_module->refCount--;
390 #if !defined(SYSLINK_BUILD_OPTIMIZE)
391 if (Ipc_module->refCount < 0) {
392 Gate_leaveSystem (key);
393 /*! @retval Ipc_E_INVALIDSTATE Module was not initialized */
394 status = Ipc_E_INVALIDSTATE;
395 GT_setFailureReason (curTrace,
396 GT_4CLASS,
397 "Ipc_destroy",
398 status,
399 "Module was not initialized!");
400 }
401 else {
402 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
403 if (Ipc_module->refCount == 0) {
404 Gate_leaveSystem (key);
405 status = Platform_destroy ();
406 if (status < 0) {
407 status = Ipc_E_FAIL;
408 GT_setFailureReason (curTrace,
409 GT_4CLASS,
410 "Ipc_destroy",
411 status,
412 "Platform_destroy failed!");
413 }
414 }
415 else {
416 Gate_leaveSystem (key);
417 }
418 #if !defined(SYSLINK_BUILD_OPTIMIZE)
419 }
420 #endif /* if !defined(SYSLINK_BUILD_OPTIMIZE) */
422 GT_1trace (curTrace, GT_LEAVE, "Ipc_destroy", status);
424 /*! @retval Ipc_S_SUCCESS Operation successful */
425 return status;
426 }
429 #if defined (__cplusplus)
430 }
431 #endif /* defined (__cplusplus) */