diff mbox series

[RFC,net] net: phy: fix the issue that netif always links up after resuming

Message ID 1543479131-14097-1-git-send-email-hayashi.kunihiko@socionext.com
State New
Headers show
Series [RFC,net] net: phy: fix the issue that netif always links up after resuming | expand

Commit Message

Kunihiko Hayashi Nov. 29, 2018, 8:12 a.m. UTC
Even though the link is down before entering hibernation,
there is an issue that the network interface always links up after resuming
from hibernation.

The phydev->state is PHY_READY before enabling the network interface, so
the link is down. After resuming from hibernation, the phydev->state is
forcibly set to PHY_UP in mdio_bus_phy_restore(), and the link becomes up.

This patch expects to solve the issue by changing phydev->state to PHY_UP
only when the link is up.

Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>

---
 drivers/net/phy/phy_device.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

-- 
2.7.4

Comments

Heiner Kallweit Nov. 29, 2018, 10:47 p.m. UTC | #1
On 29.11.2018 09:12, Kunihiko Hayashi wrote:
> Even though the link is down before entering hibernation,

> there is an issue that the network interface always links up after resuming

> from hibernation.

> 

> The phydev->state is PHY_READY before enabling the network interface, so

> the link is down. After resuming from hibernation, the phydev->state is

> forcibly set to PHY_UP in mdio_bus_phy_restore(), and the link becomes up.

> 

> This patch expects to solve the issue by changing phydev->state to PHY_UP

> only when the link is up.

> 

> Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>

> ---

>  drivers/net/phy/phy_device.c | 6 ++++--

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

> 

> diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c

> index ab33d17..d5bba0f 100644

> --- a/drivers/net/phy/phy_device.c

> +++ b/drivers/net/phy/phy_device.c

> @@ -309,8 +309,10 @@ static int mdio_bus_phy_restore(struct device *dev)

>  		return ret;

>  

>  	/* The PHY needs to renegotiate. */

> -	phydev->link = 0;

> -	phydev->state = PHY_UP;

> +	if (phydev->link) {

> +		phydev->link = 0;

> +		phydev->state = PHY_UP;

> +	}

>  

Thanks for reporting. I agree that it isn't right to unconditionally set
PHY_UP, because we don't know whether the PHY was started before
hibernation. However I don't think using phydev->link as criteria is
right. Example would be: PHY was started before hibernation, but w/o link.
In this case we want to set PHY_UP to start an aneg, because a cable may
have been plugged in whilst system was sleeping.

So I think, similar to phy_stop_machine, we should use state >= UP and
state != HALTED as criteria, and also phy_start_machine() would need to
be called only if this criteria is met.

It may make sense to add a helper for checking whether PHY is in a
started state (>=UP && !=HALTED), because we need this in more than
one place.

>  	phy_start_machine(phydev);

>  

>
Florian Fainelli Nov. 30, 2018, 12:37 a.m. UTC | #2
On 11/29/2018 2:47 PM, Heiner Kallweit wrote:
> On 29.11.2018 09:12, Kunihiko Hayashi wrote:

>> Even though the link is down before entering hibernation,

>> there is an issue that the network interface always links up after resuming

>> from hibernation.

>>

>> The phydev->state is PHY_READY before enabling the network interface, so

>> the link is down. After resuming from hibernation, the phydev->state is

>> forcibly set to PHY_UP in mdio_bus_phy_restore(), and the link becomes up.

>>

>> This patch expects to solve the issue by changing phydev->state to PHY_UP

>> only when the link is up.

>>

>> Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>

>> ---

>>  drivers/net/phy/phy_device.c | 6 ++++--

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

>>

>> diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c

>> index ab33d17..d5bba0f 100644

>> --- a/drivers/net/phy/phy_device.c

>> +++ b/drivers/net/phy/phy_device.c

>> @@ -309,8 +309,10 @@ static int mdio_bus_phy_restore(struct device *dev)

>>  		return ret;

>>  

>>  	/* The PHY needs to renegotiate. */

>> -	phydev->link = 0;

>> -	phydev->state = PHY_UP;

>> +	if (phydev->link) {

>> +		phydev->link = 0;

>> +		phydev->state = PHY_UP;

>> +	}

>>  

> Thanks for reporting. I agree that it isn't right to unconditionally set

> PHY_UP, because we don't know whether the PHY was started before

> hibernation. However I don't think using phydev->link as criteria is

> right. Example would be: PHY was started before hibernation, but w/o link.

> In this case we want to set PHY_UP to start an aneg, because a cable may

> have been plugged in whilst system was sleeping.

> 

> So I think, similar to phy_stop_machine, we should use state >= UP and

> state != HALTED as criteria, and also phy_start_machine() would need to

> be called only if this criteria is met.

> 

> It may make sense to add a helper for checking whether PHY is in a

> started state (>=UP && !=HALTED), because we need this in more than

> one place.


Agreed, that would make sense.
-- 
Florian
Kunihiko Hayashi Nov. 30, 2018, 4:37 a.m. UTC | #3
Hi Heiner Florian,

Thank you for your comments.

On Thu, 29 Nov 2018 16:37:48 -0800 <f.fainelli@gmail.com> wrote:

> 

> 

> On 11/29/2018 2:47 PM, Heiner Kallweit wrote:

> > On 29.11.2018 09:12, Kunihiko Hayashi wrote:

> >> Even though the link is down before entering hibernation,

> >> there is an issue that the network interface always links up after resuming

> >> from hibernation.

> >>

> >> The phydev->state is PHY_READY before enabling the network interface, so

> >> the link is down. After resuming from hibernation, the phydev->state is

> >> forcibly set to PHY_UP in mdio_bus_phy_restore(), and the link becomes up.

> >>

> >> This patch expects to solve the issue by changing phydev->state to PHY_UP

> >> only when the link is up.

> >>

> >> Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>

> >> ---

> >>  drivers/net/phy/phy_device.c | 6 ++++--

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

> >>

> >> diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c

> >> index ab33d17..d5bba0f 100644

> >> --- a/drivers/net/phy/phy_device.c

> >> +++ b/drivers/net/phy/phy_device.c

> >> @@ -309,8 +309,10 @@ static int mdio_bus_phy_restore(struct device *dev)

> >>  		return ret;

> >>  

> >>  	/* The PHY needs to renegotiate. */

> >> -	phydev->link = 0;

> >> -	phydev->state = PHY_UP;

> >> +	if (phydev->link) {

> >> +		phydev->link = 0;

> >> +		phydev->state = PHY_UP;

> >> +	}

> >>  

> > Thanks for reporting. I agree that it isn't right to unconditionally set

> > PHY_UP, because we don't know whether the PHY was started before

> > hibernation. However I don't think using phydev->link as criteria is

> > right. Example would be: PHY was started before hibernation, but w/o link.

> > In this case we want to set PHY_UP to start an aneg, because a cable may

> > have been plugged in whilst system was sleeping.


Indeed. I didn't consider the case that the PHY was started but a cable was
unplugged before hibernation.

> > So I think, similar to phy_stop_machine, we should use state >= UP and

> > state != HALTED as criteria, and also phy_start_machine() would need to

> > be called only if this criteria is met.

> > 

> > It may make sense to add a helper for checking whether PHY is in a

> > started state (>=UP && !=HALTED), because we need this in more than

> > one place.

> 

> Agreed, that would make sense.


I agree, too.
I'll try this in v2 patch that changes the PHY state to PHY_UP and calls
phy_start_machine(), only when the PHY was started before hibernation.
If I understand correctly, it will be like that:

	phydev->link = 0;
	if (phy_is_started(phydev)) {
		phydev->state = PHY_UP;
		phy_start_machine(phydev);
	}

Thank you,

---
Best Regards,
Kunihiko Hayashi
Heiner Kallweit Nov. 30, 2018, 6:20 a.m. UTC | #4
On 30.11.2018 05:37, Kunihiko Hayashi wrote:
> Hi Heiner Florian,

> 

> Thank you for your comments.

> 

> On Thu, 29 Nov 2018 16:37:48 -0800 <f.fainelli@gmail.com> wrote:

> 

>>

>>

>> On 11/29/2018 2:47 PM, Heiner Kallweit wrote:

>>> On 29.11.2018 09:12, Kunihiko Hayashi wrote:

>>>> Even though the link is down before entering hibernation,

>>>> there is an issue that the network interface always links up after resuming

>>>> from hibernation.

>>>>

>>>> The phydev->state is PHY_READY before enabling the network interface, so

>>>> the link is down. After resuming from hibernation, the phydev->state is

>>>> forcibly set to PHY_UP in mdio_bus_phy_restore(), and the link becomes up.

>>>>

>>>> This patch expects to solve the issue by changing phydev->state to PHY_UP

>>>> only when the link is up.

>>>>

>>>> Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>

>>>> ---

>>>>  drivers/net/phy/phy_device.c | 6 ++++--

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

>>>>

>>>> diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c

>>>> index ab33d17..d5bba0f 100644

>>>> --- a/drivers/net/phy/phy_device.c

>>>> +++ b/drivers/net/phy/phy_device.c

>>>> @@ -309,8 +309,10 @@ static int mdio_bus_phy_restore(struct device *dev)

>>>>  		return ret;

>>>>  

>>>>  	/* The PHY needs to renegotiate. */

>>>> -	phydev->link = 0;

>>>> -	phydev->state = PHY_UP;

>>>> +	if (phydev->link) {

>>>> +		phydev->link = 0;

>>>> +		phydev->state = PHY_UP;

>>>> +	}

>>>>  

>>> Thanks for reporting. I agree that it isn't right to unconditionally set

>>> PHY_UP, because we don't know whether the PHY was started before

>>> hibernation. However I don't think using phydev->link as criteria is

>>> right. Example would be: PHY was started before hibernation, but w/o link.

>>> In this case we want to set PHY_UP to start an aneg, because a cable may

>>> have been plugged in whilst system was sleeping.

> 

> Indeed. I didn't consider the case that the PHY was started but a cable was

> unplugged before hibernation.

> 

>>> So I think, similar to phy_stop_machine, we should use state >= UP and

>>> state != HALTED as criteria, and also phy_start_machine() would need to

>>> be called only if this criteria is met.

>>>

>>> It may make sense to add a helper for checking whether PHY is in a

>>> started state (>=UP && !=HALTED), because we need this in more than

>>> one place.

>>

>> Agreed, that would make sense.

> 

> I agree, too.

> I'll try this in v2 patch that changes the PHY state to PHY_UP and calls

> phy_start_machine(), only when the PHY was started before hibernation.

> If I understand correctly, it will be like that:

> 

> 	phydev->link = 0;

Even this may go into the if clause. If PHY isn't started then
phydev->link should be 0 anyway.

> 	if (phy_is_started(phydev)) {

> 		phydev->state = PHY_UP;

> 		phy_start_machine(phydev);

> 	}

> 

Yes, this is what was meant. Thanks.

> Thank you,

> 

> ---

> Best Regards,

> Kunihiko Hayashi

> 

> 

>
Kunihiko Hayashi Nov. 30, 2018, 6:38 a.m. UTC | #5
Hi Heiner,

On Fri, 30 Nov 2018 07:20:27 +0100 <hkallweit1@gmail.com> wrote:

> On 30.11.2018 05:37, Kunihiko Hayashi wrote:

> > Hi Heiner Florian,

> > 

> > Thank you for your comments.

> > 

> > On Thu, 29 Nov 2018 16:37:48 -0800 <f.fainelli@gmail.com> wrote:

> > 

> >>

> >>

> >> On 11/29/2018 2:47 PM, Heiner Kallweit wrote:

> >>> On 29.11.2018 09:12, Kunihiko Hayashi wrote:

> >>>> Even though the link is down before entering hibernation,

> >>>> there is an issue that the network interface always links up after resuming

> >>>> from hibernation.

> >>>>

> >>>> The phydev->state is PHY_READY before enabling the network interface, so

> >>>> the link is down. After resuming from hibernation, the phydev->state is

> >>>> forcibly set to PHY_UP in mdio_bus_phy_restore(), and the link becomes up.

> >>>>

> >>>> This patch expects to solve the issue by changing phydev->state to PHY_UP

> >>>> only when the link is up.

> >>>>

> >>>> Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>

> >>>> ---

> >>>>  drivers/net/phy/phy_device.c | 6 ++++--

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

> >>>>

> >>>> diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c

> >>>> index ab33d17..d5bba0f 100644

> >>>> --- a/drivers/net/phy/phy_device.c

> >>>> +++ b/drivers/net/phy/phy_device.c

> >>>> @@ -309,8 +309,10 @@ static int mdio_bus_phy_restore(struct device *dev)

> >>>>  		return ret;

> >>>>  

> >>>>  	/* The PHY needs to renegotiate. */

> >>>> -	phydev->link = 0;

> >>>> -	phydev->state = PHY_UP;

> >>>> +	if (phydev->link) {

> >>>> +		phydev->link = 0;

> >>>> +		phydev->state = PHY_UP;

> >>>> +	}

> >>>>  

> >>> Thanks for reporting. I agree that it isn't right to unconditionally set

> >>> PHY_UP, because we don't know whether the PHY was started before

> >>> hibernation. However I don't think using phydev->link as criteria is

> >>> right. Example would be: PHY was started before hibernation, but w/o link.

> >>> In this case we want to set PHY_UP to start an aneg, because a cable may

> >>> have been plugged in whilst system was sleeping.

> > 

> > Indeed. I didn't consider the case that the PHY was started but a cable was

> > unplugged before hibernation.

> > 

> >>> So I think, similar to phy_stop_machine, we should use state >= UP and

> >>> state != HALTED as criteria, and also phy_start_machine() would need to

> >>> be called only if this criteria is met.

> >>>

> >>> It may make sense to add a helper for checking whether PHY is in a

> >>> started state (>=UP && !=HALTED), because we need this in more than

> >>> one place.

> >>

> >> Agreed, that would make sense.

> > 

> > I agree, too.

> > I'll try this in v2 patch that changes the PHY state to PHY_UP and calls

> > phy_start_machine(), only when the PHY was started before hibernation.

> > If I understand correctly, it will be like that:

> > 

> > 	phydev->link = 0;

> Even this may go into the if clause. If PHY isn't started then

> phydev->link should be 0 anyway.


Yes. To clarify more, this will go into the if clause. 

> 

> > 	if (phy_is_started(phydev)) {

> > 		phydev->state = PHY_UP;

> > 		phy_start_machine(phydev);

> > 	}

> > 

> Yes, this is what was meant. Thanks.


Thank you,

---
Best Regards,
Kunihiko Hayashi
diff mbox series

Patch

diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index ab33d17..d5bba0f 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -309,8 +309,10 @@  static int mdio_bus_phy_restore(struct device *dev)
 		return ret;
 
 	/* The PHY needs to renegotiate. */
-	phydev->link = 0;
-	phydev->state = PHY_UP;
+	if (phydev->link) {
+		phydev->link = 0;
+		phydev->state = PHY_UP;
+	}
 
 	phy_start_machine(phydev);