]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/open-amp.git/blob - lib/remoteproc/remoteproc.c
rm compilation warnings, clean comments, file rename
[processor-sdk/open-amp.git] / lib / remoteproc / remoteproc.c
1 /*
2  * Copyright (c) 2014, Mentor Graphics Corporation
3  * All rights reserved.
4  * Copyright (c) 2015 Xilinx, Inc. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  *    this list of conditions and the following disclaimer in the documentation
13  *    and/or other materials provided with the distribution.
14  * 3. Neither the name of Mentor Graphics Corporation nor the names of its
15  *    contributors may be used to endorse or promote products derived from this
16  *    software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
31 #include "openamp/remoteproc.h"
32 #include "openamp/remoteproc_loader.h"
33 #include "openamp/rsc_table_parser.h"
34 #include "openamp/env.h"
35 #include "openamp/hil.h"
37 /**
38  * remoteproc_resource_init
39  *
40  * Initializes resources for remoteproc remote configuration. Only
41  * remoteproc remote applications are allowed to call this function.
42  *
43  * @param rsc_info          - pointer to resource table info control
44  *                                                        block
45  * @param channel_created   - callback function for channel creation
46  * @param channel_destroyed - callback function for channel deletion
47  * @param default_cb        - default callback for channel I/O
48  * @param rproc_handle      - pointer to new remoteproc instance
49  *
50  * @param returns - status of function execution
51  *
52  */
53 int remoteproc_resource_init(struct rsc_table_info *rsc_info,
54                              rpmsg_chnl_cb_t channel_created,
55                              rpmsg_chnl_cb_t channel_destroyed,
56                              rpmsg_rx_cb_t default_cb,
57                              struct remote_proc **rproc_handle)
58 {
60         struct remote_proc *rproc;
61         int status;
63         if (!rsc_info) {
64                 return RPROC_ERR_PARAM;
65         }
67         /* Initialize environment component */
68         status = env_init();
69         if (status != RPROC_SUCCESS) {
70                 return status;
71         }
73         rproc = env_allocate_memory(sizeof(struct remote_proc));
74         if (rproc) {
75                 env_memset(rproc, 0x00, sizeof(struct remote_proc));
76                 /* There can be only one master for remote configuration so use the
77                  * rsvd cpu id for creating hil proc */
78                 rproc->proc = hil_create_proc(HIL_RSVD_CPU_ID);
79                 if (rproc->proc) {
80                         /* Parse resource table */
81                         status =
82                             handle_rsc_table(rproc, rsc_info->rsc_tab,
83                                              rsc_info->size);
84                         if (status == RPROC_SUCCESS) {
85                                 /* Initialize RPMSG "messaging" component */
86                                 *rproc_handle = rproc;
87                                 status =
88                                     rpmsg_init(rproc->proc->cpu_id,
89                                                &rproc->rdev, channel_created,
90                                                channel_destroyed, default_cb,
91                                                RPMSG_MASTER);
92                         } else {
93                                 status = RPROC_ERR_NO_RSC_TABLE;
94                         }
95                 } else {
96                         status = RPROC_ERR_CPU_ID;
97                 }
98         } else {
99                 status = RPROC_ERR_NO_MEM;
100         }
102         /* Cleanup in case of error */
103         if (status != RPROC_SUCCESS) {
104                 *rproc_handle = 0;
105                 (void)remoteproc_resource_deinit(rproc);
106                 return status;
107         }
108         return status;
111 /**
112  * remoteproc_resource_deinit
113  *
114  * Uninitializes resources for remoteproc "remote" configuration.
115  *
116  * @param rproc - pointer to rproc instance
117  *
118  * @param returns - status of function execution
119  *
120  */
122 int remoteproc_resource_deinit(struct remote_proc *rproc)
124         int i = 0;
125         struct proc_vring *vring_hw = 0;
126         if (rproc) {
127                 if (rproc->rdev) {
128                         /* disable IPC interrupts */
129                         if (rproc->proc->ops->reg_ipi_after_deinit) {
130                                 for (i = 0; i < 2; i++) {
131                                         vring_hw =
132                                             &rproc->proc->vdev.vring_info[i];
133                                         rproc->proc->ops->
134                                             reg_ipi_after_deinit(vring_hw);
135                                 }
136                         }
137                         rpmsg_deinit(rproc->rdev);
138                 }
139                 if (rproc->proc) {
140                         hil_delete_proc(rproc->proc);
141                 }
143                 env_free_memory(rproc);
144         }
146         env_deinit();
148         /*
149          * Flush and Invalidate the caches - When the application is built with
150          * Xilinx Standalone BSP, caches are invalidated as part of boot process.
151          * Even if the master boots firmware multiple times without hard reset on
152          * same core, caches are flushed and invalidated at the end of
153          * remoteproc_resource_deinit for this run and caches would be again
154          * invalidated before starting the main thread of the application on next
155          * run to avoid any cache inconsistencies.
156          */
157          env_flush_invalidate_all_caches();
160         return RPROC_SUCCESS;
163 /**
164  * remoteproc_init
165  *
166  * Initializes resources for remoteproc master configuration. Only
167  * remoteproc master applications are allowed to call this function.
168  *
169  * @param fw_name           - name of frimware
170  * @param channel_created   - callback function for channel creation
171  * @param channel_destroyed - callback function for channel deletion
172  * @param default_cb        - default callback for channel I/O
173  * @param rproc_handle      - pointer to new remoteproc instance
174  *
175  * @param returns - status of function execution
176  *
177  */
178 int remoteproc_init(char *fw_name, rpmsg_chnl_cb_t channel_created,
179                     rpmsg_chnl_cb_t channel_destroyed, rpmsg_rx_cb_t default_cb,
180                     struct remote_proc **rproc_handle)
183         struct remote_proc *rproc;
184         struct resource_table *rsc_table;
185         unsigned int fw_addr, fw_size, rsc_size;
186         int status, cpu_id;
188         if (!fw_name) {
189                 return RPROC_ERR_PARAM;
190         }
192         /* Initialize environment component */
193         status = env_init();
194         if (status != RPROC_SUCCESS) {
195                 return status;
196         }
198         rproc = env_allocate_memory(sizeof(struct remote_proc));
199         if (rproc) {
200                 env_memset((void *)rproc, 0x00, sizeof(struct remote_proc));
201                 /* Get CPU ID for the given firmware name */
202                 cpu_id = hil_get_cpuforfw(fw_name);
203                 if (cpu_id >= 0) {
204                         /* Create proc instance */
205                         rproc->proc = hil_create_proc(cpu_id);
206                         if (rproc->proc) {
207                                 /* Retrieve firmware attributes */
208                                 status =
209                                     hil_get_firmware(fw_name, &fw_addr,
210                                                      &fw_size);
211                                 if (!status) {
212                                         /* Initialize ELF loader - currently only ELF format is supported */
213                                         rproc->loader =
214                                             remoteproc_loader_init(ELF_LOADER);
215                                         if (rproc->loader) {
216                                                 /* Attach the given firmware with the ELF parser/loader */
217                                                 status =
218                                                     remoteproc_loader_attach_firmware
219                                                     (rproc->loader,
220                                                      (void *)fw_addr);
221                                         } else {
222                                                 status = RPROC_ERR_LOADER;
223                                         }
224                                 }
225                         } else {
226                                 status = RPROC_ERR_NO_MEM;
227                         }
228                 } else {
229                         status = RPROC_ERR_INVLD_FW;
230                 }
231         } else {
232                 status = RPROC_ERR_NO_MEM;
233         }
235         if (!status) {
236                 rproc->role = RPROC_MASTER;
238                 /* Get resource table from firmware */
239                 rsc_table =
240                     remoteproc_loader_retrieve_resource_section(rproc->loader,
241                                                                 &rsc_size);
242                 if (rsc_table) {
243                         /* Parse resource table */
244                         status = handle_rsc_table(rproc, rsc_table, rsc_size);
245                 } else {
246                         status = RPROC_ERR_NO_RSC_TABLE;
247                 }
248         }
250         /* Cleanup in case of error */
251         if (status != RPROC_SUCCESS) {
252                 (void)remoteproc_deinit(rproc);
253                 return status;
254         }
256         rproc->channel_created = channel_created;
257         rproc->channel_destroyed = channel_destroyed;
258         rproc->default_cb = default_cb;
260         *rproc_handle = rproc;
262         return status;
265 /**
266  * remoteproc_deinit
267  *
268  * Uninitializes resources for remoteproc "master" configuration.
269  *
270  * @param rproc - pointer to remote proc instance
271  *
272  * @param returns - status of function execution
273  *
274  */
275 int remoteproc_deinit(struct remote_proc *rproc)
278         if (rproc) {
279                 if (rproc->loader) {
280                         (void)remoteproc_loader_delete(rproc->loader);
281                         rproc->loader = RPROC_NULL;
282                 }
283                 if (rproc->proc) {
284                         hil_delete_proc(rproc->proc);
285                         rproc->proc = RPROC_NULL;
286                 }
287                 env_free_memory(rproc);
288         }
290         env_deinit();
292         return RPROC_SUCCESS;
295 /**
296  * remoteproc_boot
297  *
298  * This function loads the image on the remote processor and starts
299  * its execution from image load address.
300  *
301  * @param rproc - pointer to remoteproc instance to boot
302  *
303  * @param returns - status of function execution
304  */
305 int remoteproc_boot(struct remote_proc *rproc)
308         void *load_addr;
309         int status;
311         if (!rproc) {
312                 return RPROC_ERR_PARAM;
313         }
315         /* Stop the remote CPU */
316         hil_shutdown_cpu(rproc->proc);
318         /* Load the firmware */
319         status = remoteproc_loader_load_remote_firmware(rproc->loader);
320         if (status == RPROC_SUCCESS) {
321                 load_addr = remoteproc_get_load_address(rproc->loader);
322                 if (load_addr != RPROC_ERR_PTR) {
323                         /* Start the remote cpu */
324                         status = hil_boot_cpu(rproc->proc,
325                                               (unsigned int)load_addr);
326                         if (status == RPROC_SUCCESS) {
327                                 /* Wait for remote side to come up. This delay is arbitrary and may
328                                  * need adjustment for different configuration of remote systems */
329                                 env_sleep_msec(RPROC_BOOT_DELAY);
331                                 /* Initialize RPMSG "messaging" component */
333                                 /* It is a work-around to work with remote Linux context. 
334                                    Since the upstream Linux rpmsg implementation always 
335                                    assumes itself to be an rpmsg master, we initialize
336                                    the remote device as an rpmsg master for remote Linux
337                                    configuration only. */
338 #if defined (OPENAMP_REMOTE_LINUX_ENABLE)
339                                 status =
340                                     rpmsg_init(rproc->proc->cpu_id,
341                                                &rproc->rdev,
342                                                rproc->channel_created,
343                                                rproc->channel_destroyed,
344                                                rproc->default_cb, RPMSG_MASTER);
345 #else
346                                 status =
347                                     rpmsg_init(rproc->proc->cpu_id,
348                                                &rproc->rdev,
349                                                rproc->channel_created,
350                                                rproc->channel_destroyed,
351                                                rproc->default_cb, RPMSG_REMOTE);
352 #endif
353                         }
354                 } else {
355                         status = RPROC_ERR_LOADER;
356                 }
357         } else {
358                 status = RPROC_ERR_LOADER;
359         }
361         return status;
364 /**
365  * remoteproc_shutdown
366  *
367  * This function shutdowns the remote execution context
368  *
369  * @param rproc - pointer to remote proc instance to shutdown
370  *
371  * @param returns - status of function execution
372  */
373 int remoteproc_shutdown(struct remote_proc *rproc)
376         if (rproc) {
377                 if (rproc->rdev) {
378                         rpmsg_deinit(rproc->rdev);
379                         rproc->rdev = RPROC_NULL;
380                 }
381                 if (rproc->proc) {
382                         hil_shutdown_cpu(rproc->proc);
383                 }
384         }
386         return RPROC_SUCCESS;