From 64640e98aa39db510545c04974963cc3d0822dd7 Mon Sep 17 00:00:00 2001 From: Alexander Heldt Date: Tue, 3 Nov 2026 12:07:24 +0100 Subject: [PATCH] pinwheel: Fix intermittent webcam failure from IPU6 isys oops On 7.3 the in-tree IPU6 isys driver can be runtime-suspended while isys_probe() is still running, before it has set drvdata. The suspend callback then dereferences a NULL isys, oopses, and psys never probes, so /dev/ipu-psys0 is missing and the camera HAL fails with "Failed to open PSYS". Patch the isys runtime PM callbacks to return early when drvdata is not set yet. The patched module is built on its own from the kernel source and installed under updates/, so it overrides the in-tree one without having to rebuild the whole kernel. --- hosts/pinwheel/modules/webcam/default.nix | 55 ++++++++++++++++++- .../ipu6-isys-runtime-pm-null-check.patch | 22 ++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 hosts/pinwheel/modules/webcam/ipu6-isys-runtime-pm-null-check.patch diff --git a/hosts/pinwheel/modules/webcam/default.nix b/hosts/pinwheel/modules/webcam/default.nix index 69ceeef..96ec3ec 100644 --- a/hosts/pinwheel/modules/webcam/default.nix +++ b/hosts/pinwheel/modules/webcam/default.nix @@ -1,4 +1,55 @@ -{ config, lib, ... }: +{ + config, + lib, + pkgs, + ... +}: +let + inherit (config.boot.kernelPackages) kernel kernelModuleMakeFlags; + + ipu6-isys = pkgs.stdenv.mkDerivation { + pname = "ipu6-isys"; + inherit (kernel) version; + + __structuredAttrs = true; + + patches = [ ./ipu6-isys-runtime-pm-null-check.patch ]; + + nativeBuildInputs = kernel.moduleBuildDependencies; + + unpackPhase = '' + tar -xf ${kernel.src} --strip-components=1 --wildcards '*/drivers/media/pci/intel/ipu6/*' + ''; + + postPatch = '' + sed -i '/+= intel-ipu6\.o/d' drivers/media/pci/intel/ipu6/Makefile + ''; + + makeFlags = kernelModuleMakeFlags ++ [ + "KERNELRELEASE=${kernel.modDirVersion}" + ]; + + installFlags = [ + "DEPMOD=true" + "INSTALL_MOD_PATH=${placeholder "out"}" + ]; + + buildPhase = '' + runHook preBuild + make -C ${kernel.dev}/lib/modules/${kernel.modDirVersion}/build \ + M=$(pwd)/drivers/media/pci/intel/ipu6 "''${makeFlags[@]}" + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + make -C ${kernel.dev}/lib/modules/${kernel.modDirVersion}/build \ + M=$(pwd)/drivers/media/pci/intel/ipu6 modules_install \ + "''${makeFlags[@]}" "''${installFlags[@]}" + runHook postInstall + ''; + }; +in { nixpkgs.overlays = [ (final: prev: { @@ -28,6 +79,8 @@ }) ]; + boot.extraModulePackages = [ ipu6-isys ]; + hardware.ipu6 = { enable = true; platform = "ipu6epmtl"; diff --git a/hosts/pinwheel/modules/webcam/ipu6-isys-runtime-pm-null-check.patch b/hosts/pinwheel/modules/webcam/ipu6-isys-runtime-pm-null-check.patch new file mode 100644 index 0000000..8d3dcc0 --- /dev/null +++ b/hosts/pinwheel/modules/webcam/ipu6-isys-runtime-pm-null-check.patch @@ -0,0 +1,22 @@ +--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c ++++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c +@@ -858,6 +858,9 @@ + unsigned long flags; + int ret; + ++ if (!isys) ++ return 0; ++ + ret = ipu6_mmu_hw_init(adev->mmu); + if (ret) + return ret; +@@ -885,6 +888,9 @@ + struct ipu6_isys *isys = dev_get_drvdata(dev); + unsigned long flags; + ++ if (!isys) ++ return 0; ++ + spin_lock_irqsave(&isys->power_lock, flags); + isys->power = 0; + spin_unlock_irqrestore(&isys->power_lock, flags);