mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-15 09:34:17 +00:00
PHYLIB: Spinlock fixes for softirqs
Use spin_lock_bh()/spin_unlock_bh() for the phydev lock throughout as it is used in phy_timer() that is called as a softirq and all the other operations may happen in the user context. There has been a change recently that did such a conversion for some of the operations on the lock, but some have been left intact. Many of them, perhaps all, may be called in the user context and I was able to trigger recursive spinlock acquisition indeed, so I think for the sake of long-term maintenance it is best to convert them all, even if unnecessarily for one or two -- better safe than sorry. Perhaps one in phy_timer() could actually be skipped as only called as a softirq -- I can send an update if that sounds like a good idea. Checked with checkpatch.pl and at the runtime. Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
parent
1f8f4559f8
commit
9ff8c68b3c
@ -424,7 +424,7 @@ int phy_start_aneg(struct phy_device *phydev)
|
|||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
spin_lock(&phydev->lock);
|
spin_lock_bh(&phydev->lock);
|
||||||
|
|
||||||
if (AUTONEG_DISABLE == phydev->autoneg)
|
if (AUTONEG_DISABLE == phydev->autoneg)
|
||||||
phy_sanitize_settings(phydev);
|
phy_sanitize_settings(phydev);
|
||||||
@ -445,7 +445,7 @@ int phy_start_aneg(struct phy_device *phydev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
spin_unlock(&phydev->lock);
|
spin_unlock_bh(&phydev->lock);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(phy_start_aneg);
|
EXPORT_SYMBOL(phy_start_aneg);
|
||||||
@ -490,10 +490,10 @@ void phy_stop_machine(struct phy_device *phydev)
|
|||||||
{
|
{
|
||||||
del_timer_sync(&phydev->phy_timer);
|
del_timer_sync(&phydev->phy_timer);
|
||||||
|
|
||||||
spin_lock(&phydev->lock);
|
spin_lock_bh(&phydev->lock);
|
||||||
if (phydev->state > PHY_UP)
|
if (phydev->state > PHY_UP)
|
||||||
phydev->state = PHY_UP;
|
phydev->state = PHY_UP;
|
||||||
spin_unlock(&phydev->lock);
|
spin_unlock_bh(&phydev->lock);
|
||||||
|
|
||||||
phydev->adjust_state = NULL;
|
phydev->adjust_state = NULL;
|
||||||
}
|
}
|
||||||
@ -537,9 +537,9 @@ static void phy_force_reduction(struct phy_device *phydev)
|
|||||||
*/
|
*/
|
||||||
void phy_error(struct phy_device *phydev)
|
void phy_error(struct phy_device *phydev)
|
||||||
{
|
{
|
||||||
spin_lock(&phydev->lock);
|
spin_lock_bh(&phydev->lock);
|
||||||
phydev->state = PHY_HALTED;
|
phydev->state = PHY_HALTED;
|
||||||
spin_unlock(&phydev->lock);
|
spin_unlock_bh(&phydev->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -690,10 +690,10 @@ static void phy_change(struct work_struct *work)
|
|||||||
if (err)
|
if (err)
|
||||||
goto phy_err;
|
goto phy_err;
|
||||||
|
|
||||||
spin_lock(&phydev->lock);
|
spin_lock_bh(&phydev->lock);
|
||||||
if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state))
|
if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state))
|
||||||
phydev->state = PHY_CHANGELINK;
|
phydev->state = PHY_CHANGELINK;
|
||||||
spin_unlock(&phydev->lock);
|
spin_unlock_bh(&phydev->lock);
|
||||||
|
|
||||||
enable_irq(phydev->irq);
|
enable_irq(phydev->irq);
|
||||||
|
|
||||||
@ -718,7 +718,7 @@ phy_err:
|
|||||||
*/
|
*/
|
||||||
void phy_stop(struct phy_device *phydev)
|
void phy_stop(struct phy_device *phydev)
|
||||||
{
|
{
|
||||||
spin_lock(&phydev->lock);
|
spin_lock_bh(&phydev->lock);
|
||||||
|
|
||||||
if (PHY_HALTED == phydev->state)
|
if (PHY_HALTED == phydev->state)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
@ -734,7 +734,7 @@ void phy_stop(struct phy_device *phydev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
spin_unlock(&phydev->lock);
|
spin_unlock_bh(&phydev->lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cannot call flush_scheduled_work() here as desired because
|
* Cannot call flush_scheduled_work() here as desired because
|
||||||
@ -782,7 +782,7 @@ static void phy_timer(unsigned long data)
|
|||||||
int needs_aneg = 0;
|
int needs_aneg = 0;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
spin_lock(&phydev->lock);
|
spin_lock_bh(&phydev->lock);
|
||||||
|
|
||||||
if (phydev->adjust_state)
|
if (phydev->adjust_state)
|
||||||
phydev->adjust_state(phydev->attached_dev);
|
phydev->adjust_state(phydev->attached_dev);
|
||||||
@ -948,7 +948,7 @@ static void phy_timer(unsigned long data)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock(&phydev->lock);
|
spin_unlock_bh(&phydev->lock);
|
||||||
|
|
||||||
if (needs_aneg)
|
if (needs_aneg)
|
||||||
err = phy_start_aneg(phydev);
|
err = phy_start_aneg(phydev);
|
||||||
|
@ -670,9 +670,9 @@ static int phy_remove(struct device *dev)
|
|||||||
|
|
||||||
phydev = to_phy_device(dev);
|
phydev = to_phy_device(dev);
|
||||||
|
|
||||||
spin_lock(&phydev->lock);
|
spin_lock_bh(&phydev->lock);
|
||||||
phydev->state = PHY_DOWN;
|
phydev->state = PHY_DOWN;
|
||||||
spin_unlock(&phydev->lock);
|
spin_unlock_bh(&phydev->lock);
|
||||||
|
|
||||||
if (phydev->drv->remove)
|
if (phydev->drv->remove)
|
||||||
phydev->drv->remove(phydev);
|
phydev->drv->remove(phydev);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user