From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 102732D97AB for ; Mon, 11 Aug 2025 20:12:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.137.202.133 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754943153; cv=none; b=bLyrXy1Pe1llZYr7D6zjldM3yX6dgozOMd3HZCRMZHOoMOhSzFnSlufkb1RcXsajKtzbmKm1fUSuB/4UqgnYqQxW0r79tKEO711c283bHKBGeNhOp8R/ov2yUlNT4Iq0jC0V5x/3QuI7Acxt6swTlUVPwv5zpPE4I1xq3N0EN94= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754943153; c=relaxed/simple; bh=Zx89pX4c/NsfhxPLi86pH89NLXYOyiWoZ3wPS81fsQQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=nuM3dQGstFT+sQI2Su76IcViUOQ7qIJpliAwA39G1gpwWtOY+EEXYbD48XfYD9o+iMsCypruSDDeW610w6KWj1BLRjgSAn4fMDedsyam164bQs6XBF13wQlNact3XUQeIrxKb5aZhgiE2B8ydZKbMb6BOPUZC3Afwum559X5bwo= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=kernel.org; spf=none smtp.mailfrom=infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=PgIOJuoY; arc=none smtp.client-ip=198.137.202.133 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=kernel.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="PgIOJuoY" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=bombadil.20210309; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=2+w3CpEnE0xafG7muSQJx7d0ewFZbjGj2KB/fzc+04Q=; b=PgIOJuoYH63m+swO2T6ypgwQO+ GXowSkhpEhn+4sQWMrCJ1c0GHNRIUMsMFVT7fdPk2zc2fTdXyqquUsDtvjYtQdQM5Q5Uucms70n8I gddf5IOgQzDD4u1d1sF4Dj+3NckyL9Ki7hsKTaPopzsvwI2fYFSVnhErJFqMPicbHUiThjMiBfFuZ 07vNuhjM1JWo9Dy1BAwEtFxBVh+2WBo77kfTw26Yb5gqfNF3QCnN0884lEX8rYVfiCD50NOygrav5 EiLWLtJdffM28Y/fikST6tyCUHjLovg0HwMXVjgpV/X7x5PwqhoFZ3AlQEUh0GzTvhze1616oOStZ lHYafzMA==; Received: from mcgrof by bombadil.infradead.org with local (Exim 4.98.2 #2 (Red Hat Linux)) id 1ulYsh-0000000903w-1ma8; Mon, 11 Aug 2025 20:12:31 +0000 From: Luis Chamberlain To: Chuck Lever , Daniel Gomez , kdevops@lists.linux.dev Cc: Luis Chamberlain Subject: [PATCH 3/8] gen-dynamic-pci: add GPU detection and naming support Date: Mon, 11 Aug 2025 13:12:25 -0700 Message-ID: <20250811201230.2145164-4-mcgrof@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250811201230.2145164-1-mcgrof@kernel.org> References: <20250811201230.2145164-1-mcgrof@kernel.org> Precedence: bulk X-Mailing-List: kdevops@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: Luis Chamberlain Add specialized detection and naming support for GPU devices in the PCI passthrough configuration generator, similar to existing NVMe support. This provides cleaner, more informative names for GPUs in the menuconfig interface. Features added: - Automatic detection of AMD, NVIDIA, and Intel GPUs based on device names and common GPU keywords - GPU memory detection from sysfs when available (via mem_info_vram_total or resource file size estimation) - Clean formatting of GPU names with vendor prefixes and memory info - Support for various GPU families: * AMD: Radeon, Instinct, FirePro, RDNA, GCN series * NVIDIA: GeForce, Quadro, Tesla, RTX/GTX series * Intel: UHD Graphics, HD Graphics, Iris, Arc series Example output: - Before: "0000:03:00.0 IOMMU group None - Device 0834" - After: "0000:03:00.0 IOMMU group None - GPU - Radeon Pro VII/Radeon Instinct MI50 32GB" This makes it much easier for users to identify and select GPUs for passthrough in the configuration menu. Generated-by: Claude AI Signed-off-by: Luis Chamberlain --- .../dynamic-kconfig/gen-dynamic-pci.py | 194 +++++++++++++++++- 1 file changed, 187 insertions(+), 7 deletions(-) diff --git a/playbooks/python/workflows/dynamic-kconfig/gen-dynamic-pci.py b/playbooks/python/workflows/dynamic-kconfig/gen-dynamic-pci.py index f86ce74..52824c7 100755 --- a/playbooks/python/workflows/dynamic-kconfig/gen-dynamic-pci.py +++ b/playbooks/python/workflows/dynamic-kconfig/gen-dynamic-pci.py @@ -64,11 +64,156 @@ def get_special_device_nvme(pci_id, IOMMUGroup): ) -def get_kconfig_device_name(pci_id, sdevice, IOMMUGroup): +def get_gpu_memory_info(pci_id): + """Try to get GPU memory information from sysfs.""" + # Try to get memory info from various possible locations + mem_paths = [ + sys_bus_prefix + pci_id + "/mem_info_vram_total", + sys_bus_prefix + pci_id + "/drm/card0/mem_info_vram_total", + ] + + for mem_path in mem_paths: + if os.path.isfile(mem_path): + try: + with open(mem_path, "r") as f: + mem_bytes = int(f.read().strip()) + mem_gb = mem_bytes / (1024 * 1024 * 1024) + return f"{mem_gb:.0f}GB" + except: + pass + + # Try to get memory from resource file size (less accurate) + resource_path = sys_bus_prefix + pci_id + "/resource0" + if os.path.isfile(resource_path): + try: + size = os.path.getsize(resource_path) + if size > 0: + size_gb = size / (1024 * 1024 * 1024) + if size_gb >= 1: + return f"{size_gb:.0f}GB" + except: + pass + + return None + + +def get_special_device_gpu(pci_id, device_name, IOMMUGroup): + """Generate a nice display name for GPU devices.""" + pci_id_name = strip_kconfig_name(pci_id) + + # Clean up the device name to extract the GPU model + gpu_model = device_name + + # Common GPU name patterns to clean up + replacements = [ + ("[AMD/ATI]", "AMD"), + ("Advanced Micro Devices, Inc.", "AMD"), + ("NVIDIA Corporation", "NVIDIA"), + ("Intel Corporation", "Intel"), + ] + + for old, new in replacements: + gpu_model = gpu_model.replace(old, new).strip() + + # Try to extract specific GPU model from brackets + import re + + bracket_match = re.search(r"\[([^\]]+)\]", gpu_model) + if bracket_match: + model_name = bracket_match.group(1) + # Keep the vendor prefix if it's a clean model name + if "Radeon" in model_name or "GeForce" in model_name or "Intel" in model_name: + gpu_model = model_name + else: + # Prepend vendor if needed + if "AMD" in gpu_model and "Radeon" not in model_name: + gpu_model = f"AMD {model_name}" + elif ( + "NVIDIA" in gpu_model + and "GeForce" not in model_name + and "Quadro" not in model_name + ): + gpu_model = f"NVIDIA {model_name}" + else: + gpu_model = model_name + + # Remove any existing memory info from the model name (e.g., "32GB" at the end) + gpu_model = re.sub(r"\s+\d+GB\s*$", "", gpu_model) + + # Try to get memory info + mem_info = get_gpu_memory_info(pci_id) + + # Build the display name + if mem_info: + display_name = ( + f"{pci_id_name} IOMMU group {IOMMUGroup} - GPU - {gpu_model} {mem_info}" + ) + else: + display_name = f"{pci_id_name} IOMMU group {IOMMUGroup} - GPU - {gpu_model}" + + return display_name + + +def is_gpu_device(device_name): + """Check if a device is a GPU based on its name.""" + gpu_keywords = [ + # AMD/ATI + "Radeon", + "Vega", + "Navi", + "RDNA", + "GCN", + "Polaris", + "Fiji", + "Instinct", + "FirePro", + "FireGL", + "RX", + "AMD.*GPU", + # NVIDIA + "GeForce", + "Quadro", + "Tesla", + "NVIDIA.*GPU", + "GTX", + "RTX", + "Titan", + "NVS", + "GRID", + # Intel + "Intel.*Graphics", + "UHD Graphics", + "HD Graphics", + "Iris", + "Arc", + "Xe Graphics", + # Generic + "VGA compatible controller", + "Display controller", + "3D controller", + "Graphics", + ] + + device_lower = device_name.lower() + for keyword in gpu_keywords: + if keyword.lower() in device_lower: + return True + return False + + +def get_kconfig_device_name( + pci_id, sdevice, IOMMUGroup, vendor_name=None, device_name=None +): default_name = "%s IOMMU group %s - %s" % (pci_id, IOMMUGroup, sdevice) special_name = None + + # Check for NVMe devices if os.path.isdir(sys_bus_prefix + pci_id + "/nvme"): special_name = get_special_device_nvme(pci_id, IOMMUGroup) + # Check for GPU devices + elif device_name and is_gpu_device(device_name): + special_name = get_special_device_gpu(pci_id, device_name, IOMMUGroup) + if not special_name: return strip_kconfig_name(default_name) return strip_kconfig_name(special_name) @@ -107,10 +252,21 @@ def add_pcie_kconfig_target(config_name, sdevice): def add_pcie_kconfig_entry( - pci_id, sdevice, domain, bus, slot, function, IOMMUGroup, config_id + pci_id, + sdevice, + domain, + bus, + slot, + function, + IOMMUGroup, + config_id, + vendor_name=None, + device_name=None, ): prefix = passthrough_prefix + "_%04d" % config_id - name = get_kconfig_device_name(pci_id, sdevice, IOMMUGroup) + name = get_kconfig_device_name( + pci_id, sdevice, IOMMUGroup, vendor_name, device_name + ) add_pcie_kconfig_name(prefix, name) add_pcie_kconfig_target(prefix, sdevice) add_pcie_kconfig_string(prefix, pci_id, "pci_id") @@ -123,7 +279,9 @@ def add_pcie_kconfig_entry( add_pcie_kconfig_string(prefix, function, "function") -def add_new_device(slot, sdevice, IOMMUGroup, possible_id): +def add_new_device( + slot, sdevice, IOMMUGroup, possible_id, vendor_name=None, device_name=None +): # Example expeced format 0000:2d:00.0 m = re.match( r"^(?P\w+):" "(?P\w+):" "(?P\w+)\." "(?P\w+)$", @@ -154,7 +312,16 @@ def add_new_device(slot, sdevice, IOMMUGroup, possible_id): ) add_pcie_kconfig_entry( - slot, sdevice, domain, bus, mslot, function, IOMMUGroup, possible_id + slot, + sdevice, + domain, + bus, + mslot, + function, + IOMMUGroup, + possible_id, + vendor_name, + device_name, ) return possible_id @@ -184,6 +351,8 @@ def main(): slot = -1 sdevice = None IOMMUGroup = None + vendor_name = None + device_name = None for line in all_lines: line = line.strip() @@ -197,20 +366,31 @@ def main(): if tag == "Slot": if sdevice: num_candidate_devices = add_new_device( - slot, sdevice, IOMMUGroup, num_candidate_devices + slot, + sdevice, + IOMMUGroup, + num_candidate_devices, + vendor_name, + device_name, ) slot = data sdevice = None IOMMUGroup = None + vendor_name = None + device_name = None elif tag == "SDevice": sdevice = data elif tag == "IOMMUGroup": IOMMUGroup = data + elif tag == "Vendor": + vendor_name = data + elif tag == "Device": + device_name = data # Handle the last device if sdevice and slot: num_candidate_devices = add_new_device( - slot, sdevice, IOMMUGroup, num_candidate_devices + slot, sdevice, IOMMUGroup, num_candidate_devices, vendor_name, device_name ) add_pcie_kconfig_string(passthrough_prefix, num_candidate_devices, "NUM_DEVICES") -- 2.47.2