diff mbox series

net: fec: Fix phy_device lookup for phy_reset_after_clk_enable()

Message ID 20201006202029.254212-1-marex@denx.de
State New
Headers show
Series net: fec: Fix phy_device lookup for phy_reset_after_clk_enable() | expand

Commit Message

Marek Vasut Oct. 6, 2020, 8:20 p.m. UTC
The phy_reset_after_clk_enable() is always called with ndev->phydev,
however that pointer may be NULL even though the PHY device instance
already exists and is sufficient to perform the PHY reset.

If the PHY still is not bound to the MAC, but there is OF PHY node
and a matching PHY device instance already, use the OF PHY node to
obtain the PHY device instance, and then use that PHY device instance
when triggering the PHY reset.

Fixes: 1b0a83ac04e3 ("net: fec: add phy_reset_after_clk_enable() support")
Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Christoph Niedermaier <cniedermaier@dh-electronics.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: NXP Linux Team <linux-imx@nxp.com>
Cc: Richard Leitner <richard.leitner@skidata.com>
Cc: Shawn Guo <shawnguo@kernel.org>
---
 drivers/net/ethernet/freescale/fec_main.c | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

Comments

Florian Fainelli Oct. 6, 2020, 9:09 p.m. UTC | #1
On 10/6/2020 1:20 PM, Marek Vasut wrote:
> The phy_reset_after_clk_enable() is always called with ndev->phydev,

> however that pointer may be NULL even though the PHY device instance

> already exists and is sufficient to perform the PHY reset.

> 

> If the PHY still is not bound to the MAC, but there is OF PHY node

> and a matching PHY device instance already, use the OF PHY node to

> obtain the PHY device instance, and then use that PHY device instance

> when triggering the PHY reset.

> 

> Fixes: 1b0a83ac04e3 ("net: fec: add phy_reset_after_clk_enable() support")

> Signed-off-by: Marek Vasut <marex@denx.de>

> Cc: Christoph Niedermaier <cniedermaier@dh-electronics.com>

> Cc: David S. Miller <davem@davemloft.net>

> Cc: NXP Linux Team <linux-imx@nxp.com>

> Cc: Richard Leitner <richard.leitner@skidata.com>

> Cc: Shawn Guo <shawnguo@kernel.org>

> ---

>   drivers/net/ethernet/freescale/fec_main.c | 22 ++++++++++++++++++++--

>   1 file changed, 20 insertions(+), 2 deletions(-)

> 

> diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c

> index 2d5433301843..5a4b20941aeb 100644

> --- a/drivers/net/ethernet/freescale/fec_main.c

> +++ b/drivers/net/ethernet/freescale/fec_main.c

> @@ -1912,6 +1912,24 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,

>   	return ret;

>   }

>   

> +static void fec_enet_phy_reset_after_clk_enable(struct net_device *ndev)

> +{

> +	struct fec_enet_private *fep = netdev_priv(ndev);

> +	struct phy_device *phy_dev = ndev->phydev;

> +

> +	/*

> +	 * If the PHY still is not bound to the MAC, but there is

> +	 * OF PHY node and a matching PHY device instance already,

> +	 * use the OF PHY node to obtain the PHY device instance,

> +	 * and then use that PHY device instance when triggering

> +	 * the PHY reset.

> +	 */

> +	if (!phy_dev && fep->phy_node)

> +		phy_dev = of_phy_find_device(fep->phy_node);


Don't you need to put the phy_dev reference at some point?
-- 
Florian
Marek Vasut Oct. 6, 2020, 10:02 p.m. UTC | #2
On 10/6/20 11:09 PM, Florian Fainelli wrote:
> 

> 

> On 10/6/2020 1:20 PM, Marek Vasut wrote:

>> The phy_reset_after_clk_enable() is always called with ndev->phydev,

>> however that pointer may be NULL even though the PHY device instance

>> already exists and is sufficient to perform the PHY reset.

>>

>> If the PHY still is not bound to the MAC, but there is OF PHY node

>> and a matching PHY device instance already, use the OF PHY node to

>> obtain the PHY device instance, and then use that PHY device instance

>> when triggering the PHY reset.

>>

>> Fixes: 1b0a83ac04e3 ("net: fec: add phy_reset_after_clk_enable()

>> support")

>> Signed-off-by: Marek Vasut <marex@denx.de>

>> Cc: Christoph Niedermaier <cniedermaier@dh-electronics.com>

>> Cc: David S. Miller <davem@davemloft.net>

>> Cc: NXP Linux Team <linux-imx@nxp.com>

>> Cc: Richard Leitner <richard.leitner@skidata.com>

>> Cc: Shawn Guo <shawnguo@kernel.org>

>> ---

>>   drivers/net/ethernet/freescale/fec_main.c | 22 ++++++++++++++++++++--

>>   1 file changed, 20 insertions(+), 2 deletions(-)

>>

>> diff --git a/drivers/net/ethernet/freescale/fec_main.c

>> b/drivers/net/ethernet/freescale/fec_main.c

>> index 2d5433301843..5a4b20941aeb 100644

>> --- a/drivers/net/ethernet/freescale/fec_main.c

>> +++ b/drivers/net/ethernet/freescale/fec_main.c

>> @@ -1912,6 +1912,24 @@ static int fec_enet_mdio_write(struct mii_bus

>> *bus, int mii_id, int regnum,

>>       return ret;

>>   }

>>   +static void fec_enet_phy_reset_after_clk_enable(struct net_device

>> *ndev)

>> +{

>> +    struct fec_enet_private *fep = netdev_priv(ndev);

>> +    struct phy_device *phy_dev = ndev->phydev;

>> +

>> +    /*

>> +     * If the PHY still is not bound to the MAC, but there is

>> +     * OF PHY node and a matching PHY device instance already,

>> +     * use the OF PHY node to obtain the PHY device instance,

>> +     * and then use that PHY device instance when triggering

>> +     * the PHY reset.

>> +     */

>> +    if (!phy_dev && fep->phy_node)

>> +        phy_dev = of_phy_find_device(fep->phy_node);

> 

> Don't you need to put the phy_dev reference at some point?


Probably, yes.

But first, does this approach and this patch even make sense ?
I mean, it fixes my problem, but is this right ?
Jakub Kicinski Oct. 9, 2020, 12:46 a.m. UTC | #3
On Wed, 7 Oct 2020 00:02:42 +0200 Marek Vasut wrote:
> On 10/6/20 11:09 PM, Florian Fainelli wrote:

> > On 10/6/2020 1:20 PM, Marek Vasut wrote:  

> >> The phy_reset_after_clk_enable() is always called with ndev->phydev,

> >> however that pointer may be NULL even though the PHY device instance

> >> already exists and is sufficient to perform the PHY reset.

> >>

> >> If the PHY still is not bound to the MAC, but there is OF PHY node

> >> and a matching PHY device instance already, use the OF PHY node to

> >> obtain the PHY device instance, and then use that PHY device instance

> >> when triggering the PHY reset.

> >>

> >> Fixes: 1b0a83ac04e3 ("net: fec: add phy_reset_after_clk_enable()

> >> support")

> >> Signed-off-by: Marek Vasut <marex@denx.de>


> >> diff --git a/drivers/net/ethernet/freescale/fec_main.c

> >> b/drivers/net/ethernet/freescale/fec_main.c

> >> index 2d5433301843..5a4b20941aeb 100644

> >> --- a/drivers/net/ethernet/freescale/fec_main.c

> >> +++ b/drivers/net/ethernet/freescale/fec_main.c

> >> @@ -1912,6 +1912,24 @@ static int fec_enet_mdio_write(struct mii_bus

> >> *bus, int mii_id, int regnum,

> >>       return ret;

> >>   }

> >>   +static void fec_enet_phy_reset_after_clk_enable(struct net_device

> >> *ndev)

> >> +{

> >> +    struct fec_enet_private *fep = netdev_priv(ndev);

> >> +    struct phy_device *phy_dev = ndev->phydev;

> >> +

> >> +    /*

> >> +     * If the PHY still is not bound to the MAC, but there is

> >> +     * OF PHY node and a matching PHY device instance already,

> >> +     * use the OF PHY node to obtain the PHY device instance,

> >> +     * and then use that PHY device instance when triggering

> >> +     * the PHY reset.

> >> +     */

> >> +    if (!phy_dev && fep->phy_node)

> >> +        phy_dev = of_phy_find_device(fep->phy_node);  

> > 

> > Don't you need to put the phy_dev reference at some point?  

> 

> Probably, yes.

> 

> But first, does this approach and this patch even make sense ?

> I mean, it fixes my problem, but is this right ?


Can you describe your problem in detail?

To an untrained eye this looks pretty weird.
Marek Vasut Oct. 9, 2020, 7:20 a.m. UTC | #4
On 10/9/20 2:46 AM, Jakub Kicinski wrote:
> On Wed, 7 Oct 2020 00:02:42 +0200 Marek Vasut wrote:

>> On 10/6/20 11:09 PM, Florian Fainelli wrote:

>>> On 10/6/2020 1:20 PM, Marek Vasut wrote:  

>>>> The phy_reset_after_clk_enable() is always called with ndev->phydev,

>>>> however that pointer may be NULL even though the PHY device instance

>>>> already exists and is sufficient to perform the PHY reset.

>>>>

>>>> If the PHY still is not bound to the MAC, but there is OF PHY node

>>>> and a matching PHY device instance already, use the OF PHY node to

>>>> obtain the PHY device instance, and then use that PHY device instance

>>>> when triggering the PHY reset.

>>>>

>>>> Fixes: 1b0a83ac04e3 ("net: fec: add phy_reset_after_clk_enable()

>>>> support")

>>>> Signed-off-by: Marek Vasut <marex@denx.de>

> 

>>>> diff --git a/drivers/net/ethernet/freescale/fec_main.c

>>>> b/drivers/net/ethernet/freescale/fec_main.c

>>>> index 2d5433301843..5a4b20941aeb 100644

>>>> --- a/drivers/net/ethernet/freescale/fec_main.c

>>>> +++ b/drivers/net/ethernet/freescale/fec_main.c

>>>> @@ -1912,6 +1912,24 @@ static int fec_enet_mdio_write(struct mii_bus

>>>> *bus, int mii_id, int regnum,

>>>>       return ret;

>>>>   }

>>>>   +static void fec_enet_phy_reset_after_clk_enable(struct net_device

>>>> *ndev)

>>>> +{

>>>> +    struct fec_enet_private *fep = netdev_priv(ndev);

>>>> +    struct phy_device *phy_dev = ndev->phydev;

>>>> +

>>>> +    /*

>>>> +     * If the PHY still is not bound to the MAC, but there is

>>>> +     * OF PHY node and a matching PHY device instance already,

>>>> +     * use the OF PHY node to obtain the PHY device instance,

>>>> +     * and then use that PHY device instance when triggering

>>>> +     * the PHY reset.

>>>> +     */

>>>> +    if (!phy_dev && fep->phy_node)

>>>> +        phy_dev = of_phy_find_device(fep->phy_node);  

>>>

>>> Don't you need to put the phy_dev reference at some point?  

>>

>> Probably, yes.

>>

>> But first, does this approach and this patch even make sense ?

>> I mean, it fixes my problem, but is this right ?

> 

> Can you describe your problem in detail?


Yes, I tried to do that in the commit message and the extra detailed
comment above the code. What exactly do you not understand from that?

> To an untrained eye this looks pretty weird.


I see, I'm not quite sure how to address this comment.
Jakub Kicinski Oct. 9, 2020, 3:15 p.m. UTC | #5
On Fri, 9 Oct 2020 09:20:30 +0200 Marek Vasut wrote:
> > Can you describe your problem in detail?  

> 

> Yes, I tried to do that in the commit message and the extra detailed

> comment above the code. What exactly do you not understand from that?


Why it's not bound on the first open (I'm guessing it's the first open
that has the ndev->phydev == NULL? I shouldn't have to guess).

> > To an untrained eye this looks pretty weird.  

> 

> I see, I'm not quite sure how to address this comment.


If ndev->phydev sometimes is not-NULL on open, then that's a valid
state to be in. Why not make sure that we're always in that state 
and can depend on ndev->phydev rather than rummaging around for 
the phy_device instance.
Marek Vasut Oct. 9, 2020, 5:34 p.m. UTC | #6
On 10/9/20 5:15 PM, Jakub Kicinski wrote:
> On Fri, 9 Oct 2020 09:20:30 +0200 Marek Vasut wrote:

>>> Can you describe your problem in detail?  

>>

>> Yes, I tried to do that in the commit message and the extra detailed

>> comment above the code. What exactly do you not understand from that?

> 

> Why it's not bound on the first open


It is getting bound on the first open. The problem is in probe(), where
fec_enet_clk_enable(ndev, true) [yes, the name of that function is bad]
calls fec_enet_phy_reset_after_clk_enable() and the ndev->phydev is NULL
while there is already existing instance of that phydev .

So this patch adds this extra look up to get the phydev, which then
permits phy_reset_after_clk_enable() to call phy_device_reset() instead
of returning -ENODEV.

> (I'm guessing it's the first open

> that has the ndev->phydev == NULL? I shouldn't have to guess).


If I had a crystal ball that'd tell me all the review questions up
front, I would write perfect patches with all the feedback sorted out in
V1. Sorry, I don't have one ...

>>> To an untrained eye this looks pretty weird.  

>>

>> I see, I'm not quite sure how to address this comment.

> 

> If ndev->phydev sometimes is not-NULL on open, then that's a valid

> state to be in. Why not make sure that we're always in that state 

> and can depend on ndev->phydev rather than rummaging around for 

> the phy_device instance.


Nope, the problem is in probe() in this case.
Jakub Kicinski Oct. 9, 2020, 6:02 p.m. UTC | #7
On Fri, 9 Oct 2020 19:34:10 +0200 Marek Vasut wrote:
> >>> To an untrained eye this looks pretty weird.    

> >>

> >> I see, I'm not quite sure how to address this comment.  

> > 

> > If ndev->phydev sometimes is not-NULL on open, then that's a valid

> > state to be in. Why not make sure that we're always in that state 

> > and can depend on ndev->phydev rather than rummaging around for 

> > the phy_device instance.  

> 

> Nope, the problem is in probe() in this case.


In that case it would be cleaner to pass fep and phydev as arguments
into fec_enet_clk_enable(), rather than netdev, and have only probe()
do the necessary dance.
Marek Vasut Oct. 10, 2020, 8:45 a.m. UTC | #8
On 10/9/20 8:02 PM, Jakub Kicinski wrote:
> On Fri, 9 Oct 2020 19:34:10 +0200 Marek Vasut wrote:

>>>>> To an untrained eye this looks pretty weird.    

>>>>

>>>> I see, I'm not quite sure how to address this comment.  

>>>

>>> If ndev->phydev sometimes is not-NULL on open, then that's a valid

>>> state to be in. Why not make sure that we're always in that state 

>>> and can depend on ndev->phydev rather than rummaging around for 

>>> the phy_device instance.  

>>

>> Nope, the problem is in probe() in this case.

> 

> In that case it would be cleaner to pass fep and phydev as arguments

> into fec_enet_clk_enable(), rather than netdev, and have only probe()

> do the necessary dance.


So correction, the problem does only happen in open(), in probe() the
phydev->drv is still NULL so the PHY reset cannot be triggered. In
open(), first the clock have to be enabled, then the reset must toggle,
then the PHY IDs can be reliably read.

I suspect reset in probe() will need another patch.
diff mbox series

Patch

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 2d5433301843..5a4b20941aeb 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1912,6 +1912,24 @@  static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
 	return ret;
 }
 
+static void fec_enet_phy_reset_after_clk_enable(struct net_device *ndev)
+{
+	struct fec_enet_private *fep = netdev_priv(ndev);
+	struct phy_device *phy_dev = ndev->phydev;
+
+	/*
+	 * If the PHY still is not bound to the MAC, but there is
+	 * OF PHY node and a matching PHY device instance already,
+	 * use the OF PHY node to obtain the PHY device instance,
+	 * and then use that PHY device instance when triggering
+	 * the PHY reset.
+	 */
+	if (!phy_dev && fep->phy_node)
+		phy_dev = of_phy_find_device(fep->phy_node);
+
+	phy_reset_after_clk_enable(phy_dev);
+}
+
 static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
 {
 	struct fec_enet_private *fep = netdev_priv(ndev);
@@ -1938,7 +1956,7 @@  static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
 		if (ret)
 			goto failed_clk_ref;
 
-		phy_reset_after_clk_enable(ndev->phydev);
+		fec_enet_phy_reset_after_clk_enable(ndev);
 	} else {
 		clk_disable_unprepare(fep->clk_enet_out);
 		if (fep->clk_ptp) {
@@ -2987,7 +3005,7 @@  fec_enet_open(struct net_device *ndev)
 	 * phy_reset_after_clk_enable() before because the PHY wasn't probed.
 	 */
 	if (reset_again)
-		phy_reset_after_clk_enable(ndev->phydev);
+		fec_enet_phy_reset_after_clk_enable(ndev);
 
 	/* Probe and connect to PHY when open the interface */
 	ret = fec_enet_mii_probe(ndev);