From 53ded3f04d951edb733ca71a1e238ba160b8dfc2 Mon Sep 17 00:00:00 2001 From: Junnan Wu Date: Sat, 19 Oct 2024 09:08:59 +0800 Subject: [PATCH] scmi: sensor axis extended attributes support For Android requirment, virtio-scmi axis descriptor should support extended attributes. This patch does this things. We get axis's resolution during reading "scale" and store. When agent wants to get axis descriptions, device will add resolution value to extend attribute field. At the same time, max and min range also have been configured. Signed-off-by: Junnan Wu --- vhost-device-scmi/CHANGELOG.md | 2 ++ vhost-device-scmi/src/devices/common.rs | 25 ++++++++++++++++++- vhost-device-scmi/src/devices/iio.rs | 32 +++++++++++++++++++++---- vhost-device-scmi/src/scmi.rs | 8 ++++++- 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/vhost-device-scmi/CHANGELOG.md b/vhost-device-scmi/CHANGELOG.md index 1a502e3b9..626dec624 100644 --- a/vhost-device-scmi/CHANGELOG.md +++ b/vhost-device-scmi/CHANGELOG.md @@ -3,6 +3,8 @@ ### Added +- [[#798]](https://github.com/rust-vmm/vhost-device/pull/798) scmi: extended sensor attributes support + ### Changed ### Fixed diff --git a/vhost-device-scmi/src/devices/common.rs b/vhost-device-scmi/src/devices/common.rs index efabe005a..18903c370 100644 --- a/vhost-device-scmi/src/devices/common.rs +++ b/vhost-device-scmi/src/devices/common.rs @@ -359,6 +359,11 @@ pub trait SensorT: Send { 0 } + /// Returns the resolution of the sensor scale. + fn resolution(&self) -> u32 { + 0 + } + /// Returns the prefix of axes names. /// /// Usually no need to redefine this. @@ -383,8 +388,10 @@ pub trait SensorT: Send { /// Usually no need to redefine this. fn axis_description(&self, axis: u32) -> Vec { let mut values = vec![]; + let axis_exponent = self.unit_exponent(0); + let axis_resolution = self.resolution(); values.push(MessageValue::Unsigned(axis)); // axis id - values.push(MessageValue::Unsigned(0)); // attributes low + values.push(MessageValue::Unsigned(1 << 8)); // attributes low (Extended attributes support) values.push(MessageValue::Unsigned(self.format_unit(axis))); // attributes high // Name in the recommended format, 16 bytes: @@ -394,6 +401,22 @@ pub trait SensorT: Send { format!("{prefix}_{suffix}"), MAX_SIMPLE_STRING_LENGTH, )); + + // Extended attribute + values.push(MessageValue::Unsigned( + 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: + // axis_min_range_low 0x0 + // axis_min_range_high 0x80000000 + // axis_max_range_low 0xFFFFFFFF + // axis_max_range_high 0x7FFFFFFF + values.push(MessageValue::Signed(0)); // min_range_low + values.push(MessageValue::Signed(i32::MIN)); // min_range_high + values.push(MessageValue::Signed(-1i32)); // max_range_low + values.push(MessageValue::Signed(i32::MAX)); // max_range_high values } diff --git a/vhost-device-scmi/src/devices/iio.rs b/vhost-device-scmi/src/devices/iio.rs index 52103953a..7a82665ff 100644 --- a/vhost-device-scmi/src/devices/iio.rs +++ b/vhost-device-scmi/src/devices/iio.rs @@ -255,6 +255,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. + custom_resolution: u64, /// Channel scan type, necessary if the sensor supports notifications. /// The data from /dev/iio:deviceX will be formatted according to this. /// The ChanScanType is parsed from "scan_elements/_type" @@ -262,7 +266,7 @@ struct Axis { } impl Axis { - fn new(path: OsString, unit_exponent: i8, custom_exponent: i8) -> Axis { + fn new(path: OsString, unit_exponent: i8, custom_exponent: i8, custom_resolution: u64) -> Axis { let scan_path = Path::new(&path).parent().unwrap().join("scan_elements"); let mut scan_name = path.clone(); scan_name.push("_type"); @@ -273,6 +277,7 @@ impl Axis { path, unit_exponent, custom_exponent, + custom_resolution, scan_type: ChanScanType::new(scan_type), } } else { @@ -280,6 +285,7 @@ impl Axis { path, unit_exponent, custom_exponent, + custom_resolution, scan_type: None, } } @@ -371,6 +377,13 @@ impl SensorT for IIOSensor { axis.unit_exponent + axis.custom_exponent } + fn resolution(&self) -> u32 { + // All the axes are supposed to have the same value for resolution. + // We are just using the values from the Axis 0 here. + let axis: &Axis = self.axes.first().unwrap(); + axis.custom_resolution as u32 + } + fn number_of_axes(&self) -> u32 { if self.scalar { 0 @@ -579,14 +592,23 @@ impl IIOSensor { } } - fn custom_exponent(&self, path: &OsStr, unit_exponent: i8) -> i8 { + // This function gets both custom exponent and resolution by reading "scale" + // A scale value should be parsed as "[resolution]e[exponent]" + fn custom_exponent_and_resolution(&self, path: &OsStr, unit_exponent: i8) -> (i8, u64) { let mut custom_exponent: i8 = 0; + let mut custom_resolution: u64 = 0; if let Ok(Some(scale)) = self.read_axis_scale(path) { // Crash completely OK if *this* doesn't fit: custom_exponent = scale.log10() as i8; if scale < 1.0 { // The logarithm is truncated towards zero, we need floor custom_exponent -= 1; + // Calculate the resolution of scale + custom_resolution = + (scale * 10i32.pow(-custom_exponent as u32) as f64).trunc() as u64; + } else { + custom_resolution = + (scale / 10i32.pow(custom_exponent as u32) as f64).trunc() as u64; } // The SCMI exponent (unit_exponent + custom_exponent) can have max. 5 bits: custom_exponent = min(15 - unit_exponent, custom_exponent); @@ -596,7 +618,7 @@ impl IIOSensor { &path, custom_exponent ); } - custom_exponent + (custom_exponent, custom_resolution) } fn add_axis(&mut self, axes: &mut Vec, path: &OsStr) { @@ -606,11 +628,13 @@ impl IIOSensor { .map_or(0, |mapping| mapping.unit_exponent); // To get meaningful integer values, we must adjust exponent to // the provided scale if any. - let custom_exponent = self.custom_exponent(path, unit_exponent); + let (custom_exponent, custom_resolution) = + self.custom_exponent_and_resolution(path, unit_exponent); axes.push(Axis::new( OsString::from(path), unit_exponent, custom_exponent, + custom_resolution, )); } diff --git a/vhost-device-scmi/src/scmi.rs b/vhost-device-scmi/src/scmi.rs index 7e6e02b4d..da8c90788 100644 --- a/vhost-device-scmi/src/scmi.rs +++ b/vhost-device-scmi/src/scmi.rs @@ -1384,9 +1384,15 @@ mod tests { let name = format!("acc_{}", char::from_u32('X' as u32 + axis_index).unwrap()).to_string(); let mut description = vec![ MessageValue::Unsigned(axis_index), - MessageValue::Unsigned(0), + MessageValue::Unsigned(1 << 8), MessageValue::Unsigned(u32::from(SENSOR_UNIT_METERS_PER_SECOND_SQUARED)), MessageValue::String(name, MAX_SIMPLE_STRING_LENGTH), + // Add extended attributes + MessageValue::Unsigned(0), + MessageValue::Signed(0), + MessageValue::Signed(i32::MIN), + MessageValue::Signed(-1i32), + MessageValue::Signed(i32::MAX), ]; result.append(&mut description); test_message(