Adding RPMsg Extension layer implementing zero-copy send and receive.
[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"
60 #include "metal/cache.h"
62 /**
63  * rpmsg_init
64  *
65  * Thus function allocates and initializes the rpmsg driver resources for
66  * given hil_proc. The successful return from this function leaves
67  * fully enabled IPC link.
68  *
69  * @param proc              - pointer to hil_proc
70  * @param rdev              - pointer to newly created remote device
71  * @param channel_created   - callback function for channel creation
72  * @param channel_destroyed - callback function for channel deletion
73  * @param default_cb        - default callback for channel I/O
74  * @param role              - role of the other device, Master or Remote
75  *
76  * @return - status of function execution
77  *
78  */
80 int rpmsg_init(struct hil_proc *proc,
81                struct remote_device **rdev,
82                rpmsg_chnl_cb_t channel_created,
83                rpmsg_chnl_cb_t channel_destroyed,
84                rpmsg_rx_cb_t default_cb, int role)
85 {
86         int status;
88         /* Initialize the remote device for given cpu id */
89         status = rpmsg_rdev_init(proc, rdev, role,
90                                  channel_created,
91                                  channel_destroyed, default_cb);
92         if (status == RPMSG_SUCCESS) {
93                 /* Kick off IPC with the remote device */
94                 status = rpmsg_start_ipc(*rdev);
95         }
97         /* Deinit system in case of error */
98         if (status != RPMSG_SUCCESS) {
99                 rpmsg_deinit(*rdev);
100         }
102         return status;
105 /**
106  * rpmsg_deinit
107  *
108  * Thus function frees rpmsg driver resources for given remote device.
109  *
110  * @param rdev  -  pointer to device to de-init
111  *
112  */
114 void rpmsg_deinit(struct remote_device *rdev)
116         if (rdev) {
117                 rpmsg_rdev_deinit(rdev);
118         }
121 /**
122  * This function sends rpmsg "message" to remote device.
123  *
124  * @param rp_chnl - pointer to rpmsg channel
125  * @param src     - source address of channel
126  * @param dst     - destination address of channel
127  * @param data    - data to transmit
128  * @param size    - size of data
129  * @param wait    - boolean, wait or not for buffer to become
130  *                  available
131  *
132  * @return - status of function execution
133  *
134  */
136 int rpmsg_send_offchannel_raw(struct rpmsg_channel *rp_chnl, uint32_t src,
137                               uint32_t dst, char *data, int size, int wait)
139         struct remote_device *rdev;
140         struct rpmsg_hdr *rp_hdr;
141         void *buffer;
142         unsigned short idx;
143         int tick_count = 0;
144         unsigned long buff_len;
145         int ret;
147         if (!rp_chnl || !data) {
148                 return RPMSG_ERR_PARAM;
149         }
151         /* Get the associated remote device for channel. */
152         rdev = rp_chnl->rdev;
154         /* Validate device state */
155         if (rp_chnl->state != RPMSG_CHNL_STATE_ACTIVE
156             || rdev->state != RPMSG_DEV_STATE_ACTIVE) {
157                 return RPMSG_ERR_DEV_STATE;
158         }
160         if (size > (rpmsg_get_buffer_size(rp_chnl))) {
161                 return RPMSG_ERR_BUFF_SIZE;
162         }
164         /* Lock the device to enable exclusive access to virtqueues */
165         metal_mutex_acquire(&rdev->lock);
166         /* Get rpmsg buffer for sending message. */
167         buffer = rpmsg_get_tx_buffer(rdev, &buff_len, &idx);
168         /* Unlock the device */
169         metal_mutex_release(&rdev->lock);
171         if (!buffer && !wait) {
172                 return RPMSG_ERR_NO_BUFF;
173         }
175         while (!buffer) {
176                 /*
177                  * Wait parameter is true - pool the buffer for
178                  * 15 secs as defined by the APIs.
179                  */
180                 env_sleep_msec(RPMSG_TICKS_PER_INTERVAL);
181                 metal_mutex_acquire(&rdev->lock);
182                 buffer = rpmsg_get_tx_buffer(rdev, &buff_len, &idx);
183                 metal_mutex_release(&rdev->lock);
184                 tick_count += RPMSG_TICKS_PER_INTERVAL;
185                 if (!buffer && (tick_count >=
186                     (RPMSG_TICK_COUNT / RPMSG_TICKS_PER_INTERVAL))) {
187                         return RPMSG_ERR_NO_BUFF;
188                 }
189         }
191         rp_hdr = (struct rpmsg_hdr *)buffer;
193         /* Initialize RPMSG header. */
194         rp_hdr->dst = dst;
195         rp_hdr->src = src;
196         rp_hdr->len = size;
197         rp_hdr->reserved = 0;
199         /* Copy data to rpmsg buffer. */
200         if (rdev->proc->sh_buff.io->mem_flags & METAL_IO_MAPPED)
201                 metal_memcpy_io((void *)RPMSG_LOCATE_DATA(rp_hdr), data, size);
202         else
203                 memcpy((void *)RPMSG_LOCATE_DATA(rp_hdr), data, size);
205         metal_mutex_acquire(&rdev->lock);
207         /* Enqueue buffer on virtqueue. */
208         ret = rpmsg_enqueue_buffer(rdev, buffer, buff_len, idx);
209         RPMSG_ASSERT(ret == VQUEUE_SUCCESS, "FATAL: RPMSG failed to enqueue buffer.\n");
210         /* Let the other side know that there is a job to process. */
211         virtqueue_kick(rdev->tvq);
213         metal_mutex_release(&rdev->lock);
215         return RPMSG_SUCCESS;
218 /**
219  * rpmsg_get_buffer_size
220  *
221  * Returns buffer size available for sending messages.
222  *
223  * @param channel - pointer to rpmsg channel
224  *
225  * @return - buffer size
226  *
227  */
228 int rpmsg_get_buffer_size(struct rpmsg_channel *rp_chnl)
230         struct remote_device *rdev;
231         int length;
233         /* Get associated remote device for channel. */
234         rdev = rp_chnl->rdev;
236         metal_mutex_acquire(&rdev->lock);
238         if (rdev->role == RPMSG_REMOTE) {
239                 /*
240                  * If device role is Remote then buffers are provided by us
241                  * (RPMSG Master), so just provide the macro.
242                  */
243                 length = RPMSG_BUFFER_SIZE - sizeof(struct rpmsg_hdr);
244         } else {
245                 /*
246                  * If other core is Master then buffers are provided by it,
247                  * so get the buffer size from the virtqueue.
248                  */
249                 length =
250                     (int)virtqueue_get_desc_size(rdev->tvq) -
251                     sizeof(struct rpmsg_hdr);
252         }
254         metal_mutex_release(&rdev->lock);
256         return length;
259 void rpmsg_hold_rx_buffer(struct rpmsg_channel *rpdev, void *rxbuf)
261         struct rpmsg_hdr *rp_hdr = NULL;
262         if (!rpdev || !rxbuf)
263             return;
265         rp_hdr = RPMSG_HDR_FROM_BUF(rxbuf);
267         /* set held status to keep buffer */
268         rp_hdr->reserved |= RPMSG_BUF_HELD;
271 void rpmsg_release_rx_buffer(struct rpmsg_channel *rpdev, void *rxbuf)
273         struct rpmsg_hdr *hdr;
274         struct remote_device *rdev;
275         struct rpmsg_hdr_reserved * reserved = NULL;
276         struct metal_io_region *io;
277         unsigned int len;
279         if (!rpdev || !rxbuf)
280             return;
282         rdev = rpdev->rdev;
283         hdr = RPMSG_HDR_FROM_BUF(rxbuf);
285         /* Get the pointer to the reserved field that contains buffer size
286          * and the index */
287         reserved = (struct rpmsg_hdr_reserved*)&hdr->reserved;
288         hdr->reserved &= (~RPMSG_BUF_HELD);
289         len = (unsigned int)virtqueue_get_buffer_length(rdev->rvq,
290                                                 reserved->idx);
292         io = rdev->proc->sh_buff.io;
293         if (io) {
294                 if (! (io->mem_flags & METAL_UNCACHED))
295                         metal_cache_flush(rxbuf, len);
296         }
298         metal_mutex_acquire(&rdev->lock);
300         /* Return used buffer, with total length
301            (header length + buffer size). */
302         rpmsg_return_buffer(rdev, hdr, (unsigned long)len, reserved->idx);
304         metal_mutex_release(&rdev->lock);
307 void *rpmsg_get_tx_payload_buffer(struct rpmsg_channel *rpdev, uint32_t *size,
308                                  int wait)
310         struct rpmsg_hdr *hdr;
311         struct remote_device *rdev;
312         struct rpmsg_hdr_reserved *reserved;
313         unsigned short idx;
314         unsigned long buff_len, tick_count = 0;
316         if (!rpdev || !size)
317                 return NULL;
319         rdev = rpdev->rdev;
321         metal_mutex_acquire(&rdev->lock);
323         /* Get tx buffer from vring */
324         hdr = (struct rpmsg_hdr *) rpmsg_get_tx_buffer(rdev, &buff_len, &idx);
326         metal_mutex_release(&rdev->lock);
328         if (!hdr && !wait) {
329                 return NULL;
330         } else {
331                 while (!hdr) {
332                         /*
333                          * Wait parameter is true - pool the buffer for
334                          * 15 secs as defined by the APIs.
335                          */
336                         env_sleep_msec(RPMSG_TICKS_PER_INTERVAL);
337                         metal_mutex_acquire(&rdev->lock);
338                         hdr = (struct rpmsg_hdr *) rpmsg_get_tx_buffer(rdev, &buff_len, &idx);
339                         metal_mutex_release(&rdev->lock);
340                         tick_count += RPMSG_TICKS_PER_INTERVAL;
341                         if (tick_count >= (RPMSG_TICK_COUNT / RPMSG_TICKS_PER_INTERVAL)) {
342                                         return NULL;
343                         }
344                 }
346                 /* Store the index into the reserved field to be used when sending */
347                 reserved = (struct rpmsg_hdr_reserved*)&hdr->reserved;
348                 reserved->idx = (uint16_t)idx;
350                 /* Actual data buffer size is vring buffer size minus rpmsg header length */
351                 *size = (uint32_t)(buff_len - sizeof(struct rpmsg_hdr));
352                 return (void *)RPMSG_LOCATE_DATA(hdr);
353         }
356 int rpmsg_send_offchannel_nocopy(struct rpmsg_channel *rpdev, uint32_t src,
357                                  uint32_t dst, void *txbuf, int len)
359         struct rpmsg_hdr *hdr;
360         struct remote_device *rdev;
361         struct rpmsg_hdr_reserved * reserved = NULL;
362         int status;
364         if (!rpdev || !txbuf)
365             return RPMSG_ERR_PARAM;
367         rdev = rpdev->rdev;
368         hdr = RPMSG_HDR_FROM_BUF(txbuf);
370         /* Initialize RPMSG header. */
371         hdr->dst = dst;
372         hdr->src = src;
373         hdr->len = len;
374         hdr->flags = 0;
375         hdr->reserved &= (~RPMSG_BUF_HELD);
377         /* Get the pointer to the reserved field that contains buffer size and
378          * the index */
379         reserved = (struct rpmsg_hdr_reserved*)&hdr->reserved;
381         metal_mutex_acquire(&rdev->lock);
383         status = rpmsg_enqueue_buffer(rdev, hdr,
384                         (unsigned long)virtqueue_get_buffer_length(
385                         rdev->tvq, reserved->idx),
386                         reserved->idx);
387         if (status == RPMSG_SUCCESS) {
388                 /* Let the other side know that there is a job to process. */
389                 virtqueue_kick(rdev->tvq);
390         }
392         metal_mutex_release(&rdev->lock);
394         return status;
397 /**
398  * rpmsg_create_ept
399  *
400  * This function creates rpmsg endpoint for the rpmsg channel.
401  *
402  * @param channel - pointer to rpmsg channel
403  * @param cb      - Rx completion call back
404  * @param priv    - private data
405  * @param addr    - endpoint src address
406  *
407  * @return - pointer to endpoint control block
408  *
409  */
410 struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *rp_chnl,
411                                         rpmsg_rx_cb_t cb, void *priv,
412                                         uint32_t addr)
415         struct remote_device *rdev = RPMSG_NULL;
416         struct rpmsg_endpoint *rp_ept = RPMSG_NULL;
418         if (!rp_chnl || !cb) {
419                 return RPMSG_NULL;
420         }
422         rdev = rp_chnl->rdev;
424         rp_ept = _create_endpoint(rdev, cb, priv, addr);
426         if (rp_ept) {
427                 rp_ept->rp_chnl = rp_chnl;
428         }
430         return rp_ept;
433 /**
434  * rpmsg_destroy_ept
435  *
436  * This function deletes rpmsg endpoint and performs cleanup.
437  *
438  * @param rp_ept - pointer to endpoint to destroy
439  *
440  */
441 void rpmsg_destroy_ept(struct rpmsg_endpoint *rp_ept)
444         struct remote_device *rdev;
445         struct rpmsg_channel *rp_chnl;
447         if (!rp_ept)
448                 return;
450         rp_chnl = rp_ept->rp_chnl;
451         rdev = rp_chnl->rdev;
453         _destroy_endpoint(rdev, rp_ept);
456 /**
457  * rpmsg_create_channel
458  *
459  * This function provides facility to create channel dynamically. It sends
460  * Name Service announcement to remote device to let it know about the channel
461  * creation. There must be an active communication among the cores (or atleast
462  * one rpmsg channel must already exist) before using this API to create new
463  * channels.
464  *
465  * @param rdev - pointer to remote device
466  * @param name - channel name
467  *
468  * @return - pointer to new rpmsg channel
469  *
470  */
471 struct rpmsg_channel *rpmsg_create_channel(struct remote_device *rdev,
472                                            char *name)
475         struct rpmsg_channel *rp_chnl;
476         struct rpmsg_endpoint *rp_ept;
478         if (!rdev || !name) {
479                 return RPMSG_NULL;
480         }
482         /* Create channel instance */
483         rp_chnl = _rpmsg_create_channel(rdev, name, RPMSG_NS_EPT_ADDR,
484                                         RPMSG_NS_EPT_ADDR);
485         if (!rp_chnl) {
486                 return RPMSG_NULL;
487         }
489         /* Create default endpoint for the channel */
490         rp_ept = rpmsg_create_ept(rp_chnl, rdev->default_cb, rdev,
491                                   RPMSG_ADDR_ANY);
493         if (!rp_ept) {
494                 _rpmsg_delete_channel(rp_chnl);
495                 return RPMSG_NULL;
496         }
498         rp_chnl->rp_ept = rp_ept;
499         rp_chnl->src = rp_ept->addr;
500         rp_chnl->state = RPMSG_CHNL_STATE_NS;
502         /* Notify the application of channel creation event */
503         if (rdev->channel_created) {
504                 rdev->channel_created(rp_chnl);
505         }
507         /* Send NS announcement to remote processor */
508         rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_CREATE);
510         return rp_chnl;
513 /**
514  * rpmsg_delete_channel
515  *
516  * Deletes the given RPMSG channel. The channel must first be created with the
517  * rpmsg_create_channel API.
518  *
519  * @param rp_chnl - pointer to rpmsg channel to delete
520  *
521  */
522 void rpmsg_delete_channel(struct rpmsg_channel *rp_chnl)
525         struct remote_device *rdev;
527         if (!rp_chnl) {
528                 return;
529         }
531         rdev = rp_chnl->rdev;
533         if (rp_chnl->state > RPMSG_CHNL_STATE_IDLE) {
534                 /* Notify the other processor that channel no longer exists */
535                 rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_DESTROY);
536         }
538         /* Notify channel deletion to application */
539         if (rdev->channel_destroyed) {
540                 rdev->channel_destroyed(rp_chnl);
541         }
543         rpmsg_destroy_ept(rp_chnl->rp_ept);
544         _rpmsg_delete_channel(rp_chnl);
546         return;