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 crate::dma::buffer::DmaBuffer;
use crate::dma::engine;
use crate::gpu::GpuDevice;
use core::sync::atomic::{AtomicUsize, Ordering};

static NV_IRQ_COUNT: AtomicUsize = AtomicUsize::new(0);

pub fn nvidia_irq_shim() {
    NV_IRQ_COUNT.fetch_add(1, Ordering::AcqRel);
}

pub struct NvidiaDriver {
    pub device: GpuDevice,
    mapped_bar: Option<usize>,
}

impl NvidiaDriver {
    pub fn probe(dev: &GpuDevice) -> Option<Self> {
        if dev.vendor_id == 0x10DE {
            Some(NvidiaDriver {
                device: *dev,
                mapped_bar: None,
            })
        } else {
            None
        }
    }

    pub fn init(&mut self) -> bool {
        if self.device.bar0 != 0 {
            let bar_off = 0x10u8;
            if let Some(sz) = crate::bus::pci::api::probe_bar_size(
                self.device.bus,
                self.device.device,
                self.device.function,
                bar_off,
            ) {
                let base = (self.device.bar0 as usize) & !0xfusize;
                let va = crate::bus::pci::api::map_mmio_region(base, sz);
                self.mapped_bar = Some(va);
            } else {
                self.mapped_bar = Some(self.device.bar0 as usize);
            }
        }
        if let Some(d) = crate::bus::pci::api::read_config_u32(
            self.device.bus,
            self.device.device,
            self.device.function,
            0x3C,
        ) {
            let irq_line = (d & 0xff) as u8;
            if irq_line != 0 && irq_line != 0xff {
                let vec = 0x20u8.wrapping_add(irq_line);
                let ok = crate::interrupt::register(vec as usize, nvidia_irq_shim);
                debug_assert!(ok);
                crate::interrupt::Controller::enable_irq(irq_line);
            }
        }
        true
    }

    pub fn irq_count() -> usize {
        NV_IRQ_COUNT.load(Ordering::Acquire)
    }

    pub fn allocate_framebuffer(&self, size: usize, align: usize) -> Option<usize> {
        let buf = crate::gpu::memory::allocator::GpuAllocator::alloc_framebuffer(size, align)?;
        crate::gpu::memory::allocator::GpuAllocator::map_for_device(&buf, align)
    }

    pub fn submit_command_queue(&self, cmds: &[&[u8]]) -> Result<usize, &'static str> {
        let total: usize = cmds.iter().map(|c| c.len()).sum();
        let buf = crate::gpu::memory::allocator::GpuAllocator::alloc_framebuffer(total, 4096)
            .ok_or("alloc failed")?;
        let mut off = 0usize;
        for c in cmds {
            unsafe {
                core::ptr::copy_nonoverlapping(c.as_ptr(), buf.as_ptr().add(off), c.len());
            }
            off += c.len();
        }
        let engine = engine::get().ok_or("no dma engine")?;
        engine.submit_buffer(&buf, 0, 4096)
    }

    pub fn submit_command(&self, cmd: &[u8]) -> Result<usize, &'static str> {
        let engine = engine::get().ok_or("no dma engine")?;
        let buf = DmaBuffer::new(cmd.len(), 4096).ok_or("alloc failed")?;
        unsafe {
            core::ptr::copy_nonoverlapping(cmd.as_ptr(), buf.as_ptr(), cmd.len());
        }
        engine.submit_buffer(&buf, 0, 4096)
    }
}