From 89380720bf81eb1aedbe8f09a87eaeac64e61a0e Mon Sep 17 00:00:00 2001 From: Jon Sahlberg Date: Wed, 4 Dec 2024 11:49:59 +0200 Subject: [PATCH] Generic acpi and reset of PCI audio device Lenovo X1 PCI audio device needs to be reset when audioVM shuts down Generic version that allows configuration for other platforms Signed-off-by: Jon Sahlberg --- modules/hardware/definition.nix | 15 +++++++++++++++ .../microvm/virtualization/microvm/audiovm.nix | 16 ++++++++++------ .../virtualization/microvm/microvm-host.nix | 18 +++++++++++++----- .../lenovo-x1/definitions/x1-gen10.nix | 7 +++++++ .../lenovo-x1/definitions/x1-gen11.nix | 9 +++++++++ 5 files changed, 54 insertions(+), 11 deletions(-) diff --git a/modules/hardware/definition.nix b/modules/hardware/definition.nix index 33412faeb..8a5e722e9 100644 --- a/modules/hardware/definition.nix +++ b/modules/hardware/definition.nix @@ -266,6 +266,21 @@ in }; audio = { + removePciDevice = mkOption { + description = "PCI Device path to remove at VM reboot"; + type = types.nullOr types.str; + default = null; + }; + rescanPciDevice = mkOption { + description = "PCI Device path to rescan at VM reboot"; + type = types.nullOr types.str; + default = null; + }; + acpiPath = mkOption { + description = "Path to ACPI file to add to a VM"; + type = types.nullOr types.str; + default = null; + }; # With the current implementation, the whole PCI IOMMU group 14: # 00:1f.x in the example from Lenovo X1 Carbon # must be defined for passthrough to AudioVM diff --git a/modules/microvm/virtualization/microvm/audiovm.nix b/modules/microvm/virtualization/microvm/audiovm.nix index 438aa14ed..64c47cab1 100644 --- a/modules/microvm/virtualization/microvm/audiovm.nix +++ b/modules/microvm/virtualization/microvm/audiovm.nix @@ -12,6 +12,7 @@ let vmName = "audio-vm"; macAddress = "02:00:00:03:03:03"; isGuiVmEnabled = config.ghaf.virtualization.microvm.guivm.enable; + has_acpi_path = config.ghaf.hardware.definition.audio.acpiPath != null; sshKeysHelper = pkgs.callPackage ../../../../packages/ssh-keys-helper { inherit pkgs; @@ -119,12 +120,15 @@ let aarch64-linux = "virt"; } .${configHost.nixpkgs.hostPlatform.system}; - extraArgs = [ - "-device" - "qemu-xhci" - "-acpitable" - "file=/sys/firmware/acpi/tables/NHLT" - ]; + extraArgs = + [ + "-device" + "qemu-xhci" + ] + ++ lib.optionals has_acpi_path [ + "-acpitable" + "file=${config.ghaf.hardware.definition.audio.acpiPath}" + ]; }; }; diff --git a/modules/microvm/virtualization/microvm/microvm-host.nix b/modules/microvm/virtualization/microvm/microvm-host.nix index b1c57274c..f049cdc80 100644 --- a/modules/microvm/virtualization/microvm/microvm-host.nix +++ b/modules/microvm/virtualization/microvm/microvm-host.nix @@ -9,6 +9,14 @@ }: let cfg = config.ghaf.virtualization.microvm-host; + has_remove_pci_device = config.ghaf.hardware.definition.audio.removePciDevice != null; + has_rescan_pci_device = config.ghaf.hardware.definition.audio.rescanPciDevice != null; + has_acpi_path = config.ghaf.hardware.definition.audio.acpiPath != null; + rescan_pci_device = + if has_rescan_pci_device then + config.ghaf.hardware.definition.audio.rescanPciDevice + else + config.ghaf.hardware.definition.audio.removePciDevice; in { imports = [ @@ -62,21 +70,21 @@ in lib.optionalAttrs config.ghaf.virtualization.microvm.audiovm.enable { # The + here is a systemd feature to make the script run as root. - ExecStartPre = [ + ExecStartPre = lib.mkIf has_acpi_path [ "+${pkgs.writeShellScript "ACPI-table-permission" '' # The script gives permissionf sot a microvm user # to read ACPI tables of soundcaed mic array. - ${pkgs.coreutils}/bin/chmod 444 /sys/firmware/acpi/tables/NHLT + ${pkgs.coreutils}/bin/chmod 444 ${config.ghaf.hardware.definition.audio.acpiPath} ''}" ]; - ExecStopPost = [ + ExecStopPost = lib.mkIf has_remove_pci_device [ "+${pkgs.writeShellScript "reload-audio" '' # The script makes audio device internal state to reset # This fixes issue of audio device getting into some unexpected # state when the VM is being shutdown during audio mic recording - echo "1" > /sys/bus/pci/devices/0000:00:1f.3/remove + echo "1" > ${config.ghaf.hardware.definition.audio.removePciDevice} sleep 0.1 - echo "1" > /sys/bus/pci/devices/0000:00:1f.0/rescan + echo "1" > ${rescan_pci_device} ''}" ]; }; diff --git a/modules/reference/hardware/lenovo-x1/definitions/x1-gen10.nix b/modules/reference/hardware/lenovo-x1/definitions/x1-gen10.nix index c14217c53..06bed134b 100644 --- a/modules/reference/hardware/lenovo-x1/definitions/x1-gen10.nix +++ b/modules/reference/hardware/lenovo-x1/definitions/x1-gen10.nix @@ -89,6 +89,13 @@ # 00:1f.x in the Lenovo X1 Carbon 10 gen # must be defined for passthrough to AudioVM audio = { + # Force a PCI device reset to the device to get pci device to the default state at shutdown + removePciDevice = "0000:00:1f.3"; + # Force a PCI device rescan after resetting a device to refind the device on host + rescanPciDevice = "0000:00:1f.0"; + # Add acpi table to audioVM to enable microphone array profile + acpiPath = "/sys/firmware/acpi/tables/NHLT"; + pciDevices = [ { # ISA bridge: Intel Corporation Alder Lake PCH eSPI Controller(rev 01) diff --git a/modules/reference/hardware/lenovo-x1/definitions/x1-gen11.nix b/modules/reference/hardware/lenovo-x1/definitions/x1-gen11.nix index a241c92ee..1ffcfe561 100644 --- a/modules/reference/hardware/lenovo-x1/definitions/x1-gen11.nix +++ b/modules/reference/hardware/lenovo-x1/definitions/x1-gen11.nix @@ -99,6 +99,15 @@ # 00:1f.x in the example from Lenovo X1 Carbon # must be defined for passthrough to AudioVM audio = { + # Force a PCI device reset to the audio device + # This is to get the pci hardware device to the default state at shutdown + removePciDevice = "0000:00:1f.3"; + # Force a PCI device rescan after resetting a device + # to refind the device on host after reset + rescanPciDevice = "0000:00:1f.0"; + # Add acpi table file to audioVM to enable Lenovo X1 microphone array profile + acpiPath = "/sys/firmware/acpi/tables/NHLT"; + pciDevices = [ { # ISA bridge: Intel Corporation Raptor Lake LPC/eSPI Controller (rev 01)