Patchwork [v3] rtl8139: implement 8139cp link status

login
register
mail settings
Submitter Amos Kong
Date Sept. 14, 2012, 2:16 a.m.
Message ID <1347588966-20350-1-git-send-email-akong@redhat.com>
Download mbox | patch
Permalink /patch/183775/
State New
Headers show

Comments

Amos Kong - Sept. 14, 2012, 2:16 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 LinkDown bit of MediaStatus is inverse with 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
---
 hw/rtl8139.c |   32 ++++++++++++++++++++++++++++++--
 1 files changed, 30 insertions(+), 2 deletions(-)
Paolo Bonzini - Sept. 14, 2012, 8:36 a.m.
Il 14/09/2012 04:16, Amos Kong ha scritto:
> +            /* 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);
> +}
> +

Actually, this is worse than v2 because then one bit is migrated and the
other is not.

I think v2 is correct and, on top of it, you have to check in post_load
whether nc->link_down matches the loaded BMSR value.  If not, you need
to either set the link status in NetClientState, or generate an
RxUnderrun interrupt.

An alternative is to add a get_link_status callback and call it after
migration for all NIC NetClientStates.

Paolo
Amos Kong - Sept. 14, 2012, 9:20 a.m.
On 14/09/12 16:36, Paolo Bonzini wrote:
> Il 14/09/2012 04:16, Amos Kong ha scritto:
>> +            /* 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);
>> +}
>> +
>
> Actually, this is worse than v2 because then one bit is migrated and the
> other is not.

> I think v2 is correct and, on top of it, you have to check in post_load
> whether nc->link_down matches the loaded BMSR value.  If not, you need
> to either set the link status in NetClientState, or generate an
> RxUnderrun interrupt.


If correct link_down in rtl8139_post_load(), both v2 and v3 will work.

   s->nic->nc.link_down = (s->BasicModeStatus & 0x04) == 0;

s->BasicModeStatus is really migrated, s->nic->nc.link_down is inferred.
so I will continually work on v2.


> An alternative is to add a get_link_status callback and call it after
> migration for all NIC NetClientStates.
>
> Paolo

Thanks.

Patch

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)