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