Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# ----------------------------------------------------------------------------
# Title : AES Stream Drivers Documentation Deployment
# ----------------------------------------------------------------------------
# Builds Sphinx documentation and deploys to GitHub Pages.
# Triggered only on tag pushes (e.g., v1.0.0 or 1.0.0).
#
# Prerequisites:
# - secrets.GH_TOKEN must be set (repo scope PAT) — already configured
# - GitHub Pages must be configured: Settings > Pages > Branch: gh-pages / (root)
# - docs/ directory must contain a Makefile with an 'html' target
# ----------------------------------------------------------------------------

name: Documentation

on:
push:
tags:
- '*'

jobs:
build_and_deploy_docs:
name: Build and Deploy Sphinx Docs
runs-on: ubuntu-24.04

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y doxygen

- name: Install Python dependencies
run: |
python -m pip install --upgrade pip
pip install -r docs/requirements.txt

- name: Build Sphinx documentation
env:
DOCS_VERSION: ${{ github.ref_name }}
run: |
cd docs
doxygen Doxyfile
make html

- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GH_TOKEN }}
publish_dir: docs/_build/html
publish_branch: gh-pages
force_orphan: true
user_name: 'github-actions[bot]'
user_email: 'github-actions[bot]@users.noreply.github.com'
commit_message: 'Deploy docs for ${{ github.ref_name }}'
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,8 @@ compile_commands.json
.claude/
.planning/
CLAUDE.md

# Sphinx and Doxygen generated output
docs/_build/
docs/_doxygen/
_doxygen/
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# aes-stream-drivers

[DOE Code](https://www.osti.gov/doecode/biblio/8043)
**[Documentation](https://slaclab.github.io/aes-stream-drivers)** | [DOE Code](https://www.osti.gov/doecode/biblio/8043)

Common repository for streaming kernel drivers (datadev, gpuDirect, Yocto, etc)

Expand Down
72 changes: 72 additions & 0 deletions docs/Doxyfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Doxyfile for aes-stream-drivers
# Run from the docs/ directory: doxygen Doxyfile
# Output: _doxygen/xml/ (consumed by Breathe/Sphinx)

#---------------------------------------------------------------------------
# Project
#---------------------------------------------------------------------------
PROJECT_NAME = "aes-stream-drivers"
PROJECT_NUMBER =
PROJECT_BRIEF = "SLAC AES Stream Drivers — User Space API"

#---------------------------------------------------------------------------
# Input
#---------------------------------------------------------------------------
INPUT = ../include/
RECURSIVE = YES
FILE_PATTERNS = *.h *.c
EXTENSION_MAPPING = h=C c=C

#---------------------------------------------------------------------------
# Output: XML only (Breathe consumes this; no HTML site from Doxygen)
#---------------------------------------------------------------------------
OUTPUT_DIRECTORY = _doxygen
GENERATE_HTML = NO
GENERATE_LATEX = NO
GENERATE_XML = YES
XML_OUTPUT = xml
XML_PROGRAMLISTING = NO

#---------------------------------------------------------------------------
# Comment extraction
#---------------------------------------------------------------------------
JAVADOC_AUTOBRIEF = YES
QT_AUTOBRIEF = NO
AUTOLINK_SUPPORT = YES

#---------------------------------------------------------------------------
# C/kernel specifics
#---------------------------------------------------------------------------
OPTIMIZE_OUTPUT_FOR_C = YES
TYPEDEF_HIDES_STRUCT = NO
EXTRACT_ALL = NO
EXTRACT_STATIC = YES
EXTRACT_ANON_NSPACES = NO

#---------------------------------------------------------------------------
# Macro handling
# NOTE: DMA_IN_KERNEL is intentionally NOT listed here.
# The userspace API (dmaWrite, dmaRead, etc.) lives inside
# #ifndef DMA_IN_KERNEL blocks. Leaving it undefined makes those
# functions visible to Doxygen.
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = NO
PREDEFINED = __attribute__(x)= \
__user= \
__iomem= \
__must_check=

#---------------------------------------------------------------------------
# Noise reduction
#---------------------------------------------------------------------------
STRIP_CODE_COMMENTS = NO
SOURCE_BROWSER = NO
INLINE_SOURCES = NO
REFERENCES_RELATION = NO
GENERATE_TODOLIST = NO
GENERATE_BUGLIST = NO
QUIET = YES
WARNINGS = YES
WARN_IF_UNDOCUMENTED = NO
19 changes: 19 additions & 0 deletions docs/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Minimal Sphinx Makefile
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build

.PHONY: help Makefile html clean

help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

html:
@$(SPHINXBUILD) -b html "$(SOURCEDIR)" "$(BUILDDIR)/html" $(SPHINXOPTS) $(O)

clean:
rm -rf $(BUILDDIR)

%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
67 changes: 67 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Configuration file for the Sphinx documentation builder.
# Run: cd docs && make html
# Prerequisites: pip install -r docs/requirements.txt && doxygen Doxyfile

import os
import sys

# -- Path setup --------------------------------------------------------------
sys.path.insert(0, os.path.abspath('.'))

# -- Project information -----------------------------------------------------
project = 'aes-stream-drivers'
copyright = '2026, SLAC National Accelerator Laboratory'
author = 'SLAC AES Group'

# Version: CI sets DOCS_VERSION to the git tag (e.g. "v3.2.1")
# Local builds fall back to "dev"
release = os.environ.get('DOCS_VERSION', 'dev').lstrip('v')
version = release

# -- General configuration ---------------------------------------------------
extensions = [
'breathe',
'sphinx_rtd_theme',
'sphinx_copybutton',
]

templates_path = ['_templates']
exclude_patterns = ['_build', '_doxygen', 'Thumbs.db', '.DS_Store']

# -- Breathe configuration ---------------------------------------------------
# Path is relative to conf.py (docs/ directory)
breathe_projects = {
'aes-stream-drivers': '_doxygen/xml',
}
breathe_default_project = 'aes-stream-drivers'
breathe_domain_by_extension = {'h': 'c', 'c': 'c'}
breathe_default_members = ('members', 'undoc-members')

# -- sphinx-copybutton configuration -----------------------------------------
copybutton_prompt_text = r'^\$ |^>>> '
copybutton_prompt_is_regexp = True
copybutton_only_copy_prompt_lines = False

# -- HTML output configuration -----------------------------------------------
html_theme = 'sphinx_rtd_theme'

html_theme_options = {
'navigation_depth': 4,
'titles_only': False,
'collapse_navigation': False,
'sticky_navigation': True,
'includehidden': True,
'logo_only': False,
'prev_next_buttons_location': 'bottom',
}

html_context = {
'display_github': True,
'github_user': 'slaclab',
'github_repo': 'aes-stream-drivers',
'github_version': 'main',
'conf_py_path': '/docs/',
'source_suffix': '.rst',
}

html_static_path = ['_static']
117 changes: 117 additions & 0 deletions docs/explanation/architecture.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
Driver Architecture
===================

The aes-stream-drivers project provides Linux kernel drivers for high-bandwidth DMA over PCIe
(data_dev) and AXI stream on Zynq/RCE (rce_stream). The design goal is a shared common layer
that handles the POSIX file interface, buffer management, and DMA housekeeping, while delegating
all hardware-specific behavior to a small vtable. This lets the same userspace API work across
PCIe, AXI, and future bus types without duplication.

The Hardware Abstraction Vtable
--------------------------------

The central abstraction in the driver is ``struct hardware_functions``, a C function pointer
table (vtable) defined in ``dma_common.h``. The common layer calls into this vtable for all
hardware-specific operations — interrupt handling, DMA engine initialization, buffer submission,
and register access — without knowing which hardware implementation it is calling.

.. code-block:: c

/* dma_common.h */
struct hardware_functions {
irqreturn_t (*irq)(int irq, void *dev_id);
void (*init)(struct DmaDevice *dev);
void (*enable)(struct DmaDevice *dev);
void (*clear)(struct DmaDevice *dev);
void (*irqEnable)(struct DmaDevice *dev, int mask);
void (*retRxBuffer)(struct DmaDevice *dev, struct DmaBuffer **buff, uint32_t count);
int32_t (*sendBuffer)(struct DmaDevice *dev, struct DmaBuffer **buff, uint32_t count);
int32_t (*command)(struct DmaDevice *dev, uint32_t cmd, uint64_t arg);
void (*seqShow)(struct seq_file *s, struct DmaDevice *dev);
};

The concrete instance for the PCIe/x86 data_dev hardware is ``DataDev_functions``, defined in
``data_dev_top.c``:

.. code-block:: c

/* data_dev_top.c */
struct hardware_functions DataDev_functions = {
.irq = AxisG2_Irq,
.init = AxisG2_Init,
.clear = AxisG2_Clear,
.enable = AxisG2_Enable,
.irqEnable = AxisG2_IrqEnable,
.retRxBuffer = AxisG2_RetRxBuffer,
.sendBuffer = AxisG2_SendBuffer,
.command = DataDev_Command,
.seqShow = DataDev_SeqShow,
};

The RCE/ARM rce_stream driver provides a different instance pointing to ``AxisG1_*`` functions.
Both platforms share the entire common layer unchanged.

Component Relationships
------------------------

The driver is organized as a layered stack. Each layer has a well-defined interface to the layer
above and below it.

.. code-block:: text

Userspace application
| open/read/write/ioctl/mmap
v
DmaDesc (per-fd state: channel mask, rx queue)
|
v
DmaDevice (per-card: buffer pools, config, hwFunc vtable)
| .init/.irq/.sendBuffer/.retRxBuffer
v
hardware_functions vtable
|
+---+------------------+
AxisG2_functions AxisG1_functions
(data_dev/PCIe) (rce_stream/ARM)

Each layer's role:

- **DmaDesc**: created per ``open(2)`` call; holds the per-client channel mask and receive queue;
destroyed on ``close(2)``
- **DmaDevice**: created per physical card at module load; holds the shared DMA buffer pools,
hardware register mapping, and a pointer to the ``hardware_functions`` vtable
- **hardware_functions vtable**: the boundary between generic DMA logic and hardware-specific
behavior; the common layer calls only through this interface

PCIe BAR0 Memory Map
---------------------

For the data_dev PCIe driver, BAR0 maps the following regions:

.. code-block:: c

/* data_dev_top.h */
#define AGEN2_OFF 0x00000000 /* DMAv2 Engine (64 kB) */
#define PHY_OFF 0x00010000 /* PCIe PHY (64 kB) */
#define AVER_OFF 0x00020000 /* AxiVersion (64 kB) */
#define PROM_OFF 0x00030000 /* PROM (320 kB) */
#define USER_OFF 0x00800000 /* User Space (8 MB) */

The DMAv2 engine at offset 0 is the AxisG2 IP core. The AxiVersion block at ``AVER_OFF``
(0x20000) provides firmware version and build information readable via ``/proc/datadev_N``.
The user space region at ``USER_OFF`` (0x800000) is application firmware — its layout is
design-specific and not interpreted by the driver.

PCI Device Identification
--------------------------

The driver binds to devices with PCI vendor ID ``0x1a4a`` (SLAC) and device ID ``0x2030``.
Use ``lspci -d 1a4a:2030`` to confirm the card is recognized by the kernel before loading the
module.

Further Reading
----------------

- DMA buffer allocation and zero-copy: :doc:`dma-modes`
- AXI stream channel routing: :doc:`axi-stream-protocol`
- DMA API function reference: :doc:`../reference/dma-api`
Loading
Loading