qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [6279] RTL8139: Latch C+ mode state instead of inferring it


From: Anthony Liguori
Subject: [Qemu-devel] [6279] RTL8139: Latch C+ mode state instead of inferring it from C+ Command register ( Avi Kivity)
Date: Tue, 13 Jan 2009 15:20:18 +0000

Revision: 6279
          http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=6279
Author:   aliguori
Date:     2009-01-13 15:20:14 +0000 (Tue, 13 Jan 2009)

Log Message:
-----------
RTL8139: Latch C+ mode state instead of inferring it from C+ Command register 
(Avi Kivity)

It was observed that Windows 2003 x64 hangs when shutting down if an
RTL8139 NIC and a USB device tablet are both present.  What seems to be
happening is:

- the guest shuts down the transmitter and receiver
- time passes
- the guest requests a tally counter dump

As it happens, the tally counter command register overlaps the transmit
status register in C mode.  Qemu determines whether the chip is in C or C+
mode by looking at the C+ transmit enable bit; as this is now unset, the
dump tally counter command is interpreted as a C mode transmit command.  The
guest doesn't think so, however, and continues to poll for completion of the
tally counter dump command.  This never occurs, so the guest hangs.

Fix by redefining C+ mode as "a write to the C+ command register has occurred
since the last reset".  The data sheet is silent on the matter.

Signed-off-by: Avi Kivity <address@hidden>
Signed-off-by: Anthony Liguori <address@hidden>

Modified Paths:
--------------
    trunk/hw/rtl8139.c

Modified: trunk/hw/rtl8139.c
===================================================================
--- trunk/hw/rtl8139.c  2009-01-13 15:13:53 UTC (rev 6278)
+++ trunk/hw/rtl8139.c  2009-01-13 15:20:14 UTC (rev 6279)
@@ -472,6 +472,8 @@
     uint32_t   currTxDesc;
 
     /* C+ mode */
+    uint32_t   cplus_enabled;
+
     uint32_t   currCPlusRxDesc;
     uint32_t   currCPlusTxDesc;
 
@@ -1232,7 +1234,9 @@
     s->CSCR = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD;
 
     s->CpCmd   = 0x0; /* reset C+ mode */
+    s->cplus_enabled = 0;
 
+
 //    s->BasicModeCtrl = 0x3100; // 100Mbps, full duplex, autonegotiation
 //    s->BasicModeCtrl = 0x2100; // 100Mbps, full duplex
     s->BasicModeCtrl = 0x1000; // autonegotiation
@@ -1420,6 +1424,8 @@
 
     DEBUG_PRINT(("RTL8139C+ command register write(w) val=0x%04x\n", val));
 
+    s->cplus_enabled = 1;
+
     /* mask unwriteable bits */
     val = SET_MASKED(val, 0xff84, s->CpCmd);
 
@@ -2367,7 +2373,7 @@
 
     /* handle C+ transmit mode register configuration */
 
-    if (rtl8139_cp_transmitter_enabled(s))
+    if (s->cplus_enabled)
     {
         DEBUG_PRINT(("RTL8139C+ DTCCR write offset=0x%x val=0x%08x 
descriptor=%d\n", txRegOffset, val, descriptor));
 
@@ -3190,6 +3196,8 @@
     qemu_put_be64(f, s->TCTR_base);
 
     RTL8139TallyCounters_save(f, &s->tally_counters);
+
+    qemu_put_be32s(f, &s->cplus_enabled);
 }
 
 static int rtl8139_load(QEMUFile* f,void* opaque,int version_id)
@@ -3199,7 +3207,7 @@
     int ret;
 
     /* just 2 versions for now */
-    if (version_id > 3)
+    if (version_id > 4)
             return -EINVAL;
 
     if (version_id >= 3) {
@@ -3299,6 +3307,12 @@
         RTL8139TallyCounters_clear(&s->tally_counters);
     }
 
+    if (version_id >= 4) {
+        qemu_get_be32s(f, &s->cplus_enabled);
+    } else {
+        s->cplus_enabled = s->CpCmd != 0;
+    }
+
     return 0;
 }
 
@@ -3447,7 +3461,7 @@
     s->cplus_txbuffer_len = 0;
     s->cplus_txbuffer_offset = 0;
 
-    register_savevm("rtl8139", -1, 3, rtl8139_save, rtl8139_load, s);
+    register_savevm("rtl8139", -1, 4, rtl8139_save, rtl8139_load, s);
 
 #ifdef RTL8139_ONBOARD_TIMER
     s->timer = qemu_new_timer(vm_clock, rtl8139_timer, s);






reply via email to

[Prev in Thread] Current Thread [Next in Thread]