diff mbox

[v2] rtl8139: implement 8139cp link status

Message ID 1347526299-27407-1-git-send-email-akong@redhat.com
State New
Headers show

Commit Message

Amos Kong Sept. 13, 2012, 8:51 a.m. UTC
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 reverse. 

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 migration trouble
---
 hw/rtl8139.c |   19 +++++++++++++++++--
 1 files changed, 17 insertions(+), 2 deletions(-)

Comments

Stefan Hajnoczi Sept. 13, 2012, 12:29 p.m. UTC | #1
On Thu, Sep 13, 2012 at 9:51 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 reverse.
>
> 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 migration trouble
> ---
>  hw/rtl8139.c |   19 +++++++++++++++++--
>  1 files changed, 17 insertions(+), 2 deletions(-)
>
> diff --git a/hw/rtl8139.c b/hw/rtl8139.c
> index 844f1b8..fa949ca 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,7 @@ static uint32_t rtl8139_io_readb(void *opaque, uint8_t addr)
>              break;
>
>          case MediaStatus:
> -            ret = 0xd0;
> +            ret = 0xd0 | ~(s->BasicModeStatus & 0x0004);
>              DPRINTF("MediaStatus read 0x%x\n", ret);
>              break;

This does not give any hint that BMSR & 0x4 is the link status
(inverted).  I suggest adding an enum like the other constants at the
top of the file:

ret = 0xd0 | (nc->link_down ? MSRLinkDown : 0);

Regarding migration: do we migrate the NetClient->link_down field?  If
we only migrate the status register value then the link may actually
be up at the net.c level.

Stefan
Amos Kong Sept. 14, 2012, 1:34 a.m. UTC | #2
On 13/09/12 20:29, Stefan Hajnoczi wrote:
> On Thu, Sep 13, 2012 at 9:51 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 reverse.
>>
>> 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 migration trouble
>> ---
>>   hw/rtl8139.c |   19 +++++++++++++++++--
>>   1 files changed, 17 insertions(+), 2 deletions(-)
>>
>> diff --git a/hw/rtl8139.c b/hw/rtl8139.c
>> index 844f1b8..fa949ca 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,7 @@ static uint32_t rtl8139_io_readb(void *opaque, uint8_t addr)
>>               break;
>>
>>           case MediaStatus:
>> -            ret = 0xd0;
>> +            ret = 0xd0 | ~(s->BasicModeStatus & 0x0004);
>>               DPRINTF("MediaStatus read 0x%x\n", ret);
>>               break;
>
> This does not give any hint that BMSR & 0x4 is the link status
> (inverted).

only mentioned in the commitlog, will add a comment here.

> I suggest adding an enum like the other constants at the
> top of the file:
>
> ret = 0xd0 | (nc->link_down ? MSRLinkDown : 0);

Ok, I will update the patch.

> Regarding migration: do we migrate the NetClient->link_down field? If
> we only migrate the status register value then the link may actually
> be up at the net.c level.

I tried to add 'MediaStatus' to 'struct RTL8139State', and update
'VMStateDescription vmstate_rtl8139', then the value of MediaStatus
will be migrated.

But the idea in v2 is better.

> Stefan

Thanks.
Stefan Hajnoczi Sept. 14, 2012, 7:30 a.m. UTC | #3
On Fri, Sep 14, 2012 at 2:34 AM, Amos Kong <akong@redhat.com> wrote:
> On 13/09/12 20:29, Stefan Hajnoczi wrote:
>>
>> On Thu, Sep 13, 2012 at 9:51 AM, Amos Kong <akong@redhat.com> wrote:
>> Regarding migration: do we migrate the NetClient->link_down field? If
>> we only migrate the status register value then the link may actually
>> be up at the net.c level.
>
>
> I tried to add 'MediaStatus' to 'struct RTL8139State', and update
> 'VMStateDescription vmstate_rtl8139', then the value of MediaStatus
> will be migrated.
>
> But the idea in v2 is better.

Migrating the NIC's media status is not enough.  Above I asked about
migrating nc->link_down, which determines whether net.c delivers
packets or drops them.

Your patch migrates the NIC's media status but I believe nc->link_down
isn't being migrated and the guest will therefore receive packets from
the host!  This could lead to unexpected results since the guest
thinks the link is down.

It's not a bug in your patch, but a larger issue that needs to be
addressed for all NICs that support migration.  (Unless I missed the
code that will migrate link_down.)

Stefan
Jason Wang Sept. 14, 2012, 9:01 a.m. UTC | #4
On 09/14/2012 03:30 PM, Stefan Hajnoczi wrote:
> On Fri, Sep 14, 2012 at 2:34 AM, Amos Kong<akong@redhat.com>  wrote:
>> On 13/09/12 20:29, Stefan Hajnoczi wrote:
>>> On Thu, Sep 13, 2012 at 9:51 AM, Amos Kong<akong@redhat.com>  wrote:
>>> Regarding migration: do we migrate the NetClient->link_down field? If
>>> we only migrate the status register value then the link may actually
>>> be up at the net.c level.
>>
>> I tried to add 'MediaStatus' to 'struct RTL8139State', and update
>> 'VMStateDescription vmstate_rtl8139', then the value of MediaStatus
>> will be migrated.
>>
>> But the idea in v2 is better.
> Migrating the NIC's media status is not enough.  Above I asked about
> migrating nc->link_down, which determines whether net.c delivers
> packets or drops them.
>
> Your patch migrates the NIC's media status but I believe nc->link_down
> isn't being migrated and the guest will therefore receive packets from
> the host!  This could lead to unexpected results since the guest
> thinks the link is down.
>
> It's not a bug in your patch, but a larger issue that needs to be
> addressed for all NICs that support migration.  (Unless I missed the
> code that will migrate link_down.)
>
> Stefan

A possible solution is to infer the nc->link_down from the media status 
register in the destination. It works without adding more codes net.c 
but need model specific callback functions.
diff mbox

Patch

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 844f1b8..fa949ca 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,7 @@  static uint32_t rtl8139_io_readb(void *opaque, uint8_t addr)
             break;
 
         case MediaStatus:
-            ret = 0xd0;
+            ret = 0xd0 | ~(s->BasicModeStatus & 0x0004);
             DPRINTF("MediaStatus read 0x%x\n", ret);
             break;
 
@@ -3453,12 +3453,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)