RE: [PATCH net] ptp: netc: fix potential interrupt storm caused by incorrect unbind order
From: Wei Fang (OSS) <hidden>
Date: 2026-07-27 04:46:55
Also in:
imx, sashiko-reviews
quoted
diff --git a/drivers/ptp/ptp_netc.c b/drivers/ptp/ptp_netc.c index 5e381c354d746..3bab86afe8e23 100644 --- a/drivers/ptp/ptp_netc.c +++ b/drivers/ptp/ptp_netc.c@@ -1019,9 +1019,9 @@ static void netc_timer_remove(struct pci_dev*pdev)quoted
{ struct netc_timer *priv = pci_get_drvdata(pdev); + ptp_clock_unregister(priv->clock); + netc_timer_wr(priv, NETC_TMR_TEMASK, 0);[Severity: High] Does moving ptp_clock_unregister() before masking hardware interrupts introduce a use-after-free regression in the interrupt handler?
That is indeed a problem, I will fix it in next version.
If EXTTS events are configured, ptp_clock_unregister() drops the final device reference and frees priv->clock if no file descriptors are open. Because the hardware interrupt mask (NETC_TMR_TEMASK) is not cleared until the next instruction, and free_irq() has not yet been called, the hardware can still fire an EXTTS interrupt. If this occurs, the ISR netc_timer_isr() processes the event and unconditionally dereferences the freed clock object: netc_timer_isr() -> netc_timer_handle_etts_event() { ... ptp_clock_event(priv->clock, &event); ... }quoted
netc_timer_wr(priv, NETC_TMR_CTRL, 0); - ptp_clock_unregister(priv->clock); netc_timer_free_msix_irq(priv); netc_timer_pci_remove(pdev); }[Severity: High] This isn't a bug introduced by this patch, but can the driver encounter a hard lockup during probe on kexec or an unclean shutdown? Because the NETC timer does not support PCIe FLR, hardware registers retain their state. In netc_timer_probe(), the driver requests the IRQ via netc_timer_init_msix_irq() before resetting the hardware state. If the hardware has a pending interrupt, it fires immediately upon request_irq(). At this point, priv->tmr_emask is 0. The ISR netc_timer_isr() masks the hardware status with priv->tmr_emask and writes 0 back to the Write-1-to-Clear (W1C) register, failing to clear the pending hardware interrupt: netc_timer_isr() { ... tmr_event = netc_timer_rd(priv, NETC_TMR_TEVENT); tmr_event &= priv->tmr_emask; /* Clear interrupts status */ netc_timer_wr(priv, NETC_TMR_TEVENT, tmr_event); ... } The ISR then defeats the kernel's spurious interrupt detection by unconditionally returning IRQ_HANDLED, causing the interrupt controller to re-invoke the ISR in an infinite loop: netc_timer_isr() { ... return IRQ_HANDLED; } -- Sashiko AI review · https://sashiko.dev/#/patchset/20260724065116.521893-1-wei.fang@ oss.nxp.com?part=1