Thread (20 messages) flat view 20 messages, 2 authors, 1d ago

Re: [PATCH net-next v3 03/10] net: ethernet: ravb: Simplify gPTP start and stop

From: netdev-bot+sashiko@kernel.org
Date: 2026-09-07 02:48:33
Also in: linux-devicetree, linux-renesas-soc, lkml

Thank you for your contribution! Sashiko AI review found 2 potential
issue(s) to consider:

Critical: 0 · High: 2 · Medium: 0 · Low: 0

- [High] ravb_open() leaks the registered PTP clock for info->ccc_gac
  devices (R-Car Gen3/Gen4) when ravb_phy_start() fails.
- [High] Folding ravb_ptp_stop() into the tail of ravb_stop_dma()
  (ravb_main.c:1126-1128) makes gPTP teardown conditional on the AVB-…

--

net: ethernet: ravb: Simplify gPTP start and stop

This moves the info->gptp gPTP clock start and stop into ravb_dmac_init()
and ravb_stop_dma() so the gPTP clock follows the AVB-DMAC, and drops the
info->gptp part of the combined "gptp || ccc_gac" conditions in
ravb_open() and ravb_close().  The commit message states "There are no
functional change".  Two behaviour differences below look like they may
not hold up.
quoted hunk ↗ jump to hunk
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index a89f6fe7866fe..2d0022a4f85c3 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -707,7 +707,15 @@ static int ravb_dmac_init(struct net_device *ndev)
 		return error;
 
 	/* Setting the control will start the AVB-DMAC process. */
-	return ravb_set_opmode(ndev, CCC_OPC_OPERATION);
+	error = ravb_set_opmode(ndev, CCC_OPC_OPERATION);
+	if (error)
+		return error;
+
+	/* Initialise PTP Clock driver */
+	if (info->gptp)
+		ravb_ptp_init(ndev, priv->pdev);
+
+	return 0;
 }
 
 static void ravb_get_tx_tstamp(struct net_device *ndev)
@@ -1115,6 +1123,10 @@ static int ravb_stop_dma(struct net_device *ndev)
 			netdev_err(ndev, "failed to stop AXI BUS\n");
 	}
 
+	/* Stop PTP Clock driver */
+	if (info->gptp)
+		ravb_ptp_stop(ndev);
+
[Severity: High]

Is the gPTP stop still guaranteed to run for info->gptp parts?  Placing it
here puts it behind the three ravb_wait() timeouts earlier in
ravb_stop_dma():

	error = ravb_wait(ndev, TCCR, info->tccr_mask, 0);
	if (error)
		return error;

	error = ravb_wait(ndev, CSR, CSR_TPO0 | CSR_TPO1 | CSR_TPO2 | CSR_TPO3,
			  0);
	if (error)
		return error;
	...
	error = ravb_wait(ndev, CSR, CSR_RPO, 0);
	if (error)
		return error;

Before this patch every caller ran the stop unconditionally before
ravb_stop_dma(), so a wedged DMAC could not skip it.  Now ravb_close()
only logs the failure and keeps going:

	if (ravb_stop_dma(ndev) < 0)
		netdev_err(ndev,
			   "device will be stopped after h/w processes are done.\n");

so on a .gptp = 1 part (ravb_gen2_hw_info, ravb_rzv2m_hw_info) the PHC
stays registered across close.  A later open then goes
ravb_open() -> ravb_dmac_init() -> ravb_ptp_init(), which registers a
second clock and overwrites the pointer without checking:

	clock = ptp_clock_register(&priv->ptp.info, &pdev->dev);
	...
	WRITE_ONCE(priv->ptp.clock, clock);

Does that permanently orphan the first registration?  ravb_remove() does
no PTP teardown before free_netdev(), and the orphaned clock's
ptp_clock_info lives in the netdev private area, so its ops would point
at freed memory after unbind.

Skipping ravb_ptp_stop() on those early returns also skips the interrupt
quiescing it performs:

	ravb_ptp_disable(ndev);
	ravb_ptp_sync_irqs(ndev);

ravb_close() then walks and frees priv->ts_skb_list without priv->lock,
while ravb_timestamp_interrupt() -> ravb_get_tx_tstamp() can still be
doing list_del() on the same list.  Can that corrupt the list?

There is also the reverse ordering.  If ravb_stop_dma() fails only in its
final ravb_set_opmode(ndev, CCC_OPC_CONFIG), the ravb_ptp_stop() above has
already unregistered the clock, and ravb_tx_timeout_work() takes the
"goto out" path whose ravb_ptp_init() is removed by this patch (hunk
below), leaving a running interface with no PHC until an administrative
down/up.  Same question for ravb_set_ringparam(): its

		error = ravb_stop_dma(ndev);
		if (error) {
			netdev_err(ndev,
				   "cannot set ringparam! Any AVB processes are still running?\n");
			return error;
		}

now returns with the gPTP clock still registered where previously it had
been stopped first.
quoted hunk ↗ jump to hunk
 	/* Stop AVB-DMAC process */
 	return ravb_set_opmode(ndev, CCC_OPC_CONFIG);
 }
@@ -1719,9 +1731,7 @@ static int ravb_set_ringparam(struct net_device *ndev,
 
 	if (netif_running(ndev)) {
 		netif_device_detach(ndev);
-		/* Stop PTP Clock driver */
-		if (info->gptp)
-			ravb_ptp_stop(ndev);
+
 		/* Wait for DMA stopping */
 		error = ravb_stop_dma(ndev);
 		if (error) {
[ ... ]
quoted hunk ↗ jump to hunk
@@ -1961,7 +1967,7 @@ static int ravb_open(struct net_device *ndev)
 	ravb_emac_init(ndev);
 
 	/* Initialise PTP Clock driver */
-	if (info->gptp || info->ccc_gac)
+	if (info->ccc_gac)
 		ravb_ptp_init(ndev, priv->pdev);
 
 	/* PHY control start */
@@ -1974,9 +1980,6 @@ static int ravb_open(struct net_device *ndev)
 	return 0;
 
 out_ptp_stop:
-	/* Stop PTP Clock driver */
-	if (info->gptp || info->ccc_gac)
-		ravb_ptp_stop(ndev);
 	ravb_stop_dma(ndev);
[Severity: High]

Does this leak the registered PTP clock for info->ccc_gac parts?

ravb_open() still registers it just above:

	if (info->ccc_gac)
		ravb_ptp_init(ndev, priv->pdev);

and the next fallible step is ravb_phy_start(), which jumps here.  The
replacement stop folded into ravb_stop_dma() is gated on info->gptp, and
that flag is mutually exclusive with ccc_gac (ravb_gen2_hw_info and
ravb_rzv2m_hw_info set .gptp = 1, ravb_gen3_hw_info and ravb_gen4_hw_info
set .ccc_gac = 1), so nothing unregisters the clock on this path.

ravb_close() is the only remaining ccc_gac ravb_ptp_stop() site, and it is
not reached because ndo_open returned an error.  The device is then put in
CCC_OPC_RESET and runtime suspended while /dev/ptpN stays alive with
ptp_clock_info pointing into the netdev private area.  Each further
"ip link set ethX up" attempt registers another clock and orphans the
previous one via the WRITE_ONCE(priv->ptp.clock, clock) in
ravb_ptp_init(), and ravb_remove() frees the netdev without unregistering
anything.
 out_set_reset:
 	ravb_set_opmode(ndev, CCC_OPC_RESET);
[ ... ]
quoted hunk ↗ jump to hunk
@@ -2020,10 +2023,6 @@ static void ravb_tx_timeout_work(struct work_struct *work)
 
 	netif_tx_stop_all_queues(ndev);
 
-	/* Stop PTP Clock driver */
-	if (info->gptp)
-		ravb_ptp_stop(ndev);
-
 	/* Wait for DMA stopping */
 	if (ravb_stop_dma(ndev)) {
 		/* If ravb_stop_dma() fails, the hardware is still operating
[ ... ]
quoted hunk ↗ jump to hunk
@@ -2056,10 +2055,6 @@ static void ravb_tx_timeout_work(struct work_struct *work)
 	ravb_emac_init(ndev);
 
 out:
-	/* Initialise PTP Clock driver */
-	if (info->gptp)
-		ravb_ptp_init(ndev, priv->pdev);
-
 	netif_tx_start_all_queues(ndev);
 
 out_unlock:
@@ -2374,7 +2369,7 @@ static int ravb_close(struct net_device *ndev)
 	}
 
 	/* Stop PTP Clock driver */
-	if (info->gptp || info->ccc_gac)
+	if (info->ccc_gac)
 		ravb_ptp_stop(ndev);
 
 	/* Set the config mode to stop the AVB-DMAC's processes */
Both concerns come down to the same question: since ravb_stop_dma() can
return early, and its callers treat that failure differently, is the
folded start/stop still symmetric on every exit path, or would performing
the stop before the ravb_wait() loops (or leaving it at the call sites)
keep the previous behaviour?

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260902084703.3228504-1-niklas.soderlund%2Brenesas%40ragnatech.se
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help