nuttx/drivers/virtio/virtio.c

349 lines
9.3 KiB
C
Raw Normal View History

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-03-22 04:49:43 +01:00
/****************************************************************************
* drivers/virtio/virtio.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 <debug.h>
#include <nuttx/mutex.h>
#include <nuttx/kmalloc.h>
#include <nuttx/virtio/virtio.h>
#include "virtio-blk.h"
#include "virtio-gpu.h"
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-03-22 04:49:43 +01:00
#include "virtio-net.h"
#include "virtio-rng.h"
#include "virtio-serial.h"
/****************************************************************************
* Private Types
****************************************************************************/
struct virtio_bus_s
{
mutex_t lock; /* Lock for the list */
struct list_node device; /* Wait match virtio device list */
struct list_node driver; /* Virtio driver list */
};
struct virtio_device_item_s
{
struct list_node node; /* list node */
struct virtio_device *device; /* Pointer to the virtio device */
struct virtio_driver *driver; /* Pointer to the virtio driver that
* matched with current virtio device
*/
};
/****************************************************************************
* Private Data
****************************************************************************/
static struct virtio_bus_s g_virtio_bus =
{
NXMUTEX_INITIALIZER,
LIST_INITIAL_VALUE(g_virtio_bus.device),
LIST_INITIAL_VALUE(g_virtio_bus.driver),
};
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: virtio_alloc_buf
****************************************************************************/
FAR void *virtio_alloc_buf(FAR struct virtio_device *vdev,
size_t size, size_t align)
{
if (align == 0)
{
return kmm_malloc(size);
}
else
{
return kmm_memalign(align, size);
}
}
/****************************************************************************
* Name: virtio_zalloc_buf
****************************************************************************/
FAR void *virtio_zalloc_buf(FAR struct virtio_device *vdev,
size_t size, size_t align)
{
FAR void *ptr = virtio_alloc_buf(vdev, size, align);
if (ptr != NULL)
{
memset(ptr, 0, size);
}
return ptr;
}
/****************************************************************************
* Name: virtio_mmio_free_buf
****************************************************************************/
void virtio_free_buf(FAR struct virtio_device *vdev, FAR void *buf)
{
kmm_free(buf);
}
/****************************************************************************
* Name: virtio_register_drivers
****************************************************************************/
void virtio_register_drivers(void)
{
int ret = OK;
#ifdef CONFIG_DRIVERS_VIRTIO_BLK
ret = virtio_register_blk_driver();
if (ret < 0)
{
vrterr("virtio_register_blk_driver failed, ret=%d\n", ret);
}
#endif
#ifdef CONFIG_DRIVERS_VIRTIO_GPU
ret = virtio_register_gpu_driver();
if (ret < 0)
{
vrterr("virtio_register_gpu_driver failed, ret=%d\n", ret);
}
#endif
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-03-22 04:49:43 +01:00
#ifdef CONFIG_DRIVERS_VIRTIO_NET
ret = virtio_register_net_driver();
if (ret < 0)
{
vrterr("virtio_register_net_driver failed, ret=%d\n", ret);
}
#endif
#ifdef CONFIG_DRIVERS_VIRTIO_RNG
ret = virtio_register_rng_driver();
if (ret < 0)
{
vrterr("virtio_register_rng_driver failed, ret=%d\n", ret);
}
#endif
#ifdef CONFIG_DRIVERS_VIRTIO_SERIAL
ret = virtio_register_serial_driver();
if (ret < 0)
{
vrterr("virtio_serial_driver_init failed, ret=%d\n", ret);
}
#endif
UNUSED(ret);
}
/****************************************************************************
* Name: virtio_register_driver
****************************************************************************/
int virtio_register_driver(FAR struct virtio_driver *driver)
{
FAR struct list_node *node;
int ret;
DEBUGASSERT(driver != NULL && driver->probe != NULL &&
driver->remove != NULL);
ret = nxmutex_lock(&g_virtio_bus.lock);
if (ret < 0)
{
return ret;
}
/* Add the driver to the virtio_bus driver list */
list_add_tail(&g_virtio_bus.driver, &driver->node);
/* Match all the devices has registered in the virtio_bus */
list_for_every(&g_virtio_bus.device, node)
{
FAR struct virtio_device_item_s *item =
container_of(node, struct virtio_device_item_s, node);
FAR struct virtio_device *device = item->device;
if (driver->device == device->id.device)
{
/* If found the device in the device list, call driver probe,
* if probe success, assign item->driver to indicate the device
* matched.
*/
if (driver->probe(device) >= 0)
{
item->driver = driver;
}
}
}
nxmutex_unlock(&g_virtio_bus.lock);
return ret;
}
/****************************************************************************
* Name: virtio_unregister_driver
****************************************************************************/
int virtio_unregister_driver(FAR struct virtio_driver *driver)
{
FAR struct list_node *node;
int ret;
DEBUGASSERT(driver != NULL);
ret = nxmutex_lock(&g_virtio_bus.lock);
if (ret < 0)
{
return ret;
}
/* Find all the devices matched with driver in device list */
list_for_every(&g_virtio_bus.device, node)
{
FAR struct virtio_device_item_s *item =
container_of(node, struct virtio_device_item_s, node);
if (item->driver == driver)
{
/* 1. Call driver remove function;
* 2. Mark item->driver NULL to indicate the device unmatched;
*/
driver->remove(item->device);
item->driver = NULL;
}
}
/* Remove the driver from the driver list */
list_delete(&driver->node);
nxmutex_unlock(&g_virtio_bus.lock);
return ret;
}
/****************************************************************************
* Name: virtio_register_device
****************************************************************************/
int virtio_register_device(FAR struct virtio_device *device)
{
FAR struct virtio_device_item_s *item;
FAR struct list_node *node;
int ret;
item = kmm_zalloc(sizeof(*item));
if (item == NULL)
{
return -ENOMEM;
}
item->device = device;
ret = nxmutex_lock(&g_virtio_bus.lock);
if (ret < 0)
{
kmm_free(item);
return ret;
}
/* Add the device to the virtio_bus device list */
list_add_tail(&g_virtio_bus.device, &item->node);
/* Match the driver has registered in the virtio_bus */
list_for_every(&g_virtio_bus.driver, node)
{
FAR struct virtio_driver *driver =
container_of(node, struct virtio_driver, node);
if (driver->device == device->id.device)
{
/* If found the driver in the driver list, call driver probe,
* if probe success, assign item->driver to indicate the device
* matched.
*/
if (driver->probe(device) >= 0)
{
item->driver = driver;
}
break;
}
}
nxmutex_unlock(&g_virtio_bus.lock);
return ret;
}
/****************************************************************************
* Name: virtio_unregister_device
****************************************************************************/
int virtio_unregister_device(FAR struct virtio_device *device)
{
FAR struct list_node *node;
int ret;
ret = nxmutex_lock(&g_virtio_bus.lock);
if (ret < 0)
{
return ret;
}
/* Find the device in device list */
list_for_every(&g_virtio_bus.device, node)
{
FAR struct virtio_device_item_s *item =
container_of(node, struct virtio_device_item_s, node);
if (item->device == device)
{
/* Call driver remove and mark item->driver NULL to indicate
* the device unmatched
*/
item->driver->remove(device);
item->driver = NULL;
/* Remove the device from the device list and free memory */
list_delete(&item->node);
kmm_free(item);
break;
}
}
nxmutex_unlock(&g_virtio_bus.lock);
return ret;
}