0bf3b58fb10872fbf0a952f7c76eb58a7baf549b
[processor-sdk/open-amp.git] / lib / rpmsg / rpmsg.c
1 /*
2  * Copyright (c) 2014, Mentor Graphics Corporation
3  * All rights reserved.
4  * Copyright (c) 2016 Freescale Semiconductor, 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 /**************************************************************************
32  * FILE NAME
33  *
34  *       rpmsg.c
35  *
36  * COMPONENT
37  *
38  *       OpenAMP stack.
39  *
40  * DESCRIPTION
41  *
42  * Main file for the RPMSG driver. This file implements APIs as defined by
43  * RPMSG documentation(Linux docs) and also provides some utility functions.
44  *
45  * RPMSG driver represents each processor/core to which it communicates with
46  * remote_device control block.
47  * Each remote device(processor) defines its role in the communication i.e
48  * whether it is RPMSG Master or Remote. If the device(processor) to which
49  * driver is talking is RPMSG master then RPMSG driver implicitly behaves as
50  * Remote and vice versa.
51  * RPMSG Master is responsible for initiating communications with the Remote
52  * and shared buffers management. Terms remote device/core/proc are used
53  * interchangeably for the processor to which RPMSG driver is communicating
54  * irrespective of the fact whether it is RPMSG Remote or Master.
55  *
56  **************************************************************************/
57 #include <string.h>
58 #include "openamp/rpmsg.h"
59 #include "metal/sys.h"
61 /**
62  * rpmsg_init
63  *
64  * Thus function allocates and initializes the rpmsg driver resources for
65  * given hil_proc. The successful return from this function leaves
66  * fully enabled IPC link.
67  *
68  * @param proc              - pointer to hil_proc
69  * @param rdev              - pointer to newly created remote device
70  * @param channel_created   - callback function for channel creation
71  * @param channel_destroyed - callback function for channel deletion
72  * @param default_cb        - default callback for channel I/O
73  * @param role              - role of the other device, Master or Remote
74  *
75  * @return - status of function execution
76  *
77  */
79 int rpmsg_init(struct hil_proc *proc,
80                struct remote_device **rdev,
81                rpmsg_chnl_cb_t channel_created,
82                rpmsg_chnl_cb_t channel_destroyed,
83                rpmsg_rx_cb_t default_cb, int role)
84 {
85         int status;
87         /* Initialize the remote device for given cpu id */
88         status = rpmsg_rdev_init(proc, rdev, role,
89                                  channel_created,
90                                  channel_destroyed, default_cb);
91         if (status == RPMSG_SUCCESS) {
92                 /* Kick off IPC with the remote device */
93                 status = rpmsg_start_ipc(*rdev);
94         }
96         /* Deinit system in case of error */
97         if (status != RPMSG_SUCCESS) {
98                 rpmsg_deinit(*rdev);
99         }
101         return status;
104 /**
105  * rpmsg_deinit
106  *
107  * Thus function frees rpmsg driver resources for given remote device.
108  *
109  * @param rdev  -  pointer to device to de-init
110  *
111  */
113 void rpmsg_deinit(struct remote_device *rdev)
115         if (rdev) {
116                 rpmsg_rdev_deinit(rdev);
117         }
120 /**
121  * This function sends rpmsg "message" to remote device.
122  *
123  * @param rp_chnl - pointer to rpmsg channel
124  * @param src     - source address of channel
125  * @param dst     - destination address of channel
126  * @param data    - data to transmit
127  * @param size    - size of data
128  * @param wait    - boolean, wait or not for buffer to become
129  *                  available
130  *
131  * @return - status of function execution
132  *
133  */
135 int rpmsg_send_offchannel_raw(struct rpmsg_channel *rp_chnl, uint32_t src,
136                               uint32_t dst, char *data, int size, int wait)
138         struct remote_device *rdev;
139         struct rpmsg_hdr *rp_hdr;
140         void *buffer;
141         unsigned short idx;
142         int tick_count = 0;
143         unsigned long buff_len;
144         int ret;
146         if (!rp_chnl || !data) {
147                 return RPMSG_ERR_PARAM;
148         }
150         /* Get the associated remote device for channel. */
151         rdev = rp_chnl->rdev;
153         /* Validate device state */
154         if (rp_chnl->state != RPMSG_CHNL_STATE_ACTIVE
155             || rdev->state != RPMSG_DEV_STATE_ACTIVE) {
156                 return RPMSG_ERR_DEV_STATE;
157         }
159         if (size > (rpmsg_get_buffer_size(rp_chnl))) {
160                 return RPMSG_ERR_BUFF_SIZE;
161         }
163         /* Lock the device to enable exclusive access to virtqueues */
164         metal_mutex_acquire(&rdev->lock);
165         /* Get rpmsg buffer for sending message. */
166         buffer = rpmsg_get_tx_buffer(rdev, &buff_len, &idx);
167         /* Unlock the device */
168         metal_mutex_release(&rdev->lock);
170         if (!buffer && !wait) {
171                 return RPMSG_ERR_NO_BUFF;
172         }
174         while (!buffer) {
175                 /*
176                  * Wait parameter is true - pool the buffer for
177                  * 15 secs as defined by the APIs.
178                  */
179                 env_sleep_msec(RPMSG_TICKS_PER_INTERVAL);
180                 metal_mutex_acquire(&rdev->lock);
181                 buffer = rpmsg_get_tx_buffer(rdev, &buff_len, &idx);
182                 metal_mutex_release(&rdev->lock);
183                 tick_count += RPMSG_TICKS_PER_INTERVAL;
184                 if (!buffer && (tick_count >=
185                     (RPMSG_TICK_COUNT / RPMSG_TICKS_PER_INTERVAL))) {
186                         return RPMSG_ERR_NO_BUFF;
187                 }
188         }
190         rp_hdr = (struct rpmsg_hdr *)buffer;
192         /* Initialize RPMSG header. */
193         rp_hdr->dst = dst;
194         rp_hdr->src = src;
195         rp_hdr->len = size;
197         /* Copy data to rpmsg buffer. */
198         if (rdev->proc->sh_buff.io->mem_flags & METAL_IO_MAPPED)
199                 metal_memcpy_io((void *)RPMSG_LOCATE_DATA(rp_hdr), data, size);
200         else
201                 memcpy((void *)RPMSG_LOCATE_DATA(rp_hdr), data, size);
203         metal_mutex_acquire(&rdev->lock);
205         /* Enqueue buffer on virtqueue. */
206         ret = rpmsg_enqueue_buffer(rdev, buffer, buff_len, idx);
207         RPMSG_ASSERT(ret == VQUEUE_SUCCESS, "FATAL: RPMSG failed to enqueue buffer.\n");
208         /* Let the other side know that there is a job to process. */
209         virtqueue_kick(rdev->tvq);
211         metal_mutex_release(&rdev->lock);
213         return RPMSG_SUCCESS;
216 /**
217  * rpmsg_get_buffer_size
218  *
219  * Returns buffer size available for sending messages.
220  *
221  * @param channel - pointer to rpmsg channel
222  *
223  * @return - buffer size
224  *
225  */
226 int rpmsg_get_buffer_size(struct rpmsg_channel *rp_chnl)
228         struct remote_device *rdev;
229         int length;
231         /* Get associated remote device for channel. */
232         rdev = rp_chnl->rdev;
234         metal_mutex_acquire(&rdev->lock);
236         if (rdev->role == RPMSG_REMOTE) {
237                 /*
238                  * If device role is Remote then buffers are provided by us
239                  * (RPMSG Master), so just provide the macro.
240                  */
241                 length = RPMSG_BUFFER_SIZE - sizeof(struct rpmsg_hdr);
242         } else {
243                 /*
244                  * If other core is Master then buffers are provided by it,
245                  * so get the buffer size from the virtqueue.
246                  */
247                 length =
248                     (int)virtqueue_get_desc_size(rdev->tvq) -
249                     sizeof(struct rpmsg_hdr);
250         }
252         metal_mutex_release(&rdev->lock);
254         return length;
257 /**
258  * rpmsg_create_ept
259  *
260  * This function creates rpmsg endpoint for the rpmsg channel.
261  *
262  * @param channel - pointer to rpmsg channel
263  * @param cb      - Rx completion call back
264  * @param priv    - private data
265  * @param addr    - endpoint src address
266  *
267  * @return - pointer to endpoint control block
268  *
269  */
270 struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *rp_chnl,
271                                         rpmsg_rx_cb_t cb, void *priv,
272                                         uint32_t addr)
275         struct remote_device *rdev = RPMSG_NULL;
276         struct rpmsg_endpoint *rp_ept = RPMSG_NULL;
278         if (!rp_chnl || !cb) {
279                 return RPMSG_NULL;
280         }
282         rdev = rp_chnl->rdev;
284         rp_ept = _create_endpoint(rdev, cb, priv, addr);
286         if (rp_ept) {
287                 rp_ept->rp_chnl = rp_chnl;
288         }
290         return rp_ept;
293 /**
294  * rpmsg_destroy_ept
295  *
296  * This function deletes rpmsg endpoint and performs cleanup.
297  *
298  * @param rp_ept - pointer to endpoint to destroy
299  *
300  */
301 void rpmsg_destroy_ept(struct rpmsg_endpoint *rp_ept)
304         struct remote_device *rdev;
305         struct rpmsg_channel *rp_chnl;
307         if (!rp_ept)
308                 return;
310         rp_chnl = rp_ept->rp_chnl;
311         rdev = rp_chnl->rdev;
313         _destroy_endpoint(rdev, rp_ept);
316 /**
317  * rpmsg_create_channel
318  *
319  * This function provides facility to create channel dynamically. It sends
320  * Name Service announcement to remote device to let it know about the channel
321  * creation. There must be an active communication among the cores (or atleast
322  * one rpmsg channel must already exist) before using this API to create new
323  * channels.
324  *
325  * @param rdev - pointer to remote device
326  * @param name - channel name
327  *
328  * @return - pointer to new rpmsg channel
329  *
330  */
331 struct rpmsg_channel *rpmsg_create_channel(struct remote_device *rdev,
332                                            char *name)
335         struct rpmsg_channel *rp_chnl;
336         struct rpmsg_endpoint *rp_ept;
338         if (!rdev || !name) {
339                 return RPMSG_NULL;
340         }
342         /* Create channel instance */
343         rp_chnl = _rpmsg_create_channel(rdev, name, RPMSG_NS_EPT_ADDR,
344                                         RPMSG_NS_EPT_ADDR);
345         if (!rp_chnl) {
346                 return RPMSG_NULL;
347         }
349         /* Create default endpoint for the channel */
350         rp_ept = rpmsg_create_ept(rp_chnl, rdev->default_cb, rdev,
351                                   RPMSG_ADDR_ANY);
353         if (!rp_ept) {
354                 _rpmsg_delete_channel(rp_chnl);
355                 return RPMSG_NULL;
356         }
358         rp_chnl->rp_ept = rp_ept;
359         rp_chnl->src = rp_ept->addr;
360         rp_chnl->state = RPMSG_CHNL_STATE_NS;
362         /* Notify the application of channel creation event */
363         if (rdev->channel_created) {
364                 rdev->channel_created(rp_chnl);
365         }
367         /* Send NS announcement to remote processor */
368         rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_CREATE);
370         return rp_chnl;
373 /**
374  * rpmsg_delete_channel
375  *
376  * Deletes the given RPMSG channel. The channel must first be created with the
377  * rpmsg_create_channel API.
378  *
379  * @param rp_chnl - pointer to rpmsg channel to delete
380  *
381  */
382 void rpmsg_delete_channel(struct rpmsg_channel *rp_chnl)
385         struct remote_device *rdev;
387         if (!rp_chnl) {
388                 return;
389         }
391         rdev = rp_chnl->rdev;
393         if (rp_chnl->state > RPMSG_CHNL_STATE_IDLE) {
394                 /* Notify the other processor that channel no longer exists */
395                 rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_DESTROY);
396         }
398         /* Notify channel deletion to application */
399         if (rdev->channel_destroyed) {
400                 rdev->channel_destroyed(rp_chnl);
401         }
403         rpmsg_destroy_ept(rp_chnl->rp_ept);
404         _rpmsg_delete_channel(rp_chnl);
406         return;