intel: Phase 2 — memory management modernization
- mod.rs: identity PPGTT with 2MB-pages, PDP register programming in cs_submit - lmem.rs: free-list page allocator replacing simple bump allocator - ring.rs: expose write_reg as pub(crate) for PDP register access
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
use log::info;
|
||||
use log::{debug, info};
|
||||
|
||||
use redox_driver_sys::memory::MmioRegion;
|
||||
|
||||
@@ -25,6 +25,8 @@ pub struct IntelLmem {
|
||||
bar_addr: u64,
|
||||
bar_size: u64,
|
||||
next_offset: u64,
|
||||
free_list: Vec<(u64, u64)>,
|
||||
total_allocated: u64,
|
||||
}
|
||||
|
||||
impl IntelLmem {
|
||||
@@ -43,29 +45,73 @@ impl IntelLmem {
|
||||
bar_addr,
|
||||
bar_size,
|
||||
next_offset: 0,
|
||||
free_list: Vec::new(),
|
||||
total_allocated: 0,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn alloc(&mut self, size: u64, alignment: u64) -> Result<u64> {
|
||||
let aligned_size = align_up(size, alignment);
|
||||
|
||||
if let Some(idx) = self
|
||||
.free_list
|
||||
.iter()
|
||||
.position(|&(start, free_size)| {
|
||||
let aligned_start = align_up(start, alignment);
|
||||
aligned_start + aligned_size <= start + free_size
|
||||
})
|
||||
{
|
||||
let (free_start, free_size) = self.free_list.remove(idx);
|
||||
let aligned = align_up(free_start, alignment);
|
||||
let remainder = (aligned + aligned_size).saturating_sub(free_start);
|
||||
if remainder < free_size {
|
||||
self.free_list
|
||||
.push((free_start + remainder, free_size - remainder));
|
||||
}
|
||||
self.total_allocated += aligned_size;
|
||||
let vram_addr = self.bar_addr + aligned;
|
||||
debug!(
|
||||
"redox-drm-intel: LMEM reused {:#x} bytes at offset {:#x} (phys {:#010x}) from free list",
|
||||
aligned_size, aligned, vram_addr
|
||||
);
|
||||
return Ok(vram_addr);
|
||||
}
|
||||
|
||||
let aligned = align_up(self.next_offset, alignment);
|
||||
let end = aligned
|
||||
.checked_add(size)
|
||||
.checked_add(aligned_size)
|
||||
.ok_or_else(|| DriverError::Buffer("Intel LMEM allocation overflow".into()))?;
|
||||
if end > self.bar_size {
|
||||
return Err(DriverError::Buffer(format!(
|
||||
"Intel LMEM exhausted: need {:#x} at offset {:#x}, have {:#x}",
|
||||
size, aligned, self.bar_size
|
||||
aligned_size, aligned, self.bar_size
|
||||
)));
|
||||
}
|
||||
self.next_offset = end;
|
||||
self.total_allocated += aligned_size;
|
||||
let vram_addr = self.bar_addr + aligned;
|
||||
info!(
|
||||
"redox-drm-intel: LMEM allocated {:#x} bytes at offset {:#x} (phys {:#010x})",
|
||||
size, aligned, vram_addr
|
||||
aligned_size, aligned, vram_addr
|
||||
);
|
||||
Ok(vram_addr)
|
||||
}
|
||||
|
||||
pub fn free(&mut self, offset: u64, size: u64) {
|
||||
let aligned_size = align_up(size, 4096);
|
||||
self.free_list.push((offset, aligned_size));
|
||||
self.free_list.sort_by_key(|&(start, _)| start);
|
||||
self.total_allocated = self.total_allocated.saturating_sub(aligned_size);
|
||||
debug!(
|
||||
"redox-drm-intel: LMEM freed {:#x} bytes at offset {:#x}, {} regions in free list",
|
||||
aligned_size, offset, self.free_list.len()
|
||||
);
|
||||
}
|
||||
|
||||
pub fn allocated_bytes(&self) -> u64 {
|
||||
self.total_allocated
|
||||
}
|
||||
|
||||
pub fn vram_mmio(&self) -> &MmioRegion {
|
||||
&self.mmio
|
||||
}
|
||||
|
||||
@@ -89,7 +89,6 @@ const RING_HEAD_OFFSET: usize = 0x34;
|
||||
|
||||
const GEN8_PDP0_UDW: usize = 0x270;
|
||||
const GEN8_PDP0_LDW: usize = 0x274;
|
||||
const GEN8_PDP_STRIDE: usize = 8;
|
||||
|
||||
pub struct IntelDriver {
|
||||
info: PciDeviceInfo,
|
||||
@@ -290,7 +289,11 @@ impl IntelDriver {
|
||||
let mut ring = IntelRing::create(mmio_arc.clone(), RingType::Render)?;
|
||||
ring.bind_gtt(&mut gtt)?;
|
||||
|
||||
let (default_pd_base, has_ppgtt) = setup_identity_ppgtt(&mut gtt, &device_info)?;
|
||||
let (default_pd_base, has_ppgtt) = if device_info.is_gen9_or_later() {
|
||||
setup_identity_ppgtt(&mut gtt)?
|
||||
} else {
|
||||
(0, false)
|
||||
};
|
||||
|
||||
let mut guc = GucFirmware::new(mmio_arc.clone());
|
||||
if let Some(guc_key) = device_info.guc_fw_key {
|
||||
@@ -1018,6 +1021,14 @@ impl GpuDriver for IntelDriver {
|
||||
|
||||
let mut ring = self.ring.lock()
|
||||
.map_err(|_| DriverError::Initialization("Intel ring state poisoned".into()))?;
|
||||
|
||||
if self.has_ppgtt && self.default_pd_base != 0 {
|
||||
let pd_lo = (self.default_pd_base & 0xFFFF_FFFF) as u32;
|
||||
let pd_hi = ((self.default_pd_base >> 32) & 0xFFFF_FFFF) as u32;
|
||||
ring.write_reg(GEN8_PDP0_LDW, pd_lo)?;
|
||||
ring.write_reg(GEN8_PDP0_UDW, pd_hi)?;
|
||||
}
|
||||
|
||||
ring.submit_batch(cmds)?;
|
||||
let seqno = ring.last_seqno();
|
||||
drop(ring);
|
||||
@@ -1261,3 +1272,36 @@ fn discover_vbt(mmio: &MmioRegion) -> Option<vbt::VbtInfo> {
|
||||
debug!("redox-drm-intel: no VBT found in MMIO, using port heuristic");
|
||||
None
|
||||
}
|
||||
|
||||
fn setup_identity_ppgtt(gtt: &mut IntelGtt) -> Result<(u64, bool)> {
|
||||
use redox_driver_sys::dma::DmaBuffer;
|
||||
|
||||
let pd_bytes = 4096usize;
|
||||
let mut pd_buf = DmaBuffer::allocate(pd_bytes, 4096)
|
||||
.map_err(|e| DriverError::Buffer(format!("PPGTT PD DMA alloc failed: {e}")))?;
|
||||
let pd_phys = pd_buf.physical_address() as u64;
|
||||
|
||||
let pd_slice = unsafe {
|
||||
std::slice::from_raw_parts_mut(pd_buf.as_mut_ptr(), pd_bytes)
|
||||
};
|
||||
|
||||
for entry in 0..128u64 {
|
||||
let page_addr = entry * 0x200000;
|
||||
let pte_val = page_addr
|
||||
| (1u64 << 0)
|
||||
| (1u64 << 1)
|
||||
| (1u64 << 7);
|
||||
let offset = (entry as usize) * 8;
|
||||
pd_slice[offset..offset + 8].copy_from_slice(&pte_val.to_le_bytes());
|
||||
}
|
||||
|
||||
let pd_gpu_addr = gtt.alloc_range(pd_bytes as u64)?;
|
||||
gtt.map_range(pd_gpu_addr, pd_phys, pd_bytes as u64, (1u64 << 0) | (1u64 << 1))?;
|
||||
|
||||
info!(
|
||||
"redox-drm-intel: identity PPGTT PD at {:#010x} (phys {:#010x}, 128 × 2MB entries, covers {}MB)",
|
||||
pd_gpu_addr, pd_phys, 128 * 2
|
||||
);
|
||||
|
||||
Ok((pd_gpu_addr, true))
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ impl IntelRing {
|
||||
Ok(self.mmio.read32(offset))
|
||||
}
|
||||
|
||||
fn write_reg(&self, reg: usize, value: u32) -> Result<()> {
|
||||
pub(crate) fn write_reg(&self, reg: usize, value: u32) -> Result<()> {
|
||||
let offset = self
|
||||
.base
|
||||
.checked_add(reg)
|
||||
|
||||
Reference in New Issue
Block a user