[PATCH net-next 1/9] ptp: ocp: move the CPLD identification read off the sync worker
flat view
COLD28d
From: Sagi Maimon <hidden>
Date: 2026-09-22 14:28:38
Also in:
linux-doc, lkml
Subsystem:
networking drivers, opencompute ptp clock driver, ptp hardware clock support, the rest · Maintainers:
Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Vadim Fedorenko, Richard Cochran, Linus Torvalds
ptp_ocp_sync_work() samples the in-sync bit once a second and emits the
dpll change notification. Since the TAP CPLD support it also resolves the
i2c adapter and performs the one-shot CPLD identification read, and that
read can block for seconds: adva_x1_bus_claim() waits for the MicroBlaze
to grant the TMC segment for up to MBLAZE_RETRIES * MBLAZE_RETRY_US, and
the hand-back polls for the grant to drop for as long again.
While that runs the in-sync sampling and the dpll notification are delayed
by the same amount, and because ptp_ocp_remove() - which is also the
.shutdown handler - begins with cancel_delayed_work_sync(&bp->sync_work),
unbind and reboot block for it too.
Give the identification its own delayed work, queued from probe only on
boards that have the part and rescheduled only until the one-shot read is
settled, so a claim that has to wait no longer holds up anything else.
Fixes: 3b815e29966f ("ptp: ocp: add TAP CPLD access for ADVA TimeCard X1")
Signed-off-by: Sagi Maimon <redacted>
---
drivers/ptp/ptp_ocp.c | 39 ++++++++++++++++++++++++++++++---------
1 file changed, 30 insertions(+), 9 deletions(-)
diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 2802989e8494..4a58bcc14648 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c@@ -402,6 +402,8 @@ struct ptp_ocp { bool sync; time64_t gnss_lost; struct delayed_work sync_work; + /* CPLD identification, off the 1 Hz sync poller */ + struct delayed_work cpld_work; int id; int n_irqs; struct ptp_ocp_serial_port port[__PORT_COUNT];
@@ -5935,18 +5937,32 @@ ptp_ocp_sync_work(struct work_struct *work) bp->sync = sync; - /* Resolve the adapter here rather than once in probe, where it can - * race the adapter's own registration, and read the ID as soon as it - * turns up. A claim can fail transiently - the firmware may not - * grant the segment straight after power-up - so adva_x1_cpld_read_id() - * retries a bounded number of times before giving up. - */ + queue_delayed_work(system_power_efficient_wq, &bp->sync_work, HZ); +} + +/* + * Resolve the i2c adapter and read the CPLD identification. + * + * Kept off ptp_ocp_sync_work(): a claim can block for seconds - the + * MicroBlaze handshake polls for up to MBLAZE_RETRIES * MBLAZE_RETRY_US and + * the hand-back does the same - which would delay the in-sync sampling and + * the dpll change notification, and stall the cancel_delayed_work_sync() on + * the unbind and shutdown paths for as long. + * + * Reschedules only while there is something left to do, so a board without + * the part, or one whose identification is settled, costs nothing. + */ +static void ptp_ocp_cpld_work(struct work_struct *work) +{ + struct ptp_ocp *bp = container_of(work, struct ptp_ocp, cpld_work.work); + adva_x1_cache_i2c_adap(bp); - if (bp->has_cpld && !READ_ONCE(bp->cpld_id_tried) && - READ_ONCE(bp->cpld_i2c_adap_nr) >= 0) + if (READ_ONCE(bp->cpld_i2c_adap_nr) >= 0) adva_x1_cpld_read_id(bp); - queue_delayed_work(system_power_efficient_wq, &bp->sync_work, HZ); + if (!READ_ONCE(bp->cpld_id_tried)) + queue_delayed_work(system_power_efficient_wq, &bp->cpld_work, + HZ); } static int
@@ -5984,6 +6000,7 @@ ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id) bp->cpld_i2c_adap_nr = -1; INIT_DELAYED_WORK(&bp->sync_work, ptp_ocp_sync_work); + INIT_DELAYED_WORK(&bp->cpld_work, ptp_ocp_cpld_work); /* compat mode. * Older FPGA firmware only returns 2 irq's.
@@ -6046,6 +6063,9 @@ ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id) } } queue_delayed_work(system_power_efficient_wq, &bp->sync_work, HZ); + if (bp->has_cpld) + queue_delayed_work(system_power_efficient_wq, &bp->cpld_work, + HZ); return 0; out_dpll:
@@ -6080,6 +6100,7 @@ ptp_ocp_remove(struct pci_dev *pdev) int i; cancel_delayed_work_sync(&bp->sync_work); + cancel_delayed_work_sync(&bp->cpld_work); for (i = 0; i < OCP_SMA_NUM; i++) { if (bp->sma[i].dpll_pin) { dpll_pin_unregister(bp->dpll, bp->sma[i].dpll_pin, &dpll_pins_ops, &bp->sma[i]);
--
2.47.0