diff mbox series

[RFC,08/18] net: FEC: Fixup EEE

Message ID 20230217034230.1249661-9-andrew@lunn.ch (mailing list archive)
State RFC
Delegated to: Netdev Maintainers
Headers show
Series Rework MAC drivers EEE support | expand

Checks

Context Check Description
netdev/tree_selection success Guessed tree name to be net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count fail Series longer than 15 patches (and no cover letter)
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit fail Errors and warnings before: 4 this patch: 4
netdev/cc_maintainers warning 6 maintainers not CCed: linux-mediatek@lists.infradead.org pabeni@redhat.com kuba@kernel.org edumazet@google.com linux-arm-kernel@lists.infradead.org davem@davemloft.net
netdev/build_clang fail Errors and warnings before: 4 this patch: 4
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn fail Errors and warnings before: 4 this patch: 4
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 68 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Andrew Lunn Feb. 17, 2023, 3:42 a.m. UTC
The enabling/disabling of EEE in the MAC should happen as a result of
auto negotiation. So move the enable/disable into
fec_enet_adjust_link() which gets called by phylib when there is a
change in link status.

fec_enet_set_eee() now just stores away the LTI timer value and if TX
LPI should be enabled. Everything else is passed to phylib, so it can
correctly setup the PHY.

fec_enet_get_eee() relies on phylib doing most of the work,
the MAC driver just adds the LTI timer value and the stored tx_lpi_enabled.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/freescale/fec_main.c | 27 ++++-------------------
 1 file changed, 4 insertions(+), 23 deletions(-)

Comments

Oleksij Rempel Feb. 17, 2023, 8:19 a.m. UTC | #1
On Fri, Feb 17, 2023 at 04:42:20AM +0100, Andrew Lunn wrote:
> The enabling/disabling of EEE in the MAC should happen as a result of
> auto negotiation. So move the enable/disable into
> fec_enet_adjust_link() which gets called by phylib when there is a
> change in link status.
> 
> fec_enet_set_eee() now just stores away the LTI timer value and if TX
> LPI should be enabled. Everything else is passed to phylib, so it can
> correctly setup the PHY.
> 
> fec_enet_get_eee() relies on phylib doing most of the work,
> the MAC driver just adds the LTI timer value and the stored tx_lpi_enabled.
> 
> Signed-off-by: Andrew Lunn <andrew@lunn.ch>
> ---
>  drivers/net/ethernet/freescale/fec_main.c | 27 ++++-------------------
>  1 file changed, 4 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
> index 195df75ee614..5aca705876fe 100644
> --- a/drivers/net/ethernet/freescale/fec_main.c
> +++ b/drivers/net/ethernet/freescale/fec_main.c
> @@ -1930,18 +1930,13 @@ static int fec_enet_us_to_tx_cycle(struct net_device *ndev, int us)
>  	return us * (fep->clk_ref_rate / 1000) / 1000;
>  }
>  
> -static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable)
> +static int fec_enet_eee_mode_set(struct net_device *ndev, bool eee_active)
>  {
>  	struct fec_enet_private *fep = netdev_priv(ndev);
>  	struct ethtool_eee *p = &fep->eee;
>  	unsigned int sleep_cycle, wake_cycle;
> -	int ret = 0;
> -
> -	if (enable) {
> -		ret = phy_init_eee(ndev->phydev, false);
> -		if (ret)
> -			return ret;
>  
> +	if (eee_active && p->tx_lpi_enabled) {
>  		sleep_cycle = fec_enet_us_to_tx_cycle(ndev, p->tx_lpi_timer);
>  		wake_cycle = sleep_cycle;
>  	} else {
> @@ -1949,10 +1944,6 @@ static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable)
>  		wake_cycle = 0;
>  	}
>  
> -	p->tx_lpi_enabled = enable;
> -	p->eee_enabled = enable;
> -	p->eee_active = enable;
> -
>  	writel(sleep_cycle, fep->hwp + FEC_LPI_SLEEP);
>  	writel(wake_cycle, fep->hwp + FEC_LPI_WAKE);
>  
> @@ -1997,6 +1988,7 @@ static void fec_enet_adjust_link(struct net_device *ndev)
>  			netif_tx_unlock_bh(ndev);
>  			napi_enable(&fep->napi);
>  		}
> +		fec_enet_eee_mode_set(ndev, phy_dev->eee_active);

Most of iMX variants do not support EEE. It should be something like this:
	if (fep->quirks & FEC_QUIRK_HAS_EEE)
		fec_enet_eee_mode_set(ndev, phy_dev->eee_active);

>  	} else {
>  		if (fep->link) {
>  			napi_disable(&fep->napi);
> @@ -3109,8 +3101,6 @@ fec_enet_get_eee(struct net_device *ndev, struct ethtool_eee *edata)
>  	if (!netif_running(ndev))
>  		return -ENETDOWN;
>  
> -	edata->eee_enabled = p->eee_enabled;
> -	edata->eee_active = p->eee_active;
>  	edata->tx_lpi_timer = p->tx_lpi_timer;
>  	edata->tx_lpi_enabled = p->tx_lpi_enabled;
>  
> @@ -3122,7 +3112,6 @@ fec_enet_set_eee(struct net_device *ndev, struct ethtool_eee *edata)
>  {
>  	struct fec_enet_private *fep = netdev_priv(ndev);
>  	struct ethtool_eee *p = &fep->eee;
> -	int ret = 0;
>  
>  	if (!(fep->quirks & FEC_QUIRK_HAS_EEE))
>  		return -EOPNOTSUPP;
> @@ -3131,15 +3120,7 @@ fec_enet_set_eee(struct net_device *ndev, struct ethtool_eee *edata)
>  		return -ENETDOWN;
>  
>  	p->tx_lpi_timer = edata->tx_lpi_timer;
> -
> -	if (!edata->eee_enabled || !edata->tx_lpi_enabled ||
> -	    !edata->tx_lpi_timer)
> -		ret = fec_enet_eee_mode_set(ndev, false);
> -	else
> -		ret = fec_enet_eee_mode_set(ndev, true);
> -
> -	if (ret)
> -		return ret;
> +	p->tx_lpi_enabled = edata->tx_lpi_enabled;

Hm.. this change have effect only after link restart. Should we do
something like this?

	if (phydev->link)
		fec_enet_eee_mode_set(ndev, phydev->eee_active);

or, execute phy_ethtool_set_eee() first and some how detect if link
changed? Or restart link by phylib on every change?

>  
>  	return phy_ethtool_set_eee(ndev->phydev, edata);
>  }
> -- 
> 2.39.1
> 
>
Russell King (Oracle) Feb. 17, 2023, 12:32 p.m. UTC | #2
On Fri, Feb 17, 2023 at 09:19:43AM +0100, Oleksij Rempel wrote:
> On Fri, Feb 17, 2023 at 04:42:20AM +0100, Andrew Lunn wrote:
> > @@ -3131,15 +3120,7 @@ fec_enet_set_eee(struct net_device *ndev, struct ethtool_eee *edata)
> >  		return -ENETDOWN;
> >  
> >  	p->tx_lpi_timer = edata->tx_lpi_timer;
> > -
> > -	if (!edata->eee_enabled || !edata->tx_lpi_enabled ||
> > -	    !edata->tx_lpi_timer)
> > -		ret = fec_enet_eee_mode_set(ndev, false);
> > -	else
> > -		ret = fec_enet_eee_mode_set(ndev, true);
> > -
> > -	if (ret)
> > -		return ret;
> > +	p->tx_lpi_enabled = edata->tx_lpi_enabled;
> 
> Hm.. this change have effect only after link restart. Should we do
> something like this?
> 
> 	if (phydev->link)
> 		fec_enet_eee_mode_set(ndev, phydev->eee_active);
> 
> or, execute phy_ethtool_set_eee() first and some how detect if link
> changed? Or restart link by phylib on every change?

Restarting the link on every "change" (even when nothing has changed)
is a dirty hack, and can be very annoying, leading to multiple link
restarts e.g. at boot time which can turn into several seconds of
boot delay depending on how much is configured.

I would suggest as a general principle, we should be keeping link
renegotiations to a minimum - and phylib already tries to do that in
several places.

Also note that reading phydev->eee_active without holding the phydev
mutex can be racy - and I would also ask what would prevent two calls
to fec_enet_eee_mode_set() running concurrently, once by the
adjust_link callback and once via the set_eee method. This applies
to reading phydev->link as well, so it may be best to hold the
phydev mutex around that entire if() clause.
Andrew Lunn Feb. 17, 2023, 1:58 p.m. UTC | #3
> > @@ -1997,6 +1988,7 @@ static void fec_enet_adjust_link(struct net_device *ndev)
> >  			netif_tx_unlock_bh(ndev);
> >  			napi_enable(&fep->napi);
> >  		}
> > +		fec_enet_eee_mode_set(ndev, phy_dev->eee_active);
> 
> Most of iMX variants do not support EEE. It should be something like this:
> 	if (fep->quirks & FEC_QUIRK_HAS_EEE)
> 		fec_enet_eee_mode_set(ndev, phy_dev->eee_active);

Yes, i missed that. Thanks. 

> > @@ -3131,15 +3120,7 @@ fec_enet_set_eee(struct net_device *ndev, struct ethtool_eee *edata)
> >  		return -ENETDOWN;
> >  
> >  	p->tx_lpi_timer = edata->tx_lpi_timer;
> > -
> > -	if (!edata->eee_enabled || !edata->tx_lpi_enabled ||
> > -	    !edata->tx_lpi_timer)
> > -		ret = fec_enet_eee_mode_set(ndev, false);
> > -	else
> > -		ret = fec_enet_eee_mode_set(ndev, true);
> > -
> > -	if (ret)
> > -		return ret;
> > +	p->tx_lpi_enabled = edata->tx_lpi_enabled;
> 
> Hm.. this change have effect only after link restart. Should we do
> something like this?
> 
> 	if (phydev->link)
> 		fec_enet_eee_mode_set(ndev, phydev->eee_active);
> 
> or, execute phy_ethtool_set_eee() first and some how detect if link
> changed? Or restart link by phylib on every change?

The whole startup sequence needs looking at, and ties in with the
phy_supports_eee() call we need to add. Given that EEE is broken with
most MAC drivers, i thought we could do that in a follow up patch
series.

As Russell says, we want to avoid multiple auto-neg cycles. Ideally we
want phy_supports_eee() to be called before phy_start() so that EEE
advertisement is set correctly for the first auto-neg. What is missing
from many MAC drivers is a default value from the LPI timer. It seems
like the need eee_set() has to be called with a value, or they are
relying on hardware reset values. Maybe we need to define a default?

We also need to discuss policy of if EEE should be enabled by default
for those systems which support it. As you have pointed out, it can
effect PTP quality.

   Andrew
Andrew Lunn Feb. 18, 2023, 2 a.m. UTC | #4
> >  	p->tx_lpi_timer = edata->tx_lpi_timer;
> > -
> > -	if (!edata->eee_enabled || !edata->tx_lpi_enabled ||
> > -	    !edata->tx_lpi_timer)
> > -		ret = fec_enet_eee_mode_set(ndev, false);
> > -	else
> > -		ret = fec_enet_eee_mode_set(ndev, true);
> > -
> > -	if (ret)
> > -		return ret;
> > +	p->tx_lpi_enabled = edata->tx_lpi_enabled;
> 
> Hm.. this change have effect only after link restart. Should we do
> something like this?

I think moving tx_lpi_enabled into phylib will help here. phylib can
track if only this changes, and then call the adjust_link callback
without actually doing an auto neg is only that changes.

	Andrew
diff mbox series

Patch

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 195df75ee614..5aca705876fe 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1930,18 +1930,13 @@  static int fec_enet_us_to_tx_cycle(struct net_device *ndev, int us)
 	return us * (fep->clk_ref_rate / 1000) / 1000;
 }
 
-static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable)
+static int fec_enet_eee_mode_set(struct net_device *ndev, bool eee_active)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	struct ethtool_eee *p = &fep->eee;
 	unsigned int sleep_cycle, wake_cycle;
-	int ret = 0;
-
-	if (enable) {
-		ret = phy_init_eee(ndev->phydev, false);
-		if (ret)
-			return ret;
 
+	if (eee_active && p->tx_lpi_enabled) {
 		sleep_cycle = fec_enet_us_to_tx_cycle(ndev, p->tx_lpi_timer);
 		wake_cycle = sleep_cycle;
 	} else {
@@ -1949,10 +1944,6 @@  static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable)
 		wake_cycle = 0;
 	}
 
-	p->tx_lpi_enabled = enable;
-	p->eee_enabled = enable;
-	p->eee_active = enable;
-
 	writel(sleep_cycle, fep->hwp + FEC_LPI_SLEEP);
 	writel(wake_cycle, fep->hwp + FEC_LPI_WAKE);
 
@@ -1997,6 +1988,7 @@  static void fec_enet_adjust_link(struct net_device *ndev)
 			netif_tx_unlock_bh(ndev);
 			napi_enable(&fep->napi);
 		}
+		fec_enet_eee_mode_set(ndev, phy_dev->eee_active);
 	} else {
 		if (fep->link) {
 			napi_disable(&fep->napi);
@@ -3109,8 +3101,6 @@  fec_enet_get_eee(struct net_device *ndev, struct ethtool_eee *edata)
 	if (!netif_running(ndev))
 		return -ENETDOWN;
 
-	edata->eee_enabled = p->eee_enabled;
-	edata->eee_active = p->eee_active;
 	edata->tx_lpi_timer = p->tx_lpi_timer;
 	edata->tx_lpi_enabled = p->tx_lpi_enabled;
 
@@ -3122,7 +3112,6 @@  fec_enet_set_eee(struct net_device *ndev, struct ethtool_eee *edata)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
 	struct ethtool_eee *p = &fep->eee;
-	int ret = 0;
 
 	if (!(fep->quirks & FEC_QUIRK_HAS_EEE))
 		return -EOPNOTSUPP;
@@ -3131,15 +3120,7 @@  fec_enet_set_eee(struct net_device *ndev, struct ethtool_eee *edata)
 		return -ENETDOWN;
 
 	p->tx_lpi_timer = edata->tx_lpi_timer;
-
-	if (!edata->eee_enabled || !edata->tx_lpi_enabled ||
-	    !edata->tx_lpi_timer)
-		ret = fec_enet_eee_mode_set(ndev, false);
-	else
-		ret = fec_enet_eee_mode_set(ndev, true);
-
-	if (ret)
-		return ret;
+	p->tx_lpi_enabled = edata->tx_lpi_enabled;
 
 	return phy_ethtool_set_eee(ndev->phydev, edata);
 }