diff --git a/nix/nixos-modules/astral/vfio/test_config.json b/nix/nixos-modules/astral/vfio/test_config.json index d56020f4..aa7f71f4 100644 --- a/nix/nixos-modules/astral/vfio/test_config.json +++ b/nix/nixos-modules/astral/vfio/test_config.json @@ -13,6 +13,12 @@ "type": "usb", "id": "12c9:2003" } + ], + "gpu": [ + { + "type": "pci", + "id": "10de:2482" + } ] } } diff --git a/nix/nixos-modules/astral/vfio/vfiohotplug.py b/nix/nixos-modules/astral/vfio/vfiohotplug.py index d29d28c4..c9b29020 100755 --- a/nix/nixos-modules/astral/vfio/vfiohotplug.py +++ b/nix/nixos-modules/astral/vfio/vfiohotplug.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 - +import re import logging import os import subprocess @@ -29,6 +29,14 @@ class Config: groups: t.Dict[str, t.List[Device]] +@dataclass +class PCIPath: + domain: str + bus: str + slot: str + function: str + + def parser(): parser = argparse.ArgumentParser( prog="vfiohotplug", @@ -95,11 +103,21 @@ def assoc_group_name(query: str, config: Config) -> str: def manage_device(action: str, device: Device, config: Config): with tempfile.NamedTemporaryFile("w") as f: - xml = f""" + match device.type: + case "usb": + xml = f""" - - + + +""" + case "pci": + path = find_pci_path(device.vendor, device.product) + xml = f""" + + +
+ """ logger.debug("Writing XML file %r: %r", f.name, xml) @@ -155,7 +173,24 @@ def parse_device(d: dict) -> Device: vendor, product = d["id"].split(":") except ValueError: raise ValueError(f"ID not in : form: {d['id']}") - return Device(dt, "0x" + vendor, "0x" + product) + return Device(dt, vendor, product) + + +def find_pci_path(vendor: str, product: str) -> PCIPath: + vpid = f"{vendor}:{product}" + logger.debug("querying path of device %s", vpid) + output = ( + subprocess.check_output(["lspci", "-d", vpid, "-D"]) + .decode() + .strip() + .splitlines() + ) + + results = [ + PCIPath(*re.match(r"(\d+):(\d+):(\d+).(\d+).*", l).groups()) for l in output + ] + logger.info("associated pci:%s to paths: %r", vpid, results) + return results[0] if __name__ == "__main__":