diff mbox series

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

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

Commit Message

Kunihiko Hayashi Dec. 3, 2018, 8:22 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 adds a new convenient function to check whether the PHY is in
a started state, and expects to solve the issue by changing phydev->state
to PHY_UP and calling phy_start_machine() only when the PHY is started.

Suggested-by: Heiner Kallweit <hkallweit1@gmail.com>
Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>

---

Changes since v2:
 - add mutex lock/unlock for changing phydev->state
 - check whether the mutex is locked in phy_is_started()
 
Changes since v1:
 - introduce a new helper function phy_is_started() and use it instead of
   checking link status
 - replace checking phydev->state with phy_is_started() in
   phy_stop_machine()

drivers/net/phy/phy.c        |  2 +-
 drivers/net/phy/phy_device.c | 12 +++++++++---
 include/linux/phy.h          | 13 +++++++++++++
 3 files changed, 23 insertions(+), 4 deletions(-)

-- 
2.7.4

Comments

Kunihiko Hayashi Dec. 17, 2018, 6:41 a.m. UTC | #1
Hi,

Gentle ping...
Are there any comments about changes since v2?

v2: https://www.spinics.net/lists/netdev/msg536926.html

Thank you,

On Mon, 3 Dec 2018 17:22:29 +0900 <hayashi.kunihiko@socionext.com> 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 adds a new convenient function to check whether the PHY is in

> a started state, and expects to solve the issue by changing phydev->state

> to PHY_UP and calling phy_start_machine() only when the PHY is started.

> 

> Suggested-by: Heiner Kallweit <hkallweit1@gmail.com>

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

> ---

> 

> Changes since v2:

>  - add mutex lock/unlock for changing phydev->state

>  - check whether the mutex is locked in phy_is_started()

>  

> Changes since v1:

>  - introduce a new helper function phy_is_started() and use it instead of

>    checking link status

>  - replace checking phydev->state with phy_is_started() in

>    phy_stop_machine()

> 

> drivers/net/phy/phy.c        |  2 +-

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

>  include/linux/phy.h          | 13 +++++++++++++

>  3 files changed, 23 insertions(+), 4 deletions(-)

> 

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

> index 1d73ac3..f484d03 100644

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

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

> @@ -670,7 +670,7 @@ void phy_stop_machine(struct phy_device *phydev)

>  	cancel_delayed_work_sync(&phydev->state_queue);

>  

>  	mutex_lock(&phydev->lock);

> -	if (phydev->state > PHY_UP && phydev->state != PHY_HALTED)

> +	if (phy_is_started(phydev))

>  		phydev->state = PHY_UP;

>  	mutex_unlock(&phydev->lock);

>  }

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

> index ab33d17..4897d24 100644

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

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

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

>  		return ret;

>  

>  	/* The PHY needs to renegotiate. */

> -	phydev->link = 0;

> -	phydev->state = PHY_UP;

> +	mutex_lock(&phydev->lock);

> +	if (phy_is_started(phydev)) {

> +		phydev->state = PHY_UP;

> +		mutex_unlock(&phydev->lock);

> +		phydev->link = 0;

> +		phy_start_machine(phydev);

> +	} else {

> +		mutex_unlock(&phydev->lock);

> +	}

>  

> -	phy_start_machine(phydev);

>  

>  	return 0;

>  }

> diff --git a/include/linux/phy.h b/include/linux/phy.h

> index 3ea87f7..dd21537 100644

> --- a/include/linux/phy.h

> +++ b/include/linux/phy.h

> @@ -898,6 +898,19 @@ static inline bool phy_is_pseudo_fixed_link(struct phy_device *phydev)

>  }

>  

>  /**

> + * phy_is_started - Convenience function for testing whether a PHY is in

> + * a started state

> + * @phydev: the phy_device struct

> + *

> + * The caller must have taken the phy_device mutex lock.

> + */

> +static inline bool phy_is_started(struct phy_device *phydev)

> +{

> +	WARN_ON(!mutex_is_locked(&phydev->lock));

> +	return phydev->state >= PHY_UP && phydev->state != PHY_HALTED;

> +}

> +

> +/**

>   * phy_write_mmd - Convenience function for writing a register

>   * on an MMD on a given PHY.

>   * @phydev: The phy_device struct

> -- 

> 2.7.4


---
Best Regards,
Kunihiko Hayashi
Heiner Kallweit Dec. 17, 2018, 6:41 p.m. UTC | #2
On 17.12.2018 07:41, Kunihiko Hayashi wrote:
> Hi,

> 

> Gentle ping...

> Are there any comments about changes since v2?

> 

> v2: https://www.spinics.net/lists/netdev/msg536926.html

> 

> Thank you,

> 

> On Mon, 3 Dec 2018 17:22:29 +0900 <hayashi.kunihiko@socionext.com> 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 adds a new convenient function to check whether the PHY is in

>> a started state, and expects to solve the issue by changing phydev->state

>> to PHY_UP and calling phy_start_machine() only when the PHY is started.

>>

This convenience function and the related change to phy_stop() are part of
the following already and don't need to be part of your patch.
https://patchwork.ozlabs.org/patch/1014171/

>> Suggested-by: Heiner Kallweit <hkallweit1@gmail.com>

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

>> ---

>>

>> Changes since v2:

>>  - add mutex lock/unlock for changing phydev->state

>>  - check whether the mutex is locked in phy_is_started()

>>  

>> Changes since v1:

>>  - introduce a new helper function phy_is_started() and use it instead of

>>    checking link status

>>  - replace checking phydev->state with phy_is_started() in

>>    phy_stop_machine()

>>

>> drivers/net/phy/phy.c        |  2 +-

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

>>  include/linux/phy.h          | 13 +++++++++++++

>>  3 files changed, 23 insertions(+), 4 deletions(-)

>>

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

>> index 1d73ac3..f484d03 100644

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

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

>> @@ -670,7 +670,7 @@ void phy_stop_machine(struct phy_device *phydev)

>>  	cancel_delayed_work_sync(&phydev->state_queue);

>>  

>>  	mutex_lock(&phydev->lock);

>> -	if (phydev->state > PHY_UP && phydev->state != PHY_HALTED)

>> +	if (phy_is_started(phydev))

>>  		phydev->state = PHY_UP;


I'm wondering whether we need to do this. If the PHY is attached,
then mdio_bus_phy_suspend() calls phy_stop_machine() which does
exactly the same. If the PHY is not attached, then we don't have
to do anything. Therefore I think we just have to do the same as
in mdio_bus_phy_resume():

if (phydev->attached_dev && phydev->adjust_link)
	phy_start_machine(phydev);

Can you test this?

>>  	mutex_unlock(&phydev->lock);

>>  }

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

>> index ab33d17..4897d24 100644

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

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

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

>>  		return ret;

>>  

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

>> -	phydev->link = 0;

>> -	phydev->state = PHY_UP;

>> +	mutex_lock(&phydev->lock);

>> +	if (phy_is_started(phydev)) {

>> +		phydev->state = PHY_UP;

>> +		mutex_unlock(&phydev->lock);

>> +		phydev->link = 0;

>> +		phy_start_machine(phydev);

>> +	} else {

>> +		mutex_unlock(&phydev->lock);

>> +	}

>>  

>> -	phy_start_machine(phydev);

>>  

>>  	return 0;

>>  }

>> diff --git a/include/linux/phy.h b/include/linux/phy.h

>> index 3ea87f7..dd21537 100644

>> --- a/include/linux/phy.h

>> +++ b/include/linux/phy.h

>> @@ -898,6 +898,19 @@ static inline bool phy_is_pseudo_fixed_link(struct phy_device *phydev)

>>  }

>>  

>>  /**

>> + * phy_is_started - Convenience function for testing whether a PHY is in

>> + * a started state

>> + * @phydev: the phy_device struct

>> + *

>> + * The caller must have taken the phy_device mutex lock.

>> + */

>> +static inline bool phy_is_started(struct phy_device *phydev)

>> +{

>> +	WARN_ON(!mutex_is_locked(&phydev->lock));

>> +	return phydev->state >= PHY_UP && phydev->state != PHY_HALTED;

>> +}

>> +

>> +/**

>>   * phy_write_mmd - Convenience function for writing a register

>>   * on an MMD on a given PHY.

>>   * @phydev: The phy_device struct

>> -- 

>> 2.7.4

> 

> ---

> Best Regards,

> Kunihiko Hayashi

> 

> 

>
Heiner Kallweit Dec. 17, 2018, 6:43 p.m. UTC | #3
On 17.12.2018 19:41, Heiner Kallweit wrote:
> On 17.12.2018 07:41, Kunihiko Hayashi wrote:

>> Hi,

>>

>> Gentle ping...

>> Are there any comments about changes since v2?

>>

>> v2: https://www.spinics.net/lists/netdev/msg536926.html

>>

>> Thank you,

>>

>> On Mon, 3 Dec 2018 17:22:29 +0900 <hayashi.kunihiko@socionext.com> 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 adds a new convenient function to check whether the PHY is in

>>> a started state, and expects to solve the issue by changing phydev->state

>>> to PHY_UP and calling phy_start_machine() only when the PHY is started.

>>>

> This convenience function and the related change to phy_stop() are part of

> the following already and don't need to be part of your patch.

> https://patchwork.ozlabs.org/patch/1014171/

> 

>>> Suggested-by: Heiner Kallweit <hkallweit1@gmail.com>

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

>>> ---

>>>

>>> Changes since v2:

>>>  - add mutex lock/unlock for changing phydev->state

>>>  - check whether the mutex is locked in phy_is_started()

>>>  

>>> Changes since v1:

>>>  - introduce a new helper function phy_is_started() and use it instead of

>>>    checking link status

>>>  - replace checking phydev->state with phy_is_started() in

>>>    phy_stop_machine()

>>>

>>> drivers/net/phy/phy.c        |  2 +-

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

>>>  include/linux/phy.h          | 13 +++++++++++++

>>>  3 files changed, 23 insertions(+), 4 deletions(-)

>>>

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

>>> index 1d73ac3..f484d03 100644

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

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

>>> @@ -670,7 +670,7 @@ void phy_stop_machine(struct phy_device *phydev)

>>>  	cancel_delayed_work_sync(&phydev->state_queue);

>>>  

>>>  	mutex_lock(&phydev->lock);

>>> -	if (phydev->state > PHY_UP && phydev->state != PHY_HALTED)

>>> +	if (phy_is_started(phydev))

>>>  		phydev->state = PHY_UP;

> 

> I'm wondering whether we need to do this. If the PHY is attached,

> then mdio_bus_phy_suspend() calls phy_stop_machine() which does

> exactly the same. If the PHY is not attached, then we don't have

> to do anything. Therefore I think we just have to do the same as

> in mdio_bus_phy_resume():

> 

> if (phydev->attached_dev && phydev->adjust_link)

> 	phy_start_machine(phydev);

> 

> Can you test this?

> 

Sorry for the confusion, this comment is related to the next part
of your patch.

>>>  	mutex_unlock(&phydev->lock);

>>>  }

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

>>> index ab33d17..4897d24 100644

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

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

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

>>>  		return ret;

>>>  

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

>>> -	phydev->link = 0;

>>> -	phydev->state = PHY_UP;

>>> +	mutex_lock(&phydev->lock);

>>> +	if (phy_is_started(phydev)) {

>>> +		phydev->state = PHY_UP;

>>> +		mutex_unlock(&phydev->lock);

>>> +		phydev->link = 0;

>>> +		phy_start_machine(phydev);

>>> +	} else {

>>> +		mutex_unlock(&phydev->lock);

>>> +	}

>>>  

>>> -	phy_start_machine(phydev);

>>>  

>>>  	return 0;

>>>  }

>>> diff --git a/include/linux/phy.h b/include/linux/phy.h

>>> index 3ea87f7..dd21537 100644

>>> --- a/include/linux/phy.h

>>> +++ b/include/linux/phy.h

>>> @@ -898,6 +898,19 @@ static inline bool phy_is_pseudo_fixed_link(struct phy_device *phydev)

>>>  }

>>>  

>>>  /**

>>> + * phy_is_started - Convenience function for testing whether a PHY is in

>>> + * a started state

>>> + * @phydev: the phy_device struct

>>> + *

>>> + * The caller must have taken the phy_device mutex lock.

>>> + */

>>> +static inline bool phy_is_started(struct phy_device *phydev)

>>> +{

>>> +	WARN_ON(!mutex_is_locked(&phydev->lock));

>>> +	return phydev->state >= PHY_UP && phydev->state != PHY_HALTED;

>>> +}

>>> +

>>> +/**

>>>   * phy_write_mmd - Convenience function for writing a register

>>>   * on an MMD on a given PHY.

>>>   * @phydev: The phy_device struct

>>> -- 

>>> 2.7.4

>>

>> ---

>> Best Regards,

>> Kunihiko Hayashi

>>

>>

>>

>
Kunihiko Hayashi Dec. 18, 2018, 6:25 a.m. UTC | #4
Hi Heiner,

On Mon, 17 Dec 2018 19:43:31 +0100 <hkallweit1@gmail.com> wrote:

> On 17.12.2018 19:41, Heiner Kallweit wrote:

> > On 17.12.2018 07:41, Kunihiko Hayashi wrote:

> >> Hi,

> >>

> >> Gentle ping...

> >> Are there any comments about changes since v2?

> >>

> >> v2: https://www.spinics.net/lists/netdev/msg536926.html

> >>

> >> Thank you,

> >>

> >> On Mon, 3 Dec 2018 17:22:29 +0900 <hayashi.kunihiko@socionext.com> 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 adds a new convenient function to check whether the PHY is in

> >>> a started state, and expects to solve the issue by changing phydev->state

> >>> to PHY_UP and calling phy_start_machine() only when the PHY is started.

> >>>

> > This convenience function and the related change to phy_stop() are part of

> > the following already and don't need to be part of your patch.

> > https://patchwork.ozlabs.org/patch/1014171/


I see. I'll follow your patch when necessary.

> >>> Suggested-by: Heiner Kallweit <hkallweit1@gmail.com>

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

> >>> ---

> >>>

> >>> Changes since v2:

> >>>  - add mutex lock/unlock for changing phydev->state

> >>>  - check whether the mutex is locked in phy_is_started()

> >>>  

> >>> Changes since v1:

> >>>  - introduce a new helper function phy_is_started() and use it instead of

> >>>    checking link status

> >>>  - replace checking phydev->state with phy_is_started() in

> >>>    phy_stop_machine()

> >>>

> >>> drivers/net/phy/phy.c        |  2 +-

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

> >>>  include/linux/phy.h          | 13 +++++++++++++

> >>>  3 files changed, 23 insertions(+), 4 deletions(-)

> >>>

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

> >>> index 1d73ac3..f484d03 100644

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

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

> >>> @@ -670,7 +670,7 @@ void phy_stop_machine(struct phy_device *phydev)

> >>>  	cancel_delayed_work_sync(&phydev->state_queue);

> >>>  

> >>>  	mutex_lock(&phydev->lock);

> >>> -	if (phydev->state > PHY_UP && phydev->state != PHY_HALTED)

> >>> +	if (phy_is_started(phydev))

> >>>  		phydev->state = PHY_UP;

> > 

> > I'm wondering whether we need to do this. If the PHY is attached,

> > then mdio_bus_phy_suspend() calls phy_stop_machine() which does

> > exactly the same. If the PHY is not attached, then we don't have

> > to do anything. Therefore I think we just have to do the same as

> > in mdio_bus_phy_resume():

> > 

> > if (phydev->attached_dev && phydev->adjust_link)

> > 	phy_start_machine(phydev);


Agreed.

Although the original code changed phydev->state,
it seems that it's only enough to
- call phy_stop_machine() in mdio_bus_phy_suspend()
- call phy_start_machine() in mdio_bus_phy_resume() and mdio_bus_phy_restore()
if the PHY is attached.

> > Can you test this?


I tested your code instead of applying my entire patch, and I confirmed
that the code solved the issue in my environment.

Do you make new patch instead of my patch?
(and I can add Reported-by: for the issue and Tested-by:)

Thank you,


> > 

> Sorry for the confusion, this comment is related to the next part

> of your patch.

> 

> >>>  	mutex_unlock(&phydev->lock);

> >>>  }

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

> >>> index ab33d17..4897d24 100644

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

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

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

> >>>  		return ret;

> >>>  

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

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

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

> >>> +	mutex_lock(&phydev->lock);

> >>> +	if (phy_is_started(phydev)) {

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

> >>> +		mutex_unlock(&phydev->lock);

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

> >>> +		phy_start_machine(phydev);

> >>> +	} else {

> >>> +		mutex_unlock(&phydev->lock);

> >>> +	}

> >>>  

> >>> -	phy_start_machine(phydev);

> >>>  

> >>>  	return 0;

> >>>  }

> >>> diff --git a/include/linux/phy.h b/include/linux/phy.h

> >>> index 3ea87f7..dd21537 100644

> >>> --- a/include/linux/phy.h

> >>> +++ b/include/linux/phy.h

> >>> @@ -898,6 +898,19 @@ static inline bool phy_is_pseudo_fixed_link(struct phy_device *phydev)

> >>>  }

> >>>  

> >>>  /**

> >>> + * phy_is_started - Convenience function for testing whether a PHY is in

> >>> + * a started state

> >>> + * @phydev: the phy_device struct

> >>> + *

> >>> + * The caller must have taken the phy_device mutex lock.

> >>> + */

> >>> +static inline bool phy_is_started(struct phy_device *phydev)

> >>> +{

> >>> +	WARN_ON(!mutex_is_locked(&phydev->lock));

> >>> +	return phydev->state >= PHY_UP && phydev->state != PHY_HALTED;

> >>> +}

> >>> +

> >>> +/**

> >>>   * phy_write_mmd - Convenience function for writing a register

> >>>   * on an MMD on a given PHY.

> >>>   * @phydev: The phy_device struct

> >>> -- 

> >>> 2.7.4

> >>

> >> ---

> >> Best Regards,

> >> Kunihiko Hayashi

> >>

> >>

> >>

> > 


---
Best Regards,
Kunihiko Hayashi
Heiner Kallweit Dec. 18, 2018, 6:44 a.m. UTC | #5
On 18.12.2018 07:25, Kunihiko Hayashi wrote:
> Hi Heiner,

> 

> On Mon, 17 Dec 2018 19:43:31 +0100 <hkallweit1@gmail.com> wrote:

> 

>> On 17.12.2018 19:41, Heiner Kallweit wrote:

>>> On 17.12.2018 07:41, Kunihiko Hayashi wrote:

>>>> Hi,

>>>>

>>>> Gentle ping...

>>>> Are there any comments about changes since v2?

>>>>

>>>> v2: https://www.spinics.net/lists/netdev/msg536926.html

>>>>

>>>> Thank you,

>>>>

>>>> On Mon, 3 Dec 2018 17:22:29 +0900 <hayashi.kunihiko@socionext.com> 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 adds a new convenient function to check whether the PHY is in

>>>>> a started state, and expects to solve the issue by changing phydev->state

>>>>> to PHY_UP and calling phy_start_machine() only when the PHY is started.

>>>>>

>>> This convenience function and the related change to phy_stop() are part of

>>> the following already and don't need to be part of your patch.

>>> https://patchwork.ozlabs.org/patch/1014171/

> 

> I see. I'll follow your patch when necessary.

> 

>>>>> Suggested-by: Heiner Kallweit <hkallweit1@gmail.com>

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

>>>>> ---

>>>>>

>>>>> Changes since v2:

>>>>>  - add mutex lock/unlock for changing phydev->state

>>>>>  - check whether the mutex is locked in phy_is_started()

>>>>>  

>>>>> Changes since v1:

>>>>>  - introduce a new helper function phy_is_started() and use it instead of

>>>>>    checking link status

>>>>>  - replace checking phydev->state with phy_is_started() in

>>>>>    phy_stop_machine()

>>>>>

>>>>> drivers/net/phy/phy.c        |  2 +-

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

>>>>>  include/linux/phy.h          | 13 +++++++++++++

>>>>>  3 files changed, 23 insertions(+), 4 deletions(-)

>>>>>

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

>>>>> index 1d73ac3..f484d03 100644

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

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

>>>>> @@ -670,7 +670,7 @@ void phy_stop_machine(struct phy_device *phydev)

>>>>>  	cancel_delayed_work_sync(&phydev->state_queue);

>>>>>  

>>>>>  	mutex_lock(&phydev->lock);

>>>>> -	if (phydev->state > PHY_UP && phydev->state != PHY_HALTED)

>>>>> +	if (phy_is_started(phydev))

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

>>>

>>> I'm wondering whether we need to do this. If the PHY is attached,

>>> then mdio_bus_phy_suspend() calls phy_stop_machine() which does

>>> exactly the same. If the PHY is not attached, then we don't have

>>> to do anything. Therefore I think we just have to do the same as

>>> in mdio_bus_phy_resume():

>>>

>>> if (phydev->attached_dev && phydev->adjust_link)

>>> 	phy_start_machine(phydev);

> 

> Agreed.

> 

> Although the original code changed phydev->state,

> it seems that it's only enough to

> - call phy_stop_machine() in mdio_bus_phy_suspend()

> - call phy_start_machine() in mdio_bus_phy_resume() and mdio_bus_phy_restore()

> if the PHY is attached.

> 

>>> Can you test this?

> 

> I tested your code instead of applying my entire patch, and I confirmed

> that the code solved the issue in my environment.

> 

> Do you make new patch instead of my patch?

> (and I can add Reported-by: for the issue and Tested-by:)

> 

Up to you. It's fine with me if you submit the patch, but I can also do it
and mention you in Reported-by and Tested-by. Just let me know.

> Thank you,

> 

> 

>>>

>> Sorry for the confusion, this comment is related to the next part

>> of your patch.

>>

>>>>>  	mutex_unlock(&phydev->lock);

>>>>>  }

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

>>>>> index ab33d17..4897d24 100644

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

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

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

>>>>>  		return ret;

>>>>>  

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

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

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

>>>>> +	mutex_lock(&phydev->lock);

>>>>> +	if (phy_is_started(phydev)) {

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

>>>>> +		mutex_unlock(&phydev->lock);

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

>>>>> +		phy_start_machine(phydev);

>>>>> +	} else {

>>>>> +		mutex_unlock(&phydev->lock);

>>>>> +	}

>>>>>  

>>>>> -	phy_start_machine(phydev);

>>>>>  

>>>>>  	return 0;

>>>>>  }

>>>>> diff --git a/include/linux/phy.h b/include/linux/phy.h

>>>>> index 3ea87f7..dd21537 100644

>>>>> --- a/include/linux/phy.h

>>>>> +++ b/include/linux/phy.h

>>>>> @@ -898,6 +898,19 @@ static inline bool phy_is_pseudo_fixed_link(struct phy_device *phydev)

>>>>>  }

>>>>>  

>>>>>  /**

>>>>> + * phy_is_started - Convenience function for testing whether a PHY is in

>>>>> + * a started state

>>>>> + * @phydev: the phy_device struct

>>>>> + *

>>>>> + * The caller must have taken the phy_device mutex lock.

>>>>> + */

>>>>> +static inline bool phy_is_started(struct phy_device *phydev)

>>>>> +{

>>>>> +	WARN_ON(!mutex_is_locked(&phydev->lock));

>>>>> +	return phydev->state >= PHY_UP && phydev->state != PHY_HALTED;

>>>>> +}

>>>>> +

>>>>> +/**

>>>>>   * phy_write_mmd - Convenience function for writing a register

>>>>>   * on an MMD on a given PHY.

>>>>>   * @phydev: The phy_device struct

>>>>> -- 

>>>>> 2.7.4

>>>>

>>>> ---

>>>> Best Regards,

>>>> Kunihiko Hayashi

>>>>

>>>>

>>>>

>>>

> 

> ---

> Best Regards,

> Kunihiko Hayashi

> 

> 

>
Kunihiko Hayashi Dec. 18, 2018, 6:58 a.m. UTC | #6
Hi Heiner,

On Tue, 18 Dec 2018 07:44:33 +0100 <hkallweit1@gmail.com> wrote:

> On 18.12.2018 07:25, Kunihiko Hayashi wrote:

> > Hi Heiner,

> > 

> > On Mon, 17 Dec 2018 19:43:31 +0100 <hkallweit1@gmail.com> wrote:

> > 

> >> On 17.12.2018 19:41, Heiner Kallweit wrote:

> >>> On 17.12.2018 07:41, Kunihiko Hayashi wrote:

> >>>> Hi,

> >>>>

> >>>> Gentle ping...

> >>>> Are there any comments about changes since v2?

> >>>>

> >>>> v2: https://www.spinics.net/lists/netdev/msg536926.html

> >>>>

> >>>> Thank you,

> >>>>

> >>>> On Mon, 3 Dec 2018 17:22:29 +0900 <hayashi.kunihiko@socionext.com> 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 adds a new convenient function to check whether the PHY is in

> >>>>> a started state, and expects to solve the issue by changing phydev->state

> >>>>> to PHY_UP and calling phy_start_machine() only when the PHY is started.

> >>>>>

> >>> This convenience function and the related change to phy_stop() are part of

> >>> the following already and don't need to be part of your patch.

> >>> https://patchwork.ozlabs.org/patch/1014171/

> > 

> > I see. I'll follow your patch when necessary.

> > 

> >>>>> Suggested-by: Heiner Kallweit <hkallweit1@gmail.com>

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

> >>>>> ---

> >>>>>

> >>>>> Changes since v2:

> >>>>>  - add mutex lock/unlock for changing phydev->state

> >>>>>  - check whether the mutex is locked in phy_is_started()

> >>>>>  

> >>>>> Changes since v1:

> >>>>>  - introduce a new helper function phy_is_started() and use it instead of

> >>>>>    checking link status

> >>>>>  - replace checking phydev->state with phy_is_started() in

> >>>>>    phy_stop_machine()

> >>>>>

> >>>>> drivers/net/phy/phy.c        |  2 +-

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

> >>>>>  include/linux/phy.h          | 13 +++++++++++++

> >>>>>  3 files changed, 23 insertions(+), 4 deletions(-)

> >>>>>

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

> >>>>> index 1d73ac3..f484d03 100644

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

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

> >>>>> @@ -670,7 +670,7 @@ void phy_stop_machine(struct phy_device *phydev)

> >>>>>  	cancel_delayed_work_sync(&phydev->state_queue);

> >>>>>  

> >>>>>  	mutex_lock(&phydev->lock);

> >>>>> -	if (phydev->state > PHY_UP && phydev->state != PHY_HALTED)

> >>>>> +	if (phy_is_started(phydev))

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

> >>>

> >>> I'm wondering whether we need to do this. If the PHY is attached,

> >>> then mdio_bus_phy_suspend() calls phy_stop_machine() which does

> >>> exactly the same. If the PHY is not attached, then we don't have

> >>> to do anything. Therefore I think we just have to do the same as

> >>> in mdio_bus_phy_resume():

> >>>

> >>> if (phydev->attached_dev && phydev->adjust_link)

> >>> 	phy_start_machine(phydev);

> > 

> > Agreed.

> > 

> > Although the original code changed phydev->state,

> > it seems that it's only enough to

> > - call phy_stop_machine() in mdio_bus_phy_suspend()

> > - call phy_start_machine() in mdio_bus_phy_resume() and mdio_bus_phy_restore()

> > if the PHY is attached.

> > 

> >>> Can you test this?

> > 

> > I tested your code instead of applying my entire patch, and I confirmed

> > that the code solved the issue in my environment.

> > 

> > Do you make new patch instead of my patch?

> > (and I can add Reported-by: for the issue and Tested-by:)

> > 

> Up to you. It's fine with me if you submit the patch, but I can also do it

> and mention you in Reported-by and Tested-by. Just let me know.


I see. I'll make and submit the patch as a fix for the issue.

Thank you,

> 

> > Thank you,

> > 

> > 

> >>>

> >> Sorry for the confusion, this comment is related to the next part

> >> of your patch.

> >>

> >>>>>  	mutex_unlock(&phydev->lock);

> >>>>>  }

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

> >>>>> index ab33d17..4897d24 100644

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

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

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

> >>>>>  		return ret;

> >>>>>  

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

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

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

> >>>>> +	mutex_lock(&phydev->lock);

> >>>>> +	if (phy_is_started(phydev)) {

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

> >>>>> +		mutex_unlock(&phydev->lock);

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

> >>>>> +		phy_start_machine(phydev);

> >>>>> +	} else {

> >>>>> +		mutex_unlock(&phydev->lock);

> >>>>> +	}

> >>>>>  

> >>>>> -	phy_start_machine(phydev);

> >>>>>  

> >>>>>  	return 0;

> >>>>>  }

> >>>>> diff --git a/include/linux/phy.h b/include/linux/phy.h

> >>>>> index 3ea87f7..dd21537 100644

> >>>>> --- a/include/linux/phy.h

> >>>>> +++ b/include/linux/phy.h

> >>>>> @@ -898,6 +898,19 @@ static inline bool phy_is_pseudo_fixed_link(struct phy_device *phydev)

> >>>>>  }

> >>>>>  

> >>>>>  /**

> >>>>> + * phy_is_started - Convenience function for testing whether a PHY is in

> >>>>> + * a started state

> >>>>> + * @phydev: the phy_device struct

> >>>>> + *

> >>>>> + * The caller must have taken the phy_device mutex lock.

> >>>>> + */

> >>>>> +static inline bool phy_is_started(struct phy_device *phydev)

> >>>>> +{

> >>>>> +	WARN_ON(!mutex_is_locked(&phydev->lock));

> >>>>> +	return phydev->state >= PHY_UP && phydev->state != PHY_HALTED;

> >>>>> +}

> >>>>> +

> >>>>> +/**

> >>>>>   * phy_write_mmd - Convenience function for writing a register

> >>>>>   * on an MMD on a given PHY.

> >>>>>   * @phydev: The phy_device struct

> >>>>> -- 

> >>>>> 2.7.4

> >>>>

> >>>> ---

> >>>> Best Regards,

> >>>> Kunihiko Hayashi

> >>>>

> >>>>

> >>>>

> >>>

> > 

> > ---

> > Best Regards,

> > Kunihiko Hayashi

> > 

> > 

> > 


---
Best Regards,
Kunihiko Hayashi
diff mbox series

Patch

diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 1d73ac3..f484d03 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -670,7 +670,7 @@  void phy_stop_machine(struct phy_device *phydev)
 	cancel_delayed_work_sync(&phydev->state_queue);
 
 	mutex_lock(&phydev->lock);
-	if (phydev->state > PHY_UP && phydev->state != PHY_HALTED)
+	if (phy_is_started(phydev))
 		phydev->state = PHY_UP;
 	mutex_unlock(&phydev->lock);
 }
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index ab33d17..4897d24 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -309,10 +309,16 @@  static int mdio_bus_phy_restore(struct device *dev)
 		return ret;
 
 	/* The PHY needs to renegotiate. */
-	phydev->link = 0;
-	phydev->state = PHY_UP;
+	mutex_lock(&phydev->lock);
+	if (phy_is_started(phydev)) {
+		phydev->state = PHY_UP;
+		mutex_unlock(&phydev->lock);
+		phydev->link = 0;
+		phy_start_machine(phydev);
+	} else {
+		mutex_unlock(&phydev->lock);
+	}
 
-	phy_start_machine(phydev);
 
 	return 0;
 }
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 3ea87f7..dd21537 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -898,6 +898,19 @@  static inline bool phy_is_pseudo_fixed_link(struct phy_device *phydev)
 }
 
 /**
+ * phy_is_started - Convenience function for testing whether a PHY is in
+ * a started state
+ * @phydev: the phy_device struct
+ *
+ * The caller must have taken the phy_device mutex lock.
+ */
+static inline bool phy_is_started(struct phy_device *phydev)
+{
+	WARN_ON(!mutex_is_locked(&phydev->lock));
+	return phydev->state >= PHY_UP && phydev->state != PHY_HALTED;
+}
+
+/**
  * phy_write_mmd - Convenience function for writing a register
  * on an MMD on a given PHY.
  * @phydev: The phy_device struct