net: phy: Stop 'phy-state-machine' and 'phy_change' work on remove
Subsystems (3)
PATCH 6/6 net: phy: Stop 'phy-state-machine' and 'phy_change' work on remove
Avoids:
Unable to handle kernel NULL pointer dereference at virtual address 00000064 Workqueue: events_power_efficient phy_state_machine PC is at phy_state_machine+0x28/0x480
--- drivers/net/phy/phy_device.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/net/phy/phy_device.c +6 -0
@@ -1348,6 +1348,12 @@ static int phy_remove(struct device *dev) phydev->state =PHY_DOWN ;mutex_unlock (&phydev->lock); +cancel_delayed_work_sync (&phydev->state_queue); +flush_delayed_work (&phydev->state_queue); + +cancel_work_sync (&phydev->phy_queue); +flush_work (&phydev->phy_queue); +if (phydev->drv->remove) phydev->drv->remove (phydev); phydev->drv =NULL ;
Signature · 1 line
1.9.1
Quoted 4 lines · Neil Armstrong
Avoids:
Unable to handle kernel NULL pointer dereference at virtual address 00000064 Workqueue: events_power_efficient phy_state_machine PC is at phy_state_machine+0x28/0x480
Stripped down oops can sometimes be missing critical pieces of information to help debug the problem, is there a reason why this is being obfuscated?
You are supposed to stop the PHY state machine by calling phy_disconnect() is it possible that this is missing?
Quoted 25 lines
Signed-off-by Frode Isaksen <[email protected]>Signed-off-by Neil Armstrong <[email protected]>--- drivers/net/phy/phy_device.c | 6 ++++++ 1 file changed, 6 insertions(+)drivers/net/phy/phy_device.c +6
-0@@ -1348,6 +1348,12 @@ static int phy_remove(struct device *dev) phydev->state =PHY_DOWN ;mutex_unlock (&phydev->lock); +cancel_delayed_work_sync (&phydev->state_queue); +flush_delayed_work (&phydev->state_queue); + +cancel_work_sync (&phydev->phy_queue); +flush_work (&phydev->phy_queue); +if (phydev->drv->remove) phydev->drv->remove (phydev); phydev->drv =NULL ;
Signature · 1 line
Florian
A message that is not in the archive (sent off-list or not yet received): CAJ03sU_+nkvN1ZeqvWx56B7cb9GDCbpTFn6gJp2OmW-CKi7QFA@mail.gmail.com
(don't top post please)
Quoted 3 lines · Frode Isaksen
What will you need in the oops ? I presume you don' want everything or ?
The PHY state machine is not stopped with a PHY disconnect.
It is stopped with a phy_disconnect():
/**
* phy_disconnect - disable interrupts, stop state machine, and detach a PHY
* device
* @phydev: target phy_device struct
*/
void phy_disconnect(struct phy_device *phydev)
{
if (phydev->irq > 0)
phy_stop_interrupts(phydev);
phy_stop_machine(phydev);
phydev->adjust_link = NULL;
phy_detach(phydev);
}Quoted 56 lines
However, the
'phy-change' work is cancelled, so cancelling this work in the remove function maybe not needed. I will verify ASAP.Frode
2015-10-27 16:40 GMT+01:00 Florian Fainelli <[email protected] <mailto:[email protected]>>:
On 27/10/15 07:49, Neil Armstrong wrote: > Avoids: > Unable to handle kernel NULL pointer dereference at virtual address 00000064 > Workqueue: events_power_efficient phy_state_machine > PC is at phy_state_machine+0x28/0x480 Stripped down oops can sometimes be missing critical pieces of information to help debug the problem, is there a reason why this is being obfuscated? You are supposed to stop the PHY state machine by calling phy_disconnect() is it possible that this is missing? > > Signed-off-by: Frode Isaksen <[email protected] <mailto:[email protected]>> > Signed-off-by: Neil Armstrong <[email protected] <mailto:[email protected]>> > --- > drivers/net/phy/phy_device.c | 6 ++++++ > 1 file changed, 6 insertions(+) > > diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c > index 3833891..b5b6c1b 100644 > --- a/drivers/net/phy/phy_device.c > +++ b/drivers/net/phy/phy_device.c > @@ -1348,6 +1348,12 @@ static int phy_remove(struct device *dev) > phydev->state = PHY_DOWN; > mutex_unlock(&phydev->lock); > > + cancel_delayed_work_sync(&phydev->state_queue); > + flush_delayed_work(&phydev->state_queue); > + > + cancel_work_sync(&phydev->phy_queue); > + flush_work(&phydev->phy_queue); > + > if (phydev->drv->remove) > phydev->drv->remove(phydev); > phydev->drv = NULL; > -- Florian
Signature · 1 line
Florian
Andrew Lunn
maintainerQuoted 15 lines · Florian Fainelli
(don't top post please)
Quoted 3 lines · Frode Isaksen
What will you need in the oops ? I presume you don' want everything or ?
The PHY state machine is not stopped with a PHY disconnect.
It is stopped with a
phy_disconnect():/**
*phy_disconnect- disable interrupts, stop state machine, and detach a PHY
* device
* @phydev: targetphy_devicestruct
*/
voidphy_disconnect(struct phy_device *phydev)
Quoted 10 lines
{
if (phydev->irq > 0)
phy_stop_interrupts(phydev);
phy_stop_machine(phydev);
phydev->adjust_link = NULL;
phy_detach(phydev);
}And this does not yet get called. It probably needs to be in dsa_switch_destroy() just before unregister_netdev() of the slave devices.
However, the ordering in dsa_switch_destroy() looks wrong. The fixed phys are destroyed before the slave devices. They should probably be destroyed after the slave devices, or at least after the phy_disconnect() is called.
Andrew
A message that is not in the archive (sent off-list or not yet received): CAJ03sU9Uw9SLXGpH9wqm+GWJtFZvcSuW=YCTZseSanpNeF_+Sw@mail.gmail.com
Quoted 16 lines
Quoted 11 lines
void
phy_disconnect(struct phy_device *phydev){ if (phydev->irq > 0) phy_stop_interrupts(phydev); phy_stop_machine(phydev); phydev->adjust_link = NULL; phy_detach(phydev); }And this does not yet get called. It probably needs to be in
dsa_switch_destroy()just beforeunregister_netdev()of the slave devices.
Quoted 7 lines
However, the ordering in
dsa_switch_destroy()looks wrong. The fixed phys are destroyed before the slave devices. They should probably be destroyed after the slave devices, or at least after thephy_disconnect()is called.Andrew
Andrew, Florian,
Thanks for the review, a call to phy_disconnect was missing in dsa_switch_destroy.
I will post a new patchset with the correct fix, a switch to delayed_work and a separate dsa_slave_destroy function for sake of maintenance ease.
Neil