mirror of
https://github.com/OpenAMP/open-amp.git
synced 2026-10-02 18:23:21 +08:00
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:
committed by
Arnaud Pouliquen
parent
1f8a7cb9db
commit
6ecc2ef43e
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user