diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/execlists.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/execlists.rs new file mode 100644 index 0000000000..fe69046a07 --- /dev/null +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/execlists.rs @@ -0,0 +1,145 @@ +use std::sync::atomic::{AtomicU32, Ordering}; +use std::sync::Arc; + +use log::{debug, info, warn}; +use redox_driver_sys::memory::MmioRegion; + +use super::gtt::IntelGtt; +use crate::driver::Result; +use crate::driver::DriverError; + +const RING_ELSP_OFFSET: usize = 0x230; +const RING_EXECLIST_STATUS_LO: usize = 0x234; +const RING_CONTEXT_CONTROL_OFFSET: usize = 0x244; +const RING_CONTEXT_STATUS_PTR_OFFSET: usize = 0x3A0; +const RING_EXECLIST_CONTROL_OFFSET: usize = 0x550; + +const RING_ELSP_WRITE_COUNT: usize = 2; +const LRC_DESC_SIZE: usize = 4096; + +const CTX_CTRL_CTX_RESTORE_INHIBIT: u32 = 1 << 0; +const CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT: u32 = 1 << 1; +const CTX_CTRL_RS_CTX_ENABLE: u32 = 1 << 3; + +const EXECLIST_CONTROL_ENABLE: u32 = 1 << 0; + +const ELSP_VALID: u32 = 1 << 0; +const ELSP_PRIVILEGE_ACCESS: u32 = 1 << 8; + +const CSB_ENTRY_SIZE: usize = 8; +const MAX_CSB_ENTRIES: usize = 6; + +#[derive(Debug, Clone, Copy)] +pub struct ExeclistContext { + pub desc: u64, + pub engine_class: u8, + pub engine_instance: u8, +} + +pub struct ExeclistPort { + mmio: Arc, + ring_base: usize, + pending: [Option; RING_ELSP_WRITE_COUNT], + active: u32, +} + +impl ExeclistPort { + pub fn new(mmio: Arc, ring_base: usize) -> Self { + Self { + mmio, + ring_base, + pending: [None, None], + active: 0, + } + } + + pub fn init(&mut self) -> Result<()> { + let ctrl = self.ring_base + RING_EXECLIST_CONTROL_OFFSET; + self.mmio.write_u32(ctrl, EXECLIST_CONTROL_ENABLE); + + let ctx_ctrl = self.ring_base + RING_CONTEXT_CONTROL_OFFSET; + self.mmio.write_u32(ctx_ctrl, + CTX_CTRL_CTX_RESTORE_INHIBIT + | CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT + | CTX_CTRL_RS_CTX_ENABLE, + ); + + let csb_ptr = self.ring_base + RING_CONTEXT_STATUS_PTR_OFFSET; + self.mmio.write_u32(csb_ptr, 0); + + info!("redox-drm-intel: execlist port initialized at {:#06x}", self.ring_base); + Ok(()) + } + + pub fn submit(&mut self, ctx: ExeclistContext) -> Result<()> { + let slot = if self.pending[0].is_none() { 0 } else { 1 }; + self.pending[slot] = Some(ctx); + + self.flush_pending()?; + self.active += 1; + Ok(()) + } + + fn flush_pending(&mut self) -> Result<()> { + for slot in 0..RING_ELSP_WRITE_COUNT { + if let Some(ref ctx) = self.pending[slot] { + let elsp = self.ring_base + RING_ELSP_OFFSET + slot * 4; + let desc_lo = ctx.desc as u32; + let desc_hi = (ctx.desc >> 32) as u32; + self.mmio.write_u32(elsp, desc_lo); + self.mmio.write_u32(elsp + 4, desc_hi); + self.pending[slot] = None; + } + } + Ok(()) + } + + pub fn check_completion(&mut self) -> usize { + let status_lo = self.ring_base + RING_EXECLIST_STATUS_LO; + let status = self.mmio.read_u32(status_lo); + + let completed = (status & 0x07) as usize; + if completed > 0 { + self.active = self.active.saturating_sub(completed); + debug!("redox-drm-intel: {} contexts completed, {} active", + completed, self.active); + } + completed + } + + pub fn active_count(&self) -> u32 { + self.active + } + + pub fn is_idle(&self) -> bool { + self.active == 0 + } +} + +pub fn create_lrc_descriptor(gtt: &IntelGtt, ring_addr: u64, indirect_ctx: bool) -> Result { + let lrc_addr = gtt.allocate_range(LRC_DESC_SIZE)?; + + let desc = if indirect_ctx { + lrc_addr | ELSP_VALID | ELSP_PRIVILEGE_ACCESS | (1 << 42) + } else { + lrc_addr | ELSP_VALID | ELSP_PRIVILEGE_ACCESS + }; + + debug!("redox-drm-intel: LRC descriptor {:#018x} (ring {:#018x})", desc, ring_addr); + Ok(desc) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_execlist_context() { + let ctx = ExeclistContext { + desc: 0x1000 | ELSP_VALID as u64, + engine_class: 0, + engine_instance: 0, + }; + assert!(ctx.desc & ELSP_VALID as u64 != 0); + } +} diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/mod.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/mod.rs index 61fffefaea..715ae873aa 100644 --- a/local/recipes/gpu/redox-drm/source/src/drivers/intel/mod.rs +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/mod.rs @@ -9,6 +9,7 @@ pub mod display_power; pub mod display_watermark; pub mod dp_aux; pub mod dp_link; +pub mod execlists; pub mod fence; pub mod gmbus; pub mod gtt;