From dca06c9eca4a9c9bc06349412bf60c3f3d321fff Mon Sep 17 00:00:00 2001
Message-Id: <dca06c9eca4a9c9bc06349412bf60c3f3d321fff.1350312451.git.minovotn@redhat.com>
In-Reply-To: <aa2da19f266f7dd7345db5620ee362446fc6e806.1350312451.git.minovotn@redhat.com>
References: <aa2da19f266f7dd7345db5620ee362446fc6e806.1350312451.git.minovotn@redhat.com>
From: Amos Kong <akong@redhat.com>
Date: Mon, 15 Oct 2012 12:05:59 +0200
Subject: [PATCH 25/27] rtl8139: implement 8139cp link status

RH-Author: Amos Kong <akong@redhat.com>
Message-id: <1350302761-15231-2-git-send-email-akong@redhat.com>
Patchwork-id: 43163
O-Subject: [RHEL-6.4 qemu-kvm PATCH 1/3] rtl8139: implement 8139cp link status
Bugzilla: 852965
RH-Acked-by: Xiao Wang <jasowang@redhat.com>
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>

From: Jason Wang <jasowang@redhat.com>

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

The link status bit of MediaStatus is infered from BasicModeStatus,
they are inverse.

nc.link_down could not be migrated, this patch updates link_down in
rtl8139_post_load() to keep it coincident with real link status.

Conflicts:
    hw/rtl8139.c

Signed-off-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Amos Kong <akong@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@gmail.com>
(cherry picked from commit 9e12c5aff2cfdd1574bf732c4bbf579d0c2e85c1)
---
 hw/rtl8139.c |   24 ++++++++++++++++++++++--
 1 files changed, 22 insertions(+), 2 deletions(-)

Signed-off-by: Michal Novotny <minovotn@redhat.com>
---
 hw/rtl8139.c | 24 ++++++++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index c3d0552..0403686 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -162,7 +162,7 @@ enum IntrStatusBits {
     PCIErr = 0x8000,
     PCSTimeout = 0x4000,
     RxFIFOOver = 0x40,
-    RxUnderrun = 0x20,
+    RxUnderrun = 0x20, /* Packet Underrun / Link Change */
     RxOverflow = 0x10,
     TxErr = 0x08,
     TxOK = 0x04,
@@ -2914,7 +2914,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->BasicModeStatus & 0x04);
             DEBUG_PRINT(("RTL8139: MediaStatus read 0x%x\n", ret));
             break;
 
@@ -3179,6 +3180,10 @@ static int rtl8139_post_load(void *opaque, int version_id)
         s->cplus_enabled = s->CpCmd != 0;
     }
 
+    /* nc.link_down can't be migrated, so infer link_down according
+     * to link status bit in BasicModeStatus */
+    s->nic->nc.link_down = (s->BasicModeStatus & 0x04) == 0;
+
     return 0;
 }
 
@@ -3409,12 +3414,27 @@ static int pci_rtl8139_uninit(PCIDevice *dev)
     return 0;
 }
 
+static void rtl8139_set_link_status(VLANClientState *nc)
+{
+    RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    if (nc->link_down) {
+        s->BasicModeStatus &= ~0x04;
+    } else {
+        s->BasicModeStatus |= 0x04;
+    }
+
+    s->IntrStatus |= RxUnderrun;
+    rtl8139_update_irq(s);
+}
+
 static NetClientInfo net_rtl8139_info = {
     .type = NET_CLIENT_TYPE_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.11.7

