vm-virtio: Simplify virtio feature handling

Remove duplicated code across the different devices by handling
the virtio feature pages in VirtioDevice itself rather than
in the backends. This works as no virtio devices use feature
bits beyond 64-bits.

Signed-off-by: Cathy Zhang <cathy.zhang@intel.com>
This commit is contained in:
Cathy Zhang
2020-01-23 18:14:38 +08:00
committed by Rob Bradford
parent 411e2b43ba
commit 14eddf72b4
13 changed files with 76 additions and 231 deletions

View File

@@ -189,8 +189,12 @@ impl BusDevice for MmioDevice {
0x08 => self.device.lock().unwrap().device_type(),
0x0c => VENDOR_ID, // vendor id
0x10 => {
self.device.lock().unwrap().features(self.features_select)
| if self.features_select == 1 { 0x1 } else { 0x0 }
if self.features_select < 2 {
(self.device.lock().unwrap().features() >> (self.features_select * 32))
as u32
} else {
0
}
}
0x34 => self.with_queue(0, |q| u32::from(q.get_max_size())),
0x44 => self.with_queue(0, |q| q.ready as u32),
@@ -234,11 +238,19 @@ impl BusDevice for MmioDevice {
let v = LittleEndian::read_u32(data);
match offset {
0x14 => self.features_select = v,
0x20 => self
.device
.lock()
.unwrap()
.ack_features(self.acked_features_select, v),
0x20 => {
if self.acked_features_select < 2 {
self.device
.lock()
.unwrap()
.ack_features(u64::from(v) << (self.acked_features_select * 32));
} else {
warn!(
"invalid ack_features (page {}, value 0x{:x})",
self.acked_features_select, v
);
}
}
0x24 => self.acked_features_select = v,
0x30 => self.queue_select = v,
0x38 => mut_q = self.with_queue_mut(|q| q.size = v as u16),

View File

@@ -164,7 +164,7 @@ impl VirtioPciCommonConfig {
// Only 64 bits of features (2 pages) are defined for now, so limit
// device_feature_select to avoid shifting by 64 or more bits.
if self.device_feature_select < 2 {
locked_device.features(self.device_feature_select)
(locked_device.features() >> (self.device_feature_select * 32)) as u32
} else {
0
}
@@ -199,7 +199,8 @@ impl VirtioPciCommonConfig {
0x0c => {
if self.driver_feature_select < 2 {
let mut locked_device = device.lock().unwrap();
locked_device.ack_features(self.driver_feature_select, value);
locked_device
.ack_features(u64::from(value) << (self.driver_feature_select * 32));
} else {
warn!(
"invalid ack_features (page {}, value 0x{:x})",
@@ -280,11 +281,11 @@ mod tests {
Ok(())
}
fn features(&self, _page: u32) -> u32 {
DUMMY_FEATURES as u32
fn features(&self) -> u64 {
DUMMY_FEATURES
}
fn ack_features(&mut self, _page: u32, _value: u32) {}
fn ack_features(&mut self, _value: u64) {}
fn read_config(&self, _offset: u64, _data: &mut [u8]) {}