From: Vadim Fedorenko Date: Mon, 8 Jun 2026 15:59:52 +0000 (+0000) Subject: ptp: ocp: fix resource freeing order X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=627366c51145a07f675b1800fb5ea2ec960bd900;p=thirdparty%2Flinux.git ptp: ocp: fix resource freeing order 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 Link: https://patch.msgid.link/20260608155952.240304-1-vadim.fedorenko@linux.dev Signed-off-by: Jakub Kicinski --- diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index beacc2ffb166..735385539b9f 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -2479,8 +2479,13 @@ ptp_ocp_ts_enable(void *priv, u32 req, bool enable) iowrite32(1, ®->intr_mask); iowrite32(1, ®->intr); } else { + int irq_vec = pci_irq_vector(bp->pdev, ext->irq_vec); + iowrite32(0, ®->intr_mask); iowrite32(0, ®->enable); + ioread32(®->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); }