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.
This commit is contained in:
2026-07-25 00:18:40 +09:00
parent db37829261
commit 88ecd36e3a
5 changed files with 289 additions and 0 deletions
@@ -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/<name> 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.
@@ -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
"""
@@ -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
"""
@@ -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
"""
@@ -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
"""