From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1LMl45-0001zS-RR for qemu-devel@nongnu.org; Tue, 13 Jan 2009 10:20:25 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1LMl44-0001ya-LB for qemu-devel@nongnu.org; Tue, 13 Jan 2009 10:20:25 -0500 Received: from [199.232.76.173] (port=49553 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1LMl44-0001yV-HC for qemu-devel@nongnu.org; Tue, 13 Jan 2009 10:20:24 -0500 Received: from savannah.gnu.org ([199.232.41.3]:60403 helo=sv.gnu.org) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1LMl44-0005Yk-9l for qemu-devel@nongnu.org; Tue, 13 Jan 2009 10:20:24 -0500 Received: from cvs.savannah.gnu.org ([199.232.41.69]) by sv.gnu.org with esmtp (Exim 4.63) (envelope-from ) id 1LMl40-0003II-Ef for qemu-devel@nongnu.org; Tue, 13 Jan 2009 15:20:20 +0000 Received: from aliguori by cvs.savannah.gnu.org with local (Exim 4.63) (envelope-from ) id 1LMl3y-0003I9-2G for qemu-devel@nongnu.org; Tue, 13 Jan 2009 15:20:18 +0000 MIME-Version: 1.0 Errors-To: aliguori Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Anthony Liguori Message-Id: Date: Tue, 13 Jan 2009 15:20:18 +0000 Subject: [Qemu-devel] [6279] RTL8139: Latch C+ mode state instead of inferring it from C+ Command register ( Avi Kivity) Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org 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 Signed-off-by: Anthony Liguori 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);