mirror of
https://github.com/rust-vmm/vhost-device.git
synced 2025-12-26 14:41:23 +00:00
scmi: run rustfmt
Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
This commit is contained in:
parent
c7c395dc08
commit
4cd80cb968
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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}"));
|
||||
|
||||
@ -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.
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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>>>>>,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user