|
|
77dc39 |
From 4044e0670486ad089367952843f17351c4f6faa0 Mon Sep 17 00:00:00 2001
|
|
|
77dc39 |
From: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
77dc39 |
Date: Wed, 22 May 2013 14:50:18 +0200
|
|
|
77dc39 |
Subject: [PATCH] rtl8139: flush queued packets when RxBufPtr is written
|
|
|
77dc39 |
|
|
|
77dc39 |
Net queues support efficient "receive disable". For example, tap's file
|
|
|
77dc39 |
descriptor will not be polled while its peer has receive disabled. This
|
|
|
77dc39 |
saves CPU cycles for needlessly copying and then dropping packets which
|
|
|
77dc39 |
the peer cannot receive.
|
|
|
77dc39 |
|
|
|
77dc39 |
rtl8139 is missing the qemu_flush_queued_packets() call that wakes the
|
|
|
77dc39 |
queue up when receive becomes possible again.
|
|
|
77dc39 |
|
|
|
77dc39 |
As a result, the Windows 7 guest driver reaches a state where the
|
|
|
77dc39 |
rtl8139 cannot receive packets. The driver has actually refilled the
|
|
|
77dc39 |
receive buffer but we never resume reception.
|
|
|
77dc39 |
|
|
|
77dc39 |
The bug can be reproduced by running a large FTP 'get' inside a Windows
|
|
|
77dc39 |
7 guest:
|
|
|
77dc39 |
|
|
|
77dc39 |
$ qemu -netdev tap,id=tap0,...
|
|
|
77dc39 |
-device rtl8139,netdev=tap0
|
|
|
77dc39 |
|
|
|
77dc39 |
The Linux guest driver does not trigger the bug, probably due to a
|
|
|
77dc39 |
different buffer management strategy.
|
|
|
77dc39 |
|
|
|
77dc39 |
Reported-by: Oliver Francke <oliver.francke@filoo.de>
|
|
|
77dc39 |
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
77dc39 |
(cherry picked from commit 00b7ade807b5ce6779ddd86ce29c5521ec5c529a)
|
|
|
77dc39 |
---
|
|
|
77dc39 |
hw/net/rtl8139.c | 3 +++
|
|
|
77dc39 |
1 file changed, 3 insertions(+)
|
|
|
77dc39 |
|
|
|
77dc39 |
diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c
|
|
|
77dc39 |
index 9369507..7993f9f 100644
|
|
|
77dc39 |
--- a/hw/net/rtl8139.c
|
|
|
77dc39 |
+++ b/hw/net/rtl8139.c
|
|
|
77dc39 |
@@ -2575,6 +2575,9 @@ static void rtl8139_RxBufPtr_write(RTL8139State *s, uint32_t val)
|
|
|
77dc39 |
/* this value is off by 16 */
|
|
|
77dc39 |
s->RxBufPtr = MOD2(val + 0x10, s->RxBufferSize);
|
|
|
77dc39 |
|
|
|
77dc39 |
+ /* more buffer space may be available so try to receive */
|
|
|
77dc39 |
+ qemu_flush_queued_packets(qemu_get_queue(s->nic));
|
|
|
77dc39 |
+
|
|
|
77dc39 |
DPRINTF(" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n",
|
|
|
77dc39 |
s->RxBufferSize, s->RxBufAddr, s->RxBufPtr);
|
|
|
77dc39 |
}
|