libdrm_amdgpu_sys/amdgpu/
device_handle.rs1use crate::AMDGPU::DEVICE_HANDLE;
2use crate::*;
3#[cfg(feature = "dynamic_loading")]
4use std::sync::Arc;
5#[cfg(feature = "dynamic_loading")]
6use bindings::{DynLibDrm, DynLibDrmAmdgpu};
7
8use crate::bindings::drmDevicePtr;
9pub use bindings::{
10 amdgpu_device_handle,
11 amdgpu_gds_resource_info,
13 amdgpu_gpu_info,
14 drm_amdgpu_heap_info,
15 drm_amdgpu_info_device,
16 drm_amdgpu_info_gds,
17 drm_amdgpu_info_vram_gtt,
18 drm_amdgpu_memory_info,
19 drm_amdgpu_info_vce_clock_table,
20};
21use bindings::{
22 AMDGPU_INFO_NUM_BYTES_MOVED,
23 AMDGPU_INFO_NUM_EVICTIONS,
24 AMDGPU_INFO_VRAM_LOST_COUNTER,
25 AMDGPU_INFO_DEV_INFO,
26 AMDGPU_INFO_GDS_CONFIG,
27 AMDGPU_INFO_VRAM_GTT,
28 AMDGPU_INFO_MEMORY,
29 AMDGPU_INFO_VRAM_USAGE,
30 AMDGPU_INFO_VIS_VRAM_USAGE,
31 AMDGPU_INFO_GTT_USAGE,
32 AMDGPU_INFO_VCE_CLOCK_TABLE,
33 AMDGPU_INFO_NUM_VRAM_CPU_PAGE_FAULTS,
34};
35use core::mem::{size_of, MaybeUninit};
36
37pub struct DeviceHandle {
38 #[cfg(feature = "dynamic_loading")]
39 pub(crate) libdrm: Arc<DynLibDrm>,
40 #[cfg(feature = "dynamic_loading")]
41 pub(crate) libdrm_amdgpu: Arc<DynLibDrmAmdgpu>,
42 pub(crate) amdgpu_dev: DEVICE_HANDLE,
43 pub(crate) fd: i32,
44}
45
46unsafe impl Send for DeviceHandle {}
47unsafe impl Sync for DeviceHandle {}
48
49use std::path::PathBuf;
50
51impl LibDrmAmdgpu {
52 pub fn init_device_handle(&self, fd: i32) -> Result<(DeviceHandle, u32, u32), i32> {
53 #[cfg(not(feature = "dynamic_loading"))]
54 let init = bindings::amdgpu_device_initialize;
55 #[cfg(feature = "dynamic_loading")]
56 let init = self.libdrm_amdgpu.amdgpu_device_initialize;
57
58 unsafe {
59 let mut amdgpu_dev: MaybeUninit<amdgpu_device_handle> = MaybeUninit::zeroed();
60 let mut major: MaybeUninit<u32> = MaybeUninit::zeroed();
61 let mut minor: MaybeUninit<u32> = MaybeUninit::zeroed();
62
63 let r = init(
64 fd,
65 major.as_mut_ptr(),
66 minor.as_mut_ptr(),
67 amdgpu_dev.as_mut_ptr(),
68 );
69
70 let [major, minor] = [major.assume_init(), minor.assume_init()];
71 let device_handle = DeviceHandle {
72 #[cfg(feature = "dynamic_loading")]
73 libdrm: self.libdrm.clone(),
74 #[cfg(feature = "dynamic_loading")]
75 libdrm_amdgpu: self.libdrm_amdgpu.clone(),
76 amdgpu_dev: amdgpu_dev.assume_init(),
77 fd,
78 };
79
80 query_error!(r);
81
82 Ok((device_handle, major, minor))
83 }
84 }
85}
86
87impl DeviceHandle {
88 #[cfg(not(feature = "dynamic_loading"))]
94 pub fn init(fd: i32) -> Result<(Self, u32, u32), i32> {
95 unsafe {
96 let mut amdgpu_dev: MaybeUninit<amdgpu_device_handle> = MaybeUninit::zeroed();
97 let mut major: MaybeUninit<u32> = MaybeUninit::zeroed();
98 let mut minor: MaybeUninit<u32> = MaybeUninit::zeroed();
99
100 let r = bindings::amdgpu_device_initialize(
101 fd,
102 major.as_mut_ptr(),
103 minor.as_mut_ptr(),
104 amdgpu_dev.as_mut_ptr(),
105 );
106
107 let [major, minor] = [major.assume_init(), minor.assume_init()];
108 let device_handle = Self {
109 amdgpu_dev: amdgpu_dev.assume_init(),
110 fd,
111 };
112
113 query_error!(r);
114
115 Ok((device_handle, major, minor))
116 }
117 }
118
119 fn deinit(&self) -> Result<i32, i32> {
120 #[cfg(not(feature = "dynamic_loading"))]
121 let func = bindings::amdgpu_device_deinitialize;
122 #[cfg(feature = "dynamic_loading")]
123 let func = self.libdrm_amdgpu.amdgpu_device_deinitialize;
124
125 let r = unsafe { func(self.amdgpu_dev) };
126
127 query_error!(r);
128
129 Ok(r)
130 }
131
132 pub fn get_fd(&self) -> i32 {
133 self.fd
134 }
135
136 pub fn read_mm_registers(&self, offset: u32) -> Result<u32, i32> {
139 #[cfg(not(feature = "dynamic_loading"))]
140 let func = bindings::amdgpu_read_mm_registers;
141 #[cfg(feature = "dynamic_loading")]
142 let func = self.libdrm_amdgpu.amdgpu_read_mm_registers;
143
144 unsafe {
145 let mut out: MaybeUninit<u32> = MaybeUninit::zeroed();
146
147 let r = func(
148 self.amdgpu_dev,
149 offset, 1, 0xFFFF_FFFF, 0, out.as_mut_ptr(),
154 );
155
156 let out = out.assume_init();
157
158 query_error!(r);
159
160 Ok(out)
161 }
162 }
163
164 pub fn query_gpu_info(&self) -> Result<amdgpu_gpu_info, i32> {
165 #[cfg(not(feature = "dynamic_loading"))]
166 let func = bindings::amdgpu_query_gpu_info;
167 #[cfg(feature = "dynamic_loading")]
168 let func = self.libdrm_amdgpu.amdgpu_query_gpu_info;
169
170 unsafe {
171 let mut gpu_info: MaybeUninit<amdgpu_gpu_info> = MaybeUninit::zeroed();
172
173 let r = func(self.amdgpu_dev, gpu_info.as_mut_ptr());
174
175 let gpu_info = gpu_info.assume_init();
176
177 query_error!(r);
178
179 Ok(gpu_info)
180 }
181 }
182
183 pub fn query_gds_info(&self) -> Result<amdgpu_gds_resource_info, i32> {
184 #[cfg(not(feature = "dynamic_loading"))]
185 let func = bindings::amdgpu_query_gds_info;
186 #[cfg(feature = "dynamic_loading")]
187 let func = self.libdrm_amdgpu.amdgpu_query_gds_info;
188
189 unsafe {
190 let mut gds_info: MaybeUninit<amdgpu_gds_resource_info> = MaybeUninit::zeroed();
191
192 let r = func(self.amdgpu_dev, gds_info.as_mut_ptr());
193
194 let gds_info = gds_info.assume_init();
195
196 query_error!(r);
197
198 Ok(gds_info)
199 }
200 }
201
202 pub fn query_sw_info(&self, info: amdgpu_sw_info) -> Result<u32, i32> {
203 #[cfg(not(feature = "dynamic_loading"))]
204 let func = bindings::amdgpu_query_sw_info;
205 #[cfg(feature = "dynamic_loading")]
206 let func = self.libdrm_amdgpu.amdgpu_query_sw_info;
207
208 unsafe {
209 let mut val: MaybeUninit<u32> = MaybeUninit::zeroed();
210
211 let r = func(
212 self.amdgpu_dev,
213 info as u32,
214 val.as_mut_ptr() as *mut ::core::ffi::c_void,
215 );
216
217 let val = val.assume_init();
218
219 query_error!(r);
220
221 Ok(val)
222 }
223 }
224
225 pub(crate) fn query<T>(&self, info_id: ::core::ffi::c_uint) -> Result<T, i32> {
226 #[cfg(not(feature = "dynamic_loading"))]
227 let func = bindings::amdgpu_query_info;
228 #[cfg(feature = "dynamic_loading")]
229 let func = self.libdrm_amdgpu.amdgpu_query_info;
230
231 unsafe {
232 let mut dev: MaybeUninit<T> = MaybeUninit::zeroed();
233
234 let r = func(
235 self.amdgpu_dev,
236 info_id,
237 size_of::<T>() as u32,
238 dev.as_mut_ptr() as *mut ::core::ffi::c_void,
239 );
240
241 let dev = dev.assume_init();
242
243 query_error!(r);
244
245 Ok(dev)
246 }
247 }
248
249 pub fn device_info(&self) -> Result<drm_amdgpu_info_device, i32> {
250 Self::query(self, AMDGPU_INFO_DEV_INFO)
251 }
252
253 pub fn vram_gtt_info(&self) -> Result<drm_amdgpu_info_vram_gtt, i32> {
255 Self::query(self, AMDGPU_INFO_VRAM_GTT)
256 }
257
258 pub fn memory_info(&self) -> Result<drm_amdgpu_memory_info, i32> {
259 Self::query(self, AMDGPU_INFO_MEMORY)
260 }
261
262 pub fn vram_usage_info(&self) -> Result<u64, i32> {
263 Self::query(self, AMDGPU_INFO_VRAM_USAGE)
264 }
265
266 pub fn vis_vram_usage_info(&self) -> Result<u64, i32> {
267 Self::query(self, AMDGPU_INFO_VIS_VRAM_USAGE)
268 }
269
270 pub fn gtt_usage_info(&self) -> Result<u64, i32> {
271 Self::query(self, AMDGPU_INFO_GTT_USAGE)
272 }
273
274 pub fn gds_info(&self) -> Result<drm_amdgpu_info_gds, i32> {
275 Self::query(self, AMDGPU_INFO_GDS_CONFIG)
276 }
277
278 pub fn vce_clock_info(&self) -> Result<drm_amdgpu_info_vce_clock_table, i32> {
281 Self::query(self, AMDGPU_INFO_VCE_CLOCK_TABLE)
282 }
283
284 pub fn num_vram_cpu_page_faults(&self) -> Result<u64, i32> {
286 Self::query(self, AMDGPU_INFO_NUM_VRAM_CPU_PAGE_FAULTS)
287 }
288
289 pub fn num_bytes_moved(&self) -> Result<u64, i32> {
291 Self::query(self, AMDGPU_INFO_NUM_BYTES_MOVED)
292 }
293
294 pub fn num_evictions(&self) -> Result<u64, i32> {
296 Self::query(self, AMDGPU_INFO_NUM_EVICTIONS)
297 }
298
299 pub fn vram_lost_counter(&self) -> Result<u32, i32> {
300 Self::query(self, AMDGPU_INFO_VRAM_LOST_COUNTER)
301 }
302
303 pub fn get_pci_bus_info(&self) -> Result<PCI::BUS_INFO, i32> {
305 self.drm_get_device2()
306 }
307
308 fn drm_get_device2(&self) -> Result<PCI::BUS_INFO, i32> {
309 let pci = unsafe {
310 let mut dev_info = self.__drmGetDevice2(self.fd, 0)?;
311 let pci = core::ptr::read((*dev_info).businfo.pci);
312 self.__drmFreeDevice(&mut dev_info);
313
314 pci
315 };
316
317 Ok(PCI::BUS_INFO {
318 domain: pci.domain,
319 bus: pci.bus,
320 dev: pci.dev,
321 func: pci.func,
322 })
323 }
324
325 unsafe fn __drmGetDevice2(&self, fd: ::core::ffi::c_int, flags: u32) -> Result<drmDevicePtr, i32> { unsafe {
326 #[cfg(not(feature = "dynamic_loading"))]
327 let func = bindings::drmGetDevice2;
328 #[cfg(feature = "dynamic_loading")]
329 let func = self.libdrm.drmGetDevice2;
330
331 let mut drm_dev_info: MaybeUninit<drmDevicePtr> = MaybeUninit::uninit();
332
333 let r = func(fd, flags, drm_dev_info.as_mut_ptr());
334
335 let drm_dev_info = drm_dev_info.assume_init();
336
337 if drm_dev_info.is_null() {
338 return Err(r);
339 }
340
341 query_error!(r);
342
343 Ok(drm_dev_info)
344 }}
345
346 unsafe fn __drmFreeDevice(&self, device: *mut drmDevicePtr) { unsafe {
347 #[cfg(not(feature = "dynamic_loading"))]
348 let func = bindings::drmFreeDevice;
349 #[cfg(feature = "dynamic_loading")]
350 let func = self.libdrm.drmFreeDevice;
351
352 func(device)
353 }}
354
355 fn get_min_max_clock_from_dpm<P: Into<PathBuf>>(
356 &self,
357 sysfs_path: P,
358 ) -> Option<[u32; 2]> {
359 let parse_line = |s: &str| -> Option<u32> {
360 s.split(' ').nth(1)?.trim_end_matches("Mhz").parse::<u32>().ok()
361 };
362
363 AMDGPU::get_min_max_from_dpm(sysfs_path.into(), parse_line)
364 }
365
366 pub fn get_min_max_memory_clock_from_dpm<P: Into<PathBuf>>(
368 &self,
369 path: P
370 ) -> Option<[u32; 2]> {
371 self.get_min_max_clock_from_dpm(path.into().join("pp_dpm_mclk"))
372 }
373
374 pub fn get_min_max_gpu_clock_from_dpm<P: Into<PathBuf>>(
376 &self,
377 path: P
378 ) -> Option<[u32; 2]> {
379 self.get_min_max_clock_from_dpm(path.into().join("pp_dpm_sclk"))
380 }
381
382 pub fn get_min_max_memory_clock_from_sysfs<P: Into<PathBuf>>(
384 &self,
385 path: P
386 ) -> Option<(u32, u32)> {
387 let tmp = self.get_min_max_clock_from_dpm(path.into().join("pp_dpm_mclk"))?;
388
389 Some((tmp[0], tmp[1]))
390 }
391
392 pub fn get_min_max_memory_clock(&self) -> Option<(u32, u32)> {
394 let sysfs_path = self.get_sysfs_path().ok()?;
395 self.get_min_max_memory_clock_from_sysfs(sysfs_path)
396 }
397
398 pub fn get_min_max_gpu_clock_from_sysfs<P: Into<PathBuf>>(
400 &self,
401 path: P
402 ) -> Option<(u32, u32)> {
403 let tmp = self.get_min_max_clock_from_dpm(path.into().join("pp_dpm_sclk"))?;
404
405 Some((tmp[0], tmp[1]))
406 }
407
408 pub fn get_min_max_gpu_clock(&self) -> Option<(u32, u32)> {
410 let sysfs_path = self.get_sysfs_path().ok()?;
411 self.get_min_max_gpu_clock_from_sysfs(sysfs_path)
412 }
413
414 pub fn get_sysfs_path(&self) -> Result<PathBuf, i32> {
416 let path = self.get_pci_bus_info()?.get_sysfs_path();
417
418 Ok(path)
419 }
420
421 pub(crate) fn get_sysfs_path_io(&self) -> std::io::Result<PathBuf> {
422 let path = self
423 .get_pci_bus_info()
424 .map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, "Failed get_pci_bus_info"))?
425 .get_sysfs_path();
426
427 Ok(path)
428 }
429
430 pub fn get_hwmon_path(&self) -> Option<PathBuf> {
432 self.get_pci_bus_info().ok()?.get_hwmon_path()
433 }
434
435 pub fn check_if_secondary_die(&self) -> bool {
438 let Some(power_cap) = self.get_power_cap() else { return false };
439
440 power_cap.check_if_secondary_die()
441 }
442
443 pub fn get_min_max_link_info_from_dpm(&self) -> Option<[PCI::LINK; 2]> {
444 let pci_bus = self.get_pci_bus_info().ok()?;
445
446 pci_bus.get_min_max_link_info_from_dpm()
447 }
448
449 pub fn get_max_gpu_link(&self) -> Option<PCI::LINK> {
451 let pci_bus = self.get_pci_bus_info().ok()?;
452
453 pci_bus.get_max_gpu_link()
454 }
455
456 pub fn get_max_system_link(&self) -> Option<PCI::LINK> {
458 let pci_bus = self.get_pci_bus_info().ok()?;
459
460 pci_bus.get_max_system_link()
461 }
462}
463
464impl Drop for DeviceHandle {
465 fn drop(&mut self) {
466 self.deinit().unwrap();
467 }
468}
469
470impl drm_amdgpu_memory_info {
471 pub fn check_resizable_bar(&self) -> bool {
476 (self.vram.total_heap_size * 9 / 10) <= self.cpu_accessible_vram.total_heap_size
477 }
478}
479
480#[repr(u32)]
481pub enum amdgpu_sw_info {
482 address32_hi = 0,
483}