Skip to content

Commit 3957a2d

Browse files
committed
gen-dynamic-pci: add GPU detection and naming support
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 Reviewed-by: Chuck Lever <[email protected]> Signed-off-by: Luis Chamberlain <[email protected]>
1 parent b8bfcea commit 3957a2d

File tree

1 file changed

+187
-7
lines changed

1 file changed

+187
-7
lines changed

playbooks/python/workflows/dynamic-kconfig/gen-dynamic-pci.py

Lines changed: 187 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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

109254
def 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

Comments
 (0)