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
8 changes: 4 additions & 4 deletions cli/src/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ use crate::proxies::status_proxy;
use std::collections::HashMap;
use zbus::Connection;

/// Parses a newline-separated string of overlays into a Vec<String>
/// Parses a newline-separated string of overlays into a `Vec<String>`
///
/// # Arguments
/// * `list_str` - The string containing overlay names separated by newlines.
///
/// # Returns: Vec<String>
/// A Vec<String> where each element is an overlay name from the input string.
/// # Returns: `Vec<String>`
/// A `Vec<String>` where each element is an overlay name from the input string.
///
/// # Examples
/// ```rust,no_run
Expand All @@ -58,7 +58,7 @@ fn parse_overlay_lines(list_str: &str) -> Vec<String> {
/// # Arguments
/// * `ret_str` - The string containing device-platform pairs separated by newlines.
///
/// # Returns: HashMap<String, String>
/// # Returns: `HashMap<String, String>`
/// A HashMap<String, String> where the key is the device and the value is the platform string.
///
/// # Examples
Expand Down
18 changes: 18 additions & 0 deletions daemon/src/comm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,22 @@
//
// You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

//! Communication interfaces for the fpgad daemon.
//!
//! This module provides communication interfaces that allow external clients to
//! interact with the fpgad daemon. Currently, the only communication method is
//! DBus, which provides a system bus service for privileged FPGA operations.
//!
//! # Submodules
//!
//! - [`dbus`] - DBus interface implementation for the daemon
//!
//! # Architecture
//!
//! The daemon exposes two DBus interfaces:
//! - **Control Interface** - Write operations (loading, applying, removing)
//! - **Status Interface** - Read-only operations (querying state, listing devices)
//!
//! For more information, see the [`dbus`] module documentation.

pub mod dbus;
8 changes: 4 additions & 4 deletions daemon/src/comm/dbus/control_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ impl ControlInterface {
///
/// # Arguments
///
/// * `property_path_str`: Full path under [FPGA_MANAGERS_DIR].
/// * `property_path_str`: Full path under [crate::config::FPGA_MANAGERS_DIR].
/// * `data`: String data to write.
///
/// # Returns: `Result<String, Error>`
Expand All @@ -321,7 +321,7 @@ impl ControlInterface {
/// other reason
/// **Notes:**
///
/// * Path must be under [FPGA_MANAGERS_DIR] - determined at compile time.
/// * Path must be under [crate::config::FPGA_MANAGERS_DIR] - determined at compile time.
///
/// # Examples
///
Expand Down Expand Up @@ -349,7 +349,7 @@ impl ControlInterface {
///
/// # Arguments
///
/// * `property_path_str`: Full path under [FPGA_MANAGERS_DIR].
/// * `property_path_str`: Full path under [crate::config::FPGA_MANAGERS_DIR].
/// * `data`: Byte array to write.
///
/// # Returns: `Result<String, Error>`
Expand All @@ -360,7 +360,7 @@ impl ControlInterface {
///
/// **Notes:**
///
/// * Path must be under [FPGA_MANAGERS_DIR] - determined at compile time.
/// * Path must be under [crate::config::FPGA_MANAGERS_DIR] - determined at compile time.
///
/// # Examples
///
Expand Down
17 changes: 17 additions & 0 deletions daemon/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,23 @@
//
// You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

//! Configuration constants for the fpgad daemon.
//!
//! This module contains compile-time constants that define the file system paths used by
//! the daemon to interact with the Linux kernel's FPGA subsystem, device tree overlays,
//! and firmware loading mechanisms.
//!
//! These paths are typically stable across Linux distributions but may vary in some
//! embedded or specialized configurations. The constants are defined at compile time
//! and cannot be changed at runtime because FPGAd aims to remain stateless.
//!
//! # Kernel Subsystems
//!
//! The daemon interacts with three main kernel subsystems:
//! - **FPGA Manager** - The Linux FPGA subsystem for bitstream loading
//! - **Device Tree Overlays** - Dynamic device tree modification via configfs
//! - **Firmware Loading** - Kernel firmware loader search path configuration

/// The driver-decided location of fpga_manager objects. Typically `/sys/class/fpga_manager/`.
pub static FPGA_MANAGERS_DIR: &str = "/sys/class/fpga_manager/";

Expand Down
69 changes: 69 additions & 0 deletions daemon/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,70 @@
//
// You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

//! Error types for the fpgad daemon.
//!
//! This module defines the `FpgadError` enum, which represents all possible error
//! conditions that can occur during FPGA management operations. The error types are
//! designed to provide detailed context about failures, including file paths, data
//! values, and underlying system errors.
//!
//! # Error Categories
//!
//! - **I/O Errors** - File system operations (read, write, create, delete, directory listing)
//! - **State Errors** - FPGA device state validation failures
//! - **Argument Errors** - Invalid parameters or paths
//! - **Softener Errors** - Platform-specific operation failures (feature-gated)
//! - **Internal Errors** - Unexpected internal conditions
//!
//! # DBus Integration
//!
//! Errors are automatically converted to `zbus::fdo::Error` types for transmission over
//! DBus. The error message always includes the `FpgadError::<variant>:` prefix to allow
//! CLI clients to distinguish between application errors and DBus communication errors.
//!
//! # Examples
//!
//! ```rust,no_run
//! # use crate::error::FpgadError;
//! # use std::path::Path;
//!
//! fn read_config(path: &Path) -> Result<String, FpgadError> {
//! // Will produce: FpgadError::IORead: An IO error occurred when reading from ...
//! crate::system_io::fs_read(path)
//! }
//! ```

use log::error;
use std::path::PathBuf;
use zbus::fdo;

/// Application-level errors for FPGA management operations.
///
/// This enum represents all possible error conditions in the fpgad daemon. Each variant
/// includes detailed context about the failure, such as file paths, data being processed,
/// and the underlying system error when applicable.
///
/// All errors implement `Display` and will be formatted with the `FpgadError::<variant>:`
/// prefix, making them easily identifiable in logs and error messages sent over DBus.
#[derive(Debug, thiserror::Error)]
pub enum FpgadError {
/// Failed to read FPGA programming flags from sysfs.
#[error("FpgadError::Flag: Failed to read flags: {0}")]
Flag(String),

/// Device tree overlay was not successfully applied.
#[error("FpgadError::OverlayStatus: Overlay was not applied: {0}")]
OverlayStatus(String),

/// FPGA device is not in the expected state for the requested operation.
#[error("FpgadError::FPGAState: FPGA state is not as expected: {0}")]
FPGAState(String),

/// Invalid argument provided to a function (e.g., invalid path, bad device handle).
#[error("FpgadError::Argument: {0}")]
Argument(String),

/// Failed to read from a file system path - wrapper around std::io::Error
#[error("FpgadError::IORead: An IO error occurred when reading from {file:?}: {e}")]
IORead { file: PathBuf, e: std::io::Error },
/// Failed to write data to a file system path.
Expand All @@ -32,17 +82,36 @@ pub enum FpgadError {
/// Failed to create a file or directory - wrapper around std::io::Error
#[error("FpgadError::IOCreate: An IO error occurred when creating {file:?}: {e}")]
IOCreate { file: PathBuf, e: std::io::Error },

/// Failed to delete a file or directory - wrapper around std::io::Error
#[error("FpgadError::IODelete: An IO error occurred when deleting {file:?}: {e}")]
IODelete { file: PathBuf, e: std::io::Error },

/// Failed to list directory contents.
#[error("FpgadError::IOReadDir: An IO error occurred when reading directory {dir:?}: {e}")]
IOReadDir { dir: PathBuf, e: std::io::Error },

/// Platform-specific softener operation failed (only available with softeners feature).
#[cfg(feature = "softeners")]
#[error("FpgadError::Softener: An error occurred using softener: {0}")]
Softener(crate::softeners::error::FpgadSoftenerError),

/// Any other unexpected internal error occurred.
#[error("FpgadError::Internal: An Internal error occurred: {0}")]
Internal(String),
}

/// Convert FpgadError to DBus-compatible fdo::Error.
///
/// This implementation maps application-level errors to appropriate DBus error types
/// and logs the error before conversion. The error message retains the `FpgadError::<variant>:`
/// prefix to allow clients to distinguish between different error types.
///
/// # Error Mapping
///
/// - `Argument` → `InvalidArgs` - Invalid parameters
/// - `IORead`, `IOWrite`, `IOCreate`, `IODelete`, `IOReadDir` → `IOError` - I/O failures
/// - All others → `Failed` - General failures
impl From<FpgadError> for fdo::Error {
fn from(err: FpgadError) -> Self {
error!("{err}");
Expand Down
78 changes: 78 additions & 0 deletions daemon/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,46 @@
//
// You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

//! FPGA daemon (fpgad) - System service for managing FPGA devices.
//!
//! This is the main entry point for the fpgad daemon, which provides a DBus service for
//! managing FPGA devices on Linux systems. The daemon:
//! - Exposes two DBus interfaces: `control` and `status`
//! - Manages FPGA bitstream loading through the Linux FPGA subsystem
//! - Handles device tree overlay application and removal
//! - Provides platform-specific FPGA management capabilities
//! - Runs as a system service with appropriate privileges
//!
//! # DBus Service
//!
//! - **Service Name**: `com.canonical.fpgad`
//! - **Status Interface**: `/com/canonical/fpgad/status` - Read-only operations
//! - **Control Interface**: `/com/canonical/fpgad/control` - Write operations
//!
//! # Environment Variables
//!
//! - `RUST_LOG` - Controls logging level (`trace`, `debug`, `info`, `warn`, `error`
//! or `off`). Defaults to `info`
//!
//! # Architecture
//!
//! The daemon uses a platform abstraction approach that allows different FPGA vendors
//! and platforms to be supported through registered platform implementations. At startup,
//! the daemon:
//! 1. Registers all available platform implementations
//! 2. Creates DBus interface objects
//! 3. Connects to the system DBus and advertises the service
//! 4. Waits indefinitely for incoming DBus requests
//!
//! # Platform Support
//!
//! - **Universal Platform**: Generic FPGA support for standard Linux FPGA subsystem
//! - **Xilinx DFX Manager** (optional, feature-gated): Xilinx-specific softener which uses dfx-mgr
//! - **Additional Platforms**: Can be added via feature flags and custom implementations
//!
//! See the [`platforms`] module for details on the platform abstraction system and
//! [`softeners`] for more information on vendor-specific implementations.

use log::info;
use std::error::Error;
use std::future::pending;
Expand All @@ -32,12 +72,50 @@ use crate::{
platforms::universal::UniversalPlatform,
};

/// Register all available FPGA platform implementations.
///
/// This function is called at daemon startup to register platform handlers. Each
/// platform implementation provides vendor or hardware-specific logic for FPGA
/// management operations. Platforms are registered in order of priority, with more
/// specific platforms registered before generic ones.
///
/// # Platform Registration Order
///
/// 1. Xilinx DFX Manager (if feature enabled) - Handles Xilinx-specific devices
/// 2. Universal Platform - Fallback for standard Linux FPGA subsystem devices
fn register_platforms() {
#[cfg(feature = "xilinx-dfx-mgr")]
XilinxDfxMgrPlatform::register_platform();
UniversalPlatform::register_platform();
}

/// Main entry point for the fpgad daemon.
///
/// Initializes the daemon by:
/// 1. Setting up logging via `env_logger` (defaults to "info" level)
/// 2. Registering platform implementations
/// 3. Creating DBus interface instances
/// 4. Connecting to the system DBus and advertising the service
/// 5. Running indefinitely to serve DBus requests
///
/// # Returns: `Result<(), Box<dyn Error>>`
/// * `Ok(())` - Never returns under normal operation (runs until terminated)
/// * `Err(Box<dyn Error>)` - Initialization error (DBus connection failed, etc.)
///
/// # Environment Variables
///
/// - `RUST_LOG` - Controls logging level (`trace`, `debug`, `info`, `warn`, `error`
/// or `off`). Defaults to `info`
///
/// # Examples
///
/// ```bash
/// # Run with default logging (info level)
/// fpgad
///
/// # Run with debug logging
/// RUST_LOG=debug fpgad
/// ```
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
Expand Down
1 change: 1 addition & 0 deletions daemon/src/platforms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
// You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

#![doc = include_str!("platforms/README.md")]

pub mod platform;
pub mod universal;
pub mod universal_components;
Loading
Loading