rpmsg: remote_device: use hil_vdev_notify for remote_dev notify
[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"
61 #include "metal/sleep.h"
63 /**
64  * rpmsg_init
65  *
66  * Thus function allocates and initializes the rpmsg driver resources for
67  * given hil_proc. The successful return from this function leaves
68  * fully enabled IPC link.
69  *
70  * @param proc              - pointer to hil_proc
71  * @param rdev              - pointer to newly created remote device
72  * @param channel_created   - callback function for channel creation
73  * @param channel_destroyed - callback function for channel deletion
74  * @param default_cb        - default callback for channel I/O
75  * @param role              - role of the other device, Master or Remote
76  *
77  * @return - status of function execution
78  *
79  */
81 int rpmsg_init(struct hil_proc *proc,
82                struct remote_device **rdev,
83                rpmsg_chnl_cb_t channel_created,
84                rpmsg_chnl_cb_t channel_destroyed,
85                rpmsg_rx_cb_t default_cb, int role)
86 {
87         int status;
89         /* Initialize the remote device for given cpu id */
90         status = rpmsg_rdev_init(proc, rdev, role,
91                                  channel_created,
92                                  channel_destroyed, default_cb);
93         if (status == RPMSG_SUCCESS) {
94                 /* Kick off IPC with the remote device */
95                 status = rpmsg_start_ipc(*rdev);
96         }
98         /* Deinit system in case of error */
99         if (status != RPMSG_SUCCESS) {
100                 rpmsg_deinit(*rdev);
101         }
103         return status;
106 /**
107  * rpmsg_deinit
108  *
109  * Thus function frees rpmsg driver resources for given remote device.
110  *
111  * @param rdev  -  pointer to device to de-init
112  *
113  */
115 void rpmsg_deinit(struct remote_device *rdev)
117         if (rdev) {
118                 rpmsg_rdev_deinit(rdev);
119         }
122 /**
123  * This function sends rpmsg "message" to remote device.
124  *
125  * @param rp_chnl - pointer to rpmsg channel
126  * @param src     - source address of channel
127  * @param dst     - destination address of channel
128  * @param data    - data to transmit
129  * @param size    - size of data
130  * @param wait    - boolean, wait or not for buffer to become
131  *                  available
132  *
133  * @return - status of function execution
134  *
135  */
137 int rpmsg_send_offchannel_raw(struct rpmsg_channel *rp_chnl, uint32_t src,
138                               uint32_t dst, char *data, int size, int wait)
140         struct remote_device *rdev;
141         struct rpmsg_hdr *rp_hdr;
142         void *buffer;
143         unsigned short idx;
144         int tick_count = 0;
145         unsigned long buff_len;
146         int ret;
148         if (!rp_chnl || !data) {
149                 return RPMSG_ERR_PARAM;
150         }
152         /* Get the associated remote device for channel. */
153         rdev = rp_chnl->rdev;
155         /* Validate device state */
156         if (rp_chnl->state != RPMSG_CHNL_STATE_ACTIVE
157             || rdev->state != RPMSG_DEV_STATE_ACTIVE) {
158                 return RPMSG_ERR_DEV_STATE;
159         }
161         if (size > (rpmsg_get_buffer_size(rp_chnl))) {
162                 return RPMSG_ERR_BUFF_SIZE;
163         }
165         /* Lock the device to enable exclusive access to virtqueues */
166         metal_mutex_acquire(&rdev->lock);
167         /* Get rpmsg buffer for sending message. */
168         buffer = rpmsg_get_tx_buffer(rdev, &buff_len, &idx);
169         /* Unlock the device */
170         metal_mutex_release(&rdev->lock);
172         if (!buffer && !wait) {
173                 return RPMSG_ERR_NO_BUFF;
174         }
176         while (!buffer) {
177                 /*
178                  * Wait parameter is true - pool the buffer for
179                  * 15 secs as defined by the APIs.
180                  */
181                 metal_sleep_usec(RPMSG_TICKS_PER_INTERVAL);
182                 metal_mutex_acquire(&rdev->lock);
183                 buffer = rpmsg_get_tx_buffer(rdev, &buff_len, &idx);
184                 metal_mutex_release(&rdev->lock);
185                 tick_count += RPMSG_TICKS_PER_INTERVAL;
186                 if (!buffer && (tick_count >=
187                     (RPMSG_TICK_COUNT / RPMSG_TICKS_PER_INTERVAL))) {
188                         return RPMSG_ERR_NO_BUFF;
189                 }
190         }
192         rp_hdr = (struct rpmsg_hdr *)buffer;
194         /* Initialize RPMSG header. */
195         rp_hdr->dst = dst;
196         rp_hdr->src = src;
197         rp_hdr->len = size;
198         rp_hdr->reserved = 0;
200         /* Copy data to rpmsg buffer. */
201         if (rdev->proc->sh_buff.io->mem_flags & METAL_IO_MAPPED)
202                 metal_memcpy_io((void *)RPMSG_LOCATE_DATA(rp_hdr), data, size);
203         else
204                 memcpy((void *)RPMSG_LOCATE_DATA(rp_hdr), data, size);
206         metal_mutex_acquire(&rdev->lock);
208         /* Enqueue buffer on virtqueue. */
209         ret = rpmsg_enqueue_buffer(rdev, buffer, buff_len, idx);
210         RPMSG_ASSERT(ret == VQUEUE_SUCCESS, "FATAL: RPMSG failed to enqueue buffer.\n");
211         /* Let the other side know that there is a job to process. */
212         virtqueue_kick(rdev->tvq);
214         metal_mutex_release(&rdev->lock);
216         return RPMSG_SUCCESS;
219 /**
220  * rpmsg_get_buffer_size
221  *
222  * Returns buffer size available for sending messages.
223  *
224  * @param channel - pointer to rpmsg channel
225  *
226  * @return - buffer size
227  *
228  */
229 int rpmsg_get_buffer_size(struct rpmsg_channel *rp_chnl)
231         struct remote_device *rdev;
232         int length;
234         /* Get associated remote device for channel. */
235         rdev = rp_chnl->rdev;
237         metal_mutex_acquire(&rdev->lock);
239         if (rdev->role == RPMSG_REMOTE) {
240                 /*
241                  * If device role is Remote then buffers are provided by us
242                  * (RPMSG Master), so just provide the macro.
243                  */
244                 length = RPMSG_BUFFER_SIZE - sizeof(struct rpmsg_hdr);
245         } else {
246                 /*
247                  * If other core is Master then buffers are provided by it,
248                  * so get the buffer size from the virtqueue.
249                  */
250                 length =
251                     (int)virtqueue_get_desc_size(rdev->tvq) -
252                     sizeof(struct rpmsg_hdr);
253         }
255         metal_mutex_release(&rdev->lock);
257         return length;
260 void rpmsg_hold_rx_buffer(struct rpmsg_channel *rpdev, void *rxbuf)
262         struct rpmsg_hdr *rp_hdr = NULL;
263         if (!rpdev || !rxbuf)
264             return;
266         rp_hdr = RPMSG_HDR_FROM_BUF(rxbuf);
268         /* set held status to keep buffer */
269         rp_hdr->reserved |= RPMSG_BUF_HELD;
272 void rpmsg_release_rx_buffer(struct rpmsg_channel *rpdev, void *rxbuf)
274         struct rpmsg_hdr *hdr;
275         struct remote_device *rdev;
276         struct rpmsg_hdr_reserved * reserved = NULL;
277         struct metal_io_region *io;
278         unsigned int len;
280         if (!rpdev || !rxbuf)
281             return;
283         rdev = rpdev->rdev;
284         hdr = RPMSG_HDR_FROM_BUF(rxbuf);
286         /* Get the pointer to the reserved field that contains buffer size
287          * and the index */
288         reserved = (struct rpmsg_hdr_reserved*)&hdr->reserved;
289         hdr->reserved &= (~RPMSG_BUF_HELD);
290         len = (unsigned int)virtqueue_get_buffer_length(rdev->rvq,
291                                                 reserved->idx);
293         io = rdev->proc->sh_buff.io;
294         if (io) {
295                 if (! (io->mem_flags & METAL_UNCACHED))
296                         metal_cache_flush(rxbuf, len);
297         }
299         metal_mutex_acquire(&rdev->lock);
301         /* Return used buffer, with total length
302            (header length + buffer size). */
303         rpmsg_return_buffer(rdev, hdr, (unsigned long)len, reserved->idx);
305         metal_mutex_release(&rdev->lock);
308 void *rpmsg_get_tx_payload_buffer(struct rpmsg_channel *rpdev, uint32_t *size,
309                                  int wait)
311         struct rpmsg_hdr *hdr;
312         struct remote_device *rdev;
313         struct rpmsg_hdr_reserved *reserved;
314         unsigned short idx;
315         unsigned long buff_len, tick_count = 0;
317         if (!rpdev || !size)
318                 return NULL;
320         rdev = rpdev->rdev;
322         metal_mutex_acquire(&rdev->lock);
324         /* Get tx buffer from vring */
325         hdr = (struct rpmsg_hdr *) rpmsg_get_tx_buffer(rdev, &buff_len, &idx);
327         metal_mutex_release(&rdev->lock);
329         if (!hdr && !wait) {
330                 return NULL;
331         } else {
332                 while (!hdr) {
333                         /*
334                          * Wait parameter is true - pool the buffer for
335                          * 15 secs as defined by the APIs.
336                          */
337                         metal_sleep_usec(RPMSG_TICKS_PER_INTERVAL);
338                         metal_mutex_acquire(&rdev->lock);
339                         hdr = (struct rpmsg_hdr *) rpmsg_get_tx_buffer(rdev, &buff_len, &idx);
340                         metal_mutex_release(&rdev->lock);
341                         tick_count += RPMSG_TICKS_PER_INTERVAL;
342                         if (tick_count >= (RPMSG_TICK_COUNT / RPMSG_TICKS_PER_INTERVAL)) {
343                                         return NULL;
344                         }
345                 }
347                 /* Store the index into the reserved field to be used when sending */
348                 reserved = (struct rpmsg_hdr_reserved*)&hdr->reserved;
349                 reserved->idx = (uint16_t)idx;
351                 /* Actual data buffer size is vring buffer size minus rpmsg header length */
352                 *size = (uint32_t)(buff_len - sizeof(struct rpmsg_hdr));
353                 return (void *)RPMSG_LOCATE_DATA(hdr);
354         }
357 int rpmsg_send_offchannel_nocopy(struct rpmsg_channel *rpdev, uint32_t src,
358                                  uint32_t dst, void *txbuf, int len)
360         struct rpmsg_hdr *hdr;
361         struct remote_device *rdev;
362         struct rpmsg_hdr_reserved * reserved = NULL;
363         int status;
365         if (!rpdev || !txbuf)
366             return RPMSG_ERR_PARAM;
368         rdev = rpdev->rdev;
369         hdr = RPMSG_HDR_FROM_BUF(txbuf);
371         /* Initialize RPMSG header. */
372         hdr->dst = dst;
373         hdr->src = src;
374         hdr->len = len;
375         hdr->flags = 0;
376         hdr->reserved &= (~RPMSG_BUF_HELD);
378         /* Get the pointer to the reserved field that contains buffer size and
379          * the index */
380         reserved = (struct rpmsg_hdr_reserved*)&hdr->reserved;
382         metal_mutex_acquire(&rdev->lock);
384         status = rpmsg_enqueue_buffer(rdev, hdr,
385                         (unsigned long)virtqueue_get_buffer_length(
386                         rdev->tvq, reserved->idx),
387                         reserved->idx);
388         if (status == RPMSG_SUCCESS) {
389                 /* Let the other side know that there is a job to process. */
390                 virtqueue_kick(rdev->tvq);
391         }
393         metal_mutex_release(&rdev->lock);
395         return status;
398 /**
399  * rpmsg_create_ept
400  *
401  * This function creates rpmsg endpoint for the rpmsg channel.
402  *
403  * @param channel - pointer to rpmsg channel
404  * @param cb      - Rx completion call back
405  * @param priv    - private data
406  * @param addr    - endpoint src address
407  *
408  * @return - pointer to endpoint control block
409  *
410  */
411 struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *rp_chnl,
412                                         rpmsg_rx_cb_t cb, void *priv,
413                                         uint32_t addr)
416         struct remote_device *rdev = RPMSG_NULL;
417         struct rpmsg_endpoint *rp_ept = RPMSG_NULL;
419         if (!rp_chnl || !cb) {
420                 return RPMSG_NULL;
421         }
423         rdev = rp_chnl->rdev;
425         rp_ept = _create_endpoint(rdev, cb, priv, addr);
427         if (rp_ept) {
428                 rp_ept->rp_chnl = rp_chnl;
429         }
431         return rp_ept;
434 /**
435  * rpmsg_destroy_ept
436  *
437  * This function deletes rpmsg endpoint and performs cleanup.
438  *
439  * @param rp_ept - pointer to endpoint to destroy
440  *
441  */
442 void rpmsg_destroy_ept(struct rpmsg_endpoint *rp_ept)
445         struct remote_device *rdev;
446         struct rpmsg_channel *rp_chnl;
448         if (!rp_ept)
449                 return;
451         rp_chnl = rp_ept->rp_chnl;
452         rdev = rp_chnl->rdev;
454         _destroy_endpoint(rdev, rp_ept);
457 /**
458  * rpmsg_create_channel
459  *
460  * This function provides facility to create channel dynamically. It sends
461  * Name Service announcement to remote device to let it know about the channel
462  * creation. There must be an active communication among the cores (or atleast
463  * one rpmsg channel must already exist) before using this API to create new
464  * channels.
465  *
466  * @param rdev - pointer to remote device
467  * @param name - channel name
468  *
469  * @return - pointer to new rpmsg channel
470  *
471  */
472 struct rpmsg_channel *rpmsg_create_channel(struct remote_device *rdev,
473                                            char *name)
476         struct rpmsg_channel *rp_chnl;
477         struct rpmsg_endpoint *rp_ept;
479         if (!rdev || !name) {
480                 return RPMSG_NULL;
481         }
483         /* Create channel instance */
484         rp_chnl = _rpmsg_create_channel(rdev, name, RPMSG_NS_EPT_ADDR,
485                                         RPMSG_NS_EPT_ADDR);
486         if (!rp_chnl) {
487                 return RPMSG_NULL;
488         }
490         /* Create default endpoint for the channel */
491         rp_ept = rpmsg_create_ept(rp_chnl, rdev->default_cb, rdev,
492                                   RPMSG_ADDR_ANY);
494         if (!rp_ept) {
495                 _rpmsg_delete_channel(rp_chnl);
496                 return RPMSG_NULL;
497         }
499         rp_chnl->rp_ept = rp_ept;
500         rp_chnl->src = rp_ept->addr;
501         rp_chnl->state = RPMSG_CHNL_STATE_NS;
503         /* Notify the application of channel creation event */
504         if (rdev->channel_created) {
505                 rdev->channel_created(rp_chnl);
506         }
508         /* Send NS announcement to remote processor */
509         rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_CREATE);
511         return rp_chnl;
514 /**
515  * rpmsg_delete_channel
516  *
517  * Deletes the given RPMSG channel. The channel must first be created with the
518  * rpmsg_create_channel API.
519  *
520  * @param rp_chnl - pointer to rpmsg channel to delete
521  *
522  */
523 void rpmsg_delete_channel(struct rpmsg_channel *rp_chnl)
526         struct remote_device *rdev;
528         if (!rp_chnl) {
529                 return;
530         }
532         rdev = rp_chnl->rdev;
534         if (rp_chnl->state > RPMSG_CHNL_STATE_IDLE) {
535                 /* Notify the other processor that channel no longer exists */
536                 rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_DESTROY);
537         }
539         /* Notify channel deletion to application */
540         if (rdev->channel_destroyed) {
541                 rdev->channel_destroyed(rp_chnl);
542         }
544         rpmsg_destroy_ept(rp_chnl->rp_ept);
545         _rpmsg_delete_channel(rp_chnl);
547         return;