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 * ======== Ipc.xdc ========
34 *
35 */
37 import xdc.runtime.Error;
38 import xdc.runtime.Assert;
39 import xdc.rov.ViewInfo;
40 import ti.sdo.utils.MultiProc;
42 /*!
43 * ======== Ipc ========
44 * IPC Master Manager
45 *
46 * @p(html)
47 * This module has a common header that can be found in the {@link ti.ipc}
48 * package. Application code should include the common header file (not the
49 * RTSC-generated one):
50 *
51 * <PRE>#include <ti/ipc/Ipc.h></PRE>
52 *
53 * The RTSC module must be used in the application's RTSC configuration file
54 * (.cfg):
55 *
56 * <PRE>Ipc = xdc.useModule('ti.sdo.ipc.Ipc');</PRE>
57 *
58 * Documentation for all runtime APIs, instance configuration parameters,
59 * error codes macros and type definitions available to the application
60 * integrator can be found in the
61 * <A HREF="../../../../doxygen/html/files.html">Doxygen documenation</A>
62 * for the IPC product. However, the documentation presented on this page
63 * should be referred to for information specific to the RTSC module, such as
64 * module configuration, Errors, and Asserts.
65 * @p
66 *
67 * The most common static configuration that is required of the Ipc module
68 * is the {@link #procSync} configuration that affects the behavior of the
69 * Ipc_start and Ipc_attach runtime APIs.
70 *
71 * Additionally, certain subsystems of IPC (such as Notify and MessageQ) can
72 * be disabled to save resources on a per-connection basis by configuring Ipc
73 * using {@link #setEntryMeta}.
74 *
75 */
77 @Template ("./Ipc.xdt")
78 module Ipc
79 {
80 /*!
81 * ======== ModuleView ========
82 * @_nodoc
83 */
84 metaonly struct ModuleView {
85 UInt16 remoteProcId;
86 Bool attached;
87 Bool setupNotify;
88 Bool setupMessageQ;
89 };
91 /*!
92 * ======== rovViewInfo ========
93 * @_nodoc
94 */
95 @Facet
96 metaonly config xdc.rov.ViewInfo.Instance rovViewInfo =
97 xdc.rov.ViewInfo.create({
98 viewMap: [
99 ['Module',
100 {
101 type: xdc.rov.ViewInfo.MODULE_DATA,
102 viewInitFxn: 'viewInitModule',
103 structName: 'ModuleView'
104 }
105 ],
106 ]
107 });
109 /*!
110 * Various configuration options for {@link #procSync}
111 *
112 * The values in this enum affect the behavior of the Ipc_start and
113 * Ipc_attach runtime APIs.
114 *
115 * ProcSync_ALL: Calling Ipc_start will also internally Ipc_attach to
116 * each remote processor. The application should never call Ipc_attach.
117 * This type of startup and synchronization should be used if all IPC
118 * processors on a device start up at the same time and connections should
119 * be established between every possible pair of processors.
120 *
121 * ProcSync_PAIR (default): Calling Ipc_start will perform system-wide IPC
122 * initialization required on all processor, but connections to remote
123 * processors will not be established (i.e. Ipc_attach will never be
124 * called). This configuration should be chosen if synchronization is
125 * required and some/all these conditions are true:
126 * @p(blist)
127 * - It is necessary to control when synchronization with each remote
128 * processor occurs
129 * - Useful work can be done while trying to synchronize with a remote
130 * processor by yielding a thread after each attempt to Ipc_attach
131 * to the processor.
132 * - Connections to all remote processors are unnecessary and connections
133 * should selectively be made to save memory
134 * @p
135 * NOTE: A connection should be made to the owner of region 0 (usually the
136 * processor with id = 0) before any connection to any other remote
137 * processor can be made. For example, if there are three processors
138 * configured with MultiProc, #1 should attach to #0 before it can attach
139 * to #2.
140 *
141 * ProcSync_NONE: This should be selected with caution. Ipc_start will
142 * work exactly as it does with ProcSync_PAIR. However, Ipc_attach will
143 * not synchronize with the remote processor. Callers of Ipc_attach are
144 * bound by the same restrictions imposed by using ProcSync_PAIR.
145 * Additionally, an Ipc_attach to a remote processor whose id is less than
146 * our own has to occur *after* the corresponding remote processor has
147 * called attach to the original processor. For example, processor #2
148 * can call
149 * @p(code)
150 * Ipc_attach(1);
151 * @p
152 * only after processor #1 has called:
153 * @p(code)
154 * Ipc_attach(2);
155 * @p
156 *
157 */
158 enum ProcSync {
159 ProcSync_NONE, /*! ProcSync_PAIR with no synchronization */
160 ProcSync_PAIR, /*! Ipc_start does not Ipc_attach */
161 ProcSync_ALL /*! Ipc_start attach to all remote procs */
162 };
164 /*!
165 * Struct used for configuration via {@link #setEntryMeta}
166 *
167 * This structure defines the fields that are to be configured
168 * between the executing processor and a remote processor.
169 */
170 struct Entry {
171 UInt16 remoteProcId; /*! Remote processor id */
172 Bool setupNotify; /*! Whether to setup Notify */
173 Bool setupMessageQ; /*! Whether to setup MessageQ */
174 };
176 /*! struct for attach/detach plugs. */
177 struct UserFxn {
178 Int (*attach)(UArg, UInt16);
179 Int (*detach)(UArg, UInt16);
180 };
182 /*
183 *************************************************************************
184 * Generic IPC Errors/Asserts
185 *************************************************************************
186 */
188 /*!
189 * ======== A_addrNotInSharedRegion ========
190 * Assert raised when an address lies outside all known shared regions
191 */
192 config Assert.Id A_addrNotInSharedRegion = {
193 msg: "A_addrNotInSharedRegion: Address not in any shared region"
194 };
196 /*!
197 * ======== A_addrNotCacheAligned ========
198 * Assert raised when an address is not cache-aligned
199 */
200 config Assert.Id A_addrNotCacheAligned = {
201 msg: "A_addrNotCacheAligned: Address is not cache aligned"
202 };
204 /*!
205 * ======== A_nullArgument ========
206 * Assert raised when a required argument is null
207 */
208 config Assert.Id A_nullArgument = {
209 msg: "A_nullArgument: Required argument is null"
210 };
212 /*!
213 * ======== A_nullPointer ========
214 * Assert raised when a pointer is null
215 */
216 config Assert.Id A_nullPointer = {
217 msg: "A_nullPointer: Pointer is null"
218 };
220 /*!
221 * ======== A_invArgument ========
222 * Assert raised when an argument is invalid
223 */
224 config Assert.Id A_invArgument = {
225 msg: "A_invArgument: Invalid argument supplied"
226 };
228 /*!
229 * ======== A_invParam ========
230 * Assert raised when a parameter is invalid
231 */
232 config Assert.Id A_invParam = {
233 msg: "A_invParam: Invalid configuration parameter supplied"
234 };
236 /*!
237 * ======== A_internal ========
238 * Assert raised when an internal error is encountered
239 */
240 config Assert.Id A_internal = {
241 msg: "A_internal: An internal error has occurred"
242 };
244 /*!
245 * ======== E_nameFailed ========
246 * Error raised when a name failed to be added to the NameServer
247 *
248 * Error raised in a create call when a name fails to be added
249 * to the NameServer table. This can be because the name already
250 * exists, the table has reached its max length, or out of memory.
251 */
252 config Error.Id E_nameFailed = {
253 msg: "E_nameFailed: '%s' name failed to be added to NameServer"
254 };
256 /*!
257 * ======== E_internal ========
258 * Error raised when an internal error occured
259 */
260 config Error.Id E_internal = {
261 msg: "E_internal: An internal error occurred"
262 };
264 /*!
265 * ======== E_versionMismatch ========
266 * Error raised when a version mismatch occurs
267 *
268 * Error raised in an open call because there is
269 * a version mismatch between the opener and the creator
270 */
271 config Error.Id E_versionMismatch = {
272 msg: "E_versionMismatch: IPC Module version mismatch: creator: %d, opener: %d"
273 };
275 /*
276 *************************************************************************
277 * Module-wide Config Parameters
278 *************************************************************************
279 */
281 /*!
282 * ======== sr0MemorySetup ========
283 * Whether Shared Region 0 memory is accessible
284 *
285 * Certain devices have a slave MMU that needs to be configured by the
286 * host core before the slave core can access shared region 0. If
287 * the host core is also running BIOS, it is necessary to set this
288 * configuration to 'true', otherwise {@link #start} will always fail.
289 *
290 * This configuration should not be used for devices that don't have
291 * a slave MMU and don't run Linux.
292 */
293 config Bool sr0MemorySetup;
295 /*! @_nodoc
296 * ======== hostProcId ========
297 * Host processor identifier.
298 *
299 * Used to specify the host processor's id. This parameter is only used
300 * in a Syslink system.
301 */
302 metaonly config UInt16 hostProcId = MultiProc.INVALIDID;
304 /*!
305 * ======== procSync ========
306 * Affects how Ipc_start and Ipc_attach behave
307 *
308 * Refer to the documentation for the {@link #ProcSync} enum for
309 * information about the various ProcSync options.
310 */
311 config ProcSync procSync = Ipc.ProcSync_PAIR;
313 /*! @_nodoc
314 * ======== generateSlaveDataForHost ========
315 * generates the slave's data into a section for the host.
316 */
317 config Bool generateSlaveDataForHost;
319 /*!@_nodoc
320 * ======== userFxn ========
321 * Attach and Detach hooks.
322 */
323 config UserFxn userFxn;
325 /*
326 *************************************************************************
327 * IPC Functions
328 *************************************************************************
329 */
331 /*!
332 * ======== addUserFxn ========
333 * Add a function that gets called during Ipc_attach/detach.
334 *
335 * The user added functions must be non-blocking and must run
336 * to completion. The functions need to check to make sure it
337 * is not called multiple times when more than one thread calls
338 * Ipc_attach() for the same processor. It is safe to use IPC
339 * APIs in a user function as long as the IPC APIs satisfy these
340 * requirements.
341 *
342 * @p(code)
343 * var Ipc = xdc.useModule('ti.sdo.ipc.Ipc');
344 * var fxn = new Ipc.UserFxn;
345 * fxn.attach = '&userAttachFxn';
346 * fxn.detach = '&userDetachFxn';
347 * Ipc.addUserFxn(fxn, arg);
348 * @p
349 *
350 * @param(fxn) The user function to call during attach/detach.
351 * @param(arg) The argument to the function.
352 */
353 metaonly Void addUserFxn(UserFxn fxn, UArg arg);
355 /*!
356 * ======== getEntry ========
357 * Gets the properties for attaching to a remote processor.
358 *
359 * This function must be called before Ipc_attach(). The
360 * parameter entry->remoteProcId field must be set prior to calling
361 * the function.
362 *
363 * @param(entry) Properties between a pair of processors.
364 */
365 Void getEntry(Entry *entry);
367 /*!
368 * ======== setEntryMeta ========
369 * Statically sets the properties for attaching to a remote processor.
370 *
371 * This function allows the user to configure whether Notify and/or
372 * MessageQ is setup during Ipc_attach(). If 'setupNotify' is set
373 * to 'false', neither the Notify or NameServerRemoteNotify instances
374 * are created. If 'setupMessageQ' is set to 'false', the MessageQ
375 * transport instances are not created. By default, both flags are
376 * set to 'true'.
377 *
378 * Note: For any pair of processors, the flags must be the same
379 *
380 * @param(entry) Properties between a pair of processors.
381 */
382 metaonly Void setEntryMeta(Entry entry);
384 /*!
385 * ======== setEntry ========
386 * Sets the properties for attaching to a remote processor.
387 *
388 * This function must be called before Ipc_attach(). It allows
389 * the user to configure whether Notify and/or MessageQ is setup
390 * during Ipc_attach(). If 'setupNotify' is set to 'FALSE',
391 * neither the Notify or NameServerRemoteNotify instances are
392 * created. If 'setupMessageQ' is set to 'FALSE', the MessageQ
393 * transport instances are not created. By default, both flags are
394 * set to 'TRUE'.
395 *
396 * Note: For any pair of processors, the flags must be the same
397 *
398 * @param(entry) Properties between a pair of processors.
399 */
400 Void setEntry(Entry *entry);
402 /*! @_nodoc
403 * This is needed to prevent the Ipc module from being optimized away
404 * during the whole_program[_debug] partial link.
405 */
406 Void dummy();
409 internal:
411 /* flag for starting processor synchronization */
412 const UInt32 PROCSYNCSTART = 1;
414 /* flag for finishing processor synchronization */
415 const UInt32 PROCSYNCFINISH = 2;
417 /* flag for detaching */
418 const UInt32 PROCSYNCDETACH = 3;
420 /* Type of Ipc object. Each value needs to be a power of two. */
421 enum ObjType {
422 ObjType_CREATESTATIC = 0x1,
423 ObjType_CREATESTATIC_REGION = 0x2,
424 ObjType_CREATEDYNAMIC = 0x4, /* Created by sharedAddr */
425 ObjType_CREATEDYNAMIC_REGION = 0x8, /* Created by regionId */
426 ObjType_OPENDYNAMIC = 0x10, /* Opened instance */
427 ObjType_LOCAL = 0x20 /* Local-only instance */
428 };
430 /*
431 * This structure captures Configuration details of a module/instance
432 * written by a slave to synchornize with a remote slave/HOST
433 */
434 struct ConfigEntry {
435 Bits32 remoteProcId;
436 Bits32 localProcId;
437 Bits32 tag;
438 Bits32 size;
439 Bits32 next;
440 };
442 struct ProcEntry {
443 SharedRegion.SRPtr *localConfigList;
444 SharedRegion.SRPtr *remoteConfigList;
445 UInt attached;
446 Entry entry;
447 };
449 /* The structure used for reserving memory in SharedRegion */
450 struct Reserved {
451 volatile Bits32 startedKey;
452 SharedRegion.SRPtr notifySRPtr;
453 SharedRegion.SRPtr nsrnSRPtr;
454 SharedRegion.SRPtr transportSRPtr;
455 SharedRegion.SRPtr configListHead;
456 };
458 /* The structure used for reserving memory in SharedRegion */
459 struct UserFxnAndArg {
460 UserFxn userFxn;
461 UArg arg;
462 };
464 /* Storage for setup of processors */
465 metaonly config Entry entry[];
467 config UInt numUserFxns = 0;
469 /*!
470 * ======== userFxns ========
471 * Attach and Detach hooks.
472 */
473 config UserFxnAndArg userFxns[] = [];
475 /*!
476 * ======== getMasterAddr() ========
477 */
478 Ptr getMasterAddr(UInt16 remoteProcId, Ptr sharedAddr);
480 /*!
481 * ======== getRegion0ReservedSize ========
482 * Returns the amount of memory to be reserved for Ipc in SharedRegion 0.
483 *
484 * This is used for synchronizing processors.
485 */
486 SizeT getRegion0ReservedSize();
488 /*!
489 * ======== getSlaveAddr() ========
490 */
491 Ptr getSlaveAddr(UInt16 remoteProcId, Ptr sharedAddr);
493 /*!
494 * ======== procSyncStart ========
495 * Starts the process of synchronizing processors.
496 *
497 * Shared memory in region 0 will be used. The processor which owns
498 * SharedRegion 0 writes its reserve memory address in region 0
499 * to let the other processors know it has started. It then spins
500 * until the other processors start. The other processors write their
501 * reserve memory address in region 0 to let the owner processor
502 * know they've started. The other processors then spin until the
503 * owner processor writes to let them know its finished the process
504 * of synchronization before continuing.
505 */
506 Int procSyncStart(UInt16 remoteProcId, Ptr sharedAddr);
508 /*!
509 * ======== procSyncFinish ========
510 * Finishes the process of synchronizing processors.
511 *
512 * Each processor writes its reserve memory address in SharedRegion 0
513 * to let the other processors know its finished the process of
514 * synchronization.
515 */
516 Int procSyncFinish(UInt16 remoteProcId, Ptr sharedAddr);
518 /*!
519 * ======== reservedSizePerProc ========
520 * The amount of memory required to be reserved per processor.
521 */
522 SizeT reservedSizePerProc();
524 /*! Used for populated the 'objType' field in ROV views*/
525 metaonly String getObjTypeStr$view(ObjType type);
527 /* Module state */
528 struct Module_State {
529 Ptr ipcSharedAddr;
530 Ptr gateMPSharedAddr;
531 ProcEntry procEntry[];
532 };
533 }