@@ -64,11 +64,156 @@ def get_special_device_nvme(pci_id, IOMMUGroup):
6464 )
6565
6666
67- def get_kconfig_device_name (pci_id , sdevice , IOMMUGroup ):
67+ def get_gpu_memory_info (pci_id ):
68+ """Try to get GPU memory information from sysfs."""
69+ # Try to get memory info from various possible locations
70+ mem_paths = [
71+ sys_bus_prefix + pci_id + "/mem_info_vram_total" ,
72+ sys_bus_prefix + pci_id + "/drm/card0/mem_info_vram_total" ,
73+ ]
74+
75+ for mem_path in mem_paths :
76+ if os .path .isfile (mem_path ):
77+ try :
78+ with open (mem_path , "r" ) as f :
79+ mem_bytes = int (f .read ().strip ())
80+ mem_gb = mem_bytes / (1024 * 1024 * 1024 )
81+ return f"{ mem_gb :.0f} GB"
82+ except :
83+ pass
84+
85+ # Try to get memory from resource file size (less accurate)
86+ resource_path = sys_bus_prefix + pci_id + "/resource0"
87+ if os .path .isfile (resource_path ):
88+ try :
89+ size = os .path .getsize (resource_path )
90+ if size > 0 :
91+ size_gb = size / (1024 * 1024 * 1024 )
92+ if size_gb >= 1 :
93+ return f"{ size_gb :.0f} GB"
94+ except :
95+ pass
96+
97+ return None
98+
99+
100+ def get_special_device_gpu (pci_id , device_name , IOMMUGroup ):
101+ """Generate a nice display name for GPU devices."""
102+ pci_id_name = strip_kconfig_name (pci_id )
103+
104+ # Clean up the device name to extract the GPU model
105+ gpu_model = device_name
106+
107+ # Common GPU name patterns to clean up
108+ replacements = [
109+ ("[AMD/ATI]" , "AMD" ),
110+ ("Advanced Micro Devices, Inc." , "AMD" ),
111+ ("NVIDIA Corporation" , "NVIDIA" ),
112+ ("Intel Corporation" , "Intel" ),
113+ ]
114+
115+ for old , new in replacements :
116+ gpu_model = gpu_model .replace (old , new ).strip ()
117+
118+ # Try to extract specific GPU model from brackets
119+ import re
120+
121+ bracket_match = re .search (r"\[([^\]]+)\]" , gpu_model )
122+ if bracket_match :
123+ model_name = bracket_match .group (1 )
124+ # Keep the vendor prefix if it's a clean model name
125+ if "Radeon" in model_name or "GeForce" in model_name or "Intel" in model_name :
126+ gpu_model = model_name
127+ else :
128+ # Prepend vendor if needed
129+ if "AMD" in gpu_model and "Radeon" not in model_name :
130+ gpu_model = f"AMD { model_name } "
131+ elif (
132+ "NVIDIA" in gpu_model
133+ and "GeForce" not in model_name
134+ and "Quadro" not in model_name
135+ ):
136+ gpu_model = f"NVIDIA { model_name } "
137+ else :
138+ gpu_model = model_name
139+
140+ # Remove any existing memory info from the model name (e.g., "32GB" at the end)
141+ gpu_model = re .sub (r"\s+\d+GB\s*$" , "" , gpu_model )
142+
143+ # Try to get memory info
144+ mem_info = get_gpu_memory_info (pci_id )
145+
146+ # Build the display name
147+ if mem_info :
148+ display_name = (
149+ f"{ pci_id_name } IOMMU group { IOMMUGroup } - GPU - { gpu_model } { mem_info } "
150+ )
151+ else :
152+ display_name = f"{ pci_id_name } IOMMU group { IOMMUGroup } - GPU - { gpu_model } "
153+
154+ return display_name
155+
156+
157+ def is_gpu_device (device_name ):
158+ """Check if a device is a GPU based on its name."""
159+ gpu_keywords = [
160+ # AMD/ATI
161+ "Radeon" ,
162+ "Vega" ,
163+ "Navi" ,
164+ "RDNA" ,
165+ "GCN" ,
166+ "Polaris" ,
167+ "Fiji" ,
168+ "Instinct" ,
169+ "FirePro" ,
170+ "FireGL" ,
171+ "RX" ,
172+ "AMD.*GPU" ,
173+ # NVIDIA
174+ "GeForce" ,
175+ "Quadro" ,
176+ "Tesla" ,
177+ "NVIDIA.*GPU" ,
178+ "GTX" ,
179+ "RTX" ,
180+ "Titan" ,
181+ "NVS" ,
182+ "GRID" ,
183+ # Intel
184+ "Intel.*Graphics" ,
185+ "UHD Graphics" ,
186+ "HD Graphics" ,
187+ "Iris" ,
188+ "Arc" ,
189+ "Xe Graphics" ,
190+ # Generic
191+ "VGA compatible controller" ,
192+ "Display controller" ,
193+ "3D controller" ,
194+ "Graphics" ,
195+ ]
196+
197+ device_lower = device_name .lower ()
198+ for keyword in gpu_keywords :
199+ if keyword .lower () in device_lower :
200+ return True
201+ return False
202+
203+
204+ def get_kconfig_device_name (
205+ pci_id , sdevice , IOMMUGroup , vendor_name = None , device_name = None
206+ ):
68207 default_name = "%s IOMMU group %s - %s" % (pci_id , IOMMUGroup , sdevice )
69208 special_name = None
209+
210+ # Check for NVMe devices
70211 if os .path .isdir (sys_bus_prefix + pci_id + "/nvme" ):
71212 special_name = get_special_device_nvme (pci_id , IOMMUGroup )
213+ # Check for GPU devices
214+ elif device_name and is_gpu_device (device_name ):
215+ special_name = get_special_device_gpu (pci_id , device_name , IOMMUGroup )
216+
72217 if not special_name :
73218 return strip_kconfig_name (default_name )
74219 return strip_kconfig_name (special_name )
@@ -107,10 +252,21 @@ def add_pcie_kconfig_target(config_name, sdevice):
107252
108253
109254def add_pcie_kconfig_entry (
110- pci_id , sdevice , domain , bus , slot , function , IOMMUGroup , config_id
255+ pci_id ,
256+ sdevice ,
257+ domain ,
258+ bus ,
259+ slot ,
260+ function ,
261+ IOMMUGroup ,
262+ config_id ,
263+ vendor_name = None ,
264+ device_name = None ,
111265):
112266 prefix = passthrough_prefix + "_%04d" % config_id
113- name = get_kconfig_device_name (pci_id , sdevice , IOMMUGroup )
267+ name = get_kconfig_device_name (
268+ pci_id , sdevice , IOMMUGroup , vendor_name , device_name
269+ )
114270 add_pcie_kconfig_name (prefix , name )
115271 add_pcie_kconfig_target (prefix , sdevice )
116272 add_pcie_kconfig_string (prefix , pci_id , "pci_id" )
@@ -123,7 +279,9 @@ def add_pcie_kconfig_entry(
123279 add_pcie_kconfig_string (prefix , function , "function" )
124280
125281
126- def add_new_device (slot , sdevice , IOMMUGroup , possible_id ):
282+ def add_new_device (
283+ slot , sdevice , IOMMUGroup , possible_id , vendor_name = None , device_name = None
284+ ):
127285 # Example expeced format 0000:2d:00.0
128286 m = re .match (
129287 r"^(?P<DOMAIN>\w+):" "(?P<BUS>\w+):" "(?P<MSLOT>\w+)\." "(?P<FUNCTION>\w+)$" ,
@@ -154,7 +312,16 @@ def add_new_device(slot, sdevice, IOMMUGroup, possible_id):
154312 )
155313
156314 add_pcie_kconfig_entry (
157- slot , sdevice , domain , bus , mslot , function , IOMMUGroup , possible_id
315+ slot ,
316+ sdevice ,
317+ domain ,
318+ bus ,
319+ mslot ,
320+ function ,
321+ IOMMUGroup ,
322+ possible_id ,
323+ vendor_name ,
324+ device_name ,
158325 )
159326
160327 return possible_id
@@ -184,6 +351,8 @@ def main():
184351 slot = - 1
185352 sdevice = None
186353 IOMMUGroup = None
354+ vendor_name = None
355+ device_name = None
187356
188357 for line in all_lines :
189358 line = line .strip ()
@@ -197,20 +366,31 @@ def main():
197366 if tag == "Slot" :
198367 if sdevice :
199368 num_candidate_devices = add_new_device (
200- slot , sdevice , IOMMUGroup , num_candidate_devices
369+ slot ,
370+ sdevice ,
371+ IOMMUGroup ,
372+ num_candidate_devices ,
373+ vendor_name ,
374+ device_name ,
201375 )
202376 slot = data
203377 sdevice = None
204378 IOMMUGroup = None
379+ vendor_name = None
380+ device_name = None
205381 elif tag == "SDevice" :
206382 sdevice = data
207383 elif tag == "IOMMUGroup" :
208384 IOMMUGroup = data
385+ elif tag == "Vendor" :
386+ vendor_name = data
387+ elif tag == "Device" :
388+ device_name = data
209389
210390 # Handle the last device
211391 if sdevice and slot :
212392 num_candidate_devices = add_new_device (
213- slot , sdevice , IOMMUGroup , num_candidate_devices
393+ slot , sdevice , IOMMUGroup , num_candidate_devices , vendor_name , device_name
214394 )
215395
216396 add_pcie_kconfig_string (passthrough_prefix , num_candidate_devices , "NUM_DEVICES" )
0 commit comments