[processor-sdk/open-amp.git] / apps / samples / master / nucleus / matrix_multiply / nucleus_linux / matrix_multiply.c
1 /* This is a sample demonstration application that showcases usage of remoteproc
2 and rpmsg APIs. This application is meant to run on the master CPU running Nucleus
3 and showcases booting of linux remote firmware using remoteproc and
4 IPC with remote firmware using rpmsg; Nucleus on master core acts as a remoteproc master
5 but as an rpmsg remote;It brings up a remote Linux based
6 firmware which acts as an rpmsg master and offloads matrix multiplication to Nucleus.
7 Linux app generates two random matrices and transmits them to Nucleus which computes
8 the product and transmits results back to Linux. Once Linux application is complete, it
9 requests a shutdown from Nucleus. Nucleus acknowledges with a shutdown message which results
10 in Linux starting a system halt. Nucleus shutsdown the remote core after a reasonable delay which allows
11 Linux to gracefully shutdown. */
13 /* Including required headers */
14 #include <stdio.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include "open_amp.h"
18 #include "nucleus.h"
19 #include "kernel/nu_kernel.h"
21 /* Define the main task's stack size */
22 #define STACK_SIZE (NU_MIN_STACK_SIZE * 64)
24 /* Define the main task's priority */
25 #define TASK_PRIORITY 26
27 /* Define the main task's time slice */
28 #define TASK_SLICE 20
30 #define MAX_SIZE 6
31 #define NUM_MATRIX 2
32 /* Shutdown message ID */
33 #define SHUTDOWN_MSG 0xEF56A55A
35 typedef struct _matrix
36 {
37 unsigned long size;
38 unsigned long elements[MAX_SIZE][MAX_SIZE];
39 } matrix;
42 static matrix matrix_array[NUM_MATRIX];
44 static matrix matrix_result;
46 /* Prototypes */
47 static void Main_Task_Entry( UNSIGNED argc , VOID *argv );
49 /* Application provided callbacks */
50 void rpmsg_channel_created( struct rpmsg_channel *rp_chnl );
51 void rpmsg_channel_deleted( struct rpmsg_channel *rp_chnl );
52 void rpmsg_read_cb( struct rpmsg_channel *rp_chnl , void *data , int len , void * pric , unsigned long src );
54 /* Globals */
55 NU_TASK Task_Control_Block;
56 NU_SEMAPHORE App_Sem;
57 struct rpmsg_endpoint *rp_ept;
58 struct rpmsg_channel *app_rp_chnl;
59 char fw1_name []= "firmware1";
61 static int shutdown_received = 0;
63 static void Matrix_Multiply(const matrix *m, const matrix *n, matrix *r)
64 {
65 int i, j, k;
67 r->size = m->size;
69 for (i = 0; i < m->size; ++i) {
70 for (j = 0; j < n->size; ++j) {
71 r->elements[i][j] = 0;
72 }
73 }
75 for (i = 0; i < m->size; ++i) {
76 for (j = 0; j < n->size; ++j) {
77 for (k = 0; k < r->size; ++k) {
78 r->elements[i][j] += m->elements[i][k] * n->elements[k][j];
79 }
80 }
81 }
82 }
85 /***********************************************************************
86 * *
87 * * FUNCTION
88 * *
89 * * Application_Initialize
90 * *
91 * * DESCRIPTION
92 * *
93 * * Demo application entry point
94 *
95 * ***********************************************************************/
96 VOID Application_Initialize(NU_MEMORY_POOL* mem_pool , NU_MEMORY_POOL* uncached_mem_pool )
97 {
98 VOID *pointer;
99 STATUS status = NU_SUCCESS;
101 /* Reference unused parameters to avoid toolset warnings */
102 NU_UNUSED_PARAM( uncached_mem_pool );
104 if (status == NU_SUCCESS)
105 {
106 status = NU_Allocate_Memory(mem_pool, &pointer, STACK_SIZE, NU_NO_SUSPEND);
108 /* Create the main task for matrix processing */
109 if ( status == NU_SUCCESS )
110 {
111 status = NU_Create_Task( &Task_Control_Block , "MAIN" , Main_Task_Entry , 0 ,
112 uncached_mem_pool , pointer , STACK_SIZE , TASK_PRIORITY , TASK_SLICE ,
113 NU_PREEMPT , NU_START );
114 }
115 if(status == NU_SUCCESS)
116 {
117 status = NU_Create_Semaphore(&App_Sem ,"APP_SEM", 0, NU_FIFO);
118 }
119 }
121 /* Check to see if previous operations were successful */
122 if ( status != NU_SUCCESS )
123 {
124 /* Loop forever */
125 while ( 1 );
126 }
127 }
129 /***********************************************************************
130 * *
131 * * FUNCTION
132 * *
133 * * Main_Task_Entry
134 * *
135 * * DESCRIPTION
136 * *
137 * * Entry function for the main task. This task prints a hello world
138 * * message.
139 * *
140 * ***********************************************************************/
141 static VOID Main_Task_Entry( UNSIGNED argc , VOID *argv ) {
143 struct remote_proc *proc;
144 NU_MEMORY_POOL *sys_pool_ptr;
145 STATUS status;
146 int shutdown_msg = SHUTDOWN_MSG;
148 status = NU_System_Memory_Get(&sys_pool_ptr, NU_NULL);
150 /* Start first firmware*/
151 if(status == NU_SUCCESS)
152 {
153 printf("\n\n\r************************************");
154 printf("*******************************************\r\n");
155 printf("\r\n Matrix Multiplication Application \r\n");
156 printf("\r\n");
157 printf("\r\nThis sample application will boot a remote Linux firmware \r\n");
158 printf("\r\nThis sample application will boot a remote Linux firmware \r\n");
159 printf("\r\nand handle offloaded matrix multiplication operations from\r\n");
160 printf("\r\nLinux RPMSG master to Nuclues RPMS Remote \r\n");
162 printf("\r\n******************************************");
163 printf("*************************************\n\r\n");
166 printf("\r\n\nLoading remote context : %s \r\n" , fw1_name);
168 printf("\r\n******************************************");
169 printf("*************************************\n\r\n");
171 status = remoteproc_init((void *) fw1_name, rpmsg_channel_created, rpmsg_channel_deleted, rpmsg_read_cb, &proc);
172 }
174 if((!status) && (proc))
175 {
176 printf("\r\n\n********************************************\r\n");
177 printf("BOOTING LINUX REMOTE FIRMWARE");
178 printf("\r\n********************************************\r\n\n");
179 status = remoteproc_boot(proc);
180 }
182 if(!status)
183 {
184 while(1)
185 {
186 NU_Obtain_Semaphore(&App_Sem, NU_SUSPEND);
188 if(shutdown_received == 1)
189 {
190 break;
191 }
193 /* Process received data and multiple matrices. */
194 Matrix_Multiply(&matrix_array[0], &matrix_array[1], &matrix_result);
196 /* Send the result of matrix multiplication back to master. */
197 rpmsg_send(app_rp_chnl, &matrix_result, sizeof(matrix));
198 }
200 /* Send shutdown message to remote */
201 rpmsg_send(app_rp_chnl, &shutdown_msg, sizeof(int));
203 /* The remote Linux kernel requires around ~15 seconds to shutdown itself. Wait. */
204 NU_Sleep(100 * 18);
206 remoteproc_shutdown(proc);
208 remoteproc_deinit(proc);
209 }
210 else
211 {
212 printf("\r\n\nLoading remote context: %s failed \r\n" , fw1_name);
213 }
214 }
216 /* This callback gets invoked when the remote chanl is created */
217 void rpmsg_channel_created(struct rpmsg_channel *rp_chnl) {
219 app_rp_chnl = rp_chnl;
220 rp_ept = rpmsg_create_ept(rp_chnl , rpmsg_read_cb ,RPMSG_NULL , RPMSG_ADDR_ANY);
221 }
223 /* This callback gets invoked when the remote channel is deleted */
224 void rpmsg_channel_deleted(struct rpmsg_channel *rp_chnl) {
226 rpmsg_destroy_ept(rp_ept);
227 }
229 /* This is the read callback, note we are in a task context when this callback
230 is invoked, so kernel primitives can be used freely */
231 void rpmsg_read_cb(struct rpmsg_channel *rp_chnl, void *data, int len,
232 void * priv, unsigned long src) {
234 if ((*(int *) data) == SHUTDOWN_MSG)
235 {
236 shutdown_received = 1;
237 }
239 memcpy(matrix_array, data, len);
241 NU_Release_Semaphore(&App_Sem);
242 }