mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-11 03:24:58 -06:00
virtio-net: fix TX timer with tx_burst
When virtio_net_flush_tx() reaches the tx_burst value all
the queue is not flushed and nothing restart the timer.
Fix that by doing for TX timer as we do for bottom half TX:
rearming the timer if we find any packet to send during the
virtio_net_flush_tx() call.
Fixes: e3f30488e5
("virtio-net: Limit number of packets sent per TX flush")
Cc: alex.williamson@redhat.com
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
This commit is contained in:
parent
df8d070817
commit
7550a82259
1 changed files with 41 additions and 9 deletions
|
@ -2536,14 +2536,19 @@ static void virtio_net_tx_complete(NetClientState *nc, ssize_t len)
|
||||||
|
|
||||||
virtio_queue_set_notification(q->tx_vq, 1);
|
virtio_queue_set_notification(q->tx_vq, 1);
|
||||||
ret = virtio_net_flush_tx(q);
|
ret = virtio_net_flush_tx(q);
|
||||||
if (q->tx_bh && ret >= n->tx_burst) {
|
if (ret >= n->tx_burst) {
|
||||||
/*
|
/*
|
||||||
* the flush has been stopped by tx_burst
|
* the flush has been stopped by tx_burst
|
||||||
* we will not receive notification for the
|
* we will not receive notification for the
|
||||||
* remainining part, so re-schedule
|
* remainining part, so re-schedule
|
||||||
*/
|
*/
|
||||||
virtio_queue_set_notification(q->tx_vq, 0);
|
virtio_queue_set_notification(q->tx_vq, 0);
|
||||||
qemu_bh_schedule(q->tx_bh);
|
if (q->tx_bh) {
|
||||||
|
qemu_bh_schedule(q->tx_bh);
|
||||||
|
} else {
|
||||||
|
timer_mod(q->tx_timer,
|
||||||
|
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout);
|
||||||
|
}
|
||||||
q->tx_waiting = 1;
|
q->tx_waiting = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2644,6 +2649,8 @@ drop:
|
||||||
return num_packets;
|
return num_packets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void virtio_net_tx_timer(void *opaque);
|
||||||
|
|
||||||
static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq)
|
static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq)
|
||||||
{
|
{
|
||||||
VirtIONet *n = VIRTIO_NET(vdev);
|
VirtIONet *n = VIRTIO_NET(vdev);
|
||||||
|
@ -2661,15 +2668,13 @@ static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (q->tx_waiting) {
|
if (q->tx_waiting) {
|
||||||
virtio_queue_set_notification(vq, 1);
|
/* We already have queued packets, immediately flush */
|
||||||
timer_del(q->tx_timer);
|
timer_del(q->tx_timer);
|
||||||
q->tx_waiting = 0;
|
virtio_net_tx_timer(q);
|
||||||
if (virtio_net_flush_tx(q) == -EINVAL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
/* re-arm timer to flush it (and more) on next tick */
|
||||||
timer_mod(q->tx_timer,
|
timer_mod(q->tx_timer,
|
||||||
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout);
|
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout);
|
||||||
q->tx_waiting = 1;
|
q->tx_waiting = 1;
|
||||||
virtio_queue_set_notification(vq, 0);
|
virtio_queue_set_notification(vq, 0);
|
||||||
}
|
}
|
||||||
|
@ -2702,6 +2707,8 @@ static void virtio_net_tx_timer(void *opaque)
|
||||||
VirtIONetQueue *q = opaque;
|
VirtIONetQueue *q = opaque;
|
||||||
VirtIONet *n = q->n;
|
VirtIONet *n = q->n;
|
||||||
VirtIODevice *vdev = VIRTIO_DEVICE(n);
|
VirtIODevice *vdev = VIRTIO_DEVICE(n);
|
||||||
|
int ret;
|
||||||
|
|
||||||
/* This happens when device was stopped but BH wasn't. */
|
/* This happens when device was stopped but BH wasn't. */
|
||||||
if (!vdev->vm_running) {
|
if (!vdev->vm_running) {
|
||||||
/* Make sure tx waiting is set, so we'll run when restarted. */
|
/* Make sure tx waiting is set, so we'll run when restarted. */
|
||||||
|
@ -2716,8 +2723,33 @@ static void virtio_net_tx_timer(void *opaque)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = virtio_net_flush_tx(q);
|
||||||
|
if (ret == -EBUSY || ret == -EINVAL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* If we flush a full burst of packets, assume there are
|
||||||
|
* more coming and immediately rearm
|
||||||
|
*/
|
||||||
|
if (ret >= n->tx_burst) {
|
||||||
|
q->tx_waiting = 1;
|
||||||
|
timer_mod(q->tx_timer,
|
||||||
|
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* If less than a full burst, re-enable notification and flush
|
||||||
|
* anything that may have come in while we weren't looking. If
|
||||||
|
* we find something, assume the guest is still active and rearm
|
||||||
|
*/
|
||||||
virtio_queue_set_notification(q->tx_vq, 1);
|
virtio_queue_set_notification(q->tx_vq, 1);
|
||||||
virtio_net_flush_tx(q);
|
ret = virtio_net_flush_tx(q);
|
||||||
|
if (ret > 0) {
|
||||||
|
virtio_queue_set_notification(q->tx_vq, 0);
|
||||||
|
q->tx_waiting = 1;
|
||||||
|
timer_mod(q->tx_timer,
|
||||||
|
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtio_net_tx_bh(void *opaque)
|
static void virtio_net_tx_bh(void *opaque)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue