Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ptp_qoriq: fix latency in ptp_qoriq_adjtime() operation

1588 driver loses about 1us in adjtime operation at PTP slave
This is because adjtime operation uses a slow non-atomic tmr_cnt_read()
followed by tmr_cnt_write() operation.

In the above sequence, since the timer counter operation keeps
incrementing, it leads to latency. The tmr_offset register
(which is added to TMR_CNT_H/L register giving the current time)
must be programmed with the delta nanoseconds.

Signed-off-by: Nikhil Gupta <nikhil.gupta@nxp.com>
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Tested-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Link: https://lore.kernel.org/r/20230119204034.7969-1-nikhil.gupta@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Nikhil Gupta and committed by
Jakub Kicinski
24a7fffb 5e64f59a

+44 -7
+43 -7
drivers/ptp/ptp_qoriq.c
··· 48 48 ptp_qoriq->write(&regs->ctrl_regs->tmr_cnt_h, hi); 49 49 } 50 50 51 + static u64 tmr_offset_read(struct ptp_qoriq *ptp_qoriq) 52 + { 53 + struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; 54 + u32 lo, hi; 55 + u64 ns; 56 + 57 + lo = ptp_qoriq->read(&regs->ctrl_regs->tmroff_l); 58 + hi = ptp_qoriq->read(&regs->ctrl_regs->tmroff_h); 59 + ns = ((u64) hi) << 32; 60 + ns |= lo; 61 + return ns; 62 + } 63 + 64 + static void tmr_offset_write(struct ptp_qoriq *ptp_qoriq, u64 delta_ns) 65 + { 66 + struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; 67 + u32 lo = delta_ns & 0xffffffff; 68 + u32 hi = delta_ns >> 32; 69 + 70 + ptp_qoriq->write(&regs->ctrl_regs->tmroff_l, lo); 71 + ptp_qoriq->write(&regs->ctrl_regs->tmroff_h, hi); 72 + } 73 + 51 74 /* Caller must hold ptp_qoriq->lock. */ 52 75 static void set_alarm(struct ptp_qoriq *ptp_qoriq) 53 76 { ··· 78 55 u64 ns; 79 56 u32 lo, hi; 80 57 81 - ns = tmr_cnt_read(ptp_qoriq) + 1500000000ULL; 58 + ns = tmr_cnt_read(ptp_qoriq) + tmr_offset_read(ptp_qoriq) 59 + + 1500000000ULL; 60 + 82 61 ns = div_u64(ns, 1000000000UL) * 1000000000ULL; 83 62 ns -= ptp_qoriq->tclk_period; 84 63 hi = ns >> 32; ··· 232 207 233 208 int ptp_qoriq_adjtime(struct ptp_clock_info *ptp, s64 delta) 234 209 { 235 - s64 now; 236 - unsigned long flags; 237 210 struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps); 211 + s64 now, curr_delta; 212 + unsigned long flags; 238 213 239 214 spin_lock_irqsave(&ptp_qoriq->lock, flags); 240 215 241 - now = tmr_cnt_read(ptp_qoriq); 242 - now += delta; 243 - tmr_cnt_write(ptp_qoriq, now); 216 + /* On LS1021A, eTSEC2 and eTSEC3 do not take into account the TMR_OFF 217 + * adjustment 218 + */ 219 + if (ptp_qoriq->etsec) { 220 + now = tmr_cnt_read(ptp_qoriq); 221 + now += delta; 222 + tmr_cnt_write(ptp_qoriq, now); 223 + } else { 224 + curr_delta = tmr_offset_read(ptp_qoriq); 225 + curr_delta += delta; 226 + tmr_offset_write(ptp_qoriq, curr_delta); 227 + } 244 228 set_fipers(ptp_qoriq); 245 229 246 230 spin_unlock_irqrestore(&ptp_qoriq->lock, flags); ··· 266 232 267 233 spin_lock_irqsave(&ptp_qoriq->lock, flags); 268 234 269 - ns = tmr_cnt_read(ptp_qoriq); 235 + ns = tmr_cnt_read(ptp_qoriq) + tmr_offset_read(ptp_qoriq); 270 236 271 237 spin_unlock_irqrestore(&ptp_qoriq->lock, flags); 272 238 ··· 287 253 288 254 spin_lock_irqsave(&ptp_qoriq->lock, flags); 289 255 256 + tmr_offset_write(ptp_qoriq, 0); 290 257 tmr_cnt_write(ptp_qoriq, ns); 291 258 set_fipers(ptp_qoriq); 292 259 ··· 523 488 524 489 /* The eTSEC uses differnt memory map with DPAA/ENETC */ 525 490 if (of_device_is_compatible(node, "fsl,etsec-ptp")) { 491 + ptp_qoriq->etsec = true; 526 492 ptp_qoriq->regs.ctrl_regs = base + ETSEC_CTRL_REGS_OFFSET; 527 493 ptp_qoriq->regs.alarm_regs = base + ETSEC_ALARM_REGS_OFFSET; 528 494 ptp_qoriq->regs.fiper_regs = base + ETSEC_FIPER_REGS_OFFSET;
+1
include/linux/fsl/ptp_qoriq.h
··· 149 149 struct device *dev; 150 150 bool extts_fifo_support; 151 151 bool fiper3_support; 152 + bool etsec; 152 153 int irq; 153 154 int phc_index; 154 155 u32 tclk_period; /* nanoseconds */