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:
2026-05-04 18:27:56 +01:00
parent 029472d5e3
commit 2ae7ad7afd
2 changed files with 38 additions and 10 deletions
@@ -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