update hil_proc not to add new user data struct
[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"
38 #include "metal/alloc.h"
40 /**
41  * remoteproc_resource_init
42  *
43  * Initializes resources for remoteproc remote configuration. Only
44  * remoteproc remote applications are allowed to call this function.
45  *
46  * @param rsc_info          - pointer to resource table info control
47  *                                                        block
48  * @param proc              - pointer to the hil_proc
49  * @param channel_created   - callback function for channel creation
50  * @param channel_destroyed - callback function for channel deletion
51  * @param default_cb        - default callback for channel I/O
52  * @param rproc_handle      - pointer to new remoteproc instance
53  * @param rpmsg_role        - 1 for rpmsg master, or 0 for rpmsg slave
54  *
55  * @param returns - status of function execution
56  *
57  */
58 int remoteproc_resource_init(struct rsc_table_info *rsc_info,
59                              struct hil_proc *proc,
60                              rpmsg_chnl_cb_t channel_created,
61                              rpmsg_chnl_cb_t channel_destroyed,
62                              rpmsg_rx_cb_t default_cb,
63                              struct remote_proc **rproc_handle,
64                              int rpmsg_role)
65 {
67         struct remote_proc *rproc;
68         int status;
69         int remote_rpmsg_role;
71         if (!rsc_info || !proc) {
72                 return RPROC_ERR_PARAM;
73         }
75         rproc = metal_allocate_memory(sizeof(struct remote_proc));
76         if (rproc) {
77                 memset(rproc, 0x00, sizeof(struct remote_proc));
78                 /* There can be only one master for remote configuration so use the
79                  * rsvd cpu id for creating hil proc */
80                 rproc->proc = proc;
81                 status = hil_init_proc(proc);
82                 if (!status) {
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                                 remote_rpmsg_role = (rpmsg_role == RPMSG_MASTER?
91                                                 RPMSG_REMOTE : RPMSG_MASTER);
92                                 status =
93                                     rpmsg_init(proc,
94                                                &rproc->rdev, channel_created,
95                                                channel_destroyed, default_cb,
96                                                remote_rpmsg_role);
97                         } else {
98                                 status = RPROC_ERR_NO_RSC_TABLE;
99                         }
100                 } else {
101                         status = RPROC_ERR_CPU_INIT;
102                 }
103         } else {
104                 status = RPROC_ERR_NO_MEM;
105         }
107         /* Cleanup in case of error */
108         if (status != RPROC_SUCCESS) {
109                 *rproc_handle = 0;
110                 (void)remoteproc_resource_deinit(rproc);
111                 return status;
112         }
113         return status;
116 /**
117  * remoteproc_resource_deinit
118  *
119  * Uninitializes resources for remoteproc "remote" configuration.
120  *
121  * @param rproc - pointer to rproc instance
122  *
123  * @param returns - status of function execution
124  *
125  */
127 int remoteproc_resource_deinit(struct remote_proc *rproc)
129         if (rproc) {
130                 if (rproc->rdev) {
131                         rpmsg_deinit(rproc->rdev);
132                 }
133                 metal_free_memory(rproc);
134         }
136         return RPROC_SUCCESS;
139 /**
140  * remoteproc_init
141  *
142  * Initializes resources for remoteproc master configuration. Only
143  * remoteproc master applications are allowed to call this function.
144  *
145  * @param fw_name           - name of frimware
146  * @param proc              - pointer to hil_proc
147  * @param channel_created   - callback function for channel creation
148  * @param channel_destroyed - callback function for channel deletion
149  * @param default_cb        - default callback for channel I/O
150  * @param rproc_handle      - pointer to new remoteproc instance
151  *
152  * @param returns - status of function execution
153  *
154  */
155 int remoteproc_init(char *fw_name, struct hil_proc *proc,
156                     rpmsg_chnl_cb_t channel_created,
157                     rpmsg_chnl_cb_t channel_destroyed, rpmsg_rx_cb_t default_cb,
158                     struct remote_proc **rproc_handle)
161         struct remote_proc *rproc;
162         struct resource_table *rsc_table;
163         unsigned int fw_size, rsc_size;
164         uintptr_t fw_addr;
165         int status;
167         if (!fw_name) {
168                 return RPROC_ERR_PARAM;
169         }
171         rproc = metal_allocate_memory(sizeof(struct remote_proc));
172         if (rproc) {
173                 memset((void *)rproc, 0x00, sizeof(struct remote_proc));
174                 /* Create proc instance */
175                 status = hil_init_proc(proc);
176                 if (!status) {
177                         /* Retrieve firmware attributes */
178                         status =
179                             hil_get_firmware(fw_name, &fw_addr,
180                                              &fw_size);
181                         if (!status) {
182                                 /* Initialize ELF loader - currently only ELF format is supported */
183                                 rproc->loader =
184                                     remoteproc_loader_init(ELF_LOADER);
185                                 if (rproc->loader) {
186                                         /* Attach the given firmware with the ELF parser/loader */
187                                         status =
188                                             remoteproc_loader_attach_firmware
189                                             (rproc->loader,
190                                              (void *)fw_addr);
191                                 } else {
192                                         status = RPROC_ERR_LOADER;
193                                 }
194                         }
195                 } else {
196                         status = RPROC_ERR_CPU_INIT;
197                 }
198         } else {
199                 status = RPROC_ERR_NO_MEM;
200         }
202         if (!status) {
203                 rproc->role = RPROC_MASTER;
205                 /* Get resource table from firmware */
206                 rsc_table =
207                     remoteproc_loader_retrieve_resource_section(rproc->loader,
208                                                                 &rsc_size);
209                 if (rsc_table) {
210                         /* Parse resource table */
211                         status = handle_rsc_table(rproc, rsc_table, rsc_size);
212                 } else {
213                         status = RPROC_ERR_NO_RSC_TABLE;
214                 }
215         }
217         /* Cleanup in case of error */
218         if (status != RPROC_SUCCESS) {
219                 (void)remoteproc_deinit(rproc);
220                 return status;
221         }
223         rproc->channel_created = channel_created;
224         rproc->channel_destroyed = channel_destroyed;
225         rproc->default_cb = default_cb;
227         *rproc_handle = rproc;
229         return status;
232 /**
233  * remoteproc_deinit
234  *
235  * Uninitializes resources for remoteproc "master" configuration.
236  *
237  * @param rproc - pointer to remote proc instance
238  *
239  * @param returns - status of function execution
240  *
241  */
242 int remoteproc_deinit(struct remote_proc *rproc)
245         if (rproc) {
246                 if (rproc->loader) {
247                         (void)remoteproc_loader_delete(rproc->loader);
248                         rproc->loader = RPROC_NULL;
249                 }
250                 if (rproc->proc) {
251                         hil_delete_proc(rproc->proc);
252                         rproc->proc = RPROC_NULL;
253                 }
254                 metal_free_memory(rproc);
255         }
257         return RPROC_SUCCESS;
260 /**
261  * remoteproc_boot
262  *
263  * This function loads the image on the remote processor and starts
264  * its execution from image load address.
265  *
266  * @param rproc - pointer to remoteproc instance to boot
267  *
268  * @param returns - status of function execution
269  */
270 int remoteproc_boot(struct remote_proc *rproc)
273         void *load_addr;
274         int status;
276         if (!rproc) {
277                 return RPROC_ERR_PARAM;
278         }
280         /* Stop the remote CPU */
281         hil_shutdown_cpu(rproc->proc);
283         /* Load the firmware */
284         status = remoteproc_loader_load_remote_firmware(rproc->loader);
285         if (status == RPROC_SUCCESS) {
286                 load_addr = remoteproc_get_load_address(rproc->loader);
287                 if (load_addr != RPROC_ERR_PTR) {
288                         /* Start the remote cpu */
289                         status = hil_boot_cpu(rproc->proc,
290                                               (uintptr_t)load_addr);
291                         if (status == RPROC_SUCCESS) {
292                                 /* Wait for remote side to come up. This delay is arbitrary and may
293                                  * need adjustment for different configuration of remote systems */
294                                 env_sleep_msec(RPROC_BOOT_DELAY);
296                                 /* Initialize RPMSG "messaging" component */
298                                 /* It is a work-around to work with remote Linux context. 
299                                    Since the upstream Linux rpmsg implementation always 
300                                    assumes itself to be an rpmsg master, we initialize
301                                    the remote device as an rpmsg master for remote Linux
302                                    configuration only. */
303 #if defined (OPENAMP_REMOTE_LINUX_ENABLE)
304                                 status =
305                                     rpmsg_init(rproc->proc,
306                                                &rproc->rdev,
307                                                rproc->channel_created,
308                                                rproc->channel_destroyed,
309                                                rproc->default_cb, RPMSG_MASTER);
310 #else
311                                 status =
312                                     rpmsg_init(rproc->proc,
313                                                &rproc->rdev,
314                                                rproc->channel_created,
315                                                rproc->channel_destroyed,
316                                                rproc->default_cb, RPMSG_REMOTE);
317 #endif
318                         }
319                 } else {
320                         status = RPROC_ERR_LOADER;
321                 }
322         } else {
323                 status = RPROC_ERR_LOADER;
324         }
326         return status;
329 /**
330  * remoteproc_shutdown
331  *
332  * This function shutdowns the remote execution context
333  *
334  * @param rproc - pointer to remote proc instance to shutdown
335  *
336  * @param returns - status of function execution
337  */
338 int remoteproc_shutdown(struct remote_proc *rproc)
341         if (rproc) {
342                 if (rproc->proc) {
343                         hil_shutdown_cpu(rproc->proc);
344                 }
345                 if (rproc->rdev) {
346                         rpmsg_deinit(rproc->rdev);
347                         rproc->rdev = RPROC_NULL;
348                         rproc->proc = RPROC_NULL;
349                 }
350         }
352         return RPROC_SUCCESS;