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