drivers/net/phy/mscc/mscc.h | 4 ++++ drivers/net/phy/mscc/mscc_main.c | 4 +--- drivers/net/phy/mscc/mscc_ptp.c | 40 +++++++++++++++++++++++--------- 3 files changed, 34 insertions(+), 14 deletions(-)
It looks like that every time when the interface was set down and up the
driver was creating a new ptp clock. On top of this the function
ptp_clock_unregister was never called.
Therefore fix this by calling ptp_clock_register and initialize the
mii_ts struct inside the probe function and call ptp_clock_unregister when
driver is removed.
Fixes: 7d272e63e0979d ("net: phy: mscc: timestamping and PHC support")
Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
---
drivers/net/phy/mscc/mscc.h | 4 ++++
drivers/net/phy/mscc/mscc_main.c | 4 +---
drivers/net/phy/mscc/mscc_ptp.c | 40 +++++++++++++++++++++++---------
3 files changed, 34 insertions(+), 14 deletions(-)
diff --git a/drivers/net/phy/mscc/mscc.h b/drivers/net/phy/mscc/mscc.h
index b8c6ba7c7834e..2d8eca54c40a2 100644
--- a/drivers/net/phy/mscc/mscc.h
+++ b/drivers/net/phy/mscc/mscc.h
@@ -484,6 +484,7 @@ static inline void vsc8584_config_macsec_intr(struct phy_device *phydev)
void vsc85xx_link_change_notify(struct phy_device *phydev);
void vsc8584_config_ts_intr(struct phy_device *phydev);
int vsc8584_ptp_init(struct phy_device *phydev);
+void vsc8584_ptp_deinit(struct phy_device *phydev);
int vsc8584_ptp_probe_once(struct phy_device *phydev);
int vsc8584_ptp_probe(struct phy_device *phydev);
irqreturn_t vsc8584_handle_ts_interrupt(struct phy_device *phydev);
@@ -498,6 +499,9 @@ static inline int vsc8584_ptp_init(struct phy_device *phydev)
{
return 0;
}
+static inline void vsc8584_ptp_deinit(struct phy_device *phydev)
+{
+}
static inline int vsc8584_ptp_probe_once(struct phy_device *phydev)
{
return 0;
diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c
index 800da302ae632..a034a8a8dde51 100644
--- a/drivers/net/phy/mscc/mscc_main.c
+++ b/drivers/net/phy/mscc/mscc_main.c
@@ -2370,9 +2370,7 @@ static int vsc85xx_probe(struct phy_device *phydev)
static void vsc85xx_remove(struct phy_device *phydev)
{
- struct vsc8531_private *priv = phydev->priv;
-
- skb_queue_purge(&priv->rx_skbs_list);
+ vsc8584_ptp_deinit(phydev);
}
/* Microsemi VSC85xx PHYs */
diff --git a/drivers/net/phy/mscc/mscc_ptp.c b/drivers/net/phy/mscc/mscc_ptp.c
index de6c7312e8f29..827c399d9d30f 100644
--- a/drivers/net/phy/mscc/mscc_ptp.c
+++ b/drivers/net/phy/mscc/mscc_ptp.c
@@ -1298,7 +1298,6 @@ static void vsc8584_set_input_clk_configured(struct phy_device *phydev)
static int __vsc8584_init_ptp(struct phy_device *phydev)
{
- struct vsc8531_private *vsc8531 = phydev->priv;
static const u32 ltc_seq_e[] = { 0, 400000, 0, 0, 0 };
static const u8 ltc_seq_a[] = { 8, 6, 5, 4, 2 };
u32 val;
@@ -1515,17 +1514,15 @@ static int __vsc8584_init_ptp(struct phy_device *phydev)
vsc85xx_ts_eth_cmp1_sig(phydev);
- vsc8531->mii_ts.rxtstamp = vsc85xx_rxtstamp;
- vsc8531->mii_ts.txtstamp = vsc85xx_txtstamp;
- vsc8531->mii_ts.hwtstamp = vsc85xx_hwtstamp;
- vsc8531->mii_ts.ts_info = vsc85xx_ts_info;
- phydev->mii_ts = &vsc8531->mii_ts;
+ return 0;
+}
- memcpy(&vsc8531->ptp->caps, &vsc85xx_clk_caps, sizeof(vsc85xx_clk_caps));
+static void __vsc8584_deinit_ptp(struct phy_device *phydev)
+{
+ struct vsc8531_private *vsc8531 = phydev->priv;
- vsc8531->ptp->ptp_clock = ptp_clock_register(&vsc8531->ptp->caps,
- &phydev->mdio.dev);
- return PTR_ERR_OR_ZERO(vsc8531->ptp->ptp_clock);
+ ptp_clock_unregister(vsc8531->ptp->ptp_clock);
+ skb_queue_purge(&vsc8531->rx_skbs_list);
}
void vsc8584_config_ts_intr(struct phy_device *phydev)
@@ -1552,6 +1549,18 @@ int vsc8584_ptp_init(struct phy_device *phydev)
return 0;
}
+void vsc8584_ptp_deinit(struct phy_device *phydev)
+{
+ switch (phydev->phy_id & phydev->drv->phy_id_mask) {
+ case PHY_ID_VSC8572:
+ case PHY_ID_VSC8574:
+ case PHY_ID_VSC8575:
+ case PHY_ID_VSC8582:
+ case PHY_ID_VSC8584:
+ return __vsc8584_deinit_ptp(phydev);
+ }
+}
+
irqreturn_t vsc8584_handle_ts_interrupt(struct phy_device *phydev)
{
struct vsc8531_private *priv = phydev->priv;
@@ -1612,7 +1621,16 @@ int vsc8584_ptp_probe(struct phy_device *phydev)
vsc8531->ptp->phydev = phydev;
- return 0;
+ vsc8531->mii_ts.rxtstamp = vsc85xx_rxtstamp;
+ vsc8531->mii_ts.txtstamp = vsc85xx_txtstamp;
+ vsc8531->mii_ts.hwtstamp = vsc85xx_hwtstamp;
+ vsc8531->mii_ts.ts_info = vsc85xx_ts_info;
+ phydev->mii_ts = &vsc8531->mii_ts;
+
+ memcpy(&vsc8531->ptp->caps, &vsc85xx_clk_caps, sizeof(vsc85xx_clk_caps));
+ vsc8531->ptp->ptp_clock = ptp_clock_register(&vsc8531->ptp->caps,
+ &phydev->mdio.dev);
+ return PTR_ERR_OR_ZERO(vsc8531->ptp->ptp_clock);
}
int vsc8584_ptp_probe_once(struct phy_device *phydev)
--
2.34.1
On 21/08/2025 11:46, Horatiu Vultur wrote:
> +static void __vsc8584_deinit_ptp(struct phy_device *phydev)
> +{
> + struct vsc8531_private *vsc8531 = phydev->priv;
>
> - vsc8531->ptp->ptp_clock = ptp_clock_register(&vsc8531->ptp->caps,
> - &phydev->mdio.dev);
> - return PTR_ERR_OR_ZERO(vsc8531->ptp->ptp_clock);
> + ptp_clock_unregister(vsc8531->ptp->ptp_clock);
> + skb_queue_purge(&vsc8531->rx_skbs_list);
> }
>
> void vsc8584_config_ts_intr(struct phy_device *phydev)
> @@ -1552,6 +1549,18 @@ int vsc8584_ptp_init(struct phy_device *phydev)
> return 0;
> }
>
> +void vsc8584_ptp_deinit(struct phy_device *phydev)
> +{
> + switch (phydev->phy_id & phydev->drv->phy_id_mask) {
> + case PHY_ID_VSC8572:
> + case PHY_ID_VSC8574:
> + case PHY_ID_VSC8575:
> + case PHY_ID_VSC8582:
> + case PHY_ID_VSC8584:
> + return __vsc8584_deinit_ptp(phydev);
void function has no return value. as well as it shouldn't return
anything. I'm not quite sure why do you need __vsc8584_deinit_ptp()
at all, I think everything can be coded inside vsc8584_ptp_deinit()
> + }
> +}
The 08/21/2025 14:50, Vadim Fedorenko wrote:
Hi Vadim,
>
> On 21/08/2025 11:46, Horatiu Vultur wrote:
> > +static void __vsc8584_deinit_ptp(struct phy_device *phydev)
> > +{
> > + struct vsc8531_private *vsc8531 = phydev->priv;
> >
> > - vsc8531->ptp->ptp_clock = ptp_clock_register(&vsc8531->ptp->caps,
> > - &phydev->mdio.dev);
> > - return PTR_ERR_OR_ZERO(vsc8531->ptp->ptp_clock);
> > + ptp_clock_unregister(vsc8531->ptp->ptp_clock);
> > + skb_queue_purge(&vsc8531->rx_skbs_list);
> > }
> >
> > void vsc8584_config_ts_intr(struct phy_device *phydev)
> > @@ -1552,6 +1549,18 @@ int vsc8584_ptp_init(struct phy_device *phydev)
> > return 0;
> > }
> >
> > +void vsc8584_ptp_deinit(struct phy_device *phydev)
> > +{
> > + switch (phydev->phy_id & phydev->drv->phy_id_mask) {
> > + case PHY_ID_VSC8572:
> > + case PHY_ID_VSC8574:
> > + case PHY_ID_VSC8575:
> > + case PHY_ID_VSC8582:
> > + case PHY_ID_VSC8584:
> > + return __vsc8584_deinit_ptp(phydev);
>
> void function has no return value. as well as it shouldn't return
> anything. I'm not quite sure why do you need __vsc8584_deinit_ptp()
> at all, I think everything can be coded inside vsc8584_ptp_deinit()
I understand, I can update not to return anything.
Regarding __vsc8584_deinit_ptp, I have created that function just to be
similar with the __vsc8584_init_ptp.
>
> > + }
> > +}
--
/Horatiu
On Fri, 22 Aug 2025 08:27:26 +0200 Horatiu Vultur wrote:
> > > +void vsc8584_ptp_deinit(struct phy_device *phydev)
> > > +{
> > > + switch (phydev->phy_id & phydev->drv->phy_id_mask) {
> > > + case PHY_ID_VSC8572:
> > > + case PHY_ID_VSC8574:
> > > + case PHY_ID_VSC8575:
> > > + case PHY_ID_VSC8582:
> > > + case PHY_ID_VSC8584:
> > > + return __vsc8584_deinit_ptp(phydev);
> >
> > void function has no return value. as well as it shouldn't return
> > anything. I'm not quite sure why do you need __vsc8584_deinit_ptp()
> > at all, I think everything can be coded inside vsc8584_ptp_deinit()
>
> I understand, I can update not to return anything.
It does look a little unnecessary.
> Regarding __vsc8584_deinit_ptp, I have created that function just to be
> similar with the __vsc8584_init_ptp.
Alternatively you could only deinit if the clock pointer is valid,
regardless of chip id. Unclear which one is the cleanest form, TBH.
The 08/22/2025 15:58, Jakub Kicinski wrote:
>
> On Fri, 22 Aug 2025 08:27:26 +0200 Horatiu Vultur wrote:
> > > > +void vsc8584_ptp_deinit(struct phy_device *phydev)
> > > > +{
> > > > + switch (phydev->phy_id & phydev->drv->phy_id_mask) {
> > > > + case PHY_ID_VSC8572:
> > > > + case PHY_ID_VSC8574:
> > > > + case PHY_ID_VSC8575:
> > > > + case PHY_ID_VSC8582:
> > > > + case PHY_ID_VSC8584:
> > > > + return __vsc8584_deinit_ptp(phydev);
> > >
> > > void function has no return value. as well as it shouldn't return
> > > anything. I'm not quite sure why do you need __vsc8584_deinit_ptp()
> > > at all, I think everything can be coded inside vsc8584_ptp_deinit()
> >
> > I understand, I can update not to return anything.
>
> It does look a little unnecessary.
>
> > Regarding __vsc8584_deinit_ptp, I have created that function just to be
> > similar with the __vsc8584_init_ptp.
>
> Alternatively you could only deinit if the clock pointer is valid,
> regardless of chip id. Unclear which one is the cleanest form, TBH.
I will update in the next version to check if the
vsc8531->ptp->ptp_clock is valid and in that case call
ptp_clock_unregister and skb_queue_purge.
--
/Horatiu
© 2016 - 2025 Red Hat, Inc.