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 device ID(cpu id). The successful return from this function leaves
66 * fully enabled IPC link.
67 *
68 * @param pdata - platform data for remote processor
69 * @param dev_id - remote device for which driver is to
70 * be initialized
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(void *pdata, int dev_id, 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(pdata, rdev, dev_id, role, 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;
102 }
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)
114 {
115 if (rdev) {
116 rpmsg_rdev_deinit(rdev);
117 metal_finish();
118 }
119 }
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)
138 {
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;
198 /* Copy data to rpmsg buffer. */
199 memcpy((void *)RPMSG_LOCATE_DATA(rp_hdr), data, size);
201 metal_mutex_acquire(&rdev->lock);
203 /* Enqueue buffer on virtqueue. */
204 ret = rpmsg_enqueue_buffer(rdev, buffer, buff_len, idx);
205 RPMSG_ASSERT(ret == VQUEUE_SUCCESS, "FATAL: RPMSG failed to enqueue buffer.\n");
206 /* Let the other side know that there is a job to process. */
207 virtqueue_kick(rdev->tvq);
209 metal_mutex_release(&rdev->lock);
211 return RPMSG_SUCCESS;
212 }
214 /**
215 * rpmsg_get_buffer_size
216 *
217 * Returns buffer size available for sending messages.
218 *
219 * @param channel - pointer to rpmsg channel
220 *
221 * @return - buffer size
222 *
223 */
224 int rpmsg_get_buffer_size(struct rpmsg_channel *rp_chnl)
225 {
226 struct remote_device *rdev;
227 int length;
229 /* Get associated remote device for channel. */
230 rdev = rp_chnl->rdev;
232 metal_mutex_acquire(&rdev->lock);
234 if (rdev->role == RPMSG_REMOTE) {
235 /*
236 * If device role is Remote then buffers are provided by us
237 * (RPMSG Master), so just provide the macro.
238 */
239 length = RPMSG_BUFFER_SIZE - sizeof(struct rpmsg_hdr);
240 } else {
241 /*
242 * If other core is Master then buffers are provided by it,
243 * so get the buffer size from the virtqueue.
244 */
245 length =
246 (int)virtqueue_get_desc_size(rdev->tvq) -
247 sizeof(struct rpmsg_hdr);
248 }
250 metal_mutex_release(&rdev->lock);
252 return length;
253 }
255 /**
256 * rpmsg_create_ept
257 *
258 * This function creates rpmsg endpoint for the rpmsg channel.
259 *
260 * @param channel - pointer to rpmsg channel
261 * @param cb - Rx completion call back
262 * @param priv - private data
263 * @param addr - endpoint src address
264 *
265 * @return - pointer to endpoint control block
266 *
267 */
268 struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *rp_chnl,
269 rpmsg_rx_cb_t cb, void *priv,
270 uint32_t addr)
271 {
273 struct remote_device *rdev = RPMSG_NULL;
274 struct rpmsg_endpoint *rp_ept = RPMSG_NULL;
276 if (!rp_chnl || !cb) {
277 return RPMSG_NULL;
278 }
280 rdev = rp_chnl->rdev;
282 rp_ept = _create_endpoint(rdev, cb, priv, addr);
284 if (rp_ept) {
285 rp_ept->rp_chnl = rp_chnl;
286 }
288 return rp_ept;
289 }
291 /**
292 * rpmsg_destroy_ept
293 *
294 * This function deletes rpmsg endpoint and performs cleanup.
295 *
296 * @param rp_ept - pointer to endpoint to destroy
297 *
298 */
299 void rpmsg_destroy_ept(struct rpmsg_endpoint *rp_ept)
300 {
302 struct remote_device *rdev;
303 struct rpmsg_channel *rp_chnl;
305 if (!rp_ept)
306 return;
308 rp_chnl = rp_ept->rp_chnl;
309 rdev = rp_chnl->rdev;
311 _destroy_endpoint(rdev, rp_ept);
312 }
314 /**
315 * rpmsg_create_channel
316 *
317 * This function provides facility to create channel dynamically. It sends
318 * Name Service announcement to remote device to let it know about the channel
319 * creation. There must be an active communication among the cores (or atleast
320 * one rpmsg channel must already exist) before using this API to create new
321 * channels.
322 *
323 * @param rdev - pointer to remote device
324 * @param name - channel name
325 *
326 * @return - pointer to new rpmsg channel
327 *
328 */
329 struct rpmsg_channel *rpmsg_create_channel(struct remote_device *rdev,
330 char *name)
331 {
333 struct rpmsg_channel *rp_chnl;
334 struct rpmsg_endpoint *rp_ept;
336 if (!rdev || !name) {
337 return RPMSG_NULL;
338 }
340 /* Create channel instance */
341 rp_chnl = _rpmsg_create_channel(rdev, name, RPMSG_NS_EPT_ADDR,
342 RPMSG_NS_EPT_ADDR);
343 if (!rp_chnl) {
344 return RPMSG_NULL;
345 }
347 /* Create default endpoint for the channel */
348 rp_ept = rpmsg_create_ept(rp_chnl, rdev->default_cb, rdev,
349 RPMSG_ADDR_ANY);
351 if (!rp_ept) {
352 _rpmsg_delete_channel(rp_chnl);
353 return RPMSG_NULL;
354 }
356 rp_chnl->rp_ept = rp_ept;
357 rp_chnl->src = rp_ept->addr;
358 rp_chnl->state = RPMSG_CHNL_STATE_NS;
360 /* Notify the application of channel creation event */
361 if (rdev->channel_created) {
362 rdev->channel_created(rp_chnl);
363 }
365 /* Send NS announcement to remote processor */
366 rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_CREATE);
368 return rp_chnl;
369 }
371 /**
372 * rpmsg_delete_channel
373 *
374 * Deletes the given RPMSG channel. The channel must first be created with the
375 * rpmsg_create_channel API.
376 *
377 * @param rp_chnl - pointer to rpmsg channel to delete
378 *
379 */
380 void rpmsg_delete_channel(struct rpmsg_channel *rp_chnl)
381 {
383 struct remote_device *rdev;
385 if (!rp_chnl) {
386 return;
387 }
389 rdev = rp_chnl->rdev;
391 if (rp_chnl->state > RPMSG_CHNL_STATE_IDLE) {
392 /* Notify the other processor that channel no longer exists */
393 rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_DESTROY);
394 }
396 /* Notify channel deletion to application */
397 if (rdev->channel_destroyed) {
398 rdev->channel_destroyed(rp_chnl);
399 }
401 rpmsg_destroy_ept(rp_chnl->rp_ept);
402 _rpmsg_delete_channel(rp_chnl);
404 return;
405 }