]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/open-amp.git/blob - lib/remoteproc/remoteproc.c
Replace env_memset() with memset()
[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 <string.h>
32 #include "openamp/remoteproc.h"
33 #include "openamp/remoteproc_loader.h"
34 #include "openamp/rsc_table_parser.h"
35 #include "openamp/env.h"
36 #include "openamp/hil.h"
37 #include "metal/sys.h"
39 /**
40  * remoteproc_resource_init
41  *
42  * Initializes resources for remoteproc remote configuration. Only
43  * remoteproc remote applications are allowed to call this function.
44  *
45  * @param rsc_info          - pointer to resource table info control
46  *                                                        block
47  * @param channel_created   - callback function for channel creation
48  * @param channel_destroyed - callback function for channel deletion
49  * @param default_cb        - default callback for channel I/O
50  * @param rproc_handle      - pointer to new remoteproc instance
51  *
52  * @param returns - status of function execution
53  *
54  */
55 int remoteproc_resource_init(struct rsc_table_info *rsc_info,
56                              rpmsg_chnl_cb_t channel_created,
57                              rpmsg_chnl_cb_t channel_destroyed,
58                              rpmsg_rx_cb_t default_cb,
59                              struct remote_proc **rproc_handle)
60 {
62         struct remote_proc *rproc;
63         int status;
65         if (!rsc_info) {
66                 return RPROC_ERR_PARAM;
67         }
69         /* Initialize environment component */
70         struct metal_init_params init_params = METAL_INIT_DEFAULTS;
71         status = metal_init(&init_params);
72         if (status != RPROC_SUCCESS) {
73                 return status;
74         }
76         rproc = env_allocate_memory(sizeof(struct remote_proc));
77         if (rproc) {
78                 memset(rproc, 0x00, sizeof(struct remote_proc));
79                 /* There can be only one master for remote configuration so use the
80                  * rsvd cpu id for creating hil proc */
81                 rproc->proc = hil_create_proc(HIL_RSVD_CPU_ID);
82                 if (rproc->proc) {
83                         /* Parse resource table */
84                         status =
85                             handle_rsc_table(rproc, rsc_info->rsc_tab,
86                                              rsc_info->size);
87                         if (status == RPROC_SUCCESS) {
88                                 /* Initialize RPMSG "messaging" component */
89                                 *rproc_handle = rproc;
90                                 status =
91                                     rpmsg_init(rproc->proc->cpu_id,
92                                                &rproc->rdev, channel_created,
93                                                channel_destroyed, default_cb,
94                                                RPMSG_MASTER);
95                         } else {
96                                 status = RPROC_ERR_NO_RSC_TABLE;
97                         }
98                 } else {
99                         status = RPROC_ERR_CPU_ID;
100                 }
101         } else {
102                 status = RPROC_ERR_NO_MEM;
103         }
105         /* Cleanup in case of error */
106         if (status != RPROC_SUCCESS) {
107                 *rproc_handle = 0;
108                 (void)remoteproc_resource_deinit(rproc);
109                 return status;
110         }
111         return status;
114 /**
115  * remoteproc_resource_deinit
116  *
117  * Uninitializes resources for remoteproc "remote" configuration.
118  *
119  * @param rproc - pointer to rproc instance
120  *
121  * @param returns - status of function execution
122  *
123  */
125 int remoteproc_resource_deinit(struct remote_proc *rproc)
127         int i = 0;
128         struct proc_vring *vring_hw = 0;
129         if (rproc) {
130                 if (rproc->rdev) {
131                         /* disable IPC interrupts */
132                         if (rproc->proc->ops->reg_ipi_after_deinit) {
133                                 for (i = 0; i < 2; i++) {
134                                         vring_hw =
135                                             &rproc->proc->vdev.vring_info[i];
136                                         rproc->proc->ops->
137                                             reg_ipi_after_deinit(vring_hw);
138                                 }
139                         }
140                         rpmsg_deinit(rproc->rdev);
141                 }
142                 if (rproc->proc) {
143                         hil_delete_proc(rproc->proc);
144                 }
146                 env_free_memory(rproc);
147         }
149         metal_finish();
151         /*
152          * Flush and Invalidate the caches - When the application is built with
153          * Xilinx Standalone BSP, caches are invalidated as part of boot process.
154          * Even if the master boots firmware multiple times without hard reset on
155          * same core, caches are flushed and invalidated at the end of
156          * remoteproc_resource_deinit for this run and caches would be again
157          * invalidated before starting the main thread of the application on next
158          * run to avoid any cache inconsistencies.
159          */
160          env_flush_invalidate_all_caches();
163         return RPROC_SUCCESS;
166 /**
167  * remoteproc_init
168  *
169  * Initializes resources for remoteproc master configuration. Only
170  * remoteproc master applications are allowed to call this function.
171  *
172  * @param fw_name           - name of frimware
173  * @param channel_created   - callback function for channel creation
174  * @param channel_destroyed - callback function for channel deletion
175  * @param default_cb        - default callback for channel I/O
176  * @param rproc_handle      - pointer to new remoteproc instance
177  *
178  * @param returns - status of function execution
179  *
180  */
181 int remoteproc_init(char *fw_name, rpmsg_chnl_cb_t channel_created,
182                     rpmsg_chnl_cb_t channel_destroyed, rpmsg_rx_cb_t default_cb,
183                     struct remote_proc **rproc_handle)
186         struct remote_proc *rproc;
187         struct resource_table *rsc_table;
188         unsigned int fw_addr, fw_size, rsc_size;
189         int status, cpu_id;
191         if (!fw_name) {
192                 return RPROC_ERR_PARAM;
193         }
195         /* Initialize environment component */
196         struct metal_init_params init_params = METAL_INIT_DEFAULTS;
197         status = metal_init(&init_params);
198         if (status != RPROC_SUCCESS) {
199                 return status;
200         }
202         rproc = env_allocate_memory(sizeof(struct remote_proc));
203         if (rproc) {
204                 memset((void *)rproc, 0x00, sizeof(struct remote_proc));
205                 /* Get CPU ID for the given firmware name */
206                 cpu_id = hil_get_cpuforfw(fw_name);
207                 if (cpu_id >= 0) {
208                         /* Create proc instance */
209                         rproc->proc = hil_create_proc(cpu_id);
210                         if (rproc->proc) {
211                                 /* Retrieve firmware attributes */
212                                 status =
213                                     hil_get_firmware(fw_name, &fw_addr,
214                                                      &fw_size);
215                                 if (!status) {
216                                         /* Initialize ELF loader - currently only ELF format is supported */
217                                         rproc->loader =
218                                             remoteproc_loader_init(ELF_LOADER);
219                                         if (rproc->loader) {
220                                                 /* Attach the given firmware with the ELF parser/loader */
221                                                 status =
222                                                     remoteproc_loader_attach_firmware
223                                                     (rproc->loader,
224                                                      (void *)fw_addr);
225                                         } else {
226                                                 status = RPROC_ERR_LOADER;
227                                         }
228                                 }
229                         } else {
230                                 status = RPROC_ERR_NO_MEM;
231                         }
232                 } else {
233                         status = RPROC_ERR_INVLD_FW;
234                 }
235         } else {
236                 status = RPROC_ERR_NO_MEM;
237         }
239         if (!status) {
240                 rproc->role = RPROC_MASTER;
242                 /* Get resource table from firmware */
243                 rsc_table =
244                     remoteproc_loader_retrieve_resource_section(rproc->loader,
245                                                                 &rsc_size);
246                 if (rsc_table) {
247                         /* Parse resource table */
248                         status = handle_rsc_table(rproc, rsc_table, rsc_size);
249                 } else {
250                         status = RPROC_ERR_NO_RSC_TABLE;
251                 }
252         }
254         /* Cleanup in case of error */
255         if (status != RPROC_SUCCESS) {
256                 (void)remoteproc_deinit(rproc);
257                 return status;
258         }
260         rproc->channel_created = channel_created;
261         rproc->channel_destroyed = channel_destroyed;
262         rproc->default_cb = default_cb;
264         *rproc_handle = rproc;
266         return status;
269 /**
270  * remoteproc_deinit
271  *
272  * Uninitializes resources for remoteproc "master" configuration.
273  *
274  * @param rproc - pointer to remote proc instance
275  *
276  * @param returns - status of function execution
277  *
278  */
279 int remoteproc_deinit(struct remote_proc *rproc)
282         if (rproc) {
283                 if (rproc->loader) {
284                         (void)remoteproc_loader_delete(rproc->loader);
285                         rproc->loader = RPROC_NULL;
286                 }
287                 if (rproc->proc) {
288                         hil_delete_proc(rproc->proc);
289                         rproc->proc = RPROC_NULL;
290                 }
291                 env_free_memory(rproc);
292         }
294         metal_finish();
296         return RPROC_SUCCESS;
299 /**
300  * remoteproc_boot
301  *
302  * This function loads the image on the remote processor and starts
303  * its execution from image load address.
304  *
305  * @param rproc - pointer to remoteproc instance to boot
306  *
307  * @param returns - status of function execution
308  */
309 int remoteproc_boot(struct remote_proc *rproc)
312         void *load_addr;
313         int status;
315         if (!rproc) {
316                 return RPROC_ERR_PARAM;
317         }
319         /* Stop the remote CPU */
320         hil_shutdown_cpu(rproc->proc);
322         /* Load the firmware */
323         status = remoteproc_loader_load_remote_firmware(rproc->loader);
324         if (status == RPROC_SUCCESS) {
325                 load_addr = remoteproc_get_load_address(rproc->loader);
326                 if (load_addr != RPROC_ERR_PTR) {
327                         /* Start the remote cpu */
328                         status = hil_boot_cpu(rproc->proc,
329                                               (unsigned int)load_addr);
330                         if (status == RPROC_SUCCESS) {
331                                 /* Wait for remote side to come up. This delay is arbitrary and may
332                                  * need adjustment for different configuration of remote systems */
333                                 env_sleep_msec(RPROC_BOOT_DELAY);
335                                 /* Initialize RPMSG "messaging" component */
337                                 /* It is a work-around to work with remote Linux context. 
338                                    Since the upstream Linux rpmsg implementation always 
339                                    assumes itself to be an rpmsg master, we initialize
340                                    the remote device as an rpmsg master for remote Linux
341                                    configuration only. */
342 #if defined (OPENAMP_REMOTE_LINUX_ENABLE)
343                                 status =
344                                     rpmsg_init(rproc->proc->cpu_id,
345                                                &rproc->rdev,
346                                                rproc->channel_created,
347                                                rproc->channel_destroyed,
348                                                rproc->default_cb, RPMSG_MASTER);
349 #else
350                                 status =
351                                     rpmsg_init(rproc->proc->cpu_id,
352                                                &rproc->rdev,
353                                                rproc->channel_created,
354                                                rproc->channel_destroyed,
355                                                rproc->default_cb, RPMSG_REMOTE);
356 #endif
357                         }
358                 } else {
359                         status = RPROC_ERR_LOADER;
360                 }
361         } else {
362                 status = RPROC_ERR_LOADER;
363         }
365         return status;
368 /**
369  * remoteproc_shutdown
370  *
371  * This function shutdowns the remote execution context
372  *
373  * @param rproc - pointer to remote proc instance to shutdown
374  *
375  * @param returns - status of function execution
376  */
377 int remoteproc_shutdown(struct remote_proc *rproc)
380         if (rproc) {
381                 if (rproc->rdev) {
382                         rpmsg_deinit(rproc->rdev);
383                         rproc->rdev = RPROC_NULL;
384                 }
385                 if (rproc->proc) {
386                         hil_shutdown_cpu(rproc->proc);
387                 }
388         }
390         return RPROC_SUCCESS;