Skip to content

Patch pps-gpio for PREEMPT_RT

Do this if: you run PPS from a GPIO pin on a PREEMPT_RT kernel. Which is to say — do this if you followed any realtime-kernel time-server guide. Why.

You do not need to rebuild the whole kernel. pps-gpio is a module.

Terminal window
$ uname -a | grep -o PREEMPT_RT
PREEMPT_RT
$ ps -eo pid,class,rtprio,psr,comm | grep irq/.*pps
239 RR 50 3 irq/41-pps@12.-1 ← the handler is a thread. That's the bug.

If that ps prints nothing, your handler is already in hard-IRQ context and you have nothing to fix.

In your kernel source tree, drivers/pps/clients/pps-gpio.c, in get_irqf_trigger_flags(), just before the return:

/* 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;
Terminal window
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- \
M=drivers/pps/clients modules

About a minute, versus ~40 for a full kernel.

Terminal window
scp drivers/pps/clients/pps-gpio.ko pi@host:/tmp/
ssh pi@host 'sudo install -m644 /tmp/pps-gpio.ko \
/lib/modules/$(uname -r)/kernel/drivers/pps/clients/pps-gpio.ko && \
sudo depmod -a && sudo reboot'
Terminal window
$ ps -eo pid,class,rtprio,psr,comm | grep irq/.*pps
(nothing — back in hard-irq context)

Then measure it. You should see roughly a 3× improvement in raw PPS jitter, and about a 10× improvement in chrony’s RMS offset.