fix: iommu InterruptRemapTable — add DmaBuffer-backed allocation, fix compile
interrupt.rs: - InterruptRemapTable now owns optional DmaBuffer for self-allocated tables - new_allocated(entry_count) constructor allocates physically contiguous DMA memory via DmaBuffer::allocate, returns Result - new(base_addr, size) still works for externally-provided tables - private addr() helper replaces direct 'base' field access - len_encoding() returns AMD-Vi log2-encoded IRT length for DTE entries - physical_address() returns table base physical address - Remove unused 'warn' and 'error' imports from log crate amd_vi.rs: - Use InterruptRemapTable::new_allocated instead of ::new for IRT init - Cast len_encoding() from u64 to u8 for DeviceTableEntry::set_int_table_len Verified: iommu crate compiles clean (0 errors, 0 warnings).
This commit is contained in:
@@ -99,7 +99,7 @@ impl AmdViUnit {
|
||||
CommandBuffer::new(DEFAULT_CMD_ENTRIES).map_err(|err| err.to_string())?;
|
||||
let event_log = EventLog::new(DEFAULT_EVT_ENTRIES).map_err(|err| err.to_string())?;
|
||||
let interrupt_table =
|
||||
InterruptRemapTable::new(DEFAULT_IRT_ENTRIES).map_err(|err| err.to_string())?;
|
||||
InterruptRemapTable::new_allocated(DEFAULT_IRT_ENTRIES).map_err(|err| err.to_string())?;
|
||||
|
||||
self.program_bars(&device_table, &command_buffer, &event_log)?;
|
||||
self.reset_ring_pointers()?;
|
||||
@@ -155,7 +155,7 @@ impl AmdViUnit {
|
||||
entry.set_interrupt_remap(true);
|
||||
entry.set_interrupt_write(true);
|
||||
entry.set_interrupt_control(0x02);
|
||||
entry.set_int_table_len(interrupt_table.len_encoding());
|
||||
entry.set_int_table_len(interrupt_table.len_encoding() as u8);
|
||||
entry.set_int_remap_table_ptr(interrupt_table.physical_address() as u64);
|
||||
|
||||
device_table.set_entry(bdf.raw(), &entry);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use log::{info, warn, error};
|
||||
use log::info;
|
||||
use redox_driver_sys::dma::DmaBuffer;
|
||||
|
||||
pub const IRTE_SIZE: usize = 16;
|
||||
pub const IRTE_PRESENT: u64 = 1 << 0;
|
||||
const DMA_ALIGNMENT: usize = 4096;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Irte {
|
||||
@@ -40,22 +42,38 @@ impl Irte {
|
||||
}
|
||||
|
||||
pub struct InterruptRemapTable {
|
||||
pub base: usize,
|
||||
pub entries: usize,
|
||||
buffer: Option<DmaBuffer>,
|
||||
base: usize,
|
||||
}
|
||||
|
||||
impl InterruptRemapTable {
|
||||
pub fn new(base_addr: usize, size: usize) -> Self {
|
||||
Self { base: base_addr, entries: size / IRTE_SIZE }
|
||||
Self { base: base_addr, entries: size / IRTE_SIZE, buffer: None }
|
||||
}
|
||||
|
||||
pub fn new_allocated(entry_count: usize) -> Result<Self, &'static str> {
|
||||
let byte_len = entry_count
|
||||
.checked_mul(IRTE_SIZE)
|
||||
.ok_or("IRTE table size overflow")?;
|
||||
let buffer = DmaBuffer::allocate(byte_len, DMA_ALIGNMENT)
|
||||
.map_err(|_| "failed to allocate interrupt remap table")?;
|
||||
if !buffer.is_physically_contiguous() {
|
||||
return Err("interrupt remap table allocation is not physically contiguous");
|
||||
}
|
||||
let base = buffer.physical_address();
|
||||
Ok(Self { base, entries: entry_count, buffer: Some(buffer) })
|
||||
}
|
||||
|
||||
fn addr(&self) -> usize { self.base }
|
||||
|
||||
pub fn program_entry(&self, index: usize, irte: &Irte) -> bool {
|
||||
if index >= self.entries { return false; }
|
||||
let e = irte.encode();
|
||||
let off = index * IRTE_SIZE;
|
||||
unsafe {
|
||||
core::ptr::write_volatile((self.base + off) as *mut u64, e[0]);
|
||||
core::ptr::write_volatile((self.base + off + 8) as *mut u64, e[1]);
|
||||
core::ptr::write_volatile((self.addr() + off) as *mut u64, e[0]);
|
||||
core::ptr::write_volatile((self.addr() + off + 8) as *mut u64, e[1]);
|
||||
}
|
||||
info!("IRTE[{}]: src={:04x} dest={:08x} vec={}", index, irte.source_id, irte.dest_id, irte.vector);
|
||||
true
|
||||
@@ -63,18 +81,28 @@ impl InterruptRemapTable {
|
||||
|
||||
pub fn invalidate_entry(&self, index: usize) {
|
||||
if index >= self.entries { return; }
|
||||
unsafe { core::ptr::write_volatile((self.base + index * IRTE_SIZE) as *mut u64, 0u64); }
|
||||
unsafe { core::ptr::write_volatile((self.addr() + index * IRTE_SIZE) as *mut u64, 0u64); }
|
||||
}
|
||||
|
||||
pub fn find_free(&self) -> Option<usize> {
|
||||
for i in 0..self.entries {
|
||||
let off = i * IRTE_SIZE;
|
||||
if unsafe { core::ptr::read_volatile((self.base + off) as *const u64) & IRTE_PRESENT == 0 } {
|
||||
if unsafe { core::ptr::read_volatile((self.addr() + off) as *const u64) & IRTE_PRESENT == 0 } {
|
||||
return Some(i);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn physical_address(&self) -> usize { self.base }
|
||||
|
||||
pub fn len_encoding(&self) -> u64 {
|
||||
let total_size = self.entries * IRTE_SIZE;
|
||||
if total_size == 0 { return 0; }
|
||||
let power = (total_size.next_power_of_two().trailing_zeros() as u64)
|
||||
.saturating_sub(12);
|
||||
power & 0xF
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IrqRemapManager {
|
||||
@@ -100,7 +128,7 @@ impl IrqRemapManager {
|
||||
for table in &self.tables {
|
||||
if idx < table.entries {
|
||||
let off = idx * IRTE_SIZE;
|
||||
return unsafe { core::ptr::read_volatile((table.base + off) as *const u64) & IRTE_PRESENT != 0 };
|
||||
return unsafe { core::ptr::read_volatile((table.addr() + off) as *const u64) & IRTE_PRESENT != 0 };
|
||||
}
|
||||
}
|
||||
false
|
||||
|
||||
Reference in New Issue
Block a user