intel: GEM Phase 10-12 — DMA-BUF, create params, LMEM allocator
gem_dmabuf.rs (65 lines): DmaBufManager: export/import/release with fd→handle mapping DmaBufExport/DmaBufImport structs with size tracking Per-handle export ref-counting through GemObjectManager gem_create.rs (40 lines): CreateParams: size, region, flags, alignment, name CreateManager::create() with param validation create_lmem/create_named convenience constructors gem_lmem.rs (60 lines): LmemAllocator: linear allocator for discrete GPU VRAM write_region/read_region with DWORD-aligned MMIO access 64KB alignment, used_bytes tracking, out-of-bounds checking Ported from Linux 7.1: gem/i915_gem_dmabuf.c → DmaBufManager gem/i915_gem_create.c → CreateManager + CreateParams gem/i915_gem_lmem.c → LmemAllocator GEM subdirectory: 14 files, 1050 lines, 0 errors
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
use super::gem_object::{GemObjectManager, MemoryRegionType};
|
||||
use crate::driver::{DriverError, Result};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CreateParams {
|
||||
pub size: u64,
|
||||
pub region: MemoryRegionType,
|
||||
pub flags: u32,
|
||||
pub alignment: u64,
|
||||
pub name: Option<String>,
|
||||
}
|
||||
|
||||
impl CreateParams {
|
||||
pub fn new(size: u64) -> Self {
|
||||
Self { size, region: MemoryRegionType::System, flags: 0, alignment: 4096, name: None }
|
||||
}
|
||||
|
||||
pub fn with_lmem(mut self) -> Self { self.region = MemoryRegionType::LocalMemory; self }
|
||||
pub fn with_alignment(mut self, align: u64) -> Self { self.alignment = align; self }
|
||||
pub fn with_name(mut self, name: &str) -> Self { self.name = Some(name.to_string()); self }
|
||||
}
|
||||
|
||||
pub struct CreateManager;
|
||||
|
||||
impl CreateManager {
|
||||
pub fn create(param: &CreateParams, object_manager: &mut GemObjectManager) -> Result<u32> {
|
||||
if param.size == 0 {
|
||||
return Err(DriverError::Buffer("GEM create: size must be > 0".into()));
|
||||
}
|
||||
if param.alignment == 0 || param.alignment % 4096 != 0 {
|
||||
return Err(DriverError::Buffer("GEM create: alignment must be 4K-aligned".into()));
|
||||
}
|
||||
|
||||
let handle = match param.name.as_deref() {
|
||||
Some(name) => object_manager.create_with_name(param.size, param.region, name)?,
|
||||
None => object_manager.create(param.size, param.region)?,
|
||||
};
|
||||
|
||||
Ok(handle)
|
||||
}
|
||||
|
||||
pub fn create_lmem(size: u64, object_manager: &mut GemObjectManager) -> Result<u32> {
|
||||
CreateManager::create(&CreateParams::new(size).with_lmem(), object_manager)
|
||||
}
|
||||
|
||||
pub fn create_named(size: u64, name: &str, object_manager: &mut GemObjectManager) -> Result<u32> {
|
||||
CreateManager::create(&CreateParams::new(size).with_name(name), object_manager)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
use std::sync::Arc;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::driver::{DriverError, Result};
|
||||
use super::gem_object::GemObjectManager;
|
||||
|
||||
pub struct DmaBufManager {
|
||||
exports: BTreeMap<u32, DmaBufExport>,
|
||||
imports: BTreeMap<u32, DmaBufImport>,
|
||||
next_fd: i32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DmaBufExport {
|
||||
pub gem_handle: u32,
|
||||
pub fd: i32,
|
||||
pub size: u64,
|
||||
pub exported: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DmaBufImport {
|
||||
pub gem_handle: u32,
|
||||
pub fd: i32,
|
||||
pub size: u64,
|
||||
}
|
||||
|
||||
impl DmaBufManager {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
exports: BTreeMap::new(), imports: BTreeMap::new(),
|
||||
next_fd: 10,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn export(&mut self, gem_handle: u32, object_manager: &mut GemObjectManager) -> Result<i32> {
|
||||
let size = {
|
||||
let obj = object_manager.get(gem_handle)?;
|
||||
obj.size
|
||||
};
|
||||
let fd = self.next_fd;
|
||||
self.next_fd += 1;
|
||||
|
||||
object_manager.mark_exported(gem_handle)?;
|
||||
self.exports.insert(fd as u32, DmaBufExport {
|
||||
gem_handle, fd, size, exported: true,
|
||||
});
|
||||
Ok(fd)
|
||||
}
|
||||
|
||||
pub fn import(&mut self, fd: i32, object_manager: &mut GemObjectManager) -> Result<u32> {
|
||||
if let Some(exp) = self.exports.get(&(fd as u32)) {
|
||||
let handle = object_manager.create(exp.size, super::gem_object::MemoryRegionType::System)?;
|
||||
self.imports.insert(fd as u32, DmaBufImport {
|
||||
gem_handle: handle, fd, size: exp.size,
|
||||
});
|
||||
return Ok(handle);
|
||||
}
|
||||
Err(DriverError::NotFound(format!("DMA-BUF fd {} not found", fd)))
|
||||
}
|
||||
|
||||
pub fn release_export(&mut self, fd: i32, object_manager: &mut GemObjectManager) -> Result<()> {
|
||||
if let Some(exp) = self.exports.remove(&(fd as u32)) {
|
||||
object_manager.unmark_exported(exp.gem_handle)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn export_for_handle(&self, gem_handle: u32) -> Option<i32> {
|
||||
self.exports.values()
|
||||
.find(|e| e.gem_handle == gem_handle)
|
||||
.map(|e| e.fd)
|
||||
}
|
||||
|
||||
pub fn active_exports(&self) -> usize { self.exports.len() }
|
||||
pub fn active_imports(&self) -> usize { self.imports.len() }
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
use std::sync::Arc;
|
||||
use redox_driver_sys::memory::MmioRegion;
|
||||
use crate::driver::Result;
|
||||
use crate::driver::DriverError;
|
||||
|
||||
pub struct LmemAllocator {
|
||||
mmio: Arc<MmioRegion>,
|
||||
total_bytes: u64,
|
||||
used_bytes: u64,
|
||||
largest_free: u64,
|
||||
alignment: u64,
|
||||
}
|
||||
|
||||
impl LmemAllocator {
|
||||
pub fn new(mmio: Arc<MmioRegion>, total: u64) -> Self {
|
||||
Self {
|
||||
mmio, total_bytes: total, used_bytes: 0,
|
||||
largest_free: total, alignment: 65536,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn allocate(&mut self, size: u64) -> Option<u64> {
|
||||
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();
|
||||
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();
|
||||
}
|
||||
|
||||
pub fn remaining(&self) -> u64 { self.total_bytes.saturating_sub(self.used_bytes) }
|
||||
|
||||
pub fn write_region(&self, offset: u64, data: &[u8]) -> Result<()> {
|
||||
if offset + data.len() as u64 > self.total_bytes {
|
||||
return Err(DriverError::Buffer("LMEM write out of bounds".into()));
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_region(&self, offset: u64, buf: &mut [u8]) -> Result<()> {
|
||||
if offset + buf.len() as u64 > self.total_bytes {
|
||||
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;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn used_bytes(&self) -> u64 { self.used_bytes }
|
||||
pub fn total_bytes(&self) -> u64 { self.total_bytes }
|
||||
}
|
||||
@@ -8,6 +8,9 @@ pub mod gem_region;
|
||||
pub mod gem_stolen;
|
||||
pub mod gem_tiling;
|
||||
pub mod gem_vma;
|
||||
pub mod gem_create;
|
||||
pub mod gem_dmabuf;
|
||||
pub mod gem_lmem;
|
||||
|
||||
pub use gem_context::{ContextManager, ContextPriority, GemContext, create_default_context};
|
||||
pub use gem_domain::{BusyManager, DomainManager, DomainState, GpuDomain, ThrottleManager};
|
||||
@@ -19,3 +22,6 @@ pub use gem_region::MemoryRegion;
|
||||
pub use gem_stolen::{ShrinkerManager, StolenMemoryManager};
|
||||
pub use gem_tiling::{FenceRegisterManager, TilingConfig, TilingManager, TilingMode};
|
||||
pub use gem_vma::{AddressSpaceType, GemVma, VmaManager};
|
||||
pub use gem_create::{CreateManager, CreateParams};
|
||||
pub use gem_dmabuf::{DmaBufManager, DmaBufExport, DmaBufImport};
|
||||
pub use gem_lmem::LmemAllocator;
|
||||
|
||||
Reference in New Issue
Block a user