intel: P0 — DP retrain at modeset, sync_file fd export/import

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
This commit is contained in:
2026-06-01 23:42:19 +03:00
parent bd6e9cd70c
commit aa3257c6eb
5 changed files with 92 additions and 0 deletions
@@ -186,6 +186,14 @@ pub trait GpuDriver: Send + Sync {
Err(DriverError::Unsupported("syncobj not supported by this backend"))
}
fn syncobj_export_fd(&self, _handle: SyncobjHandle) -> Result<i32> {
Err(DriverError::Unsupported("syncobj fd export not supported"))
}
fn syncobj_import_fd(&self, _fd: i32) -> Result<SyncobjHandle> {
Err(DriverError::Unsupported("syncobj fd import not supported"))
}
fn redox_private_cs_submit(
&self,
_submit: &RedoxPrivateCsSubmit,
@@ -226,6 +226,14 @@ impl IntelDisplay {
pub fn set_mode(&self, pipe: &DisplayPipe, mode: &ModeInfo) -> Result<()> {
let index = usize::from(pipe.index);
if let Some(port) = pipe.port {
if (port as usize) < self.dp_aux.len() {
debug!("redox-drm-intel: retraining DP link port {} for {}x{}@{}",
port, mode.hdisplay, mode.vdisplay, mode.vrefresh);
let _ = super::dp_link::train_dp_link(&self.mmio, &self.dp_aux[port as usize], port);
}
}
self.write32(
self.regs.htotal(index as u8),
pack_pair(mode.htotal, mode.hdisplay),
@@ -1193,6 +1193,18 @@ impl GpuDriver for IntelDriver {
Err(e) => Err(e),
}
}
fn syncobj_export_fd(&self, handle: SyncobjHandle) -> Result<i32> {
let mut mgr = self.syncobj_mgr.lock()
.map_err(|_| DriverError::Initialization("Intel syncobj state poisoned".into()))?;
mgr.export_sync_file(handle)
}
fn syncobj_import_fd(&self, fd: i32) -> Result<SyncobjHandle> {
let mgr = self.syncobj_mgr.lock()
.map_err(|_| DriverError::Initialization("Intel syncobj state poisoned".into()))?;
mgr.import_sync_file(fd)
}
}
fn detect_display_topology(display: &IntelDisplay) -> Result<(Vec<Connector>, Vec<Encoder>)> {
@@ -163,4 +163,26 @@ impl SyncobjManager {
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);
}
}
@@ -73,6 +73,8 @@ const DRM_IOCTL_MODE_ATOMIC: usize = DRM_IOCTL_BASE + 0x3C;
const DRM_IOCTL_REDOX_SYNCOBJ_CREATE: usize = DRM_IOCTL_BASE + 0x70;
const DRM_IOCTL_REDOX_SYNCOBJ_DESTROY: usize = DRM_IOCTL_BASE + 0x71;
const DRM_IOCTL_REDOX_SYNCOBJ_WAIT: usize = DRM_IOCTL_BASE + 0x72;
const DRM_IOCTL_REDOX_SYNCOBJ_HANDLE_TO_FD: usize = DRM_IOCTL_BASE + 0x73;
const DRM_IOCTL_REDOX_SYNCOBJ_FD_TO_HANDLE: usize = DRM_IOCTL_BASE + 0x74;
const DRM_MODE_ATOMIC_TEST_ONLY: u32 = 0x0100;
const DRM_MODE_ATOMIC_NONBLOCK: u32 = 0x0200;
const DRM_MODE_PAGE_FLIP_EVENT: u32 = 0x01;
@@ -598,8 +600,27 @@ struct RedoxSyncobjWaitWire {
#[derive(Clone, Copy, Debug, Default)]
struct RedoxSyncobjWaitResultWire {
completed: u32,
_pad: [u8; 4],
}
#[derive(Copy, Clone)]
#[repr(C)]
struct RedoxSyncobjHandleToFdWire {
handle: u32,
flags: u32,
fd: i32,
_pad: [u8; 4],
}
#[derive(Copy, Clone)]
#[repr(C)]
struct RedoxSyncobjFdToHandleWire {
fd: i32,
handle: u32,
_pad: [u8; 4],
}
// ---- Internal handle types ----
#[derive(Clone, Debug)]
@@ -1471,6 +1492,8 @@ impl DrmScheme {
DRM_IOCTL_REDOX_SYNCOBJ_CREATE => "SYNCOBJ_CREATE",
DRM_IOCTL_REDOX_SYNCOBJ_DESTROY => "SYNCOBJ_DESTROY",
DRM_IOCTL_REDOX_SYNCOBJ_WAIT => "SYNCOBJ_WAIT",
DRM_IOCTL_REDOX_SYNCOBJ_HANDLE_TO_FD => "SYNCOBJ_HANDLE_TO_FD",
DRM_IOCTL_REDOX_SYNCOBJ_FD_TO_HANDLE => "SYNCOBJ_FD_TO_HANDLE",
_ => "UNKNOWN",
};
log::info!(
@@ -1656,10 +1679,29 @@ impl DrmScheme {
.map_err(driver_to_syscall)?;
let resp = RedoxSyncobjWaitResultWire {
completed: if completed { 1 } else { 0 },
_pad: [0u8; 4],
};
bytes_of(&resp)
}
DRM_IOCTL_REDOX_SYNCOBJ_HANDLE_TO_FD => {
let req = decode_wire::<RedoxSyncobjHandleToFdWire>(payload)?;
let fd = self.driver.syncobj_export_fd(req.handle)
.map_err(driver_to_syscall)?;
let mut resp = req;
resp.fd = fd;
bytes_of(&resp)
}
DRM_IOCTL_REDOX_SYNCOBJ_FD_TO_HANDLE => {
let req = decode_wire::<RedoxSyncobjFdToHandleWire>(payload)?;
let handle = self.driver.syncobj_import_fd(req.fd)
.map_err(driver_to_syscall)?;
let mut resp = req;
resp.handle = handle;
bytes_of(&resp)
}
DRM_IOCTL_MODE_CREATE_DUMB => {
let mut req = decode_wire::<DrmCreateDumbWire>(payload)?;
info!(