The vsc85xx_default_config function called in the vsc85xx_config_init
function which is used by VSC8530, VSC8531, VSC8540 and VSC8541 PHYs
mistakenly calls phy_read and phy_write in-between phy_select_page and
phy_restore_page.
phy_select_page and phy_restore_page actually take and release the MDIO
bus lock so __phy_write and __phy_read (which assume that you already
have the MDIO bus lock unlike phy_write and phy_read) should be used for
any call in between the two said functions.
Let's fix this deadlock.
Fixes: 6a0bfbbe20b0 ("net: phy: mscc: migrate to phy_select/restore_page functions")
Signed-off-by: Quentin Schulz <[email protected]>
---
drivers/net/phy/mscc.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c
index 62269e578718..6856fe4d1a60 100644
--- a/drivers/net/phy/mscc.c
+++ b/drivers/net/phy/mscc.c
@@ -814,10 +814,10 @@ static int vsc85xx_default_config(struct phy_device *phydev)
if (rc < 0)
goto out_unlock;
- reg_val = phy_read(phydev, MSCC_PHY_RGMII_CNTL);
+ reg_val = __phy_read(phydev, MSCC_PHY_RGMII_CNTL);
reg_val &= ~(RGMII_RX_CLK_DELAY_MASK);
reg_val |= (RGMII_RX_CLK_DELAY_1_1_NS << RGMII_RX_CLK_DELAY_POS);
- phy_write(phydev, MSCC_PHY_RGMII_CNTL, reg_val);
+ __phy_write(phydev, MSCC_PHY_RGMII_CNTL, reg_val);
out_unlock:
rc = phy_restore_page(phydev, rc, rc > 0 ? 0 : rc);
--
2.17.1
On Thu, Nov 22, 2018 at 02:12:32PM +0100, Quentin Schulz wrote:
> The vsc85xx_default_config function called in the vsc85xx_config_init
> function which is used by VSC8530, VSC8531, VSC8540 and VSC8541 PHYs
> mistakenly calls phy_read and phy_write in-between phy_select_page and
> phy_restore_page.
>
> phy_select_page and phy_restore_page actually take and release the MDIO
> bus lock so __phy_write and __phy_read (which assume that you already
> have the MDIO bus lock unlike phy_write and phy_read) should be used for
> any call in between the two said functions.
>
> Let's fix this deadlock.
>
> Fixes: 6a0bfbbe20b0 ("net: phy: mscc: migrate to phy_select/restore_page functions")
>
> Signed-off-by: Quentin Schulz <[email protected]>
> ---
> drivers/net/phy/mscc.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c
> index 62269e578718..6856fe4d1a60 100644
> --- a/drivers/net/phy/mscc.c
> +++ b/drivers/net/phy/mscc.c
> @@ -814,10 +814,10 @@ static int vsc85xx_default_config(struct phy_device *phydev)
> if (rc < 0)
> goto out_unlock;
>
> - reg_val = phy_read(phydev, MSCC_PHY_RGMII_CNTL);
> + reg_val = __phy_read(phydev, MSCC_PHY_RGMII_CNTL);
> reg_val &= ~(RGMII_RX_CLK_DELAY_MASK);
> reg_val |= (RGMII_RX_CLK_DELAY_1_1_NS << RGMII_RX_CLK_DELAY_POS);
> - phy_write(phydev, MSCC_PHY_RGMII_CNTL, reg_val);
> + __phy_write(phydev, MSCC_PHY_RGMII_CNTL, reg_val);
Hi Quentin
You appear to be only accessing a single register, read/modify/write.
I think you can use phy_modify_paged(), which will take care of all
the locking for you.
Andrew
Hi Andrew,
On Thu, Nov 22, 2018 at 08:28:37PM +0100, Andrew Lunn wrote:
> On Thu, Nov 22, 2018 at 02:12:32PM +0100, Quentin Schulz wrote:
> > The vsc85xx_default_config function called in the vsc85xx_config_init
> > function which is used by VSC8530, VSC8531, VSC8540 and VSC8541 PHYs
> > mistakenly calls phy_read and phy_write in-between phy_select_page and
> > phy_restore_page.
> >
> > phy_select_page and phy_restore_page actually take and release the MDIO
> > bus lock so __phy_write and __phy_read (which assume that you already
> > have the MDIO bus lock unlike phy_write and phy_read) should be used for
> > any call in between the two said functions.
> >
> > Let's fix this deadlock.
> >
> > Fixes: 6a0bfbbe20b0 ("net: phy: mscc: migrate to phy_select/restore_page functions")
> >
> > Signed-off-by: Quentin Schulz <[email protected]>
> > ---
> > drivers/net/phy/mscc.c | 4 ++--
> > 1 file changed, 2 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c
> > index 62269e578718..6856fe4d1a60 100644
> > --- a/drivers/net/phy/mscc.c
> > +++ b/drivers/net/phy/mscc.c
> > @@ -814,10 +814,10 @@ static int vsc85xx_default_config(struct phy_device *phydev)
> > if (rc < 0)
> > goto out_unlock;
> >
> > - reg_val = phy_read(phydev, MSCC_PHY_RGMII_CNTL);
> > + reg_val = __phy_read(phydev, MSCC_PHY_RGMII_CNTL);
> > reg_val &= ~(RGMII_RX_CLK_DELAY_MASK);
> > reg_val |= (RGMII_RX_CLK_DELAY_1_1_NS << RGMII_RX_CLK_DELAY_POS);
> > - phy_write(phydev, MSCC_PHY_RGMII_CNTL, reg_val);
> > + __phy_write(phydev, MSCC_PHY_RGMII_CNTL, reg_val);
>
> Hi Quentin
>
> You appear to be only accessing a single register, read/modify/write.
> I think you can use phy_modify_paged(), which will take care of all
> the locking for you.
>
Grmbl... Of course :)
Thanks,
Quentin