The kernel patch
If you take one thing from this site, take this.
--- a/drivers/pps/clients/pps-gpio.c+++ b/drivers/pps/clients/pps-gpio.c@@ -156,6 +156,13 @@ get_irqf_trigger_flags(const struct pps_gpio_device_data *data) IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING); }
+ /* The handler timestamps the pulse, so it has to run in hard-irq+ * context. Under PREEMPT_RT it would otherwise be force-threaded and+ * the timestamp taken after thread wakeup latency, adding microseconds+ * of jitter to an edge that should be good to nanoseconds.+ */+ flags |= IRQF_NO_THREAD;+ return flags; }What it does
Section titled “What it does”pps-gpio requests its interrupt with only the trigger flags — no
IRQF_NO_THREAD. On a stock kernel that’s fine, because handlers run in hard-IRQ
context anyway. Under PREEMPT_RT, the kernel force-threads it, and since
the handler is where the timestamp is taken,
the measurement moves behind the scheduler.
IRQF_NO_THREAD tells the kernel: not this one. The handler stays in hard-IRQ
context; everything else keeps RT’s preemptibility.
What it’s worth
Section titled “What it’s worth”| RMS offset | raw PPS jitter | |
|---|---|---|
| PREEMPT_RT, unpatched | 2468 ns | 6947 ns |
| PREEMPT_RT, patched | 199 ns | 2568 ns |
Why you probably need it
Section titled “Why you probably need it”As far as we can tell this is not applied anywhere. Which means every person running GPIO-based PPS on a PREEMPT_RT kernel is, right now, silently eating microseconds of jitter — and has no reason to suspect it, because nothing looks broken. chrony still reports Stratum 1. The dashboard still says locked. The number is just quietly, invisibly worse.
If that’s you, this patch is free accuracy.
How to apply it
Section titled “How to apply it”See Patch pps-gpio — it’s a module, so you can rebuild
just the one .ko in about a minute rather than the whole kernel.