diff mbox

[2/2] net: ethernet: fsl: add phy reset after clk enable option

Message ID 1499346330-12166-2-git-send-email-richard.leitner@skidata.com
State Changes Requested, archived
Delegated to: David Miller
Headers show

Commit Message

Richard Leitner July 6, 2017, 1:05 p.m. UTC
Some PHYs (for example the LAN8710) doesn't allow turning the clocks off
and on again without reset (according to their datasheet). Exactly this
behaviour was introduced for power saving reasons by commit e8fcfcd5684a
("net: fec: optimize the clock management to save power")
Therefore add a devictree option to perform a PHY reset and
configuration after every clock enable.

For a better understanding here's a outline of the time response of the
clock and reset lines before and after this patch:

			  v--fec_probe()              v--fec_enet_open()
			  v                           v
	w/o patch eCLK: ___||||||||____________________|||||||||||||||||
	w/o patch nRST: ----__------------------------------------------
	w/o patch CONF: _______XX_______________________________________

	w/  patch eCLK: ___||||||||____________________|||||||||||||||||
	w/  patch nRST: ----__--------------------------__--------------
	w/  patch CONF: _______XX__________________________XX___________
			  ^                           ^
			  ^--fec_probe()              ^--fec_enet_open()

In our case this problem does occur at about every 10th to 50th POR of
an LAN8710 connected to an i.MX6 SoC. The typical symptom of this
problem is a "swinging" ethernet link. Similar issues were experienced
by users of the NXP forum:
	https://community.nxp.com/thread/389902
	https://community.nxp.com/message/309354
With this patch applied the issue didn't occur for at least a few
hundred PORs of our board.

Fixes: e8fcfcd5684a ("net: fec: optimize the clock management to sa...")
Signed-off-by: Richard Leitner <richard.leitner@skidata.com>
---
 Documentation/devicetree/bindings/net/fsl-fec.txt |  3 +++
 drivers/net/ethernet/freescale/fec.h              |  1 +
 drivers/net/ethernet/freescale/fec_main.c         | 16 ++++++++++++++++
 3 files changed, 20 insertions(+)

Comments

Andrew Lunn July 6, 2017, 1:55 p.m. UTC | #1
Hi Richard

> diff --git a/Documentation/devicetree/bindings/net/fsl-fec.txt b/Documentation/devicetree/bindings/net/fsl-fec.txt
> index 6f55bdd..1766579 100644
> --- a/Documentation/devicetree/bindings/net/fsl-fec.txt
> +++ b/Documentation/devicetree/bindings/net/fsl-fec.txt
> @@ -23,6 +23,9 @@ Optional properties:
>  - phy-handle : phandle to the PHY device connected to this device.
>  - fixed-link : Assume a fixed link. See fixed-link.txt in the same directory.
>    Use instead of phy-handle.
> +- phy-reset-after-clk-enable : If present then a phy reset and configuration
> +  will be performed everytime after the clocks are enabled. This is required
> +  for some PHYs to work properly.

It sounds like this issue will apply to any LAN8710 which has its
clock fiddled with. So this should be a centrally documented property,
which any MAC driver can implement. Please move the above text to
ethernet.txt, and instead have:

 - phy-reset-after-clk-enable : See ethernet.txt

 Thanks
	 Andrew
Richard Leitner July 6, 2017, 2:33 p.m. UTC | #2
On 07/06/2017 03:55 PM, Andrew Lunn wrote:
>> diff --git a/Documentation/devicetree/bindings/net/fsl-fec.txt b/Documentation/devicetree/bindings/net/fsl-fec.txt
>> index 6f55bdd..1766579 100644
>> --- a/Documentation/devicetree/bindings/net/fsl-fec.txt
>> +++ b/Documentation/devicetree/bindings/net/fsl-fec.txt
>> @@ -23,6 +23,9 @@ Optional properties:
>>  - phy-handle : phandle to the PHY device connected to this device.
>>  - fixed-link : Assume a fixed link. See fixed-link.txt in the same directory.
>>    Use instead of phy-handle.
>> +- phy-reset-after-clk-enable : If present then a phy reset and configuration
>> +  will be performed everytime after the clocks are enabled. This is required
>> +  for some PHYs to work properly.
> 
> It sounds like this issue will apply to any LAN8710 which has its
> clock fiddled with. So this should be a centrally documented property,
> which any MAC driver can implement. Please move the above text to
> ethernet.txt, and instead have:
> 
>  - phy-reset-after-clk-enable : See ethernet.txt

I haven't tested it on any other platform than an i.MX6, but IMHO you're
right. It sounds reasonable that it affects any SoC which is messing
around with the clock and not performing a reset by default.

Thanks for that hint!
I'll include that in the v2.

>  Thanks
> 	 Andrew
> 

regards,
Richard.L
Andy Duan July 7, 2017, 5:30 a.m. UTC | #3
From: Richard Leitner <richard.leitner@skidata.com> Sent: Thursday, July 06, 2017 9:06 PM
>To: Andy Duan <fugang.duan@nxp.com>; robh+dt@kernel.org;
>mark.rutland@arm.com
>Cc: netdev@vger.kernel.org; devicetree@vger.kernel.org; linux-
>kernel@vger.kernel.org; dev@g0hl1n.net; Richard Leitner
><richard.leitner@skidata.com>
>Subject: [PATCH 2/2] net: ethernet: fsl: add phy reset after clk enable option
>
>Some PHYs (for example the LAN8710) doesn't allow turning the clocks off and
>on again without reset (according to their datasheet). Exactly this behaviour
>was introduced for power saving reasons by commit e8fcfcd5684a
>("net: fec: optimize the clock management to save power") Therefore add a
>devictree option to perform a PHY reset and configuration after every clock
>enable.
>
>For a better understanding here's a outline of the time response of the clock
>and reset lines before and after this patch:
>
>			  v--fec_probe()              v--fec_enet_open()
>			  v                           v
>	w/o patch eCLK:
>___||||||||____________________|||||||||||||||||
>	w/o patch nRST: ----__------------------------------------------
>	w/o patch CONF:
>_______XX_______________________________________
>
>	w/  patch eCLK:
>___||||||||____________________|||||||||||||||||
>	w/  patch nRST: ----__--------------------------__--------------
>	w/  patch CONF:
>_______XX__________________________XX___________
>			  ^                           ^
>			  ^--fec_probe()              ^--fec_enet_open()
>
>In our case this problem does occur at about every 10th to 50th POR of an
>LAN8710 connected to an i.MX6 SoC. The typical symptom of this problem is a
>"swinging" ethernet link. Similar issues were experienced by users of the NXP
>forum:
>	https://community.nxp.com/thread/389902
>	https://community.nxp.com/message/309354
>With this patch applied the issue didn't occur for at least a few hundred PORs
>of our board.
>
>Fixes: e8fcfcd5684a ("net: fec: optimize the clock management to sa...")
>Signed-off-by: Richard Leitner <richard.leitner@skidata.com>
>---
> Documentation/devicetree/bindings/net/fsl-fec.txt |  3 +++
> drivers/net/ethernet/freescale/fec.h              |  1 +
> drivers/net/ethernet/freescale/fec_main.c         | 16 ++++++++++++++++
> 3 files changed, 20 insertions(+)
>
>diff --git a/Documentation/devicetree/bindings/net/fsl-fec.txt
>b/Documentation/devicetree/bindings/net/fsl-fec.txt
>index 6f55bdd..1766579 100644
>--- a/Documentation/devicetree/bindings/net/fsl-fec.txt
>+++ b/Documentation/devicetree/bindings/net/fsl-fec.txt
>@@ -23,6 +23,9 @@ Optional properties:
> - phy-handle : phandle to the PHY device connected to this device.
> - fixed-link : Assume a fixed link. See fixed-link.txt in the same directory.
>   Use instead of phy-handle.
>+- phy-reset-after-clk-enable : If present then a phy reset and
>+configuration
>+  will be performed everytime after the clocks are enabled. This is
>+required
>+  for some PHYs to work properly.
> - fsl,num-tx-queues : The property is valid for enet-avb IP, which supports
>   hw multi queues. Should specify the tx queue number, otherwise set tx
>queue
>   number to 1.
>diff --git a/drivers/net/ethernet/freescale/fec.h
>b/drivers/net/ethernet/freescale/fec.h
>index 3da8084..d4f658a 100644
>--- a/drivers/net/ethernet/freescale/fec.h
>+++ b/drivers/net/ethernet/freescale/fec.h
>@@ -538,6 +538,7 @@ struct fec_enet_private {
> 	int	phy_reset_duration;
> 	int	phy_reset_post_delay;
> 	bool	phy_reset_active_high;
>+	bool	phy_reset_after_clk_enable;
>
> 	struct	napi_struct napi;
> 	int	csum_flags;
>diff --git a/drivers/net/ethernet/freescale/fec_main.c
>b/drivers/net/ethernet/freescale/fec_main.c
>index cbbf7b8..4e744f3 100644
>--- a/drivers/net/ethernet/freescale/fec_main.c
>+++ b/drivers/net/ethernet/freescale/fec_main.c
>@@ -68,6 +68,7 @@
>
> static void set_multicast_list(struct net_device *ndev);  static void
>fec_enet_itr_coal_init(struct net_device *ndev);
>+static int fec_reset_phy(struct net_device *ndev);
>
> #define DRIVER_NAME	"fec"
>
>@@ -1862,6 +1863,18 @@ static int fec_enet_clk_enable(struct net_device
>*ndev, bool enable)
> 		ret = clk_prepare_enable(fep->clk_ref);
> 		if (ret)
> 			goto failed_clk_ref;
>+
>+		/* reset the phy after clk is enabled if it's configured */
>+		if (fep->phy_reset_after_clk_enable) {
>+			ret = fec_reset_phy(ndev);
>+			if (ret)
>+				goto failed_reset;
>+			if (ndev->phydev) {
>+				ret = phy_init_hw(ndev->phydev);
>+				if (ret)
>+					goto failed_reset;
>+			}
>+		}

Since it is common issue so long as using the PHY, can you move it into smsc phy driver like in .smsc_phy_reset() function ?
And get the reset pin from phy dts node.

Andy  

> 	} else {
> 		clk_disable_unprepare(fep->clk_ahb);
> 		clk_disable_unprepare(fep->clk_enet_out);
>@@ -1876,6 +1889,7 @@ static int fec_enet_clk_enable(struct net_device
>*ndev, bool enable)
>
> 	return 0;
>
>+failed_reset:
> failed_clk_ref:
> 	if (fep->clk_ref)
> 		clk_disable_unprepare(fep->clk_ref);
>@@ -3350,6 +3364,7 @@ fec_probe(struct platform_device *pdev)
> 			fep->phy_reset_post_delay = 1;
>
> 		fep->phy_reset_active_high =  of_property_read_bool(np,
>"phy-reset-active-high");
>+		fep->phy_reset_after_clk_enable =
>of_property_read_bool(np,
>+"phy-reset-after-clk-enable");
>
> 		ret = devm_gpio_request_one(&pdev->dev, fep->phy_reset,
> 					    fep->phy_reset_active_high ?
>GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, @@ -3360,6 +3375,7 @@
>fec_probe(struct platform_device *pdev)
> 		}
> 	} else {
> 		fep->phy_reset = 0;
>+		fep->phy_reset_after_clk_enable = false;
> 	}
>
> 	ret = of_get_phy_mode(pdev->dev.of_node);
>--
>2.1.4
Richard Leitner July 7, 2017, 5:50 a.m. UTC | #4
On 07/07/2017 07:30 AM, Andy Duan wrote:
> From: Richard Leitner <richard.leitner@skidata.com> Sent: Thursday, July 06, 2017 9:06 PM
>> To: Andy Duan <fugang.duan@nxp.com>; robh+dt@kernel.org;
>> mark.rutland@arm.com
>> Cc: netdev@vger.kernel.org; devicetree@vger.kernel.org; linux-
>> kernel@vger.kernel.org; dev@g0hl1n.net; Richard Leitner
>> <richard.leitner@skidata.com>
>> Subject: [PATCH 2/2] net: ethernet: fsl: add phy reset after clk enable option
>>
>> Some PHYs (for example the LAN8710) doesn't allow turning the clocks off and
>> on again without reset (according to their datasheet). Exactly this behaviour
>> was introduced for power saving reasons by commit e8fcfcd5684a
>> ("net: fec: optimize the clock management to save power") Therefore add a
>> devictree option to perform a PHY reset and configuration after every clock
>> enable.
>>
>> For a better understanding here's a outline of the time response of the clock
>> and reset lines before and after this patch:
>>
>> 			  v--fec_probe()              v--fec_enet_open()
>> 			  v                           v
>> 	w/o patch eCLK:
>> ___||||||||____________________|||||||||||||||||
>> 	w/o patch nRST: ----__------------------------------------------
>> 	w/o patch CONF:
>> _______XX_______________________________________
>>
>> 	w/  patch eCLK:
>> ___||||||||____________________|||||||||||||||||
>> 	w/  patch nRST: ----__--------------------------__--------------
>> 	w/  patch CONF:
>> _______XX__________________________XX___________
>> 			  ^                           ^
>> 			  ^--fec_probe()              ^--fec_enet_open()
>>
>> In our case this problem does occur at about every 10th to 50th POR of an
>> LAN8710 connected to an i.MX6 SoC. The typical symptom of this problem is a
>> "swinging" ethernet link. Similar issues were experienced by users of the NXP
>> forum:
>> 	https://community.nxp.com/thread/389902
>> 	https://community.nxp.com/message/309354
>> With this patch applied the issue didn't occur for at least a few hundred PORs
>> of our board.
>>
>> Fixes: e8fcfcd5684a ("net: fec: optimize the clock management to sa...")
>> Signed-off-by: Richard Leitner <richard.leitner@skidata.com>

...

>> *ndev, bool enable)
>> 		ret = clk_prepare_enable(fep->clk_ref);
>> 		if (ret)
>> 			goto failed_clk_ref;
>> +
>> +		/* reset the phy after clk is enabled if it's configured */
>> +		if (fep->phy_reset_after_clk_enable) {
>> +			ret = fec_reset_phy(ndev);
>> +			if (ret)
>> +				goto failed_reset;
>> +			if (ndev->phydev) {
>> +				ret = phy_init_hw(ndev->phydev);
>> +				if (ret)
>> +					goto failed_reset;
>> +			}
>> +		}
>
> Since it is common issue so long as using the PHY, can you move it into smsc phy driver like in .smsc_phy_reset() function ?
> And get the reset pin from phy dts node.

During my first glance at this problem I had the same "feeling" that it 
should go into smsc.c. Therefore I've tried that already, but I haven't 
found a suitable "place" for that. My basic problem is: Where do I know 
(from smsc.c view) when the enetrefclk was disabled/enabled again 
without changing fec_main.c?

Some more points that come into my mind:
  - The smsc_phy_reset function is registered as "soft_reset". Would it 
be OK to use nRST in it?
  - Would it be OK to call the phy_init_hw function from within the 
smsc_phy_reset?
  - IMHO I'd have to move the reset gpio binding inside the phy node 
then. Isn't that a pretty big change doing that for all PHYs/FECs? Would 
it be "worth" it?

Sorry for these many (maybe noobish) questions, but I'm pretty new to 
the kernels fec/phy stuff ;-)

>
> Andy
>

Thanks & regards,
Richard.L
Andy Duan July 7, 2017, 7:03 a.m. UTC | #5
From: Richard Leitner <richard.leitner@skidata.com> Sent: Friday, July 07, 2017 1:51 PM
>> Since it is common issue so long as using the PHY, can you move it into smsc
>phy driver like in .smsc_phy_reset() function ?
>> And get the reset pin from phy dts node.
>
>Some more points that come into my mind:
>  - The smsc_phy_reset function is registered as "soft_reset". Would it be OK to
>use nRST in it?

It is not reasonable.

>  - Would it be OK to call the phy_init_hw function from within the
>smsc_phy_reset?

No, phy_init_hw() already call .drv->soft_reset().

>  - IMHO I'd have to move the reset gpio binding inside the phy node then. Isn't
>that a pretty big change doing that for all PHYs/FECs? Would it be "worth" it?
>
To make the change to be common, there have big change for phy driver.
Maybe somebody can give one good suggestion/solution for it.

Andy
Richard Leitner July 7, 2017, 9:52 a.m. UTC | #6
On 07/07/2017 09:03 AM, Andy Duan wrote:
> From: Richard Leitner <richard.leitner@skidata.com> Sent: Friday, July 07, 2017 1:51 PM
>>> Since it is common issue so long as using the PHY, can you move it into smsc
>> phy driver like in .smsc_phy_reset() function ?
>>> And get the reset pin from phy dts node.
>>
>> Some more points that come into my mind:
>>  - The smsc_phy_reset function is registered as "soft_reset". Would it be OK to
>> use nRST in it?
>
> It is not reasonable.
>
>>  - Would it be OK to call the phy_init_hw function from within the
>> smsc_phy_reset?
>
> No, phy_init_hw() already call .drv->soft_reset().
>
>>  - IMHO I'd have to move the reset gpio binding inside the phy node then. Isn't
>> that a pretty big change doing that for all PHYs/FECs? Would it be "worth" it?
>>
> To make the change to be common, there have big change for phy driver.
> Maybe somebody can give one good suggestion/solution for it.

Sorry, I don't think I understood everything correctly:

1. The "phy-reset-gpios" binding should go inside the phy node. This 
will cause to *change ALL FEC and PHY drivers*. Correct?

2. Add an additonal "hard reset" function to the PHY driver which 
handles the "phy-reset-gpios". Correct?

3. Who should then trigger the "hard reset" of the PHY? phy_init_hw? The 
FEC?

The point is that the LAN8710 is currently not always working correctly, 
therefore this small change was proposed. Should we really change all 
PHY/FECs only because of this?
Furthermore one problem still remains: The enet_refclk is controlled by 
the FEC. How does the PHY recognize when it was disabled/enabled?

>
> Andy
>

kind regards,
Richard.L
Andy Duan July 7, 2017, 11:08 a.m. UTC | #7
From: Richard Leitner <richard.leitner@skidata.com> Sent: Friday, July 07, 2017 5:53 PM
>To: Andy Duan <fugang.duan@nxp.com>; robh+dt@kernel.org;
>mark.rutland@arm.com
>Cc: netdev@vger.kernel.org; devicetree@vger.kernel.org; linux-
>kernel@vger.kernel.org; dev@g0hl1n.net; Andrew Lunn <andrew@lunn.ch>
>Subject: Re: [PATCH 2/2] net: ethernet: fsl: add phy reset after clk enable
>option
>
>
>On 07/07/2017 09:03 AM, Andy Duan wrote:
>> From: Richard Leitner <richard.leitner@skidata.com> Sent: Friday, July
>> 07, 2017 1:51 PM
>>>> Since it is common issue so long as using the PHY, can you move it
>>>> into smsc
>>> phy driver like in .smsc_phy_reset() function ?
>>>> And get the reset pin from phy dts node.
>>>
>>> Some more points that come into my mind:
>>>  - The smsc_phy_reset function is registered as "soft_reset". Would
>>> it be OK to use nRST in it?
>>
>> It is not reasonable.
>>
>>>  - Would it be OK to call the phy_init_hw function from within the
>>> smsc_phy_reset?
>>
>> No, phy_init_hw() already call .drv->soft_reset().
>>
>>>  - IMHO I'd have to move the reset gpio binding inside the phy node
>>> then. Isn't that a pretty big change doing that for all PHYs/FECs? Would it be
>"worth" it?
>>>
>> To make the change to be common, there have big change for phy driver.
>> Maybe somebody can give one good suggestion/solution for it.
>
>Sorry, I don't think I understood everything correctly:
>
>1. The "phy-reset-gpios" binding should go inside the phy node. This will cause
>to *change ALL FEC and PHY drivers*. Correct?
>
The "phy-reset-gpios" binding should go inside the phy node that is more reasonable.
It is better PHY core driver handle phy hw reset.

>2. Add an additonal "hard reset" function to the PHY driver which handles the
>"phy-reset-gpios". Correct?
>
Correct.

>3. Who should then trigger the "hard reset" of the PHY? phy_init_hw? The FEC?
>
>The point is that the LAN8710 is currently not always working correctly,
>therefore this small change was proposed. Should we really change all
>PHY/FECs only because of this?
>Furthermore one problem still remains: The enet_refclk is controlled by the
>FEC. How does the PHY recognize when it was disabled/enabled?
>
Your patch is workaround for the issue. As you pointed out these is a common issue.
So we hope to get a better solution to handle these in common code.

Andy
Richard Leitner July 7, 2017, 11:16 a.m. UTC | #8
Hi Andy,
thanks for the clarifications!

On 07/07/2017 01:08 PM, Andy Duan wrote:
>> 3. Who should then trigger the "hard reset" of the PHY? phy_init_hw? The FEC?
>>
>> The point is that the LAN8710 is currently not always working correctly,
>> therefore this small change was proposed. Should we really change all
>> PHY/FECs only because of this?
>> Furthermore one problem still remains: The enet_refclk is controlled by the
>> FEC. How does the PHY recognize when it was disabled/enabled?
>>
> Your patch is workaround for the issue. As you pointed out these is a common issue.
> So we hope to get a better solution to handle these in common code.

Ok. I'm fine with moving the phy-reset-gpios binding into the PHY. But 
one question still remains: Who should then trigger the "hard reset" of 
the PHY?

The PHY itself doesn't "know" when the refclk is turned off/on. So the 
FEC still must call some function of the PHY after the clock was enabled 
again. So the phy-reset-after-clk-enable property will remain in the fec 
node? Or am I missing something?
Andrew Lunn July 7, 2017, 2 p.m. UTC | #9
> Ok. I'm fine with moving the phy-reset-gpios binding into the PHY.
> But one question still remains: Who should then trigger the "hard
> reset" of the PHY?

Hi Richard

I think i see a few whys to do this, but first i need to check
something. Is the clock which is causing a problem this one:

        /* clk_ref is optional, depends on board */
        fep->clk_ref = devm_clk_get(&pdev->dev, "enet_clk_ref");
        if (IS_ERR(fep->clk_ref))
                fep->clk_ref = NULL;

Possible solutions:

1) clocks are referenced counted. If it is turned on twice, it needs
   to be turned off twice before it is actually turned off. So, make
   the PHY driver also clk_prepare_enable() this clock. When the FEC
   tries to turn it off, it will stay ticking. Problem avoided, at the
   expense of some power.

2) More complex, but make the PHY driver also a clock driver. Have the
   PHY driver export a clock which the FEC use, as "enet_clk_ref". The
   implementation of this clock, would both turn the real clock on,
   and the perform the reset.

Both require no changes to the FEC, or any other MAC driver using this
PHY, so long as the MAC driver uses the common clock infrastructure to
control the clock to the PHY.

	Andrew
Rob Herring July 10, 2017, 1:26 p.m. UTC | #10
On Thu, Jul 06, 2017 at 03:05:30PM +0200, Richard Leitner wrote:
> Some PHYs (for example the LAN8710) doesn't allow turning the clocks off
> and on again without reset (according to their datasheet). Exactly this
> behaviour was introduced for power saving reasons by commit e8fcfcd5684a
> ("net: fec: optimize the clock management to save power")
> Therefore add a devictree option to perform a PHY reset and
> configuration after every clock enable.
> 
> For a better understanding here's a outline of the time response of the
> clock and reset lines before and after this patch:
> 
> 			  v--fec_probe()              v--fec_enet_open()
> 			  v                           v
> 	w/o patch eCLK: ___||||||||____________________|||||||||||||||||
> 	w/o patch nRST: ----__------------------------------------------
> 	w/o patch CONF: _______XX_______________________________________
> 
> 	w/  patch eCLK: ___||||||||____________________|||||||||||||||||
> 	w/  patch nRST: ----__--------------------------__--------------
> 	w/  patch CONF: _______XX__________________________XX___________
> 			  ^                           ^
> 			  ^--fec_probe()              ^--fec_enet_open()
> 
> In our case this problem does occur at about every 10th to 50th POR of
> an LAN8710 connected to an i.MX6 SoC. The typical symptom of this
> problem is a "swinging" ethernet link. Similar issues were experienced
> by users of the NXP forum:
> 	https://community.nxp.com/thread/389902
> 	https://community.nxp.com/message/309354
> With this patch applied the issue didn't occur for at least a few
> hundred PORs of our board.
> 
> Fixes: e8fcfcd5684a ("net: fec: optimize the clock management to sa...")
> Signed-off-by: Richard Leitner <richard.leitner@skidata.com>
> ---
>  Documentation/devicetree/bindings/net/fsl-fec.txt |  3 +++
>  drivers/net/ethernet/freescale/fec.h              |  1 +
>  drivers/net/ethernet/freescale/fec_main.c         | 16 ++++++++++++++++
>  3 files changed, 20 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/net/fsl-fec.txt b/Documentation/devicetree/bindings/net/fsl-fec.txt
> index 6f55bdd..1766579 100644
> --- a/Documentation/devicetree/bindings/net/fsl-fec.txt
> +++ b/Documentation/devicetree/bindings/net/fsl-fec.txt
> @@ -23,6 +23,9 @@ Optional properties:
>  - phy-handle : phandle to the PHY device connected to this device.
>  - fixed-link : Assume a fixed link. See fixed-link.txt in the same directory.
>    Use instead of phy-handle.
> +- phy-reset-after-clk-enable : If present then a phy reset and configuration
> +  will be performed everytime after the clocks are enabled. This is required
> +  for some PHYs to work properly.

Maybe this is not needed based on the discussion, but just to make 
sure. Since this is a property of the phy, it should be implied from the 
phy's compatible string.

Rob
Richard Leitner July 12, 2017, 9:21 a.m. UTC | #11
On 07/07/2017 04:00 PM, Andrew Lunn wrote:
>> Ok. I'm fine with moving the phy-reset-gpios binding into the PHY.
>> But one question still remains: Who should then trigger the "hard
>> reset" of the PHY?
> 
> Hi Richard
> 
> I think i see a few whys to do this, but first i need to check
> something. Is the clock which is causing a problem this one:
> 
>         /* clk_ref is optional, depends on board */
>         fep->clk_ref = devm_clk_get(&pdev->dev, "enet_clk_ref");
>         if (IS_ERR(fep->clk_ref))
>                 fep->clk_ref = NULL;

Yes. It's this one.

> 
> Possible solutions:
> 
> 1) clocks are referenced counted. If it is turned on twice, it needs
>    to be turned off twice before it is actually turned off. So, make
>    the PHY driver also clk_prepare_enable() this clock. When the FEC
>    tries to turn it off, it will stay ticking. Problem avoided, at the
>    expense of some power.

Somehow this approach triggers a "workaround-feeling" for me...
Furthermore as you say it "wastes" (at least some) power. For exactly
this reason the disabling of the clock was implemented in commit
e8fcfcd5684a ("net: fec: optimize the clock management to save power").

> 
> 2) More complex, but make the PHY driver also a clock driver. Have the
>    PHY driver export a clock which the FEC use, as "enet_clk_ref". The
>    implementation of this clock, would both turn the real clock on,
>    and the perform the reset.

This seems as a good solution to me. Furthermore IMHO it would be good
to move all PHY related dt bindings (reset-gpio, clk, etc.) from the MAC
into the PHY node.

Or are there any reasons/arguments against this approach?

> 
> Both require no changes to the FEC, or any other MAC driver using this
> PHY, so long as the MAC driver uses the common clock infrastructure to
> control the clock to the PHY.
As (IMHO) the new approach likely won't be backported to stable releases
I want to stress again the point that commit e8fcfcd5684a
("net: fec: optimize the clock management to save power") introduced
this problem and therefore "broke the PHY" for our board.

So would it be possible to add a "quick" bugfix patch (maybe this patch
or another one removing the clk disable) so this fix can be backported
to stable? Otherwise our board is only working with another
"out-of-tree" patch (which I want to avoid)...

kind regards,
Richard.L
Andrew Lunn July 12, 2017, 1:40 p.m. UTC | #12
> So would it be possible to add a "quick" bugfix patch (maybe this patch
> or another one removing the clk disable) so this fix can be backported
> to stable? Otherwise our board is only working with another
> "out-of-tree" patch (which I want to avoid)...

Hi Richard

It is a clear regression, so a minimal fix would be accepted to
stable.

	Andrew
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/net/fsl-fec.txt b/Documentation/devicetree/bindings/net/fsl-fec.txt
index 6f55bdd..1766579 100644
--- a/Documentation/devicetree/bindings/net/fsl-fec.txt
+++ b/Documentation/devicetree/bindings/net/fsl-fec.txt
@@ -23,6 +23,9 @@  Optional properties:
 - phy-handle : phandle to the PHY device connected to this device.
 - fixed-link : Assume a fixed link. See fixed-link.txt in the same directory.
   Use instead of phy-handle.
+- phy-reset-after-clk-enable : If present then a phy reset and configuration
+  will be performed everytime after the clocks are enabled. This is required
+  for some PHYs to work properly.
 - fsl,num-tx-queues : The property is valid for enet-avb IP, which supports
   hw multi queues. Should specify the tx queue number, otherwise set tx queue
   number to 1.
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 3da8084..d4f658a 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -538,6 +538,7 @@  struct fec_enet_private {
 	int	phy_reset_duration;
 	int	phy_reset_post_delay;
 	bool	phy_reset_active_high;
+	bool	phy_reset_after_clk_enable;
 
 	struct	napi_struct napi;
 	int	csum_flags;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index cbbf7b8..4e744f3 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -68,6 +68,7 @@ 
 
 static void set_multicast_list(struct net_device *ndev);
 static void fec_enet_itr_coal_init(struct net_device *ndev);
+static int fec_reset_phy(struct net_device *ndev);
 
 #define DRIVER_NAME	"fec"
 
@@ -1862,6 +1863,18 @@  static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
 		ret = clk_prepare_enable(fep->clk_ref);
 		if (ret)
 			goto failed_clk_ref;
+
+		/* reset the phy after clk is enabled if it's configured */
+		if (fep->phy_reset_after_clk_enable) {
+			ret = fec_reset_phy(ndev);
+			if (ret)
+				goto failed_reset;
+			if (ndev->phydev) {
+				ret = phy_init_hw(ndev->phydev);
+				if (ret)
+					goto failed_reset;
+			}
+		}
 	} else {
 		clk_disable_unprepare(fep->clk_ahb);
 		clk_disable_unprepare(fep->clk_enet_out);
@@ -1876,6 +1889,7 @@  static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
 
 	return 0;
 
+failed_reset:
 failed_clk_ref:
 	if (fep->clk_ref)
 		clk_disable_unprepare(fep->clk_ref);
@@ -3350,6 +3364,7 @@  fec_probe(struct platform_device *pdev)
 			fep->phy_reset_post_delay = 1;
 
 		fep->phy_reset_active_high =  of_property_read_bool(np, "phy-reset-active-high");
+		fep->phy_reset_after_clk_enable = of_property_read_bool(np, "phy-reset-after-clk-enable");
 
 		ret = devm_gpio_request_one(&pdev->dev, fep->phy_reset,
 					    fep->phy_reset_active_high ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
@@ -3360,6 +3375,7 @@  fec_probe(struct platform_device *pdev)
 		}
 	} else {
 		fep->phy_reset = 0;
+		fep->phy_reset_after_clk_enable = false;
 	}
 
 	ret = of_get_phy_mode(pdev->dev.of_node);