diff options
author | Vincent Guittot <vincent.guittot@linaro.org> | 2022-02-01 17:31:11 +0100 |
---|---|---|
committer | Vincent Guittot <vincent.guittot@linaro.org> | 2022-08-13 11:51:13 +0200 |
commit | 1baa715ebdc305e83bc98f3f6b416ac4e62e6d8a (patch) | |
tree | faa29c3518ea3a3e939841bb05407a8162b356f9 /hw/virtio | |
parent | 717d828c9e7d8cd577d84bfe590e51993d1ce6e2 (diff) |
virtio-mmio: support device mode
With device mode, the virtio-mmio behaves like the device side of the
virtio-mmio transport layer instead of the driver side
Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org>
Diffstat (limited to 'hw/virtio')
-rw-r--r-- | hw/virtio/vhost-user-scmi.c | 9 | ||||
-rw-r--r-- | hw/virtio/vhost-user.c | 50 | ||||
-rw-r--r-- | hw/virtio/vhost.c | 10 | ||||
-rw-r--r-- | hw/virtio/virtio-mmio.c | 54 | ||||
-rw-r--r-- | hw/virtio/virtio.c | 21 |
5 files changed, 132 insertions, 12 deletions
diff --git a/hw/virtio/vhost-user-scmi.c b/hw/virtio/vhost-user-scmi.c index 10ead3c3e7..2bede14b88 100644 --- a/hw/virtio/vhost-user-scmi.c +++ b/hw/virtio/vhost-user-scmi.c @@ -90,6 +90,15 @@ static void vu_scmi_set_status(VirtIODevice *vdev, uint8_t status) VHostUserSCMI *scmi = VHOST_USER_SCMI(vdev); bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK; + /* + * When emulating device mode, we start backend as soon as features have + * been set in order to be notified when guest will set vring and flags + * like VIRTIO_CONFIG_S_DRIVER_OK + */ + if (vdev->device_mode) { + should_start = status & VIRTIO_CONFIG_S_FEATURES_OK; + } + if (!vdev->vm_running) { should_start = false; } diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 6abbc9da32..216fa94773 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -134,6 +134,11 @@ typedef enum VhostUserSlaveRequest { VHOST_USER_SLAVE_IOTLB_MSG = 1, VHOST_USER_SLAVE_CONFIG_CHANGE_MSG = 2, VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG = 3, + VHOST_USER_SLAVE_VRING_CALL = 4, + VHOST_USER_SLAVE_VRING_ERR = 5, + VHOST_USER_SLAVE_VRING_NUM = 6, + VHOST_USER_SLAVE_VRING_ADDR = 7, + VHOST_USER_SLAVE_DRIVER_STATE = 8, VHOST_USER_SLAVE_MAX } VhostUserSlaveRequest; @@ -1557,6 +1562,40 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev, return 0; } +static int vhost_user_slave_handle_vring_num(struct vhost_dev *dev, + struct vhost_vring_state *state) +{ + VirtIODevice *vdev = dev->vdev; + info_report("vhost_user_slave_handle_vring_num idx %u num %d", state->index, state->num); + virtio_queue_set_num(vdev, state->index & 0xFF , state->num); + return 0; +} + +static int vhost_user_slave_handle_vring_addr(struct vhost_dev *dev, + struct vhost_vring_addr *addr) +{ + VirtIODevice *vdev = dev->vdev; + info_report("vhost_user_slave_handle_vring_addr idx %u hw desc addr %lx", addr->index, addr->desc_user_addr); + virtio_queue_set_rings(vdev, addr->index & 0xFF, addr->desc_user_addr, + addr->avail_user_addr, + addr->used_user_addr); + return 0; +} + +static int vhost_user_slave_handle_driver_state(struct vhost_dev *dev, + struct vhost_vring_state *state) +{ + VirtIODevice *vdev = dev->vdev; + info_report("vhost_user_slave_handle_driver_state idx %u state 0x%x", state->index, state->num); + virtio_queue_set_ready(vdev, state->index & 0xFF, state->num); + if (state->num) + vdev->status |= VIRTIO_CONFIG_S_DRIVER_OK; + else + vdev->status &= ~VIRTIO_CONFIG_S_DRIVER_OK; + + return 0; +} + static void close_slave_channel(struct vhost_user *u) { g_source_destroy(u->slave_src); @@ -1614,7 +1653,16 @@ static gboolean slave_read(QIOChannel *ioc, GIOCondition condition, ret = vhost_user_slave_handle_vring_host_notifier(dev, &payload.area, fd ? fd[0] : -1); break; - default: + case VHOST_USER_SLAVE_VRING_NUM: + ret = vhost_user_slave_handle_vring_num(dev, &payload.state); + break; + case VHOST_USER_SLAVE_VRING_ADDR: + ret = vhost_user_slave_handle_vring_addr(dev, &payload.addr); + break; + case VHOST_USER_SLAVE_DRIVER_STATE: + ret = vhost_user_slave_handle_driver_state(dev, &payload.state); + break; + default: error_report("Received unexpected msg type: %d.", hdr.request); ret = -EINVAL; } diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index b643f42ea4..b922412a15 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -1093,6 +1093,15 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, }; struct VirtQueue *vvq = virtio_get_queue(vdev, idx); + if (vdev->device_mode) { + state.num = virtio_queue_get_last_avail_idx(vdev, idx); + r = dev->vhost_ops->vhost_set_vring_base(dev, &state); + if (r) { + VHOST_OPS_DEBUG(r, "vhost_set_vring_base failed"); + return -errno; + } + } + else { a = virtio_queue_get_desc_addr(vdev, idx); if (a == 0) { /* Queue might not be ready for start */ @@ -1148,6 +1157,7 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, if (r < 0) { goto fail_alloc; } + } file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq)); r = dev->vhost_ops->vhost_set_vring_kick(dev, &file); diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c index 883b67d394..962459e64c 100644 --- a/hw/virtio/virtio-mmio.c +++ b/hw/virtio/virtio-mmio.c @@ -193,6 +193,10 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size) __func__, offset); return 0; } + + if (vdev->device_mode) { + return virtio_queue_get_ready(vdev, vdev->queue_sel); + } return proxy->vqs[vdev->queue_sel].enabled; case VIRTIO_MMIO_INTERRUPT_STATUS: return qatomic_read(&vdev->isr); @@ -215,21 +219,42 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size) * the shared memory doesn't exist */ return -1; + case VIRTIO_MMIO_QUEUE_NUM: + if (vdev->device_mode) + return virtio_queue_get_num(vdev, vdev->queue_sel); + /* fallthrough */ + case VIRTIO_MMIO_QUEUE_DESC_LOW: + if (vdev->device_mode) + return virtio_queue_get_addr(vdev, vdev->queue_sel) & 0xFFFFFFFF; + /* fallthrough */ + case VIRTIO_MMIO_QUEUE_DESC_HIGH: + if (vdev->device_mode) + return virtio_queue_get_addr(vdev, vdev->queue_sel) >> 32; + /* fallthrough */ + case VIRTIO_MMIO_QUEUE_AVAIL_LOW: + if (vdev->device_mode) + return virtio_queue_get_avail_addr(vdev, vdev->queue_sel) & 0xFFFFFFFF; + /* fallthrough */ + case VIRTIO_MMIO_QUEUE_AVAIL_HIGH: + if (vdev->device_mode) + return virtio_queue_get_avail_addr(vdev, vdev->queue_sel) >> 32; + /* fallthrough */ + case VIRTIO_MMIO_QUEUE_USED_LOW: + if (vdev->device_mode) + return virtio_queue_get_used_addr(vdev, vdev->queue_sel) & 0xFFFFFFFF; + /* fallthrough */ + case VIRTIO_MMIO_QUEUE_USED_HIGH: + if (vdev->device_mode) + return virtio_queue_get_used_addr(vdev, vdev->queue_sel) >> 32; + /* fallthrough */ case VIRTIO_MMIO_DEVICE_FEATURES_SEL: case VIRTIO_MMIO_DRIVER_FEATURES: case VIRTIO_MMIO_DRIVER_FEATURES_SEL: case VIRTIO_MMIO_GUEST_PAGE_SIZE: case VIRTIO_MMIO_QUEUE_SEL: - case VIRTIO_MMIO_QUEUE_NUM: case VIRTIO_MMIO_QUEUE_ALIGN: case VIRTIO_MMIO_QUEUE_NOTIFY: case VIRTIO_MMIO_INTERRUPT_ACK: - case VIRTIO_MMIO_QUEUE_DESC_LOW: - case VIRTIO_MMIO_QUEUE_DESC_HIGH: - case VIRTIO_MMIO_QUEUE_AVAIL_LOW: - case VIRTIO_MMIO_QUEUE_AVAIL_HIGH: - case VIRTIO_MMIO_QUEUE_USED_LOW: - case VIRTIO_MMIO_QUEUE_USED_HIGH: qemu_log_mask(LOG_GUEST_ERROR, "%s: read of write-only register (0x%" HWADDR_PRIx ")\n", __func__, offset); @@ -415,7 +440,10 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value, virtio_update_irq(vdev); break; case VIRTIO_MMIO_STATUS: - if (!(value & VIRTIO_CONFIG_S_DRIVER_OK)) { + if (vdev->device_mode) { + if (!(value & VIRTIO_CONFIG_S_FEATURES_OK)) + virtio_mmio_stop_ioeventfd(proxy); + } else if( !(value & VIRTIO_CONFIG_S_DRIVER_OK)) { virtio_mmio_stop_ioeventfd(proxy); } @@ -427,7 +455,10 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value, virtio_set_status(vdev, value & 0xff); - if (value & VIRTIO_CONFIG_S_DRIVER_OK) { + if (vdev->device_mode) { + if (value & VIRTIO_CONFIG_S_FEATURES_OK) + virtio_mmio_start_ioeventfd(proxy); + } else if (value & VIRTIO_CONFIG_S_DRIVER_OK) { virtio_mmio_start_ioeventfd(proxy); } @@ -496,11 +527,14 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value, } proxy->vqs[vdev->queue_sel].used[1] = value; break; + case VIRTIO_MMIO_DEVICE_FEATURES: + if (vdev->device_mode) + proxy->guest_features[proxy->host_features_sel] = value; + /* fallthrough */ case VIRTIO_MMIO_MAGIC_VALUE: case VIRTIO_MMIO_VERSION: case VIRTIO_MMIO_DEVICE_ID: case VIRTIO_MMIO_VENDOR_ID: - case VIRTIO_MMIO_DEVICE_FEATURES: case VIRTIO_MMIO_QUEUE_NUM_MAX: case VIRTIO_MMIO_INTERRUPT_STATUS: case VIRTIO_MMIO_CONFIG_GENERATION: diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 9d637e043e..892d881216 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -123,6 +123,8 @@ struct VirtQueue unsigned int inuse; + bool ready; + uint16_t vector; VirtIOHandleOutput handle_output; VirtIODevice *vdev; @@ -1938,7 +1940,12 @@ int virtio_set_status(VirtIODevice *vdev, uint8_t val) } } - if ((vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) != + if (vdev->device_mode) { + if ((vdev->status & VIRTIO_CONFIG_S_FEATURES_OK) != + (val & VIRTIO_CONFIG_S_FEATURES_OK)) { + virtio_set_started(vdev, val & VIRTIO_CONFIG_S_FEATURES_OK); + } + } else if ((vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) != (val & VIRTIO_CONFIG_S_DRIVER_OK)) { virtio_set_started(vdev, val & VIRTIO_CONFIG_S_DRIVER_OK); } @@ -2015,6 +2022,7 @@ void virtio_reset(void *opaque) vdev->vq[i].notification = true; vdev->vq[i].vring.num = vdev->vq[i].vring.num_default; vdev->vq[i].inuse = 0; + vdev->vq[i].ready = false; virtio_virtqueue_reset_region_cache(&vdev->vq[i]); } } @@ -3300,6 +3308,16 @@ bool virtio_queue_enabled(VirtIODevice *vdev, int n) return virtio_queue_enabled_legacy(vdev, n); } +bool virtio_queue_get_ready(VirtIODevice *vdev, int n) +{ + return vdev->vq[n].ready; +} + +void virtio_queue_set_ready(VirtIODevice *vdev, int n, bool ready) +{ + vdev->vq[n].ready = ready; +} + hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n) { return vdev->vq[n].vring.avail; @@ -3685,6 +3703,7 @@ static Property virtio_properties[] = { DEFINE_PROP_BOOL("use-disabled-flag", VirtIODevice, use_disabled_flag, true), DEFINE_PROP_BOOL("x-disable-legacy-check", VirtIODevice, disable_legacy_check, false), + DEFINE_PROP_BOOL("device-mode", VirtIODevice, device_mode, false), DEFINE_PROP_END_OF_LIST(), }; |