Expand redox-drm DRM scheme, amdgpu port, and update patches

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-04-18 17:58:44 +01:00
parent d4f6268854
commit 7904dc9b3d
13 changed files with 1271 additions and 1068 deletions
@@ -10,7 +10,7 @@ use log::{debug, info, warn};
use redox_driver_sys::memory::MmioRegion;
use redox_driver_sys::pci::{PciBarInfo, PciDevice, PciDeviceInfo};
use crate::driver::{DriverError, GpuDriver, Result};
use crate::driver::{DriverError, DriverEvent, GpuDriver, Result};
use crate::drivers::interrupt::InterruptHandle;
use crate::gem::{GemHandle, GemManager};
use crate::kms::connector::{synthetic_edid, Connector};
@@ -41,17 +41,10 @@ const AMD_HPD_RX_INT_ACK_MASK: u32 = 0x0000_0100;
const AMD_IH_STATUS_INTERRUPT_PENDING_MASK: u32 = 0x0000_0001;
const AMD_IH_STATUS_RING_OVERFLOW_MASK: u32 = 0x0000_0002;
#[derive(Clone, Debug)]
pub enum IrqEvent {
Vblank { crtc_id: u32, count: u64 },
Hotplug { connector_id: u32 },
Unknown,
}
pub struct AmdDriver {
info: PciDeviceInfo,
mmio: MmioRegion,
irq_handle: Option<InterruptHandle>,
irq_handle: Mutex<Option<InterruptHandle>>,
display: DisplayCore,
gem: Mutex<GemManager>,
connectors: Mutex<Vec<Connector>>,
@@ -119,6 +112,7 @@ impl AmdDriver {
info.location
))
})?);
let irq_mode = irq_handle.as_ref().map(|handle| handle.mode_name()).unwrap_or("none");
let display = DisplayCore::with_framebuffer(mmio.as_ptr(), mmio.size(), fb_phys, fb_size)?;
let (connectors, encoders) = detect_display_topology(&display)?;
@@ -140,16 +134,17 @@ impl AmdDriver {
}
info!(
"redox-drm: AMD driver ready for {} with {} connector(s), {} firmware blob(s) loaded",
"redox-drm: AMD driver ready for {} with {} connector(s), {} firmware blob(s) loaded, IRQ mode {}",
info.location,
connectors.len(),
fw_count
fw_count,
irq_mode
);
Ok(Self {
info,
mmio,
irq_handle,
irq_handle: Mutex::new(irq_handle),
display,
gem: Mutex::new(GemManager::new()),
connectors: Mutex::new(connectors),
@@ -163,7 +158,7 @@ impl AmdDriver {
})
}
pub fn process_irq(&self) -> Result<IrqEvent> {
pub fn process_irq(&self) -> Result<Option<DriverEvent>> {
let ih_status = self.read_mmio_reg(AMD_IH_STATUS);
let ih_cntl = self.read_mmio_reg(AMD_IH_CNTL);
let ih_rptr = self.read_mmio_reg(AMD_IH_RB_RPTR);
@@ -188,7 +183,7 @@ impl AmdDriver {
connector_id, ih_status, ih_cntl, ih_rptr, ih_wptr
);
return Ok(IrqEvent::Hotplug { connector_id });
return Ok(Some(DriverEvent::Hotplug { connector_id }));
}
if ring_pending || (ih_status & AMD_IH_STATUS_INTERRUPT_PENDING_MASK != 0) {
@@ -201,12 +196,12 @@ impl AmdDriver {
crtc_id, count, ih_status, ih_cntl, ih_rptr, ih_wptr
);
return Ok(IrqEvent::Vblank { crtc_id, count });
return Ok(Some(DriverEvent::Vblank { crtc_id, count }));
}
}
self.acknowledge_ih(ih_wptr);
Ok(IrqEvent::Unknown)
Ok(None)
}
fn read_mmio_reg(&self, register_index: usize) -> u32 {
@@ -541,32 +536,53 @@ impl GpuDriver for AmdDriver {
}
}
fn handle_irq(&self) -> Result<Option<(u32, u64)>> {
fn handle_irq(&self) -> Result<Option<DriverEvent>> {
let irq_event = {
let mut irq_handle = self
.irq_handle
.lock()
.map_err(|_| DriverError::Initialization("AMD IRQ state poisoned".into()))?;
match irq_handle.as_mut() {
Some(handle) => handle.try_wait()?,
None => return Ok(None),
}
};
if !irq_event {
return Ok(None);
}
let irq = self
.irq_handle
.lock()
.ok()
.and_then(|guard| guard.as_ref().map(|h| h.irq()));
match self.process_irq()? {
IrqEvent::Vblank { crtc_id, count } => {
Some(DriverEvent::Vblank { crtc_id, count }) => {
debug!(
"redox-drm: handled AMD vblank IRQ for {} CRTC {} count={} irq={:?}",
self.info.location,
crtc_id,
count,
self.irq_handle.as_ref().map(|h| h.irq())
irq
);
Ok(Some((crtc_id, count)))
Ok(Some(DriverEvent::Vblank { crtc_id, count }))
}
IrqEvent::Hotplug { connector_id } => {
Some(DriverEvent::Hotplug { connector_id }) => {
info!(
"redox-drm: handled AMD hotplug IRQ for {} connector {} irq={:?}",
self.info.location,
connector_id,
self.irq_handle.as_ref().map(|h| h.irq())
irq
);
Ok(None)
Ok(Some(DriverEvent::Hotplug { connector_id }))
}
IrqEvent::Unknown => {
None => {
debug!(
"redox-drm: handled AMD IRQ for {} with no decoded source irq={:?}",
self.info.location,
self.irq_handle.as_ref().map(|h| h.irq())
irq
);
Ok(None)
}
@@ -9,8 +9,9 @@ use std::sync::Mutex;
use log::{debug, info, warn};
use redox_driver_sys::memory::MmioRegion;
use redox_driver_sys::pci::{PciBarInfo, PciDevice, PciDeviceInfo};
use redox_driver_sys::quirks::PciQuirkFlags;
use crate::driver::{DriverError, GpuDriver, Result};
use crate::driver::{DriverError, DriverEvent, GpuDriver, Result};
use crate::drivers::interrupt::InterruptHandle;
use crate::gem::{GemHandle, GemManager};
use crate::kms::connector::{synthetic_edid, Connector};
@@ -57,6 +58,27 @@ impl IntelDriver {
)));
}
let quirks = info.quirks();
if !quirks.is_empty() {
info!(
"redox-drm: Intel init for {} using quirk policy {:?}",
info.location, quirks
);
}
if quirks.contains(PciQuirkFlags::DISABLE_ACCEL) {
return Err(DriverError::Pci(format!(
"device {:#06x}:{:#06x} at {} has DISABLE_ACCEL quirk — refusing Intel init",
info.vendor_id, info.device_id, info.location
)));
}
if quirks.contains(PciQuirkFlags::NEED_FIRMWARE) {
info!(
"redox-drm: Intel device {} entered init with explicit firmware policy and {} cached blob(s)",
info.location,
firmware.len()
);
}
let gtt_bar = find_memory_bar(&info, 0, "GGTT BAR0")?;
let mmio_bar = find_memory_bar(&info, 2, "MMIO BAR2")?;
validate_intel_bars(&info, &gtt_bar, &mmio_bar)?;
@@ -93,18 +115,21 @@ impl IntelDriver {
None
}
};
let irq_mode = irq_handle.as_ref().map(|handle| handle.mode_name()).unwrap_or("none");
if !firmware.is_empty() {
warn!(
"redox-drm: Intel driver ignores {} firmware blob(s); i915-class GPUs usually boot without scheme:firmware blobs",
firmware.len()
info!(
"redox-drm: Intel startup firmware cache populated with {} blob(s) for {}",
firmware.len(),
info.location
);
}
info!(
"redox-drm: Intel driver ready for {} with {} connector(s)",
"redox-drm: Intel driver ready for {} with {} connector(s), IRQ mode {}",
info.location,
connectors.len()
connectors.len(),
irq_mode
);
Ok(Self {
@@ -177,7 +202,7 @@ impl IntelDriver {
Ok(connector.info.connector_type_id.saturating_sub(1) as u8)
}
fn process_irq(&self) -> Result<Option<(u32, u64)>> {
fn process_irq(&self) -> Result<Option<DriverEvent>> {
let previous = self.cached_connectors();
let current = self.refresh_connectors()?;
@@ -186,6 +211,20 @@ impl IntelDriver {
"redox-drm: Intel hotplug event detected on {}",
self.info.location
);
if let Some(connector) = current
.iter()
.find(|connector| {
previous
.iter()
.find(|old| old.id == connector.id)
.map(|old| old.connection != connector.connection)
.unwrap_or(true)
})
{
return Ok(Some(DriverEvent::Hotplug {
connector_id: connector.id,
}));
}
}
let ring_busy = self
@@ -200,7 +239,7 @@ impl IntelDriver {
"redox-drm: Intel IRQ decoded as display event crtc={} ring_busy={}",
crtc_id, ring_busy
);
return Ok(Some((crtc_id, count)));
return Ok(Some(DriverEvent::Vblank { crtc_id, count }));
}
if ring_busy {
@@ -459,7 +498,7 @@ impl GpuDriver for IntelDriver {
}
}
fn handle_irq(&self) -> Result<Option<(u32, u64)>> {
fn handle_irq(&self) -> Result<Option<DriverEvent>> {
let irq_event = {
let mut irq_handle = self
.irq_handle
@@ -23,10 +23,22 @@ pub enum InterruptHandle {
},
}
fn force_legacy_irq(quirks: PciQuirkFlags) -> bool {
quirks.contains(PciQuirkFlags::FORCE_LEGACY_IRQ)
}
impl InterruptHandle {
pub fn setup(device_info: &PciDeviceInfo, pci_device: &mut PciDevice) -> Result<Self> {
let quirks = device_info.quirks();
if force_legacy_irq(quirks) {
info!(
"redox-drm: forcing legacy IRQ for {} (FORCE_LEGACY_IRQ quirk)",
device_info.location
);
return Self::try_legacy(device_info);
}
if !quirks.contains(PciQuirkFlags::NO_MSIX) {
if let Ok(Some(handle)) = Self::try_msix(device_info, pci_device) {
return Ok(handle);
@@ -49,13 +61,6 @@ impl InterruptHandle {
);
}
if quirks.contains(PciQuirkFlags::FORCE_LEGACY_IRQ) {
info!(
"redox-drm: forcing legacy IRQ for {} (FORCE_LEGACY_IRQ quirk)",
device_info.location
);
}
Self::try_legacy(device_info)
}
@@ -196,7 +201,6 @@ impl InterruptHandle {
.map_err(|e| DriverError::Io(e.to_string()))
}
InterruptHandle::Msi { handle, .. } | InterruptHandle::Legacy { handle, .. } => {
let mut buf = [0u8; 8];
let _ = handle.wait().map_err(|e| DriverError::Io(e.to_string()))?;
Ok(())
}
@@ -210,7 +214,31 @@ impl InterruptHandle {
}
}
pub fn mode_name(&self) -> &'static str {
match self {
InterruptHandle::Msix { .. } => "MSI-X",
InterruptHandle::Msi { .. } => "MSI",
InterruptHandle::Legacy { .. } => "legacy INTx",
}
}
pub fn is_msix(&self) -> bool {
matches!(self, InterruptHandle::Msix { .. })
}
}
#[cfg(test)]
mod tests {
use super::force_legacy_irq;
use redox_driver_sys::quirks::PciQuirkFlags;
#[test]
fn force_legacy_irq_only_triggers_on_quirk() {
assert!(!force_legacy_irq(PciQuirkFlags::empty()));
assert!(!force_legacy_irq(PciQuirkFlags::NO_MSI));
assert!(force_legacy_irq(PciQuirkFlags::FORCE_LEGACY_IRQ));
assert!(force_legacy_irq(
PciQuirkFlags::FORCE_LEGACY_IRQ | PciQuirkFlags::NO_MSIX
));
}
}