From c57d26864e0b94d4f6b90eb8642d80280da16230 Mon Sep 17 00:00:00 2001 From: Bernardo Magri Date: Thu, 18 Jun 2026 19:49:39 +0100 Subject: [PATCH] feat(hardware): nomarchy.hardware.* enablement beyond nixos-hardware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The nixos-hardware "common-*" profiles the installer selects cover the basics (microcode, the Intel/AMD VA-API media stack, weekly fstrim), and power.nix adds thermald + power-profiles-daemon. This adds the gap above them, generically and detected at install time. New modules/nixos/hardware.nix exposes a vendor-keyed nomarchy.hardware.* surface — broadly-beneficial bits default ON when the vendor is detected (opt-out), heavy/experimental bits behind opt-in toggles: - intel.enable -> GuC/HuC (i915.enable_guc=3); intel.computeRuntime (opt-in: intel-compute-runtime + vpl-gpu-rt) - amd.enable -> amd_pstate=active + radeonsi VA-API env; amd.rocm.enable + amd.rocm.gfxOverride (opt-in: ROCm HIP/OpenCL) - fingerprint.enable -> fprintd; fingerprint.pam (opt-in: login + sudo) - npu.enable (opt-in/experimental) -> the in-kernel driver (amdxdna/intel_vpu) keyed by vendor; userspace runtime is BYO hardware-db.sh now detects Intel/AMD, a fingerprint reader (libfprint USB vendor IDs) and an NPU (Intel VPU / AMD XDNA PCI IDs), emitting NOMARCHY lines the installer bakes into system.nix — safe defaults active, opt-ins commented. Audited against the commons to avoid double-setting. Verified: flake check green; a toggles-on build has amd_pstate=active + i915.enable_guc=3 in kernel-params and ships fprintd.service; detection runs correctly on the (AMD Ryzen-AI) dev machine. On-hardware verification of the AMD/NPU/Intel-compute runtime bits is still pending. Docs: template commented examples, README option table, ROADMAP status. Co-Authored-By: Claude Opus 4.8 --- README.md | 7 + docs/ROADMAP.md | 16 +++ modules/nixos/default.nix | 2 +- modules/nixos/hardware.nix | 165 ++++++++++++++++++++++ pkgs/nomarchy-install/hardware-db.sh | 51 ++++++- pkgs/nomarchy-install/nomarchy-install.sh | 54 ++++++- templates/downstream/system.nix | 11 ++ 7 files changed, 301 insertions(+), 5 deletions(-) create mode 100644 modules/nixos/hardware.nix diff --git a/README.md b/README.md index ba67b87..c916558 100644 --- a/README.md +++ b/README.md @@ -219,6 +219,13 @@ examples: **[docs/OVERRIDES.md](docs/OVERRIDES.md)**. | `nomarchy.system.power.laptop` | `false` | Marks a laptop, gating battery-only features; the installer sets it when a battery is present | | `nomarchy.system.power.thermal.enable` | `false` | thermald (Intel-only); the installer enables it on a GenuineIntel CPU | | `nomarchy.system.power.batteryChargeLimit` | `null` | Stop charging at this % (e.g. `80`) where the hardware supports it; needs `power.laptop` | +| `nomarchy.hardware.intel.enable` | `false` | Intel enablement above nixos-hardware (GuC/HuC via `i915.enable_guc=3`); the installer sets it on an Intel CPU/GPU | +| `nomarchy.hardware.intel.computeRuntime` | `false` | Opt-in: Intel GPU compute — OpenCL/Level-Zero (`intel-compute-runtime`) + oneVPL (`vpl-gpu-rt`) | +| `nomarchy.hardware.amd.enable` | `false` | AMD enablement above nixos-hardware (amd-pstate EPP + radeonsi VA-API); installer-set on an AMD CPU/GPU | +| `nomarchy.hardware.amd.rocm.enable` | `false` | Opt-in: ROCm HIP/OpenCL GPU compute (multi-GB); pair with `.gfxOverride` (e.g. `"11.0.0"`) for an unlisted iGPU | +| `nomarchy.hardware.fingerprint.enable` | `false` | fprintd for a detected fingerprint reader (installer-set); enroll with `fprintd-enroll` | +| `nomarchy.hardware.fingerprint.pam` | `false` | Opt-in: use the fingerprint for login + sudo (PAM) | +| `nomarchy.hardware.npu.enable` | `false` | Opt-in/experimental: load the on-die NPU driver (`amdxdna`/`intel_vpu`); userspace runtime is BYO | | `nomarchy.services.tailscale.enable` | `false` | Opt-in: Tailscale mesh VPN (then `sudo tailscale up`) | | `nomarchy.services.syncthing.enable` | `false` | Opt-in: Syncthing file sync as the login user (GUI at `127.0.0.1:8384`) | | `nomarchy.services.podman.enable` | `false` | Opt-in: rootless Podman (`docker` aliased to it) | diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index a0a07c7..7266096 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -263,6 +263,22 @@ how to override it. Items marked ✓ are shipped. Complements nixos-hardware (model quirks) rather than replacing it; keep the detection in the installer's `hardware-db` so an installed machine bakes the right defaults, all overridable through `nomarchy.hardware.*`. + - ✓ **Mechanism + broad seed shipped** (`modules/nixos/hardware.nix`): a + vendor-keyed `nomarchy.hardware.*` surface (`intel`, `amd`, `fingerprint`, + `npu`), `hardware-db.sh` extended to detect Intel/AMD, a fingerprint reader + (libfprint USB vendor IDs) and an NPU (Intel VPU / AMD XDNA PCI IDs), and + the installer bakes the matching toggles into `system.nix` — safe defaults + active (GuC/HuC, amd-pstate, AMD VA-API env, fprintd), heavy/experimental + opt-ins commented (Intel compute-runtime, ROCm, fingerprint PAM, NPU + driver). Audited against the nixos-hardware commons so it only fills the + gap above them — microcode / the media-driver VA-API stack / weekly fstrim + already come from `common-cpu-*` / `common-gpu-*` / `common-pc-ssd`. + Exercised live on the dev machine's detection (an AMD Ryzen-AI laptop: AMD + + fingerprint + NPU all detected) and a toggles-on build (`amd_pstate=active` + + `i915.enable_guc=3` in kernel-params, `fprintd.service` present). + **Remaining: on-hardware verification of the runtime bits (AMD/NPU/Intel + GPU-compute) — none are testable in CI or on the Intel Latitudes for the + AMD paths.** SSD TRIM is intentionally left to `common-pc-ssd`. Worked example — ThinkPad T14s (Ryzen 7 PRO 7840U + Radeon 780M): - **GPU compute — ROCm:** the 780M is an RDNA3 iGPU (gfx1103) ROCm doesn't officially list, so it needs `HSA_OVERRIDE_GFX_VERSION=11.0.0`. Multi-GB diff --git a/modules/nixos/default.nix b/modules/nixos/default.nix index 391fea9..b874fd8 100644 --- a/modules/nixos/default.nix +++ b/modules/nixos/default.nix @@ -22,7 +22,7 @@ let ''; in { - imports = [ ./options.nix ./plymouth.nix ./file-manager.nix ./power.nix ./services.nix ]; + imports = [ ./options.nix ./plymouth.nix ./file-manager.nix ./power.nix ./services.nix ./hardware.nix ]; config = { # The safe half of distro branding: distroName flows into diff --git a/modules/nixos/hardware.nix b/modules/nixos/hardware.nix new file mode 100644 index 0000000..2851055 --- /dev/null +++ b/modules/nixos/hardware.nix @@ -0,0 +1,165 @@ +# Hardware enablement beyond nixos-hardware. +# +# The nixos-hardware "common-*" profiles the installer selects cover the +# BASICS (microcode, the Intel/AMD VA-API media stack, weekly fstrim), and +# power.nix adds thermald + power-profiles-daemon. This module fills the GAP +# above those: broadly-beneficial bits that default ON when the installer +# detects the vendor (opt-OUT), and heavier/experimental bits behind opt-IN +# toggles. The installer's hardware-db.sh probes what's present and writes the +# matching nomarchy.hardware.* into the generated system.nix. +# +# Audited against the commons so we don't double-set: we add GuC/HuC, the +# amd-pstate governor, the AMD VA-API env, GPU-compute runtimes, fprintd, and +# the NPU driver — none of which the commons turn on. +{ config, lib, pkgs, ... }: + +let + cfg = config.nomarchy.hardware; +in +{ + options.nomarchy.hardware = { + intel = { + enable = lib.mkEnableOption '' + Intel CPU/GPU enablement (the installer turns this on when it detects + an Intel CPU or GPU). Complements nixos-hardware's common-gpu-intel''; + + guc = lib.mkOption { + type = lib.types.bool; + default = cfg.intel.enable; + defaultText = lib.literalExpression "config.nomarchy.hardware.intel.enable"; + description = '' + Load the GPU's GuC/HuC firmware (i915.enable_guc=3) — better power + management and HuC-accelerated media on Gen11+ (Xe) iGPUs. On by + default with intel.enable; safe on modern Intel graphics. + ''; + }; + + computeRuntime = lib.mkEnableOption '' + Intel GPU compute: the OpenCL / Level Zero (intel-compute-runtime) and + oneVPL (vpl-gpu-rt) runtimes for GPU compute and transcode. Opt-in (a + few hundred MB) — the Intel counterpart to AMD ROCm''; + }; + + amd = { + enable = lib.mkEnableOption '' + AMD CPU/GPU enablement (installer-set on an AMD CPU or GPU). + Complements nixos-hardware's common-cpu-amd / common-gpu-amd''; + + pstate = lib.mkOption { + type = lib.types.bool; + default = cfg.amd.enable; + defaultText = lib.literalExpression "config.nomarchy.hardware.amd.enable"; + description = '' + Use the amd-pstate EPP driver (amd_pstate=active) — the modern Zen + power/perf governor that power-profiles-daemon drives per profile. + On by default with amd.enable (broadly beneficial on Zen 2+). + ''; + }; + + vaapi = lib.mkOption { + type = lib.types.bool; + default = cfg.amd.enable; + defaultText = lib.literalExpression "config.nomarchy.hardware.amd.enable"; + description = '' + Point VA-API at mesa's radeonsi (LIBVA_DRIVER_NAME=radeonsi) for + hardware video decode/encode. On by default with amd.enable. + ''; + }; + + rocm = { + enable = lib.mkEnableOption '' + AMD ROCm: the HIP / OpenCL GPU-compute stack (multi-GB closure). + Opt-in — unlocks GPU PyTorch / Ollama on Radeon''; + + gfxOverride = lib.mkOption { + type = lib.types.str; + default = ""; + example = "11.0.0"; + description = '' + HSA_OVERRIDE_GFX_VERSION for GPUs ROCm doesn't officially list + (e.g. an RDNA3 780M iGPU, gfx1103, needs "11.0.0"). Empty = no + override. + ''; + }; + }; + }; + + fingerprint = { + enable = lib.mkEnableOption '' + a fingerprint reader via fprintd (the installer turns this on when it + detects a known reader). Enroll with `fprintd-enroll`''; + + pam = lib.mkEnableOption '' + using the fingerprint for login and sudo (PAM). Opt-in — password-only + stays the default for the cautious; enroll a finger first''; + }; + + npu.enable = lib.mkEnableOption '' + the on-die NPU (AI accelerator) kernel driver — amdxdna on AMD (Ryzen + AI), intel_vpu on Intel (Core Ultra and newer). Opt-in and experimental: + this loads the in-kernel driver only; the userspace runtime (AMD XRT / + oneAPI Level Zero NPU) is yours to add''; + }; + + config = lib.mkMerge [ + # ── Intel ────────────────────────────────────────────────────────── + (lib.mkIf cfg.intel.guc { + boot.kernelParams = [ "i915.enable_guc=3" ]; + }) + (lib.mkIf cfg.intel.computeRuntime { + hardware.graphics.extraPackages = with pkgs; [ intel-compute-runtime vpl-gpu-rt ]; + }) + + # ── AMD ──────────────────────────────────────────────────────────── + (lib.mkIf cfg.amd.pstate { + boot.kernelParams = [ "amd_pstate=active" ]; + }) + (lib.mkIf cfg.amd.vaapi { + # radeonsi itself comes from mesa (via common-gpu-amd); this just steers + # libva at it. mkDefault so a hand-set value or another module wins. + environment.sessionVariables.LIBVA_DRIVER_NAME = lib.mkDefault "radeonsi"; + hardware.graphics.extraPackages = [ pkgs.libva ]; + }) + (lib.mkIf cfg.amd.rocm.enable { + hardware.graphics.extraPackages = [ pkgs.rocmPackages.clr pkgs.rocmPackages.clr.icd ]; + environment.sessionVariables = lib.optionalAttrs (cfg.amd.rocm.gfxOverride != "") { + HSA_OVERRIDE_GFX_VERSION = cfg.amd.rocm.gfxOverride; + }; + }) + + # ── Fingerprint ──────────────────────────────────────────────────── + (lib.mkIf cfg.fingerprint.enable { + services.fprintd.enable = true; + }) + (lib.mkIf (cfg.fingerprint.enable && cfg.fingerprint.pam) { + security.pam.services.login.fprintAuth = true; + security.pam.services.sudo.fprintAuth = true; + }) + + # ── NPU (in-kernel driver only; userspace runtime is BYO) ────────── + (lib.mkIf (cfg.npu.enable && cfg.amd.enable) { + boot.kernelModules = [ "amdxdna" ]; + }) + (lib.mkIf (cfg.npu.enable && cfg.intel.enable) { + boot.kernelModules = [ "intel_vpu" ]; + }) + + # ── Sanity ───────────────────────────────────────────────────────── + { + assertions = [ + { + assertion = cfg.amd.rocm.enable -> cfg.amd.enable; + message = "nomarchy.hardware.amd.rocm.enable needs nomarchy.hardware.amd.enable."; + } + { + assertion = cfg.intel.computeRuntime -> cfg.intel.enable; + message = "nomarchy.hardware.intel.computeRuntime needs nomarchy.hardware.intel.enable."; + } + { + assertion = cfg.npu.enable -> (cfg.amd.enable || cfg.intel.enable); + message = "nomarchy.hardware.npu.enable needs a detected Intel or AMD platform."; + } + ]; + } + ]; +} diff --git a/pkgs/nomarchy-install/hardware-db.sh b/pkgs/nomarchy-install/hardware-db.sh index acc89c4..1497bec 100644 --- a/pkgs/nomarchy-install/hardware-db.sh +++ b/pkgs/nomarchy-install/hardware-db.sh @@ -112,6 +112,7 @@ HARDWARE_DB=( # ---------------------------------------------------------------------------- nomarchy_detect_hw() { local sys_vendor product_name cpu_vendor + local nvidia=0 amdgpu=0 intelgpu=0 sys_vendor=$(cat /sys/class/dmi/id/sys_vendor 2>/dev/null || echo "") product_name=$(cat /sys/class/dmi/id/product_name 2>/dev/null || echo "") cpu_vendor=$(lscpu 2>/dev/null | awk -F: '/Vendor ID/{gsub(/ /,"",$2); print $2; exit}') @@ -126,7 +127,7 @@ nomarchy_detect_hw() { # GPU (lspci may list several; report all) if command -v lspci >/dev/null 2>&1; then - local gpu_line nvidia=0 amdgpu=0 intelgpu=0 + local gpu_line while IFS= read -r gpu_line; do case "$gpu_line" in *"[10de:"*|*"NVIDIA"*) nvidia=1 ;; @@ -140,6 +141,54 @@ nomarchy_detect_hw() { (( intelgpu )) && { echo "MODULE common-gpu-intel"; echo "DETAIL gpu: Intel"; detected=1; } fi + # ── nomarchy.hardware.* enablement — the gap ABOVE the nixos-hardware + # commons (GuC/HuC, amd-pstate, the AMD VA-API env, GPU-compute runtimes, + # fprintd, the NPU driver). Emitted as NOMARCHY lines the installer turns + # into nomarchy.hardware.* in system.nix; safe bits active, heavy opt-ins + # commented. + if [[ "$cpu_vendor" == "GenuineIntel" || $intelgpu -eq 1 ]]; then + echo "NOMARCHY hardware.intel.enable=true" + echo "DETAIL nomarchy.hardware.intel: GuC/HuC on; GPU-compute runtime opt-in" + fi + if [[ "$cpu_vendor" == "AuthenticAMD" || $amdgpu -eq 1 ]]; then + echo "NOMARCHY hardware.amd.enable=true" + echo "DETAIL nomarchy.hardware.amd: amd-pstate + VA-API on; ROCm opt-in" + fi + + # Fingerprint reader — libfprint's common USB vendor IDs (Goodix, + # Synaptics/Validity, Elan, EgisTec, Upek, AuthenTec, FocalTech, NB). + local have_fp=0 + if command -v lsusb >/dev/null 2>&1; then + local vid + for vid in 27c6 06cb 138a 04f3 1c7a 147e 08ff 2808 1fae; do + lsusb 2>/dev/null | grep -qiE "ID ${vid}:" && { have_fp=1; break; } + done + else + local f + for f in /sys/bus/usb/devices/*/idVendor; do + [[ -e "$f" ]] || continue + case "$(cat "$f" 2>/dev/null)" in + 27c6|06cb|138a|04f3|1c7a|147e|08ff|2808|1fae) have_fp=1; break ;; + esac + done + fi + if [[ $have_fp -eq 1 ]]; then + echo "NOMARCHY hardware.fingerprint.enable=true" + echo "DETAIL fingerprint reader detected → fprintd (PAM login/sudo opt-in)" + fi + + # NPU (detect-only → a commented, experimental opt-in). Intel VPU / + # AMD XDNA PCI IDs; best-effort across recent gens. + if command -v lspci >/dev/null 2>&1; then + if lspci -nn 2>/dev/null | grep -qiE '\[8086:(7d1d|643e|ad1d|b03e)\]'; then + echo "NOMARCHY-NPU intel" + echo "DETAIL Intel NPU detected (opt-in, experimental)" + elif lspci -nn 2>/dev/null | grep -qiE '\[1022:1502\]'; then + echo "NOMARCHY-NPU amd" + echo "DETAIL AMD XDNA NPU detected (opt-in, experimental)" + fi + fi + # Chassis (glob test, not compgen — nixpkgs' non-interactive bash # is built without the completion builtins) local bats=(/sys/class/power_supply/BAT*) diff --git a/pkgs/nomarchy-install/nomarchy-install.sh b/pkgs/nomarchy-install/nomarchy-install.sh index a1342ce..dc6ed3e 100644 --- a/pkgs/nomarchy-install/nomarchy-install.sh +++ b/pkgs/nomarchy-install/nomarchy-install.sh @@ -210,6 +210,8 @@ section "Hardware detection" source "$SHARE/hardware-db.sh" HW_PROFILES=() +HW_NOMARCHY=() # NOMARCHY hardware.* assignments from detection +NPU_VENDOR="" # "intel" | "amd" if an NPU was detected (commented opt-in) hw_mode="${NOMARCHY_HW:-auto}" if [[ "$hw_mode" == "none" ]]; then info "Hardware profiles skipped." @@ -220,8 +222,10 @@ else if [[ -n "$detection" ]]; then while IFS= read -r line; do case "$line" in - MODULE\ *) HW_PROFILES+=("${line#MODULE }") ;; - DETAIL\ *) info "→ ${line#DETAIL }" ;; + MODULE\ *) HW_PROFILES+=("${line#MODULE }") ;; + NOMARCHY-NPU\ *) NPU_VENDOR="${line#NOMARCHY-NPU }" ;; + NOMARCHY\ *) HW_NOMARCHY+=("${line#NOMARCHY }") ;; + DETAIL\ *) info "→ ${line#DETAIL }" ;; esac done <<< "$detection" fi @@ -428,6 +432,50 @@ NIX ) fi +# Hardware enablement (nomarchy.hardware.*): what hardware-db.sh detected +# above the nixos-hardware commons. Safe defaults active; the heavier or +# experimental opt-ins written commented for the user to flip on. +HARDWARE_CONFIG="" +if [[ ${#HW_NOMARCHY[@]} -gt 0 || -n "$NPU_VENDOR" ]]; then + has_intel=0; has_amd=0; has_fp=0 + if [[ ${#HW_NOMARCHY[@]} -gt 0 ]]; then + for nm in "${HW_NOMARCHY[@]}"; do + case "$nm" in + hardware.intel.enable=true) has_intel=1 ;; + hardware.amd.enable=true) has_amd=1 ;; + hardware.fingerprint.enable=true) has_fp=1 ;; + esac + done + fi + hw_lines=" # Hardware enablement (auto-detected). Safe defaults are active; + # the heavier opt-ins are commented — uncomment to turn them on." + if [[ $has_intel -eq 1 ]]; then + hw_lines+=" + nomarchy.hardware.intel.enable = true; # GuC/HuC firmware (i915.enable_guc=3) + # nomarchy.hardware.intel.computeRuntime = true; # OpenCL/oneVPL GPU compute (opt-in)" + fi + if [[ $has_amd -eq 1 ]]; then + hw_lines+=" + nomarchy.hardware.amd.enable = true; # amd-pstate EPP + radeonsi VA-API + # nomarchy.hardware.amd.rocm.enable = true; # ROCm GPU compute (multi-GB, opt-in) + # nomarchy.hardware.amd.rocm.gfxOverride = \"\"; # e.g. \"11.0.0\" for an unlisted iGPU" + fi + if [[ $has_fp -eq 1 ]]; then + hw_lines+=" + nomarchy.hardware.fingerprint.enable = true; # fprintd (enroll: fprintd-enroll) + # nomarchy.hardware.fingerprint.pam = true; # use it for login + sudo (opt-in)" + fi + if [[ -n "$NPU_VENDOR" ]]; then + hw_lines+=" + # nomarchy.hardware.npu.enable = true; # $NPU_VENDOR NPU driver (experimental; userspace runtime BYO)" + fi + HARDWARE_CONFIG=$(cat < "$FLAKE_DIR/system.nix" < "$FLAKE_DIR/system.nix" <