Fix SBC overlay upgrade + simplify PCIe Gen 3 config
All checks were successful
Build Talos CM5 Image / build (push) Successful in 3m22s

Two fixes in one:

1. SBC overlay upgrade path: the overlay installer was always writing
   to /boot/EFI, but on SBC layouts (no BOOT partition) the GRUB code
   mounts EFI at /boot. Config.txt and firmware ended up in a stale
   /boot/EFI/ subdirectory, invisible to the firmware. The installer
   now detects the SBC layout and writes to the correct location.

2. PCIe Gen 3: dtparam=pciex1_gen=3 works on CM5 (the DT overrides
   exist), so the custom pcie-gen3.dtbo overlay is unnecessary.
   Simplified to just use dtparam in config.txt.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Mathias Beaulieu-Duncan 2026-02-16 19:45:39 -05:00
parent 3cfbe794f7
commit 91d86de629
4 changed files with 68 additions and 69 deletions

View File

@ -18,9 +18,7 @@ enable_uart=1
[pi5]
enable_uart=0
# Enable PCIe Gen 3 for NVMe (~800 MB/s vs ~400 MB/s Gen 2)
# CM5 DTB lacks the pciex1 alias needed for dtparam=pciex1_gen=3,
# so we use a custom overlay that targets pcie@1000110000 directly.
dtoverlay=pcie-gen3
dtparam=pciex1_gen=3
[all]
# Disable Bluetooth.
dtoverlay=disable-bt

Binary file not shown.

View File

@ -1,66 +0,0 @@
From b7b424db9b0f771c60c4090c30bf1246eeef6995 Mon Sep 17 00:00:00 2001
From: Mathias Beaulieu-Duncan <mathias@openharbor.io>
Date: Mon, 16 Feb 2026 19:07:45 -0500
Subject: [PATCH] Add PCIe Gen 3 overlay for CM5
The CM5 device tree (bcm2712-rpi-cm5-cm5io.dtb) lacks the pciex1 alias
that the Pi 5 DTB provides, making dtparam=pciex1_gen=3 silently
non-functional on CM5 boards.
This adds a custom device tree overlay (pcie-gen3.dtbo) that targets
/axi/pcie@1000110000 directly to set max-link-speed = <3>, bypassing
the missing alias entirely. The overlay is embedded in the installer
binary and written to /boot/EFI/overlays/ during install/upgrade.
Combined with dtoverlay=pcie-gen3 in config.txt, this enables PCIe
Gen 3 (8.0 GT/s, ~800 MB/s) for NVMe on CM5 Compute Blades.
---
installers/rpi5/src/main.go | 10 ++++++++++
installers/rpi5/src/pcie-gen3.dtbo | Bin 0 -> 230 bytes
2 files changed, 10 insertions(+)
create mode 100644 installers/rpi5/src/pcie-gen3.dtbo
diff --git a/installers/rpi5/src/main.go b/installers/rpi5/src/main.go
index fed3819..1134168 100644
--- a/installers/rpi5/src/main.go
+++ b/installers/rpi5/src/main.go
@@ -17,6 +17,9 @@ import (
//go:embed config.txt
var configTxt []byte
+//go:embed pcie-gen3.dtbo
+var pcieGen3Dtbo []byte
+
func main() {
adapter.Execute(&RpiInstaller{})
}
@@ -52,6 +55,13 @@ func (i *RpiInstaller) Install(options overlay.InstallOptions[rpiOptions]) error
return err
}
+ // Write custom PCIe Gen 3 overlay for CM5 (its DTB lacks the pciex1 alias
+ // needed by dtparam, so we target pcie@1000110000 directly).
+ err = os.WriteFile(filepath.Join(options.MountPrefix, "/boot/EFI/overlays/pcie-gen3.dtbo"), pcieGen3Dtbo, 0o644)
+ if err != nil {
+ return err
+ }
+
if options.ExtraOptions.ConfigTxt != "" {
configTxt = []byte(options.ExtraOptions.ConfigTxt)
}
diff --git a/installers/rpi5/src/pcie-gen3.dtbo b/installers/rpi5/src/pcie-gen3.dtbo
new file mode 100644
index 0000000000000000000000000000000000000000..863d0ea1bd8860dd361fe12d017330655d97a39e
GIT binary patch
literal 230
zcmcb>`|m9S1H&^QwgBP-K&%18f<P<)#2}ys#2sK3D!~ZlG6QK|5Id<TIaensIoHVC
z&<HBWm{ydSo|~Fi;$Q$40jU)QVs8D!icI~2<jhnDLjwZ?Ll6N`!N9;6AD>^AT9lJm
z86OYQ1k%F-#Ntpk6Oe{s&gA^ug2a-{q?}ZSlEk9))Dm4FH-jNJu|hW|GcQ}WxF9t(
Gg#iGv7$sN$
literal 0
HcmV?d00001
--
2.50.1 (Apple Git-155)

View File

@ -0,0 +1,67 @@
From 113b5acba0bfc2fcc4f7494f88b0b9601bdbd4c2 Mon Sep 17 00:00:00 2001
From: Mathias Beaulieu-Duncan <mathias@openharbor.io>
Date: Mon, 16 Feb 2026 19:07:45 -0500
Subject: [PATCH] Fix SBC overlay upgrade: detect EFI mount path for SBC
layouts
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
On SBC platforms (RPi5/CM5), the disk layout has no separate BOOT
partition. During upgrades, the GRUB install code mounts the EFI
partition at /boot instead of /boot/EFI. The overlay installer was
always writing to /boot/EFI, causing config.txt and firmware files
to end up in the wrong subdirectory — invisible to the firmware.
Detect the SBC layout by checking if config.txt already exists at
/boot/ (indicating EFI is mounted there), and write files to the
correct location. Also clean up any stale /boot/EFI/ directory
from previous incorrect upgrades.
---
installers/rpi5/src/main.go | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/installers/rpi5/src/main.go b/installers/rpi5/src/main.go
index fed3819..862d72e 100644
--- a/installers/rpi5/src/main.go
+++ b/installers/rpi5/src/main.go
@@ -42,13 +42,25 @@ func (i *RpiInstaller) GetOptions(extra rpiOptions) (overlay.Options, error) {
}
func (i *RpiInstaller) Install(options overlay.InstallOptions[rpiOptions]) error {
- err := copy.Dir(filepath.Join(options.ArtifactsPath, "arm64/firmware/boot"), filepath.Join(options.MountPrefix, "/boot/EFI"))
- if err != nil {
+ // Determine where the EFI partition is mounted.
+ // Standard layout: BOOT (XFS) at /boot, EFI (VFAT) at /boot/EFI
+ // SBC layout: no BOOT partition, EFI (VFAT) at /boot
+ efiDir := filepath.Join(options.MountPrefix, "/boot/EFI")
+
+ if _, err := os.Stat(filepath.Join(options.MountPrefix, "/boot/config.txt")); err == nil {
+ // config.txt exists at /boot — EFI partition is mounted at /boot (SBC layout).
+ efiDir = filepath.Join(options.MountPrefix, "/boot")
+
+ // Clean up stale /boot/EFI/ directory from previous upgrades that
+ // wrote to the wrong path.
+ os.RemoveAll(filepath.Join(options.MountPrefix, "/boot/EFI"))
+ }
+
+ if err := copy.Dir(filepath.Join(options.ArtifactsPath, "arm64/firmware/boot"), efiDir); err != nil {
return err
}
- err = copy.File(filepath.Join(options.ArtifactsPath, "arm64/u-boot/rpi5/u-boot.bin"), filepath.Join(options.MountPrefix, "/boot/EFI/u-boot.bin"))
- if err != nil {
+ if err := copy.File(filepath.Join(options.ArtifactsPath, "arm64/u-boot/rpi5/u-boot.bin"), filepath.Join(efiDir, "u-boot.bin")); err != nil {
return err
}
@@ -58,5 +70,5 @@ func (i *RpiInstaller) Install(options overlay.InstallOptions[rpiOptions]) error
configTxt = append(configTxt, []byte("\n"+options.ExtraOptions.ConfigTxtAppend)...)
- return os.WriteFile(filepath.Join(options.MountPrefix, "/boot/EFI/config.txt"), configTxt, 0o644)
+ return os.WriteFile(filepath.Join(efiDir, "config.txt"), configTxt, 0o644)
}
--
2.50.1 (Apple Git-155)