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:
@@ -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, >t_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
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user