xref: /aosp_15_r20/external/crosvm/devices/src/virtio/vhost/scmi.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2023 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::BTreeMap;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::path::Path;
7*bb4ee6a4SAndroid Build Coastguard Worker 
8*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::anyhow;
9*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context;
10*bb4ee6a4SAndroid Build Coastguard Worker use base::error;
11*bb4ee6a4SAndroid Build Coastguard Worker use base::warn;
12*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptor;
13*bb4ee6a4SAndroid Build Coastguard Worker use base::Event;
14*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor;
15*bb4ee6a4SAndroid Build Coastguard Worker use base::WorkerThread;
16*bb4ee6a4SAndroid Build Coastguard Worker use vhost::Scmi as VhostScmiHandle;
17*bb4ee6a4SAndroid Build Coastguard Worker use vhost::Vhost;
18*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory;
19*bb4ee6a4SAndroid Build Coastguard Worker 
20*bb4ee6a4SAndroid Build Coastguard Worker use super::worker::Worker;
21*bb4ee6a4SAndroid Build Coastguard Worker use super::Error;
22*bb4ee6a4SAndroid Build Coastguard Worker use super::Result;
23*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::DeviceType;
24*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::Interrupt;
25*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::Queue;
26*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::VirtioDevice;
27*bb4ee6a4SAndroid Build Coastguard Worker use crate::Suspendable;
28*bb4ee6a4SAndroid Build Coastguard Worker 
29*bb4ee6a4SAndroid Build Coastguard Worker const QUEUE_SIZE: u16 = 128;
30*bb4ee6a4SAndroid Build Coastguard Worker const NUM_QUEUES: usize = 2;
31*bb4ee6a4SAndroid Build Coastguard Worker const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE; NUM_QUEUES];
32*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_SCMI_F_P2A_CHANNELS: u32 = 0;
33*bb4ee6a4SAndroid Build Coastguard Worker 
34*bb4ee6a4SAndroid Build Coastguard Worker pub struct Scmi {
35*bb4ee6a4SAndroid Build Coastguard Worker     worker_thread: Option<WorkerThread<()>>,
36*bb4ee6a4SAndroid Build Coastguard Worker     vhost_handle: Option<VhostScmiHandle>,
37*bb4ee6a4SAndroid Build Coastguard Worker     interrupts: Option<Vec<Event>>,
38*bb4ee6a4SAndroid Build Coastguard Worker     avail_features: u64,
39*bb4ee6a4SAndroid Build Coastguard Worker     acked_features: u64,
40*bb4ee6a4SAndroid Build Coastguard Worker }
41*bb4ee6a4SAndroid Build Coastguard Worker 
42*bb4ee6a4SAndroid Build Coastguard Worker impl Scmi {
43*bb4ee6a4SAndroid Build Coastguard Worker     /// Create a new virtio-scmi device.
new(vhost_scmi_device_path: &Path, base_features: u64) -> Result<Scmi>44*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(vhost_scmi_device_path: &Path, base_features: u64) -> Result<Scmi> {
45*bb4ee6a4SAndroid Build Coastguard Worker         let handle = VhostScmiHandle::new(vhost_scmi_device_path).map_err(Error::VhostOpen)?;
46*bb4ee6a4SAndroid Build Coastguard Worker 
47*bb4ee6a4SAndroid Build Coastguard Worker         let avail_features = base_features | 1 << VIRTIO_SCMI_F_P2A_CHANNELS;
48*bb4ee6a4SAndroid Build Coastguard Worker 
49*bb4ee6a4SAndroid Build Coastguard Worker         let mut interrupts = Vec::new();
50*bb4ee6a4SAndroid Build Coastguard Worker         for _ in 0..NUM_QUEUES {
51*bb4ee6a4SAndroid Build Coastguard Worker             interrupts.push(Event::new().map_err(Error::VhostIrqCreate)?);
52*bb4ee6a4SAndroid Build Coastguard Worker         }
53*bb4ee6a4SAndroid Build Coastguard Worker 
54*bb4ee6a4SAndroid Build Coastguard Worker         Ok(Scmi {
55*bb4ee6a4SAndroid Build Coastguard Worker             worker_thread: None,
56*bb4ee6a4SAndroid Build Coastguard Worker             vhost_handle: Some(handle),
57*bb4ee6a4SAndroid Build Coastguard Worker             interrupts: Some(interrupts),
58*bb4ee6a4SAndroid Build Coastguard Worker             avail_features,
59*bb4ee6a4SAndroid Build Coastguard Worker             acked_features: 0,
60*bb4ee6a4SAndroid Build Coastguard Worker         })
61*bb4ee6a4SAndroid Build Coastguard Worker     }
62*bb4ee6a4SAndroid Build Coastguard Worker 
acked_features(&self) -> u6463*bb4ee6a4SAndroid Build Coastguard Worker     pub fn acked_features(&self) -> u64 {
64*bb4ee6a4SAndroid Build Coastguard Worker         self.acked_features
65*bb4ee6a4SAndroid Build Coastguard Worker     }
66*bb4ee6a4SAndroid Build Coastguard Worker }
67*bb4ee6a4SAndroid Build Coastguard Worker 
68*bb4ee6a4SAndroid Build Coastguard Worker impl VirtioDevice for Scmi {
keep_rds(&self) -> Vec<RawDescriptor>69*bb4ee6a4SAndroid Build Coastguard Worker     fn keep_rds(&self) -> Vec<RawDescriptor> {
70*bb4ee6a4SAndroid Build Coastguard Worker         let mut keep_rds = Vec::new();
71*bb4ee6a4SAndroid Build Coastguard Worker 
72*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(handle) = &self.vhost_handle {
73*bb4ee6a4SAndroid Build Coastguard Worker             keep_rds.push(handle.as_raw_descriptor());
74*bb4ee6a4SAndroid Build Coastguard Worker         }
75*bb4ee6a4SAndroid Build Coastguard Worker 
76*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(interrupt) = &self.interrupts {
77*bb4ee6a4SAndroid Build Coastguard Worker             for vhost_int in interrupt.iter() {
78*bb4ee6a4SAndroid Build Coastguard Worker                 keep_rds.push(vhost_int.as_raw_descriptor());
79*bb4ee6a4SAndroid Build Coastguard Worker             }
80*bb4ee6a4SAndroid Build Coastguard Worker         }
81*bb4ee6a4SAndroid Build Coastguard Worker 
82*bb4ee6a4SAndroid Build Coastguard Worker         keep_rds
83*bb4ee6a4SAndroid Build Coastguard Worker     }
84*bb4ee6a4SAndroid Build Coastguard Worker 
device_type(&self) -> DeviceType85*bb4ee6a4SAndroid Build Coastguard Worker     fn device_type(&self) -> DeviceType {
86*bb4ee6a4SAndroid Build Coastguard Worker         DeviceType::Scmi
87*bb4ee6a4SAndroid Build Coastguard Worker     }
88*bb4ee6a4SAndroid Build Coastguard Worker 
queue_max_sizes(&self) -> &[u16]89*bb4ee6a4SAndroid Build Coastguard Worker     fn queue_max_sizes(&self) -> &[u16] {
90*bb4ee6a4SAndroid Build Coastguard Worker         QUEUE_SIZES
91*bb4ee6a4SAndroid Build Coastguard Worker     }
92*bb4ee6a4SAndroid Build Coastguard Worker 
features(&self) -> u6493*bb4ee6a4SAndroid Build Coastguard Worker     fn features(&self) -> u64 {
94*bb4ee6a4SAndroid Build Coastguard Worker         self.avail_features
95*bb4ee6a4SAndroid Build Coastguard Worker     }
96*bb4ee6a4SAndroid Build Coastguard Worker 
ack_features(&mut self, value: u64)97*bb4ee6a4SAndroid Build Coastguard Worker     fn ack_features(&mut self, value: u64) {
98*bb4ee6a4SAndroid Build Coastguard Worker         let mut v = value;
99*bb4ee6a4SAndroid Build Coastguard Worker 
100*bb4ee6a4SAndroid Build Coastguard Worker         // Check if the guest is ACK'ing a feature that we didn't claim to have.
101*bb4ee6a4SAndroid Build Coastguard Worker         let unrequested_features = v & !self.avail_features;
102*bb4ee6a4SAndroid Build Coastguard Worker         if unrequested_features != 0 {
103*bb4ee6a4SAndroid Build Coastguard Worker             warn!("scmi: virtio-scmi got unknown feature ack: {:x}", v);
104*bb4ee6a4SAndroid Build Coastguard Worker 
105*bb4ee6a4SAndroid Build Coastguard Worker             // Don't count these features as acked.
106*bb4ee6a4SAndroid Build Coastguard Worker             v &= !unrequested_features;
107*bb4ee6a4SAndroid Build Coastguard Worker         }
108*bb4ee6a4SAndroid Build Coastguard Worker         self.acked_features |= v;
109*bb4ee6a4SAndroid Build Coastguard Worker     }
110*bb4ee6a4SAndroid Build Coastguard Worker 
activate( &mut self, mem: GuestMemory, interrupt: Interrupt, queues: BTreeMap<usize, Queue>, ) -> anyhow::Result<()>111*bb4ee6a4SAndroid Build Coastguard Worker     fn activate(
112*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
113*bb4ee6a4SAndroid Build Coastguard Worker         mem: GuestMemory,
114*bb4ee6a4SAndroid Build Coastguard Worker         interrupt: Interrupt,
115*bb4ee6a4SAndroid Build Coastguard Worker         queues: BTreeMap<usize, Queue>,
116*bb4ee6a4SAndroid Build Coastguard Worker     ) -> anyhow::Result<()> {
117*bb4ee6a4SAndroid Build Coastguard Worker         if queues.len() != NUM_QUEUES {
118*bb4ee6a4SAndroid Build Coastguard Worker             return Err(anyhow!(
119*bb4ee6a4SAndroid Build Coastguard Worker                 "net: expected {} queues, got {}",
120*bb4ee6a4SAndroid Build Coastguard Worker                 NUM_QUEUES,
121*bb4ee6a4SAndroid Build Coastguard Worker                 queues.len()
122*bb4ee6a4SAndroid Build Coastguard Worker             ));
123*bb4ee6a4SAndroid Build Coastguard Worker         }
124*bb4ee6a4SAndroid Build Coastguard Worker         let vhost_handle = self.vhost_handle.take().context("missing vhost_handle")?;
125*bb4ee6a4SAndroid Build Coastguard Worker         let interrupts = self.interrupts.take().context("missing interrupts")?;
126*bb4ee6a4SAndroid Build Coastguard Worker         let acked_features = self.acked_features;
127*bb4ee6a4SAndroid Build Coastguard Worker         let mut worker = Worker::new(
128*bb4ee6a4SAndroid Build Coastguard Worker             queues,
129*bb4ee6a4SAndroid Build Coastguard Worker             vhost_handle,
130*bb4ee6a4SAndroid Build Coastguard Worker             interrupts,
131*bb4ee6a4SAndroid Build Coastguard Worker             interrupt,
132*bb4ee6a4SAndroid Build Coastguard Worker             acked_features,
133*bb4ee6a4SAndroid Build Coastguard Worker             None,
134*bb4ee6a4SAndroid Build Coastguard Worker         );
135*bb4ee6a4SAndroid Build Coastguard Worker         let activate_vqs = |_handle: &VhostScmiHandle| -> Result<()> { Ok(()) };
136*bb4ee6a4SAndroid Build Coastguard Worker 
137*bb4ee6a4SAndroid Build Coastguard Worker         worker
138*bb4ee6a4SAndroid Build Coastguard Worker             .init(mem, QUEUE_SIZES, activate_vqs, None)
139*bb4ee6a4SAndroid Build Coastguard Worker             .context("vhost worker init exited with error")?;
140*bb4ee6a4SAndroid Build Coastguard Worker 
141*bb4ee6a4SAndroid Build Coastguard Worker         self.worker_thread = Some(WorkerThread::start("vhost_scmi", move |kill_evt| {
142*bb4ee6a4SAndroid Build Coastguard Worker             let cleanup_vqs = |_handle: &VhostScmiHandle| -> Result<()> { Ok(()) };
143*bb4ee6a4SAndroid Build Coastguard Worker             let result = worker.run(cleanup_vqs, kill_evt);
144*bb4ee6a4SAndroid Build Coastguard Worker             if let Err(e) = result {
145*bb4ee6a4SAndroid Build Coastguard Worker                 error!("vhost_scmi worker thread exited with error: {:?}", e);
146*bb4ee6a4SAndroid Build Coastguard Worker             }
147*bb4ee6a4SAndroid Build Coastguard Worker         }));
148*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
149*bb4ee6a4SAndroid Build Coastguard Worker     }
150*bb4ee6a4SAndroid Build Coastguard Worker 
on_device_sandboxed(&mut self)151*bb4ee6a4SAndroid Build Coastguard Worker     fn on_device_sandboxed(&mut self) {
152*bb4ee6a4SAndroid Build Coastguard Worker         // ignore the error but to log the error. We don't need to do
153*bb4ee6a4SAndroid Build Coastguard Worker         // anything here because when activate, the other vhost set up
154*bb4ee6a4SAndroid Build Coastguard Worker         // will be failed to stop the activate thread.
155*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(vhost_handle) = &self.vhost_handle {
156*bb4ee6a4SAndroid Build Coastguard Worker             match vhost_handle.set_owner() {
157*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(_) => {}
158*bb4ee6a4SAndroid Build Coastguard Worker                 Err(e) => error!("{}: failed to set owner: {:?}", self.debug_label(), e),
159*bb4ee6a4SAndroid Build Coastguard Worker             }
160*bb4ee6a4SAndroid Build Coastguard Worker         }
161*bb4ee6a4SAndroid Build Coastguard Worker     }
162*bb4ee6a4SAndroid Build Coastguard Worker }
163*bb4ee6a4SAndroid Build Coastguard Worker 
164*bb4ee6a4SAndroid Build Coastguard Worker impl Suspendable for Scmi {}
165