qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH] e1000: fix link down handling with auto negotia


From: Amos Kong
Subject: Re: [Qemu-devel] [PATCH] e1000: fix link down handling with auto negotiation
Date: Thu, 7 Feb 2013 08:04:17 +0800
User-agent: Mutt/1.5.21 (2010-09-15)

On Tue, Feb 05, 2013 at 09:00:21PM +0200, Michael S. Tsirkin wrote:
> Fixes a couple of regression bugs introduced by
> b9d03e352cb6b31a66545763f6a1e20c9abf0c2c and related to
> auto-negotiation:
> -   Auto-negotiation currently sets link up even if it was
>     forced down from the monitor.
> -   If Auto-negotiation was in progress during migration,
>     link will never come up.
> 
> As a fix, don't touch NC link_down field at all,
> instead add code on receive path to check
> guest link status.
> 
> Signed-off-by: Michael S. Tsirkin <address@hidden>

Give a late ACK. I reviewed & tested this patch yesterday and did find
any problem.

We will set the link_down flag and E1000_STATUS_LU bit un-synchronous
during auto-negotiation stage. I considered to set_link status in
different time, patch seems ok.

> ---
> 
> This was lightly tested only. Intend to test some more
> and report, testing results wellcome.
> 
>  hw/e1000.c | 50 +++++++++++++++++++++++++++++++++++++++++++-------
>  1 file changed, 43 insertions(+), 7 deletions(-)
> 
> diff --git a/hw/e1000.c b/hw/e1000.c
> index bb150c6..f537974 100644
> --- a/hw/e1000.c
> +++ b/hw/e1000.c
> @@ -166,11 +166,10 @@ static void
>  set_phy_ctrl(E1000State *s, int index, uint16_t val)
>  {
>      if ((val & MII_CR_AUTO_NEG_EN) && (val & MII_CR_RESTART_AUTO_NEG)) {
> -        qemu_get_queue(s->nic)->link_down = true;
>          e1000_link_down(s);
>          s->phy_reg[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE;
>          DBGOUT(PHY, "Start link auto negotiation\n");
>          qemu_mod_timer(s->autoneg_timer, qemu_get_clock_ms(vm_clock) + 500);
>      }
>  }
>  
> @@ -178,8 +182,9 @@ static void
>  e1000_autoneg_timer(void *opaque)
>  {
>      E1000State *s = opaque;
> -    qemu_get_queue(s->nic)->link_down = false;
> -    e1000_link_up(s);
> +    if (!qemu_get_queue(s->nic)->link_down) {
> +        e1000_link_up(s);
> +    }
>      s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
>      DBGOUT(PHY, "Auto negotiation is completed\n");
>  }
> @@ -784,7 +790,8 @@ e1000_can_receive(NetClientState *nc)
>  {
>      E1000State *s = qemu_get_nic_opaque(nc);
>  
> -    return (s->mac_reg[RCTL] & E1000_RCTL_EN) && e1000_has_rxbufs(s, 1);
> +    return (s->mac_reg[STATUS] & E1000_STATUS_LU) &&
> +        (s->mac_reg[RCTL] & E1000_RCTL_EN) && e1000_has_rxbufs(s, 1);
>  }
>  
>  static uint64_t rx_desc_base(E1000State *s)
> @@ -810,8 +817,13 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, 
> size_t size)
>      size_t desc_size;
>      size_t total_size;
>  
> -    if (!(s->mac_reg[RCTL] & E1000_RCTL_EN))
> +    if (!(s->mac_reg[STATUS] & E1000_STATUS_LU)) {
>          return -1;
> +    }
> +
> +    if (!(s->mac_reg[RCTL] & E1000_RCTL_EN)) {
> +        return -1;
> +    }
>  
>      /* Pad to minimum Ethernet frame length */
>      if (size < sizeof(min_buf)) {
> @@ -1110,14 +1122,37 @@ static bool is_version_1(void *opaque, int version_id)
>      return version_id == 1;
>  }
>  
> +static void e1000_pre_save(void *opaque)
> +{
> +    E1000State *s = opaque;
> +    NetClientState *nc = qemu_get_queue(s->nic);
> +    /*
> +     * If link is down and auto-negotiation is ongoing, complete
> +     * auto-negotiation immediately.  This allows is to look at
> +     * MII_SR_AUTONEG_COMPLETE to infer link status on load.
> +     */
> +    if (nc->link_down &&
> +        s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN &&
> +        s->phy_reg[PHY_CTRL] & MII_CR_RESTART_AUTO_NEG) {
> +         s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
> +    }
> +}
> +
>  static int e1000_post_load(void *opaque, int version_id)
>  {
>      E1000State *s = opaque;
>      NetClientState *nc = qemu_get_queue(s->nic);
>  
>      /* nc.link_down can't be migrated, so infer link_down according
> -     * to link status bit in mac_reg[STATUS] */
> +     * to link status bit in mac_reg[STATUS].
> +     * Alternatively, restart link negotiation if it was in progress. */
>      nc->link_down = (s->mac_reg[STATUS] & E1000_STATUS_LU) == 0;
> +    if (s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN &&
> +        s->phy_reg[PHY_CTRL] & MII_CR_RESTART_AUTO_NEG &&
> +        !(s->phy_reg[PHY_STATUS] & MII_SR_AUTONEG_COMPLETE)) {
> +        nc->link_down = false;
> +        qemu_mod_timer(s->autoneg_timer, qemu_get_clock_ms(vm_clock) + 500);
> +    }
>  
>      return 0;
>  }
> @@ -1127,6 +1162,7 @@ static const VMStateDescription vmstate_e1000 = {
>      .version_id = 2,
>      .minimum_version_id = 1,
>      .minimum_version_id_old = 1,
> +    .pre_save = e1000_pre_save,
>      .post_load = e1000_post_load,
>      .fields      = (VMStateField []) {
>          VMSTATE_PCI_DEVICE(dev, E1000State),
> -- 
> MST



reply via email to

[Prev in Thread] Current Thread [Next in Thread]