* [PATCH net v4 0/2] net: ravb: fix PTP clock lifetime
@ 2026-08-11 10:37 Xuanqiang Luo
2026-08-11 10:37 ` [PATCH net v4 1/2] net: ravb: avoid dereferencing an invalid PTP clock Xuanqiang Luo
2026-08-11 10:37 ` [PATCH net v4 2/2] net: ravb: serialize PTP clock teardown Xuanqiang Luo
0 siblings, 2 replies; 3+ messages in thread
From: Xuanqiang Luo @ 2026-08-11 10:37 UTC (permalink / raw)
To: linux-renesas-soc, netdev, niklas.soderlund, kuba,
vadim.fedorenko
Cc: paul, andrew+netdev, davem, edumazet, pabeni, richardcochran,
masaru.nagai.vx, luoxuanqiang
From: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
This series fixes RAVB PTP clock lifetime handling. It reports a cached PHC
index without accessing the clock pointer and drains PTP interrupts before
unregistering the clock.
Patch 1 caches the PHC index and handles registration failures.
Patch 2 detaches the clock with xchg() and drains the PTP IRQs before
unregistering it.
---
Changes:
v4:
- Rebase onto Linux 7.2-rc7.
Patch 1:
- Cache the PHC index separately instead of locking clock access.
(Vadim Fedorenko)
- Reword the subject and update the commit message for the cached PHC
index approach.
- Add Vadim Fedorenko's Reviewed-by tag.
Patch 2:
- Replace priv->lock serialization with PTP interrupt disabling and IRQ
draining before unregistering the clock. (Vadim Fedorenko)
- Use READ_ONCE() and WRITE_ONCE() for lockless clock pointer access and
xchg() to detach the clock atomically.
- Track the error and management IRQs and synchronize all IRQs that can
invoke the PTP handler.
- Update the commit message to describe the interrupt handler race and
the new teardown sequence.
v3: https://lore.kernel.org/all/20260806095126.57803-1-xuanqiang.luo@linux.dev/
Patch 1:
- Omit Niklas Söderlund's Reviewed-by tag because the implementation he
reviewed has changed.
- Describe the NULL pointer dereference before the first open as the most
likely failure mode in the commit message. (Jakub Kicinski, Sashiko)
- Normalize PTP clock registration failures to NULL.
(Jakub Kicinski, Sashiko)
- Keep hardware timestamping capabilities independent of PHC
availability. (Jakub Kicinski, Sashiko)
Patch 2 (new):
- Serialize PTP clock publication and access with priv->lock, and detach
the clock before unregistering it. (Jakub Kicinski, Sashiko)
v2: https://lore.kernel.org/all/20260802090750.116215-1-xuanqiang.luo@linux.dev/
- Only advertise hardware timestamping support when a PHC is available
(Niklas Söderlund).
v1: https://lore.kernel.org/all/20260731063254.71260-1-xuanqiang.luo@linux.dev/
Xuanqiang Luo (2):
net: ravb: avoid dereferencing an invalid PTP clock
net: ravb: serialize PTP clock teardown
drivers/net/ethernet/renesas/ravb.h | 3 ++
drivers/net/ethernet/renesas/ravb_main.c | 9 +++--
drivers/net/ethernet/renesas/ravb_ptp.c | 44 ++++++++++++++++++++----
3 files changed, 47 insertions(+), 9 deletions(-)
base-commit: db2ddb87143519e20a95aa36c60b36107b736a58
--
2.43.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH net v4 1/2] net: ravb: avoid dereferencing an invalid PTP clock
2026-08-11 10:37 [PATCH net v4 0/2] net: ravb: fix PTP clock lifetime Xuanqiang Luo
@ 2026-08-11 10:37 ` Xuanqiang Luo
2026-08-11 10:37 ` [PATCH net v4 2/2] net: ravb: serialize PTP clock teardown Xuanqiang Luo
1 sibling, 0 replies; 3+ messages in thread
From: Xuanqiang Luo @ 2026-08-11 10:37 UTC (permalink / raw)
To: linux-renesas-soc, netdev, niklas.soderlund, kuba,
vadim.fedorenko
Cc: paul, andrew+netdev, davem, edumazet, pabeni, richardcochran,
masaru.nagai.vx, luoxuanqiang, stable
From: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
The PTP clock is unavailable before the first open, so querying its
index can dereference a NULL pointer. Registration failures can also
leave an error pointer in priv->ptp.clock.
Cache the PHC index separately and report -1 while no clock is
registered. Normalize registration errors to NULL and preserve the
static timestamping capabilities.
Fixes: a0d2f20650e8 ("Renesas Ethernet AVB PTP clock driver")
Cc: stable@vger.kernel.org
Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
Signed-off-by: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
---
drivers/net/ethernet/renesas/ravb.h | 1 +
drivers/net/ethernet/renesas/ravb_main.c | 3 ++-
drivers/net/ethernet/renesas/ravb_ptp.c | 15 +++++++++++++--
3 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h
index 5e56ec9b1013a..2a4fcb12a63cb 100644
--- a/drivers/net/ethernet/renesas/ravb.h
+++ b/drivers/net/ethernet/renesas/ravb.h
@@ -1028,6 +1028,7 @@ struct ravb_ptp_perout {
struct ravb_ptp {
struct ptp_clock *clock;
struct ptp_clock_info info;
+ int phc_index;
u32 default_addend;
u32 current_addend;
int extts[N_EXT_TS];
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 5f88733094d0f..db0229e008494 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -1779,7 +1779,7 @@ static int ravb_get_ts_info(struct net_device *ndev,
(1 << HWTSTAMP_FILTER_NONE) |
(1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
(1 << HWTSTAMP_FILTER_ALL);
- info->phc_index = ptp_clock_index(priv->ptp.clock);
+ info->phc_index = READ_ONCE(priv->ptp.phc_index);
}
return 0;
@@ -2953,6 +2953,7 @@ static int ravb_probe(struct platform_device *pdev)
priv->rstc = rstc;
priv->ndev = ndev;
priv->pdev = pdev;
+ priv->ptp.phc_index = -1;
priv->num_tx_ring[RAVB_BE] = BE_TX_RING_SIZE;
priv->num_rx_ring[RAVB_BE] = BE_RX_RING_SIZE;
if (info->nc_queues) {
diff --git a/drivers/net/ethernet/renesas/ravb_ptp.c b/drivers/net/ethernet/renesas/ravb_ptp.c
index 226c6c0ab945b..cbec7c057d715 100644
--- a/drivers/net/ethernet/renesas/ravb_ptp.c
+++ b/drivers/net/ethernet/renesas/ravb_ptp.c
@@ -315,6 +315,7 @@ void ravb_ptp_interrupt(struct net_device *ndev)
void ravb_ptp_init(struct net_device *ndev, struct platform_device *pdev)
{
struct ravb_private *priv = netdev_priv(ndev);
+ struct ptp_clock *clock;
unsigned long flags;
priv->ptp.info = ravb_ptp_info;
@@ -327,7 +328,15 @@ void ravb_ptp_init(struct net_device *ndev, struct platform_device *pdev)
ravb_modify(ndev, GCCR, GCCR_TCSS, GCCR_TCSS_ADJGPTP);
spin_unlock_irqrestore(&priv->lock, flags);
- priv->ptp.clock = ptp_clock_register(&priv->ptp.info, &pdev->dev);
+ clock = ptp_clock_register(&priv->ptp.info, &pdev->dev);
+ if (IS_ERR(clock)) {
+ netdev_err(ndev, "failed to register PTP clock: %pe\n", clock);
+ clock = NULL;
+ }
+
+ priv->ptp.clock = clock;
+ if (clock)
+ WRITE_ONCE(priv->ptp.phc_index, ptp_clock_index(clock));
}
void ravb_ptp_stop(struct net_device *ndev)
@@ -337,5 +346,7 @@ void ravb_ptp_stop(struct net_device *ndev)
ravb_write(ndev, 0, GIC);
ravb_write(ndev, 0, GIS);
- ptp_clock_unregister(priv->ptp.clock);
+ WRITE_ONCE(priv->ptp.phc_index, -1);
+ if (priv->ptp.clock)
+ ptp_clock_unregister(priv->ptp.clock);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH net v4 2/2] net: ravb: serialize PTP clock teardown
2026-08-11 10:37 [PATCH net v4 0/2] net: ravb: fix PTP clock lifetime Xuanqiang Luo
2026-08-11 10:37 ` [PATCH net v4 1/2] net: ravb: avoid dereferencing an invalid PTP clock Xuanqiang Luo
@ 2026-08-11 10:37 ` Xuanqiang Luo
1 sibling, 0 replies; 3+ messages in thread
From: Xuanqiang Luo @ 2026-08-11 10:37 UTC (permalink / raw)
To: linux-renesas-soc, netdev, niklas.soderlund, kuba,
vadim.fedorenko
Cc: paul, andrew+netdev, davem, edumazet, pabeni, richardcochran,
masaru.nagai.vx, luoxuanqiang, stable
From: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
ravb_ptp_interrupt() can race with ravb_ptp_stop() and pass the clock to
ptp_clock_event() while ptp_clock_unregister() is freeing it. This can
lead to a use-after-free.
Use READ_ONCE() and WRITE_ONCE() for lockless access to the clock pointer.
Atomically detach it with xchg() before disabling PTP interrupts, then
synchronize all IRQs which can invoke ravb_ptp_interrupt() before
unregistering the detached clock.
A handler which read the old pointer completes before the clock is
unregistered, while later handlers read NULL and skip the event.
Fixes: a0d2f20650e8 ("Renesas Ethernet AVB PTP clock driver")
Cc: stable@vger.kernel.org
Signed-off-by: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
---
drivers/net/ethernet/renesas/ravb.h | 2 ++
drivers/net/ethernet/renesas/ravb_main.c | 6 ++--
drivers/net/ethernet/renesas/ravb_ptp.c | 37 +++++++++++++++++++-----
3 files changed, 35 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h
index 2a4fcb12a63cb..3ee4c61081890 100644
--- a/drivers/net/ethernet/renesas/ravb.h
+++ b/drivers/net/ethernet/renesas/ravb.h
@@ -1124,6 +1124,8 @@ struct ravb_private {
int msg_enable;
int speed;
int emac_irq;
+ int err_irq;
+ int mgmt_irq;
unsigned no_avb_link:1;
unsigned avb_link_active_low:1;
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index db0229e008494..ea1c7e536791e 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -2885,11 +2885,13 @@ static int ravb_setup_irqs(struct ravb_private *priv)
return error;
if (info->err_mgmt_irqs) {
- error = ravb_setup_irq(priv, "err_a", "err_a", NULL, ravb_multi_interrupt);
+ error = ravb_setup_irq(priv, "err_a", "err_a", &priv->err_irq,
+ ravb_multi_interrupt);
if (error)
return error;
- error = ravb_setup_irq(priv, "mgmt_a", "mgmt_a", NULL, ravb_multi_interrupt);
+ error = ravb_setup_irq(priv, "mgmt_a", "mgmt_a", &priv->mgmt_irq,
+ ravb_multi_interrupt);
if (error)
return error;
}
diff --git a/drivers/net/ethernet/renesas/ravb_ptp.c b/drivers/net/ethernet/renesas/ravb_ptp.c
index cbec7c057d715..43218bc15b151 100644
--- a/drivers/net/ethernet/renesas/ravb_ptp.c
+++ b/drivers/net/ethernet/renesas/ravb_ptp.c
@@ -289,16 +289,17 @@ static const struct ptp_clock_info ravb_ptp_info = {
void ravb_ptp_interrupt(struct net_device *ndev)
{
struct ravb_private *priv = netdev_priv(ndev);
+ struct ptp_clock *clock = READ_ONCE(priv->ptp.clock);
u32 gis = ravb_read(ndev, GIS);
gis &= ravb_read(ndev, GIC);
- if (gis & GIS_PTCF) {
+ if ((gis & GIS_PTCF) && clock) {
struct ptp_clock_event event;
event.type = PTP_CLOCK_EXTTS;
event.index = 0;
event.timestamp = ravb_read(ndev, GCPT);
- ptp_clock_event(priv->ptp.clock, &event);
+ ptp_clock_event(clock, &event);
}
if (gis & GIS_PTMF) {
struct ravb_ptp_perout *perout = priv->ptp.perout;
@@ -334,19 +335,39 @@ void ravb_ptp_init(struct net_device *ndev, struct platform_device *pdev)
clock = NULL;
}
- priv->ptp.clock = clock;
+ WRITE_ONCE(priv->ptp.clock, clock);
if (clock)
WRITE_ONCE(priv->ptp.phc_index, ptp_clock_index(clock));
}
-void ravb_ptp_stop(struct net_device *ndev)
+static void ravb_ptp_disable(struct net_device *ndev)
{
- struct ravb_private *priv = netdev_priv(ndev);
-
ravb_write(ndev, 0, GIC);
ravb_write(ndev, 0, GIS);
+}
+
+static void ravb_ptp_sync_irqs(struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+
+ synchronize_irq(ndev->irq);
+ if (priv->info->err_mgmt_irqs) {
+ synchronize_irq(priv->err_irq);
+ synchronize_irq(priv->mgmt_irq);
+ }
+}
+
+void ravb_ptp_stop(struct net_device *ndev)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ struct ptp_clock *clock;
WRITE_ONCE(priv->ptp.phc_index, -1);
- if (priv->ptp.clock)
- ptp_clock_unregister(priv->ptp.clock);
+ clock = xchg(&priv->ptp.clock, NULL);
+
+ ravb_ptp_disable(ndev);
+ ravb_ptp_sync_irqs(ndev);
+
+ if (clock)
+ ptp_clock_unregister(clock);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-08-11 10:39 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-11 10:37 [PATCH net v4 0/2] net: ravb: fix PTP clock lifetime Xuanqiang Luo
2026-08-11 10:37 ` [PATCH net v4 1/2] net: ravb: avoid dereferencing an invalid PTP clock Xuanqiang Luo
2026-08-11 10:37 ` [PATCH net v4 2/2] net: ravb: serialize PTP clock teardown Xuanqiang Luo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox