From: Jason Wang <jasow...@redhat.com>

Add a link status chang callback and change the link status bit in BMSR
& MSR accordingly. Tested in Linux/Windows guests.

The LinkDown bit of MediaStatus is inverse with link status.

Signed-off-by: Jason Wang <jasow...@redhat.com>
Signed-off-by: Amos Kong <ak...@redhat.com>
---
v2: don't add MediaState in RTL8139State to avoid trouble
v3: adding an enum MediaStatusBits
---
 hw/rtl8139.c |   32 ++++++++++++++++++++++++++++++--
 1 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 844f1b8..02d571f 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -167,7 +167,7 @@ enum IntrStatusBits {
     PCIErr = 0x8000,
     PCSTimeout = 0x4000,
     RxFIFOOver = 0x40,
-    RxUnderrun = 0x20,
+    RxUnderrun = 0x20, /* Packet Underrun / Link Change */
     RxOverflow = 0x10,
     TxErr = 0x08,
     TxOK = 0x04,
@@ -274,6 +274,18 @@ enum Config3Bits {
     Cfg3_GNTSel    = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */
 };
 
+/* Bits in MediaStatus */
+enum MediaStatusBits {
+    MSR_RXPF       = (1 << 0), /* Receive Pause Flag */
+    MSR_TXPF       = (1 << 1), /* Transmit Pause Flag */
+    MSR_LinkDown   = (1 << 2), /* Inverse of Link Status */
+    MSR_Speed_10   = (1 << 3), /* Media Speed */
+    MSR_Aux_Status = (1 << 4), /* Aux. Power Present Status */
+    MSR_Reserved   = (1 << 5), /* Reserved */
+    MSR_RXFCE      = (1 << 6), /* Rx Flow Control Enable */
+    MSR_TXFCE      = (1 << 7), /* Tx Flow Control Enable */
+};
+
 /* Bits in Config4 */
 enum Config4Bits {
     LWPTN = (1 << 2),    /* not on 8139, 8139A */
@@ -3007,7 +3019,8 @@ static uint32_t rtl8139_io_readb(void *opaque, uint8_t 
addr)
             break;
 
         case MediaStatus:
-            ret = 0xd0;
+            /* The LinkDown bit of MediaStatus is inverse with link status */
+            ret = 0xd0 | (s->nic->nc.link_down ? MSR_LinkDown : 0);
             DPRINTF("MediaStatus read 0x%x\n", ret);
             break;
 
@@ -3453,12 +3466,27 @@ static void pci_rtl8139_uninit(PCIDevice *dev)
     qemu_del_net_client(&s->nic->nc);
 }
 
+static void rtl8139_set_link_status(NetClientState *nc)
+{
+    RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    if (nc->link_down) {
+        s->BasicModeStatus &= ~0x0004;
+    } else {
+        s->BasicModeStatus |= 0x0004;
+    }
+
+    s->IntrStatus |= RxUnderrun;
+    rtl8139_update_irq(s);
+}
+
 static NetClientInfo net_rtl8139_info = {
     .type = NET_CLIENT_OPTIONS_KIND_NIC,
     .size = sizeof(NICState),
     .can_receive = rtl8139_can_receive,
     .receive = rtl8139_receive,
     .cleanup = rtl8139_cleanup,
+    .link_status_changed = rtl8139_set_link_status,
 };
 
 static int pci_rtl8139_init(PCIDevice *dev)
-- 
1.7.1


Reply via email to