1 /*
2 * Copyright (c) 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 * ======== message_multicore.c ========
34 * Multiprocessor MessageQ example
35 *
36 * This is an example program that uses MessageQ to pass a message
37 * from one processor to another.
38 *
39 * Each processor creates its own MessageQ first and then will try to open
40 * a remote processor's MessageQ.
41 *
42 * See message_multicore.k file for expected output.
43 */
45 #include <xdc/std.h>
46 #include <string.h>
48 /* -----------------------------------XDC.RUNTIME module Headers */
49 #include <xdc/runtime/System.h>
50 #include <xdc/runtime/IHeap.h>
52 /* ----------------------------------- IPC module Headers */
53 #include <ti/ipc/Ipc.h>
54 #include <ti/ipc/MessageQ.h>
55 #include <ti/ipc/HeapBufMP.h>
56 #include <ti/ipc/MultiProc.h>
58 /* ----------------------------------- BIOS6 module Headers */
59 #include <ti/sysbios/BIOS.h>
60 #include <ti/sysbios/knl/Task.h>
61 #include <ti/sysbios/knl/Clock.h>
62 #include <ti/sysbios/family/c66/Cache.h>
64 /* ----------------------------------- To get globals from .cfg Header */
65 #include <xdc/cfg/global.h>
67 #define HEAP_NAME "myHeapBuf"
68 #define HEAPID 0
69 #define NUMLOOPS 10
71 Char localQueueName[10];
72 Char nextQueueName[10];
73 UInt16 nextProcId;
75 /*
76 * ======== tsk0_func ========
77 * Allocates a message and ping-pongs the message around the processors.
78 * A local message queue is created and a remote message queue is opened.
79 * Messages are sent to the remote message queue and retrieved from the
80 * local MessageQ.
81 */
82 Void tsk0_func(UArg arg0, UArg arg1)
83 {
84 MessageQ_Msg msg;
85 MessageQ_Handle messageQ;
86 MessageQ_QueueId remoteQueueId;
87 Int status;
88 UInt16 msgId = 0;
89 HeapBufMP_Handle heapHandle;
90 HeapBufMP_Params heapBufParams;
92 if (MultiProc_self() == 0) {
93 /*
94 * Create the heap that will be used to allocate messages.
95 */
96 HeapBufMP_Params_init(&heapBufParams);
97 heapBufParams.regionId = 0;
98 heapBufParams.name = HEAP_NAME;
99 heapBufParams.numBlocks = 1;
100 heapBufParams.blockSize = sizeof(MessageQ_MsgHeader);
101 heapHandle = HeapBufMP_create(&heapBufParams);
102 if (heapHandle == NULL) {
103 System_abort("HeapBufMP_create failed\n" );
104 }
105 }
106 else {
107 /* Open the heap created by the other processor. Loop until opened. */
108 do {
109 status = HeapBufMP_open(HEAP_NAME, &heapHandle);
110 /*
111 * Sleep for 1 clock tick to avoid inundating remote processor
112 * with interrupts if open failed
113 */
114 if (status < 0) {
115 Task_sleep(1);
116 }
117 } while (status < 0);
118 }
120 /* Register this heap with MessageQ */
121 MessageQ_registerHeap((IHeap_Handle)heapHandle, HEAPID);
123 /* Create the local message queue */
124 messageQ = MessageQ_create(localQueueName, NULL);
125 if (messageQ == NULL) {
126 System_abort("MessageQ_create failed\n" );
127 }
129 /* Open the remote message queue. Spin until it is ready. */
130 do {
131 status = MessageQ_open(nextQueueName, &remoteQueueId);
132 /*
133 * Sleep for 1 clock tick to avoid inundating remote processor
134 * with interrupts if open failed
135 */
136 if (status < 0) {
137 Task_sleep(1);
138 }
139 } while (status < 0);
141 if (MultiProc_self() == 0) {
142 /* Allocate a message to be ping-ponged around the processors */
143 msg = MessageQ_alloc(HEAPID, sizeof(MessageQ_MsgHeader));
144 if (msg == NULL) {
145 System_abort("MessageQ_alloc failed\n" );
146 }
148 /*
149 * Send the message to the next processor and wait for a message
150 * from the previous processor.
151 */
152 System_printf("Start the main loop\n");
153 while (msgId < NUMLOOPS) {
154 /* Increment...the remote side will check this */
155 msgId++;
156 MessageQ_setMsgId(msg, msgId);
158 System_printf("Sending a message #%d to %s\n", msgId, nextQueueName);
160 /* send the message to the remote processor */
161 status = MessageQ_put(remoteQueueId, msg);
162 if (status < 0) {
163 System_abort("MessageQ_put had a failure/error\n");
164 }
166 /* Get a message */
167 status = MessageQ_get(messageQ, &msg, MessageQ_FOREVER);
168 if (status < 0) {
169 System_abort("This should not happen since timeout is forever\n");
170 }
171 }
172 }
173 else {
174 /*
175 * Wait for a message from the previous processor and
176 * send it to the next processor
177 */
178 System_printf("Start the main loop\n");
179 while (TRUE) {
180 /* Get a message */
181 status = MessageQ_get(messageQ, &msg, MessageQ_FOREVER);
182 if (status < 0) {
183 System_abort("This should not happen since timeout is forever\n");
184 }
186 System_printf("Sending a message #%d to %s\n", MessageQ_getMsgId(msg),
187 nextQueueName);
189 /* Get the message id */
190 msgId = MessageQ_getMsgId(msg);
192 /* send the message to the remote processor */
193 status = MessageQ_put(remoteQueueId, msg);
194 if (status < 0) {
195 System_abort("MessageQ_put had a failure/error\n");
196 }
198 /* test done */
199 if (msgId >= NUMLOOPS) {
200 break;
201 }
202 }
203 }
205 System_printf("The test is complete\n");
206 BIOS_exit(0);
207 }
209 #define CACHE_WB_TICK_PERIOD 5
211 /*
212 * ======== VirtQueue_cacheWb ========
213 *
214 * Used for flushing SysMin trace buffer.
215 */
216 Void traceBuf_cacheWb()
217 {
218 static UInt32 oldticks = 0;
219 UInt32 newticks;
221 newticks = Clock_getTicks();
222 if (newticks - oldticks < (UInt32)CACHE_WB_TICK_PERIOD) {
223 /* Don't keep flushing cache */
224 return;
225 }
227 oldticks = newticks;
229 Cache_wbAll();
231 }
233 /*
234 * ======== main ========
235 * Synchronizes all processors (in Ipc_start) and calls BIOS_start
236 */
237 Int main(Int argc, Char* argv[])
238 {
239 Int status;
241 nextProcId = (MultiProc_self() + 1) % MultiProc_getNumProcessors();
243 /* Generate queue names based on own proc ID and total number of procs */
244 System_sprintf(localQueueName, "%s", MultiProc_getName(MultiProc_self()));
245 System_sprintf(nextQueueName, "%s", MultiProc_getName(nextProcId));
247 /*
248 * Ipc_start() calls Ipc_attach() to synchronize all remote processors
249 * because 'Ipc.procSync' is set to 'Ipc.ProcSync_ALL' in *.cfg
250 */
251 status = Ipc_start();
252 if (status < 0) {
253 System_abort("Ipc_start failed\n");
254 }
256 BIOS_start();
258 return (0);
259 }