zephyr/subsys/ipc/ipc_service/lib/ipc_rpmsg.c

121 lines
2.8 KiB
C

/*
* Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/ipc/ipc_rpmsg.h>
static void rpmsg_service_unbind(struct rpmsg_endpoint *ep)
{
rpmsg_destroy_ept(ep);
}
static void ns_bind_cb(struct rpmsg_device *rdev, const char *name, uint32_t dest)
{
struct rpmsg_virtio_device *p_rvdev;
struct ipc_rpmsg_instance *instance;
struct ipc_rpmsg_ept *ept;
int err;
p_rvdev = CONTAINER_OF(rdev, struct rpmsg_virtio_device, rdev);
instance = CONTAINER_OF(p_rvdev->shpool, struct ipc_rpmsg_instance, shm_pool);
for (size_t i = 0; i < NUM_ENDPOINTS; i++) {
ept = &instance->endpoint[i];
if (strcmp(name, ept->name) == 0) {
/*
* The destination address is 'dest' so ns_bind_cb() is
* *NOT* called on the REMOTE side. The bound_cb()
* function will eventually take care of notifying the
* REMOTE side if needed.
*/
err = rpmsg_create_ept(&ept->ep, rdev, name, RPMSG_ADDR_ANY,
dest, instance->cb, rpmsg_service_unbind);
if (err != 0) {
return;
}
ept->bound = true;
if (instance->bound_cb) {
instance->bound_cb(ept);
}
}
}
}
int ipc_rpmsg_register_ept(struct ipc_rpmsg_instance *instance, unsigned int role,
struct ipc_rpmsg_ept *ept)
{
struct rpmsg_device *rdev;
if (!instance || !ept) {
return -EINVAL;
}
rdev = rpmsg_virtio_get_rpmsg_device(&instance->rvdev);
if (role == RPMSG_REMOTE) {
/*
* The destination address is RPMSG_ADDR_ANY, this will trigger
* the ns_bind_cb() callback function on the HOST side.
*/
return rpmsg_create_ept(&ept->ep, rdev, ept->name, RPMSG_ADDR_ANY,
RPMSG_ADDR_ANY, instance->cb, rpmsg_service_unbind);
}
return RPMSG_SUCCESS;
}
int ipc_rpmsg_init(struct ipc_rpmsg_instance *instance,
unsigned int role,
unsigned int buffer_size,
struct metal_io_region *shm_io,
struct virtio_device *vdev,
void *shb, size_t size,
rpmsg_ns_bind_cb p_bind_cb)
{
rpmsg_ns_bind_cb bind_cb = p_bind_cb;
if (!instance || !shb) {
return -EINVAL;
}
if (p_bind_cb == NULL) {
bind_cb = ns_bind_cb;
}
if (role == RPMSG_HOST) {
struct rpmsg_virtio_config config = { 0 };
config.h2r_buf_size = (uint32_t) buffer_size;
config.r2h_buf_size = (uint32_t) buffer_size;
rpmsg_virtio_init_shm_pool(&instance->shm_pool, shb, size);
return rpmsg_init_vdev_with_config(&instance->rvdev, vdev, bind_cb,
shm_io, &instance->shm_pool,
&config);
} else {
return rpmsg_init_vdev(&instance->rvdev, vdev, bind_cb, shm_io, NULL);
}
}
int ipc_rpmsg_deinit(struct ipc_rpmsg_instance *instance,
unsigned int role)
{
if (!instance) {
return -EINVAL;
}
rpmsg_deinit_vdev(&instance->rvdev);
if (role == RPMSG_HOST) {
memset(&instance->shm_pool, 0, sizeof(struct rpmsg_virtio_shm_pool));
}
return 0;
}