qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] RTL8139: Latch C+ mode state instead of inferring it from C+ Command register
@ 2009-01-12 12:29 Avi Kivity
  2009-01-13 15:20 ` [Qemu-devel] " Anthony Liguori
  0 siblings, 1 reply; 2+ messages in thread
From: Avi Kivity @ 2009-01-12 12:29 UTC (permalink / raw)
  To: Anthony Liguori, qemu-devel

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 <avi@redhat.com>
---
 hw/rtl8139.c |   20 +++++++++++++++++---
 1 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 687667a..2527d9b 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -472,6 +472,8 @@ typedef struct RTL8139State {
     uint32_t   currTxDesc;
 
     /* C+ mode */
+    uint32_t   cplus_enabled;
+
     uint32_t   currCPlusRxDesc;
     uint32_t   currCPlusTxDesc;
 
@@ -1232,6 +1234,8 @@ static void rtl8139_reset(RTL8139State *s)
     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
@@ -1420,6 +1424,8 @@ static void rtl8139_CpCmd_write(RTL8139State *s, uint32_t val)
 
     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 @@ static void rtl8139_TxStatus_write(RTL8139State *s, uint32_t txRegOffset, uint32
 
     /* 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 @@ static void rtl8139_save(QEMUFile* f,void* opaque)
     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 @@ static int rtl8139_load(QEMUFile* f,void* opaque,int version_id)
     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 @@ static int rtl8139_load(QEMUFile* f,void* opaque,int version_id)
         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;
 }
 
@@ -3450,7 +3464,7 @@ PCIDevice *pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn)
     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);
-- 
1.6.0.6

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [Qemu-devel] Re: [PATCH] RTL8139: Latch C+ mode state instead of inferring it from C+ Command register
  2009-01-12 12:29 [Qemu-devel] [PATCH] RTL8139: Latch C+ mode state instead of inferring it from C+ Command register Avi Kivity
@ 2009-01-13 15:20 ` Anthony Liguori
  0 siblings, 0 replies; 2+ messages in thread
From: Anthony Liguori @ 2009-01-13 15:20 UTC (permalink / raw)
  To: Avi Kivity; +Cc: qemu-devel

Avi Kivity wrote:
> 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 <avi@redhat.com>
>
>   
Applied.  Thanks.

Regards,

Anthony Liguori

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2009-01-13 15:20 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-01-12 12:29 [Qemu-devel] [PATCH] RTL8139: Latch C+ mode state instead of inferring it from C+ Command register Avi Kivity
2009-01-13 15:20 ` [Qemu-devel] " Anthony Liguori

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).