So the guest can stop and start net device. It freely implements the RFC https://lists.oasis-open.org/archives/virtio-comment/202012/msg00027.html
To stop (as "pause") the device is required to migrate status and vring addresses between device and SVQ. Once the device is stopped, the driver can request avail_idx, so it can be assigned to SVQ. This is a WIP commit: as with VIRTIO_F_QUEUE_STATE, is introduced in virtio_config.h before of even proposing for the kernel, with no feature flag, and, with no checking in the device. It also needs a modified vp_vdpa driver that supports to set and retrieve status. For virtio-net with qemu device there is no need to restore avail state: Since every tx and rx operation is entirely done in BQL regarding virtio, it would be enough with restore last_avail_idx with used_idx. Doing this way test the vq state part of the rest of the series. Signed-off-by: Eugenio Pérez <epere...@redhat.com> --- include/standard-headers/linux/virtio_config.h | 2 ++ hw/net/virtio-net.c | 6 ++++-- hw/virtio/virtio-pci.c | 7 +++++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/include/standard-headers/linux/virtio_config.h b/include/standard-headers/linux/virtio_config.h index 59fad3eb45..b3f6b1365d 100644 --- a/include/standard-headers/linux/virtio_config.h +++ b/include/standard-headers/linux/virtio_config.h @@ -40,6 +40,8 @@ #define VIRTIO_CONFIG_S_DRIVER_OK 4 /* Driver has finished configuring features */ #define VIRTIO_CONFIG_S_FEATURES_OK 8 +/* Device is stopped */ +#define VIRTIO_CONFIG_S_DEVICE_STOPPED 32 /* Device entered invalid state, driver must reset it */ #define VIRTIO_CONFIG_S_NEEDS_RESET 0x40 /* We've given up on this device. */ diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index bd7958b9f0..e8f55cdeba 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -198,6 +198,7 @@ static bool virtio_net_started(VirtIONet *n, uint8_t status) { VirtIODevice *vdev = VIRTIO_DEVICE(n); return (status & VIRTIO_CONFIG_S_DRIVER_OK) && + (!(status & VIRTIO_CONFIG_S_DEVICE_STOPPED)) && (n->status & VIRTIO_NET_S_LINK_UP) && vdev->vm_running; } @@ -385,7 +386,7 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status) qemu_flush_queued_packets(ncs); } - if (!q->tx_waiting) { + if (!q->tx_waiting && !(status & VIRTIO_CONFIG_S_DEVICE_STOPPED)) { continue; } @@ -1503,7 +1504,8 @@ static bool virtio_net_can_receive(NetClientState *nc) } if (!virtio_queue_ready(q->rx_vq) || - !(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) { + !(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) || + vdev->status == VIRTIO_CONFIG_S_DEVICE_STOPPED) { return false; } diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 6f30118c4e..9ed0f62222 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -326,13 +326,15 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) } break; case VIRTIO_PCI_STATUS: - if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) { + if (!(val & VIRTIO_CONFIG_S_DRIVER_OK) || + val & VIRTIO_CONFIG_S_DEVICE_STOPPED) { virtio_pci_stop_ioeventfd(proxy); } virtio_set_status(vdev, val & 0xFF); - if (val & VIRTIO_CONFIG_S_DRIVER_OK) { + if (val & VIRTIO_CONFIG_S_DRIVER_OK && + !(val & VIRTIO_CONFIG_S_DEVICE_STOPPED)) { virtio_pci_start_ioeventfd(proxy); } @@ -1303,6 +1305,7 @@ static void virtio_pci_common_write(void *opaque, hwaddr addr, proxy->vqs[vdev->queue_sel].used[0]); virtio_queue_set_last_avail_idx(vdev, vdev->queue_sel, proxy->vqs[vdev->queue_sel].state); + virtio_queue_update_used_idx(vdev, vdev->queue_sel); proxy->vqs[vdev->queue_sel].enabled = 1; } else { virtio_error(vdev, "wrong value for queue_enable %"PRIx64, val); -- 2.27.0