* [PATCH net 0/2] net: phy: Unbind/bind fixes
@ 2017-02-05 22:25 Florian Fainelli
2017-02-05 22:25 ` [PATCH net 1/2] net: phy: Check phydev->drv Florian Fainelli
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Florian Fainelli @ 2017-02-05 22:25 UTC (permalink / raw)
To: netdev; +Cc: davem, andrew, Russell King, Florian Fainelli
Hi all,
This patch series addresses the inability to safely unbind and bind
PHY drivers by making the appropriate checks throught PHYLIB where we
may be directly responding to user-space queries, as well as from within
the kernel state machine.
The second patch makes the unbind -> bind working by taking care of the
PHY state machine state.
Florian Fainelli (2):
net: phy: Check phydev->drv
net: phy: Fix PHY driver bind and unbind events
drivers/net/phy/phy.c | 26 ++++++++++++++++++++++----
drivers/net/phy/phy_device.c | 27 +++++++++++++++++++++++++--
include/linux/phy.h | 3 +++
3 files changed, 50 insertions(+), 6 deletions(-)
--
2.9.3
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH net 1/2] net: phy: Check phydev->drv
2017-02-05 22:25 [PATCH net 0/2] net: phy: Unbind/bind fixes Florian Fainelli
@ 2017-02-05 22:25 ` Florian Fainelli
2017-02-05 22:25 ` [PATCH net 2/2] net: phy: Fix PHY driver bind and unbind events Florian Fainelli
2017-02-08 6:47 ` [PATCH net 0/2] net: phy: Unbind/bind fixes Florian Fainelli
2 siblings, 0 replies; 4+ messages in thread
From: Florian Fainelli @ 2017-02-05 22:25 UTC (permalink / raw)
To: netdev; +Cc: davem, andrew, Russell King, Florian Fainelli
In preparation for supporting driver bind/unbind properly, sprinkle checks on
phydev->drv where we may call into PHYLIB from user-space or other parts of the
kernel.
Suggested-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
drivers/net/phy/phy.c | 26 ++++++++++++++++++++++----
include/linux/phy.h | 3 +++
2 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 7cc1b7dcfe05..d6f7838455dd 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -580,7 +580,7 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
return 0;
case SIOCSHWTSTAMP:
- if (phydev->drv->hwtstamp)
+ if (phydev->drv && phydev->drv->hwtstamp)
return phydev->drv->hwtstamp(phydev, ifr);
/* fall through */
@@ -603,6 +603,9 @@ int phy_start_aneg(struct phy_device *phydev)
{
int err;
+ if (!phydev->drv)
+ return -EIO;
+
mutex_lock(&phydev->lock);
if (AUTONEG_DISABLE == phydev->autoneg)
@@ -975,7 +978,7 @@ void phy_state_machine(struct work_struct *work)
old_state = phydev->state;
- if (phydev->drv->link_change_notify)
+ if (phydev->drv && phydev->drv->link_change_notify)
phydev->drv->link_change_notify(phydev);
switch (phydev->state) {
@@ -1286,6 +1289,9 @@ EXPORT_SYMBOL(phy_write_mmd_indirect);
*/
int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
{
+ if (!phydev->drv)
+ return -EIO;
+
/* According to 802.3az,the EEE is supported only in full duplex-mode.
* Also EEE feature is active when core is operating with MII, GMII
* or RGMII (all kinds). Internal PHYs are also allowed to proceed and
@@ -1363,6 +1369,9 @@ EXPORT_SYMBOL(phy_init_eee);
*/
int phy_get_eee_err(struct phy_device *phydev)
{
+ if (!phydev->drv)
+ return -EIO;
+
return phy_read_mmd_indirect(phydev, MDIO_PCS_EEE_WK_ERR, MDIO_MMD_PCS);
}
EXPORT_SYMBOL(phy_get_eee_err);
@@ -1379,6 +1388,9 @@ int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_eee *data)
{
int val;
+ if (!phydev->drv)
+ return -EIO;
+
/* Get Supported EEE */
val = phy_read_mmd_indirect(phydev, MDIO_PCS_EEE_ABLE, MDIO_MMD_PCS);
if (val < 0)
@@ -1412,6 +1424,9 @@ int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data)
{
int val = ethtool_adv_to_mmd_eee_adv_t(data->advertised);
+ if (!phydev->drv)
+ return -EIO;
+
/* Mask prohibited EEE modes */
val &= ~phydev->eee_broken_modes;
@@ -1423,7 +1438,7 @@ EXPORT_SYMBOL(phy_ethtool_set_eee);
int phy_ethtool_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
{
- if (phydev->drv->set_wol)
+ if (phydev->drv && phydev->drv->set_wol)
return phydev->drv->set_wol(phydev, wol);
return -EOPNOTSUPP;
@@ -1432,7 +1447,7 @@ EXPORT_SYMBOL(phy_ethtool_set_wol);
void phy_ethtool_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
{
- if (phydev->drv->get_wol)
+ if (phydev->drv && phydev->drv->get_wol)
phydev->drv->get_wol(phydev, wol);
}
EXPORT_SYMBOL(phy_ethtool_get_wol);
@@ -1468,6 +1483,9 @@ int phy_ethtool_nway_reset(struct net_device *ndev)
if (!phydev)
return -ENODEV;
+ if (!phydev->drv)
+ return -EIO;
+
return genphy_restart_aneg(phydev);
}
EXPORT_SYMBOL(phy_ethtool_nway_reset);
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 7fc1105605bf..231e07bb0d76 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -802,6 +802,9 @@ int phy_stop_interrupts(struct phy_device *phydev);
static inline int phy_read_status(struct phy_device *phydev)
{
+ if (!phydev->drv)
+ return -EIO;
+
return phydev->drv->read_status(phydev);
}
--
2.9.3
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH net 2/2] net: phy: Fix PHY driver bind and unbind events
2017-02-05 22:25 [PATCH net 0/2] net: phy: Unbind/bind fixes Florian Fainelli
2017-02-05 22:25 ` [PATCH net 1/2] net: phy: Check phydev->drv Florian Fainelli
@ 2017-02-05 22:25 ` Florian Fainelli
2017-02-08 6:47 ` [PATCH net 0/2] net: phy: Unbind/bind fixes Florian Fainelli
2 siblings, 0 replies; 4+ messages in thread
From: Florian Fainelli @ 2017-02-05 22:25 UTC (permalink / raw)
To: netdev; +Cc: davem, andrew, Russell King, Florian Fainelli
The PHY library does not deal very well with bind and unbind events. The first
thing we would see is that we were not properly canceling the PHY state machine
workqueue, so we would be crashing while dereferencing phydev->drv since there
is no driver attached anymore.
Once we fix that, there are several things that did not quite work as expected:
- if the PHY state machine was running, we were not stopping it properly, and
the state machine state would not be marked as such
- when we rebind the driver, nothing would happen, since we would not know which
state we were before the unbind
This patch takes the following approach:
- if the PHY was attached, and the state machine was running we would stop it,
remember where we left, and schedule the state machine for restart upong
driver bind
- if the PHY was attached, but HALTED, we would let it in that state, and do not
alter the state upon driver bind
- in all other cases (detached) we would keep the PHY in DOWN state waiting for
a network driver to show up, and set PHY_READY on driver bind
Suggested-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
drivers/net/phy/phy_device.c | 27 +++++++++++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 0d8f4d3847f6..05888bd17b97 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1709,6 +1709,7 @@ static int phy_probe(struct device *dev)
struct phy_device *phydev = to_phy_device(dev);
struct device_driver *drv = phydev->mdio.dev.driver;
struct phy_driver *phydrv = to_phy_driver(drv);
+ bool should_start = false;
int err = 0;
phydev->drv = phydrv;
@@ -1758,24 +1759,46 @@ static int phy_probe(struct device *dev)
}
/* Set the state to READY by default */
- phydev->state = PHY_READY;
+ if (phydev->state > PHY_UP && phydev->state != PHY_HALTED)
+ should_start = true;
+ else
+ phydev->state = PHY_READY;
if (phydev->drv->probe)
err = phydev->drv->probe(phydev);
mutex_unlock(&phydev->lock);
+ if (should_start)
+ phy_start(phydev);
+
return err;
}
static int phy_remove(struct device *dev)
{
struct phy_device *phydev = to_phy_device(dev);
+ bool should_stop = false;
+ enum phy_state state;
+
+ cancel_delayed_work_sync(&phydev->state_queue);
mutex_lock(&phydev->lock);
- phydev->state = PHY_DOWN;
+ state = phydev->state;
+ if (state > PHY_UP && state != PHY_HALTED)
+ should_stop = true;
+ else
+ phydev->state = PHY_DOWN;
mutex_unlock(&phydev->lock);
+ /* phy_stop() sets the state to HALTED, undo that for the ->probe() function
+ * to have a chance to resume where we left
+ */
+ if (should_stop) {
+ phy_stop(phydev);
+ phydev->state = state;
+ }
+
if (phydev->drv->remove)
phydev->drv->remove(phydev);
phydev->drv = NULL;
--
2.9.3
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH net 0/2] net: phy: Unbind/bind fixes
2017-02-05 22:25 [PATCH net 0/2] net: phy: Unbind/bind fixes Florian Fainelli
2017-02-05 22:25 ` [PATCH net 1/2] net: phy: Check phydev->drv Florian Fainelli
2017-02-05 22:25 ` [PATCH net 2/2] net: phy: Fix PHY driver bind and unbind events Florian Fainelli
@ 2017-02-08 6:47 ` Florian Fainelli
2 siblings, 0 replies; 4+ messages in thread
From: Florian Fainelli @ 2017-02-08 6:47 UTC (permalink / raw)
To: netdev; +Cc: davem, andrew, Russell King
On 02/05/2017 02:25 PM, Florian Fainelli wrote:
> Hi all,
>
> This patch series addresses the inability to safely unbind and bind
> PHY drivers by making the appropriate checks throught PHYLIB where we
> may be directly responding to user-space queries, as well as from within
> the kernel state machine.
>
> The second patch makes the unbind -> bind working by taking care of the
> PHY state machine state.
I need to make another set of fixes after "net: phy: Fix lack of
reference count on PHY driver" because the Generic PHY driver is of
course behaving differently and my testing was focused on every other
one but this one which is built-in...
>
> Florian Fainelli (2):
> net: phy: Check phydev->drv
> net: phy: Fix PHY driver bind and unbind events
>
> drivers/net/phy/phy.c | 26 ++++++++++++++++++++++----
> drivers/net/phy/phy_device.c | 27 +++++++++++++++++++++++++--
> include/linux/phy.h | 3 +++
> 3 files changed, 50 insertions(+), 6 deletions(-)
>
--
Florian
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2017-02-08 6:48 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-02-05 22:25 [PATCH net 0/2] net: phy: Unbind/bind fixes Florian Fainelli
2017-02-05 22:25 ` [PATCH net 1/2] net: phy: Check phydev->drv Florian Fainelli
2017-02-05 22:25 ` [PATCH net 2/2] net: phy: Fix PHY driver bind and unbind events Florian Fainelli
2017-02-08 6:47 ` [PATCH net 0/2] net: phy: Unbind/bind fixes Florian Fainelli
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).