]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ptp: ocp: fix resource freeing order
authorVadim Fedorenko <vadim.fedorenko@linux.dev>
Mon, 8 Jun 2026 15:59:52 +0000 (15:59 +0000)
committerJakub Kicinski <kuba@kernel.org>
Wed, 10 Jun 2026 02:26:56 +0000 (19:26 -0700)
Commit a60fc3294a37 ("ptp: rework ptp_clock_unregister() to disable
events") added a call to ptp_disable_all_events() which changes the
configuration of pins if they support EXTTS events. In ptp_ocp_detach()
pins resources are freed before ptp_clock_unregister() and it leads to
use-after-free during driver removal. Fix it by changing the order of
free/unregister calls. To avoid irq handler running on the other core
while ptp device unregistering, call synchronize_irq() after HW is
configured to stop producing irqs and no irqs are in-flight.

Fixes: a60fc3294a37 ("ptp: rework ptp_clock_unregister() to disable events")
Signed-off-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
Link: https://patch.msgid.link/20260608155952.240304-1-vadim.fedorenko@linux.dev
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/ptp/ptp_ocp.c

index beacc2ffb166b315df7559952f1d3a012b9fc958..735385539b9f88044cfabe4c881f89933b3e7219 100644 (file)
@@ -2479,8 +2479,13 @@ ptp_ocp_ts_enable(void *priv, u32 req, bool enable)
                iowrite32(1, &reg->intr_mask);
                iowrite32(1, &reg->intr);
        } else {
+               int irq_vec = pci_irq_vector(bp->pdev, ext->irq_vec);
+
                iowrite32(0, &reg->intr_mask);
                iowrite32(0, &reg->enable);
+               ioread32(&reg->intr_mask);
+               if (irq_vec > 0)
+                       synchronize_irq(irq_vec);
        }
 
        return 0;
@@ -4867,6 +4872,22 @@ ptp_ocp_detach(struct ptp_ocp *bp)
        ptp_ocp_detach_sysfs(bp);
        ptp_ocp_attr_group_del(bp);
        timer_delete_sync(&bp->watchdog);
+       /* Disable interrupts on all timestampers */
+       if (bp->ts0)
+               ptp_ocp_ts_enable(bp->ts0, 0, false);
+       if (bp->ts1)
+               ptp_ocp_ts_enable(bp->ts1, 0, false);
+       if (bp->ts2)
+               ptp_ocp_ts_enable(bp->ts2, 0, false);
+       if (bp->ts3)
+               ptp_ocp_ts_enable(bp->ts3, 0, false);
+       if (bp->ts4)
+               ptp_ocp_ts_enable(bp->ts4, 0, false);
+       if (bp->pps)
+               ptp_ocp_ts_enable(bp->pps, ~0, false);
+       if (bp->ptp)
+               ptp_clock_unregister(bp->ptp);
+       kfree(bp->ptp_info.pin_config);
        ptp_ocp_unregister_ext(bp->ts0);
        ptp_ocp_unregister_ext(bp->ts1);
        ptp_ocp_unregister_ext(bp->ts2);
@@ -4884,9 +4905,6 @@ ptp_ocp_detach(struct ptp_ocp *bp)
                clk_hw_unregister_fixed_rate(bp->i2c_clk);
        if (bp->n_irqs)
                pci_free_irq_vectors(bp->pdev);
-       if (bp->ptp)
-               ptp_clock_unregister(bp->ptp);
-       kfree(bp->ptp_info.pin_config);
        device_unregister(&bp->dev);
 }