1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
32 33 34 35
36
37 package ti.sdo.ipc;
38
39 import xdc.runtime.IHeap;
40 import xdc.runtime.Assert;
41 import xdc.runtime.Error;
42 import xdc.runtime.Diags;
43 import xdc.runtime.Log;
44 import xdc.runtime.IGateProvider;
45 import xdc.runtime.knl.ISync;
46
47 import ti.sysbios.syncs.SyncSem;
48
49 import ti.sdo.ipc.interfaces.IMessageQTransport;
50 import ti.sdo.utils.NameServer;
51 import ti.sdo.utils.List;
52
53 import xdc.rov.ViewInfo;
54
55 /*!
56 * ======== MessageQ ========
57 * Message-passing with queuing
58 *
59 * The MessageQ module supports the structured sending and receiving of
60 * variable length messages. This module can be used for homogeneous
61 * (DSP to DSP) or heterogeneous (Arm to DSP) multi-processor messaging.
62 *
63 * MessageQ provides more sophisticated messaging than other modules. It is
64 * typically used for complex situations such as multi-processor messaging.
65 *
66 * The following are key features of the MessageQ module:
67 * @p(blist)
68 * -Writers and readers can be relocated to another processor with no
69 * runtime code changes.
70 * -Timeouts are allowed when receiving messages.
71 * -Readers can determine the writer and reply back.
72 * -Receiving a message is deterministic when the timeout is zero.
73 * -Messages can reside on any message queue.
74 * -Supports zero-copy transfers.
75 * -Can send and receive from any type of thread.
76 * -Notification mechanism is specified by application.
77 * -Allows QoS (quality of service) on message buffer pools. For example,
78 * using specific buffer pools for specific message queues.
79 * @p
80 *
81 * Messages are sent and received by being placed on and removed from a
82 * message queue. A reader is a thread that gets (reads) messages from a
83 * message queue. A writer is a thread that puts (writes) a message to a
84 * message queue. Each message queue has one reader and can have many writers.
85 * A thread may read from or write to multiple message queues.
86 *
87 * Conceptually, the reader thread owns a message queue. The reader thread
88 * creates a message queue. The writer threads open a created message queue
89 * to get access to them.
90 *
91 * Message queues are identified by a system-wide unique name. Internally,
92 * MessageQ uses the {@link ti.sdo.utils.NameServer} module for managing
93 * these names. The names are used for opening a message queue.
94 *
95 * Messages must be allocated from the MessageQ module. Once a message is
96 * allocated, it can be sent to any message queue. Once a message is sent, the
97 * writer loses ownership of the message and should not attempt to modify the
98 * message. Once the reader receives the message, it owns the message. It
99 * may either free the message or re-use the message.
100 *
101 * Messages in a message queue can be of variable length. The only
102 * requirement is that the first field in the definition of a message must be a
103 * {@link #MsgHeader} structure. For example:
104 * @p(code)
105 * typedef struct MyMsg {
106 * MessageQ_MsgHeader header;
107 * ...
108 * } MyMsg;
109 * @p
110 *
111 * The MessageQ API uses the MessageQ_MsgHeader internally. Your application
112 * should not modify or directly access the fields in the MessageQ_MsgHeader.
113 *
114 * All messages sent via the MessageQ module must be allocated from a
115 * {@link xdc.runtime.IHeap} implementation. The heap can also be used for
116 * other memory allocation not related to MessageQ.
117 *
118 * An application can use multiple heaps. The purpose of having multiple
119 * heaps is to allow an application to regulate its message usage. For
120 * example, an application can allocate critical messages from one heap of fast
121 * on-chip memory and non-critical messages from another heap of slower
122 * external memory.
123 *
124 * The {@link #registerHeap} and {@link #registerHeapMeta} are APIs used to
125 * assign a MessageQ heapId to a heap. When allocating a message, the heapId
126 * is used, not the heap handle. This heapId is actually placed into the
127 * message (part of the {@link #MsgHeader}). Care must be taken when assigning
128 * heapIds. Refer to the {@link #registerHeap} and {@link #registerHeapMeta}
129 * descriptions for more details.
130 *
131 * MessageQ also supports the usage of messages that are not allocated via the
132 * {@link #alloc} function. Please refer to the {@link #staticMsgInit}
133 * function description for more details.
134 *
135 * MessageQ supports reads/writes of different thread models. This is
136 * accomplished by having the creator of the message queue specify a
137 * {@link xdc.runtime.knl.ISync#Object} via the {@link #synchronizer}
138 * configuration parameter. The {@link xdc.runtime.knl.ISync#signal}
139 * portion of the ISync instance is called whenever the {@link #put}
140 * is called. The {@link xdc.runtime.knl.ISync#wait} portion is
141 * called in the {@link #get} if and only if there are no messages.
142 *
143 * Since ISyncs are binary, the reader must drain the message queue of all
144 * messages before waiting for another signal. For example, if the reader
145 * was a SYSBIOS Swi, the {@link xdc.runtime.knl.ISync} instance
146 * could be a SyncSwi. If a {@link #put} was called, the Swi_post() would
147 * be called. The Swi would run and it must call {@link #get} until no
148 * messages are returned.
149 *
150 * In a multiple processor system, MessageQ communicates to other
151 * processors via {@link ti.sdo.ipc.interfaces.IMessageQTransport} instances.
152 * MessageQ supports a high priority and a normal priority transport between
153 * any two processors. The IMessageQTransport instances are created via the
154 * {@link #SetupTransportProxy}. The instances are responsible for
155 * registering themselves with MessageQ. This is accomplished via the
156 * {@link #registerTransport} function.
157 */
158
159 @ModuleStartup
160 @InstanceInitError
161 @InstanceFinalize
162
163 module MessageQ
164 {
165 /*!
166 * ======== QueuesView ========
167 * @_nodoc
168 */
169 metaonly struct QueuesView {
170 String name;
171 UInt queueId;
172 }
173
174 /*!
175 * ======== MessagesView ========
176 * @_nodoc
177 */
178 metaonly struct MessagesView {
179 Int seqNum;
180 Int msgSize;
181 String priority;
182 String srcProc;
183 String replyProc;
184 String replyId;
185 Int msgId;
186 String heap;
187 Bool traceEnabled;
188 Int version;
189 }
190
191 /*!
192 * ======== ModuleView ========
193 * @_nodoc
194 */
195 metaonly struct ModuleView {
196 String heaps[];
197 String gate;
198 UInt16 nextSeqNum;
199 String freeHookFxn[];
200 }
201
202 /*!
203 * ======== rovViewInfo ========
204 * @_nodoc
205 */
206 @Facet
207 metaonly config xdc.rov.ViewInfo.Instance rovViewInfo =
208 xdc.rov.ViewInfo.create({
209 viewMap: [
210 ['Queues',
211 {
212 type: xdc.rov.ViewInfo.INSTANCE,
213 viewInitFxn: 'viewInitQueues',
214 structName: 'QueuesView'
215 }
216 ],
217 ['Messages',
218 {
219 type: xdc.rov.ViewInfo.INSTANCE_DATA,
220 viewInitFxn: 'viewInitMessages',
221 structName: 'MessagesView'
222 }
223 ],
224 ['Module',
225 {
226 type: xdc.rov.ViewInfo.MODULE,
227 viewInitFxn: 'viewInitModule',
228 structName: 'ModuleView'
229 }
230 ]
231 ]
232 });
233
234 /*!
235 * ======== LM_setTrace ========
236 * Logged when setting the trace flag on a message
237 *
238 * This is logged when tracing on a message is set via
239 * {@link #setMsgTrace}.
240 */
241 config Log.Event LM_setTrace = {
242 mask: Diags.USER1,
243 msg: "LM_setTrace: Message 0x%x (seqNum = %d, srcProc = %d) traceFlag = %d"
244 };
245
246 /*!
247 * ======== LM_alloc ========
248 * Logged when allocating a message
249 *
250 * When the {@link #traceFlag} is true, all message allocations
251 * are logged.
252 */
253 config Log.Event LM_alloc = {
254 mask: Diags.USER1,
255 msg: "LM_alloc: Message 0x%x (seqNum = %d, srcProc = %d) was allocated"
256 };
257
258 /*!
259 * ======== LM_staticMsgInit ========
260 * Logged when statically initializing a message
261 *
262 * When the {@link #traceFlag} is true, all messages that
263 * are statically initialized via {@link #staticMsgInit} are logged.
264 */
265 config Log.Event LM_staticMsgInit = {
266 mask: Diags.USER1,
267 msg: "LM_staticMsgInit: Message 0x%x (seqNum = %d, srcProc = %d) was set in MessageQ_staticMsgInit"
268 };
269
270 /*!
271 * ======== LM_free ========
272 * Logged when freeing a message
273 *
274 * When the {@link #traceFlag} is true, all freeing of messages
275 * are logged. If an individual message's tracing was enabled
276 * via {@link #setMsgTrace}, the MessageQ_free is also logged.
277 */
278 config Log.Event LM_free = {
279 mask: Diags.USER1,
280 msg: "LM_free: Message 0x%x (seqNum = %d, srcProc = %d) was freed"
281 };
282
283 /*!
284 * ======== LM_putLocal ========
285 * Logged when a message is placed onto a local queue
286 *
287 * When the {@link #traceFlag} is true, all putting of messages
288 * are logged. If an individual message's tracing was enabled
289 * via {@link #setMsgTrace}, the MessageQ_put is also logged.
290 */
291 config Log.Event LM_putLocal = {
292 mask: Diags.USER1,
293 msg: "LM_putLocal: Message 0x%x (seqNum = %d, srcProc = %d) was placed onto queue 0x%x"
294 };
295
296 /*!
297 * ======== LM_putRemote ========
298 * Logged when a message is given to a transport
299 *
300 * When the {@link #traceFlag} is true, all putting of messages
301 * to a transport are logged. If an individual message's tracing
302 * was enabled via {@link #setMsgTrace}, the MessageQ_put is
303 * also logged.
304 */
305 config Log.Event LM_putRemote = {
306 mask: Diags.USER1,
307 msg: "LM_putRemote: Message 0x%x (seqNum = %d, srcProc = %d) was given to processor %d transport"
308 };
309
310 /*!
311 * ======== LM_rcvByTransport ========
312 * Logged when a transport receives an incoming message
313 *
314 * When the {@link #traceFlag} is true, all incoming messages
315 * are logged. If an individual message's tracing
316 * was enabled via {@link #setMsgTrace}, the receiving of a message is
317 * also logged.
318 */
319 config Log.Event LM_rcvByTransport = {
320 mask: Diags.USER1,
321 msg: "LM_rcvByTransport: Message 0x%x (seqNum = %d, srcProc = %d) was received"
322 };
323
324 /*!
325 * ======== LM_get ========
326 * Logged when a message is received off the queue
327 *
328 * When the {@link #traceFlag} is true, all getting of messages
329 * are logged. If an individual message's tracing
330 * was enabled via {@link #setMsgTrace}, the MessageQ_get is
331 * also logged.
332 */
333 config Log.Event LM_get = {
334 mask: Diags.USER1,
335 msg: "LM_get: Message 0x%x (seqNum = %d, srcProc = %d) was received by queue 0x%x"
336 };
337
338 /*!
339 * ======== FreeHookFxn ========
340 * Function prototype for the MessageQ_free callback
341 *
342 * @param(Bits16) heapId of message that was freed
343 * @param(Bits16) msgId of message that was freed
344 */
345 typedef Void (*FreeHookFxn)(Bits16, Bits16);
346
347 /*! MessageQ ID */
348 typedef UInt32 QueueId;
349
350 /*!
351 * ======== SetupTransportProxy ========
352 * MessageQ transport setup proxy
353 */
354 proxy SetupTransportProxy inherits ti.sdo.ipc.interfaces.ITransportSetup;
355
356 /*!
357 * Message priority values. These must match the values defined in
358 * ti/ipc/MessageQ.h but are needed here for ROV.
359 */
360 const UInt NORMALPRI = 0;
361 const UInt HIGHPRI = 1;
362 const UInt RESERVEDPRI = 2;
363 const UInt URGENTPRI = 3;
364
365 /*!
366 * Denotes any queueId is acceptable
367 *
368 * This constant is the default for the {@link #queueId} parameter.
369 * This value must match ti/ipc/MessageQ.h but is needed to initialize
370 * queueId.
371 */
372 const Bits16 ANY = ~(0);
373
374 /*!
375 * Assert raised when calling API with wrong handle
376 *
377 * Some APIs can only be called with an opened handle (e.g.
378 * {@link #close}. Some can only be called with a created handle
379 * (e.g. {@link #get}).
380 */
381 config Assert.Id A_invalidContext = {
382 msg: "A_invalidContext: Cannot call with an open/create handle"
383 };
384
385 /*!
386 * Assert raised when attempting to free a static message
387 */
388 config Assert.Id A_cannotFreeStaticMsg = {
389 msg: "A_cannotFreeStaticMsg: Cannot call MessageQ_free with static msg"
390 };
391
392 /*!
393 * Assert raised when an invalid message is supplied
394 */
395 config Assert.Id A_invalidMsg = {
396 msg: "A_invalidMsg: Invalid message"
397 };
398
399 /*!
400 * Assert raised when an invalid queueId is supplied
401 */
402 config Assert.Id A_invalidQueueId = {
403 msg: "A_invalidQueueId: Invalid queueId is used"
404 };
405
406 /*!
407 * Assert raised when using an invalid heapId
408 */
409 config Assert.Id A_heapIdInvalid = {
410 msg: "A_heapIdInvalid: heapId is invalid"
411 };
412
413 /*!
414 * Assert raised when using an invalid procId
415 */
416 config Assert.Id A_procIdInvalid = {
417 msg: "A_procIdInvalid: procId is invalid"
418 };
419
420 /*!
421 * Assert raised for an invalid MessageQ object
422 */
423 config Assert.Id A_invalidObj = {
424 msg: "A_invalidObj: an invalid obj is used"
425 };
426
427 /*!
428 * Assert raised for an invalid parameter
429 */
430 config Assert.Id A_invalidParam = {
431 msg: "A_invalidParam: an invalid parameter was passed in"
432 };
433
434 /*!
435 * Assert raised when attempting to send a message to a core
436 * where a transport has not been registered.
437 */
438 config Assert.Id A_unregisteredTransport = {
439 msg: "A_unregisteredTransport: transport is not registered"
440 };
441
442 /*!
443 * Assert raised when attempting to unblock a remote MessageQ or one that
444 * has been configured with a non-blocking synchronizer
445 */
446 config Assert.Id A_invalidUnblock = {
447 msg: "A_invalidUnblock: Trying to unblock a remote MessageQ or a queue with non-blocking synchronizer"
448 };
449
450 /*!
451 * Error raised if all the message queue objects are taken
452 */
453 config Error.Id E_maxReached = {
454 msg: "E_maxReached: All objects in use. MessageQ.maxRuntimeEntries is %d"
455 };
456
457 /*!
458 * Error raised when heapId has not been registered
459 */
460 config Error.Id E_unregisterHeapId = {
461 msg: "E_unregisterHeapId: Heap id %d not registered"
462 };
463
464 /*!
465 * Error raised in a create call when a name fails to be added
466 * to the NameServer table. This can be because the name already
467 * exists, the table has reached its max length, or out of memory.
468 */
469 config Error.Id E_nameFailed = {
470 msg: "E_nameFailed: '%s' name failed to be added to NameServer"
471 };
472
473 /*!
474 * Error raised if the requested queueIndex is not available
475 */
476 config Error.Id E_indexNotAvailable = {
477 msg: "E_indexNotAvailable: queueIndex %d not available"
478 };
479
480 /*!
481 * Trace setting
482 *
483 * This flag allows the configuration of the default module trace
484 * settings.
485 */
486 config Bool traceFlag = false;
487
488 /*!
489 * Number of heapIds in the system
490 *
491 * This allows MessageQ to pre-allocate the heaps table.
492 * The heaps table is used when registering heaps.
493 *
494 * There is no default heap, so unless the system is only using
495 * {@link #staticMsgInit}, the application must register a heap.
496 */
497 config UInt16 numHeaps = 8;
498
499 /*!
500 * Maximum number of MessageQs that can be dynamically created
501 */
502 config UInt maxRuntimeEntries = NameServer.ALLOWGROWTH;
503
504 /*!
505 * Number of reserved MessageQ indexes
506 *
507 * An application can request the first N message queue indexes be
508 * reserved to be used by MessageQ_create2. MessageQ_create will
509 * not use these slots. The application can use any index less than
510 * the value of numReservedEntries for the queueIndex field in the
511 * MessageQ_Params2 structure.
512 *
513 * numReservedEntries must be equal or less than
514 * {@link #maxRuntimeEntries}.
515 */
516 config UInt numReservedEntries = 0;
517
518 /*!
519 * Gate used to make the name table thread safe
520 *
521 * This gate is used when accessing the name table during
522 * a {@link #create}, {@link #delete}, and {@link #open}.
523 *
524 * This gate is also used to protect MessageQ when growing
525 * internal tables in the {@link #create}.
526 *
527 * The table is in local memory, not shared memory. So a
528 * single processor gate will work.
529 *
530 * The default will be {@link xdc.runtime.knl.GateThread}
531 * instance.
532 */
533 config IGateProvider.Handle nameTableGate = null;
534
535 /*!
536 * Maximum length for Message queue names
537 */
538 config UInt maxNameLen = 32;
539
540 /*!
541 * Section name is used to place the names table
542 */
543 metaonly config String tableSection = null;
544
545 /*!
546 * ======== freeHookFxn ========
547 * Free function in MessageQ_free after message was freed back to the heap
548 */
549 config FreeHookFxn freeHookFxn = null;
550
551 /*!
552 * ======== registerHeapMeta ========
553 * Statically register a heap with MessageQ
554 *
555 * Build error if heapId is in use.
556 *
557 * @param(heap) Heap to register
558 * @param(heapId) heapId associated with the heap
559 */
560 metaonly Void registerHeapMeta(IHeap.Handle heap, UInt16 heapId);
561
562 /*!
563 * ======== registerTransportMeta ========
564 * Statically register a transport with MessageQ
565 *
566 * Build error if remote processor already has a transport
567 * registered.
568 *
569 * @param(transport) transport to register
570 * @param(procId) procId that transport communicaties with
571 * @param(priority) priority of transport
572 */
573 metaonly Void registerTransportMeta(IMessageQTransport.Handle transport, UInt16 procId, UInt priority);
574
575 /*!
576 * ======== registerTransport ========
577 * Register a transport with MessageQ
578 *
579 * This API is called by the transport when it is created.
580 *
581 * @param(transport) transport to register
582 * @param(procId) MultiProc id that transport communicates with
583 * @param(priority) priority of transport
584 *
585 * @b(returns) Whether the register was successful.
586 */
587 Bool registerTransport(IMessageQTransport.Handle transport, UInt16 procId,
588 UInt priority);
589
590 /*!
591 * ======== unregisterTransport ========
592 * Unregister a transport with MessageQ
593 *
594 * @param(procId) unregister transport that communicates with
595 * this remote processor
596 * @param(priority) priority of transport
597 */
598 Void unregisterTransport(UInt16 procId, UInt priority);
599
600 instance:
601
602 /*!
603 * ISync handle used to signal IO completion
604 *
605 * The ISync instance is used in the {@link #get} and {@link #put}.
606 * The {@link xdc.runtime.knl.ISync#signal} is called as part
607 * of the {@link #put} call. The {@link xdc.runtime.knl.ISync#wait} is
608 * called in the {@link #get} if there are no messages present.
609 */
610 config ISync.Handle synchronizer = null;
611
612 /*!
613 * Requested MessageQ_QueueIndex
614 *
615 * This parameter allows an application to specify the queueIndex to
616 * be used for a message queue. To use this functionality, the
617 * MessageQ.numReservedEntries static configuration parameter must be set to
618 * a specific value.
619 *
620 * The default is {@link #ANY}. This means do that you are not asking for
621 * an explicit index. MessageQ will find the first available one which is
622 * equal or greater than MessageQ.numReservedEntries.
623 */
624 config UInt16 queueIndex = ANY;
625
626 /*! @_nodoc
627 * ======== create ========
628 * Create a message queue
629 *
630 * @param(name) Name of the message queue.
631 */
632 create(String name);
633
634 internal:
635 636 637 638 639 640 641 642 643 644 645
646
647 /*! Mask to extract version setting */
648 const UInt VERSIONMASK = 0xE000;
649
650 /*! Version setting */
651 const UInt HEADERVERSION = 0x2000;
652
653 /*! Mask to extract Trace setting */
654 const UInt TRACEMASK = 0x1000;
655
656 /*! Shift for Trace setting */
657 const UInt TRACESHIFT = 12;
658
659 /*!
660 * Mask to extract priority setting.
661 * This is needed here for ROV but must match
662 * the value defined in ti/ipc/MessageQ.h
663 */
664 const UInt PRIORITYMASK = 0x3;
665
666 /*! Mask to extract priority setting */
667 const UInt TRANSPORTPRIORITYMASK = 0x1;
668
669 /*! return code for Instance_init */
670 const Int PROXY_FAILURE = 1;
671
672 673 674 675
676 const UInt16 STATICMSG = 0xFFFF;
677
678 /*! Required first field in every message */
679 @Opaque struct MsgHeader {
680 Bits32 reserved0;
681 Bits32 reserved1;
682 Bits32 msgSize;
683 Bits16 flags;
684 Bits16 msgId;
685 Bits16 dstId;
686 Bits16 dstProc;
687 Bits16 replyId;
688 Bits16 replyProc;
689 Bits16 srcProc;
690 Bits16 heapId;
691 Bits16 seqNum;
692 Bits16 reserved;
693 };
694
695 struct HeapEntry {
696 IHeap.Handle heap;
697 UInt16 heapId;
698 };
699
700 struct TransportEntry {
701 IMessageQTransport.Handle transport;
702 UInt16 procId;
703 };
704
705 /*!
706 * ======== nameSrvPrms ========
707 * This Params object is used for temporary storage of the
708 * module wide parameters that are for setting the NameServer instance.
709 */
710 metaonly config NameServer.Params nameSrvPrms;
711
712 /*!
713 * Statically registered heaps
714 *
715 * This configuration parameter allows the static registeration
716 * of heaps. The index of the array corresponds to the heapId.
717 */
718 metaonly config HeapEntry staticHeaps[];
719
720 /*!
721 * Statically registered transports
722 *
723 * This configuration parameter allows the static registeration
724 * of transports. The index of the array corresponds to the procId.
725 */
726 metaonly config TransportEntry staticTransports[];
727
728 /*!
729 * Allows for the number of dynamically created message queues to grow.
730 */
731 UInt16 grow(Object *obj, Error.Block *eb);
732
733 struct Instance_State {
734 QueueId queue;
735 ISync.Handle synchronizer;
736 List.Object normalList;
737 List.Object highList;
738 Ptr nsKey;
739 SyncSem.Handle syncSemHandle;
740 Bool unblocked;
741 };
742
743 struct Module_State {
744 IMessageQTransport.Handle transports[][2];
745 Handle queues[];
746 IHeap.Handle heaps[];
747 IGateProvider.Handle gate;
748 UInt16 numQueues;
749 UInt16 numHeaps;
750 NameServer.Handle nameServer;
751 FreeHookFxn freeHookFxn;
752 Bool canFreeQueues;
753 UInt16 seqNum;
754 };
755 }