Skip to content

Commit

Permalink
remoteproc_virtio: optimize the remoteproc virtio transport layer
Browse files Browse the repository at this point in the history
1. Implement the rproc_virtio_create_virtqueues() and
   rproc_virtio_delete_virtqueues().
2. Because 1, also modified the rpmsg init.

Signed-off-by: Bowen Wang <wangbowen6@xiaomi.com>
  • Loading branch information
CV-Bowen committed Nov 8, 2023
1 parent d513645 commit 741c59a
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 48 deletions.
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
rpmsg_virtio_delete_virtqueues(struct rpmsg_virtio_device *rvdev)
{
virtio_delete_virtqueues(rvdev->vdev);
}

/**
* @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);
}
#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;

/* 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;
}

static void rproc_virtio_virtqueue_notify(struct virtqueue *vq)
{
struct remoteproc_virtio *rpvdev;
Expand Down Expand Up @@ -183,6 +266,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 @@ -213,46 +298,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));
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->role = role;
vdev->reset_cb = rst_cb;
Expand All @@ -268,33 +335,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 @@ -784,8 +784,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 @@ -796,8 +794,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 @@ -809,6 +805,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 @@ -836,7 +847,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 @@ -850,7 +862,7 @@ int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev,
buffer);

if (status != RPMSG_SUCCESS) {
return status;
goto err;
}
}
}
Expand All @@ -874,7 +886,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:
rpmsg_virtio_delete_virtqueues(rvdev);
return status;
#endif /*!VIRTIO_DEVICE_ONLY*/
}

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

rpmsg_virtio_delete_virtqueues(rvdev);
metal_mutex_deinit(&rdev->lock);
}
}

0 comments on commit 741c59a

Please sign in to comment.