From 6ecc2ef43e992d85cdeb7b883552a48bfa9bcd24 Mon Sep 17 00:00:00 2001 From: Dan Milea Date: Thu, 8 May 2025 15:46:30 +0300 Subject: [PATCH] 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 --- lib/virtio_mmio/virtio_mmio_drv.c | 67 ++++++++++++++++------------- lib/virtio_mmio/virtio_net_drv.c | 42 +++++++----------- lib/virtio_mmio/virtio_rng_drv.c | 18 +++++++- lib/virtio_mmio/virtio_serial_drv.c | 16 ++++++- 4 files changed, 85 insertions(+), 58 deletions(-) diff --git a/lib/virtio_mmio/virtio_mmio_drv.c b/lib/virtio_mmio/virtio_mmio_drv.c index efa1826..25af083 100644 --- a/lib/virtio_mmio/virtio_mmio_drv.c +++ b/lib/virtio_mmio/virtio_mmio_drv.c @@ -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); diff --git a/lib/virtio_mmio/virtio_net_drv.c b/lib/virtio_mmio/virtio_net_drv.c index ea326b9..37c3713 100644 --- a/lib/virtio_mmio/virtio_net_drv.c +++ b/lib/virtio_mmio/virtio_net_drv.c @@ -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; diff --git a/lib/virtio_mmio/virtio_rng_drv.c b/lib/virtio_mmio/virtio_rng_drv.c index 9c20a54..9f42056 100644 --- a/lib/virtio_mmio/virtio_rng_drv.c +++ b/lib/virtio_mmio/virtio_rng_drv.c @@ -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); diff --git a/lib/virtio_mmio/virtio_serial_drv.c b/lib/virtio_mmio/virtio_serial_drv.c index 8b5a312..2754772 100644 --- a/lib/virtio_mmio/virtio_serial_drv.c +++ b/lib/virtio_mmio/virtio_serial_drv.c @@ -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);