scmi: run rustfmt

Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
This commit is contained in:
Manos Pitsidianakis 2025-07-08 11:15:30 +03:00 committed by Stefano Garzarella
parent c7c395dc08
commit 4cd80cb968
7 changed files with 121 additions and 96 deletions

View File

@ -9,16 +9,19 @@
//! The module also defines common infrastructure to provide sensor devices to
//! SCMI, see [SensorT].
use std::collections::{HashMap, HashSet};
use std::ffi::OsString;
use std::fmt::Write;
use std::fs::File;
use std::os::unix::io::RawFd;
use std::{
collections::{HashMap, HashSet},
ffi::OsString,
fmt::Write,
fs::File,
os::unix::io::RawFd,
};
use itertools::Itertools;
use log::debug;
use thiserror::Error as ThisError;
use super::{fake, iio};
use crate::scmi::{
self, DeviceResult, MessageId, MessageValue, MessageValues, ProtocolId, ScmiDevice,
ScmiDeviceError, MAX_SIMPLE_STRING_LENGTH, SENSOR_AXIS_DESCRIPTION_GET, SENSOR_CONFIG_GET,
@ -26,8 +29,6 @@ use crate::scmi::{
SENSOR_READING_GET, SENSOR_UPDATE,
};
use super::{fake, iio};
/// Non-SCMI related device errors.
#[derive(Debug, ThisError)]
pub enum DeviceError {
@ -233,10 +234,12 @@ pub struct Sensor {
/// using [Sensor::new] are disabled initially.
enabled: bool,
/// Sensor notification can be enabled or disabled when frontend sends SENSOR_CONTINUOUS_UPDATE_NOTIFY.
/// Sensor notification can be enabled or disabled when frontend sends
/// SENSOR_CONTINUOUS_UPDATE_NOTIFY.
notify_enabled: bool,
/// If this sensor supports notifying the frontend actively, it should record
/// notification device file here. (e.g. For iio device, the file is /dev/iio:deviceX)
/// If this sensor supports notifying the frontend actively, it should
/// record notification device file here. (e.g. For iio device, the file
/// is /dev/iio:deviceX)
pub notify_dev: Option<File>,
/// Sensor id, to identify the sensor in notification lookup.
@ -407,8 +410,8 @@ pub trait SensorT: Send {
axis_resolution | ((axis_exponent as u32) << 27),
)); //resolution
// In SCMI spec, it specifies that if the sensor does not report the min and max range,
// the following field should be as as:
// In SCMI spec, it specifies that if the sensor does not report the min and max
// range, the following field should be as as:
// axis_min_range_low 0x0
// axis_min_range_high 0x80000000
// axis_max_range_low 0xFFFFFFFF
@ -520,8 +523,8 @@ pub trait SensorT: Send {
/// Returns the notification messages from the device.
///
/// Usually need to redefine this. Different sensors may have different ways to
/// get notifications.
/// Usually need to redefine this. Different sensors may have different ways
/// to get notifications.
fn reading_update(&mut self, _device_index: u32) -> DeviceResult {
Ok(vec![])
}
@ -529,7 +532,8 @@ pub trait SensorT: Send {
/// Enable/Disable Sensor notify function.
///
/// Usually need to redefine this.
/// Different sensors require different configuration to enable/disable notifications.
/// Different sensors require different configuration to enable/disable
/// notifications.
fn notify_status_set(&self, _enabled: bool) -> Result<(), DeviceError> {
Ok(())
}
@ -563,7 +567,8 @@ pub trait SensorT: Send {
fn notify(&mut self, device_index: u32, message_id: MessageId) -> DeviceResult {
match message_id {
SENSOR_UPDATE => {
// Read pending notifications, to prevent spamming the frontend with EVENT:IN interrupts.
// Read pending notifications, to prevent spamming the frontend with EVENT:IN
// interrupts.
let ret = self.reading_update(device_index);
if !self.sensor().enabled || !self.sensor().notify_enabled {
return Result::Err(ScmiDeviceError::NotEnabled);

View File

@ -9,9 +9,10 @@
//! arranging SCMI virtualization setup without the need to bind real host
//! devices.
use std::os::unix::io::RawFd;
use super::common::{DeviceProperties, MaybeDevice, Sensor, SensorDevice, SensorT};
use crate::scmi::{self, DeviceResult, MessageValue};
use std::os::unix::io::RawFd;
pub struct FakeSensor {
sensor: Sensor,

View File

@ -9,22 +9,21 @@
//!
//! For some entry points, see [IIOSensor] and [Axis].
use std::cmp::{max, min};
use std::ffi::{OsStr, OsString};
use std::fs;
use std::fs::File;
use std::io::{ErrorKind, Read};
use std::os::unix::io::AsRawFd;
use std::os::unix::io::RawFd;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::{
cmp::{max, min},
ffi::{OsStr, OsString},
fs,
fs::File,
io::{ErrorKind, Read},
os::unix::io::{AsRawFd, RawFd},
path::{Path, PathBuf},
str::FromStr,
};
use log::{debug, error, warn};
use crate::scmi::{self, DeviceResult, MessageValue, ScmiDeviceError, MAX_SIMPLE_STRING_LENGTH};
use super::common::{DeviceError, DeviceProperties, MaybeDevice, Sensor, SensorDevice, SensorT};
use crate::scmi::{self, DeviceResult, MessageValue, ScmiDeviceError, MAX_SIMPLE_STRING_LENGTH};
/// Information about units used by the given Linux IIO channel.
struct UnitMapping<'a> {
@ -255,9 +254,10 @@ struct Axis {
/// sufficiently accurate SCMI value that is represented by an integer (not
/// a float) + decadic exponent.
custom_exponent: i8,
/// This is an extended attribute field. It reports the resolution of the sensor axis.
/// The representation is in [custom_resolution] x 10^[custom_exponent] format.
/// This field is present only if Bit[8] of axis_attributes_low is set to 1.
/// This is an extended attribute field. It reports the resolution of the
/// sensor axis. The representation is in [custom_resolution] x
/// 10^[custom_exponent] format. This field is present only if Bit[8] of
/// axis_attributes_low is set to 1.
custom_resolution: u64,
/// Channel scan type, necessary if the sensor supports notifications.
/// The data from /dev/iio:deviceX will be formatted according to this.
@ -426,11 +426,13 @@ impl SensorT for IIOSensor {
fn reading_update(&mut self, device_index: u32) -> DeviceResult {
let mut result = vec![];
// The buffer length should correspond to the IIO device type.
// The type is available from /sys/bus/iio/devices/iio:deviceX/scan_elements/in_XXX_type.
// For example, if the content of in_XXX_type is le:s16/16>>0, each value is a little endian
// signed 16-bit integer. For a 3-axes sensor with [x, y, z, (t)] values, i.e. the 3 axes plus an
// optional timestamp, we need 6 or 8 bytes buffer.
// Currently, the only supported type is "le:s16/16>>0".
// The type is available from
// /sys/bus/iio/devices/iio:deviceX/scan_elements/in_XXX_type.
// For example, if the content of in_XXX_type is le:s16/16>>0, each value is a
// little endian signed 16-bit integer. For a 3-axes sensor with [x, y,
// z, (t)] values, i.e. the 3 axes plus an optional timestamp, we need 6
// or 8 bytes buffer. Currently, the only supported type is
// "le:s16/16>>0".
let scan_type = self.axes[0].scan_type.unwrap();
let signed = scan_type.sign == 's';
@ -731,14 +733,14 @@ impl IIOSensor {
#[cfg(test)]
mod tests {
use crate::scmi::ScmiDevice;
use super::*;
use std::{
assert_eq, fs,
path::{Path, PathBuf},
};
use super::*;
use crate::scmi::ScmiDevice;
fn make_directory(prefix: &str) -> PathBuf {
for i in 1..100 {
let path = Path::new(".").join(format!("{prefix}{i}"));

View File

@ -3,8 +3,9 @@
//! Implementation of SCMI bindings to host devices.
//!
//! The general infrastructure is implemented in [crate::devices::common] module.
//! Access to particular kinds of devices is implemented in the other modules:
//! The general infrastructure is implemented in [crate::devices::common]
//! module. Access to particular kinds of devices is implemented in the other
//! modules:
//! - [crate::devices::fake] provides a fake sensor.
//! - [crate::devices::iio] implements access to industrial I/O (IIO) devices.

View File

@ -6,7 +6,8 @@
//! [System Control and Management Interface](https://developer.arm.com/Architectures/System%20Control%20and%20Management%20Interface)
//! (SCMI).
//!
//! Currently, the mandatory parts of the following SCMI protocols are implemented:
//! Currently, the mandatory parts of the following SCMI protocols are
//! implemented:
//!
//! - base
//! - sensor management
@ -37,8 +38,6 @@ mod devices;
mod scmi;
mod vhu_scmi;
use devices::common::{devices_help, DeviceDescription, DeviceProperties};
use std::{
path::PathBuf,
process::exit,
@ -46,9 +45,9 @@ use std::{
};
use clap::{CommandFactory, Parser};
use devices::common::{devices_help, DeviceDescription, DeviceProperties};
use itertools::Itertools;
use log::{debug, error};
use vhost_user_backend::VhostUserDaemon;
use vhu_scmi::VuScmiBackend;
use vm_memory::{GuestMemoryAtomic, GuestMemoryMmap};
@ -103,8 +102,9 @@ fn start_backend(config: VuScmiConfig) -> Result<()> {
)
.map_err(|e| e.to_string())?;
// Register devices such as "/dev/iio:deviceX" which can actively notify the frontend to epoll the handler.
// Then once there is data coming from these devices, an event will be created. (device_event=3)
// Register devices such as "/dev/iio:deviceX" which can actively notify the
// frontend to epoll the handler. Then once there is data coming from
// these devices, an event will be created. (device_event=3)
let handlers = daemon.get_epoll_handlers();
backend
.read()
@ -145,18 +145,15 @@ fn main() {
#[cfg(test)]
mod tests {
use super::*;
use std::path::Path;
use super::*;
#[test]
fn test_command_line() {
let path = "/foo/scmi.sock".to_owned();
let params_string = format!(
"binary \
--device dummy \
-s {path} \
--device fake,name=foo,prop=value \
-d fake,name=bar"
"binary --device dummy -s {path} --device fake,name=foo,prop=value -d fake,name=bar"
);
let params: Vec<&str> = params_string.split_whitespace().collect();
let args: args::ScmiArgs = Parser::parse_from(params);

View File

@ -130,7 +130,8 @@ impl From<&MessageValues> for Response {
}
impl Response {
// Notification is different from general response, it doesn't need ReturnStatus.
// Notification is different from general response, it doesn't need
// ReturnStatus.
pub fn from_notification(value: &MessageValues) -> Self {
Self {
values: value.to_vec(),
@ -211,9 +212,10 @@ impl ScmiRequest {
pub(crate) fn new(header: MessageHeader) -> Self {
let protocol_id: u8 = ((header >> 10) & 0xFF).try_into().unwrap();
let message_id: u8 = (header & 0xFF).try_into().unwrap();
// Token is an arbitrary info, the Linux SCMI driver uses it as a sequence number.
// No actual meaning for vhost except copying the unchanged header in the response
// as required by SCMI specification. We extract it here only for debugging purposes.
// Token is an arbitrary info, the Linux SCMI driver uses it as a sequence
// number. No actual meaning for vhost except copying the unchanged
// header in the response as required by SCMI specification. We extract
// it here only for debugging purposes.
let token: u16 = ((header >> 18) & 0x3FF).try_into().unwrap();
let message_type = match (header >> 8) & 0x3 {
0 => MessageType::Command,
@ -436,10 +438,14 @@ impl HandlerMap {
|handler: &ScmiHandler, _| -> Response {
let n_sensors = u32::from(handler.devices.number_of_devices(SENSOR_PROTOCOL_ID));
let values: MessageValues = vec![
MessageValue::Unsigned(n_sensors), // # of sensors, no async commands
MessageValue::Unsigned(0), // lower shared memory address -- not supported
MessageValue::Unsigned(0), // higher shared memory address -- not supported
MessageValue::Unsigned(0), // length of shared memory -- not supported
// # of sensors, no async commands
MessageValue::Unsigned(n_sensors),
// lower shared memory address -- not supported
MessageValue::Unsigned(0),
// higher shared memory address -- not supported
MessageValue::Unsigned(0),
// length of shared memory -- not supported
MessageValue::Unsigned(0),
];
Response::from(&values)
},
@ -667,10 +673,11 @@ pub type DeviceResult = Result<MessageValues, ScmiDeviceError>;
pub type DeviceIdentify = (ProtocolId, usize);
/// EventfdMap is a structure used to construct the relationship between device_event and DeviceIdentify
/// Once a device supports notification, it should insert a key-value to this hashmap
/// "device_event" is automatically assigned according to "available device event",
/// then function handle_event can find the device via this hashmap.
/// EventfdMap is a structure used to construct the relationship between
/// device_event and DeviceIdentify Once a device supports notification, it
/// should insert a key-value to this hashmap "device_event" is automatically
/// assigned according to "available device event", then function handle_event
/// can find the device via this hashmap.
struct EventfdMap {
// Next available device_event, it should be initialized with NOTIFY_ALLOW_START_FD
available_device_event: u16,
@ -686,7 +693,8 @@ impl EventfdMap {
}
}
// If this device has eventfd for notification, insert it into map with a device_eventfd
// If this device has eventfd for notification, insert it into map with a
// device_eventfd
fn insert(&mut self, device_identify: DeviceIdentify) {
let mut map = self.map.lock().unwrap();
map.insert(self.available_device_event, device_identify);
@ -755,9 +763,9 @@ impl ScmiHandler {
self.event_fds.available_device_event - 1
}
/// According to device_event, find out the device which will do notification.
/// Then call its notify function to return a ScmiResponse.
/// Now only SENSOR PROTOCOL can do notification.
/// According to device_event, find out the device which will do
/// notification. Then call its notify function to return a
/// ScmiResponse. Now only SENSOR PROTOCOL can do notification.
/// And it supports only the `SENSOR_UPDATE` message.
pub fn notify(&mut self, device_event: u16) -> Option<ScmiResponse> {
let event_fds_locked = self.event_fds.map.lock().unwrap();
@ -847,7 +855,8 @@ impl ScmiHandler {
.expect("Impossibly large number of SCMI protocols")
}
// If a device can notify, record its event_fd, which will be assigned to the device later.
// If a device can notify, record its event_fd, which will be assigned to the
// device later.
pub fn register_device(&mut self, device: Box<dyn ScmiDevice>) {
let register_event = device.get_notify_fd().is_some();
let device_identify = self.devices.insert(device);
@ -955,9 +964,8 @@ impl ScmiHandler {
#[cfg(test)]
mod tests {
use crate::devices::{common::DeviceProperties, fake::FakeSensor};
use super::*;
use crate::devices::{common::DeviceProperties, fake::FakeSensor};
#[test]
fn test_response_from_status() {
@ -1377,8 +1385,9 @@ mod tests {
MessageValue::Unsigned(0),
MessageValue::Unsigned(axis_index),
];
// Each call will return only one descriptor to avoid exceeding the maximum length of the message
// and to inform about the number of the remaining sensor axis descriptions.
// Each call will return only one descriptor to avoid exceeding the maximum
// length of the message and to inform about the number of the remaining
// sensor axis descriptions.
let num_axis_flags = 1 | ((n_axes - axis_index - 1) << 26);
let mut result = vec![MessageValue::Unsigned(num_axis_flags)];
let name = format!("acc_{}", char::from_u32('X' as u32 + axis_index).unwrap()).to_string();

View File

@ -5,29 +5,35 @@
//! General part of the vhost-user SCMI backend. Nothing very different from
//! the other rust-vmm backends.
use std::{
io,
io::Result as IoResult,
mem::size_of,
sync::{Arc, RwLock},
};
use log::{debug, error, warn};
use std::io;
use std::io::Result as IoResult;
use std::mem::size_of;
use std::sync::{Arc, RwLock};
use thiserror::Error as ThisError;
use vhost::vhost_user::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};
use vhost_user_backend::VringEpollHandler;
use vhost_user_backend::{VhostUserBackendMut, VringRwLock, VringT};
use virtio_bindings::bindings::virtio_config::{VIRTIO_F_NOTIFY_ON_EMPTY, VIRTIO_F_VERSION_1};
use virtio_bindings::bindings::virtio_ring::{
VIRTIO_RING_F_EVENT_IDX, VIRTIO_RING_F_INDIRECT_DESC,
use vhost_user_backend::{VhostUserBackendMut, VringEpollHandler, VringRwLock, VringT};
use virtio_bindings::bindings::{
virtio_config::{VIRTIO_F_NOTIFY_ON_EMPTY, VIRTIO_F_VERSION_1},
virtio_ring::{VIRTIO_RING_F_EVENT_IDX, VIRTIO_RING_F_INDIRECT_DESC},
};
use virtio_queue::{DescriptorChain, QueueOwnedT};
use vm_memory::{
Bytes, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryLoadGuard, GuestMemoryMmap,
};
use vmm_sys_util::epoll::EventSet;
use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK};
use vmm_sys_util::{
epoll::EventSet,
eventfd::{EventFd, EFD_NONBLOCK},
};
use crate::devices::common::{available_devices, DeviceError};
use crate::scmi::{MessageHeader, ScmiHandler, ScmiRequest};
use crate::VuScmiConfig;
use crate::{
devices::common::{available_devices, DeviceError},
scmi::{MessageHeader, ScmiHandler, ScmiRequest},
VuScmiConfig,
};
// QUEUE_SIZE must be apparently at least 1024 for MMIO.
// There is probably a maximum size per descriptor defined in the kernel.
@ -92,14 +98,17 @@ pub struct VuScmiBackend {
event_idx: bool,
pub exit_event: EventFd,
mem: Option<GuestMemoryAtomic<GuestMemoryMmap>>,
/// Event vring and descriptors serve for asynchronous responses and notifications.
/// They are obtained from the driver and we store them here for later use.
/// (We currently don't implement asynchronous responses or notifications but we support
/// the event queue because the Linux VIRTIO SCMI driver seems to be unhappy if it is not
/// present. And it doesn't harm to be ready for possible event queue use in future.)
/// Event vring and descriptors serve for asynchronous responses and
/// notifications. They are obtained from the driver and we store them
/// here for later use. (We currently don't implement asynchronous
/// responses or notifications but we support the event queue because
/// the Linux VIRTIO SCMI driver seems to be unhappy if it is not
/// present. And it doesn't harm to be ready for possible event queue use in
/// future.)
event_vring: Option<VringRwLock>,
event_descriptors: Vec<DescriptorChain<GuestMemoryLoadGuard<GuestMemoryMmap>>>,
/// The abstraction of request handling, with all the needed information stored inside.
/// The abstraction of request handling, with all the needed information
/// stored inside.
scmi_handler: ScmiHandler,
}
@ -140,7 +149,8 @@ impl VuScmiBackend {
}
/// Registers all the devices that can provide notifications
/// Create a hashmap to store the relationship about device's notify_fd and scmibackend eventfd.
/// Create a hashmap to store the relationship about device's notify_fd and
/// scmibackend eventfd.
pub fn register_device_event_fd(
&self,
handlers: Vec<Arc<VringEpollHandler<Arc<RwLock<VuScmiBackend>>>>>,