From: Russell King - ARM Linux <hidden> Date: 2015-09-18 09:46:43
Hi,
While looking at the phy code, I identified a number of weaknesses
where refcounting on device structures was being leaked, where
modules could be removed while in-use, and where the fixed-phy could
end up having unintended consequences caused by incorrect calls to
fixed_phy_update_state().
This patch series resolves those issues, some of which were discovered
with testing on an Armada 388 board. Not all patches are fully tested,
particularly the one which touches several network drivers.
When resolving the struct device refcounting problems, several different
solutions were considered before settling on the implementation here -
one of the considerations was to avoid touching many network drivers.
The solution here is:
phy_attach*() - takes a refcount
phy_detach*() - drops the phy_attach refcount
Provided drivers always attach and detach their phys, which they should
already be doing, this should change nothing, even if they leak a refcount.
of_phy_find_device() and of_* functions which use that take
a refcount. Arrange for this refcount to be dropped once
the phy is attached.
This is the reason why the previous change is important - we can't drop
this refcount taken by of_phy_find_device() until something else holds
a reference on the device. This resolves the leaked refcount caused by
using of_phy_connect() or of_phy_attach().
Even without the above changes, these drivers are leaking by calling
of_phy_find_device(). These drivers are addressed by adding the
appropriate release of that refcount.
The mdiobus code also suffered from the same kind of leak, but thankfully
this only happened in one place - the mdio-mux code.
I also found that the try_module_get() in the phy layer code was utterly
useless: phydev->dev.driver was guaranteed to always be NULL, so
try_module_get() was always being called with a NULL argument. I proved
this with my SFP code, which declares its own MDIO bus - the module use
count was never incremented irrespective of how I set the MDIO bus up.
This allowed the MDIO bus code to be removed from the kernel while there
were still PHYs attached to it.
One other bug was discovered: while using in-band-status with mvneta, it
was found that if a real phy is attached with in-band-status enabled,
and another ethernet interface is using the fixed-phy infrastructure, the
interface using the fixed-phy infrastructure is configured according to
the other interface using the in-band-status - which is caused by the
fixed-phy code not verifying that the phy_device passed in is actually
a fixed-phy device, rather than a real MDIO phy.
Lastly, having mdio_bus reversing phy_device_register() internals seems
like a layering violation - it's trivial to move that code to the phy
device layer.
drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 23 ++++++---
drivers/net/ethernet/cavium/thunder/thunder_bgx.c | 19 +++++++
drivers/net/ethernet/freescale/gianfar.c | 6 ++-
drivers/net/ethernet/freescale/ucc_geth.c | 8 ++-
drivers/net/ethernet/marvell/mvneta.c | 2 +
drivers/net/ethernet/xilinx/xilinx_emaclite.c | 2 +
drivers/net/phy/fixed_phy.c | 2 +-
drivers/net/phy/mdio-mux.c | 19 ++++---
drivers/net/phy/mdio_bus.c | 24 ++++++---
drivers/net/phy/phy_device.c | 62 ++++++++++++++++++-----
drivers/of/of_mdio.c | 27 ++++++++--
include/linux/phy.h | 6 ++-
12 files changed, 156 insertions(+), 44 deletions(-)
--
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
From: Russell King <hidden> Date: 2015-09-18 09:47:13
of_mdio_find_bus() leaks a struct device refcount, caused by using
class_find_device() and not realising that the device reference has
its refcount incremented:
* Note, you will need to drop the reference with put_device() after use.
...
while ((dev = class_dev_iter_next(&iter))) {
if (match(dev, data)) {
get_device(dev);
break;
}
Update the comment, and arrange for the only user of this function
to drop this refcount when disposing of a reference to it.
Signed-off-by: Russell King <redacted>
---
drivers/net/phy/mdio-mux.c | 19 +++++++++++++------
drivers/net/phy/mdio_bus.c | 4 +++-
2 files changed, 16 insertions(+), 7 deletions(-)
@@ -113,18 +113,18 @@ int mdio_mux_init(struct device *dev,if(!parent_bus_node)return-ENODEV;-parent_bus=of_mdio_find_bus(parent_bus_node);-if(parent_bus==NULL){-ret_val=-EPROBE_DEFER;-gotoerr_parent_bus;-}-pb=devm_kzalloc(dev,sizeof(*pb),GFP_KERNEL);if(pb==NULL){ret_val=-ENOMEM;gotoerr_parent_bus;}+parent_bus=of_mdio_find_bus(parent_bus_node);+if(parent_bus==NULL){+ret_val=-EPROBE_DEFER;+gotoerr_parent_bus;+}+pb->switch_data=data;pb->switch_fn=switch_fn;pb->current_child=-1;
@@ -173,6 +173,10 @@ int mdio_mux_init(struct device *dev,dev_info(dev,"Version "DRV_VERSION"\n");return0;}++/* balance the reference of_mdio_find_bus() took */+put_device(&pb->mii_bus->dev);+err_parent_bus:of_node_put(parent_bus_node);returnret_val;
@@ -189,6 +193,9 @@ void mdio_mux_uninit(void *mux_handle)mdiobus_free(cb->mii_bus);cb=cb->next;}++/* balance the reference of_mdio_find_bus() in mdio_mux_init() took */+put_device(&pb->mii_bus->dev);}EXPORT_SYMBOL_GPL(mdio_mux_uninit);
From: Russell King <hidden> Date: 2015-09-18 09:47:19
Re-implement the mdiobus module refcounting to ensure that we actually
ensure that the mdiobus module code does not go away while we might call
into it.
The old scheme using bus->dev.driver was buggy, because bus->dev is a
class device which never has a struct device_driver associated with it,
and hence the associated code trying to obtain a refcount did nothing
useful.
Instead, take the approach that other subsystems do: pass the module
when calling mdiobus_register(), and record that in the mii_bus struct.
When we need to increment the module use count in the phy code, use
this stored pointer. When the phy is deteched, drop the module
refcount, remembering that the phy device might go away at that point.
This doesn't stop the mii_bus going away while there are in-use phys -
it merely stops the underlying code vanishing.
Signed-off-by: Russell King <redacted>
---
drivers/net/phy/mdio_bus.c | 5 +++--
drivers/net/phy/phy_device.c | 32 ++++++++++++++++++--------------
include/linux/phy.h | 5 ++++-
3 files changed, 25 insertions(+), 17 deletions(-)
@@ -582,10 +582,15 @@ EXPORT_SYMBOL(phy_init_hw);intphy_attach_direct(structnet_device*dev,structphy_device*phydev,u32flags,phy_interface_tinterface){+structmii_bus*bus=phydev->bus;structdevice*d=&phydev->dev;-structmodule*bus_module;interr;+if(!try_module_get(bus->owner)){+dev_err(&dev->dev,"failed to get the bus module\n");+return-EIO;+}+/* Assume that if there is no driver, that it doesn't*exist,andweshouldusethegenphydriver.*/
@@ -600,20 +605,13 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,err=device_bind_driver(d);if(err)-returnerr;+gotoerror;}if(phydev->attached_dev){dev_err(&dev->dev,"PHY already attached\n");-return-EBUSY;-}--/* Increment the bus module reference count */-bus_module=phydev->bus->dev.driver?-phydev->bus->dev.driver->owner:NULL;-if(!try_module_get(bus_module)){-dev_err(&dev->dev,"failed to get the bus module\n");-return-EIO;+err=-EBUSY;+gotoerror;}phydev->attached_dev=dev;
From: Russell King <hidden> Date: 2015-09-18 09:47:24
Take a refcount on the phy struct device when the phy device is attached
to a network device, and drop it after it's detached. This ensures that
a refcount is held on the phy device while the device is being used by
a network device, thereby preventing the phy_device from being
unexpectedly kfree()'d by phy_device_release().
Signed-off-by: Russell King <redacted>
---
drivers/net/phy/phy_device.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
@@ -591,6 +592,8 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,return-EIO;}+get_device(d);+/* Assume that if there is no driver, that it doesn't*exist,andweshouldusethegenphydriver.*/
From: Russell King <hidden> Date: 2015-09-18 09:47:29
bus_find_device() is defined as:
* This is similar to the bus_for_each_dev() function above, but it
* returns a reference to a device that is 'found' for later use, as
* determined by the @match callback.
and it does indeed return a reference-counted pointer to the device:
while ((dev = next_device(&i)))
if (match(dev, data) && get_device(dev))
^^^^^^^^^^^^^^^
break;
klist_iter_exit(&i);
return dev;
What that means is that when we're done with the struct device, we must
drop that reference. Neither of_phy_connect() nor of_phy_attach() did
this when phy_connect_direct() or phy_attach_direct() failed.
With our previous patch, phy_connect_direct() and phy_attach_direct()
take a new refcount on the phy device when successful, so we can drop
our local reference immediatley after these functions, whether or not
they succeeded.
Signed-off-by: Russell King <redacted>
---
drivers/of/of_mdio.c | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
@@ -225,13 +228,19 @@ struct phy_device *of_phy_connect(struct net_device *dev,phy_interface_tiface){structphy_device*phy=of_phy_find_device(phy_np);+intret;if(!phy)returnNULL;phy->dev_flags=flags;-returnphy_connect_direct(dev,phy,hndlr,iface)?NULL:phy;+ret=phy_connect_direct(dev,phy,hndlr,iface);++/* refcount is held by phy_connect_direct() on success */+put_device(&phy->dev);++returnret?NULL:phy;}EXPORT_SYMBOL(of_phy_connect);
@@ -241,17 +250,27 @@ EXPORT_SYMBOL(of_phy_connect);*@phy_np:NodepointerforthePHY*@flags:flagstopasstothePHY*@iface:PHYdatainterfacetype+*+*Ifsuccessful,returnsapointertothephy_devicewiththeembedded+*structdevicerefcountincrementedbyone,orNULLonfailure.The+*refcountmustbedroppedbycallingphy_disconnect()orphy_detach().*/structphy_device*of_phy_attach(structnet_device*dev,structdevice_node*phy_np,u32flags,phy_interface_tiface){structphy_device*phy=of_phy_find_device(phy_np);+intret;if(!phy)returnNULL;-returnphy_attach_direct(dev,phy,flags,iface)?NULL:phy;+ret=phy_attach_direct(dev,phy,flags,iface);++/* refcount is held by phy_attach_direct() on success */+put_device(&phy->dev);++returnret?NULL:phy;}EXPORT_SYMBOL(of_phy_attach);
From: Russell King <hidden> Date: 2015-09-18 09:47:34
of_phy_find_device() increments the phy struct device refcount,
which we need to properly balance. Add code to network drivers
using this function to ensure that the struct device refcount is
correctly balanced.
Signed-off-by: Russell King <redacted>
---
drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 23 +++++++++++++++--------
drivers/net/ethernet/cavium/thunder/thunder_bgx.c | 19 +++++++++++++++++++
drivers/net/ethernet/freescale/gianfar.c | 3 +++
drivers/net/ethernet/freescale/ucc_geth.c | 8 +++++++-
drivers/net/ethernet/marvell/mvneta.c | 2 ++
drivers/net/ethernet/xilinx/xilinx_emaclite.c | 2 ++
6 files changed, 48 insertions(+), 9 deletions(-)
@@ -689,16 +689,23 @@ static int xgene_enet_phy_connect(struct net_device *ndev)netdev_dbg(ndev,"No phy-handle found in DT\n");return-ENODEV;}-pdata->phy_dev=of_phy_find_device(phy_np);-}-phy_dev=pdata->phy_dev;+pdata->phy_dev=of_phy_connect(ndev,phy_np,+&xgene_enet_adjust_link,+pdata->phy_mode);+if(!pdata->phy_dev){+netdev_err(ndev,"Could not connect to PHY\n");+return-ENODEV;+}+}else{+phy_dev=pdata->phy_dev;-if(!phy_dev||-phy_connect_direct(ndev,phy_dev,&xgene_enet_adjust_link,-pdata->phy_mode)){-netdev_err(ndev,"Could not connect to PHY\n");-return-ENODEV;+if(!phy_dev||+phy_connect_direct(ndev,phy_dev,&xgene_enet_adjust_link,+pdata->phy_mode)){+netdev_err(ndev,"Could not connect to PHY\n");+return-ENODEV;+}}pdata->phy_speed=SPEED_UNKNOWN;
@@ -1702,6 +1702,7 @@ static void gfar_configure_serdes(struct net_device *dev)tbiphy=of_phy_find_device(priv->tbi_node);if(!tbiphy){dev_err(&dev->dev,"error: Could not get TBI device\n");+put_device(&tbiphy->dev);return;}
@@ -828,6 +828,8 @@ static int xemaclite_mdio_setup(struct net_local *lp, struct device *dev)if(!phydev)dev_info(dev,"MDIO of the phy is not registered yet\n");+else+put_device(&phydev->dev);return0;}
From: Russell King <hidden> Date: 2015-09-18 09:47:40
Validate that the phy_device passed into fixed_phy_update_state() is a
fixed-phy device before walking the list of phys for a fixed phy at the
same address.
Signed-off-by: Russell King <redacted>
---
drivers/net/phy/fixed_phy.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Russell King <hidden> Date: 2015-09-18 09:47:45
Add a phy_device_remove() function to complement phy_device_register(),
which undoes the effects of phy_device_register() by removing the phy
device from visibility, but not freeing it.
This allows these details to be moved out of the mdio bus code into
the phy code where this action belongs.
Signed-off-by: Russell King <redacted>
---
drivers/net/ethernet/freescale/gianfar.c | 5 +++--
drivers/net/phy/mdio_bus.c | 15 ++++++++++-----
drivers/net/phy/phy_device.c | 18 ++++++++++++++++++
include/linux/phy.h | 1 +
4 files changed, 32 insertions(+), 7 deletions(-)
@@ -1702,7 +1702,6 @@ static void gfar_configure_serdes(struct net_device *dev)tbiphy=of_phy_find_device(priv->tbi_node);if(!tbiphy){dev_err(&dev->dev,"error: Could not get TBI device\n");-put_device(&tbiphy->dev);return;}
@@ -1711,8 +1710,10 @@ static void gfar_configure_serdes(struct net_device *dev)*everythingforus?Resettingittakesthelinkdownandrequires*severalsecondsforittocomeback.*/-if(phy_read(tbiphy,MII_BMSR)&BMSR_LSTATUS)+if(phy_read(tbiphy,MII_BMSR)&BMSR_LSTATUS){+put_device(&tbiphy->dev);return;+}/* Single clk mode, mii mode off(for serdes communication) */phy_write(tbiphy,MII_TBICON,TBICON_CLK_SELECT);
From: Russell King <hidden> Date: 2015-09-18 09:55:04
of_mdio_find_bus() leaks a struct device refcount, caused by using
class_find_device() and not realising that the device reference has
its refcount incremented:
* Note, you will need to drop the reference with put_device() after use.
...
while ((dev = class_dev_iter_next(&iter))) {
if (match(dev, data)) {
get_device(dev);
break;
}
Update the comment, and arrange for the only user of this function
to drop this refcount when disposing of a reference to it.
Signed-off-by: Russell King <redacted>
---
drivers/net/phy/mdio-mux.c | 19 +++++++++++++------
drivers/net/phy/mdio_bus.c | 4 +++-
2 files changed, 16 insertions(+), 7 deletions(-)
@@ -113,18 +113,18 @@ int mdio_mux_init(struct device *dev,if(!parent_bus_node)return-ENODEV;-parent_bus=of_mdio_find_bus(parent_bus_node);-if(parent_bus==NULL){-ret_val=-EPROBE_DEFER;-gotoerr_parent_bus;-}-pb=devm_kzalloc(dev,sizeof(*pb),GFP_KERNEL);if(pb==NULL){ret_val=-ENOMEM;gotoerr_parent_bus;}+parent_bus=of_mdio_find_bus(parent_bus_node);+if(parent_bus==NULL){+ret_val=-EPROBE_DEFER;+gotoerr_parent_bus;+}+pb->switch_data=data;pb->switch_fn=switch_fn;pb->current_child=-1;
@@ -173,6 +173,10 @@ int mdio_mux_init(struct device *dev,dev_info(dev,"Version "DRV_VERSION"\n");return0;}++/* balance the reference of_mdio_find_bus() took */+put_device(&pb->mii_bus->dev);+err_parent_bus:of_node_put(parent_bus_node);returnret_val;
@@ -189,6 +193,9 @@ void mdio_mux_uninit(void *mux_handle)mdiobus_free(cb->mii_bus);cb=cb->next;}++/* balance the reference of_mdio_find_bus() in mdio_mux_init() took */+put_device(&pb->mii_bus->dev);}EXPORT_SYMBOL_GPL(mdio_mux_uninit);
From: Russell King <hidden> Date: 2015-09-18 09:55:18
Re-implement the mdiobus module refcounting to ensure that we actually
ensure that the mdiobus module code does not go away while we might call
into it.
The old scheme using bus->dev.driver was buggy, because bus->dev is a
class device which never has a struct device_driver associated with it,
and hence the associated code trying to obtain a refcount did nothing
useful.
Instead, take the approach that other subsystems do: pass the module
when calling mdiobus_register(), and record that in the mii_bus struct.
When we need to increment the module use count in the phy code, use
this stored pointer. When the phy is deteched, drop the module
refcount, remembering that the phy device might go away at that point.
This doesn't stop the mii_bus going away while there are in-use phys -
it merely stops the underlying code vanishing.
Signed-off-by: Russell King <redacted>
---
drivers/net/phy/mdio_bus.c | 5 +++--
drivers/net/phy/phy_device.c | 32 ++++++++++++++++++--------------
include/linux/phy.h | 5 ++++-
3 files changed, 25 insertions(+), 17 deletions(-)
@@ -582,10 +582,15 @@ EXPORT_SYMBOL(phy_init_hw);intphy_attach_direct(structnet_device*dev,structphy_device*phydev,u32flags,phy_interface_tinterface){+structmii_bus*bus=phydev->bus;structdevice*d=&phydev->dev;-structmodule*bus_module;interr;+if(!try_module_get(bus->owner)){+dev_err(&dev->dev,"failed to get the bus module\n");+return-EIO;+}+/* Assume that if there is no driver, that it doesn't*exist,andweshouldusethegenphydriver.*/
@@ -600,20 +605,13 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,err=device_bind_driver(d);if(err)-returnerr;+gotoerror;}if(phydev->attached_dev){dev_err(&dev->dev,"PHY already attached\n");-return-EBUSY;-}--/* Increment the bus module reference count */-bus_module=phydev->bus->dev.driver?-phydev->bus->dev.driver->owner:NULL;-if(!try_module_get(bus_module)){-dev_err(&dev->dev,"failed to get the bus module\n");-return-EIO;+err=-EBUSY;+gotoerror;}phydev->attached_dev=dev;
From: Russell King <hidden> Date: 2015-09-18 09:55:30
Take a refcount on the phy struct device when the phy device is attached
to a network device, and drop it after it's detached. This ensures that
a refcount is held on the phy device while the device is being used by
a network device, thereby preventing the phy_device from being
unexpectedly kfree()'d by phy_device_release().
Signed-off-by: Russell King <redacted>
---
drivers/net/phy/phy_device.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
@@ -591,6 +592,8 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,return-EIO;}+get_device(d);+/* Assume that if there is no driver, that it doesn't*exist,andweshouldusethegenphydriver.*/
From: Russell King <hidden> Date: 2015-09-18 09:55:44
bus_find_device() is defined as:
* This is similar to the bus_for_each_dev() function above, but it
* returns a reference to a device that is 'found' for later use, as
* determined by the @match callback.
and it does indeed return a reference-counted pointer to the device:
while ((dev = next_device(&i)))
if (match(dev, data) && get_device(dev))
^^^^^^^^^^^^^^^
break;
klist_iter_exit(&i);
return dev;
What that means is that when we're done with the struct device, we must
drop that reference. Neither of_phy_connect() nor of_phy_attach() did
this when phy_connect_direct() or phy_attach_direct() failed.
With our previous patch, phy_connect_direct() and phy_attach_direct()
take a new refcount on the phy device when successful, so we can drop
our local reference immediatley after these functions, whether or not
they succeeded.
Signed-off-by: Russell King <redacted>
---
drivers/of/of_mdio.c | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
@@ -225,13 +228,19 @@ struct phy_device *of_phy_connect(struct net_device *dev,phy_interface_tiface){structphy_device*phy=of_phy_find_device(phy_np);+intret;if(!phy)returnNULL;phy->dev_flags=flags;-returnphy_connect_direct(dev,phy,hndlr,iface)?NULL:phy;+ret=phy_connect_direct(dev,phy,hndlr,iface);++/* refcount is held by phy_connect_direct() on success */+put_device(&phy->dev);++returnret?NULL:phy;}EXPORT_SYMBOL(of_phy_connect);
@@ -241,17 +250,27 @@ EXPORT_SYMBOL(of_phy_connect);*@phy_np:NodepointerforthePHY*@flags:flagstopasstothePHY*@iface:PHYdatainterfacetype+*+*Ifsuccessful,returnsapointertothephy_devicewiththeembedded+*structdevicerefcountincrementedbyone,orNULLonfailure.The+*refcountmustbedroppedbycallingphy_disconnect()orphy_detach().*/structphy_device*of_phy_attach(structnet_device*dev,structdevice_node*phy_np,u32flags,phy_interface_tiface){structphy_device*phy=of_phy_find_device(phy_np);+intret;if(!phy)returnNULL;-returnphy_attach_direct(dev,phy,flags,iface)?NULL:phy;+ret=phy_attach_direct(dev,phy,flags,iface);++/* refcount is held by phy_attach_direct() on success */+put_device(&phy->dev);++returnret?NULL:phy;}EXPORT_SYMBOL(of_phy_attach);
From: Russell King <hidden> Date: 2015-09-18 09:55:54
of_phy_find_device() increments the phy struct device refcount,
which we need to properly balance. Add code to network drivers
using this function to ensure that the struct device refcount is
correctly balanced.
Signed-off-by: Russell King <redacted>
---
drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 23 +++++++++++++++--------
drivers/net/ethernet/cavium/thunder/thunder_bgx.c | 19 +++++++++++++++++++
drivers/net/ethernet/freescale/gianfar.c | 3 +++
drivers/net/ethernet/freescale/ucc_geth.c | 8 +++++++-
drivers/net/ethernet/marvell/mvneta.c | 2 ++
drivers/net/ethernet/xilinx/xilinx_emaclite.c | 2 ++
6 files changed, 48 insertions(+), 9 deletions(-)
@@ -689,16 +689,23 @@ static int xgene_enet_phy_connect(struct net_device *ndev)netdev_dbg(ndev,"No phy-handle found in DT\n");return-ENODEV;}-pdata->phy_dev=of_phy_find_device(phy_np);-}-phy_dev=pdata->phy_dev;+pdata->phy_dev=of_phy_connect(ndev,phy_np,+&xgene_enet_adjust_link,+pdata->phy_mode);+if(!pdata->phy_dev){+netdev_err(ndev,"Could not connect to PHY\n");+return-ENODEV;+}+}else{+phy_dev=pdata->phy_dev;-if(!phy_dev||-phy_connect_direct(ndev,phy_dev,&xgene_enet_adjust_link,-pdata->phy_mode)){-netdev_err(ndev,"Could not connect to PHY\n");-return-ENODEV;+if(!phy_dev||+phy_connect_direct(ndev,phy_dev,&xgene_enet_adjust_link,+pdata->phy_mode)){+netdev_err(ndev,"Could not connect to PHY\n");+return-ENODEV;+}}pdata->phy_speed=SPEED_UNKNOWN;
@@ -1702,6 +1702,7 @@ static void gfar_configure_serdes(struct net_device *dev)tbiphy=of_phy_find_device(priv->tbi_node);if(!tbiphy){dev_err(&dev->dev,"error: Could not get TBI device\n");+put_device(&tbiphy->dev);return;}
@@ -828,6 +828,8 @@ static int xemaclite_mdio_setup(struct net_local *lp, struct device *dev)if(!phydev)dev_info(dev,"MDIO of the phy is not registered yet\n");+else+put_device(&phydev->dev);return0;}
From: Russell King <hidden> Date: 2015-09-18 09:56:00
Validate that the phy_device passed into fixed_phy_update_state() is a
fixed-phy device before walking the list of phys for a fixed phy at the
same address.
Signed-off-by: Russell King <redacted>
---
drivers/net/phy/fixed_phy.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Russell King <hidden> Date: 2015-09-18 09:56:05
Add a phy_device_remove() function to complement phy_device_register(),
which undoes the effects of phy_device_register() by removing the phy
device from visibility, but not freeing it.
This allows these details to be moved out of the mdio bus code into
the phy code where this action belongs.
Signed-off-by: Russell King <redacted>
---
drivers/net/ethernet/freescale/gianfar.c | 5 +++--
drivers/net/phy/mdio_bus.c | 15 ++++++++++-----
drivers/net/phy/phy_device.c | 18 ++++++++++++++++++
include/linux/phy.h | 1 +
4 files changed, 32 insertions(+), 7 deletions(-)
@@ -1702,7 +1702,6 @@ static void gfar_configure_serdes(struct net_device *dev)tbiphy=of_phy_find_device(priv->tbi_node);if(!tbiphy){dev_err(&dev->dev,"error: Could not get TBI device\n");-put_device(&tbiphy->dev);return;}
@@ -1711,8 +1710,10 @@ static void gfar_configure_serdes(struct net_device *dev)*everythingforus?Resettingittakesthelinkdownandrequires*severalsecondsforittocomeback.*/-if(phy_read(tbiphy,MII_BMSR)&BMSR_LSTATUS)+if(phy_read(tbiphy,MII_BMSR)&BMSR_LSTATUS){+put_device(&tbiphy->dev);return;+}/* Single clk mode, mii mode off(for serdes communication) */phy_write(tbiphy,MII_TBICON,TBICON_CLK_SELECT);
From: Russell King - ARM Linux <hidden> Date: 2015-09-18 10:01:22
Sorry guys, some of you will get the patches twice, as Sören's name
in the header caused vger to reject all the patches.
--
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Russell,
On Fri, 2015-09-18 at 10:56AM +0100, Russell King - ARM Linux wrote:
Sorry guys, some of you will get the patches twice, as Sören's name
in the header caused vger to reject all the patches.
That is the first time I hear about an issue like that. I've been
receiving patches fine thus far and nobody reported any rejections (by
vger) to me. Is it some bounce on Xilinx/my side or is vger suddenly
rejecting non-ascii chars or is something in the mail processing chain
not properly encoding those chars?
Please, let me know if I can help with the problem.
Thanks,
Sören
From: Russell King - ARM Linux <hidden> Date: 2015-09-18 15:21:10
On Fri, Sep 18, 2015 at 08:01:28AM -0700, Sören Brinkmann wrote:
Hi Russell,
On Fri, 2015-09-18 at 10:56AM +0100, Russell King - ARM Linux wrote:
quoted
Sorry guys, some of you will get the patches twice, as Sören's name
in the header caused vger to reject all the patches.
That is the first time I hear about an issue like that. I've been
receiving patches fine thus far and nobody reported any rejections (by
vger) to me. Is it some bounce on Xilinx/my side or is vger suddenly
rejecting non-ascii chars or is something in the mail processing chain
not properly encoding those chars?
Please, let me know if I can help with the problem.
It's to do with how I generate the patch set and submit it to my MTA.
The result is that the header fields contain an ö. Almost all MTAs
accept this despite it being questionable, but zmailer is extra fussy
and rejects this - and rejected the messages to lkml, netdev, etc.
Normally, the MUA would encode "Sören Brinkmann" in a header into a
7-bit ascii representation as "=?utf-8?B?U8O2cmVu?= Brinkmann".
It's one of the many issues of not using a MUA to send out patches.
It's also worth noting that git-send-email misses out mime headers
(or used to - which is why I have my own scripts for doing this)
which technically makes the bodies it mails out in violation of the
RFCs.
--
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
Le 09/18/15 02:46, Russell King - ARM Linux a écrit :
Hi,
While looking at the phy code, I identified a number of weaknesses
where refcounting on device structures was being leaked, where
modules could be removed while in-use, and where the fixed-phy could
end up having unintended consequences caused by incorrect calls to
fixed_phy_update_state().
This patch series resolves those issues, some of which were discovered
with testing on an Armada 388 board. Not all patches are fully tested,
particularly the one which touches several network drivers.
When resolving the struct device refcounting problems, several different
solutions were considered before settling on the implementation here -
one of the considerations was to avoid touching many network drivers.
The solution here is:
phy_attach*() - takes a refcount
phy_detach*() - drops the phy_attach refcount
Provided drivers always attach and detach their phys, which they should
already be doing, this should change nothing, even if they leak a refcount.
of_phy_find_device() and of_* functions which use that take
a refcount. Arrange for this refcount to be dropped once
the phy is attached.
This is the reason why the previous change is important - we can't drop
this refcount taken by of_phy_find_device() until something else holds
a reference on the device. This resolves the leaked refcount caused by
using of_phy_connect() or of_phy_attach().
Even without the above changes, these drivers are leaking by calling
of_phy_find_device(). These drivers are addressed by adding the
appropriate release of that refcount.
The mdiobus code also suffered from the same kind of leak, but thankfully
this only happened in one place - the mdio-mux code.
I also found that the try_module_get() in the phy layer code was utterly
useless: phydev->dev.driver was guaranteed to always be NULL, so
try_module_get() was always being called with a NULL argument. I proved
this with my SFP code, which declares its own MDIO bus - the module use
count was never incremented irrespective of how I set the MDIO bus up.
This allowed the MDIO bus code to be removed from the kernel while there
were still PHYs attached to it.
One other bug was discovered: while using in-band-status with mvneta, it
was found that if a real phy is attached with in-band-status enabled,
and another ethernet interface is using the fixed-phy infrastructure, the
interface using the fixed-phy infrastructure is configured according to
the other interface using the in-band-status - which is caused by the
fixed-phy code not verifying that the phy_device passed in is actually
a fixed-phy device, rather than a real MDIO phy.
Lastly, having mdio_bus reversing phy_device_register() internals seems
like a layering violation - it's trivial to move that code to the phy
device layer.
Reviewed-by: Florian Fainelli <redacted>
Thanks!
--
Florian
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
From: David Miller <davem@davemloft.net> Date: 2015-09-21 19:02:06
From: Russell King <redacted>
Date: Fri, 18 Sep 2015 10:54:55 +0100
Update the comment, and arrange for the only user of this function
to drop this refcount when disposing of a reference to it.
mdio_mux is not the only user of of_mdio_find_bus(), DSA uses it as
well.
So if anything this commit message is inaccurate.
I also wonder about this refcounting scheme.
If you are going to drop the inner device reference, then we take the
mdio bus returned from of_mdio_find_bus() what holds onto it and keeps
it from disappearing on us?
Don't we have to hold onto some reference count of some kind here?
From: Russell King - ARM Linux <hidden> Date: 2015-09-21 19:32:27
On Mon, Sep 21, 2015 at 12:01:59PM -0700, David Miller wrote:
From: Russell King <rmk+kernel-lFZ/pmaqli7XmaaqVzeoHQ@public.gmane.org>
Date: Fri, 18 Sep 2015 10:54:55 +0100
quoted
Update the comment, and arrange for the only user of this function
to drop this refcount when disposing of a reference to it.
mdio_mux is not the only user of of_mdio_find_bus(), DSA uses it as
well.
So if anything this commit message is inaccurate.
Yes, I missed that as it wasn't under drivers/net. It doesn't change
the validity of this patch, the existing code is wrong and I'm not
introducing anything that makes the code any more wrong than it is.
I'll fix the commit message, and I'll fix the DSA code too but in a
separate patch. Thanks for pointing it out.
I also wonder about this refcounting scheme.
It's the standard driver model refcounting rules that we've lived with
for about a decade, ever since the driver model was introduced by
Patrick Mochel.
If you are going to drop the inner device reference, then we take the
mdio bus returned from of_mdio_find_bus() what holds onto it and keeps
it from disappearing on us?
Don't we have to hold onto some reference count of some kind here?
In the case of the mdio mux code, I'm dropping the reference when
either (a) we've encountered an error during initialisation and we're
cleaning up, or (b) when the mdio mux code is being torn down after
the mdiomux bus has been unregistered and freed. In both cases, we're
done with the mdio bus that was returned from of_mdio_find_bus().
In case (a), the devres code will release the kmalloc'd memory when
mdio_mux_gpio_probe() or mdio_mux_mmioreg_probe() propagates the error
out of their probe() function.
I'm not sure why you think anything is wrong here - maybe it's the odd
code structure to the success path at the bottom of mdio_mux_init()?
--
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
From: David Miller <hidden> Date: 2015-09-21 22:08:31
From: Russell King - ARM Linux <redacted>
Date: Mon, 21 Sep 2015 20:32:07 +0100
In the case of the mdio mux code, I'm dropping the reference when
either (a) we've encountered an error during initialisation and
we're cleaning up, or (b) when the mdio mux code is being torn down
after the mdiomux bus has been unregistered and freed. In both
cases, we're done with the mdio bus that was returned from
of_mdio_find_bus().
In case (a), the devres code will release the kmalloc'd memory when
mdio_mux_gpio_probe() or mdio_mux_mmioreg_probe() propagates the error
out of their probe() function.
I'm not sure why you think anything is wrong here - maybe it's the odd
code structure to the success path at the bottom of mdio_mux_init()?
Ok I may have misread your change. I'll restudy it when you respin
the series with the commit message fixed and the DSA change added.
Thanks.