Le 06/09/15 21:36, Keng Soon Cheah a écrit :
> The PHY_AN_PENDING state is put as a gate to enter the PHY_AN state
> where it will wait for any uncomplete auto-negotiation session to
> finish before starting a new one.
> 
> This extra state could be used to workaround some auto-negotation
> issues from certain vendors.

The typical way to work around these problems are to fix them at the PHY
driver level, see below.

> 
> an_pending_timeout module parameter is used to enable the AN_PENDING
> transition state. Set it to 0 to disable AN_PENDING state transition,
> set it to any non-zero value to specify the timeout period for
> PHY_AN_PENDING state in second. The default value is 0.
> 
> an_pending_guard module parameter serves as a guard band to delay
> the auto-negotiation firing after the previous auto-negotiation
> finish.
> 
> Signed-off-by: Keng Soon Cheah <keng.soon.ch...@ni.com>
> 
> Conflicts:
> 
>       drivers/net/phy/phy.c
> ---
> We observed failure in the ethernet link operation when our board pairs
> with some network switch model. The problem happens when an
> auto-negotiation is started around the time the previous auto-negotiation
> complete. We believe this might be an interoperatibility issue between
> the PHYs but we need a short-term solution in software to workaround the
> issue.
> 
> We found that we are able to avoid from hitting the problem by waiting any
> pending auto-negotiation to complete before starting a new one and this
> patch is designed to serve the purpose.

That sounds like a bug in the PHY state machine and/or the PHY driver if
you are allowed to restart auto-negotiation while one is pending. Now
that the PHY state machine has debug prints built-in, could you capture
a trace of this failing case?

Is this observed with the generic PHY driver or a custom PHY driver?

> 
> A PHY_AN_PENDING state is introduced and it will act as a gate to enter
> the PHY_AN state. This state will check for auto-negotiation completion
> or timeout after an_pending_timeout period, then it will wait for
> an_pending_guard before triggering another auto-negotiation.
> 
> The following diagram shows the timing diagram
> 
> 
>            an_pending_timeout           an_pending_guard
>    V                                                       V auto-nego
>    |--------------------------------->|....................|
>                                       ^
>                        auto-negotiation complete/timeout
> 
> We do not have plan to submit this patch upstream (unless the community
> feels this patch is useful in general) but we would like to seek for
> feedback or advice if this patch could introduce new problems.

As usual with state machines, introducing a new state needs to be
carefully done in order to make sure that all transitions are correct,
so far I would rather work on finding the root cause/extending the
timeout and/or making it configurable on a PHY-driver basis rather than
having this additional state which is more error prone.

Thanks!

> 
> ---
>  drivers/net/phy/phy.c |   44 +++++++++++++++++++++++++++++++++++++++++++-
>  include/linux/phy.h   |    3 ++-
>  2 files changed, 45 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
> index b2197b5..35e6484 100644
> --- a/drivers/net/phy/phy.c
> +++ b/drivers/net/phy/phy.c
> @@ -38,6 +38,16 @@
>  
>  #include <asm/irq.h>
>  
> +static unsigned int an_pending_timeout;
> +module_param(an_pending_timeout, uint, 0644);
> +MODULE_PARM_DESC(an_pending_timeout,
> +     "Timeout period for PHY_AN_PENDING state in second. 0 to disable 
> PHY_AN_PENDING state (default)");
> +
> +static unsigned int an_pending_guard;
> +module_param(an_pending_guard, uint, 0644);
> +MODULE_PARM_DESC(an_pending_guard,
> +     "Guard band period before firing auto-negotiation from PHY_AN_PENDING 
> state in second. Default to 0");
> +
>  static const char *phy_speed_to_str(int speed)
>  {
>       switch (speed) {
> @@ -82,7 +92,6 @@ static const char *phy_state_to_str(enum phy_state st)
>       return NULL;
>  }
>  
> -
>  /**
>   * phy_print_status - Convenience function to print out the current phy 
> status
>   * @phydev: the phy_device struct
> @@ -485,6 +494,18 @@ int phy_start_aneg(struct phy_device *phydev)
>  
>       /* Invalidate LP advertising flags */
>       phydev->lp_advertising = 0;
> +     if (an_pending_timeout) {
> +             switch (phydev->state) {
> +             case PHY_AN_PENDING:
> +             case PHY_HALTED:
> +                     break;
> +             default:
> +                     phydev->state = PHY_AN_PENDING;
> +                     phydev->link_timeout = an_pending_timeout;
> +                     goto out_unlock;
> +             }
> +
> +     }
>  
>       err = phydev->drv->config_aneg(phydev);
>       if (err < 0)
> @@ -831,6 +852,27 @@ void phy_state_machine(struct work_struct *work)
>               phydev->link_timeout = PHY_AN_TIMEOUT;
>  
>               break;
> +     case PHY_AN_PENDING:
> +             /* Check if negotiation is done.  Break if there's an error */
> +             err = phy_aneg_done(phydev);
> +             if (err < 0)
> +                     break;
> +
> +             /* If AN is done, we'll proceed with the real aneg triggering */
> +             if (err > 0) {
> +                     if (phydev->link_timeout > 0)
> +                             phydev->link_timeout = -(an_pending_guard);
> +                     else if (phydev->link_timeout < 0)
> +                             phydev->link_timeout++;
> +             } else
> +                     phydev->link_timeout--;
> +
> +             if (0 == phydev->link_timeout) {
> +                     needs_aneg = true;
> +
> +                     phydev->link_timeout = PHY_AN_TIMEOUT;
> +             }
> +             break;
>       case PHY_AN:
>               err = phy_read_status(phydev);
>               if (err < 0)
> diff --git a/include/linux/phy.h b/include/linux/phy.h
> index a26c3f8..a63afdc 100644
> --- a/include/linux/phy.h
> +++ b/include/linux/phy.h
> @@ -308,7 +308,8 @@ enum phy_state {
>       PHY_FORCING,
>       PHY_CHANGELINK,
>       PHY_HALTED,
> -     PHY_RESUMING
> +     PHY_RESUMING,
> +     PHY_AN_PENDING
>  };
>  
>  /**
> 


-- 
Florian
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to