From 88ecd36e3a4c038b94f2c3339e4da409119d9116 Mon Sep 17 00:00:00 2001 From: vasilito Date: Sat, 25 Jul 2026 00:18:40 +0900 Subject: [PATCH] firmware: split redbear-firmware into per-vendor recipes Closes the v4.0 plan P3 'per-vendor firmware packaging' item. redbear-firmware (the single bundle recipe) shipped the entire linux-firmware tarball wholesale. That works but forces every image to drag in blobs it does not use (e.g., a serial console image pulls amdgpu GPU firmware). The plan called for per-vendor splits mirroring linux-firmware's per-package convention (linux-firmware-amdgpu, linux-firmware-intel, etc.). New recipes (all version 0.3.1, Cat 1, locally maintainable): redbear-firmware-amdgpu - /lib/firmware/amdgpu/ + amdnpu/ redbear-firmware-intel - /lib/firmware/i915/ + intel/ redbear-firmware-iwlwifi - /lib/firmware/iwlwifi-*.{ucode,pnvm} redbear-firmware-bluetooth - /lib/firmware/ibt-*.{sfi,ddc} Each recipe downloads the same linux-firmware-main tarball into a shared cookbook cache (build/redbear-firmware-cache/) and stages only its subset, with the matching LICENSE.* and WHENCE metadata in /lib/firmware/LICENSES/. The share cache means a single wget per cookbook build regardless of how many per-vendor recipes are included. redbear-firmware (the whole bundle) stays in place for legacy configs that don't want to choose. Per-vendor recipes do not conflict with it because the subsets are disjoint paths under /lib/firmware. redbear-driver-policy/initfs.manifest gains a [firmware] section documenting the per-vendor recipe -> driver mapping. driver-manager itself does not install firmware -- configs pull the relevant redbear-firmware-* packages via the [packages] section. fetch-firmware.sh already supports the same per-vendor / per-subset matrix (--vendor {amd,intel} --subset {all,rdna,dmc,wifi,bluetooth}) so the manual fetch path and the build path now agree on taxonomy. --- .../source/policy/initfs.manifest | 18 +++++ .../redbear-firmware-amdgpu/recipe.toml | 69 ++++++++++++++++++ .../redbear-firmware-bluetooth/recipe.toml | 64 +++++++++++++++++ .../system/redbear-firmware-intel/recipe.toml | 68 ++++++++++++++++++ .../redbear-firmware-iwlwifi/recipe.toml | 70 +++++++++++++++++++ 5 files changed, 289 insertions(+) create mode 100644 local/recipes/system/redbear-firmware-amdgpu/recipe.toml create mode 100644 local/recipes/system/redbear-firmware-bluetooth/recipe.toml create mode 100644 local/recipes/system/redbear-firmware-intel/recipe.toml create mode 100644 local/recipes/system/redbear-firmware-iwlwifi/recipe.toml diff --git a/local/recipes/system/redbear-driver-policy/source/policy/initfs.manifest b/local/recipes/system/redbear-driver-policy/source/policy/initfs.manifest index 9fc2e67bfc..a51981946c 100644 --- a/local/recipes/system/redbear-driver-policy/source/policy/initfs.manifest +++ b/local/recipes/system/redbear-driver-policy/source/policy/initfs.manifest @@ -14,6 +14,24 @@ # Pre-driver staged microcode load (executed by kernel before any driver binds). microcode = ["amd-ucode", "intel-ucode"] +[firmware] +# Per-vendor firmware package mapping. driver-manager does not install +# firmware directly; configs pull in the relevant redbear-firmware-* +# packages via the [packages] section. This table is documentation: +# the firmware-loader scheme resolves /lib/firmware/ requests at +# runtime, regardless of which package staged the file. +# +# Per-vendor recipe | Driver(s) | Source subset +# ------------------+-----------------------+--------------- +# redbear-firmware-amdgpu | redox-drm (AMD) | amdgpu/, amdnpu/ +# redbear-firmware-intel | redox-drm (Intel) | i915/, intel/ +# redbear-firmware-iwlwifi | redbear-iwlwifi | iwlwifi-*.ucode, *.pnvm +# redbear-firmware-bluetooth | redbear-btusb (Intel) | ibt-*.sfi, ibt-*.ddc +# redbear-firmware | meta (ships everything) | whole linux-firmware +# +# Configs SHOULD prefer the per-vendor recipes for smaller images. +# redbear-firmware (the all-in-one) is kept for legacy configs and dev. + [policy] # Driver-policy file (modprobe.d equivalent) loaded before any driver binds. # This is /etc/driver-manager.d/00-blacklist.conf. diff --git a/local/recipes/system/redbear-firmware-amdgpu/recipe.toml b/local/recipes/system/redbear-firmware-amdgpu/recipe.toml new file mode 100644 index 0000000000..40ca0453b2 --- /dev/null +++ b/local/recipes/system/redbear-firmware-amdgpu/recipe.toml @@ -0,0 +1,69 @@ +[package] +name = "redbear-firmware-amdgpu" +version = "0.3.1" +description = "AMD GPU firmware (amdgpu + amdnpu subsets from linux-firmware)" + +[source] +path = "source" +upstream = "https://gitlab.com/kernel-firmware/linux-firmware.git" + +[build] +template = "custom" +dependencies = ["driver-manager-config"] +script = """ +set -eo pipefail + +FIRMWARE_URL="https://gitlab.com/kernel-firmware/linux-firmware/-/archive/main/linux-firmware-main.tar.gz" +CACHE_DIR="\${COOKBOOK_ROOT}/build/redbear-firmware-cache" +ARCHIVE="\${CACHE_DIR}/linux-firmware-main.tar.gz" +EXTRACTED="\${CACHE_DIR}/linux-firmware-main" + +mkdir -p "\${CACHE_DIR}" + +if [ ! -f "\${ARCHIVE}" ]; then + if [ "\${REPO_OFFLINE:-1}" = "1" ] && [ -z "\${REDBEAR_ALLOW_UPSTREAM:-}" ]; then + echo "ERROR: redbear-firmware-amdgpu requires network access but REPO_OFFLINE=1." >&2 + echo " Set REPO_OFFLINE=0 or pass REDBEAR_ALLOW_UPSTREAM=1." >&2 + exit 1 + fi + wget -O "\${ARCHIVE}" "\${FIRMWARE_URL}" +fi + +if [ ! -d "\${EXTRACTED}" ]; then + mkdir -p "\${EXTRACTED}" + tar -xf "\${ARCHIVE}" -C "\${EXTRACTED}" --strip-components=1 +fi + +STAGE="\${COOKBOOK_STAGE}/lib/firmware" +mkdir -p "\${STAGE}" +mkdir -p "\${STAGE}/LICENSES" + +# AMD GPU subset: amdgpu, amdnpu. The amdgpu package needs both: +# - /lib/firmware/amdgpu/ (modern GPU firmware blobs) +# - /lib/firmware/amdnpu/ (NPU firmware blobs, optional) +for vendor_dir in amdgpu amdnpu; do + src="\${EXTRACTED}/\${vendor_dir}" + if [ -d "\${src}" ]; then + cp -r "\${src}" "\${STAGE}/" + fi +done + +# License metadata for the staged blobs. +for license_file in LICENSE.amdgpu LICENSE.amdnpu WHENCE; do + if [ -f "\${EXTRACTED}/\${license_file}" ]; then + install -Dm0644 "\${EXTRACTED}/\${license_file}" "\${STAGE}/LICENSES/\${license_file}" + fi +done + +cat > "\${STAGE}/LICENSES/redbear-firmware-amdgpu.txt" <<'EOF' +Red Bear firmware bundle: AMD GPU subset +========================================= + +This package stages only the AMD GPU firmware subset from upstream +linux-firmware: + - amdgpu/ -- AMD GPU display/compute firmware blobs + - amdnpu/ -- AMD NPU firmware blobs + +Licenses vary by file; see WHENCE and LICENSE.* upstream. +EOF +""" diff --git a/local/recipes/system/redbear-firmware-bluetooth/recipe.toml b/local/recipes/system/redbear-firmware-bluetooth/recipe.toml new file mode 100644 index 0000000000..1e03f2f0dd --- /dev/null +++ b/local/recipes/system/redbear-firmware-bluetooth/recipe.toml @@ -0,0 +1,64 @@ +[package] +name = "redbear-firmware-bluetooth" +version = "0.3.1" +description = "Intel Bluetooth ibt firmware (.sfi and .ddc blobs)" + +[source] +path = "source" +upstream = "https://gitlab.com/kernel-firmware/linux-firmware.git" + +[build] +template = "custom" +dependencies = ["driver-manager-config"] +script = """ +set -eo pipefail + +FIRMWARE_URL="https://gitlab.com/kernel-firmware/linux-firmware/-/archive/main/linux-firmware-main.tar.gz" +CACHE_DIR="\${COOKBOOK_ROOT}/build/redbear-firmware-cache" +ARCHIVE="\${CACHE_DIR}/linux-firmware-main.tar.gz" +EXTRACTED="\${CACHE_DIR}/linux-firmware-main" + +mkdir -p "\${CACHE_DIR}" + +if [ ! -f "\${ARCHIVE}" ]; then + if [ "\${REPO_OFFLINE:-1}" = "1" ] && [ -z "\${REDBEAR_ALLOW_UPSTREAM:-}" ]; then + echo "ERROR: redbear-firmware-bluetooth requires network access but REPO_OFFLINE=1." >&2 + echo " Set REPO_OFFLINE=0 or pass REDBEAR_ALLOW_UPSTREAM=1." >&2 + exit 1 + fi + wget -O "\${ARCHIVE}" "\${FIRMWARE_URL}" +fi + +if [ ! -d "\${EXTRACTED}" ]; then + mkdir -p "\${EXTRACTED}" + tar -xf "\${ARCHIVE}" -C "\${EXTRACTED}" --strip-components=1 +fi + +STAGE="\${COOKBOOK_STAGE}/lib/firmware" +mkdir -p "\${STAGE}" +mkdir -p "\${STAGE}/LICENSES" + +# Intel Bluetooth subset: ibt-*.sfi and ibt-*.ddc blobs. +for f in "\${EXTRACTED}"/ibt-*.sfi "\${EXTRACTED}"/ibt-*.ddc; do + [ -f "\$f" ] || continue + install -Dm0644 "\$f" "\${STAGE}/$(basename "\$f")" +done + +# License metadata. +for license_file in LICENCE.ibt_firmware WHENCE; do + if [ -f "\${EXTRACTED}/\${license_file}" ]; then + install -Dm0644 "\${EXTRACTED}/\${license_file}" "\${STAGE}/LICENSES/\${license_file}" + fi +done + +cat > "\${STAGE}/LICENSES/redbear-firmware-bluetooth.txt" <<'EOF' +Red Bear firmware bundle: Intel Bluetooth subset +================================================ + +This package stages only the Intel Bluetooth firmware from upstream +linux-firmware: ibt-*.sfi (sequencer firmware) and ibt-*.ddc (device +description blobs). + +License: see LICENCE.ibt_firmware upstream. +EOF +""" diff --git a/local/recipes/system/redbear-firmware-intel/recipe.toml b/local/recipes/system/redbear-firmware-intel/recipe.toml new file mode 100644 index 0000000000..71b569fbaa --- /dev/null +++ b/local/recipes/system/redbear-firmware-intel/recipe.toml @@ -0,0 +1,68 @@ +[package] +name = "redbear-firmware-intel" +version = "0.3.1" +description = "Intel firmware subsets (i915 DMC + sound + VPU + ISH)" + +[source] +path = "source" +upstream = "https://gitlab.com/kernel-firmware/linux-firmware.git" + +[build] +template = "custom" +dependencies = ["driver-manager-config"] +script = """ +set -eo pipefail + +FIRMWARE_URL="https://gitlab.com/kernel-firmware/linux-firmware/-/archive/main/linux-firmware-main.tar.gz" +CACHE_DIR="\${COOKBOOK_ROOT}/build/redbear-firmware-cache" +ARCHIVE="\${CACHE_DIR}/linux-firmware-main.tar.gz" +EXTRACTED="\${CACHE_DIR}/linux-firmware-main" + +mkdir -p "\${CACHE_DIR}" + +if [ ! -f "\${ARCHIVE}" ]; then + if [ "\${REPO_OFFLINE:-1}" = "1" ] && [ -z "\${REDBEAR_ALLOW_UPSTREAM:-}" ]; then + echo "ERROR: redbear-firmware-intel requires network access but REPO_OFFLINE=1." >&2 + echo " Set REPO_OFFLINE=0 or pass REDBEAR_ALLOW_UPSTREAM=1." >&2 + exit 1 + fi + wget -O "\${ARCHIVE}" "\${FIRMWARE_URL}" +fi + +if [ ! -d "\${EXTRACTED}" ]; then + mkdir -p "\${EXTRACTED}" + tar -xf "\${ARCHIVE}" -C "\${EXTRACTED}" --strip-components=1 +fi + +STAGE="\${COOKBOOK_STAGE}/lib/firmware" +mkdir -p "\${STAGE}" +mkdir -p "\${STAGE}/LICENSES" + +# Intel subset: i915 DMC, sound (HDA), VPU, ISH. These power Intel GPUs, +# Intel HDA audio, Intel VPU accelerators, and Intel sensor hubs. +for vendor_dir in i915 intel; do + src="\${EXTRACTED}/\${vendor_dir}" + if [ -d "\${src}" ]; then + cp -r "\${src}" "\${STAGE}/" + fi +done + +# License metadata for the staged blobs. +for license_file in LICENSE.i915 LICENSE.intel LICENSE.intel_vpu WHENCE; do + if [ -f "\${EXTRACTED}/\${license_file}" ]; then + install -Dm0644 "\${EXTRACTED}/\${license_file}" "\${STAGE}/LICENSES/\${license_file}" + fi +done + +cat > "\${STAGE}/LICENSES/redbear-firmware-intel.txt" <<'EOF' +Red Bear firmware bundle: Intel subset +====================================== + +This package stages only the Intel firmware subset from upstream +linux-firmware: + - i915/ -- Intel display engine DMC blobs + - intel/ -- Intel sound (HDA), VPU, ISH, and other blobs + +Licenses vary by file; see WHENCE and LICENSE.* upstream. +EOF +""" diff --git a/local/recipes/system/redbear-firmware-iwlwifi/recipe.toml b/local/recipes/system/redbear-firmware-iwlwifi/recipe.toml new file mode 100644 index 0000000000..a36f51ae9f --- /dev/null +++ b/local/recipes/system/redbear-firmware-iwlwifi/recipe.toml @@ -0,0 +1,70 @@ +[package] +name = "redbear-firmware-iwlwifi" +version = "0.3.1" +description = "Intel iwlwifi Wi-Fi firmware (.ucode and .pnvm blobs)" + +[source] +path = "source" +upstream = "https://gitlab.com/kernel-firmware/linux-firmware.git" + +[build] +template = "custom" +dependencies = ["driver-manager-config"] +script = """ +set -eo pipefail + +FIRMWARE_URL="https://gitlab.com/kernel-firmware/linux-firmware/-/archive/main/linux-firmware-main.tar.gz" +CACHE_DIR="\${COOKBOOK_ROOT}/build/redbear-firmware-cache" +ARCHIVE="\${CACHE_DIR}/linux-firmware-main.tar.gz" +EXTRACTED="\${CACHE_DIR}/linux-firmware-main" + +mkdir -p "\${CACHE_DIR}" + +if [ ! -f "\${ARCHIVE}" ]; then + if [ "\${REPO_OFFLINE:-1}" = "1" ] && [ -z "\${REDBEAR_ALLOW_UPSTREAM:-}" ]; then + echo "ERROR: redbear-firmware-iwlwifi requires network access but REPO_OFFLINE=1." >&2 + echo " Set REPO_OFFLINE=0 or pass REDBEAR_ALLOW_UPSTREAM=1." >&2 + exit 1 + fi + wget -O "\${ARCHIVE}" "\${FIRMWARE_URL}" +fi + +if [ ! -d "\${EXTRACTED}" ]; then + mkdir -p "\${EXTRACTED}" + tar -xf "\${ARCHIVE}" -C "\${EXTRACTED}" --strip-components=1 +fi + +STAGE="\${COOKBOOK_STAGE}/lib/firmware" +mkdir -p "\${STAGE}" +mkdir -p "\${STAGE}/LICENSES" + +# iwlwifi subset: top-level iwlwifi-*.ucode and .pnvm blobs. +# firmware-loader's builtin fallback maps /lib/firmware/iwlwifi-* into +# intel/iwlwifi/iwlwifi-* for new layouts, so staging at the top level +# keeps both paths working. +for f in "\${EXTRACTED}"/iwlwifi-*.ucode "\${EXTRACTED}"/iwlwifi-*.pnvm; do + [ -f "\$f" ] || continue + install -Dm0644 "\$f" "\${STAGE}/$(basename "\$f")" +done + +# License metadata. +for license_file in LICENCE.iwlwifi_firmware WHENCE; do + if [ -f "\${EXTRACTED}/\${license_file}" ]; then + install -Dm0644 "\${EXTRACTED}/\${license_file}" "\${STAGE}/LICENSES/\${license_file}" + fi +done + +cat > "\${STAGE}/LICENSES/redbear-firmware-iwlwifi.txt" <<'EOF' +Red Bear firmware bundle: Intel iwlwifi subset +============================================== + +This package stages only the iwlwifi Wi-Fi firmware from upstream +linux-firmware. The redbear-iwlwifi driver loads these blobs via the +firmware-loader scheme. + +firmware-loader's path-map fallback also resolves the new layout: + /lib/firmware/iwlwifi-*.ucode --> /lib/firmware/intel/iwlwifi/iwlwifi-*.ucode + +License: see LICENCE.iwlwifi_firmware upstream. +EOF +"""