diff options
Diffstat (limited to 'hw/net/virtio-net.c')
| -rw-r--r-- | hw/net/virtio-net.c | 57 |
1 files changed, 51 insertions, 6 deletions
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index b6903aea54..8b32339b76 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -124,6 +124,16 @@ static int vq2q(int queue_index) return queue_index / 2; } +static void flush_or_purge_queued_packets(NetClientState *nc) +{ + if (!nc->peer) { + return; + } + + qemu_flush_or_purge_queued_packets(nc->peer, true); + assert(!virtio_net_get_subqueue(nc)->async_tx.elem); +} + /* TODO * - we could suppress RX interrupt if we were so inclined. */ @@ -536,6 +546,43 @@ static RxFilterInfo *virtio_net_query_rxfilter(NetClientState *nc) return info; } +static void virtio_net_queue_reset(VirtIODevice *vdev, uint32_t queue_index) +{ + VirtIONet *n = VIRTIO_NET(vdev); + NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(queue_index)); + + if (!nc->peer) { + return; + } + + if (get_vhost_net(nc->peer) && + nc->peer->info->type == NET_CLIENT_DRIVER_TAP) { + vhost_net_virtqueue_reset(vdev, nc, queue_index); + } + + flush_or_purge_queued_packets(nc); +} + +static void virtio_net_queue_enable(VirtIODevice *vdev, uint32_t queue_index) +{ + VirtIONet *n = VIRTIO_NET(vdev); + NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(queue_index)); + int r; + + if (!nc->peer || !vdev->vhost_started) { + return; + } + + if (get_vhost_net(nc->peer) && + nc->peer->info->type == NET_CLIENT_DRIVER_TAP) { + r = vhost_net_virtqueue_restart(vdev, nc, queue_index); + if (r < 0) { + error_report("unable to restart vhost net virtqueue: %d, " + "when resetting the queue", queue_index); + } + } +} + static void virtio_net_reset(VirtIODevice *vdev) { VirtIONet *n = VIRTIO_NET(vdev); @@ -566,12 +613,7 @@ static void virtio_net_reset(VirtIODevice *vdev) /* Flush any async TX */ for (i = 0; i < n->max_queue_pairs; i++) { - NetClientState *nc = qemu_get_subqueue(n->nic, i); - - if (nc->peer) { - qemu_flush_or_purge_queued_packets(nc->peer, true); - assert(!virtio_net_get_subqueue(nc)->async_tx.elem); - } + flush_or_purge_queued_packets(qemu_get_subqueue(n->nic, i)); } } @@ -746,6 +788,7 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features, } if (!get_vhost_net(nc->peer)) { + virtio_add_feature(&features, VIRTIO_F_RING_RESET); return features; } @@ -3822,6 +3865,8 @@ static void virtio_net_class_init(ObjectClass *klass, void *data) vdc->set_features = virtio_net_set_features; vdc->bad_features = virtio_net_bad_features; vdc->reset = virtio_net_reset; + vdc->queue_reset = virtio_net_queue_reset; + vdc->queue_enable = virtio_net_queue_enable; vdc->set_status = virtio_net_set_status; vdc->guest_notifier_mask = virtio_net_guest_notifier_mask; vdc->guest_notifier_pending = virtio_net_guest_notifier_pending; |