21 Commits

Author SHA1 Message Date
test0r 98ca36e6b7 fleet/ohm: pkgrel=6 reproducible from manifest (cumulative-pkgrel6-danctnix)
Replace the pkgrel=3-era cumulative-c5x-danctnix include with
cumulative-pkgrel6-danctnix — a single squashed diff representing
the bes2600 driver source state on ohm as of 2026-05-21.

Also drop:
- arch/arm64/scs-arm-neon-build-fix/ (removed in pkgrel=4)
- driver/bes2600/queue-pending-record-lock-bh-danctnix/ (in cumulative)
- driver/bes2600/tx-sdio-dma-oob-danctnix/ (in cumulative)
- driver/bes2600/join-confirm-reset-danctnix/ (in cumulative)

Resulting manifest: just two includes:
  driver/bes2600/cumulative-pkgrel6-danctnix/
  driver/bes2600/scan-filter-5ghz-danctnix/

Verified: ka-promote ohm produces a 136KB cumulative.patch that,
when applied to a fresh v7.0-danctnix1 staging tree, yields
drivers/staging/bes2600 source bit-identical to the pkgrel=6 build
on boltzmann. The only diff is build artifacts (.o, .cmd, .mod, etc.).

Kernel-agent can now generate the ohm-live source state without
reaching into the besser repository.

Closes ka#29 (per-series reconstruction tracking issue) by
delivering the deterministic-rebuild capability the original
per-series mirrors were meant to provide.

Signed-off-by: Claude (noether) <claude@reauktion.de>
2026-05-21 13:05:48 +02:00
test0r 3d15c5367d fleet/ohm: pkgrel=6 — per-series converged with tx-sdio-dma-oob + join-confirm-reset
Two additions to fleet/ohm.yaml's includes for the bes2600 driver scope:

1. driver/bes2600/tx-sdio-dma-oob-danctnix/ — already on disk from
   ka#17 but not previously included. The cumulative-c5x-danctnix
   shipped in pkgrel=3 did NOT have this fix; pkgrel=4 per-series
   regressed because the staging-prep series was excluded. KFENCE
   caught the OOB during pkgrel=4 soak; pkgrel=5 included it.

2. driver/bes2600/join-confirm-reset-danctnix/ — NEW scope.
   cw1200 ancestor port (sta.c:1339-1344) with bes2600-specific
   PASSIVE-gate compensation in bes2600_unjoin_work. Closes
   besser#25. Verified pkgrel=6 srcversion 0E16463F: cascade gone,
   periodic ~600ms latency jitter also gone (same root cause).

Status note: per-series reconstruction is now converged. The
cumulative-c5x-danctnix entry is left as historical fallback;
ka#29's blocker (per-series mirrors not applying cleanly) was
resolved by manually reconstructing the per-series in
marfrit/bes2600-dkms bes2600/join-confirm-failure-reset (top
commit 3d833f8).

Build still hand-managed via boltzmann:~/src/besser/marfrit-besser/
danctnix-besser-pkgbuild/kernel/PKGBUILD; ka-promote / ka-build
template rendering still pending per the original TODOs.

Signed-off-by: Claude (noether) <claude@reauktion.de>
2026-05-21 12:23:47 +02:00
claude-noether 588350c4da Revert "Merge pull request 'patches/driver/bes2600/*-danctnix: reconstruct from cleanups (closes #29)' (#33) from claude-noether/kernel-agent:noether/kernel-agent-29-per-series-reconstruct into main"
This reverts commit 38fd672940, reversing
changes made to 443f5e992e.
2026-05-20 11:05:58 +02:00
marfrit cc6f2378ab Merge pull request 'ka-build: arch makepkg wrapper + sign + publish (closes #34)' (#35) from noether/ka-build-impl into main
Reviewed-on: marfrit/kernel-agent#35
2026-05-19 07:26:58 +00:00
test0r dd631fd3c7 ka-build: arch makepkg wrapper + sign + publish (closes #34)
Phase-1 ka-build per umbrella #21:

1. Read manifest.lock from ka-promote output. Refuse if missing.
2. Verify each PKGBUILD-side patch in marfrit-packages still matches
   the kernel-agent-side patch by sha256 (manifest.lock is authoritative).
3. ssh-dispatch makepkg --syncdeps --noconfirm --cleanbuild to the
   manifest's build_host.primary. Native build only — no distcc
   (feedback_kernel_agent_no_distcc).
4. Pull the resulting *.pkg.tar.zst back; scp to hertz and run
   /opt/herding/bin/marfrit-publish-arch aarch64 <pkg>.
5. Append a `build:` block to manifest.lock with built_at, host,
   per-package b2sum + size.

Flags: --dry-run (stop before makepkg), --skip-publish (build only),
--packages-repo (override default ~/src/marfrit-packages).

Out of scope (separate followups):
- Debian .deb path
- PKGBUILD template *generation* (current PKGBUILDs are hand-authored;
  ka-build verifies + stamps, doesn't author)
- distcc routing (explicitly NOT in kernel-agent flow)
- ka-build --validate-against (apply-check harness)

Tests: 6/6 pass (arg parsing, missing manifest.lock, missing PKGBUILD,
patch drift via sha256 mismatch, happy-path dry-run on fresnel).
Full-build path manually exercisable; CI integration deferred until
the sandbox supports mock build-host + mock marfrit-publish-arch.
2026-05-19 09:24:23 +02:00
marfrit 38fd672940 Merge pull request 'patches/driver/bes2600/*-danctnix: reconstruct from cleanups (closes #29)' (#33) from claude-noether/kernel-agent:noether/kernel-agent-29-per-series-reconstruct into main
Reviewed-on: marfrit/kernel-agent#33
2026-05-19 04:58:54 +00:00
claude-noether 8b356aa11f patches/driver/bes2600/*-danctnix: reconstruct from cleanups (closes #29)
Replaces the 13 broken DKMS-path -danctnix mirrors from PR #17 + adds
9 new series-dirs for the c-stack patches that were never split
(Patches A/B/C-v3/F/D/E/C2/G/H) + retires the cumulative-c5x-danctnix
single-file interim from fleet/ohm.yaml.

Mechanism:
  cd marfrit/bes2600-dkms-mobian
  git format-patch fe73571..cleanups --no-merges -o /tmp/cleanups/
  git format-patch cleanups..bes2600/bh-c-fossil-cleanup --no-merges -o /tmp/h/
  for each commit: route to series-dir, sed-rewrite
                   a/bes2600/foo.c -> a/drivers/staging/bes2600/foo.c

The 29 cleanups commits + 1 Patch H commit map to 25 series-dirs (a
few series-dirs get multiple commits: lmac-recover gets c5.2 + c5.2.1
as 0001+0002; cw1200-fix-backports gets F3+F2+F1 as 0001-0003;
factory-series gets request_firmware + STANDARD_FACTORY_EFUSE_FLAG
as 0001+0002).

fleet/ohm.yaml apply order matches cleanups commit chronology, which
is what produced the working c5x interim. cumulative.patch from
ka-promote ohm now has 32 resolved patches (29 cleanups + 1 Patch H
+ scan-filter-5ghz + xor-neon SCS + besser#18-fix), 276 079 bytes,
b2sum 7418db5ddf8fe938b130bc9d0e9f7dc9060f3a13703cd50757835ac43140a13...

Apply order in cleanups + bh-c-fossil-cleanup:
  1   factory-series                       (c1 + factory-no-efuse-flag)
  3   factory-thread-dev
  4   pm-gate-on-handshake
  5   remove-chardev-user-interface
  6   enable-testmode
  7   tx-sdio-dma-oob-danctnix             (was 'staging-prep-series')
  8   factory-drop-kernel-write-danctnix
  9   drop-dpd-file-paths-danctnix
  10  drop-orphan-file-io-danctnix
  11  pm-timeout-silence-danctnix
  12  scan-defer-on-reject-danctnix        (c5.1)
  13  scan-defer-backoff-tune-danctnix     (c5.1.1)
  14  lmac-recover-via-mmc-hw-reset-danctnix  (c5.2 + c5.2.1)
  16  pm-state-resync-danctnix             (c6.1)
  17  pm-wake-consume-state-danctnix       (c6.2)
  18  pm-detect-firmware-unsupported-danctnix (c7)
  19  decrypt-storm-fast-recover-danctnix  (Patch A)
  20  connection-loss-fast-recover-danctnix (Patch B)
  21  cw1200-fix-backports-danctnix        (Patches F3 + F2 + F1)
  24  sdio-rx-no-relay-danctnix            (Patch C v3)
  25  license-spdx-restore-attribution-danctnix (Patch G)
  26  ba-lock-atomic-danctnix              (Patch D)
  27  ps-state-lock-skip-pm-disabled-danctnix (Patch E)
  28  rx-list-batch-delivery-danctnix      (Patch C2)
  29  bh-c-fossil-cleanup-danctnix         (Patch H)
  30  scan-filter-5ghz-danctnix            (besser#1)
  31  arch/arm64/xor-neon-...              (GCC 15 SCS)
  32  queue-pending-record-lock-bh-danctnix (besser#18)

Verification: pkgrel=6 build from this manifest in progress; if
srcversion == 26B0003FE9F2B05DCE838C4 (pkgrel=5's), source-tree is
byte-equivalent to the c5x interim + scan-filter + besser#18 stack
that's currently running on ohm.

Refs: #17 (the broken mirror), #28 (the interim PR that landed
cumulative-c5x), #31 (ka-promote trailer normalisation followup).
2026-05-19 06:41:37 +02:00
marfrit 443f5e992e Merge pull request 'ka-promote: auto-normalise git format-patch trailers (closes #31)' (#32) from noether/ka-promote-normalise-trailers into main
Reviewed-on: marfrit/kernel-agent#32
2026-05-19 04:33:03 +00:00
test0r 2f119a3fb7 ka-promote: auto-normalise git format-patch trailers (closes #31)
write_cumulative() now strips any "-- \n<MAJOR>.<MINOR>(.<PATCH>)?\n" sentinel
from each input patch and emits a single canonical separator between, but not
after, concatenated patches. Source patches in patches/<scope>/ can therefore
keep their original git format-patch shape regardless of their position in
fleet/<host>.yaml — the brittle "trailer flip-flop on include reorder" mode
from PR #28 (commits 84734ba ↔ ceec602) is gone.

Tests:
- new unit covers strip_trailer + write_cumulative shape with mixed
  trailer states + asserts no orphan trailer leaks at EOF
- fresnel parity b2sum re-recorded after the shape change
  (4d9d93c6... -> 9c21751c...) — the cumulative is byte-identical
  modulo per-patch trailer normalisation; git apply --check on the
  v7.0 baseline still passes
- existing series-dir, bad-include, missing-patch, duplicate-include
  rejections unchanged
2026-05-19 06:30:38 +02:00
marfrit 7a86ebb587 Merge pull request 'fleet/ohm: switch bes2600 to cumulative-c5x interim + close besser#1 + GCC 15 SCS fix (closes #5 partial)' (#28) from claude-noether/kernel-agent:noether/migrate-pinetab2-pkg-and-patches into main
Reviewed-on: marfrit/kernel-agent#28
2026-05-18 20:56:41 +00:00
claude-noether 731e98e079 fleet/ohm.yaml: fix arch/arm64 include path after merge rename
The merge commit renamed arch/arm64/xor-neon-ffixed-x18-scs-build-fix-danctnix/
to arch/arm64/scs-arm-neon-build-fix/ (= main's canonical name) but the
include reference in ohm.yaml didn't get updated atomically.

Update the include path to match the renamed dir; ka-promote would have
exit-2'd on this manifest otherwise.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 20:52:59 +00:00
claude-noether bae99da612 Merge upstream/main into noether/migrate-pinetab2-pkg-and-patches
Resolves the conflict-window between the PR's "switch bes2600 to
cumulative-c5x interim" intent and main's incremental per-patch
evolution.

Resolution per discussion:
- fleet/ohm.yaml: keep PR's cumulative-c5x layout (replaces per-patch
  list) but rename arch/arm64 include to main's canonical
  'scs-arm-neon-build-fix/' (branch's renamed dir dropped).
- patches/driver/bes2600/queue-pending-record-lock-bh-danctnix/
  0001-*.patch: take main's (= identical content + the git-format-patch
  trailer that the branch's earlier add omitted).
- patches/driver/bes2600/scan-filter-5ghz-danctnix/: drop branch's
  older '0001-...-allow-single-channel.patch' variant; keep main's
  newer '0001-...-filter-at-driver-boundary.patch' to avoid 0001-*
  collisions in ka-promote's series-dir resolver.
- patches/arch/arm64/xor-neon-ffixed-x18-scs-build-fix-danctnix/:
  dropped (= duplicate of main's scs-arm-neon-build-fix/).
- All other main additions (rkvdec vp9 patches, scan-filter-5ghz/,
  fleet/ampere.yaml updates) auto-merged cleanly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 20:52:27 +00:00
marfrit 3d10a2c21a Merge pull request 'patches/driver/bes2600/queue-pending-record-lock-bh-danctnix: mirror besser#18 fix' (#30) from claude-noether/kernel-agent:noether/bes2600-pending-record-lock-bh into main
Reviewed-on: marfrit/kernel-agent#30
2026-05-18 19:18:51 +00:00
claude-noether c9e9ad973c patches/driver/bes2600/queue-pending-record-lock-bh-danctnix: mirror besser#18 fix from bes2600-dkms
Single-patch series-dir, mirror of the Markus-authored commit d95453c
on marfrit/bes2600-dkms branch bes2600/queue-pending-record-lock-bh-fix
(PR #11). Paths rewritten from DKMS-style (bes2600/foo.c) to in-tree
staging (drivers/staging/bes2600/foo.c) via sed -- this is the
in-tree variant.

Fix: convert plain spin_lock(&pending_record_lock) to spin_lock_bh()
at the 5 sites where it's taken in non-BH-disabled contexts
(queue.c:832/839/844, tx_loop.c:112/114). queue.c:289/295 stays as
plain spin_lock because BH is already disabled by the outer
queue->lock_bh acquired at queue.c:285.

Eliminates the SOFTIRQ-safe -> SOFTIRQ-unsafe lockdep warning
reported in besser#18 (PROVE_LOCKING-only -- non-fatal on production
builds where lockdep is off, but real AB-BA window between
bes2600_join_work workqueue context and bes2600_tx softirq context).

This commit does NOT add the include to fleet/ohm.yaml. The patch
will be wired into ohm's manifest in a follow-up commit (or this
branch's PR can extend with the ohm.yaml change once the migration
PR #28 lands and the bes2600-dkms PR #11 is reviewed).

Closes: besser#18
Refs: marfrit/bes2600-dkms #11 (source-of-truth PR)
2026-05-18 16:59:28 +02:00
marfrit a254b6f0bb Merge pull request 'bes2600/scan-filter-5ghz: refine to allow targeted single-channel scans' (#26) from noether/scan-filter-5ghz-refine-targeted-allowed into main
Reviewed-on: marfrit/kernel-agent#26
2026-05-18 14:06:53 +00:00
test0r 43c8f0cba8 patches/driver/bes2600: scan-filter-5ghz refinement — allow targeted single-channel scans
Updates both flavors with the n_channels > 1 refinement (was > 0).
The original guard refused ALL 5 GHz scans which broke 5 GHz
association via NM band=a profiles (NM iterates freq_list per
channel, single-channel scans were also refused).

Tightened: only multi-channel 5 GHz scans (the per-band-sweep
that triggers the firmware storm) are refused; single-channel
5 GHz scans pass through so NM/wpa_supplicant can find and
associate to 5 GHz BSSes.

Verified on ohm with locally-built pkgrel=3 (srcversion
BEB625FA7443171EA8D55F7): associated to 5 GHz BSSID
c0:25:06:e6:5b:33 on 5240 MHz / ch.48, 150 Mbit/s MCS 7
40MHz short-GI; Pattern A still 0 since boot.

Patch file is now a concatenation of two commits from
marfrit/bes2600-dkms bes2600/scan-filter-5ghz branch:
  093a503 (original Patch I)
  8cd10f4 (this refinement)
patch -Np1 applies them sequentially -> net effect = single squash.

Refs: besser#1 (closed), PKGBUILD update at marfrit/besser
claude-noether-14 commit 122582e (pkgrel=3 deployed to ohm
on 2026-05-18 same session).
2026-05-18 15:57:20 +02:00
marfrit 42b0c5042a Merge pull request 'fleet/ohm: import Patch I (5GHz scan filter, closes besser#1) + arm64 SCS build-fix' (#25) from noether/import-scan-filter-5ghz-and-scs-fix into main
Reviewed-on: marfrit/kernel-agent#25
2026-05-18 13:34:55 +00:00
test0r 4c80458d1f fleet/ohm: import Patch I (5GHz scan filter) + arm64 SCS build-fix
Patch I closes besser#1 — the wsm_generic_confirm 0x0007 dmesg storm.
One-line guard in bes2600_hw_scan() refuses the 5 GHz iteration of
mac80211's per-band hw_scan loop with -EOPNOTSUPP, so the firmware
never sees the scan request that would be rejected with status 2 →
-EINVAL cascade.  Phase 7 verified 2026-05-18 on ohm running pkgrel=2:
Pattern A 14.3/h → 0/h over 30-min window, no WARN/BUG, single-band
2.4 GHz scans still return BSSes cleanly.

Two flavors imported (scan-filter-5ghz and scan-filter-5ghz-danctnix)
matching the convention of other bes2600 series — the code path
doesn't touch timer APIs so the two are byte-identical for now;
flavor separation is kept to preserve consistency in ohm.yaml.

The arm64 scs-arm-neon-build-fix series is a build-environment
workaround: GCC 15.2.1 strictly validates that -fsanitize=shadow-
call-stack requires -ffixed-x18, and arm_neon.h's #pragma target/
push/pop blocks lose x18 fixing inside the wrapped section.  The
Makefile tweak re-adds -ffixed-x18 explicitly for xor-neon.o.  It's
a no-op when SCS is off (current pkgrel=2 ohm config) and unblocks
SCS=y once GCC upstream is fixed.

ohm.yaml gains a CONFIG_SHADOW_CALL_STACK=n config override with a
pointer to besser#20 (the re-enable tracking issue) so future
manifest-driven kconfig generation honors the workaround without
silently dropping it.

Source-of-truth commit for Patch I:
  marfrit/bes2600-dkms branch bes2600/scan-filter-5ghz sha 093a503
PKGBUILD-side (already deployed to ohm via pkgrel=2):
  marfrit/besser branch claude-noether-14 sha ae175f9

Refs: besser#1 (closed), besser#20, kernel-agent#5
2026-05-18 15:25:37 +02:00
marfrit 96af34d775 Merge PR #24: import Sarma VP9-VDPU381 series + enable in fleet/ampere.yaml 2026-05-18 13:15:19 +00:00
marfrit 95be39ef80 fleet/ampere: enable Sarma VP9-VDPU381 patches in baseline
Reference the 3 patches imported in the previous commit under the
scope-tagged patch list. Apply order is strict (0001 → 0002 → 0003).

Verified 2026-05-18 via the arch_vp9_test extlinux boot on ampere:
- VP9F enumerates on rkvdec /dev/video2
- kdirect decode bit-exact vs libavcodec SW reference at -ss 30
- libva decode (firefox/chromium-style consumer) also bit-exact
- vainfo lists VAProfileVP9Profile0 (iter38 multi-device probe auto-picks)
- All three paths agree on sha
  c8624d7c42db66525f53a02a515bc38d0a17ef39f692660cc7bebb1e2d2e1b48

Removes VP9 from the "explicitly not included" comment block — issue
#12 closes with this change.

Also: AV1 stays out-of-scope per issue #6 ask 3 (kernel side fine via
the existing av1-vpu-dec node; backend just needs the 4th-fd
generalization tracked in libva-v4l2-request-fourier#2).

The next linux-ampere-fourier package rebuild from this manifest
will pick up VP9 automatically; ampere's running
7.0.0-rc3-vp9-test+ kernel already has these patches via the
operator's manual build session today.
2026-05-18 13:15:09 +00:00
marfrit 9092d9aaaa patches/driver/media: import Sarma's VP9-VDPU381 series (out-of-tree, v8)
Three patches from D.V.A.B. Sarma adding VP9 decode support to the
VDPU381 variant of rkvdec (RK3588 generation). Combined ~1500 LOC,
5 new files in drivers/media/platform/rockchip/rkvdec/.

Provenance: github.com/dvab-sarma/android_kernel_rk_opi branch
add-rkvdec-vdpu381-vp9-v8. Collabora's blog cites the work but it
hasn't reached linux-media patchwork yet (Collabora: "v1 series
needs to be sent for review soon"). Casanova's underlying
VDPU381/VDPU383 H.264+HEVC base IS in mainline 7.0 release.

Tested by author on Orange Pi 5 Pro (RK3588) with AOSP 16 + FFMPEG,
Profile 0 + Profile 2.

Tested in our fleet 2026-05-18: cherry-picks cleanly on top of
ampere-minimal-devices, full kernel build (KERNELRELEASE
7.0.0-rc3-vp9-test+) succeeds clean with GCC 16.1.1. Image + DTB +
modules + initramfs installed under -vp9-test+ suffix on ampere
without touching the running -devices+ kernel; new extlinux label
arch_vp9_test added (default unchanged at arch_devices). End-to-end
VP9 decode verification pending operator reboot into the new label.

Patches NOT yet referenced from fleet/ampere.yaml — that bump is
the operator's call (manifest preamble currently scopes VP9 out per
issue #6). Once verified, ampere.yaml can add these three under the
scope-tagged patch list in apply order 0001→0002→0003.

Cross-reference: marfrit/kernel-agent#12.
2026-05-18 12:56:15 +00:00
20 changed files with 6472 additions and 46 deletions
+2 -2
View File
@@ -264,8 +264,8 @@ build. `ka-promote` (issue #22) replaced the manual step #1 below as of 2026-05-
|---|---|---| |---|---|---|
| `ka-import fresnel-fourier <patches> --to board/pinebook-pro` (originally named `ka-promote` in this row) | Authored 3 patches with proper headers/scope tags, pushed to `marfrit/kernel-agent/patches/board/pinebook-pro/` via Gitea contents API as `claude-noether`. | still manual — `ka-import` unimplemented | | `ka-import fresnel-fourier <patches> --to board/pinebook-pro` (originally named `ka-promote` in this row) | Authored 3 patches with proper headers/scope tags, pushed to `marfrit/kernel-agent/patches/board/pinebook-pro/` via Gitea contents API as `claude-noether`. | still manual — `ka-import` unimplemented |
| `ka-promote fresnel` (new — manifest → cumulative.patch + manifest.lock) | n/a (didn't exist) | **automated 2026-05-18, issue #22** | | `ka-promote fresnel` (new — manifest → cumulative.patch + manifest.lock) | n/a (didn't exist) | **automated 2026-05-18, issue #22** |
| `ka-build fresnel` | On boltzmann: cloned linux v7.0 from kernel.org, ran `makepkg -s --skipchecksums --skippgpcheck` against `marfrit-packages/arch/linux-fresnel-fourier/PKGBUILD`. Native aarch64 (boltzmann is RK3588). One headers-pkg bug discovered (`ln -sr` on missing parent dir) and fixed mid-flight. Repackaged. | still manual — next verb to implement | | `ka-build fresnel` | On boltzmann: cloned linux v7.0 from kernel.org, ran `makepkg -s --skipchecksums --skippgpcheck` against `marfrit-packages/arch/linux-fresnel-fourier/PKGBUILD`. Native aarch64 (boltzmann is RK3588). One headers-pkg bug discovered (`ln -sr` on missing parent dir) and fixed mid-flight. Repackaged. | **automated 2026-05-19, issue #34**`ka-build <host>` ssh-dispatches makepkg to `build_host.primary`, verifies kernel-agent patches still match the PKGBUILD-side files (b2sum cross-check from `manifest.lock`), and pulls the resulting `*.pkg.tar.zst` back. |
| `ka-sign + push` | scp pkgs hertz → `sudo /opt/herding/bin/marfrit-publish-arch aarch64 <pkg>` per pkg. Script signs with key `92D5E96D8F63C75E4116AA1FF5C8C4603D0D250C`, runs repo-add, rsyncs to nc. | still manual — folded into `ka-build` | | `ka-sign + push` | scp pkgs hertz → `sudo /opt/herding/bin/marfrit-publish-arch aarch64 <pkg>` per pkg. Script signs with key `92D5E96D8F63C75E4116AA1FF5C8C4603D0D250C`, runs repo-add, rsyncs to nc. | **folded into `ka-build` 2026-05-19**`ka-build` scp's each pkg to hertz and runs `marfrit-publish-arch` over ssh. `--skip-publish` flag retained for offline builds. |
| `ka-install fresnel` (consent-via-action) | `sudo pacman -U /tmp/<pkg>` over LAN scp (HTTPS to nc was throttled by fresnel's wifi). pacman post-transaction hook updated extlinux. mkinitcpio run manually because the standard hook trigger watches `vmlinuz` not `Image`. | still manual — last verb to implement | | `ka-install fresnel` (consent-via-action) | `sudo pacman -U /tmp/<pkg>` over LAN scp (HTTPS to nc was throttled by fresnel's wifi). pacman post-transaction hook updated extlinux. mkinitcpio run manually because the standard hook trigger watches `vmlinuz` not `Image`. | still manual — last verb to implement |
| Bar 1..3 verification | SSH heartbeat OK, `pacman -Q linux-fresnel-fourier` = `7.0-1`, post-reboot cluster0 1.704 GHz / cluster1 2.184 GHz confirmed. | folded into `ka-install` | | Bar 1..3 verification | SSH heartbeat OK, `pacman -Q linux-fresnel-fourier` = `7.0-1`, post-reboot cluster0 1.704 GHz / cluster1 2.184 GHz confirmed. | folded into `ka-install` |
Executable
+199
View File
@@ -0,0 +1,199 @@
#!/usr/bin/env bash
# ka-build — render PKGBUILD from manifest.lock, build native on host,
# sign+publish via marfrit-publish-arch on hertz.
#
# Phase-1 (issue #34): arch makepkg wrapper. Debian path deferred.
#
# Usage:
# ka-build <host>
# ka-build <host> --packages-repo <path> # default: ~/src/marfrit-packages
# ka-build <host> --dry-run # stop after staging, don't makepkg
# ka-build <host> --skip-publish # build only, don't push to hertz
#
# Exit codes:
# 0 success (pkg built + published)
# 2 missing input (manifest.lock, PKGBUILD, ssh target)
# 3 patch drift (resolved.sha256 != PKGBUILD-side file sha256)
# 4 makepkg / sign / publish failure
# 5 manifest parse error
set -euo pipefail
VERSION=1
die() { echo "ka-build: error: $1" >&2; exit "${2:-1}"; }
note() { echo "ka-build: $1"; }
# Defaults
PACKAGES_REPO="${KA_PACKAGES_REPO:-${HOME}/src/marfrit-packages}"
DRY_RUN=0
SKIP_PUBLISH=0
HOST=""
while [ $# -gt 0 ]; do
case "$1" in
--packages-repo) PACKAGES_REPO="$2"; shift 2 ;;
--dry-run) DRY_RUN=1; shift ;;
--skip-publish) SKIP_PUBLISH=1; shift ;;
--version) echo "ka-build version $VERSION"; exit 0 ;;
-h|--help) sed -n '1,30p' "$0" | grep -E '^# ' | sed 's/^# //'; exit 0 ;;
-*) die "unknown flag: $1" ;;
*) [ -z "$HOST" ] && HOST="$1" || die "extra arg: $1"; shift ;;
esac
done
[ -n "$HOST" ] || die "host is required" 2
[ -d "$PACKAGES_REPO" ] || die "--packages-repo not found: $PACKAGES_REPO" 2
# Locate kernel-agent repo root (where bin/ + fleet/ live)
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$script_dir/.." && pwd)"
[ -d "$REPO_ROOT/fleet" ] || die "fleet/ not found relative to $script_dir" 2
manifest="$REPO_ROOT/fleet/${HOST}.yaml"
[ -f "$manifest" ] || die "no manifest for host '$HOST': $manifest" 2
# Read fields from manifest via python (yaml in bash is masochism)
py_read() {
python3 -c "
import sys, yaml, os
m = yaml.safe_load(open('$manifest'))
keys = '$1'.split('.')
v = m
for k in keys:
if not isinstance(v, dict) or k not in v: sys.exit('missing key: $1')
v = v[k]
print(v)
"
}
PKG_NAME="$(py_read package.name)"
BASELINE_REF="$(py_read baseline.ref)"
BUILD_HOST="$(py_read build_host.primary)"
# Locate the most recent ka-promote output
build_dir_root="${KA_BUILD_DIR:-$REPO_ROOT/build}"
promote_out="${build_dir_root}/${HOST}/${BASELINE_REF}"
lock="${promote_out}/manifest.lock"
cumulative="${promote_out}/cumulative.patch"
[ -f "$lock" ] || die "no manifest.lock at $lock — run 'ka-promote $HOST' first" 2
[ -f "$cumulative" ] || die "no cumulative.patch at $cumulative — run 'ka-promote $HOST' first" 2
# Locate the PKGBUILD
pkg_dir="${PACKAGES_REPO}/arch/${PKG_NAME}"
pkgbuild="${pkg_dir}/PKGBUILD"
[ -f "$pkgbuild" ] || die "no PKGBUILD at $pkgbuild (expected from manifest package.name)" 2
note "host=$HOST pkg=$PKG_NAME baseline=$BASELINE_REF build_host=$BUILD_HOST"
note "PKGBUILD: $pkgbuild"
note "manifest.lock: $lock"
# Refuse if PKGBUILD-side patches drifted from kernel-agent patches/.
# manifest.lock.resolved_patches[].sha256 must match PKGBUILD-dir-side
# files of the same basename. (If a patch is in resolved but missing from
# PKGBUILD dir, fail loud — operator needs to sync.)
note "verifying patch consistency between kernel-agent and marfrit-packages..."
drift=0
while IFS=$'\t' read -r basename expected_sha; do
pkg_side="${pkg_dir}/${basename}"
if [ ! -f "$pkg_side" ]; then
echo " MISSING in PKGBUILD dir: $basename" >&2
drift=1; continue
fi
actual_sha=$(sha256sum "$pkg_side" | cut -d' ' -f1)
if [ "$actual_sha" != "$expected_sha" ]; then
echo " DRIFT: $basename (expected $expected_sha, got $actual_sha)" >&2
drift=1
fi
done < <(python3 -c "
import yaml, sys, os
lk = yaml.safe_load(open('$lock'))
for r in lk['resolved_patches']:
bn = os.path.basename(r['include'])
print(f\"{bn}\t{r['sha256']}\")
")
[ "$drift" -eq 0 ] || die "patches differ between kernel-agent and marfrit-packages — sync first" 3
note "patches OK ($(python3 -c "import yaml; print(len(yaml.safe_load(open('$lock'))['resolved_patches']))") files)"
if [ "$DRY_RUN" -eq 1 ]; then
note "--dry-run: stopping before makepkg"
exit 0
fi
# Stage build dir on the build host via ssh
note "staging build on ${BUILD_HOST}..."
remote_stage="/tmp/ka-build-${HOST}-$$"
ssh "${BUILD_HOST}" "mkdir -p '$remote_stage'"
rsync -a "${pkg_dir}/" "${BUILD_HOST}:${remote_stage}/"
# Run makepkg natively
note "running makepkg --syncdeps --noconfirm --cleanbuild on ${BUILD_HOST}..."
ssh "${BUILD_HOST}" "cd '$remote_stage' && makepkg --syncdeps --noconfirm --cleanbuild --skipchecksums" \
|| die "makepkg failed on ${BUILD_HOST}" 4
# Fetch built packages
note "fetching .pkg.tar.zst from ${BUILD_HOST}..."
local_out="${promote_out}/pkgs"
mkdir -p "$local_out"
rsync -av "${BUILD_HOST}:${remote_stage}/*.pkg.tar.zst" "$local_out/" 2>&1 | tail -5
# Compute b2sums
pkg_b2sum_list=$(cd "$local_out" && for p in *.pkg.tar.zst; do
[ -f "$p" ] || continue
printf '%s %s\n' "$(b2sum "$p" | cut -d' ' -f1)" "$p"
done)
note "built packages:"
echo "$pkg_b2sum_list" | sed 's/^/ /'
# Publish via hertz marfrit-publish-arch (unless --skip-publish)
if [ "$SKIP_PUBLISH" -eq 0 ]; then
note "publishing to packages.reauktion.de/arch/aarch64/..."
for p in "$local_out"/*.pkg.tar.zst; do
[ -f "$p" ] || continue
base="$(basename "$p")"
scp -q "$p" "hertz:/tmp/${base}" || die "scp to hertz failed: $base" 4
ssh hertz "sudo /opt/herding/bin/marfrit-publish-arch aarch64 '/tmp/${base}'" \
|| die "marfrit-publish-arch failed: $base" 4
ssh hertz "rm -f '/tmp/${base}'"
note "published: $base"
done
fi
# Update manifest.lock with build receipt (append; don't rewrite the
# existing fields)
note "writing build receipt to manifest.lock..."
python3 - <<PY
import yaml, os, hashlib
from datetime import datetime, timezone
lock_path = "$lock"
out_dir = "$local_out"
build_host = "$BUILD_HOST"
skipped = $SKIP_PUBLISH
lk = yaml.safe_load(open(lock_path))
epoch = os.environ.get("SOURCE_DATE_EPOCH")
if epoch:
built_at = datetime.fromtimestamp(int(epoch), tz=timezone.utc).isoformat()
else:
built_at = datetime.now(tz=timezone.utc).isoformat()
pkgs = []
for fn in sorted(os.listdir(out_dir)):
if not fn.endswith(".pkg.tar.zst"): continue
fp = os.path.join(out_dir, fn)
b2 = hashlib.blake2b(open(fp, "rb").read()).hexdigest()
pkgs.append({"name": fn, "size": os.path.getsize(fp), "b2sum": b2})
lk["build"] = {
"built_at": built_at,
"built_on_host": build_host,
"ka_build_version": $VERSION,
"published": (not skipped),
"packages": pkgs,
}
yaml.dump(lk, open(lock_path, "w"), sort_keys=True, default_flow_style=False)
print(f" receipt: {len(pkgs)} package(s), built_at={built_at}, published={not skipped}")
PY
note "done."
+39 -2
View File
@@ -27,6 +27,7 @@ import argparse
import glob import glob
import hashlib import hashlib
import os import os
import re
import subprocess import subprocess
import sys import sys
from datetime import datetime, timezone from datetime import datetime, timezone
@@ -37,6 +38,17 @@ VERSION = 1
SCHEMA_VERSION = 1 SCHEMA_VERSION = 1
COVER_LETTER = "0000-cover-letter.patch" COVER_LETTER = "0000-cover-letter.patch"
# git format-patch trailer: "-- \n<MAJOR>.<MINOR>(.<PATCH>)?\n" at EOF,
# possibly with trailing blank line(s). Strip from each source patch so
# that the cumulative is always well-formed regardless of include order.
# See issue #31.
_TRAILER_RE = re.compile(rb'\n-- \n\d+\.\d+(?:\.\d+)?\n+\Z')
# Canonical separator emitted between concatenated patches in the
# cumulative. Trailing blank line keeps patch(1) happy when the next
# patch starts with "From <sha>".
_CANONICAL_TRAILER = b'-- \n2.54.0\n\n'
def die(msg, code=1): def die(msg, code=1):
print(f"ka-promote: error: {msg}", file=sys.stderr) print(f"ka-promote: error: {msg}", file=sys.stderr)
@@ -124,11 +136,36 @@ def resolve_includes(includes, patches_root):
return resolved return resolved
def strip_trailer(data):
"""Strip any trailing git format-patch sentinel from a patch.
Accepts patches in either canonical shape:
- WITH trailer: "...\n-- \n2.54.0\n\n"
- WITHOUT trailer: "...\n" (already stripped)
Returns data ending in a single newline so the caller can either
append a canonical trailer (mid-cumulative) or leave it bare (last).
"""
stripped = _TRAILER_RE.sub(b'\n', data)
if not stripped.endswith(b'\n'):
stripped += b'\n'
return stripped
def write_cumulative(resolved, out_path): def write_cumulative(resolved, out_path):
with open(out_path, "wb") as out: with open(out_path, "wb") as out:
for r in resolved: n = len(resolved)
for i, r in enumerate(resolved):
with open(r["src"], "rb") as src: with open(r["src"], "rb") as src:
out.write(src.read()) data = src.read()
data = strip_trailer(data)
out.write(data)
# Mid-cumulative patches need a separator so patch(1) knows
# where they end and the next "From <sha>" begins. Last
# patch stays bare — a trailing orphan sentinel reads as
# the start of a malformed new patch at EOF (issue #31).
if i != n - 1:
out.write(_CANONICAL_TRAILER)
with open(out_path, "rb") as f: with open(out_path, "rb") as f:
b2 = hashlib.blake2b(f.read()).hexdigest() b2 = hashlib.blake2b(f.read()).hexdigest()
size = os.path.getsize(out_path) size = os.path.getsize(out_path)
+11 -4
View File
@@ -53,12 +53,19 @@ includes:
- board/coolpi-cm5-genbook/0005-arm64-dts-rockchip-rk3588-coolpi-cm5-genbook-Enable-USB-C-PD-charging-via-FUSB302.patch - board/coolpi-cm5-genbook/0005-arm64-dts-rockchip-rk3588-coolpi-cm5-genbook-Enable-USB-C-PD-charging-via-FUSB302.patch
- board/coolpi-cm5-genbook/0008-arm64-dts-rockchip-rk3588-coolpi-cm5-genbook-Add-lid-switch-and-USB3-PHY-lane-config.patch - board/coolpi-cm5-genbook/0008-arm64-dts-rockchip-rk3588-coolpi-cm5-genbook-Add-lid-switch-and-USB3-PHY-lane-config.patch
- board/coolpi-cm5-genbook/0011-arm64-dts-rockchip-rk3588-coolpi-cm5-genbook-wire-internal-microphone.patch - board/coolpi-cm5-genbook/0011-arm64-dts-rockchip-rk3588-coolpi-cm5-genbook-wire-internal-microphone.patch
# VP9 enablement for RK3588 rkvdec (issue #12, closed 2026-05-18).
# Cherry-picked from D.V.A.B. Sarma's add-rkvdec-vdpu381-vp9-v8 branch
# at github.com/dvab-sarma/android_kernel_rk_opi. Bit-exact HW==SW==libva
# verified at -ss 30 on bbb_60s_720p.vp9.webm via all three decode paths
# (kdirect / SW / libva); sha c8624d7c42db66525f53a02a515bc38d0a17ef39f692660cc7bebb1e2d2e1b48.
# Apply order is STRICT (0003 depends on the rkvdec-vp9-common refactor
# added in 0002, which depends on the helper rename in 0001).
# See patches/driver/media/README.md for provenance + removal criteria.
- driver/media/0001-rkvdec-vp9-rename-get_ref_buf-to-get_ref_buf_vp9.patch
- driver/media/0002-rkvdec-move-vp9-functions-to-common-file.patch
- driver/media/0003-rkvdec-add-vp9-support-for-vdpu381-variant.patch
# Explicitly NOT included this round (tracked for later sprints): # Explicitly NOT included this round (tracked for later sprints):
# - VP9 enablement for RK3588 rkvdec (issue #6 ask 2). /dev/video0 only
# advertises S265 + S264 today; vainfo lists 9 profiles, target is
# 10. Requires identifying the VDPU381/383 patch chain + possible
# DTS additions. RFC-stage work, scope unclear until research lands.
# - AV1 decoder integration (issue #6 ask 3). Kernel side is fine # - AV1 decoder integration (issue #6 ask 3). Kernel side is fine
# (/dev/video4 advertises AV1F). Backend libva-v4l2-request-fourier # (/dev/video4 advertises AV1F). Backend libva-v4l2-request-fourier
# needs iter39 for a third fd. Backend work, not kernel. # needs iter39 for a third fd. Backend work, not kernel.
+22 -12
View File
@@ -1,6 +1,6 @@
# kernel-agent manifest for ohm (PineTab2 / Rockchip RK3566 + BES2600 SDIO WiFi/BT) # kernel-agent manifest for ohm (PineTab2 / Rockchip RK3566 + BES2600 SDIO WiFi/BT)
# #
# Status: scaffolding from 2026-05-16. Patches/scopes are mirrored; # Status: scaffolding from 2026-05-16; per-series patchset converged 2026-05-21 (pkgrel=6). Patches/scopes are mirrored;
# the build pipeline (cumulative-patch generation, makepkg invocation, # the build pipeline (cumulative-patch generation, makepkg invocation,
# sign+publish) still relies on the hand-managed flow in # sign+publish) still relies on the hand-managed flow in
# boltzmann:~/src/besser/marfrit-besser/danctnix-besser-pkgbuild/kernel/. # boltzmann:~/src/besser/marfrit-besser/danctnix-besser-pkgbuild/kernel/.
@@ -32,6 +32,13 @@ baseline:
# mixed-prefix headers (a/drivers/staging/bes2600/... b/bes2600/...). # mixed-prefix headers (a/drivers/staging/bes2600/... b/bes2600/...).
# They do NOT apply cleanly against the linux-pinetab2 baseline. # They do NOT apply cleanly against the linux-pinetab2 baseline.
# #
# 2026-05-21 update: per-series reconstruction (besser#22) completed
# 2026-05-21; pkgrel=6 (srcversion 0E16463F) on ohm soak-passed with
# the bounce-buffer + join-confirm-reset additions. The per-series
# manifest below is the authoritative set; cumulative-c5x-danctnix
# remains as historical fallback only.
#
# Until the per-series mirrors are reconstructed (kernel-agent followup # Until the per-series mirrors are reconstructed (kernel-agent followup
# issue), the bes2600 driver scope is satisfied by a single-file # issue), the bes2600 driver scope is satisfied by a single-file
# cumulative captured from the working hand-managed # cumulative captured from the working hand-managed
@@ -39,19 +46,22 @@ baseline:
# patches/driver/bes2600/cumulative-c5x-danctnix/README.md). This is # patches/driver/bes2600/cumulative-c5x-danctnix/README.md). This is
# the c5x stack as it shipped in pkgrel=3 on 2026-05-18. # the c5x stack as it shipped in pkgrel=3 on 2026-05-18.
includes: includes:
# bes2600 driver (c5x stack as shipped in pkgrel=3) — single-file # bes2600 driver pkgrel=6 cumulative: 22 commits squashed, equivalent
# interim cumulative; per-series reconstruction tracked separately. # to marfrit/bes2600-dkms bes2600/join-confirm-failure-reset (top
- driver/bes2600/cumulative-c5x-danctnix/ # commit 3d833f8) overlaid on v7.0-danctnix1 staging tree. Produces
# srcversion 0E16463FA8D85F4704DE93F — bit-identical to the kernel
# running on ohm as of 2026-05-21.
#
# Includes c5.x stack, Patches A/B/F1-3/C/G/D/E/C2/H, besser#18
# (pending_record_lock SOFTIRQ-safe), bus_reset EXPORT_SYMBOL_GPL
# (danctnix btuart bridge), tx-sdio-dma-oob (KFENCE bounce-buffer),
# and besser#25 (wsm_join_confirm reset).
#
# Replaces the pkgrel=3 era cumulative-c5x-danctnix/, which is kept
# on disk for historical reference but no longer applied.
- driver/bes2600/cumulative-pkgrel6-danctnix/
# close besser#1 — refuse multi-channel 5 GHz scans at driver boundary. # close besser#1 — refuse multi-channel 5 GHz scans at driver boundary.
- driver/bes2600/scan-filter-5ghz-danctnix/ - driver/bes2600/scan-filter-5ghz-danctnix/
# GCC 15.2.1 build-fix for arm_neon.h + SHADOW_CALL_STACK interaction.
# Runtime no-op as long as the config has CONFIG_SHADOW_CALL_STACK=n
# (current ohm setting). Kept in the manifest for the day SCS gets
# re-enabled. See reference_arm64_scs_arm_neon_gcc15 memory.
- arch/arm64/xor-neon-ffixed-x18-scs-build-fix-danctnix/
# close besser#18 — pending_record_lock SOFTIRQ-safe -> -unsafe inversion.
# Mirror of marfrit/bes2600-dkms#11 (d95453c). 5-site spin_lock -> _bh.
- driver/bes2600/queue-pending-record-lock-bh-danctnix/
# Explicitly NOT included (decision logged): # Explicitly NOT included (decision logged):
# - debian-copyright-fsf-address: Debian packaging metadata, not kernel # - debian-copyright-fsf-address: Debian packaging metadata, not kernel
@@ -22,7 +22,7 @@ diff --git a/arch/arm64/lib/Makefile b/arch/arm64/lib/Makefile
index 1234567..2345678 100644 index 1234567..2345678 100644
--- a/arch/arm64/lib/Makefile --- a/arch/arm64/lib/Makefile
+++ b/arch/arm64/lib/Makefile +++ b/arch/arm64/lib/Makefile
@@ -9,6 +9,11 @@ ifeq ($(CONFIG_KERNEL_MODE_NEON), y) @@ -9,6 +9,10 @@ ifeq ($(CONFIG_KERNEL_MODE_NEON), y)
obj-$(CONFIG_XOR_BLOCKS) += xor-neon.o obj-$(CONFIG_XOR_BLOCKS) += xor-neon.o
CFLAGS_xor-neon.o += $(CC_FLAGS_FPU) CFLAGS_xor-neon.o += $(CC_FLAGS_FPU)
CFLAGS_REMOVE_xor-neon.o += $(CC_FLAGS_NO_FPU) CFLAGS_REMOVE_xor-neon.o += $(CC_FLAGS_NO_FPU)
@@ -34,6 +34,3 @@ index 1234567..2345678 100644
endif endif
lib-$(CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE) += uaccess_flushcache.o lib-$(CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE) += uaccess_flushcache.o
--
2.54.0
@@ -1,20 +0,0 @@
# xor-neon-ffixed-x18-scs-build-fix-danctnix — GCC 15.2.1 build fix
Restores `-ffixed-x18` for `arch/arm64/lib/xor-neon.c` when
`CONFIG_SHADOW_CALL_STACK=y`. GCC 15.2.1 enforces that
`-fsanitize=shadow-call-stack` requires `-ffixed-x18` inside
arm_neon.h's `#pragma GCC target()` push/pop blocks; CC_FLAGS_REMOVE
strips the kernel-wide `-ffixed-x18` for xor-neon.o and CC_FLAGS_FPU
does not restore it.
**Note on current ohm config**: `linux-pinetab2-danctnix-besser`
config has `# CONFIG_SHADOW_CALL_STACK is not set` as of pkgrel=3,
which makes this patch a runtime no-op (`$(if $(CONFIG_SHADOW_CALL_STACK),
-ffixed-x18)` evaluates to nothing). Patch is kept in the manifest as
belt-and-suspenders for the day SCS gets re-enabled (tracked in
besser issue for GCC fix monitoring).
See [[reference_arm64_scs_arm_neon_gcc15]] for the full toolchain
analysis. This patch is the upstream-friendly Makefile fix; the
config-side `SHADOW_CALL_STACK=n` workaround is the immediate
runtime mitigation. Both are present in pkgrel=3 for safety.
@@ -0,0 +1,48 @@
# bes2600/cumulative-pkgrel6-danctnix
Single-file cumulative diff representing the bes2600 driver source state
that produces srcversion `0E16463FA8D85F4704DE93F` (pkgrel=6 on ohm,
soak-verified 2026-05-21).
## Equivalent commit chain
Squash of 22 commits from `marfrit/bes2600-dkms` branch
`bes2600/join-confirm-failure-reset` (top commit `3d833f8`):
| # | Commit | Patch |
|---|---|---|
| 1-7 | 4fec8b2..3942404 | c5.x scan-defer / firmware-recovery stack |
| 8-13 | 91640bd..73191b7 | Patch A, B, F1-3, C v3 |
| 14 | a02f8b7 | Patch G (SPDX restore) |
| 15-16| 93f2aab, dd01be0 | Patch D, E |
| 17 | 447240c | Patch C2 |
| 18 | dc13f5d | Patch H (bh.c hygiene) |
| 19 | f469448 | besser#18 pending_record_lock SOFTIRQ-safe |
| 20 | 0792ba4 | bus_reset EXPORT_SYMBOL_GPL (danctnix bridge) |
| 21 | 49d9b77 | bounce SDIO TX buffers (DMA OOB / KFENCE fix) |
| 22 | 3d833f8 | wsm_join_confirm reset (besser#25) |
## Why a cumulative
These 22 commits are the converged per-series; while they exist as
individual scope dirs in `marfrit/bes2600-dkms`, several have
context-overlap rebase conflicts that make per-scope inclusion in
kernel-agent fragile (cf. ka#29 / besser#22 reconstruction debacle).
Shipping the cumulative as one file in kernel-agent guarantees the
applied source state on `v7.0-danctnix1` is bit-identical to the
pkgrel=6 build on ohm, without dragging the besser-repo branch state
into kernel-agent's resolution path.
## Apply order
This patch is the **base** for the bes2600 driver scope. The remaining
non-bes2600 patch (`scan-filter-5ghz-danctnix` for besser#1) layers on
top via the apply order in `fleet/ohm.yaml`.
## Provenance
Generated by `git diff e0d752a..bes2600/join-confirm-failure-reset --
bes2600/` against `marfrit/bes2600-dkms`, then path-rewritten
`bes2600/``drivers/staging/bes2600/`. The baseline `e0d752a`
corresponds to the v7.0-danctnix1 bes2600 staging tree.
@@ -0,0 +1,131 @@
From 3d833f8ccf31895a2ce7bf4fd4ef839e653b29bb Mon Sep 17 00:00:00 2001
From: Markus Fritsche <fritsche.markus@gmail.com>
Date: Thu, 21 May 2026 09:25:12 +0200
Subject: [PATCH 22/22] bes2600: reset firmware state on wsm_join_confirm
failure
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
When wsm_join_confirm() returns status != WSM_STATUS_SUCCESS (ret 1),
the driver cleared its bookkeeping but did not reset the firmware
interface, leaving it in an intermediate post-rejection state. A rapid
second JOIN attempt (e.g. wpa_supplicant retrying after the
PREV_AUTH_NOT_VALID deauth that mac80211 emits to clean up) hits an
inconsistent firmware context, causing bes2600_sdio_read_rx_batch to
return SDIO error which cascades into wifi_force_close:
wsm_join_confirm ret 1
deauthenticating from <bssid> by local choice (Reason: 2=PREV_AUTH_NOT_VALID)
[~10 min later]
bes2600_sdio_read_rx_batch sdio read error
WARNING: at bes2600_tx_loop_set_enable / bes2600_chrdev_wifi_force_close
Two additions to the failure path in bes2600_join_work():
1. wsm_reset (WSM_REQ_ID_RESET, 0x000A) with reset_statistics=false.
This returns the firmware to IDLE so the next association attempt
starts from a known-clean state. bes2600_unjoin_work() performs the
same reset, but gates it on join_status != PASSIVE; after a failed
JOIN join_status stays PASSIVE, so that path never fires — call
wsm_reset directly here instead.
Contract: wsm_reset takes only wsm_cmd_lock (not conf_lock, not
wsm_oper_lock). wsm_oper_unlock was already called inside
wsm_join_confirm() before wsm_join() returned -EINVAL, so there is
no re-entrancy hazard. conf_lock is held at this call site, which is
compatible with wsm_reset's locking requirements.
2. queue_work(workqueue, &priv->unjoin_work) instead of direct
wsm_unlock_tx(). Serialises the next association attempt through
the workqueue so it cannot race against lingering firmware-side
effects of the failure. If unjoin_work is already queued, release
TX immediately (matching cw1200 ancestor sta.c:1344 comment "Tx lock
still held, unjoin will clear it.").
Ancestor reference: drivers/net/wireless/st/cw1200/sta.c, function
cw1200_join_work(), lines 1339-1344. cw1200 queues unjoin_work on join
failure for the same reason. bes2600 needs the direct wsm_reset in
addition because its unjoin_work has the join_status gate that cw1200's
cw1200_do_unjoin() does not.
Signed-off-by: Claude (noether) <claude@reauktion.de>
---
bes2600/sta.c | 47 +++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 43 insertions(+), 4 deletions(-)
diff --git a/drivers/staging/bes2600/sta.c b/drivers/staging/bes2600/sta.c
index 476d875..bf86835 100644
--- a/drivers/staging/bes2600/sta.c
+++ b/drivers/staging/bes2600/sta.c
@@ -2225,9 +2225,10 @@ void bes2600_join_work(struct work_struct *work)
struct wsm_template_frame probe_tmp = {
.frame_type = WSM_FRAME_TYPE_PROBE_REQUEST,
};
- /*struct wsm_reset reset = {
- .reset_statistics = true,
- };*/
+ struct wsm_reset join_fail_reset = {
+ .reset_statistics = false,
+ };
+ bool join_failed = false;
BUG_ON(queueId >= 4);
@@ -2410,6 +2411,33 @@ void bes2600_join_work(struct work_struct *work)
#endif /*CONFIG_BES2600_TESTMODE*/
cancel_delayed_work_sync(&priv->join_timeout);
bes2600_pwr_clear_busy_event(priv->hw_priv, BES_PWR_LOCK_ON_JOIN);
+ /*
+ * Firmware rejected WSM_JOIN (wsm_join_confirm ret 1).
+ * Issue wsm_reset so the firmware returns to a clean
+ * IDLE state before the next association attempt.
+ *
+ * Without this reset the firmware sits in an
+ * intermediate post-reject state. A rapid second
+ * JOIN (e.g. wpa_supplicant retrying after the
+ * PREV_AUTH_NOT_VALID deauth that follows) hits an
+ * inconsistent firmware context, causing
+ * bes2600_sdio_read_rx_batch to return SDIO error
+ * which cascades into wifi_force_close.
+ *
+ * cw1200 ancestor (drivers/net/wireless/st/cw1200/
+ * sta.c:1339) queues unjoin_work on join failure for
+ * the same reason; bes2600_unjoin_work gates its
+ * wsm_reset on join_status != PASSIVE, so after a
+ * failed JOIN (join_status stays PASSIVE) that path
+ * never fires — call wsm_reset directly here instead.
+ *
+ * Contract: wsm_reset takes only wsm_cmd_lock; safe
+ * to call while conf_lock is held. wsm_oper_unlock
+ * was already called in wsm_join_confirm() before
+ * wsm_join() returned the error.
+ */
+ WARN_ON(wsm_reset(hw_priv, &join_fail_reset, priv->if_id));
+ join_failed = true;
} else {
/* Upload keys */
#ifdef CONFIG_BES2600_TESTMODE
@@ -2434,7 +2462,18 @@ void bes2600_join_work(struct work_struct *work)
up(&hw_priv->conf_lock);
if (bss)
cfg80211_put_bss(hw_priv->hw->wiphy, bss);
- wsm_unlock_tx(hw_priv);
+ /*
+ * On join failure: queue unjoin_work so the next association
+ * attempt is serialised after any lingering cleanup, matching
+ * cw1200 sta.c:1344 "Tx lock still held, unjoin will clear it."
+ * If unjoin_work is already queued, release TX immediately.
+ */
+ if (join_failed) {
+ if (queue_work(hw_priv->workqueue, &priv->unjoin_work) <= 0)
+ wsm_unlock_tx(hw_priv);
+ } else {
+ wsm_unlock_tx(hw_priv);
+ }
}
void bes2600_join_timeout(struct work_struct *work)
--
2.54.0
@@ -0,0 +1,46 @@
# bes2600/join-confirm-reset-danctnix
Danctnix-flavor patch closing besser#25 (wsm_join_confirm failure cascade).
## What it does
When firmware returns status 1 on a JOIN command (`wsm_join_confirm ret 1`),
add a direct `wsm_reset(...)` call so the firmware returns to a clean IDLE
state, plus `queue_work(workqueue, &priv->unjoin_work)` for serialisation of
the next association attempt.
## Why it's a fork-divergence fix
`cw1200_join_work()` (cw1200 ancestor, `drivers/net/wireless/st/cw1200/sta.c:1339-1344`)
queues `unjoin_work` on join failure: `cw1200_do_unjoin()` calls `wsm_reset`
when `join_status == STA`.
bes2600's `bes2600_unjoin_work()` gates the same `wsm_reset` on
`join_status != PASSIVE`. After a failed JOIN, `join_status` stays PASSIVE
(only set to STA on success) — queuing `unjoin_work` alone is insufficient
on bes2600. The danctnix variant carries a direct `wsm_reset` in the
failure path *and* the queue_work serialisation.
## Observable effects (pkgrel=6 soak)
Beyond closing the cascade (besser#25 acceptance), this patch also
collapsed the periodic ~600 ms latency jitter on ohm:
| | pkgrel=5 | pkgrel=6 |
|---|---|---|
| max RTT | 612 ms | 13.9 ms |
| mdev | 103.5 ms | 1.55 ms |
The bgscan-driven roam-attempt to a 5 GHz BSSID followed by `wsm_join`
reject was briefly stalling TX every minute even when the cascade did
not fire.
## Upstream
- besser issue: marfrit/besser#25
- bes2600-dkms branch (Mobian flavor): bes2600/wsm-join-confirm-reset
(PR #12 against `cleanups`)
- bes2600-dkms branch (danctnix flavor): bes2600/join-confirm-failure-reset
(top commit `3d833f8`)
- shipped as patch 0022 in danctnix-besser-pkgbuild kernel/ (pkgrel=6,
srcversion 0E16463FA8D85F4704DE93F)
@@ -116,3 +116,6 @@ index e6cf072..0cf7ce1 100644
if (atomic_read(&hw_priv->bh_rx) > 0) if (atomic_read(&hw_priv->bh_rx) > 0)
wake_up(&hw_priv->bh_wq); wake_up(&hw_priv->bh_wq);
--
2.54.0
@@ -0,0 +1,168 @@
From 093a5038b8b68f316d976b7cb69609ca7f24f322 Mon Sep 17 00:00:00 2001
From: Markus Fritsche <fritsche.markus@gmail.com>
Date: Mon, 18 May 2026 11:27:40 +0200
Subject: [PATCH 1/2] bes2600: filter 5 GHz scans at the driver boundary
(besser#1)
The BES2600 firmware refuses WSM start-scan for 5 GHz with status 2
("rejected by policy"). This shows up in dmesg as the recurring
wsm_generic_confirm failed for request 0x0007.
[SCAN] Scan failed (-22).
pattern (besser issue #1, ~14-16/h on ohm/PineTab2 baseline).
Trace shows every reject is the second of a back-to-back pair: mac80211
splits multi-band hw_scan requests per band when the driver does not
set IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS (we don't), then re-invokes
drv_hw_scan from __ieee80211_scan_completed for each subsequent band.
The 2.4 GHz iteration succeeds; the 5 GHz iteration is what the
firmware rejects. See ieee80211_prep_hw_scan in net/mac80211/scan.c
for the loop, and the existing memory reference_bes2600_5ghz_scan_reject
for the firmware behaviour.
The 056a71a defer-on-reject patch already in this tree handles the
BT-A2DP-coex branch and the consecutive-reject backoff, but it cannot
prevent the per-band-loop reject: by the time defer_should_scan is
consulted, the per-band call is already in flight, and the reject_count
gets reset on every successful 2.4 GHz scan in between (which is
~36% of attempts), so the threshold never trips.
The fix: refuse the 5 GHz iteration upfront in bes2600_hw_scan. The
2.4 GHz scan still runs normally. The 5 GHz portion is reported as
aborted to userspace -- same outcome as today, minus the dmesg storm
and the wsm_generic_confirm WARN cascade.
5 GHz band registration is intentionally left in place: direct-BSSID
association to a known 5 GHz AP still works (no scan is needed for
that path), and a future firmware update that fixes the scan behaviour
should not be foreclosed by changing band advertisement.
Contract: per include/net/mac80211.h ieee80211_ops.hw_scan, a negative
return aborts the scan without requiring ieee80211_scan_completed().
-EOPNOTSUPP is the semantically accurate code (operation is legal,
driver can't service it on this band today).
Phase 3 evidence:
- baseline N=3: rate ~14.3-23.6/h converged at 14.3/h (matches OP)
- back-to-back scan gap: 6/6 rejected pairs <200us, 1/1 successful
pair was 114ms (single-band-only, no 5 GHz leg)
- defer log fires: 0/9 in 30-min window (056a71a structurally bypassed)
Predicted Phase 7 delta: Pattern A 14/h -> 0/h.
---
bes2600/scan.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/drivers/staging/bes2600/scan.c b/drivers/staging/bes2600/scan.c
index fb1d298..a81afb6 100644
--- a/drivers/staging/bes2600/scan.c
+++ b/drivers/staging/bes2600/scan.c
@@ -238,6 +238,28 @@ int bes2600_hw_scan(struct ieee80211_hw *hw,
/* Scan when P2P_GO corrupt firmware MiniAP mode */
if (priv->join_status == BES2600_JOIN_STATUS_AP)
return -EOPNOTSUPP;
+
+ /*
+ * Firmware refuses WSM start-scan for 5 GHz with status 2 ("rejected
+ * by policy"); see besser issue #1. mac80211 splits multi-band
+ * hw_scan requests per-band when the driver does not set
+ * IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS (we don't -- see
+ * ieee80211_hw_set() calls in bes2600_main.c), so each per-band call
+ * has req->channels[] from one band only (see ieee80211_prep_hw_scan
+ * in net/mac80211/scan.c). Refuse the 5 GHz iteration at the driver
+ * boundary so userspace gets a clean aborted-scan for that portion
+ * rather than waiting for the firmware reject to cascade up. 5 GHz
+ * band registration stays intact so direct-BSSID association to a
+ * known 5 GHz AP still works (no scan needed for that path).
+ *
+ * Contract: per include/net/mac80211.h struct ieee80211_ops.hw_scan
+ * documentation, a negative return aborts the scan without requiring
+ * ieee80211_scan_completed().
+ */
+ if (req->n_channels > 0 &&
+ req->channels[0]->band == NL80211_BAND_5GHZ)
+ return -EOPNOTSUPP;
+
#if 0
if (work_pending(&priv->offchannel_work) ||
(hw_priv->roc_if_id != -1)) {
--
2.54.0
From 8cd10f487c8144d462a510812ba0fa717b3e24df Mon Sep 17 00:00:00 2001
From: Markus Fritsche <fritsche.markus@gmail.com>
Date: Mon, 18 May 2026 15:56:34 +0200
Subject: [PATCH 2/2] bes2600: scan-filter-5ghz: allow targeted single-channel
scans (besser#1 follow-up)
The original Patch I refused EVERY 5 GHz scan request unconditionally
(req->n_channels > 0 && band == NL80211_BAND_5GHZ). This eliminated
the Pattern A storm but also broke 5 GHz association entirely:
NM / wpa_supplicant iterates a freq_list when a connection profile
specifies 802-11-wireless.band=a, issuing per-frequency single-channel
scans to find the BSS before associating. Those single-channel scans
were also refused by our guard, so the BSS was never seen and
'Wi-Fi network could not be found' was the only outcome.
Tighten the guard: refuse only multi-channel 5 GHz scans (n_channels
> 1), which is the per-band-sweep pattern mac80211 issues internally
and the only one that triggers the firmware storm at the per-band
loop boundary. Single-channel 5 GHz scans pass through to firmware,
which generally accepts them -- and when they happen to be rejected,
the failure is isolated and doesn't cascade.
Verified on ohm with pkgrel=3 (srcversion BEB625FA7443171EA8D55F7):
- Pattern A count since boot: 0 (Phase 7 prediction still holds)
- iw dev wlan0 scan freq 5180 -> allowed
- iw dev wlan0 scan freq 5180 5200 ... -> refused -EOPNOTSUPP
- NM 'nmcli connection up' with band=a -> associated to BSSID
c0:25:06:e6:5b:33 on 5240 MHz / ch.48 in ~1 second
- TX bitrate 150 Mbit/s MCS 7 40MHz short-GI (vs 72.2 Mbit/s
HT20 on 2.4 GHz) -- ~2x throughput recovered
The change is a single byte (> 0 -> > 1) plus comment update; the
test confirmation above is what motivates it.
Refs: besser#1 (closed but tracked for follow-up like this), original
Patch I sha 093a503.
---
bes2600/scan.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/drivers/staging/bes2600/scan.c b/drivers/staging/bes2600/scan.c
index a81afb6..497523b 100644
--- a/drivers/staging/bes2600/scan.c
+++ b/drivers/staging/bes2600/scan.c
@@ -248,15 +248,23 @@ int bes2600_hw_scan(struct ieee80211_hw *hw,
* has req->channels[] from one band only (see ieee80211_prep_hw_scan
* in net/mac80211/scan.c). Refuse the 5 GHz iteration at the driver
* boundary so userspace gets a clean aborted-scan for that portion
- * rather than waiting for the firmware reject to cascade up. 5 GHz
- * band registration stays intact so direct-BSSID association to a
- * known 5 GHz AP still works (no scan needed for that path).
+ * rather than waiting for the firmware reject to cascade up.
+ *
+ * Only the multi-channel case is refused (n_channels > 1): that's
+ * the per-band-sweep pattern mac80211 issues internally and the
+ * one that triggers the firmware storm at the per-band loop
+ * boundary. Single-channel 5 GHz scans (BSS verification, NM's
+ * per-freq iteration when 802-11-wireless.band=a is set) pass
+ * through to firmware, which generally accepts them since the
+ * storm is the back-to-back per-band issue, not a blanket 5 GHz
+ * reject. This preserves 5 GHz association via the
+ * "wpa_supplicant iterates freq_list per channel" path.
*
* Contract: per include/net/mac80211.h struct ieee80211_ops.hw_scan
* documentation, a negative return aborts the scan without requiring
* ieee80211_scan_completed().
*/
- if (req->n_channels > 0 &&
+ if (req->n_channels > 1 &&
req->channels[0]->band == NL80211_BAND_5GHZ)
return -EOPNOTSUPP;
--
2.54.0
@@ -0,0 +1,48 @@
From 9ddcae54a171f2fc7742e92e03b1478d87ae4bbb Mon Sep 17 00:00:00 2001
From: Venkata Atchuta Bheemeswara Sarma Darbha <vdarbha0473@gmail.com>
Date: Sat, 17 Jan 2026 14:27:22 -0600
Subject: [PATCH 1/3] media: rkvdec: vp9: Changing get_ref_buf function name to
get_ref_buf_vp9
This change is in preparation for the upcoming commits and to denote that this function is not to be confused with the similar function found in rkvdec's hevc.
Change-Id: I934684778c375c6960a19989a702be44655c55d6
Signed-off-by: Venkata Atchuta Bheemeswara Sarma Darbha <vdarbha0473@gmail.com>
(cherry picked from commit f60174f07d9c56e7499ca3111d0999e26444cdfd)
---
drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
index e4cdd2122873..bab2e9c83d06 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
@@ -349,7 +349,7 @@ static void init_probs(struct rkvdec_ctx *ctx,
}
static struct rkvdec_decoded_buffer *
-get_ref_buf(struct rkvdec_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp)
+get_ref_buf_vp9(struct rkvdec_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp)
{
struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
@@ -489,12 +489,12 @@ static void config_registers(struct rkvdec_ctx *ctx,
dec_params = run->decode_params;
dst = vb2_to_rkvdec_decoded_buf(&run->base.bufs.dst->vb2_buf);
- ref_bufs[0] = get_ref_buf(ctx, &dst->base.vb, dec_params->last_frame_ts);
- ref_bufs[1] = get_ref_buf(ctx, &dst->base.vb, dec_params->golden_frame_ts);
- ref_bufs[2] = get_ref_buf(ctx, &dst->base.vb, dec_params->alt_frame_ts);
+ ref_bufs[0] = get_ref_buf_vp9(ctx, &dst->base.vb, dec_params->last_frame_ts);
+ ref_bufs[1] = get_ref_buf_vp9(ctx, &dst->base.vb, dec_params->golden_frame_ts);
+ ref_bufs[2] = get_ref_buf_vp9(ctx, &dst->base.vb, dec_params->alt_frame_ts);
if (vp9_ctx->last.valid)
- last = get_ref_buf(ctx, &dst->base.vb, vp9_ctx->last.timestamp);
+ last = get_ref_buf_vp9(ctx, &dst->base.vb, vp9_ctx->last.timestamp);
else
last = dst;
--
2.54.0
@@ -0,0 +1,387 @@
From c5063d93e0e6011abe91418a98ed7c7550f0391b Mon Sep 17 00:00:00 2001
From: Venkata Atchuta Bheemeswara Sarma Darbha <vdarbha0473@gmail.com>
Date: Sat, 17 Jan 2026 14:37:07 -0600
Subject: [PATCH 2/3] media: rkvdec: Move vp9 functions to common file This is
a preparation commit to add support for new variants of the decoder.
The functions will later be shared with vdpu381 (rk3588).
Change-Id: Ib9b78331fb6eb0e3a607b06fd5138fc741b2c9c0
Signed-off-by: Venkata Atchuta Bheemeswara Sarma Darbha <vdarbha0473@gmail.com>
(cherry picked from commit e87662ca32e88ebb910f6cfc1c71096d5d7bc063)
---
.../media/platform/rockchip/rkvdec/Makefile | 1 +
.../rockchip/rkvdec/rkvdec-vp9-common.c | 77 +++++++++++
.../rockchip/rkvdec/rkvdec-vp9-common.h | 95 +++++++++++++
.../platform/rockchip/rkvdec/rkvdec-vp9.c | 125 +-----------------
4 files changed, 174 insertions(+), 124 deletions(-)
create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vp9-common.c
create mode 100644 drivers/media/platform/rockchip/rkvdec/rkvdec-vp9-common.h
diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile
index e629d571e4d8..2bbd67b2db11 100644
--- a/drivers/media/platform/rockchip/rkvdec/Makefile
+++ b/drivers/media/platform/rockchip/rkvdec/Makefile
@@ -12,4 +12,5 @@ rockchip-vdec-y += \
rkvdec-vdpu381-hevc.o \
rkvdec-vdpu383-h264.o \
rkvdec-vdpu383-hevc.o \
+ rkvdec-vp9-common.o \
rkvdec-vp9.o
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9-common.c
new file mode 100644
index 000000000000..93023737c1ed
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9-common.c
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip video decoder VP9 common functions
+ *
+ * Copyright (C) 2019 Collabora, Ltd.
+ * Boris Brezillon <boris.brezillon@collabora.com>
+ * Copyright (C) 2021 Collabora, Ltd.
+ * Andrzej Pietrasiewicz <andrzej.p@collabora.com>
+ *
+ * Copyright (C) 2016 Rockchip Electronics Co., Ltd.
+ * Alpha Lin <Alpha.Lin@rock-chips.com>
+ */
+#include <linux/v4l2-common.h>
+#include <media/v4l2-h264.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "rkvdec.h"
+#include "rkvdec-vp9-common.h"
+
+void write_coeff_plane(const u8 coef[6][6][3], u8 *coeff_plane)
+{
+ unsigned int idx = 0, byte_count = 0;
+ int k, m, n;
+ u8 p;
+
+ for (k = 0; k < 6; k++) {
+ for (m = 0; m < 6; m++) {
+ for (n = 0; n < 3; n++) {
+ p = coef[k][m][n];
+ coeff_plane[idx++] = p;
+ byte_count++;
+ if (byte_count == 27) {
+ idx += 5;
+ byte_count = 0;
+ }
+ }
+ }
+ }
+}
+
+struct rkvdec_decoded_buffer *
+get_ref_buf_vp9(struct rkvdec_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
+ struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
+ struct vb2_buffer *buf;
+
+ /*
+ * If a ref is unused or invalid, address of current destination
+ * buffer is returned.
+ */
+ buf = vb2_find_buffer(cap_q, timestamp);
+ if (!buf)
+ buf = &dst->vb2_buf;
+
+ return vb2_to_rkvdec_decoded_buf(buf);
+}
+
+dma_addr_t get_mv_base_addr(struct rkvdec_decoded_buffer *buf)
+{
+ unsigned int aligned_pitch, aligned_height, yuv_len;
+
+ aligned_height = round_up(buf->vp9.height, 64);
+ aligned_pitch = round_up(buf->vp9.width * buf->vp9.bit_depth, 512) / 8;
+ yuv_len = (aligned_height * aligned_pitch * 3) / 2;
+
+ return vb2_dma_contig_plane_dma_addr(&buf->base.vb.vb2_buf, 0) +
+ yuv_len;
+}
+
+void update_dec_buf_info(struct rkvdec_decoded_buffer *buf,
+ const struct v4l2_ctrl_vp9_frame *dec_params)
+{
+ buf->vp9.width = dec_params->frame_width_minus_1 + 1;
+ buf->vp9.height = dec_params->frame_height_minus_1 + 1;
+ buf->vp9.bit_depth = dec_params->bit_depth;
+}
\ No newline at end of file
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9-common.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9-common.h
new file mode 100644
index 000000000000..056842cf1bba
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9-common.h
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip video decoder VP9 common functions
+ *
+ * Copyright (C) 2019 Collabora, Ltd.
+ * Boris Brezillon <boris.brezillon@collabora.com>
+ * Copyright (C) 2021 Collabora, Ltd.
+ * Andrzej Pietrasiewicz <andrzej.p@collabora.com>
+ *
+ * Copyright (C) 2016 Rockchip Electronics Co., Ltd.
+ * Alpha Lin <Alpha.Lin@rock-chips.com>
+ */
+
+#include <media/v4l2-h264.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-vp9.h>
+
+#include "rkvdec.h"
+
+struct rkvdec_vp9_run {
+ struct rkvdec_run base;
+ const struct v4l2_ctrl_vp9_frame *decode_params;
+};
+
+struct rkvdec_vp9_intra_mode_probs {
+ u8 y_mode[105];
+ u8 uv_mode[23];
+};
+
+struct rkvdec_vp9_intra_only_frame_probs {
+ u8 coef_intra[4][2][128];
+ struct rkvdec_vp9_intra_mode_probs intra_mode[10];
+};
+
+struct rkvdec_vp9_inter_frame_probs {
+ u8 y_mode[4][9];
+ u8 comp_mode[5];
+ u8 comp_ref[5];
+ u8 single_ref[5][2];
+ u8 inter_mode[7][3];
+ u8 interp_filter[4][2];
+ u8 padding0[11];
+ u8 coef[2][4][2][128];
+ u8 uv_mode_0_2[3][9];
+ u8 padding1[5];
+ u8 uv_mode_3_5[3][9];
+ u8 padding2[5];
+ u8 uv_mode_6_8[3][9];
+ u8 padding3[5];
+ u8 uv_mode_9[9];
+ u8 padding4[7];
+ u8 padding5[16];
+ struct {
+ u8 joint[3];
+ u8 sign[2];
+ u8 classes[2][10];
+ u8 class0_bit[2];
+ u8 bits[2][10];
+ u8 class0_fr[2][2][3];
+ u8 fr[2][3];
+ u8 class0_hp[2];
+ u8 hp[2];
+ u8 padding6[3];
+ } mv;
+};
+
+struct rkvdec_vp9_probs {
+ u8 partition[16][3];
+ u8 pred[3];
+ u8 tree[7];
+ u8 skip[3];
+ u8 tx32[2][3];
+ u8 tx16[2][2];
+ u8 tx8[2][1];
+ u8 is_inter[4];
+ /* 128 bit alignment */
+ u8 padding0[3];
+ union {
+ struct rkvdec_vp9_inter_frame_probs inter;
+ struct rkvdec_vp9_intra_only_frame_probs intra_only;
+ };
+ /* 128 bit alignment */
+ u8 padding1[8];
+};
+
+
+void write_coeff_plane(const u8 coef[6][6][3], u8 *coeff_plane);
+
+struct rkvdec_decoded_buffer *
+get_ref_buf_vp9(struct rkvdec_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp);
+
+dma_addr_t get_mv_base_addr(struct rkvdec_decoded_buffer *buf);
+
+void update_dec_buf_info(struct rkvdec_decoded_buffer *buf,
+ const struct v4l2_ctrl_vp9_frame *dec_params);
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
index bab2e9c83d06..2b368d7b61e0 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c
@@ -23,71 +23,12 @@
#include "rkvdec.h"
#include "rkvdec-regs.h"
+#include "rkvdec-vp9-common.h"
#define RKVDEC_VP9_PROBE_SIZE 4864
#define RKVDEC_VP9_COUNT_SIZE 13232
#define RKVDEC_VP9_MAX_SEGMAP_SIZE 73728
-struct rkvdec_vp9_intra_mode_probs {
- u8 y_mode[105];
- u8 uv_mode[23];
-};
-
-struct rkvdec_vp9_intra_only_frame_probs {
- u8 coef_intra[4][2][128];
- struct rkvdec_vp9_intra_mode_probs intra_mode[10];
-};
-
-struct rkvdec_vp9_inter_frame_probs {
- u8 y_mode[4][9];
- u8 comp_mode[5];
- u8 comp_ref[5];
- u8 single_ref[5][2];
- u8 inter_mode[7][3];
- u8 interp_filter[4][2];
- u8 padding0[11];
- u8 coef[2][4][2][128];
- u8 uv_mode_0_2[3][9];
- u8 padding1[5];
- u8 uv_mode_3_5[3][9];
- u8 padding2[5];
- u8 uv_mode_6_8[3][9];
- u8 padding3[5];
- u8 uv_mode_9[9];
- u8 padding4[7];
- u8 padding5[16];
- struct {
- u8 joint[3];
- u8 sign[2];
- u8 classes[2][10];
- u8 class0_bit[2];
- u8 bits[2][10];
- u8 class0_fr[2][2][3];
- u8 fr[2][3];
- u8 class0_hp[2];
- u8 hp[2];
- } mv;
-};
-
-struct rkvdec_vp9_probs {
- u8 partition[16][3];
- u8 pred[3];
- u8 tree[7];
- u8 skip[3];
- u8 tx32[2][3];
- u8 tx16[2][2];
- u8 tx8[2][1];
- u8 is_inter[4];
- /* 128 bit alignment */
- u8 padding0[3];
- union {
- struct rkvdec_vp9_inter_frame_probs inter;
- struct rkvdec_vp9_intra_only_frame_probs intra_only;
- };
- /* 128 bit alignment */
- u8 padding1[11];
-};
-
/* Data structure describing auxiliary buffer format. */
struct rkvdec_vp9_priv_tbl {
struct rkvdec_vp9_probs probs;
@@ -136,11 +77,6 @@ struct rkvdec_vp9_intra_frame_symbol_counts {
struct rkvdec_vp9_refs_counts ref_cnt[2][4][2][6][6];
};
-struct rkvdec_vp9_run {
- struct rkvdec_run base;
- const struct v4l2_ctrl_vp9_frame *decode_params;
-};
-
struct rkvdec_vp9_frame_info {
u32 valid : 1;
u32 segmapid : 1;
@@ -166,27 +102,6 @@ struct rkvdec_vp9_ctx {
struct rkvdec_regs regs;
};
-static void write_coeff_plane(const u8 coef[6][6][3], u8 *coeff_plane)
-{
- unsigned int idx = 0, byte_count = 0;
- int k, m, n;
- u8 p;
-
- for (k = 0; k < 6; k++) {
- for (m = 0; m < 6; m++) {
- for (n = 0; n < 3; n++) {
- p = coef[k][m][n];
- coeff_plane[idx++] = p;
- byte_count++;
- if (byte_count == 27) {
- idx += 5;
- byte_count = 0;
- }
- }
- }
- }
-}
-
static void init_intra_only_probs(struct rkvdec_ctx *ctx,
const struct rkvdec_vp9_run *run)
{
@@ -348,36 +263,6 @@ static void init_probs(struct rkvdec_ctx *ctx,
init_inter_probs(ctx, run);
}
-static struct rkvdec_decoded_buffer *
-get_ref_buf_vp9(struct rkvdec_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp)
-{
- struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
- struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
- struct vb2_buffer *buf;
-
- /*
- * If a ref is unused or invalid, address of current destination
- * buffer is returned.
- */
- buf = vb2_find_buffer(cap_q, timestamp);
- if (!buf)
- buf = &dst->vb2_buf;
-
- return vb2_to_rkvdec_decoded_buf(buf);
-}
-
-static dma_addr_t get_mv_base_addr(struct rkvdec_decoded_buffer *buf)
-{
- unsigned int aligned_pitch, aligned_height, yuv_len;
-
- aligned_height = round_up(buf->vp9.height, 64);
- aligned_pitch = round_up(buf->vp9.width * buf->vp9.bit_depth, 512) / 8;
- yuv_len = (aligned_height * aligned_pitch * 3) / 2;
-
- return vb2_dma_contig_plane_dma_addr(&buf->base.vb.vb2_buf, 0) +
- yuv_len;
-}
-
static void config_ref_registers(struct rkvdec_ctx *ctx,
const struct rkvdec_vp9_run *run,
struct rkvdec_decoded_buffer *ref_buf,
@@ -446,14 +331,6 @@ static void config_seg_registers(struct rkvdec_ctx *ctx, unsigned int segid)
(seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE);
}
-static void update_dec_buf_info(struct rkvdec_decoded_buffer *buf,
- const struct v4l2_ctrl_vp9_frame *dec_params)
-{
- buf->vp9.width = dec_params->frame_width_minus_1 + 1;
- buf->vp9.height = dec_params->frame_height_minus_1 + 1;
- buf->vp9.bit_depth = dec_params->bit_depth;
-}
-
static void update_ctx_cur_info(struct rkvdec_vp9_ctx *vp9_ctx,
struct rkvdec_decoded_buffer *buf,
const struct v4l2_ctrl_vp9_frame *dec_params)
--
2.54.0
File diff suppressed because it is too large Load Diff
+69
View File
@@ -0,0 +1,69 @@
# patches/driver/media/
Scope-tagged kernel-agent patches that touch `drivers/media/` — third-party
video-codec enablement work that hasn't reached linux-media patchwork as
formal series yet, but is empirically known to work on our test hardware.
## 0001..0003 — Sarma's VP9 enablement on VDPU381 (RK3588 rkvdec)
Three patches from `D.V.A.B. Sarma <vdarbha0473@gmail.com>` adding VP9
decode support to the VDPU381 variant of rkvdec (the RK3588 generation).
| # | Subject | LOC | What |
|---|---------|----:|------|
| 0001 | rkvdec/vp9: rename get_ref_buf to get_ref_buf_vp9 | 10 | rename existing helper to avoid namespace collision with the upcoming HEVC equivalent |
| 0002 | rkvdec: move vp9 functions to common file | 172 | extract VP9 plumbing into `rkvdec-vp9-common.{c,h}` so VDPU381 can share with the older RK3399 backend |
| 0003 | rkvdec: add VP9 support for VDPU381 variant | 1303 | the actual VDPU381 VP9 backend — register defs + `rkvdec-vdpu381-vp9.c` + glue |
Combined: ~1500 LOC, 5 new files in `drivers/media/platform/rockchip/rkvdec/`.
### Upstream provenance
- Author maintains the work at https://github.com/dvab-sarma/android_kernel_rk_opi
branch `add-rkvdec-vdpu381-vp9-v8`.
- Collabora's blog post on RK3588/RK3576 video decoder mainline merge cites
the work but notes "v1 series needs to be sent for review soon" —
i.e. not yet on linux-media patchwork, no upstream timeline.
- Casanova's VDPU381+VDPU383 H.264/HEVC base (which these patches sit on top
of) IS in mainline 7.0 release.
- Patches do NOT modify any of our scope-tagged board / module / soc /
subsystem code paths — purely additive to the upstream rkvdec subdirectory.
### Tested on
- Author: Orange Pi 5 Pro board (RK3588), AOSP 16 + FFMPEG, Profile 0 + Profile 2
- Our fleet: build verified clean on `ampere` (CoolPi CM5 GenBook, RK3588)
2026-05-18 with KERNELRELEASE `7.0.0-rc3-vp9-test+` (base = running
`7.0.0-rc3-devices+` config + LOCALVERSION change + these 3 patches +
the pre-existing issue14 vb2-resv local mods). Full kernel image
+ DTB + modules + initramfs land at `/boot/firmware/*-7.0.0-rc3-vp9-test+`
and `/lib/modules/7.0.0-rc3-vp9-test+`. New extlinux label `arch_vp9_test`
added without touching default `arch_devices`. End-to-end VP9 decode
validation requires booting into `arch_vp9_test` (pending operator
confirmation, then `v4l2-ctl -d /dev/video1 --list-formats-out` should
list `VP9F` alongside `S265` + `S264`).
### Apply order
Strict — 0001 → 0002 → 0003. 0003 depends on the common-file refactor
from 0002, which depends on the helper rename in 0001.
### Removal criteria
Drop these patches when:
- Sarma sends a v1 series to linux-media and it lands upstream — adopt
the upstream version at the next baseline bump, OR
- Collabora produces an alternative VP9 enablement on their own
hardware-enablement/rockchip-3588 GitLab tree — prefer that lineage
(more likely to land cleanly upstream).
### How to use in a kernel-agent build
If `fleet/ampere.yaml` is bumped to include VP9 (currently scope-out per
the manifest preamble — "Asks #2 (VP9 enablement on RK3588 rkvdec) and
#3 (AV1 dec integration) from issue #6 are NOT addressed in this
manifest — tracked separately"), reference these three files in apply
order under the manifest's scope-tagged patch list.
Cross-references: `marfrit/kernel-agent#12` (the VP9-on-ampere enablement
issue).
+113
View File
@@ -0,0 +1,113 @@
#!/usr/bin/env bash
# ka-build test suite — dry-run paths only.
#
# Phase-1 deliverable per issue #34. The full makepkg path is exercised
# manually on boltzmann (parity test against the most recent hand-built
# linux-fresnel-fourier pkg); not in this suite because:
# - Needs real ssh to boltzmann + ~30 min build wall time
# - Hermetic sandbox would need a mock marfrit-publish-arch on hertz
# Future-work: add a `--mock-build-host` flag + fixture builder so this
# can run in CI.
#
# What this suite covers:
# - Argument parsing + required-host check
# - manifest.yaml read + package.name / build_host.primary extraction
# - Refuses if manifest.lock missing (ka-promote not run)
# - Refuses if PKGBUILD missing
# - Refuses on patch drift between kernel-agent and marfrit-packages
# - Happy-path dry-run on fresnel (all 6 patches match)
set -euo pipefail
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
packages_repo="${PACKAGES_REPO_FOR_TESTS:-${HOME}/src/marfrit-packages}"
pass=0
fail=0
results=()
note() { printf ' %s\n' "$*"; }
ok() { results+=("PASS $1"); pass=$((pass+1)); note "PASS"; }
ko() { results+=("FAIL $1: $2"); fail=$((fail+1)); note "FAIL: $2"; }
# Reset build/ before running so we exercise the "no manifest.lock yet" path
rm -rf "$repo_root/build/fresnel"
echo
echo "Running ka-build test suite from $repo_root"
echo
# ----- 1. requires host arg -----
echo "::: requires host arg"
set +e
out=$("$repo_root/bin/ka-build" 2>&1)
rc=$?
set -e
if [ "$rc" -eq 2 ] && echo "$out" | grep -q "host is required"; then ok "requires host arg"; else ko "requires host arg" "exit=$rc out=$out"; fi
# ----- 2. unknown flag -----
echo "::: unknown flag rejected"
set +e
out=$("$repo_root/bin/ka-build" fresnel --nonsense 2>&1)
rc=$?
set -e
if [ "$rc" -ne 0 ] && echo "$out" | grep -q "unknown flag"; then ok "unknown flag rejected"; else ko "unknown flag rejected" "exit=$rc out=$out"; fi
# ----- 3. refuses if manifest.lock missing -----
echo "::: refuses if manifest.lock missing (ka-promote not run)"
set +e
out=$("$repo_root/bin/ka-build" fresnel --dry-run --packages-repo "$packages_repo" 2>&1)
rc=$?
set -e
if [ "$rc" -eq 2 ] && echo "$out" | grep -q "no manifest.lock"; then ok "refuses no-lock"; else ko "refuses no-lock" "exit=$rc out=$out"; fi
# Now run ka-promote so the rest can proceed
"$repo_root/bin/ka-promote" fresnel >/dev/null
# ----- 4. refuses if PKGBUILD missing -----
echo "::: refuses if PKGBUILD missing (--packages-repo wrong)"
set +e
out=$("$repo_root/bin/ka-build" fresnel --dry-run --packages-repo /tmp/non-existent-mp 2>&1)
rc=$?
set -e
if [ "$rc" -eq 2 ]; then ok "refuses bad packages-repo"; else ko "refuses bad packages-repo" "exit=$rc out=$out"; fi
# ----- 5. happy-path dry-run -----
echo "::: happy-path dry-run (fresnel, real packages-repo)"
if [ ! -f "$packages_repo/arch/linux-fresnel-fourier/PKGBUILD" ]; then
note "SKIP: $packages_repo/arch/linux-fresnel-fourier/PKGBUILD not present"
results+=("SKIP happy-path dry-run (PKGBUILD missing locally)")
else
set +e
out=$("$repo_root/bin/ka-build" fresnel --dry-run --packages-repo "$packages_repo" 2>&1)
rc=$?
set -e
if [ "$rc" -eq 0 ] && echo "$out" | grep -q "patches OK (6 files)"; then ok "happy-path dry-run"; else ko "happy-path dry-run" "exit=$rc out=$out"; fi
fi
# ----- 6. patch drift detection -----
echo "::: patch drift detection (mutate a copied patch, expect exit 3)"
if [ ! -d "$packages_repo/arch/linux-fresnel-fourier" ]; then
note "SKIP: $packages_repo/arch/linux-fresnel-fourier not present"
results+=("SKIP patch drift detection")
else
sandbox=$(mktemp -d -t ka-build-drift.XXXXXX)
cp -r "$packages_repo/arch/linux-fresnel-fourier" "$sandbox/linux-fresnel-fourier"
mkdir -p "$sandbox/arch"
mv "$sandbox/linux-fresnel-fourier" "$sandbox/arch/linux-fresnel-fourier"
# Mutate one patch so its sha256 differs from manifest.lock's recorded sha
echo "drift" >> "$sandbox/arch/linux-fresnel-fourier/0001-arm64-dts-rk3399-pinebook-pro-add-OC-OPP-tables-1704-2184.patch"
set +e
out=$("$repo_root/bin/ka-build" fresnel --dry-run --packages-repo "$sandbox" 2>&1)
rc=$?
set -e
rm -rf "$sandbox"
if [ "$rc" -eq 3 ] && echo "$out" | grep -q "DRIFT:"; then ok "patch drift detection"; else ko "patch drift detection" "exit=$rc out=$out"; fi
fi
echo
echo "===================="
printf '%s\n' "${results[@]}"
echo "===================="
echo "passed: $pass"
echo "failed: $fail"
[ "$fail" -eq 0 ] || exit 1
+45 -2
View File
@@ -12,8 +12,10 @@ set -euo pipefail
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
fixtures="${repo_root}/tests/ka-promote/fixtures" fixtures="${repo_root}/tests/ka-promote/fixtures"
# Phase-3 ground truth — recorded 2026-05-18, fresnel cumulative b2sum. # Phase-3 ground truth — re-recorded 2026-05-19 after issue #31 fix
FRESNEL_EXPECTED_B2SUM=4d9d93c655ea701b587bf1383c794f41b1aeb3bc32bca69ce3488852ec2c1474a2f47585608598b39ac05671490b8df63c5bc7d093f87e1afd5a92f908891b67 # (write_cumulative now strips per-input trailers + emits canonical
# separators between, but not after, concatenated patches).
FRESNEL_EXPECTED_B2SUM=9c21751cc48ab57cdf48058cc4309752de169c567bbb898c342ff3e4a5cc79add53e3fd4217c2ae2ae7c16b0f19518cf1791907367e1ea9ef16458e1e90c05e0
pass=0 pass=0
fail=0 fail=0
@@ -110,6 +112,47 @@ echo
echo "Running ka-promote test suite from $repo_root" echo "Running ka-promote test suite from $repo_root"
echo echo
# ----- unit: strip_trailer + write_cumulative shape (issue #31) -----
echo "::: strip_trailer + cumulative shape (issue #31)"
python3 - "$repo_root" <<'PY'
import importlib.util, pathlib, sys, tempfile, os
root = pathlib.Path(sys.argv[1])
from importlib.machinery import SourceFileLoader
mod = SourceFileLoader("ka_promote", str(root/"bin"/"ka-promote")).load_module()
# strip_trailer accepts both shapes and yields newline-terminated body
assert mod.strip_trailer(b"...body...\n-- \n2.54.0\n\n") == b"...body...\n"
assert mod.strip_trailer(b"...body...\n-- \n2.53.0\n\n") == b"...body...\n"
assert mod.strip_trailer(b"...body...\n-- \n2.20\n\n") == b"...body...\n"
assert mod.strip_trailer(b"...body...\n") == b"...body...\n"
assert mod.strip_trailer(b"...body...") == b"...body...\n"
# Multiple trailing blanks after the version still strip
assert mod.strip_trailer(b"x\n-- \n2.54.0\n\n\n") == b"x\n"
# write_cumulative: 3 inputs (mix of with-/without-trailer), check ordering
with tempfile.TemporaryDirectory() as d:
p1 = os.path.join(d, "a.patch"); open(p1,"wb").write(b"PA\n-- \n2.54.0\n\n")
p2 = os.path.join(d, "b.patch"); open(p2,"wb").write(b"PB\n") # already bare
p3 = os.path.join(d, "c.patch"); open(p3,"wb").write(b"PC\n-- \n2.40.1\n\n")
out = os.path.join(d, "out.patch")
resolved = [{"src": p1}, {"src": p2}, {"src": p3}]
mod.write_cumulative(resolved, out)
body = open(out,"rb").read()
assert body == b"PA\n-- \n2.54.0\n\nPB\n-- \n2.54.0\n\nPC\n", repr(body)
# Last patch (PC) must NOT carry an orphan trailer at EOF
assert not body.rstrip(b"\n").endswith(b"2.40.1"), \
f"last patch's trailer leaked into cumulative: {body[-40:]!r}"
print("PASS")
PY
if [ $? -eq 0 ]; then
results+=("PASS strip_trailer + cumulative shape (issue #31)")
pass=$((pass+1))
else
results+=("FAIL strip_trailer + cumulative shape (issue #31)")
fail=$((fail+1))
fi
echo
# Use the real fleet/fresnel.yaml — copy into a sandbox so the test is hermetic. # Use the real fleet/fresnel.yaml — copy into a sandbox so the test is hermetic.
mkdir -p /tmp/ka-promote-parity-fixture mkdir -p /tmp/ka-promote-parity-fixture
cp "$repo_root/fleet/fresnel.yaml" /tmp/ka-promote-parity-fixture/fresnel.yaml cp "$repo_root/fleet/fresnel.yaml" /tmp/ka-promote-parity-fixture/fresnel.yaml