diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_lmem.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_lmem.rs index bd345e01a4..9619f9f0ce 100644 --- a/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_lmem.rs +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/gem/gem_lmem.rs @@ -1,40 +1,149 @@ +use std::collections::BTreeMap; use std::sync::Arc; + use redox_driver_sys::memory::MmioRegion; -use crate::driver::Result; + use crate::driver::DriverError; +use crate::driver::Result; + +struct FreeBlock { + offset: u64, + size: u64, +} + +struct AllocEntry { + size: u64, +} pub struct LmemAllocator { mmio: Arc, total_bytes: u64, - used_bytes: u64, - largest_free: u64, + free_list: BTreeMap, + allocs: BTreeMap, alignment: u64, } impl LmemAllocator { pub fn new(mmio: Arc, total: u64) -> Self { + let mut free_list = BTreeMap::new(); + free_list.insert(0, FreeBlock { offset: 0, size: total }); Self { - mmio, total_bytes: total, used_bytes: 0, - largest_free: total, alignment: 65536, + mmio, + total_bytes: total, + free_list, + allocs: BTreeMap::new(), + alignment: 65536, } } pub fn allocate(&mut self, size: u64) -> Option { - let aligned = ((size + self.alignment - 1) / self.alignment) * self.alignment; - if aligned > self.remaining() { return None; } - let offset = self.used_bytes; - self.used_bytes += aligned; - self.largest_free = self.remaining(); + let aligned = Self::align_up(size, self.alignment); + if aligned > self.total_bytes { + return None; + } + + let mut best_offset = None; + let mut best_size = u64::MAX; + for (&off, block) in self.free_list.iter() { + if block.size >= aligned && block.size < best_size { + best_offset = Some(off); + best_size = block.size; + } + } + + let offset = best_offset?; + let block = self.free_list.remove(&offset).expect("block must exist"); + let remaining = block.size - aligned; + if remaining > 0 { + self.free_list + .insert(offset + aligned, FreeBlock { offset: offset + aligned, size: remaining }); + } + self.allocs.insert(offset, AllocEntry { size: aligned }); Some(offset) } pub fn free(&mut self, offset: u64, size: u64) { - let aligned = ((size + self.alignment - 1) / self.alignment) * self.alignment; - self.used_bytes = self.used_bytes.saturating_sub(aligned); - self.largest_free = self.remaining(); + let aligned = Self::align_up(size, self.alignment); + let entry = match self.allocs.remove(&offset) { + Some(e) => e, + None => return, + }; + let freed = entry.size.min(aligned); + + let next_offset = offset + freed; + if let Some(next_block) = self.free_list.remove(&next_offset) { + let merged = FreeBlock { offset, size: freed + next_block.size }; + self.free_list.insert(offset, merged); + } else { + self.free_list.insert(offset, FreeBlock { offset, size: freed }); + } + + if offset >= self.alignment { + let mut prev_key = None; + for (&off, block) in self.free_list.iter() { + if off + block.size == offset { + prev_key = Some(off); + } + } + if let Some(prev_off) = prev_key { + let prev_block = self.free_list.remove(&prev_off).expect("must exist"); + let merged = FreeBlock { + offset: prev_off, + size: prev_block.size + freed, + }; + self.free_list.remove(&offset); + self.free_list.insert(prev_off, merged); + } + } } - pub fn remaining(&self) -> u64 { self.total_bytes.saturating_sub(self.used_bytes) } + pub fn allocate_aligned(&mut self, size: u64, align: u64) -> Option { + let aligned_size = Self::align_up(size, self.alignment); + let align_mask = align - 1; + + for (&off, block) in self.free_list.iter() { + if block.size >= aligned_size { + let aligned_offset = (off + align_mask) & !align_mask; + if aligned_offset + aligned_size <= off + block.size { + let before = aligned_offset.saturating_sub(off); + let after = (off + block.size) - (aligned_offset + aligned_size); + + self.free_list.remove(&off); + if before > 0 { + self.free_list.insert(off, FreeBlock { offset: off, size: before }); + } + if after > 0 { + let after_off = aligned_offset + aligned_size; + self.free_list.insert(after_off, FreeBlock { offset: after_off, size: after }); + } + self.allocs.insert(aligned_offset, AllocEntry { size: aligned_size }); + return Some(aligned_offset); + } + } + } + None + } + + pub fn remaining(&self) -> u64 { + self.free_list.values().map(|b| b.size).sum() + } + + pub fn largest_free(&self) -> u64 { + self.free_list.values().map(|b| b.size).max().unwrap_or(0) + } + + pub fn used_bytes(&self) -> u64 { + self.total_bytes - self.remaining() + } + + pub fn total_bytes(&self) -> u64 { + self.total_bytes + } + + #[inline] + fn align_up(size: u64, align: u64) -> u64 { + ((size + align - 1) / align) * align + } pub fn write_region(&self, offset: u64, data: &[u8]) -> Result<()> { if offset + data.len() as u64 > self.total_bytes { @@ -42,10 +151,8 @@ impl LmemAllocator { } for (i, &byte) in data.iter().enumerate() { if (offset as usize + i) % 4 == 0 && i + 3 < data.len() { - let val = u32::from_le_bytes([ - data[i], data[i+1], data[i+2], data[i+3], - ]); - self.mmio.write32((offset as usize + i), val); + let val = u32::from_le_bytes([data[i], data[i + 1], data[i + 2], data[i + 3]]); + self.mmio.write32(offset as usize + i, val); } } Ok(()) @@ -56,18 +163,11 @@ impl LmemAllocator { return Err(DriverError::Buffer("LMEM read out of bounds".into())); } let mut i = 0; - while i < buf.len() { - if i + 4 <= buf.len() { - let val = self.mmio.read32((offset as usize + i)); - buf[i..i+4].copy_from_slice(&val.to_le_bytes()); - i += 4; - } else { - break; - } + while i + 4 <= buf.len() { + let val = self.mmio.read32(offset as usize + i); + buf[i..i + 4].copy_from_slice(&val.to_le_bytes()); + i += 4; } Ok(()) } - - pub fn used_bytes(&self) -> u64 { self.used_bytes } - pub fn total_bytes(&self) -> u64 { self.total_bytes } -} +} \ No newline at end of file diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/mocs.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/mocs.rs index ee35390951..fb7d05f4a4 100644 --- a/local/recipes/gpu/redox-drm/source/src/drivers/intel/mocs.rs +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/mocs.rs @@ -15,6 +15,13 @@ const GEN12_MOCS_UC: u32 = 0x0000_0008; const GEN12_MOCS_WT: u32 = 0x0000_0018; const GEN12_MOCS_WB: u32 = 0x0005_0038; +const GEN8_PPAT_WB: u32 = 0x3; +const GEN8_PPAT_WT: u32 = 0x2; +const GEN8_PPAT_WC: u32 = 0x1; +const GEN8_PPAT_UC: u32 = 0x0; +const GEN8_PPAT_LLC: u32 = 1 << 2; +const GEN8_PPAT_LLCELLC: u32 = 2 << 2; + pub fn init_mocs(mmio: &Arc, device_info: &IntelDeviceInfo) -> Result<()> { if device_info.is_gen12_or_later() { let entries: [u32; 64] = [ @@ -36,3 +43,30 @@ pub fn init_mocs(mmio: &Arc, device_info: &IntelDeviceInfo) -> Resul } Ok(()) } + +pub fn init_pat(mmio: &Arc, device_info: &IntelDeviceInfo) -> Result<()> { + if device_info.is_gen12_or_later() { + let base = 0x4800usize; + mmio.write32(base, GEN8_PPAT_WB); + mmio.write32(base + 4, GEN8_PPAT_WC); + mmio.write32(base + 8, GEN8_PPAT_WT); + mmio.write32(base + 12, GEN8_PPAT_UC); + mmio.write32(base + 16, GEN8_PPAT_WB); + mmio.write32(base + 20, GEN8_PPAT_WB); + mmio.write32(base + 24, GEN8_PPAT_WB); + mmio.write32(base + 28, GEN8_PPAT_WB); + info!("redox-drm-intel: Gen12 PAT initialized"); + } else if device_info.is_gen9_or_later() { + let base = 0x40E0usize; + mmio.write32(base, GEN8_PPAT_WB | GEN8_PPAT_LLC); + mmio.write32(base + 4, GEN8_PPAT_WC | GEN8_PPAT_LLCELLC); + mmio.write32(base + 8, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC); + mmio.write32(base + 12, GEN8_PPAT_UC); + mmio.write32(base + 16, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC); + mmio.write32(base + 20, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC); + mmio.write32(base + 24, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC); + mmio.write32(base + 28, GEN8_PPAT_WB | GEN8_PPAT_LLCELLC); + info!("redox-drm-intel: Gen9 PAT initialized"); + } + Ok(()) +} 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 ffb2dbd788..b846bd5329 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 @@ -354,6 +354,7 @@ impl IntelDriver { ); mocs::init_mocs(&mmio_arc, &device_info)?; + mocs::init_pat(&mmio_arc, &device_info)?; let mut dpll = DisplayPll::new(mmio_arc.clone(), &device_info); dpll.init()?; diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/regs_gt.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/regs_gt.rs index 19c5a4251b..deb81fd600 100644 --- a/local/recipes/gpu/redox-drm/source/src/drivers/intel/regs_gt.rs +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/regs_gt.rs @@ -450,3 +450,15 @@ pub const ICL_HDC_MODE: usize = 0x7300; pub const TBIMR_FAST_CLIP: u32 = 1 << 5; pub const L3_PWM_TIMER_INIT_VAL_MASK: u32 = 0x3FF; pub const FF_MODE2_TDS_TIMER_MASK: u32 = 0xFF << 16; + +pub const GEN8_PRIVATE_PAT_LO: usize = 0x40E0; +pub const GEN8_PRIVATE_PAT_HI: usize = 0x40E4; +pub const GEN12_PAT_INDEX: usize = 0x4800; + +pub const GEN8_PPAT_WB: u32 = 0x3; +pub const GEN8_PPAT_WT: u32 = 0x2; +pub const GEN8_PPAT_WC: u32 = 0x1; +pub const GEN8_PPAT_UC: u32 = 0x0; +pub const GEN8_PPAT_LLC: u32 = 1 << 2; +pub const GEN8_PPAT_LLCELLC: u32 = 2 << 2; +pub const GEN8_PPAT_ELLC_OVERRIDE: u32 = 0 << 2;