aboutsummaryrefslogtreecommitdiff
path: root/hw/rtl8139.c
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2012-07-16 10:52:03 +0300
committerAvi Kivity <avi@redhat.com>2012-07-16 10:52:03 +0300
commit7fa12eb15f95c269f488fce4096093c96dbaffab (patch)
tree8ca766bebdead1ae21819bdc691b1097008ae834 /hw/rtl8139.c
parent6f82a5ea52302bab33287b0191538be6f9138637 (diff)
parent785adb09b9fd0d4df6707f00247ec519c42fcfc6 (diff)
Merge tag 'v1.1.1' into stable-1.1qemu-kvm-1.1.1
* tag 'v1.1.1': (34 commits) update VERSION for v1.1.1 s390x: fix s390 virtio aliases rtl8139: validate rx ring before receiving packets ahci: SATA FIS is 20 bytes, not 0x20 qemu-img: document qed format on qemu-img man page virtio: Fix compiler warning for non Linux hosts sheepdog: fix return value of do_load_save_vm_state qemu/xendisk: set maximum number of grants to be used build: install qmp-commands.txt fdc: fix implied seek while there is no media in drive qcow2: fix autoclear image header update Prevent disk data loss when closing qemu qcow2: fix endianness conversion pci_bridge_dev: fix error path in pci_bridge_dev_initfn() qdev: release parent properties on dc->init failure intel-hda: Fix reset of MSI function ahci: Fix reset of MSI function rtl8139: honor RxOverflow flag in can_receive method configure: Fix build for some versions of glibc (9pfs) monitor: Fix memory leak with readline completion ... Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'hw/rtl8139.c')
-rw-r--r--hw/rtl8139.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 2413bc3d2..7b150475f 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -781,6 +781,13 @@ static inline dma_addr_t rtl8139_addr64(uint32_t low, uint32_t high)
#endif
}
+/* Workaround for buggy guest driver such as linux who allocates rx
+ * rings after the receiver were enabled. */
+static bool rtl8139_cp_rx_valid(RTL8139State *s)
+{
+ return !(s->RxRingAddrLO == 0 && s->RxRingAddrHI == 0);
+}
+
static int rtl8139_can_receive(VLANClientState *nc)
{
RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque;
@@ -792,14 +799,14 @@ static int rtl8139_can_receive(VLANClientState *nc)
if (!rtl8139_receiver_enabled(s))
return 1;
- if (rtl8139_cp_receiver_enabled(s)) {
+ if (rtl8139_cp_receiver_enabled(s) && rtl8139_cp_rx_valid(s)) {
/* ??? Flow control not implemented in c+ mode.
This is a hack to work around slirp deficiencies anyway. */
return 1;
} else {
avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr,
s->RxBufferSize);
- return (avail == 0 || avail >= 1514);
+ return (avail == 0 || avail >= 1514 || (s->IntrMask & RxOverflow));
}
}
@@ -937,6 +944,10 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
if (rtl8139_cp_receiver_enabled(s))
{
+ if (!rtl8139_cp_rx_valid(s)) {
+ return size;
+ }
+
DPRINTF("in C+ Rx mode ================\n");
/* begin C+ receiver mode */