Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

remoteproc_virtio: optimize the remoteproc virtio transport layer #489

Merged
merged 1 commit into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
73 changes: 70 additions & 3 deletions lib/include/openamp/rpmsg_virtio.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,43 +118,99 @@ __deprecated static inline int deprecated_rpmsg_slave(void)
return RPMSG_REMOTE;
}

/**
* @brief Get rpmsg virtio device role.
*
* @param rvdev Pointer to rpmsg virtio device.
*
* @return RPMSG_REMOTE or RPMSG_HOST
*/
static inline unsigned int
rpmsg_virtio_get_role(struct rpmsg_virtio_device *rvdev)
{
return rvdev->vdev->role;
}

/**
* @brief Set rpmsg virtio device status.
*
* @param rvdev Pointer to rpmsg virtio device.
* @param status Value to be set as rpmsg virtio device status.
*/
static inline void rpmsg_virtio_set_status(struct rpmsg_virtio_device *rvdev,
uint8_t status)
{
rvdev->vdev->func->set_status(rvdev->vdev, status);
}

/**
* @brief Retrieve rpmsg virtio device status.
*
* @param rvdev Pointer to rpmsg virtio device.
*
* @return The rpmsg virtio device status.
*/
static inline uint8_t rpmsg_virtio_get_status(struct rpmsg_virtio_device *rvdev)
{
return rvdev->vdev->func->get_status(rvdev->vdev);
}

/**
* @brief Get the rpmsg virtio device features.
*
* @param rvdev Pointer to the rpmsg virtio device.
*
* @return The features supported by both the rpmsg driver and rpmsg device.
*/
static inline uint32_t
rpmsg_virtio_get_features(struct rpmsg_virtio_device *rvdev)
{
return rvdev->vdev->func->get_features(rvdev->vdev);
}

/**
* @brief Retrieve configuration data from the rpmsg virtio device.
*
* @param rvdev Pointer to the rpmsg virtio device.
* @param offset Offset of the data within the configuration area.
* @param dst Address of the buffer that will hold the data.
* @param length Length of the data to be retrieved.
*/
static inline void
rpmsg_virtio_read_config(struct rpmsg_virtio_device *rvdev,
uint32_t offset, void *dst, int length)
{
rvdev->vdev->func->read_config(rvdev->vdev, offset, dst, length);
}

/**
* @brief Write configuration data to the rpmsg virtio device.
*
* @param rvdev Pointer to the rpmsg virtio device.
* @param offset Offset of the data within the configuration area.
* @param src Address of the buffer that holds the data to write.
* @param length Length of the data to be written.
*
* @return 0 on success, otherwise error code.
*/
static inline void
rpmsg_virtio_write_config(struct rpmsg_virtio_device *rvdev,
uint32_t offset, void *dst, int length)
uint32_t offset, void *src, int length)
{
rvdev->vdev->func->write_config(rvdev->vdev, offset, dst, length);
rvdev->vdev->func->write_config(rvdev->vdev, offset, src, length);
}

/**
* @brief Create the rpmsg virtio device virtqueue.
*
* @param rvdev Pointer to the rpmsg virtio device.
* @param flags Create flag.
* @param nvqs The virtqueue number.
* @param names Virtqueue names.
* @param callbacks Virtqueue callback functions.
*
* @return 0 on success, otherwise error code.
*/
static inline int
rpmsg_virtio_create_virtqueues(struct rpmsg_virtio_device *rvdev,
int flags, unsigned int nvqs,
Expand All @@ -166,7 +222,18 @@ rpmsg_virtio_create_virtqueues(struct rpmsg_virtio_device *rvdev,
}

/**
* @brief Get rpmsg virtio Tx buffer size
* @brief Delete the virtqueues created in rpmsg_virtio_create_virtqueues()
*
* @param rvdev Pointer to the rpmsg virtio device
*/
static inline void
arnopo marked this conversation as resolved.
Show resolved Hide resolved
rpmsg_virtio_delete_virtqueues(struct rpmsg_virtio_device *rvdev)
{
virtio_delete_virtqueues(rvdev->vdev);
arnopo marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* @brief Get rpmsg virtio buffer size
*
* @param rdev Pointer to the rpmsg device
*
Expand Down
130 changes: 91 additions & 39 deletions lib/remoteproc/remoteproc_virtio.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,89 @@
#include <metal/utilities.h>
#include <metal/alloc.h>

static void rproc_virtio_delete_virtqueues(struct virtio_device *vdev)
{
struct virtio_vring_info *vring_info;
unsigned int i;

if (!vdev->vrings_info)
return;

for (i = 0; i < vdev->vrings_num; i++) {
vring_info = &vdev->vrings_info[i];
if (vring_info->vq)
virtqueue_free(vring_info->vq);
}
}

static int rproc_virtio_create_virtqueue(struct virtio_device *vdev,
unsigned int flags,
unsigned int idx,
const char *name,
vq_callback callback)
{
struct virtio_vring_info *vring_info;
struct vring_alloc_info *vring_alloc;
int ret;
(void)flags;

/* Get the vring information */
vring_info = &vdev->vrings_info[idx];
vring_alloc = &vring_info->info;

/* Fail if the virtqueue has already been created */
if (vring_info->vq)
return ERROR_VQUEUE_INVLD_PARAM;

/* Alloc the virtqueue and init it */
vring_info->vq = virtqueue_allocate(vring_alloc->num_descs);
if (!vring_info->vq)
return ERROR_NO_MEM;

#ifndef VIRTIO_DEVICE_ONLY
if (vdev->role == VIRTIO_DEV_DRIVER) {
size_t offset = metal_io_virt_to_offset(vring_info->io, vring_alloc->vaddr);
size_t size = vring_size(vring_alloc->num_descs, vring_alloc->align);

metal_io_block_set(vring_info->io, offset, 0, size);
arnopo marked this conversation as resolved.
Show resolved Hide resolved
}
#endif
ret = virtqueue_create(vdev, idx, name, vring_alloc, callback,
vdev->func->notify, vring_info->vq);
if (ret)
return ret;

return 0;
}

static int rproc_virtio_create_virtqueues(struct virtio_device *vdev,
unsigned int flags,
unsigned int nvqs,
const char *names[],
vq_callback callbacks[],
void *callback_args[])
{
unsigned int i;
int ret;
(void)callback_args;

arnopo marked this conversation as resolved.
Show resolved Hide resolved
/* Check virtqueue numbers and the vrings_info */
if (nvqs > vdev->vrings_num || !vdev || !vdev->vrings_info)
return ERROR_VQUEUE_INVLD_PARAM;

/* set the notification id for vrings */
for (i = 0; i < nvqs; i++) {
ret = rproc_virtio_create_virtqueue(vdev, flags, i, names[i], callbacks[i]);
if (ret)
goto err;
}
return 0;

err:
rproc_virtio_delete_virtqueues(vdev);
return ret;
}

arnopo marked this conversation as resolved.
Show resolved Hide resolved
static void rproc_virtio_virtqueue_notify(struct virtqueue *vq)
{
struct remoteproc_virtio *rpvdev;
Expand Down Expand Up @@ -198,6 +281,8 @@ static void rproc_virtio_reset_device(struct virtio_device *vdev)
#endif

static const struct virtio_dispatch remoteproc_virtio_dispatch_funcs = {
.create_virtqueues = rproc_virtio_create_virtqueues,
.delete_virtqueues = rproc_virtio_delete_virtqueues,
.get_status = rproc_virtio_get_status,
.get_features = rproc_virtio_get_features,
.read_config = rproc_virtio_read_config,
Expand Down Expand Up @@ -229,46 +314,28 @@ rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid,
struct fw_rsc_vdev *vdev_rsc = rsc;
struct virtio_device *vdev;
unsigned int num_vrings = vdev_rsc->num_of_vrings;
unsigned int i;

rpvdev = metal_allocate_memory(sizeof(*rpvdev));
if (!rpvdev)
return NULL;
vrings_info = metal_allocate_memory(sizeof(*vrings_info) * num_vrings);
if (!vrings_info)
goto err0;
goto err;
memset(rpvdev, 0, sizeof(*rpvdev));
memset(vrings_info, 0, sizeof(*vrings_info) * num_vrings);
vdev = &rpvdev->vdev;

for (i = 0; i < num_vrings; i++) {
struct virtqueue *vq;
#ifndef VIRTIO_DEVICE_ONLY
struct fw_rsc_vdev_vring *vring_rsc;
#endif
unsigned int num_extra_desc = 0;

#ifndef VIRTIO_DEVICE_ONLY
vring_rsc = &vdev_rsc->vring[i];
if (role == VIRTIO_DEV_DRIVER) {
num_extra_desc = vring_rsc->num;
}
#endif
vq = virtqueue_allocate(num_extra_desc);
if (!vq)
goto err1;
vrings_info[i].vq = vq;
}

/* Initialize the remoteproc virtio */
rpvdev->notify = notify;
rpvdev->priv = priv;
vdev->vrings_info = vrings_info;
/* Assuming the shared memory has been mapped and registered if
* necessary
*/
rpvdev->vdev_rsc = vdev_rsc;
rpvdev->vdev_rsc_io = rsc_io;

/* Initialize the virtio device */
vdev = &rpvdev->vdev;
vdev->vrings_info = vrings_info;
vdev->notifyid = notifyid;
vdev->id.device = vdev_rsc->id;
vdev->role = role;
Expand All @@ -285,33 +352,18 @@ rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid,
#endif

return &rpvdev->vdev;

err1:
for (i = 0; i < num_vrings; i++) {
if (vrings_info[i].vq)
metal_free_memory(vrings_info[i].vq);
}
metal_free_memory(vrings_info);
err0:
err:
metal_free_memory(rpvdev);
return NULL;
}

void rproc_virtio_remove_vdev(struct virtio_device *vdev)
{
struct remoteproc_virtio *rpvdev;
unsigned int i;

if (!vdev)
return;
rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev);
for (i = 0; i < vdev->vrings_num; i++) {
struct virtqueue *vq;

vq = vdev->vrings_info[i].vq;
if (vq)
metal_free_memory(vq);
}
if (vdev->vrings_info)
metal_free_memory(vdev->vrings_info);
metal_free_memory(rpvdev);
Expand Down
31 changes: 25 additions & 6 deletions lib/rpmsg/rpmsg_virtio.c
Original file line number Diff line number Diff line change
Expand Up @@ -870,8 +870,6 @@ int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev,
vq_names[1] = "tx_vq";
callback[0] = rpmsg_virtio_rx_callback;
callback[1] = rpmsg_virtio_tx_callback;
rvdev->rvq = vdev->vrings_info[0].vq;
rvdev->svq = vdev->vrings_info[1].vq;
}
#endif /*!VIRTIO_DEVICE_ONLY*/

Expand All @@ -882,8 +880,6 @@ int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev,
vq_names[1] = "rx_vq";
callback[0] = rpmsg_virtio_tx_callback;
callback[1] = rpmsg_virtio_rx_callback;
rvdev->rvq = vdev->vrings_info[1].vq;
rvdev->svq = vdev->vrings_info[0].vq;
}
#endif /*!VIRTIO_DRIVER_ONLY*/
rvdev->shbuf_io = shm_io;
Expand All @@ -895,6 +891,21 @@ int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev,
if (status != RPMSG_SUCCESS)
return status;

/* Create virtqueue success, assign back the virtqueue */
#ifndef VIRTIO_DEVICE_ONLY
if (role == RPMSG_HOST) {
rvdev->rvq = vdev->vrings_info[0].vq;
rvdev->svq = vdev->vrings_info[1].vq;
}
#endif /*!VIRTIO_DEVICE_ONLY*/

#ifndef VIRTIO_DRIVER_ONLY
if (role == RPMSG_REMOTE) {
rvdev->rvq = vdev->vrings_info[1].vq;
rvdev->svq = vdev->vrings_info[0].vq;
}
#endif /*!VIRTIO_DRIVER_ONLY*/

/*
* Suppress "tx-complete" interrupts
* since send method use busy loop when buffer pool exhaust
Expand Down Expand Up @@ -922,7 +933,8 @@ int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev,
rvdev->config.r2h_buf_size);

if (!buffer) {
return RPMSG_ERR_NO_BUFF;
status = RPMSG_ERR_NO_BUFF;
goto err;
}

vqbuf.buf = buffer;
Expand All @@ -936,7 +948,7 @@ int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev,
buffer);

if (status != RPMSG_SUCCESS) {
return status;
goto err;
}
}
}
Expand All @@ -960,7 +972,13 @@ int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev,
rpmsg_virtio_set_status(rvdev, VIRTIO_CONFIG_STATUS_DRIVER_OK);
#endif /*!VIRTIO_DEVICE_ONLY*/

return RPMSG_SUCCESS;

#ifndef VIRTIO_DEVICE_ONLY
err:
arnopo marked this conversation as resolved.
Show resolved Hide resolved
rpmsg_virtio_delete_virtqueues(rvdev);
return status;
#endif /*!VIRTIO_DEVICE_ONLY*/
}

void rpmsg_deinit_vdev(struct rpmsg_virtio_device *rvdev)
Expand All @@ -980,6 +998,7 @@ void rpmsg_deinit_vdev(struct rpmsg_virtio_device *rvdev)
rvdev->rvq = 0;
rvdev->svq = 0;

rpmsg_virtio_delete_virtqueues(rvdev);
arnopo marked this conversation as resolved.
Show resolved Hide resolved
metal_mutex_deinit(&rdev->lock);
}
}