9ddfa93c0edb0718e3d254ef5e68a3de23c1492a
1 /*
2 * Copyright (c) 2014, Mentor Graphics Corporation
3 * All rights reserved.
4 * Copyright (c) 2015 Xilinx, Inc. All rights reserved.
5 * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 * 3. Neither the name of Mentor Graphics Corporation nor the names of its
16 * contributors may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
32 /**************************************************************************
33 * FILE NAME
34 *
35 * remote_device.c
36 *
37 * COMPONENT
38 *
39 * OpenAMP Stack
40 *
41 * DESCRIPTION
42 *
43 * This file provides services to manage the remote devices.It also implements
44 * the interface defined by the virtio and provides few other utility functions.
45 *
46 *
47 **************************************************************************/
49 #include <string.h>
50 #include "openamp/rpmsg.h"
51 #include "openamp/remoteproc.h"
52 #include "metal/utilities.h"
53 #include "metal/alloc.h"
54 #include "metal/atomic.h"
55 #include "metal/cpu.h"
57 /* Macro to initialize vring HW info */
58 #define INIT_VRING_ALLOC_INFO(ring_info,vring_hw) \
59 (ring_info).vaddr = (vring_hw).vaddr; \
60 (ring_info).align = (vring_hw).align; \
61 (ring_info).num_descs = (vring_hw).num_descs
63 /* Local functions */
64 static int rpmsg_rdev_init_channels(struct remote_device *rdev);
66 /* Ops table for virtio device */
67 virtio_dispatch rpmsg_rdev_config_ops = {
68 rpmsg_rdev_create_virtqueues,
69 rpmsg_rdev_get_status,
70 rpmsg_rdev_set_status,
71 rpmsg_rdev_get_feature,
72 rpmsg_rdev_set_feature,
73 rpmsg_rdev_negotiate_feature,
74 rpmsg_rdev_read_config,
75 rpmsg_rdev_write_config,
76 rpmsg_rdev_reset
77 };
79 /**
80 * rpmsg_rdev_init
81 *
82 * This function creates and initializes the remote device. The remote device
83 * encapsulates virtio device.
84 *
85 * @param proc - pointer to hil_proc
86 * @param rdev - pointer to newly created remote device
87 * @param role - role of the other device, Master or Remote
88 * @param channel_created - callback function for channel creation
89 * @param channel_destroyed - callback function for channel deletion
90 * @param default_cb - default callback for channel
91 *
92 * @return - status of function execution
93 *
94 */
95 int rpmsg_rdev_init(struct hil_proc *proc,
96 struct remote_device **rdev, int role,
97 rpmsg_chnl_cb_t channel_created,
98 rpmsg_chnl_cb_t channel_destroyed, rpmsg_rx_cb_t default_cb)
99 {
101 struct remote_device *rdev_loc;
102 struct virtio_device *virt_dev;
103 struct proc_shm *shm;
104 int status;
106 if (!proc)
107 return RPMSG_ERR_PARAM;
108 /* Initialize HIL data structures for given device */
109 if (hil_init_proc(proc))
110 return RPMSG_ERR_DEV_INIT;
112 /* Create software representation of remote processor. */
113 rdev_loc = (struct remote_device *)metal_allocate_memory(sizeof(struct remote_device));
115 if (!rdev_loc) {
116 return RPMSG_ERR_NO_MEM;
117 }
119 memset(rdev_loc, 0x00, sizeof(struct remote_device));
120 metal_mutex_init(&rdev_loc->lock);
122 rdev_loc->proc = proc;
123 rdev_loc->role = role;
124 rdev_loc->channel_created = channel_created;
125 rdev_loc->channel_destroyed = channel_destroyed;
126 rdev_loc->default_cb = default_cb;
128 /* Restrict the ept address - zero address can't be assigned */
129 rdev_loc->bitmap[0] = 1;
131 /* Initialize the virtio device */
132 virt_dev = &rdev_loc->virt_dev;
133 virt_dev->device = proc;
134 virt_dev->func = &rpmsg_rdev_config_ops;
135 if (virt_dev->func->set_features != RPMSG_NULL) {
136 virt_dev->func->set_features(virt_dev, proc->vdev.dfeatures);
137 }
139 if (rdev_loc->role == RPMSG_REMOTE) {
140 /*
141 * Since device is RPMSG Remote so we need to manage the
142 * shared buffers. Create shared memory pool to handle buffers.
143 */
144 shm = hil_get_shm_info(proc);
145 rdev_loc->mem_pool =
146 sh_mem_create_pool(shm->start_addr, shm->size,
147 RPMSG_BUFFER_SIZE);
149 if (!rdev_loc->mem_pool) {
150 return RPMSG_ERR_NO_MEM;
151 }
152 }
154 if (!rpmsg_rdev_remote_ready(rdev_loc))
155 return RPMSG_ERR_DEV_INIT;
157 /* Initialize endpoints list */
158 metal_list_init(&rdev_loc->rp_endpoints);
160 /* Initialize channels for RPMSG Remote */
161 status = rpmsg_rdev_init_channels(rdev_loc);
163 if (status != RPMSG_SUCCESS) {
164 return status;
165 }
167 *rdev = rdev_loc;
169 return RPMSG_SUCCESS;
170 }
172 /**
173 * rpmsg_rdev_deinit
174 *
175 * This function un-initializes the remote device.
176 *
177 * @param rdev - pointer to remote device to deinit.
178 *
179 * @return - none
180 *
181 */
182 void rpmsg_rdev_deinit(struct remote_device *rdev)
183 {
184 struct metal_list *node;
185 struct rpmsg_channel *rp_chnl;
186 struct rpmsg_endpoint *rp_ept;
189 while(!metal_list_is_empty(&rdev->rp_channels)) {
190 node = rdev->rp_channels.next;
191 rp_chnl = metal_container_of(node, struct rpmsg_channel, node);
193 if (rdev->channel_destroyed) {
194 rdev->channel_destroyed(rp_chnl);
195 }
197 if ((rdev->support_ns) && (rdev->role == RPMSG_MASTER)) {
198 rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_DESTROY);
199 }
201 /* Delete default endpoint for channel */
202 if (rp_chnl->rp_ept) {
203 rpmsg_destroy_ept(rp_chnl->rp_ept);
204 }
206 _rpmsg_delete_channel(rp_chnl);
207 }
209 /* Delete name service endpoint */
210 metal_mutex_acquire(&rdev->lock);
211 rp_ept = rpmsg_rdev_get_endpoint_from_addr(rdev, RPMSG_NS_EPT_ADDR);
212 metal_mutex_release(&rdev->lock);
213 if (rp_ept) {
214 _destroy_endpoint(rdev, rp_ept);
215 }
217 if (rdev->rvq) {
218 virtqueue_free(rdev->rvq);
219 }
220 if (rdev->tvq) {
221 virtqueue_free(rdev->tvq);
222 }
223 if (rdev->mem_pool) {
224 sh_mem_delete_pool(rdev->mem_pool);
225 }
226 metal_mutex_deinit(&rdev->lock);
227 if (rdev->proc) {
228 hil_delete_proc(rdev->proc);
229 rdev->proc = 0;
230 }
232 metal_free_memory(rdev);
233 }
235 /**
236 * rpmsg_rdev_get_chnl_from_id
237 *
238 * This function returns channel node based on channel name. It must be called
239 * with mutex locked.
240 *
241 * @param stack - pointer to remote device
242 * @param rp_chnl_id - rpmsg channel name
243 *
244 * @return - rpmsg channel
245 *
246 */
247 struct rpmsg_channel *rpmsg_rdev_get_chnl_from_id(struct remote_device *rdev,
248 char *rp_chnl_id)
249 {
250 struct rpmsg_channel *rp_chnl;
251 struct metal_list *node;
253 metal_list_for_each(&rdev->rp_channels, node) {
254 rp_chnl = metal_container_of(node, struct rpmsg_channel, node);
255 if (strncmp
256 (rp_chnl->name, rp_chnl_id, sizeof(rp_chnl->name))
257 == 0) {
258 return rp_chnl;
259 }
260 }
262 return RPMSG_NULL;
263 }
265 /**
266 * rpmsg_rdev_get_endpoint_from_addr
267 *
268 * This function returns endpoint node based on src address. It must be called
269 * with mutex locked.
270 *
271 * @param rdev - pointer remote device control block
272 * @param addr - src address
273 *
274 * @return - rpmsg endpoint
275 *
276 */
277 struct rpmsg_endpoint *rpmsg_rdev_get_endpoint_from_addr(struct remote_device *rdev,
278 unsigned long addr)
279 {
280 struct rpmsg_endpoint *rp_ept;
281 struct metal_list *node;
283 metal_list_for_each(&rdev->rp_endpoints, node) {
284 rp_ept = metal_container_of(node,
285 struct rpmsg_endpoint, node);
286 if (rp_ept->addr == addr) {
287 return rp_ept;
288 }
289 }
291 return RPMSG_NULL;
292 }
294 /*
295 * rpmsg_rdev_notify
296 *
297 * This function checks whether remote device is up or not. If it is up then
298 * notification is sent based on device role to start IPC.
299 *
300 * @param rdev - pointer to remote device
301 *
302 * @return - status of function execution
303 *
304 */
305 int rpmsg_rdev_notify(struct remote_device *rdev)
306 {
307 int status = RPMSG_SUCCESS;
309 if (rdev->role == RPMSG_REMOTE) {
310 status = hil_get_status(rdev->proc);
312 /*
313 * Let the remote device know that Master is ready for
314 * communication.
315 */
316 if (!status)
317 virtqueue_kick(rdev->rvq);
319 } else {
320 status = hil_set_status(rdev->proc);
321 }
323 if (status == RPMSG_SUCCESS) {
324 rdev->state = RPMSG_DEV_STATE_ACTIVE;
325 }
327 return status;
328 }
330 /**
331 * rpmsg_rdev_init_channels
332 *
333 * This function is only applicable to RPMSG remote. It obtains channel IDs
334 * from the HIL and creates RPMSG channels corresponding to each ID.
335 *
336 * @param rdev - pointer to remote device
337 *
338 * @return - status of function execution
339 *
340 */
341 int rpmsg_rdev_init_channels(struct remote_device *rdev)
342 {
343 struct rpmsg_channel *rp_chnl;
344 struct proc_chnl *chnl_info;
345 int num_chnls, idx;
347 metal_list_init(&rdev->rp_channels);
348 if (rdev->role == RPMSG_MASTER) {
350 chnl_info = hil_get_chnl_info(rdev->proc, &num_chnls);
351 for (idx = 0; idx < num_chnls; idx++) {
353 rp_chnl =
354 _rpmsg_create_channel(rdev, chnl_info[idx].name,
355 0x00, RPMSG_NS_EPT_ADDR);
356 if (!rp_chnl) {
357 return RPMSG_ERR_NO_MEM;
358 }
360 rp_chnl->rp_ept =
361 rpmsg_create_ept(rp_chnl, rdev->default_cb, rdev,
362 RPMSG_ADDR_ANY);
364 if (!rp_chnl->rp_ept) {
365 return RPMSG_ERR_NO_MEM;
366 }
368 rp_chnl->src = rp_chnl->rp_ept->addr;
369 }
370 }
372 return RPMSG_SUCCESS;
373 }
375 /**
376 * check if the remote is ready to start RPMsg communication
377 */
378 int rpmsg_rdev_remote_ready(struct remote_device *rdev)
379 {
380 struct virtio_device *vdev = &rdev->virt_dev;
381 uint8_t status;
382 if (rdev->role == RPMSG_MASTER) {
383 while (1) {
384 /* Busy wait until the remote is ready */
385 status = vdev->func->get_status(vdev);
386 if (status & VIRTIO_CONFIG_STATUS_DRIVER_OK)
387 return true;
388 metal_cpu_yield();
389 }
390 } else {
391 return true;
392 }
393 /* Never come here */
394 return false;
395 }
397 static void rpmsg_memset_io(struct metal_io_region *io, void *dst, int c, size_t count)
398 {
399 if ((io->mem_flags & METAL_IO_MAPPED)) {
400 metal_memset_io(dst, c, count);
401 } else {
402 memset(dst, c, count);
403 }
404 }
406 /**
407 *------------------------------------------------------------------------
408 * The rest of the file implements the virtio device interface as defined
409 * by the virtio.h file.
410 *------------------------------------------------------------------------
411 */
412 int rpmsg_rdev_create_virtqueues(struct virtio_device *dev, int flags, int nvqs,
413 const char *names[], vq_callback * callbacks[],
414 struct virtqueue *vqs_[])
415 {
416 struct remote_device *rdev;
417 struct vring_alloc_info ring_info;
418 struct virtqueue *vqs[RPMSG_MAX_VQ_PER_RDEV];
419 struct proc_vring *vring_table;
420 void *buffer;
421 struct metal_sg sg;
422 int idx, num_vrings, status;
424 (void)flags;
425 (void)vqs_;
427 rdev = (struct remote_device *)dev;
429 /* Get the vring HW info for the given virtio device */
430 vring_table = hil_get_vring_info(&rdev->proc->vdev, &num_vrings);
432 if (num_vrings > nvqs) {
433 return RPMSG_ERR_MAX_VQ;
434 }
436 /* Create virtqueue for each vring. */
437 for (idx = 0; idx < num_vrings; idx++) {
439 INIT_VRING_ALLOC_INFO(ring_info, vring_table[idx]);
441 if (rdev->role == RPMSG_REMOTE) {
442 rpmsg_memset_io(vring_table[idx].io, (void *)ring_info.vaddr, 0x00,
443 vring_size(vring_table[idx].num_descs, vring_table[idx].align));
444 }
446 status =
447 virtqueue_create(dev, idx, (char *)names[idx], &ring_info,
448 callbacks[idx], hil_vring_notify,
449 rdev->proc->sh_buff.io,
450 &vqs[idx]);
452 if (status != RPMSG_SUCCESS) {
453 return status;
454 }
455 }
457 //FIXME - a better way to handle this , tx for master is rx for remote and vice versa.
458 if (rdev->role == RPMSG_MASTER) {
459 rdev->tvq = vqs[0];
460 rdev->rvq = vqs[1];
461 } else {
462 rdev->tvq = vqs[1];
463 rdev->rvq = vqs[0];
464 }
466 if (rdev->role == RPMSG_REMOTE) {
467 sg.io = rdev->proc->sh_buff.io;
468 sg.len = RPMSG_BUFFER_SIZE;
469 for (idx = 0; ((idx < rdev->rvq->vq_nentries)
470 && (idx < rdev->mem_pool->total_buffs / 2));
471 idx++) {
473 /* Initialize TX virtqueue buffers for remote device */
474 buffer = sh_mem_get_buffer(rdev->mem_pool);
476 if (!buffer) {
477 return RPMSG_ERR_NO_BUFF;
478 }
480 sg.virt = buffer;
482 rpmsg_memset_io(sg.io, buffer, 0x00, RPMSG_BUFFER_SIZE);
483 status =
484 virtqueue_add_buffer(rdev->rvq, &sg, 0, 1,
485 buffer);
487 if (status != RPMSG_SUCCESS) {
488 return status;
489 }
490 }
491 }
493 return RPMSG_SUCCESS;
494 }
496 unsigned char rpmsg_rdev_get_status(struct virtio_device *dev)
497 {
498 struct hil_proc *proc = dev->device;
499 struct proc_vdev *pvdev = &proc->vdev;
500 struct fw_rsc_vdev *vdev_rsc = pvdev->vdev_info;
502 if (!vdev_rsc)
503 return -1;
505 return vdev_rsc->status;
506 }
508 void rpmsg_rdev_set_status(struct virtio_device *dev, unsigned char status)
509 {
510 struct hil_proc *proc = dev->device;
511 struct proc_vdev *pvdev = &proc->vdev;
512 struct fw_rsc_vdev *vdev_rsc = pvdev->vdev_info;
514 if (!vdev_rsc)
515 return;
517 vdev_rsc->status = status;
519 atomic_thread_fence(memory_order_seq_cst);
520 }
522 uint32_t rpmsg_rdev_get_feature(struct virtio_device *dev)
523 {
524 return dev->features;
525 }
527 void rpmsg_rdev_set_feature(struct virtio_device *dev, uint32_t feature)
528 {
529 dev->features |= feature;
530 }
532 uint32_t rpmsg_rdev_negotiate_feature(struct virtio_device *dev,
533 uint32_t features)
534 {
535 (void)dev;
536 (void)features;
538 return 0;
539 }
541 /*
542 * Read/write a variable amount from the device specific (ie, network)
543 * configuration region. This region is encoded in the same endian as
544 * the guest.
545 */
546 void rpmsg_rdev_read_config(struct virtio_device *dev, uint32_t offset,
547 void *dst, int length)
548 {
549 (void)dev;
550 (void)offset;
551 (void)dst;
552 (void)length;
554 return;
555 }
557 void rpmsg_rdev_write_config(struct virtio_device *dev, uint32_t offset,
558 void *src, int length)
559 {
560 (void)dev;
561 (void)offset;
562 (void)src;
563 (void)length;
565 return;
566 }
568 void rpmsg_rdev_reset(struct virtio_device *dev)
569 {
570 (void)dev;
572 return;
573 }