Commit 61c4c0bc authored by David S. Miller's avatar David S. Miller

Merge branch 'net-phy-fix-locking-issue'

Heiner Kallweit says:

====================
net: phy: fix locking issue

Russell pointed out that the locking used in phy_is_started() isn't
needed and misleading. This locking also contributes to a race fixed
with patch 2.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 39c13319 a2004907
...@@ -553,7 +553,7 @@ int phy_start_aneg(struct phy_device *phydev) ...@@ -553,7 +553,7 @@ int phy_start_aneg(struct phy_device *phydev)
if (err < 0) if (err < 0)
goto out_unlock; goto out_unlock;
if (__phy_is_started(phydev)) { if (phy_is_started(phydev)) {
if (phydev->autoneg == AUTONEG_ENABLE) { if (phydev->autoneg == AUTONEG_ENABLE) {
err = phy_check_link_status(phydev); err = phy_check_link_status(phydev);
} else { } else {
...@@ -709,7 +709,7 @@ void phy_stop_machine(struct phy_device *phydev) ...@@ -709,7 +709,7 @@ void phy_stop_machine(struct phy_device *phydev)
cancel_delayed_work_sync(&phydev->state_queue); cancel_delayed_work_sync(&phydev->state_queue);
mutex_lock(&phydev->lock); mutex_lock(&phydev->lock);
if (__phy_is_started(phydev)) if (phy_is_started(phydev))
phydev->state = PHY_UP; phydev->state = PHY_UP;
mutex_unlock(&phydev->lock); mutex_unlock(&phydev->lock);
} }
...@@ -839,15 +839,14 @@ EXPORT_SYMBOL(phy_stop_interrupts); ...@@ -839,15 +839,14 @@ EXPORT_SYMBOL(phy_stop_interrupts);
*/ */
void phy_stop(struct phy_device *phydev) void phy_stop(struct phy_device *phydev)
{ {
mutex_lock(&phydev->lock); if (!phy_is_started(phydev)) {
if (!__phy_is_started(phydev)) {
WARN(1, "called from state %s\n", WARN(1, "called from state %s\n",
phy_state_to_str(phydev->state)); phy_state_to_str(phydev->state));
mutex_unlock(&phydev->lock);
return; return;
} }
mutex_lock(&phydev->lock);
if (phy_interrupt_is_valid(phydev)) if (phy_interrupt_is_valid(phydev))
phy_disable_interrupts(phydev); phy_disable_interrupts(phydev);
...@@ -986,8 +985,10 @@ void phy_state_machine(struct work_struct *work) ...@@ -986,8 +985,10 @@ void phy_state_machine(struct work_struct *work)
* state machine would be pointless and possibly error prone when * state machine would be pointless and possibly error prone when
* called from phy_disconnect() synchronously. * called from phy_disconnect() synchronously.
*/ */
mutex_lock(&phydev->lock);
if (phy_polling_mode(phydev) && phy_is_started(phydev)) if (phy_polling_mode(phydev) && phy_is_started(phydev))
phy_queue_state_machine(phydev, PHY_STATE_TIME); phy_queue_state_machine(phydev, PHY_STATE_TIME);
mutex_unlock(&phydev->lock);
} }
/** /**
......
...@@ -674,26 +674,13 @@ phy_lookup_setting(int speed, int duplex, const unsigned long *mask, ...@@ -674,26 +674,13 @@ phy_lookup_setting(int speed, int duplex, const unsigned long *mask,
size_t phy_speeds(unsigned int *speeds, size_t size, size_t phy_speeds(unsigned int *speeds, size_t size,
unsigned long *mask); unsigned long *mask);
static inline bool __phy_is_started(struct phy_device *phydev)
{
WARN_ON(!mutex_is_locked(&phydev->lock));
return phydev->state >= PHY_UP;
}
/** /**
* phy_is_started - Convenience function to check whether PHY is started * phy_is_started - Convenience function to check whether PHY is started
* @phydev: The phy_device struct * @phydev: The phy_device struct
*/ */
static inline bool phy_is_started(struct phy_device *phydev) static inline bool phy_is_started(struct phy_device *phydev)
{ {
bool started; return phydev->state >= PHY_UP;
mutex_lock(&phydev->lock);
started = __phy_is_started(phydev);
mutex_unlock(&phydev->lock);
return started;
} }
void phy_resolve_aneg_linkmode(struct phy_device *phydev); void phy_resolve_aneg_linkmode(struct phy_device *phydev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment