[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250731121920.2358292-1-horatiu.vultur@microchip.com>
Date: Thu, 31 Jul 2025 14:19:20 +0200
From: Horatiu Vultur <horatiu.vultur@...rochip.com>
To: <andrew@...n.ch>, <hkallweit1@...il.com>, <linux@...linux.org.uk>,
<davem@...emloft.net>, <edumazet@...gle.com>, <kuba@...nel.org>,
<pabeni@...hat.com>, <richardcochran@...il.com>, <viro@...iv.linux.org.uk>,
<quentin.schulz@...tlin.com>, <atenart@...nel.org>
CC: <netdev@...r.kernel.org>, <linux-kernel@...r.kernel.org>, Horatiu Vultur
<horatiu.vultur@...rochip.com>
Subject: [PATCH net] phy: mscc: Fix timestamping for vsc8584
There was a problem when we received frames and the frames were
timestamped. The driver is configured to store the nanosecond part of
the timestmap in the ptp reserved bits and it would take the second part
by reading the LTC. The problem is that when reading the LTC we are in
atomic context and to read the second part will go over mdio bus which
might sleep, so we get an error.
The fix consists in actually put all the frames in a queue and start the
aux work and in that work to read the LTC and then calculate the full
received time.
Fixes: 7d272e63e0979d ("net: phy: mscc: timestamping and PHC support")
Signed-off-by: Horatiu Vultur <horatiu.vultur@...rochip.com>
---
drivers/net/phy/mscc/mscc.h | 11 ++++++
drivers/net/phy/mscc/mscc_ptp.c | 66 +++++++++++++++++++++++++++------
2 files changed, 65 insertions(+), 12 deletions(-)
diff --git a/drivers/net/phy/mscc/mscc.h b/drivers/net/phy/mscc/mscc.h
index 6a3d8a754eb8d..7281eea2395bd 100644
--- a/drivers/net/phy/mscc/mscc.h
+++ b/drivers/net/phy/mscc/mscc.h
@@ -362,6 +362,13 @@ struct vsc85xx_hw_stat {
u16 mask;
};
+struct vsc8531_skb {
+ struct list_head list;
+
+ struct sk_buff *skb;
+ u32 ns;
+};
+
struct vsc8531_private {
int rate_magic;
u16 supp_led_modes;
@@ -410,6 +417,10 @@ struct vsc8531_private {
*/
struct mutex ts_lock;
struct mutex phc_lock;
+
+ /* rx_skbs_lock: used for accessing rx_skbs_list */
+ spinlock_t rx_skbs_lock;
+ struct list_head rx_skbs_list;
};
/* Shared structure between the PHYs of the same package.
diff --git a/drivers/net/phy/mscc/mscc_ptp.c b/drivers/net/phy/mscc/mscc_ptp.c
index 275706de5847c..654add1748df3 100644
--- a/drivers/net/phy/mscc/mscc_ptp.c
+++ b/drivers/net/phy/mscc/mscc_ptp.c
@@ -1194,9 +1194,10 @@ static bool vsc85xx_rxtstamp(struct mii_timestamper *mii_ts,
{
struct vsc8531_private *vsc8531 =
container_of(mii_ts, struct vsc8531_private, mii_ts);
- struct skb_shared_hwtstamps *shhwtstamps = NULL;
+
struct vsc85xx_ptphdr *ptphdr;
- struct timespec64 ts;
+ struct vsc8531_skb *rx_skb;
+ unsigned long flags;
unsigned long ns;
if (!vsc8531->ptp->configured)
@@ -1206,27 +1207,65 @@ static bool vsc85xx_rxtstamp(struct mii_timestamper *mii_ts,
type == PTP_CLASS_NONE)
return false;
- vsc85xx_gettime(&vsc8531->ptp->caps, &ts);
-
ptphdr = get_ptp_header_rx(skb, vsc8531->ptp->rx_filter);
if (!ptphdr)
return false;
- shhwtstamps = skb_hwtstamps(skb);
- memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps));
-
ns = ntohl(ptphdr->rsrvd2);
- /* nsec is in reserved field */
- if (ts.tv_nsec < ns)
- ts.tv_sec--;
+ rx_skb = kmalloc(sizeof(*rx_skb), GFP_ATOMIC);
+ if (!rx_skb)
+ return false;
+
+ rx_skb->skb = skb;
+ rx_skb->ns = ns;
+ spin_lock_irqsave(&vsc8531->rx_skbs_lock, flags);
+ list_add(&rx_skb->list, &vsc8531->rx_skbs_list);
+ spin_unlock_irqrestore(&vsc8531->rx_skbs_lock, flags);
- shhwtstamps->hwtstamp = ktime_set(ts.tv_sec, ns);
- netif_rx(skb);
+ ptp_schedule_worker(vsc8531->ptp->ptp_clock, 0);
return true;
}
+static long vsc85xx_do_aux_work(struct ptp_clock_info *info)
+{
+ struct vsc85xx_ptp *ptp = container_of(info, struct vsc85xx_ptp, caps);
+ struct skb_shared_hwtstamps *shhwtstamps = NULL;
+ struct phy_device *phydev = ptp->phydev;
+ struct vsc8531_private *priv = phydev->priv;
+ struct vsc8531_skb *rx_skb, *tmp;
+ struct timespec64 ts;
+ unsigned long flags;
+ struct list_head skbs;
+
+ INIT_LIST_HEAD(&skbs);
+
+ vsc85xx_gettime(info, &ts);
+ spin_lock_irqsave(&priv->rx_skbs_lock, flags);
+ list_for_each_entry_safe(rx_skb, tmp, &priv->rx_skbs_list, list) {
+ shhwtstamps = skb_hwtstamps(rx_skb->skb);
+ memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps));
+
+ if (ts.tv_nsec < rx_skb->ns)
+ ts.tv_sec--;
+
+ shhwtstamps->hwtstamp = ktime_set(ts.tv_sec, rx_skb->ns);
+
+ list_del(&rx_skb->list);
+ list_add(&rx_skb->list, &skbs);
+ }
+ spin_unlock_irqrestore(&priv->rx_skbs_lock, flags);
+
+ list_for_each_entry_safe(rx_skb, tmp, &skbs, list) {
+ netif_rx(rx_skb->skb);
+ list_del(&rx_skb->list);
+ kfree(rx_skb);
+ }
+
+ return -1;
+}
+
static const struct ptp_clock_info vsc85xx_clk_caps = {
.owner = THIS_MODULE,
.name = "VSC85xx timer",
@@ -1240,6 +1279,7 @@ static const struct ptp_clock_info vsc85xx_clk_caps = {
.adjfine = &vsc85xx_adjfine,
.gettime64 = &vsc85xx_gettime,
.settime64 = &vsc85xx_settime,
+ .do_aux_work = &vsc85xx_do_aux_work,
};
static struct vsc8531_private *vsc8584_base_priv(struct phy_device *phydev)
@@ -1567,6 +1607,8 @@ int vsc8584_ptp_probe(struct phy_device *phydev)
mutex_init(&vsc8531->phc_lock);
mutex_init(&vsc8531->ts_lock);
+ spin_lock_init(&vsc8531->rx_skbs_lock);
+ INIT_LIST_HEAD(&vsc8531->rx_skbs_list);
/* Retrieve the shared load/save GPIO. Request it as non exclusive as
* the same GPIO can be requested by all the PHYs of the same package.
--
2.34.1
Powered by blists - more mailing lists