Patchwork [v4,1/3] rtl8139: implement 8139cp link status

login
register
mail settings
Submitter Amos Kong
Date Sept. 17, 2012, 2:25 a.m.
Message ID <1347848736-25194-2-git-send-email-akong@redhat.com>
Download mbox | patch
Permalink /patch/184271/
State New
Headers show

Comments

Amos Kong - Sept. 17, 2012, 2:25 a.m.
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.

Signed-off-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Amos Kong <akong@redhat.com>

---
v2: don't add MediaState in RTL8139State to avoid trouble
v3: adding an enum MediaStatusBits
v4: correct nc.link_down in the end of migration
---
 hw/rtl8139.c |   23 +++++++++++++++++++++--
 1 files changed, 21 insertions(+), 2 deletions(-)
Stefan Hajnoczi - Sept. 27, 2012, 9:30 a.m.
On Mon, Sep 17, 2012 at 3:25 AM, Amos Kong <akong@redhat.com> wrote:
> 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.
>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> Signed-off-by: Amos Kong <akong@redhat.com>
>
> ---
> v2: don't add MediaState in RTL8139State to avoid trouble
> v3: adding an enum MediaStatusBits
> v4: correct nc.link_down in the end of migration
> ---
>  hw/rtl8139.c |   23 +++++++++++++++++++++--
>  1 files changed, 21 insertions(+), 2 deletions(-)
>
> diff --git a/hw/rtl8139.c b/hw/rtl8139.c
> index 844f1b8..72c052e 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,
> @@ -3007,7 +3007,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);

We only want to OR negated bit 0x4, not all the other bits:
ret = 0xd0 | (~s->BasicModeStatus & 0x04);

>              DPRINTF("MediaStatus read 0x%x\n", ret);
>              break;
>
> @@ -3262,6 +3263,9 @@ static int rtl8139_post_load(void *opaque, int version_id)
>          s->cplus_enabled = s->CpCmd != 0;
>      }
>
> +    /* infer link_down according to link status bit in BasicModeStatus */
> +    s->nic->nc.link_down = (s->BasicModeStatus & 0x04) == 0;
> +
>      return 0;
>  }
>
> @@ -3453,12 +3457,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 &= ~0x04;
> +    } else {
> +        s->BasicModeStatus |= 0x04;
> +    }
> +
> +    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
>
>

Patch

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 844f1b8..72c052e 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,
@@ -3007,7 +3007,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);
             DPRINTF("MediaStatus read 0x%x\n", ret);
             break;
 
@@ -3262,6 +3263,9 @@  static int rtl8139_post_load(void *opaque, int version_id)
         s->cplus_enabled = s->CpCmd != 0;
     }
 
+    /* infer link_down according to link status bit in BasicModeStatus */
+    s->nic->nc.link_down = (s->BasicModeStatus & 0x04) == 0;
+
     return 0;
 }
 
@@ -3453,12 +3457,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 &= ~0x04;
+    } else {
+        s->BasicModeStatus |= 0x04;
+    }
+
+    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)