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 /**************************************************************************
32 * FILE NAME
33 *
34 * remote_device.c
35 *
36 * COMPONENT
37 *
38 * OpenAMP Stack
39 *
40 * DESCRIPTION
41 *
42 * This file provides services to manage the remote devices.It also implements
43 * the interface defined by the virtio and provides few other utility functions.
44 *
45 *
46 **************************************************************************/
48 #include "openamp/rpmsg.h"
50 /* Macro to initialize vring HW info */
51 #define INIT_VRING_ALLOC_INFO(ring_info,vring_hw) \
52 (ring_info).phy_addr = (vring_hw).phy_addr; \
53 (ring_info).align = (vring_hw).align; \
54 (ring_info).num_descs = (vring_hw).num_descs
56 /* Local functions */
57 static int rpmsg_rdev_init_channels(struct remote_device *rdev);
59 /* Ops table for virtio device */
60 virtio_dispatch rpmsg_rdev_config_ops = {
61 rpmsg_rdev_create_virtqueues,
62 rpmsg_rdev_get_status,
63 rpmsg_rdev_set_status,
64 rpmsg_rdev_get_feature,
65 rpmsg_rdev_set_feature,
66 rpmsg_rdev_negotiate_feature,
67 rpmsg_rdev_read_config,
68 rpmsg_rdev_write_config,
69 rpmsg_rdev_reset
70 };
72 /**
73 * rpmsg_rdev_init
74 *
75 * This function creates and initializes the remote device. The remote device
76 * encapsulates virtio device.
77 *
78 * @param rdev - pointer to newly created remote device
79 * @param dev-id - ID of device to create , remote cpu id
80 * @param role - role of the other device, Master or Remote
81 * @param channel_created - callback function for channel creation
82 * @param channel_destroyed - callback function for channel deletion
83 * @param default_cb - default callback for channel
84 *
85 * @return - status of function execution
86 *
87 */
88 int rpmsg_rdev_init(struct remote_device **rdev, int dev_id, int role,
89 rpmsg_chnl_cb_t channel_created,
90 rpmsg_chnl_cb_t channel_destroyed, rpmsg_rx_cb_t default_cb)
91 {
93 struct remote_device *rdev_loc;
94 struct virtio_device *virt_dev;
95 struct hil_proc *proc;
96 struct proc_shm *shm;
97 int status;
99 /* Initialize HIL data structures for given device */
100 proc = hil_create_proc(dev_id);
102 if (!proc) {
103 return RPMSG_ERR_DEV_ID;
104 }
106 /* Create software representation of remote processor. */
107 rdev_loc =
108 (struct remote_device *)
109 env_allocate_memory(sizeof(struct remote_device));
111 if (!rdev_loc) {
112 return RPMSG_ERR_NO_MEM;
113 }
115 env_memset(rdev_loc, 0x00, sizeof(struct remote_device));
116 status = env_create_mutex(&rdev_loc->lock, 1);
118 if (status != RPMSG_SUCCESS) {
120 /* Cleanup required in case of error is performed by caller */
121 return status;
122 }
124 rdev_loc->proc = proc;
125 rdev_loc->role = role;
126 rdev_loc->channel_created = channel_created;
127 rdev_loc->channel_destroyed = channel_destroyed;
128 rdev_loc->default_cb = default_cb;
130 /* Initialize the virtio device */
131 virt_dev = &rdev_loc->virt_dev;
132 virt_dev->device = proc;
133 virt_dev->func = &rpmsg_rdev_config_ops;
134 if (virt_dev->func->set_features != RPMSG_NULL) {
135 virt_dev->func->set_features(virt_dev, proc->vdev.dfeatures);
136 }
138 if (rdev_loc->role == RPMSG_REMOTE) {
139 /*
140 * Since device is RPMSG Remote so we need to manage the
141 * shared buffers. Create shared memory pool to handle buffers.
142 */
143 shm = hil_get_shm_info(proc);
144 rdev_loc->mem_pool =
145 sh_mem_create_pool(shm->start_addr, shm->size,
146 RPMSG_BUFFER_SIZE);
148 if (!rdev_loc->mem_pool) {
149 return RPMSG_ERR_NO_MEM;
150 }
151 }
153 /* Initialize channels for RPMSG Remote */
154 status = rpmsg_rdev_init_channels(rdev_loc);
156 if (status != RPMSG_SUCCESS) {
157 return status;
158 }
160 *rdev = rdev_loc;
162 return RPMSG_SUCCESS;
163 }
165 /**
166 * rpmsg_rdev_deinit
167 *
168 * This function un-initializes the remote device.
169 *
170 * @param rdev - pointer to remote device to deinit.
171 *
172 * @return - none
173 *
174 */
175 void rpmsg_rdev_deinit(struct remote_device *rdev)
176 {
177 struct llist *rp_chnl_head, *rp_chnl_temp, *node;
178 struct rpmsg_channel *rp_chnl;
180 rp_chnl_head = rdev->rp_channels;
182 while (rp_chnl_head != RPMSG_NULL) {
184 rp_chnl_temp = rp_chnl_head->next;
185 rp_chnl = (struct rpmsg_channel *)rp_chnl_head->data;
187 if (rdev->channel_destroyed) {
188 rdev->channel_destroyed(rp_chnl);
189 }
191 if ((rdev->support_ns) && (rdev->role == RPMSG_MASTER)) {
192 rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_DESTROY);
193 }
195 /* Delete default endpoint for channel */
196 if (rp_chnl->rp_ept) {
197 rpmsg_destroy_ept(rp_chnl->rp_ept);
198 }
200 _rpmsg_delete_channel(rp_chnl);
201 rp_chnl_head = rp_chnl_temp;
202 }
204 /* Delete name service endpoint */
205 node = rpmsg_rdev_get_endpoint_from_addr(rdev, RPMSG_NS_EPT_ADDR);
206 if (node) {
207 _destroy_endpoint(rdev, (struct rpmsg_endpoint *)node->data);
208 }
210 if (rdev->rvq) {
211 virtqueue_free(rdev->rvq);
212 }
213 if (rdev->tvq) {
214 virtqueue_free(rdev->tvq);
215 }
216 if (rdev->mem_pool) {
217 sh_mem_delete_pool(rdev->mem_pool);
218 }
219 if (rdev->lock) {
220 env_delete_mutex(rdev->lock);
221 }
223 env_free_memory(rdev);
224 }
226 /**
227 * rpmsg_rdev_get_chnl_node_from_id
228 *
229 * This function returns channel node based on channel name.
230 *
231 * @param stack - pointer to remote device
232 * @param rp_chnl_id - rpmsg channel name
233 *
234 * @return - channel node
235 *
236 */
237 struct llist *rpmsg_rdev_get_chnl_node_from_id(struct remote_device *rdev,
238 char *rp_chnl_id)
239 {
240 struct rpmsg_channel *rp_chnl;
241 struct llist *rp_chnl_head;
243 rp_chnl_head = rdev->rp_channels;
245 env_lock_mutex(rdev->lock);
246 while (rp_chnl_head) {
247 rp_chnl = (struct rpmsg_channel *)rp_chnl_head->data;
248 if (env_strncmp
249 (rp_chnl->name, rp_chnl_id, sizeof(rp_chnl->name))
250 == 0) {
251 env_unlock_mutex(rdev->lock);
252 return rp_chnl_head;
253 }
254 rp_chnl_head = rp_chnl_head->next;
255 }
256 env_unlock_mutex(rdev->lock);
258 return RPMSG_NULL;
259 }
261 /**
262 * rpmsg_rdev_get_chnl_from_addr
263 *
264 * This function returns channel node based on src/dst address.
265 *
266 * @param rdev - pointer remote device control block
267 * @param addr - src/dst address
268 *
269 * @return - channel node
270 *
271 */
272 struct llist *rpmsg_rdev_get_chnl_from_addr(struct remote_device *rdev,
273 unsigned long addr)
274 {
275 struct rpmsg_channel *rp_chnl;
276 struct llist *rp_chnl_head;
278 rp_chnl_head = rdev->rp_channels;
280 env_lock_mutex(rdev->lock);
281 while (rp_chnl_head) {
282 rp_chnl = (struct rpmsg_channel *)rp_chnl_head->data;
283 if ((rp_chnl->src == addr) || (rp_chnl->dst == addr)) {
284 env_unlock_mutex(rdev->lock);
285 return rp_chnl_head;
286 }
287 rp_chnl_head = rp_chnl_head->next;
288 }
289 env_unlock_mutex(rdev->lock);
291 return RPMSG_NULL;
292 }
294 /**
295 * rpmsg_rdev_get_endpoint_from_addr
296 *
297 * This function returns endpoint node based on src address.
298 *
299 * @param rdev - pointer remote device control block
300 * @param addr - src address
301 *
302 * @return - endpoint node
303 *
304 */
305 struct llist *rpmsg_rdev_get_endpoint_from_addr(struct remote_device *rdev,
306 unsigned long addr)
307 {
308 struct llist *rp_ept_lut_head;
310 rp_ept_lut_head = rdev->rp_endpoints;
312 env_lock_mutex(rdev->lock);
313 while (rp_ept_lut_head) {
314 struct rpmsg_endpoint *rp_ept =
315 (struct rpmsg_endpoint *)rp_ept_lut_head->data;
316 if (rp_ept->addr == addr) {
317 env_unlock_mutex(rdev->lock);
318 return rp_ept_lut_head;
319 }
320 rp_ept_lut_head = rp_ept_lut_head->next;
321 }
322 env_unlock_mutex(rdev->lock);
324 return RPMSG_NULL;
325 }
327 /*
328 * rpmsg_rdev_notify
329 *
330 * This function checks whether remote device is up or not. If it is up then
331 * notification is sent based on device role to start IPC.
332 *
333 * @param rdev - pointer to remote device
334 *
335 * @return - status of function execution
336 *
337 */
338 int rpmsg_rdev_notify(struct remote_device *rdev)
339 {
340 int status = RPMSG_SUCCESS;
342 if (rdev->role == RPMSG_REMOTE) {
343 status = hil_get_status(rdev->proc);
345 /*
346 * Let the remote device know that Master is ready for
347 * communication.
348 */
349 if (!status)
350 virtqueue_kick(rdev->rvq);
352 } else {
353 status = hil_set_status(rdev->proc);
354 }
356 if (status == RPMSG_SUCCESS) {
357 rdev->state = RPMSG_DEV_STATE_ACTIVE;
358 }
360 return status;
361 }
363 /**
364 * rpmsg_rdev_init_channels
365 *
366 * This function is only applicable to RPMSG remote. It obtains channel IDs
367 * from the HIL and creates RPMSG channels corresponding to each ID.
368 *
369 * @param rdev - pointer to remote device
370 *
371 * @return - status of function execution
372 *
373 */
374 int rpmsg_rdev_init_channels(struct remote_device *rdev)
375 {
376 struct rpmsg_channel *rp_chnl;
377 struct proc_chnl *chnl_info;
378 int num_chnls, idx;
380 if (rdev->role == RPMSG_MASTER) {
382 chnl_info = hil_get_chnl_info(rdev->proc, &num_chnls);
383 for (idx = 0; idx < num_chnls; idx++) {
385 rp_chnl =
386 _rpmsg_create_channel(rdev, chnl_info[idx].name,
387 0x00, RPMSG_NS_EPT_ADDR);
388 if (!rp_chnl) {
389 return RPMSG_ERR_NO_MEM;
390 }
392 rp_chnl->rp_ept =
393 rpmsg_create_ept(rp_chnl, rdev->default_cb, rdev,
394 RPMSG_ADDR_ANY);
396 if (!rp_chnl->rp_ept) {
397 return RPMSG_ERR_NO_MEM;
398 }
400 rp_chnl->src = rp_chnl->rp_ept->addr;
401 }
402 }
404 return RPMSG_SUCCESS;
405 }
407 /**
408 *------------------------------------------------------------------------
409 * The rest of the file implements the virtio device interface as defined
410 * by the virtio.h file.
411 *------------------------------------------------------------------------
412 */
413 int rpmsg_rdev_create_virtqueues(struct virtio_device *dev, int flags, int nvqs,
414 const char *names[], vq_callback * callbacks[],
415 struct virtqueue *vqs_[])
416 {
417 struct remote_device *rdev;
418 struct vring_alloc_info ring_info;
419 struct virtqueue *vqs[RPMSG_MAX_VQ_PER_RDEV];
420 struct proc_vring *vring_table;
421 void *buffer;
422 struct llist node;
423 int idx, num_vrings, status;
425 rdev = (struct remote_device *)dev;
427 /* Get the vring HW info for the given virtio device */
428 vring_table = hil_get_vring_info(&rdev->proc->vdev, &num_vrings);
430 if (num_vrings > nvqs) {
431 return RPMSG_ERR_MAX_VQ;
432 }
434 /* Create virtqueue for each vring. */
435 for (idx = 0; idx < num_vrings; idx++) {
437 INIT_VRING_ALLOC_INFO(ring_info, vring_table[idx]);
439 if (rdev->role == RPMSG_REMOTE) {
440 env_memset((void *)ring_info.phy_addr, 0x00,
441 vring_size(vring_table[idx].num_descs,
442 vring_table[idx].align));
443 }
445 status =
446 virtqueue_create(dev, idx, (char *)names[idx], &ring_info,
447 callbacks[idx], hil_vring_notify,
448 &vqs[idx]);
450 if (status != RPMSG_SUCCESS) {
451 return status;
452 }
453 }
455 //FIXME - a better way to handle this , tx for master is rx for remote and vice versa.
456 if (rdev->role == RPMSG_MASTER) {
457 rdev->tvq = vqs[0];
458 rdev->rvq = vqs[1];
459 } else {
460 rdev->tvq = vqs[1];
461 rdev->rvq = vqs[0];
462 }
464 if (rdev->role == RPMSG_REMOTE) {
465 for (idx = 0; ((idx < rdev->rvq->vq_nentries)
466 && (idx < rdev->mem_pool->total_buffs / 2));
467 idx++) {
469 /* Initialize TX virtqueue buffers for remote device */
470 buffer = sh_mem_get_buffer(rdev->mem_pool);
472 if (!buffer) {
473 return RPMSG_ERR_NO_BUFF;
474 }
476 node.data = buffer;
477 node.attr = RPMSG_BUFFER_SIZE;
478 node.next = RPMSG_NULL;
480 env_memset(buffer, 0x00, RPMSG_BUFFER_SIZE);
481 status =
482 virtqueue_add_buffer(rdev->rvq, &node, 0, 1,
483 buffer);
485 if (status != RPMSG_SUCCESS) {
486 return status;
487 }
488 }
489 }
491 return RPMSG_SUCCESS;
492 }
494 unsigned char rpmsg_rdev_get_status(struct virtio_device *dev)
495 {
496 return 0;
497 }
499 void rpmsg_rdev_set_status(struct virtio_device *dev, unsigned char status)
500 {
502 }
504 uint32_t rpmsg_rdev_get_feature(struct virtio_device *dev)
505 {
506 return dev->features;
507 }
509 void rpmsg_rdev_set_feature(struct virtio_device *dev, uint32_t feature)
510 {
511 dev->features |= feature;
512 }
514 uint32_t rpmsg_rdev_negotiate_feature(struct virtio_device *dev,
515 uint32_t features)
516 {
517 return 0;
518 }
520 /*
521 * Read/write a variable amount from the device specific (ie, network)
522 * configuration region. This region is encoded in the same endian as
523 * the guest.
524 */
525 void rpmsg_rdev_read_config(struct virtio_device *dev, uint32_t offset,
526 void *dst, int length)
527 {
528 return;
529 }
531 void rpmsg_rdev_write_config(struct virtio_device *dev, uint32_t offset,
532 void *src, int length)
533 {
534 return;
535 }
537 void rpmsg_rdev_reset(struct virtio_device *dev)
538 {
539 return;
540 }