nuttx/drivers/virtio/virtio-rng.c
wangbowen6 9aa57b6c53 virtio: add virtio framework in NuttX
1. virtio devics/drivers match and probe/remote mechanism;
2. virtio mmio transport layer based on OpenAmp (Compatible with both
   virtio mmio version 1 and 2);
3. virtio-serial driver based on new virtio framework;
4. virtio-rng driver based on new virtio framework;
5. virtio-net driver based on new virtio framework
   (IOB Offload implementation);
6. virtio-blk driver based on new virtio framework;
7. Remove the old virtio mmio framework, the old framework only
   support mmio transport layer, and the new framwork support
   more transport layer and this commit has implemented all the
   old virtio drivers;
8. Refresh the the qemu-arm64 and qemu-riscv virtio related
   configs, and update its README.txt;

New virtio-net driver has better performance
Compared with previous virtio-mmio-net:
|                        | master/-c | master/-s | this/-c | this/-s |
| :--------------------: | :-------: | :-------: | :-----: | :-----: |
| qemu-armv8a:netnsh     |  539Mbps  |  524Mbps  | 906Mbps | 715Mbps |
| qemu-armv8a:netnsh_smp |  401Mbps  |  437Mbps  | 583Mbps | 505Mbps |
| rv-virt:netnsh         |  487Mbps  |  512Mbps  | 760Mbps | 634Mbps |
| rv-virt:netnsh_smp     |  387Mbps  |  455Mbps  | 447Mbps | 502Mbps |
| rv-virt:netnsh64       |  602Mbps  |  595Mbps  | 881Mbps | 769Mbps |
| rv-virt:netnsh64_smp   |  414Mbps  |  515Mbps  | 491Mbps | 525Mbps |
| rv-virt:knetnsh64      |  515Mbps  |  457Mbps  | 606Mbps | 540Mbps |
| rv-virt:knetnsh64_smp  |  308Mbps  |  389Mbps  | 415Mbps | 474Mbps |
Note: Both CONFIG_IOB_NBUFFERS=64, using iperf command, all in Mbits/sec
      Tested in QEMU 7.2.2

Signed-off-by: wangbowen6 <wangbowen6@xiaomi.com>
Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
2023-08-10 03:39:39 +08:00

280 lines
8.0 KiB
C

/****************************************************************************
* drivers/virtio/virtio-rng.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <stdio.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/fs/fs.h>
#include <nuttx/semaphore.h>
#include <nuttx/virtio/virtio.h>
#include "virtio-rng.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
struct virtio_rng_cookie_s
{
sem_t sem;
size_t len;
};
struct virtio_rng_priv_s
{
FAR struct virtio_device *vdev;
char name[NAME_MAX];
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* RNG file operation function */
static ssize_t virtio_rng_read(FAR struct file *filep, FAR char *buffer,
size_t buflen);
/* Virtio driver functions */
static int virtio_rng_probe(FAR struct virtio_device *vdev);
static void virtio_rng_remove(FAR struct virtio_device *vdev);
/****************************************************************************
* Private Data
****************************************************************************/
static struct virtio_driver g_virtio_rng_driver =
{
LIST_INITIAL_VALUE(g_virtio_rng_driver.node), /* node */
VIRTIO_ID_ENTROPY, /* device id */
virtio_rng_probe, /* probe */
virtio_rng_remove, /* remove */
};
static const struct file_operations g_virtio_rng_ops =
{
NULL, /* open */
NULL, /* close */
virtio_rng_read, /* read */
NULL, /* write */
NULL, /* seek */
NULL, /* ioctl */
NULL, /* mmap */
NULL, /* truncate */
NULL, /* poll */
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
NULL, /* unlink */
#endif
};
static int g_virtio_rng_idx = 0;
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: virtio_rng_done
****************************************************************************/
static void virtio_rng_done(FAR struct virtqueue *vq)
{
FAR struct virtio_rng_cookie_s *cookie;
uint32_t len;
/* Get the buffer, virtqueue_get_buffer() return the cookie added in
* virtio_rng_read().
*/
cookie = virtqueue_get_buffer(vq, &len, NULL);
if (cookie != NULL)
{
/* Assign the return length */
cookie->len = len;
/* Read completed, post the sem */
nxsem_post(&cookie->sem);
}
}
/****************************************************************************
* Name: virtio_rng_read
****************************************************************************/
static ssize_t virtio_rng_read(FAR struct file *filep, FAR char *buffer,
size_t buflen)
{
FAR struct virtio_rng_priv_s *priv = filep->f_inode->i_private;
FAR struct virtqueue *vq = priv->vdev->vrings_info[0].vq;
struct virtio_rng_cookie_s cookie;
struct virtqueue_buf vb;
int ret;
/* Init the cookie */
cookie.len = 0;
nxsem_init(&cookie.sem, 0, 0);
/* Add the input buffer to the virtqueue, and the cookie as the virtqueue
* cookie. (virtqueue_get_buffer() will return cookie).
*/
vb.buf = buffer;
vb.len = buflen;
ret = virtqueue_add_buffer(vq, &vb, 0, 1, &cookie);
if (ret < 0)
{
return ret;
}
/* Notify the other side to process the added virtqueue buffer */
virtqueue_kick(vq);
/* Wait fot completion */
nxsem_wait_uninterruptible(&cookie.sem);
return cookie.len;
}
/****************************************************************************
* Name: virtio_rng_probe
****************************************************************************/
static int virtio_rng_probe(FAR struct virtio_device *vdev)
{
FAR struct virtio_rng_priv_s *priv;
FAR const char *vqnames[1];
vq_callback callback[1];
int ret;
priv = kmm_zalloc(sizeof(*priv));
if (priv == NULL)
{
vrterr("No enough memory\n");
return -ENOMEM;
}
priv->vdev = vdev;
vdev->priv = priv;
/* Call openamp api to intialize the virtio deivce */
virtio_set_status(vdev, VIRTIO_CONFIG_STATUS_DRIVER);
virtio_set_features(vdev, 0);
virtio_set_status(vdev, VIRTIO_CONFIG_FEATURES_OK);
vqnames[0] = "virtio_rng_rx";
callback[0] = virtio_rng_done;
ret = virtio_create_virtqueues(vdev, 0, 1, vqnames, callback);
if (ret < 0)
{
vrterr("virtio_device_create_virtqueue failed, ret=%d\n", ret);
goto err_with_priv;
}
virtio_set_status(vdev, VIRTIO_CONFIG_STATUS_DRIVER_OK);
virtqueue_enable_cb(vdev->vrings_info[0].vq);
/* Register NuttX driver */
if (g_virtio_rng_idx == 0)
{
strlcpy(priv->name, "/dev/random", NAME_MAX);
}
else
{
snprintf(priv->name, NAME_MAX, "/dev/random%d", g_virtio_rng_idx);
}
ret = register_driver(priv->name, &g_virtio_rng_ops, 0444, priv);
if (ret < 0)
{
vrterr("Register NuttX driver failed, ret=%d\n", ret);
goto err_with_virtqueue;
}
g_virtio_rng_idx++;
return ret;
err_with_virtqueue:
virtio_reset_device(vdev);
virtio_delete_virtqueues(vdev);
err_with_priv:
kmm_free(priv);
return ret;
}
/****************************************************************************
* Name: virtio_rng_remove
****************************************************************************/
static void virtio_rng_remove(FAR struct virtio_device *vdev)
{
FAR struct virtio_rng_priv_s *priv = vdev->priv;
unregister_driver(priv->name);
virtio_reset_device(vdev);
virtio_delete_virtqueues(vdev);
kmm_free(priv);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: devrandom_register
*
* Description:
* Initialize the RNG hardware and register the /dev/random driver.
*
****************************************************************************/
#ifdef CONFIG_DEV_RANDOM
void weak_function devrandom_register(void)
{
/* Nothing, implement it here just avoid the compile error, the driver
* /dev/random will be registered in the virtio rng driver.
*/
}
#endif
/****************************************************************************
* Name: virtio_register_rng_driver
****************************************************************************/
int virtio_register_rng_driver(void)
{
return virtio_register_driver(&g_virtio_rng_driver);
}