Skip to content

Commit

Permalink
Add an option to transfer from local buffer
Browse files Browse the repository at this point in the history
  • Loading branch information
mlvisaya committed Jan 7, 2025
1 parent 4da9dce commit d7e3afc
Showing 1 changed file with 68 additions and 19 deletions.
87 changes: 68 additions & 19 deletions runtime/apps/apis/dma/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,33 @@
//! This library provides an abstraction for performing asynchronous Direct Memory Access (DMA)
//! transfers between AXI source and AXI destination addresses.
use libtock_platform::{ErrorCode, Syscalls};
use libtock_platform::allow_ro::AllowRo;
use libtock_platform::{share, DefaultConfig, ErrorCode, Syscalls};
use libtockasync::TockSubscribe;

/// DMA interface.
pub struct AsyncDMA<S: Syscalls>(S);

const DMA_DRIVER_NUM: u32 = 0x8000_0008;
/// Configuration parameters for a DMA transfer.
#[derive(Debug, Copy, Clone)]
pub struct DMATransaction {
#[derive(Debug, Clone)]
pub struct DMATransaction<'a> {
/// Number of bytes to transfer.
pub byte_count: usize,
/// Source address for the transfer.
pub src_addr: u64,
/// Source for the transfer.
pub source: DMASource<'a>,
/// Destination address for the transfer.
pub dest_addr: u64,
}

/// Represents the source of data for a DMA transfer.
#[derive(Debug, Clone)]
pub enum DMASource<'a> {
/// A memory address as the source.
Address(u64),
/// A local buffer as the source.
Buffer(&'a [u8]),
}

impl<S: Syscalls> AsyncDMA<S> {
/// Do a DMA transfer.
///
Expand All @@ -34,15 +43,45 @@ impl<S: Syscalls> AsyncDMA<S> {
/// # Returns
/// * `Ok(())` if the transfer starts successfully.
/// * `Err(ErrorCode)` if the transfer fails.
pub async fn xfer(transaction: DMATransaction) -> Result<(), ErrorCode> {
pub async fn xfer<'a>(transaction: &DMATransaction<'a>) -> Result<(), ErrorCode> {
Self::setup(transaction).await?;

match transaction.source {
DMASource::Buffer(buffer) => Self::xfer_src_buffer(buffer).await.map(|_| ()),
DMASource::Address(_) => Self::xfer_src_address().await.map(|_| ()),
}
}

async fn xfer_src_address() -> Result<(), ErrorCode> {
let async_start = TockSubscribe::subscribe::<S>(DMA_DRIVER_NUM, dma_subscribe::XFER_DONE);
S::command(DMA_DRIVER_NUM, dma_cmd::START, 0, 0).to_result::<(), ErrorCode>()?;
S::command(DMA_DRIVER_NUM, dma_cmd::XFER_AXI_TO_AXI, 0, 0).to_result::<(), ErrorCode>()?;
async_start.await.map(|_| ())
}

async fn setup(config: DMATransaction) -> Result<(), ErrorCode> {
async fn xfer_src_buffer(buffer: &[u8]) -> Result<(), ErrorCode> {
// Use `share::scope` to safely share the buffer with the kernel
share::scope::<(AllowRo<_, DMA_DRIVER_NUM, { dma_buffer::LOCAL_SOURCE }>,), _, _>(
|handle| {
let allow_ro = handle.split().0;

// Share the local buffer as the source
S::allow_ro::<DefaultConfig, DMA_DRIVER_NUM, { dma_buffer::LOCAL_SOURCE }>(
allow_ro, buffer,
)?;

// Start the DMA transfer
let async_start =
TockSubscribe::subscribe::<S>(DMA_DRIVER_NUM, dma_subscribe::XFER_DONE);
S::command(DMA_DRIVER_NUM, dma_cmd::XFER_LOCAL_TO_AXI, 0, 0)
.to_result::<(), ErrorCode>()?;
Ok(async_start)
},
)?
.await
.map(|_| ())
}

async fn setup<'a>(config: &DMATransaction<'a>) -> Result<(), ErrorCode> {
let async_configure =
TockSubscribe::subscribe::<S>(DMA_DRIVER_NUM, dma_subscribe::SET_BYTE_XFER_COUNT_DONE);
S::command(
Expand All @@ -54,15 +93,18 @@ impl<S: Syscalls> AsyncDMA<S> {
.to_result::<(), ErrorCode>()?;
async_configure.await.map(|_| ())?;

let async_src = TockSubscribe::subscribe::<S>(DMA_DRIVER_NUM, dma_subscribe::SET_SRC_DONE);
S::command(
DMA_DRIVER_NUM,
dma_cmd::SET_SRC_ADDR,
(config.src_addr & 0xFFFF_FFFF) as u32,
(config.src_addr >> 32) as u32,
)
.to_result::<(), ErrorCode>()?;
async_src.await.map(|_| ())?;
if let DMASource::Address(src_addr) = config.source {
let async_src =
TockSubscribe::subscribe::<S>(DMA_DRIVER_NUM, dma_subscribe::SET_SRC_DONE);
S::command(
DMA_DRIVER_NUM,
dma_cmd::SET_SRC_ADDR,
(src_addr & 0xFFFF_FFFF) as u32,
(src_addr >> 32) as u32,
)
.to_result::<(), ErrorCode>()?;
async_src.await.map(|_| ())?;
}

let async_dest =
TockSubscribe::subscribe::<S>(DMA_DRIVER_NUM, dma_subscribe::SET_DEST_DONE);
Expand All @@ -88,7 +130,14 @@ mod dma_cmd {
pub const SET_BYTE_XFER_COUNT: u32 = 0;
pub const SET_SRC_ADDR: u32 = 1;
pub const SET_DEST_ADDR: u32 = 2;
pub const START: u32 = 3;
pub const XFER_AXI_TO_AXI: u32 = 3;
pub const XFER_LOCAL_TO_AXI: u32 = 4;
}

/// Buffer IDs for DMA
mod dma_buffer {
/// Buffer ID for local buffers (read-only)
pub const LOCAL_SOURCE: u32 = 0;
}

/// Subscription IDs for asynchronous notifications.
Expand Down

0 comments on commit d7e3afc

Please sign in to comment.