Message ID | 1475051544-18561-6-git-send-email-andrew@lunn.ch |
---|---|
State | RFC, archived |
Delegated to: | David Miller |
Headers | show |
On 09/28/2016 01:32 AM, Andrew Lunn wrote: > The phy_start() is used to indicate the PHY is now ready to do its > work. The state is changed, normally to PHY_UP which means that both > the MAC and the PHY are ready. > > If the phy driver is using polling, when the next poll happens, the > state machine notices the PHY is now in PHY_UP, and kicks off > auto-negotiation, if needed. > > If however, the PHY is using interrupts, there is no polling. The phy > is stuck in PHY_UP until the next interrupt comes along. And there is > no reason for the PHY to interrupt. > > Have phy_start() schedule the state machine to run, which both speeds > up the polling use case, and makes the interrupt use case actually > work. > > This problems exists whenever there is a state change which will not > cause an interrupt. Trigger the state machine in these cases, > e.g. phy_error(). > > Signed-off-by: Andrew Lunn <andrew@lunn.ch> No particular objections, this should also fix this: http://lists.openwall.net/netdev/2016/05/17/147 > --- > drivers/net/phy/phy.c | 22 ++++++++++++++++++++-- > 1 file changed, 20 insertions(+), 2 deletions(-) > > diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c > index 940450c6cd2c..f446ce04caf3 100644 > --- a/drivers/net/phy/phy.c > +++ b/drivers/net/phy/phy.c > @@ -608,6 +608,21 @@ void phy_start_machine(struct phy_device *phydev) > } > > /** > + * phy_trigger_machine - trigger the state machine to run > + * > + * @phydev: the phy_device struct > + * > + * Description: There has been a change in state which requires that the > + * state machine runs. > + */ > + > +static void phy_trigger_machine(struct phy_device *phydev) > +{ > + cancel_delayed_work_sync(&phydev->state_queue); > + queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, 0); > +} > + > +/** > * phy_stop_machine - stop the PHY state machine tracking > * @phydev: target phy_device struct > * > @@ -639,6 +654,8 @@ static void phy_error(struct phy_device *phydev) > mutex_lock(&phydev->lock); > phydev->state = PHY_HALTED; > mutex_unlock(&phydev->lock); > + > + phy_trigger_machine(phydev); > } > > /** > @@ -785,8 +802,7 @@ void phy_change(struct phy_device *phydev) > } > > /* reschedule state queue work to run as soon as possible */ > - cancel_delayed_work_sync(&phydev->state_queue); > - queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, 0); > + phy_trigger_machine(phydev); > return; > > ignore: > @@ -875,6 +891,8 @@ void phy_start(struct phy_device *phydev) > /* if phy was suspended, bring the physical link up again */ > if (do_resume) > phy_resume(phydev); > + > + phy_trigger_machine(phydev); > } > EXPORT_SYMBOL(phy_start); > >
On Wed, Sep 28, 2016 at 02:31:54PM -0700, Florian Fainelli wrote: > On 09/28/2016 01:32 AM, Andrew Lunn wrote: > > The phy_start() is used to indicate the PHY is now ready to do its > > work. The state is changed, normally to PHY_UP which means that both > > the MAC and the PHY are ready. > > > > If the phy driver is using polling, when the next poll happens, the > > state machine notices the PHY is now in PHY_UP, and kicks off > > auto-negotiation, if needed. > > > > If however, the PHY is using interrupts, there is no polling. The phy > > is stuck in PHY_UP until the next interrupt comes along. And there is > > no reason for the PHY to interrupt. > > > > Have phy_start() schedule the state machine to run, which both speeds > > up the polling use case, and makes the interrupt use case actually > > work. > > > > This problems exists whenever there is a state change which will not > > cause an interrupt. Trigger the state machine in these cases, > > e.g. phy_error(). > > > > Signed-off-by: Andrew Lunn <andrew@lunn.ch> > > No particular objections, this should also fix this: > > http://lists.openwall.net/netdev/2016/05/17/147 Hi Florian Yes, i was thinking it probably should have a fixes: tag and be a separate patch. The hard part will be figuring out when this actually broke, or does it go all the way back to when interrupt support was added? Andrew
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 940450c6cd2c..f446ce04caf3 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -608,6 +608,21 @@ void phy_start_machine(struct phy_device *phydev) } /** + * phy_trigger_machine - trigger the state machine to run + * + * @phydev: the phy_device struct + * + * Description: There has been a change in state which requires that the + * state machine runs. + */ + +static void phy_trigger_machine(struct phy_device *phydev) +{ + cancel_delayed_work_sync(&phydev->state_queue); + queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, 0); +} + +/** * phy_stop_machine - stop the PHY state machine tracking * @phydev: target phy_device struct * @@ -639,6 +654,8 @@ static void phy_error(struct phy_device *phydev) mutex_lock(&phydev->lock); phydev->state = PHY_HALTED; mutex_unlock(&phydev->lock); + + phy_trigger_machine(phydev); } /** @@ -785,8 +802,7 @@ void phy_change(struct phy_device *phydev) } /* reschedule state queue work to run as soon as possible */ - cancel_delayed_work_sync(&phydev->state_queue); - queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, 0); + phy_trigger_machine(phydev); return; ignore: @@ -875,6 +891,8 @@ void phy_start(struct phy_device *phydev) /* if phy was suspended, bring the physical link up again */ if (do_resume) phy_resume(phydev); + + phy_trigger_machine(phydev); } EXPORT_SYMBOL(phy_start);
The phy_start() is used to indicate the PHY is now ready to do its work. The state is changed, normally to PHY_UP which means that both the MAC and the PHY are ready. If the phy driver is using polling, when the next poll happens, the state machine notices the PHY is now in PHY_UP, and kicks off auto-negotiation, if needed. If however, the PHY is using interrupts, there is no polling. The phy is stuck in PHY_UP until the next interrupt comes along. And there is no reason for the PHY to interrupt. Have phy_start() schedule the state machine to run, which both speeds up the polling use case, and makes the interrupt use case actually work. This problems exists whenever there is a state change which will not cause an interrupt. Trigger the state machine in these cases, e.g. phy_error(). Signed-off-by: Andrew Lunn <andrew@lunn.ch> --- drivers/net/phy/phy.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-)