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 IMessageQTransport} instances. MessageQ supports
152 * a high priority and a normal priority transport between any two
153 * 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 }
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 /*! MessageQ ID */
339 typedef UInt32 QueueId;
340
341 /*!
342 * ======== SetupTransportProxy ========
343 * MessageQ transport setup proxy
344 */
345 proxy SetupTransportProxy inherits ti.sdo.ipc.interfaces.ITransportSetup;
346
347 /*!
348 * Message priority values. These must match the values defined in
349 * ti/ipc/MessageQ.h but are needed here for ROV.
350 */
351 const UInt NORMALPRI = 0;
352 const UInt HIGHPRI = 1;
353 const UInt RESERVEDPRI = 2;
354 const UInt URGENTPRI = 3;
355
356 /*!
357 * Assert raised when calling API with wrong handle
358 *
359 * Some APIs can only be called with an opened handle (e.g.
360 * {@link #close}. Some can only be called with a created handle
361 * (e.g. {@link #get}).
362 */
363 config Assert.Id A_invalidContext = {
364 msg: "A_invalidContext: Cannot call with an open/create handle"
365 };
366
367 /*!
368 * Assert raised when attempting to free a static message
369 */
370 config Assert.Id A_cannotFreeStaticMsg = {
371 msg: "A_cannotFreeStaticMsg: Cannot call MessageQ_free with static msg"
372 };
373
374 /*!
375 * Assert raised when an invalid message is supplied
376 */
377 config Assert.Id A_invalidMsg = {
378 msg: "A_invalidMsg: Invalid message"
379 };
380
381 /*!
382 * Assert raised when an invalid queueId is supplied
383 */
384 config Assert.Id A_invalidQueueId = {
385 msg: "A_invalidQueueId: Invalid queueId is used"
386 };
387
388 /*!
389 * Assert raised when using an invalid heapId
390 */
391 config Assert.Id A_heapIdInvalid = {
392 msg: "A_heapIdInvalid: heapId is invalid"
393 };
394
395 /*!
396 * Assert raised when using an invalid procId
397 */
398 config Assert.Id A_procIdInvalid = {
399 msg: "A_procIdInvalid: procId is invalid"
400 };
401
402 /*!
403 * Assert raised for an invalid MessageQ object
404 */
405 config Assert.Id A_invalidObj = {
406 msg: "A_invalidObj: an invalid obj is used"
407 };
408
409 /*!
410 * Assert raised for an invalid parameter
411 */
412 config Assert.Id A_invalidParam = {
413 msg: "A_invalidParam: an invalid parameter was passed in"
414 };
415
416 /*!
417 * Assert raised when attempting to send a message to a core
418 * where a transport has not been registered.
419 */
420 config Assert.Id A_unregisteredTransport = {
421 msg: "A_unregisteredTransport: transport is not registered"
422 };
423
424 /*!
425 * Assert raised when attempting to unblock a remote MessageQ or one that
426 * has been configured with a non-blocking synchronizer
427 */
428 config Assert.Id A_invalidUnblock = {
429 msg: "A_invalidUnblock: Trying to unblock a remote MessageQ or a queue with non-blocking synchronizer"
430 };
431
432 /*!
433 * Error raised if all the message queue objects are taken
434 */
435 config Error.Id E_maxReached = {
436 msg: "E_maxReached: All objects in use. MessageQ.maxRuntimeEntries is %d"
437 };
438
439 /*!
440 * Error raised when heapId has not been registered
441 */
442 config Error.Id E_unregisterHeapId = {
443 msg: "E_unregisterHeapId: Heap id %d not registered"
444 };
445
446 /*!
447 * Trace setting
448 *
449 * This flag allows the configuration of the default module trace
450 * settings.
451 */
452 config Bool traceFlag = false;
453
454 /*!
455 * Number of heapIds in the system
456 *
457 * This allows MessageQ to pre-allocate the heaps table.
458 * The heaps table is used when registering heaps.
459 *
460 * The default is 1.
461 *
462 * There is no default heap, so unless the system is only using
463 * {@link #staticMsgInit}, the application must register a heap.
464 */
465 config UInt16 numHeaps = 1;
466
467 /*!
468 * Maximum number of MessageQs that can be dynamically created
469 */
470 config UInt maxRuntimeEntries = NameServer.ALLOWGROWTH;
471
472 /*!
473 * Gate used to make the name table thread safe
474 *
475 * This gate is used when accessing the name table during
476 * a {@link #create}, {@link #delete}, and {@link #open}.
477 *
478 * This gate is also used to protect MessageQ when growing
479 * internal tables in the {@link #create}.
480 *
481 * The table is in local memory, not shared memory. So a
482 * single processor gate will work.
483 *
484 * The default will be {@link xdc.runtime.knl.GateThread}
485 * instance.
486 */
487 config IGateProvider.Handle nameTableGate = null;
488
489 /*!
490 * Maximum length for Message queue names
491 */
492 config UInt maxNameLen = 32;
493
494 /*!
495 * Section name is used to place the names table
496 */
497 metaonly config String tableSection = null;
498
499 /*!
500 * ======== registerHeapMeta ========
501 * Statically register a heap with MessageQ
502 *
503 * Build error if heapId is in use.
504 *
505 * @param(heap) Heap to register
506 * @param(heapId) heapId associated with the heap
507 */
508 metaonly Void registerHeapMeta(IHeap.Handle heap, UInt16 heapId);
509
510 /*!
511 * ======== registerTransportMeta ========
512 * Statically register a transport with MessageQ
513 *
514 * Build error if remote processor already has a transport
515 * registered.
516 *
517 * @param(transport) transport to register
518 * @param(procId) procId that transport communicaties with
519 * @param(priority) priority of transport
520 */
521 metaonly Void registerTransportMeta(IMessageQTransport.Handle transport, UInt16 procId, UInt priority);
522
523 /*! @_nodoc
524 * ======== attach ========
525 * Calls the {@link #SetupProxy} to setup the MessageQ transports.
526 */
527 Int attach(UInt16 remoteProcId, Ptr sharedAddr);
528
529 /*! @_nodoc
530 * ======== detach ========
531 * Calls the {@link #SetupProxy} to detach the MessageQ transports.
532 */
533 Int detach(UInt16 remoteProcId);
534
535 /*! @_nodoc
536 * ======== sharedMemReq ========
537 * Returns the amount of shared memory used by one transport instance.
538 *
539 * The MessageQ module itself does not use any shared memory but the
540 * underlying transport may use some shared memory.
541 */
542 SizeT sharedMemReq(Ptr sharedAddr);
543
544 /*!
545 * ======== registerTransport ========
546 * Register a transport with MessageQ
547 *
548 * This API is called by the transport when it is created.
549 *
550 * @param(transport) transport to register
551 * @param(procId) MultiProc id that transport communicates with
552 * @param(priority) priority of transport
553 *
554 * @b(returns) Whether the register was successful.
555 */
556 Bool registerTransport(IMessageQTransport.Handle transport, UInt16 procId,
557 UInt priority);
558
559 /*!
560 * ======== unregisterTransport ========
561 * Unregister a transport with MessageQ
562 *
563 * @param(procId) unregister transport that communicates with
564 * this remote processor
565 * @param(priority) priority of transport
566 */
567 Void unregisterTransport(UInt16 procId, UInt priority);
568
569 instance:
570
571 /*!
572 * ISync handle used to signal IO completion
573 *
574 * The ISync instance is used in the {@link #get} and {@link #put}.
575 * The {@link xdc.runtime.knl.ISync#signal} is called as part
576 * of the {@link #put} call. The {@link xdc.runtime.knl.ISync#wait} is
577 * called in the {@link #get} if there are no messages present.
578 */
579 config ISync.Handle synchronizer = null;
580
581 /*! @_nodoc
582 * ======== create ========
583 * Create a message queue
584 *
585 * @param(name) Name of the message queue.
586 */
587 create(String name);
588
589 internal:
590 591 592 593 594 595 596 597 598 599 600
601
602 /*! Mask to extract version setting */
603 const UInt VERSIONMASK = 0xE000;
604
605 /*! Version setting */
606 const UInt HEADERVERSION = 0x2000;
607
608 /*! Mask to extract Trace setting */
609 const UInt TRACEMASK = 0x1000;
610
611 /*! Shift for Trace setting */
612 const UInt TRACESHIFT = 12;
613
614 /*!
615 * Mask to extract priority setting.
616 * This is needed here for ROV but must match
617 * the value defined in ti/ipc/MessageQ.h
618 */
619 const UInt PRIORITYMASK = 0x3;
620
621 /*! Mask to extract priority setting */
622 const UInt TRANSPORTPRIORITYMASK = 0x1;
623
624 /*! return code for Instance_init */
625 const Int PROXY_FAILURE = 1;
626
627 628 629 630
631 const UInt16 STATICMSG = 0xFFFF;
632
633 /*! Required first field in every message */
634 @Opaque struct MsgHeader {
635 Bits32 reserved0;
636 Bits32 reserved1;
637 Bits32 msgSize;
638 Bits16 flags;
639 Bits16 msgId;
640 Bits16 dstId;
641 Bits16 dstProc;
642 Bits16 replyId;
643 Bits16 replyProc;
644 Bits16 srcProc;
645 Bits16 heapId;
646 Bits16 seqNum;
647 Bits16 reserved;
648 };
649
650 struct HeapEntry {
651 IHeap.Handle heap;
652 UInt16 heapId;
653 };
654
655 struct TransportEntry {
656 IMessageQTransport.Handle transport;
657 UInt16 procId;
658 };
659
660 /*!
661 * ======== nameSrvPrms ========
662 * This Params object is used for temporary storage of the
663 * module wide parameters that are for setting the NameServer instance.
664 */
665 metaonly config NameServer.Params nameSrvPrms;
666
667 /*!
668 * Statically registered heaps
669 *
670 * This configuration parameter allows the static registeration
671 * of heaps. The index of the array corresponds to the heapId.
672 */
673 metaonly config HeapEntry staticHeaps[];
674
675 /*!
676 * Statically registered transports
677 *
678 * This configuration parameter allows the static registeration
679 * of transports. The index of the array corresponds to the procId.
680 */
681 metaonly config TransportEntry staticTransports[];
682
683 /*!
684 * Allows for the number of dynamically created message queues to grow.
685 */
686 UInt16 grow(Object *obj, Error.Block *eb);
687
688 struct Instance_State {
689 QueueId queue;
690 ISync.Handle synchronizer;
691 List.Object normalList;
692 List.Object highList;
693 Ptr nsKey;
694 SyncSem.Handle syncSemHandle;
695 Bool unblocked;
696 };
697
698 struct Module_State {
699 IMessageQTransport.Handle transports[][2];
700 Handle queues[];
701 IHeap.Handle heaps[];
702 IGateProvider.Handle gate;
703 UInt16 numQueues;
704 UInt16 numHeaps;
705 NameServer.Handle nameServer;
706 Bool canFreeQueues;
707 UInt16 seqNum;
708
709 };
710 }
711 712 713
714