Updated virtio drivers for network, entropy and serial devices

The drivers now support devices with version numbers 2 (virtio >= 1.0)
in addition to 1 (legacy).

Signed-off-by: Dan Milea <dan.milea@windriver.com>
This commit is contained in:
Dan Milea
2025-05-23 09:21:19 +02:00
committed by Arnaud Pouliquen
parent 1f8a7cb9db
commit 6ecc2ef43e
4 changed files with 85 additions and 58 deletions
+38 -29
View File
@@ -43,6 +43,11 @@ static inline uint8_t virtio_mmio_read8(struct virtio_device *vdev, int offset)
return metal_io_read8(&vmdev->cfg_io, offset);
}
static uint8_t virtio_mmio_get_status(struct virtio_device *vdev)
{
return virtio_mmio_read32(vdev, VIRTIO_MMIO_STATUS);
}
static inline void virtio_mmio_set_status(struct virtio_device *vdev, uint8_t status)
{
#if defined(HVL_VIRTIO)
@@ -50,6 +55,9 @@ static inline void virtio_mmio_set_status(struct virtio_device *vdev, uint8_t st
struct virtio_mmio_device, vdev);
#endif
if (status != VIRTIO_CONFIG_STATUS_RESET)
status |= virtio_mmio_get_status(vdev);
virtio_mmio_write32(vdev, VIRTIO_MMIO_STATUS, status);
#if defined(HVL_VIRTIO)
if (vmdev && vmdev->ipi && vmdev->hvl_mode == 1) {
@@ -58,11 +66,6 @@ static inline void virtio_mmio_set_status(struct virtio_device *vdev, uint8_t st
#endif
}
static uint8_t virtio_mmio_get_status(struct virtio_device *vdev)
{
return virtio_mmio_read32(vdev, VIRTIO_MMIO_STATUS);
}
static void virtio_mmio_write_config(struct virtio_device *vdev,
uint32_t offset, void *dst, int length)
{
@@ -224,11 +227,7 @@ int virtio_mmio_device_init(struct virtio_mmio_device *vmdev, uintptr_t virt_mem
/* Placeholder */
return -1;
}
if (version != 1) {
metal_log(METAL_LOG_ERROR, "Bad version %08x\n", version);
return -1;
}
metal_log(METAL_LOG_DEBUG, "VIRTIO MMIO version %08x\n", version);
vendor = virtio_mmio_read32(vdev, VIRTIO_MMIO_VENDOR_ID);
metal_log(METAL_LOG_DEBUG, "VIRTIO %08x:%08x\n", vendor, devid);
@@ -257,7 +256,9 @@ int virtio_mmio_device_init(struct virtio_mmio_device *vmdev, uintptr_t virt_mem
}
#endif
virtio_mmio_set_status(vdev, VIRTIO_CONFIG_STATUS_ACK);
virtio_mmio_write32(vdev, VIRTIO_MMIO_GUEST_PAGE_SIZE, 4096);
if (version == 1) {
virtio_mmio_write32(vdev, VIRTIO_MMIO_GUEST_PAGE_SIZE, 4096);
}
return 0;
}
@@ -283,6 +284,7 @@ struct virtqueue *virtio_mmio_setup_virtqueue(struct virtio_device *vdev,
const char *vq_name)
{
uint32_t maxq;
uint64_t paddr = 0;
struct virtio_vring_info _vring_info = {0};
struct virtio_vring_info *vring_info = &_vring_info;
struct vring_alloc_info *vring_alloc_info;
@@ -300,12 +302,6 @@ struct virtqueue *virtio_mmio_setup_virtqueue(struct virtio_device *vdev,
return NULL;
}
if (vdev->id.version != 0x1) {
metal_log(METAL_LOG_ERROR,
"Only VIRTIO MMIO version 1 is currently supported\n");
return NULL;
}
vring_info->io = &vmdev->shm_io;
vring_info->info.num_descs = virtio_mmio_get_max_elem(vdev, idx);
vring_info->info.align = VIRTIO_MMIO_VRING_ALIGNMENT;
@@ -345,29 +341,42 @@ struct virtqueue *virtio_mmio_setup_virtqueue(struct virtio_device *vdev,
VIRTIO_ASSERT((maxq >= vq->vq_nentries),
"VIRTIO_MMIO_QUEUE_NUM_MAX must be greater than vqueue->vq_nentries");
virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_NUM, vq->vq_nentries);
virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_ALIGN, 4096);
virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_PFN,
((uintptr_t)metal_io_virt_to_phys(&vmdev->shm_io,
(char *)vq->vq_ring.desc)) / 4096);
if (vdev->id.version == 1) {
virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_ALIGN, 4096);
virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_PFN,
((uintptr_t)metal_io_virt_to_phys(&vmdev->shm_io,
(char *)vq->vq_ring.desc)) / 4096);
#if defined(HVL_VIRTIO)
if (vmdev && vmdev->ipi && vmdev->hvl_mode == 1) {
vmdev->ipi(vmdev->ipi_param);
/*
* For multi-virtqueue devices in hypervisorless mode, a custom
* configuration acknowledgment mechanism is used to process
* same-register configuration entries like QUEUE_PFN.
*/
* For multi-virtqueue devices in hypervisorless mode, a custom
* configuration acknowledgment mechanism is used to process
* same-register configuration entries like QUEUE_PFN.
*/
if (virtio_mmio_hvl_wait_cfg(vdev, VIRTIO_MMIO_QUEUE_PFN,
VIRTIO_MMIO_HVL_CFG_ACK) != 0) {
VIRTIO_MMIO_HVL_CFG_ACK) != 0) {
metal_log(METAL_LOG_ERROR, "HVL mode: configuration failed\n");
return NULL;
}
virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_PFN,
((uintptr_t)metal_io_virt_to_phys(vq->shm_io,
(char *)vq->vq_ring.desc)) / 4096);
((uintptr_t)metal_io_virt_to_phys(vq->shm_io,
(char *)vq->vq_ring.desc)) / 4096);
}
#endif
} else {
paddr = metal_io_virt_to_phys(&vmdev->shm_io, vq->vq_ring.desc);
virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_DESC_LOW, (uint32_t)paddr);
virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_DESC_HIGH, (uint32_t)(paddr >> 32));
paddr = metal_io_virt_to_phys(vq->shm_io, vq->vq_ring.avail);
virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_AVAIL_LOW, (uint32_t)paddr);
virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_AVAIL_HIGH, (uint32_t)(paddr >> 32));
paddr = metal_io_virt_to_phys(vq->shm_io, vq->vq_ring.used);
virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_USED_LOW, (uint32_t)paddr);
virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_USED_HIGH, (uint32_t)(paddr >> 32));
virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_READY, 1);
}
vdev->vrings_info[vdev->vrings_num].vq = vq;
vdev->vrings_num++;
virtqueue_enable_cb(vq);
+16 -26
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Wind River Systems, Inc.
* Copyright (c) 2022-2025 Wind River Systems, Inc.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -49,6 +49,7 @@ int virtio_net_init(struct virtio_device *vdev, struct virtqueue **vqs, const ch
void (**cbs)(void *), void **cb_args, int vq_count)
{
uint32_t devid, features = 0;
uint8_t status = 0;
struct virtio_net_data *dev_data = NULL;
int ret;
int i;
@@ -78,43 +79,32 @@ int virtio_net_init(struct virtio_device *vdev, struct virtqueue **vqs, const ch
virtio_set_status(vdev, VIRTIO_CONFIG_STATUS_DRIVER);
virtio_set_features(vdev, VIRTIO_NET_F_MAC/*VIRTIO_F_NOTIFY_ON_EMPTY*/);
if (vdev->id.version > 1) {
virtio_set_status(vdev, VIRTIO_CONFIG_STATUS_FEATURES_OK);
}
(void)virtio_get_features(vdev, &features);
metal_log(METAL_LOG_DEBUG, "features: %08x\n", features);
#if 1
(void)virtio_get_status(vdev, &status);
metal_log(METAL_LOG_DEBUG, "status: %08x\n", status);
if (vdev->id.version > 1 && (!(status & VIRTIO_CONFIG_STATUS_FEATURES_OK))) {
metal_log(METAL_LOG_ERROR, "Expected VIRTIO_CONFIG_STATUS_FEATURES_OK to be set\n");
return -ENODEV;
}
ret = virtio_create_virtqueues(vdev, 0, vq_count, vq_names, (vq_callback *)cbs, cb_args);
if (ret) {
metal_free_memory(vdev->vrings_info);
return ret;
}
#else
struct virtqueue *vring_vq = NULL;
for (i = 0; i < vq_count; i++) {
/* TODO: update API for compatibility with other transports like
* remoteproc virtio
*/
vring_vq = NULL;
if (vdev->vrings_info[i].vq)
vring_vq = vdev->vrings_info[i].vq;
vq = virtio_mmio_setup_virtqueue(
vdev,
i,
vring_vq, /*vqs[i],*/
cbs[i],
cb_args[i],
vq_names[i]
);
if (!vq) {
return -1;
}
}
#endif
virtio_set_status(vdev, VIRTIO_CONFIG_STATUS_DRIVER_OK);
dev_data->vqin = vdev->vrings_info[0].vq;
dev_data->vqout = vdev->vrings_info[1].vq;
dev_data->hdrsize = sizeof(struct virtio_net_hdr);
if (!(features & VIRTIO_NET_F_MRG_RXBUF)) {
dev_data->hdrsize -= 2;
+16 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Wind River Systems, Inc.
* Copyright (c) 2022-2025 Wind River Systems, Inc.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -13,6 +13,7 @@ int virtio_rng_init(struct virtio_device *vdev, struct virtqueue **vqs,
const char **vq_names, int vq_count)
{
uint32_t devid, features = 0;
uint8_t status = 0;
int i;
int ret;
@@ -38,10 +39,23 @@ int virtio_rng_init(struct virtio_device *vdev, struct virtqueue **vqs,
}
virtio_set_status(vdev, VIRTIO_CONFIG_STATUS_DRIVER);
virtio_set_features(vdev, 0/*VIRTIO_F_NOTIFY_ON_EMPTY*/);
virtio_set_features(vdev, 0);
if (vdev->id.version > 1) {
virtio_set_status(vdev, VIRTIO_CONFIG_STATUS_FEATURES_OK);
}
(void)virtio_get_features(vdev, &features);
metal_log(METAL_LOG_DEBUG, "features: %08x\n", features);
(void)virtio_get_status(vdev, &status);
metal_log(METAL_LOG_DEBUG, "status: %08x\n", status);
if (vdev->id.version > 1 && !(status & VIRTIO_CONFIG_STATUS_FEATURES_OK)) {
metal_log(METAL_LOG_ERROR, "Expected VIRTIO_CONFIG_STATUS_FEATURES_OK to be set\n");
return -ENODEV;
}
ret = virtio_create_virtqueues(vdev, 0, vq_count, vq_names, NULL, NULL);
if (ret) {
metal_free_memory(vdev->vrings_info);
+15 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Wind River Systems, Inc.
* Copyright (c) 2022-2025 Wind River Systems, Inc.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -14,6 +14,7 @@ int virtio_serial_init(struct virtio_device *vdev, struct virtqueue **vqs, char
void (**cbs)(void *), void **cb_args, int vq_count)
{
uint32_t devid, features = 0;
uint8_t status = 0;
int i;
int ret;
@@ -42,9 +43,22 @@ int virtio_serial_init(struct virtio_device *vdev, struct virtqueue **vqs, char
}
virtio_set_status(vdev, VIRTIO_CONFIG_STATUS_DRIVER);
virtio_set_features(vdev, 0);
if (vdev->id.version > 1) {
virtio_set_status(vdev, VIRTIO_CONFIG_STATUS_FEATURES_OK);
}
(void)virtio_get_features(vdev, &features);
metal_log(METAL_LOG_DEBUG, "features: %08x\n", features);
(void)virtio_get_status(vdev, &status);
metal_log(METAL_LOG_DEBUG, "status: %08x\n", status);
if (vdev->id.version > 1 && !(status & VIRTIO_CONFIG_STATUS_FEATURES_OK)) {
metal_log(METAL_LOG_ERROR, "Expected VIRTIO_CONFIG_STATUS_FEATURES_OK to be set\n");
return -ENODEV;
}
ret = virtio_create_virtqueues(vdev, 0, vq_count, (const char **)vq_names, NULL, NULL);
if (ret) {
metal_free_memory(vdev->vrings_info);