diff --git a/docs-site/astro.config.mjs b/docs-site/astro.config.mjs index 4424090..5732dc2 100644 --- a/docs-site/astro.config.mjs +++ b/docs-site/astro.config.mjs @@ -40,7 +40,7 @@ export default defineConfig({ description: "What the Raspberry Pi time-server guides get wrong, and the numbers to prove it. " + "GPS Stratum 1 on a Pi 4: PREEMPT_RT makes PPS jitter worse, the PPS interrupt " + - "cannot be pinned, PTP is impossible, and your dashboard is taxing your clock.", + "cannot be pinned, PTP needs a CM4 not a 4B, and your dashboard is taxing your clock.", // The mark IS the word "cuckoo" — a rebus. replacesTitle stops Starlight // rendering the title text beside it (which would read "…escapement The diff --git a/docs-site/src/content/docs/explanation/no-ptp-on-a-pi-4.md b/docs-site/src/content/docs/explanation/no-ptp-on-a-pi-4.md index 14fe93c..04a3390 100644 --- a/docs-site/src/content/docs/explanation/no-ptp-on-a-pi-4.md +++ b/docs-site/src/content/docs/explanation/no-ptp-on-a-pi-4.md @@ -1,14 +1,33 @@ --- -title: Why PTP is off the table on a Pi 4 -description: PTP's entire value is hardware timestamping. The Pi 4's NIC has no PTP hardware clock. Software PTP is a worse NTP. +title: No PTP on a Pi 4 Model B (but yes on a CM4) +description: The CM4 does hardware PTP. The Pi 4 Model B does not — and both report the identical PHY ID, so the kernel tells them apart by MDIO address and declines ours by name. sidebar: order: 3 --- -The reference builds all reach for **PTP** (IEEE 1588), and they're right to: on -the right hardware it's dramatically better than NTP. +:::caution[Corrected — 2026-07-14] +This page used to be called *"Why PTP is off the table on a Pi 4"* and blamed the +`bcmgenet` MAC driver for not exposing a PHC. **The headline overclaimed and the +mechanism was wrong.** A reader sent us +[Jeff Geerling's CM4 PTP write-up](https://www.jeffgeerling.com/blog/2022/ptp-and-ieee-1588-hardware-timestamping-on-raspberry-pi-cm4/), +which shows the **Compute Module 4 doing hardware PTP** — two of them synced to +within 10–15 nanoseconds. -The Pi 4 is not the right hardware. One command settles it: +Our measurement was real, but it is specific to the **Pi 4 Model B**, and the +actual reason is far better than "unsupported." Corrected version below. This is +the site working as intended. +::: + +PTP's entire value is **hardware timestamping**: the network silicon stamps the +packet as it crosses the wire, outside the operating system. That's what takes +scheduling, driver latency and queueing out of the measurement, and it's why PTP +reaches nanoseconds where NTP reaches microseconds. + +With no PHC (PTP Hardware Clock), PTP is just a protocol — packets stamped by the +*kernel*, on the *CPU*, subject to precisely the jitter you were trying to escape. +A more complicated NTP with worse tooling. + +On our board: ```console $ ethtool -T eth0 @@ -17,36 +36,106 @@ Capabilities: software-receive software-system-clock PTP Hardware Clock: none -Hardware Transmit Timestamp Modes: none -Hardware Receive Filter Modes: none + +$ ls /dev/ptp* +ls: cannot access '/dev/ptp*': No such file or directory ``` -**`PTP Hardware Clock: none`.** There isn't one. There's no `/dev/ptp0` to open. +On a CM4 that same command reports `PTP Hardware Clock: 0`, and +`/sys/class/ptp/ptp0/clock_name` says `bcm_phy_ptp`. Same family, same era, +different answer. -## Why that's fatal rather than inconvenient +## Two different chips — that report the same ID -PTP's whole advantage is **hardware timestamping**: the network card itself -stamps the packet as it crosses the wire, in silicon, outside the operating -system. That's what removes kernel scheduling, driver latency, and queueing from -the measurement, and it's why PTP reaches nanoseconds where NTP reaches -microseconds. +| board | PHY | hardware PTP | +|---|---|---| +| Compute Module 4 | BCM54210PE | **yes** | +| Compute Module 5 | — | **yes**, out of the box | +| Pi 4 Model B | BCM54213PE | no | -Take the hardware clock away and PTP is just... a protocol. Software-timestamped -PTP has the packets stamped by the *kernel*, on the *CPU*, subject to exactly the -scheduling jitter you were trying to escape. It is a more complicated NTP with -worse tooling. +Here's the part that makes this worth a page. **Both PHYs report an identical ID:** -## But the guides say the Pi 4's PHY supports PTP +```console +$ cat /sys/class/mdio_bus/unimac-mdio--19/unimac-mdio--19:01/phy_id +0x600d84a2 +``` -They do, and the *chip* does — the BCM54213PE PHY has PTP capability on paper. -It doesn't matter. The Pi 4's `bcmgenet` MAC driver doesn't expose a PHC, so -Linux has nothing to give you. And the reference builds that make PTP work feed -the PPS into the NIC through a **SYNC pin that only the CM4/CM5 break out** — a -regular Pi 4 board doesn't route it anywhere you can reach. +That value is `PHY_ID_BCM54213PE` in `include/linux/brcmphy.h` — and a CM4 +reports it too. The silicon genuinely differs; the identifier does not. So the +kernel *cannot* tell these boards apart by asking the chip who it is. -## So don't chase it +## So it tells them apart by where they're plugged in -We spent real time on this before running `ethtool -T`, which we should have run -first. If your board reports `PTP Hardware Clock: none`, close the tab. Put the -effort into the PPS path instead — that's where the nanoseconds actually are, and +From the Raspberry Pi kernel, `drivers/net/phy/bcm-phy-ptp.c`, comments and all: + +```c +struct bcm_ptp_private *bcm_ptp_probe(struct phy_device *phydev) +{ + switch (BRCM_PHY_MODEL(phydev)) { + case PHY_ID_BCM54210E: + break; +#ifdef PHY_ID_BCM54213PE + case PHY_ID_BCM54213PE: + switch (phydev->mdio.addr) { + case 0: // CM4 - this is a BCM54210PE which supports PTP + break; + case 1: // 4B - this is a BCM54213PE which doesn't + return NULL; + default: // Unknown - assume it's BCM54210PE + break; + } + break; +``` + +The disambiguator is the **MDIO bus address**. A CM4's PHY sits at address 0; a +Pi 4 Model B's sits at address 1. Ours: + +```console +$ ls -d /sys/class/mdio_bus/unimac-mdio--19/unimac-mdio--19:* +/sys/class/mdio_bus/unimac-mdio--19/unimac-mdio--19:01 + ^^ address 1 — the 4B branch +``` + +Address 1 → `return NULL` → no PHC is ever registered. That is the whole story. + +## It is not your kernel, and there is no option to flip + +This is the part worth internalising, because it's a trap that looks exactly like +a misconfiguration. All the support is *present*: + +```console +$ grep -E "CONFIG_NETWORK_PHY_TIMESTAMPING|CONFIG_BCM_NET_PHYPTP" .config +CONFIG_NETWORK_PHY_TIMESTAMPING=y +CONFIG_BCM_NET_PHYPTP=y +``` + +The driver is compiled in. The PHY ID is a recognised constant. The code path +exists, and it runs. **It runs, looks at your board, and declines.** No kernel +option changes that, no patch, no `rpi-update` — the refusal is a deliberate and +correct statement about the silicon in front of it. + +It also means our [`IRQF_NO_THREAD` kernel](/reference/the-patch/) is not the +culprit. That was the obvious suspicion when we re-opened this, so we checked it +first. It isn't. + +## What to actually do + +**On a Pi 4 Model B:** stop. Spend the effort on the PPS path, which is where the +nanoseconds actually live — and [it needs the help](/explanation/preempt-rt-made-it-worse/). + +**If you want PTP on a Pi:** buy a **CM4 or CM5**, not a 4B. You get `/dev/ptp0`, +`ethtool -T` reports hardware transmit and receive timestamping, and on the CM4 IO +board you can drive a PPS out of pin 9. Geerling's post is the guide; we're not +going to rewrite it. + +**Either way, run `ethtool -T` first.** We didn't, and burned real time on a +question that one command answers. + +:::note[Credit] +The correction, and every CM4 figure here, comes from +[Jeff Geerling's write-up](https://www.jeffgeerling.com/blog/2022/ptp-and-ieee-1588-hardware-timestamping-on-raspberry-pi-cm4/) +and the kernel patches it links to. We had the right conclusion for the wrong +reason, and stated it too broadly. Checking beats believing — including when the +thing being checked is us. +::: diff --git a/docs-site/src/content/docs/findings.md b/docs-site/src/content/docs/findings.md index ee7cb67..a46b007 100644 --- a/docs-site/src/content/docs/findings.md +++ b/docs-site/src/content/docs/findings.md @@ -12,11 +12,18 @@ A GPS-disciplined Stratum 1 NTP server: **Raspberry Pi 4** + **BerryGPS-IMU v4** 199 ns**, root delay ~1 ns, survives a cold power cut unattended. About $130 of parts, replacing an appliance that costs $1,500–$10,000. -## What the guides get wrong on a Pi 4 +## What the guides get wrong on a Pi 4 Model B + +:::note[Model B, specifically] +These are properties of the **Pi 4 Model B**, not the whole Pi 4 family. The +**CM4 and CM5 do hardware PTP** — [we got that one wrong at first, and corrected +it](/explanation/no-ptp-on-a-pi-4/). If a claim here matters to you, check it on +*your* board. That's the entire point of this site. +::: | Claim | Reality | |---|---| -| "Use PTP for real precision" | **Impossible.** `ethtool -T eth0` → `PTP Hardware Clock: none`. No hardware timestamping exists on this NIC. | +| "Use PTP for real precision" | **Not on a 4B — but yes on a CM4.** Both report the *same* PHY ID, so the kernel disambiguates by MDIO address and hands the 4B a `return NULL`. `ethtool -T` → `PTP Hardware Clock: none`. | | "Isolate the PPS IRQ on a dedicated core" | **Not permitted.** GPIO IRQs demux through `pinctrl-bcm2835` and reject `smp_affinity`. | | "Install PREEMPT_RT" | **Made jitter 3× worse** until patched — it threads the handler that takes the timestamp. | | "Raise the GPS baud rate" | **Irrelevant.** PPS offset measured −1 ns at 9600 vs 115200. Identical. NMEA only *labels* the second. | diff --git a/docs-site/src/content/docs/index.mdx b/docs-site/src/content/docs/index.mdx index 07cd3bb..8ab6809 100644 --- a/docs-site/src/content/docs/index.mdx +++ b/docs-site/src/content/docs/index.mdx @@ -76,9 +76,10 @@ board rather than take our word for it. That's the whole point. costs you the accuracy. [→ Why](/explanation/the-interrupt-you-cannot-move/) - - `ethtool -T eth0` → `PTP Hardware Clock: none`. There is no hardware - timestamping. Software PTP is just a worse NTP. Don't chase it. + + The CM4 and the 4B report the **same PHY ID**, so the kernel tells them apart + by MDIO address and hands the 4B a `return NULL`. The driver is compiled in; + it looks at your board and declines. Buy a CM4 if you want PTP. [→ Why](/explanation/no-ptp-on-a-pi-4/)