hardware 0.0.9

A no_std bare-metal hardware abstraction layer — all port I/O, memory and swap allocations are guarded at runtime. Do not consider this dependency stable before x.1.x
Documentation
use core::sync::atomic::{AtomicUsize, Ordering};

const DMA_BUF_REG: usize = 0x300;
const DMA_SIZE_REG: usize = 0x308;
const DMA_CTRL_REG: usize = 0x310;
const DMA_STATUS_REG: usize = 0x314;

const COHERENT_REGION_SIZE: usize = 4 * 1024 * 1024;
const COHERENT_ALIGN: usize = 4096;

static COHERENT_BASE: AtomicUsize = AtomicUsize::new(0);
static COHERENT_OFFSET: AtomicUsize = AtomicUsize::new(0);

pub fn setup_coherent_region(mmio_base: usize) -> usize {
    let buf = crate::dma::buffer::DmaBuffer::new(COHERENT_REGION_SIZE, COHERENT_ALIGN);
    let phys = match buf {
        Some(ref b) => {
            let p = b.phys_addr();
            if let Some(ctrl) = crate::iommu::controller::get() {
                if ctrl.is_enabled() {
                    ctrl.translate_iova(p).unwrap_or(p)
                } else {
                    p
                }
            } else {
                p
            }
        }
        None => 0,
    };

    COHERENT_BASE.store(phys, Ordering::Release);

    unsafe {
        super::super::mmio::mmio_write32(mmio_base + DMA_BUF_REG, phys as u32);
        super::super::mmio::mmio_write32(mmio_base + DMA_BUF_REG + 4, (phys >> 32) as u32);
        super::super::mmio::mmio_write32(mmio_base + DMA_SIZE_REG, COHERENT_REGION_SIZE as u32);
        super::super::mmio::mmio_write32(mmio_base + DMA_CTRL_REG, 1);
    }

    phys
}

pub fn alloc_coherent(size: usize) -> Option<usize> {
    let base = COHERENT_BASE.load(Ordering::Acquire);
    if base == 0 {
        return None;
    }
    let aligned_size = (size + COHERENT_ALIGN - 1) & !(COHERENT_ALIGN - 1);
    let off = COHERENT_OFFSET.fetch_add(aligned_size, Ordering::AcqRel);
    if off + aligned_size > COHERENT_REGION_SIZE {
        return None;
    }
    Some(base + off)
}

pub fn submit_inference_dma(token_phys: u64, token_count: u32) -> bool {
    let base = super::device::mmio_base();
    if base == 0 {
        return false;
    }
    unsafe {
        super::super::mmio::mmio_write32(base + DMA_BUF_REG, token_phys as u32);
        super::super::mmio::mmio_write32(base + DMA_BUF_REG + 4, (token_phys >> 32) as u32);
        super::super::mmio::mmio_write32(base + DMA_SIZE_REG, token_count);
        super::super::mmio::mmio_write32(base + DMA_CTRL_REG, 0x03);
    }
    true
}

pub fn is_dma_complete() -> bool {
    let base = super::device::mmio_base();
    if base == 0 {
        return false;
    }
    let status = unsafe { super::super::mmio::mmio_read32(base + DMA_STATUS_REG) };
    status & 0x01 != 0
}

pub fn coherent_base() -> usize {
    COHERENT_BASE.load(Ordering::Acquire)
}