aa3257c6eb
display.rs: DP link retraining at set_mode time Before enabling DDI_BUF_CTL, retrain DP link for the active port Uses display's own dp_aux vector for DPCD communication Fixes link recovery after mode changes syncobj.rs: sync_file fd infrastructure export_sync_file(): generate fd token, map syncobj → fd import_sync_file(): resolve fd token → syncobj handle close_sync_file(): remove fd from table driver.rs: GpuDriver trait methods for sync_file syncobj_export_fd() / syncobj_import_fd() with default Unsupported mod.rs: IntelDriver implementation delegates to SyncobjManager scheme.rs: DRM_IOCTL_REDOX_SYNCOBJ_HANDLE_TO_FD (0x73) DRM_IOCTL_REDOX_SYNCOBJ_FD_TO_HANDLE (0x74) Wire types with proper #[repr(C)] Copy+Clone attributes
189 lines
5.8 KiB
Rust
189 lines
5.8 KiB
Rust
use std::collections::BTreeMap;
|
|
use std::sync::Arc;
|
|
|
|
use log::debug;
|
|
|
|
use super::fence::FenceTimeline;
|
|
use crate::driver::{DriverError, Result, SyncobjHandle};
|
|
|
|
const DRM_SYNCOBJ_CREATE_SIGNALED: u32 = 1 << 0;
|
|
|
|
pub struct SyncobjObject {
|
|
pub handle: SyncobjHandle,
|
|
pub timeline: Arc<FenceTimeline>,
|
|
pub point: u64,
|
|
pub signaled: bool,
|
|
}
|
|
|
|
pub struct SyncobjManager {
|
|
objects: BTreeMap<SyncobjHandle, SyncobjObject>,
|
|
next_handle: SyncobjHandle,
|
|
global_timeline: Arc<FenceTimeline>,
|
|
fd_table: BTreeMap<i32, SyncobjHandle>,
|
|
next_fd: i32,
|
|
}
|
|
|
|
impl SyncobjManager {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
objects: BTreeMap::new(),
|
|
next_handle: 1,
|
|
global_timeline: Arc::new(FenceTimeline::new()),
|
|
fd_table: BTreeMap::new(),
|
|
next_fd: 10,
|
|
}
|
|
}
|
|
|
|
pub fn timeline(&self) -> &Arc<FenceTimeline> {
|
|
&self.global_timeline
|
|
}
|
|
|
|
pub fn create(&mut self, flags: u32) -> Result<SyncobjHandle> {
|
|
let handle = self.next_handle;
|
|
self.next_handle = self.next_handle.wrapping_add(1);
|
|
|
|
let signaled = flags & DRM_SYNCOBJ_CREATE_SIGNALED != 0;
|
|
let point = if signaled {
|
|
self.global_timeline.allocate_seqno()
|
|
} else {
|
|
0
|
|
};
|
|
|
|
self.objects.insert(handle, SyncobjObject {
|
|
handle,
|
|
timeline: self.global_timeline.clone(),
|
|
point,
|
|
signaled,
|
|
});
|
|
|
|
debug!("redox-drm-intel: syncobj {} created (signaled={})", handle, signaled);
|
|
Ok(handle)
|
|
}
|
|
|
|
pub fn destroy(&mut self, handle: SyncobjHandle) -> Result<()> {
|
|
self.objects.remove(&handle).map(|_| ()).ok_or_else(|| {
|
|
DriverError::NotFound(format!("syncobj handle {} not found", handle))
|
|
})
|
|
}
|
|
|
|
pub fn signal(&mut self, handles: &[SyncobjHandle]) -> Result<()> {
|
|
let point = self.global_timeline.allocate_seqno();
|
|
for &handle in handles {
|
|
if let Some(obj) = self.objects.get_mut(&handle) {
|
|
obj.point = point;
|
|
obj.signaled = false;
|
|
}
|
|
}
|
|
self.global_timeline.signal(point);
|
|
debug!("redox-drm-intel: syncobj signal — {} handle(s) at point {}", handles.len(), point);
|
|
Ok(())
|
|
}
|
|
|
|
pub fn reset(&mut self, handles: &[SyncobjHandle]) -> Result<()> {
|
|
for &handle in handles {
|
|
if let Some(obj) = self.objects.get_mut(&handle) {
|
|
obj.point = 0;
|
|
obj.signaled = false;
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub fn wait(&self, handles: &[SyncobjHandle], timeout_ns: i64) -> Result<u32> {
|
|
let timeout_ms = if timeout_ns < 0 {
|
|
u64::MAX
|
|
} else {
|
|
(timeout_ns as u64) / 1_000_000
|
|
};
|
|
|
|
for (idx, &handle) in handles.iter().enumerate() {
|
|
let obj = self.objects.get(&handle).ok_or_else(|| {
|
|
DriverError::NotFound(format!("syncobj handle {} not found", handle))
|
|
})?;
|
|
|
|
if obj.signaled || obj.point == 0 {
|
|
return Ok(idx as u32);
|
|
}
|
|
|
|
if self.global_timeline.is_completed(obj.point) {
|
|
return Ok(idx as u32);
|
|
}
|
|
|
|
if timeout_ms > 0 {
|
|
match self.global_timeline.wait(obj.point, timeout_ms) {
|
|
Ok(()) => return Ok(idx as u32),
|
|
Err(_) => continue,
|
|
}
|
|
}
|
|
}
|
|
|
|
if timeout_ns == 0 {
|
|
return Ok(0);
|
|
}
|
|
|
|
Err(DriverError::Initialization(format!(
|
|
"syncobj_wait timeout: {} handles, {} ns",
|
|
handles.len(), timeout_ns
|
|
)))
|
|
}
|
|
|
|
pub fn query(&self, handle: SyncobjHandle) -> Result<bool> {
|
|
let obj = self.objects.get(&handle).ok_or_else(|| {
|
|
DriverError::NotFound(format!("syncobj handle {} not found", handle))
|
|
})?;
|
|
|
|
if obj.signaled || obj.point == 0 {
|
|
return Ok(true);
|
|
}
|
|
|
|
Ok(self.global_timeline.is_completed(obj.point))
|
|
}
|
|
|
|
pub fn fd_to_handle(&mut self, fd: i32) -> Result<SyncobjHandle> {
|
|
self.fd_table.get(&fd).copied().ok_or_else(|| {
|
|
DriverError::NotFound(format!("syncobj fd {} not found in local table", fd))
|
|
})
|
|
}
|
|
|
|
pub fn handle_to_fd(&mut self, handle: SyncobjHandle) -> Result<i32> {
|
|
if !self.objects.contains_key(&handle) {
|
|
return Err(DriverError::NotFound(format!("syncobj handle {} not found", handle)));
|
|
}
|
|
let fd = self.next_fd;
|
|
self.next_fd = self.next_fd.wrapping_add(1);
|
|
self.fd_table.insert(fd, handle);
|
|
Ok(fd)
|
|
}
|
|
|
|
pub fn hardware_signal_completion(&self, completion_addr: u64, seqno: u64) {
|
|
self.global_timeline.signal(seqno);
|
|
debug!("redox-drm-intel: hardware fence completion at {:#010x} seqno {}", completion_addr, seqno);
|
|
}
|
|
|
|
pub fn is_handle_valid(&self, handle: SyncobjHandle) -> bool {
|
|
self.objects.contains_key(&handle)
|
|
}
|
|
|
|
pub fn export_sync_file(&mut self, handle: SyncobjHandle) -> Result<i32> {
|
|
if !self.objects.contains_key(&handle) {
|
|
return Err(DriverError::NotFound(format!("syncobj handle {} not found", handle)));
|
|
}
|
|
let fd = self.next_fd;
|
|
self.next_fd = self.next_fd.wrapping_add(1);
|
|
self.fd_table.insert(fd, handle);
|
|
debug!("redox-drm-intel: sync_file fd {} exported for syncobj {}", fd, handle);
|
|
Ok(fd)
|
|
}
|
|
|
|
pub fn import_sync_file(&self, fd: i32) -> Result<SyncobjHandle> {
|
|
self.fd_table.get(&fd).copied().ok_or_else(|| {
|
|
DriverError::NotFound(format!("sync_file fd {} not found", fd))
|
|
})
|
|
}
|
|
|
|
pub fn close_sync_file(&mut self, fd: i32) {
|
|
self.fd_table.remove(&fd);
|
|
debug!("redox-drm-intel: sync_file fd {} closed", fd);
|
|
}
|
|
}
|