-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
User space interface for DMA and Mailbox (#75)
* User space interface for DMA and Mailbox Added user APIs for DMA and mailbox The DMA API allows for AXI-to-AXI transfers or from local buffer to an AXI component. The Mailbox API allows for executing a mailbox command in an atomic fashion, i.e. execute command, wait for response, return response.
- Loading branch information
Showing
7 changed files
with
379 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# Licensed under the Apache-2.0 license | ||
|
||
[package] | ||
name = "libsyscall-caliptra" | ||
version.workspace = true | ||
authors.workspace = true | ||
edition.workspace = true | ||
|
||
[dependencies] | ||
libtock_console.workspace = true | ||
libtock_platform.workspace = true | ||
libtockasync.workspace = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
// Licensed under the Apache-2.0 license | ||
|
||
//! # DMA: A DMA Interface for AXI Source to AXI Destination Transfers | ||
//! | ||
//! This library provides an abstraction for performing asynchronous Direct Memory Access (DMA) | ||
//! transfers between AXI source and AXI destination addresses. | ||
use core::marker::PhantomData; | ||
use libtock_platform::{share, DefaultConfig, ErrorCode, Syscalls}; | ||
use libtockasync::TockSubscribe; | ||
/// DMA interface. | ||
pub struct DMA<S: Syscalls> { | ||
syscall: PhantomData<S>, | ||
driver_num: u32, | ||
} | ||
|
||
/// Define type for AXI address (64-bit wide). | ||
pub type AXIAddr = u64; | ||
|
||
/// Configuration parameters for a DMA transfer. | ||
#[derive(Debug, Clone)] | ||
pub struct DMATransaction<'a> { | ||
/// Number of bytes to transfer. | ||
pub byte_count: usize, | ||
/// Source for the transfer. | ||
pub source: DMASource<'a>, | ||
/// Destination AXI address for the transfer. | ||
pub dest_addr: AXIAddr, | ||
} | ||
|
||
/// Represents the source of data for a DMA transfer. | ||
#[derive(Debug, Clone)] | ||
pub enum DMASource<'a> { | ||
/// AXI memory address as the source. | ||
Address(AXIAddr), | ||
/// A local buffer as the source. | ||
Buffer(&'a [u8]), | ||
} | ||
|
||
impl<S: Syscalls> Default for DMA<S> { | ||
fn default() -> Self { | ||
Self::new() | ||
} | ||
} | ||
|
||
impl<S: Syscalls> DMA<S> { | ||
pub fn new() -> Self { | ||
Self { | ||
syscall: PhantomData, | ||
driver_num: DMA_DRIVER_NUM, | ||
} | ||
} | ||
|
||
/// Do a DMA transfer. | ||
/// | ||
/// This method executes a DMA transfer based on the provided `DMATransaction` configuration. | ||
/// | ||
/// # Arguments | ||
/// * `transaction` - A `DMATransaction` struct containing the transfer details. | ||
/// | ||
/// # Returns | ||
/// * `Ok(())` if the transfer starts successfully. | ||
/// * `Err(ErrorCode)` if the transfer fails. | ||
pub async fn xfer<'a>(&self, transaction: &DMATransaction<'a>) -> Result<(), ErrorCode> { | ||
self.setup(transaction)?; | ||
|
||
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(&self) -> Result<(), ErrorCode> { | ||
let async_start = TockSubscribe::subscribe::<S>(self.driver_num, dma_subscribe::XFER_DONE); | ||
S::command(self.driver_num, dma_cmd::XFER_AXI_TO_AXI, 0, 0).to_result::<(), ErrorCode>()?; | ||
async_start.await.map(|_| ()) | ||
} | ||
|
||
async fn xfer_src_buffer(&self, buffer: &[u8]) -> Result<(), ErrorCode> { | ||
// Use `share::scope` to safely share the buffer with the kernel | ||
share::scope::<(), _, _>(|_| { | ||
let async_start = TockSubscribe::subscribe_allow_ro::<S, DefaultConfig>( | ||
self.driver_num, | ||
dma_subscribe::XFER_DONE, | ||
dma_ro_buffer::LOCAL_SOURCE, | ||
buffer, | ||
); | ||
|
||
// Start the DMA transfer | ||
S::command(self.driver_num, dma_cmd::XFER_LOCAL_TO_AXI, 0, 0) | ||
.to_result::<(), ErrorCode>()?; | ||
Ok(async_start) | ||
})? | ||
.await | ||
.map(|_| ()) | ||
} | ||
|
||
fn setup(&self, config: &DMATransaction<'_>) -> Result<(), ErrorCode> { | ||
S::command( | ||
self.driver_num, | ||
dma_cmd::SET_BYTE_XFER_COUNT, | ||
config.byte_count as u32, | ||
0, | ||
) | ||
.to_result::<(), ErrorCode>()?; | ||
|
||
if let DMASource::Address(src_addr) = config.source { | ||
S::command( | ||
self.driver_num, | ||
dma_cmd::SET_SRC_ADDR, | ||
(src_addr & 0xFFFF_FFFF) as u32, | ||
(src_addr >> 32) as u32, | ||
) | ||
.to_result::<(), ErrorCode>()?; | ||
} | ||
|
||
S::command( | ||
self.driver_num, | ||
dma_cmd::SET_DEST_ADDR, | ||
(config.dest_addr & 0xFFFF_FFFF) as u32, | ||
(config.dest_addr >> 32) as u32, | ||
) | ||
.to_result::<(), ErrorCode>()?; | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
// ----------------------------------------------------------------------------- | ||
// Command IDs and DMA-specific constants | ||
// ----------------------------------------------------------------------------- | ||
|
||
// Driver number for the DMA interface | ||
pub const DMA_DRIVER_NUM: u32 = 0x8000_0008; | ||
|
||
/// Command IDs used by the DMA interface. | ||
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 XFER_AXI_TO_AXI: u32 = 3; | ||
pub const XFER_LOCAL_TO_AXI: u32 = 4; | ||
} | ||
|
||
/// Buffer IDs for DMA (read-only) | ||
mod dma_ro_buffer { | ||
/// Buffer ID for local buffers (read-only) | ||
pub const LOCAL_SOURCE: u32 = 0; | ||
} | ||
|
||
/// Subscription IDs for asynchronous notifications. | ||
mod dma_subscribe { | ||
pub const XFER_DONE: u32 = 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
// Licensed under the Apache-2.0 license | ||
|
||
#![no_std] | ||
|
||
pub mod dma; | ||
pub mod mailbox; |
Oops, something went wrong.