Path: blob/main/devices/src/usb/xhci/ring_buffer_controller.rs
5394 views
// Copyright 2019 The ChromiumOS Authors1// Use of this source code is governed by a BSD-style license that can be2// found in the LICENSE file.34use std::fmt;5use std::fmt::Display;6use std::sync::Arc;7use std::sync::MutexGuard;89use anyhow::Context;10use base::debug;11use base::error;12use base::info;13use base::Error as SysError;14use base::Event;15use base::EventType;16use remain::sorted;17use sync::Mutex;18use thiserror::Error;19use vm_memory::GuestAddress;20use vm_memory::GuestMemory;2122use super::ring_buffer::RingBuffer;23use super::ring_buffer_stop_cb::RingBufferStopCallback;24use super::xhci_abi::TransferDescriptor;25use crate::utils;26use crate::utils::EventHandler;27use crate::utils::EventLoop;2829#[sorted]30#[derive(Error, Debug)]31pub enum Error {32#[error("failed to add event to event loop: {0}")]33AddEvent(utils::Error),34#[error("failed to create event: {0}")]35CreateEvent(SysError),36}3738type Result<T> = std::result::Result<T, Error>;3940#[derive(PartialEq, Copy, Clone, Eq)]41enum RingBufferState {42/// Running: RingBuffer is running, consuming transfer descriptor.43Running,44/// Stopping: Some thread requested RingBuffer stop. It will stop when current descriptor is45/// handled.46Stopping,47/// Stopped: RingBuffer already stopped.48Stopped,49}5051/// TransferDescriptorHandler handles transfer descriptor. User should implement this trait and52/// build a ring buffer controller with the struct.53pub trait TransferDescriptorHandler {54/// Process descriptor asynchronously, write complete_event when done.55fn handle_transfer_descriptor(56&self,57descriptor: TransferDescriptor,58complete_event: Event,59) -> anyhow::Result<()>;6061/// Stop is called when trying to stop ring buffer controller. Returns true when stop must be62/// performed asynchronously. This happens because the handler is handling some descriptor63/// asynchronously, the stop callback of ring buffer controller must be called after the64/// `async` part is handled or canceled. If the TransferDescriptorHandler decide it could stop65/// immediately, it could return false.66/// For example, if a handler submitted a transfer but the transfer has not yet finished. Then67/// guest kernel requests to stop the ring buffer controller. Transfer descriptor handler will68/// return true, thus RingBufferController would transfer to Stopping state. It will be stopped69/// when all pending transfer completed.70/// On the other hand, if handler does not have any pending transfers, it would return false.71fn stop(&self) -> bool {72true73}74}7576/// RingBufferController owns a ring buffer. It lives on a event_loop. It will pop out transfer77/// descriptor and let TransferDescriptorHandler handle it.78pub struct RingBufferController<T: 'static + TransferDescriptorHandler> {79name: String,80state: Mutex<RingBufferState>,81stop_callback: Mutex<Vec<RingBufferStopCallback>>,82ring_buffer: Mutex<RingBuffer>,83handler: Mutex<T>,84event_loop: Arc<EventLoop>,85event: Event,86}8788impl<T: 'static + TransferDescriptorHandler> Display for RingBufferController<T> {89fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {90write!(f, "RingBufferController `{}`", self.name)91}92}9394impl<T: Send> RingBufferController<T>95where96T: 'static + TransferDescriptorHandler,97{98/// Create a ring buffer controller and add it to event loop.99pub fn new_with_handler(100name: String,101mem: GuestMemory,102event_loop: Arc<EventLoop>,103handler: T,104) -> Result<Arc<RingBufferController<T>>> {105let evt = Event::new().map_err(Error::CreateEvent)?;106let controller = Arc::new(RingBufferController {107name: name.clone(),108state: Mutex::new(RingBufferState::Stopped),109stop_callback: Mutex::new(Vec::new()),110ring_buffer: Mutex::new(RingBuffer::new(name, mem)),111handler: Mutex::new(handler),112event_loop: event_loop.clone(),113event: evt,114});115let event_handler: Arc<dyn EventHandler> = controller.clone();116event_loop117.add_event(118&controller.event,119EventType::Read,120Arc::downgrade(&event_handler),121)122.map_err(Error::AddEvent)?;123Ok(controller)124}125126fn lock_ring_buffer(&self) -> MutexGuard<RingBuffer> {127self.ring_buffer.lock()128}129130/// Get dequeue pointer of the internal ring buffer.131pub fn get_dequeue_pointer(&self) -> GuestAddress {132self.lock_ring_buffer().get_dequeue_pointer()133}134135/// Set dequeue pointer of the internal ring buffer.136pub fn set_dequeue_pointer(&self, ptr: GuestAddress) {137xhci_trace!("{}: set_dequeue_pointer({:x})", self.name, ptr.0);138// Fast because this should only happen during xhci setup.139self.lock_ring_buffer().set_dequeue_pointer(ptr);140}141142/// Get consumer cycle state.143pub fn get_consumer_cycle_state(&self) -> bool {144self.lock_ring_buffer().get_consumer_cycle_state()145}146147/// Set consumer cycle state.148pub fn set_consumer_cycle_state(&self, state: bool) {149xhci_trace!("{}: set consumer cycle state: {}", self.name, state);150// Fast because this should only happen during xhci setup.151self.lock_ring_buffer().set_consumer_cycle_state(state);152}153154/// Start the ring buffer.155pub fn start(&self) {156xhci_trace!("start {}", self.name);157let mut state = self.state.lock();158if *state != RingBufferState::Running {159*state = RingBufferState::Running;160if let Err(e) = self.event.signal() {161error!("cannot start event ring: {}", e);162}163}164}165166/// Stop the ring buffer asynchronously.167pub fn stop(&self, callback: RingBufferStopCallback) {168xhci_trace!("stop {}", self.name);169let mut state = self.state.lock();170if *state == RingBufferState::Stopped {171info!("xhci: {} is already stopped", self.name);172return;173}174if self.handler.lock().stop() {175*state = RingBufferState::Stopping;176self.stop_callback.lock().push(callback);177} else {178*state = RingBufferState::Stopped;179}180}181}182183impl<T> Drop for RingBufferController<T>184where185T: 'static + TransferDescriptorHandler,186{187fn drop(&mut self) {188// Remove self from the event loop.189if let Err(e) = self.event_loop.remove_event_for_descriptor(&self.event) {190error!(191"cannot remove ring buffer controller from event loop: {}",192e193);194}195}196}197198impl<T> EventHandler for RingBufferController<T>199where200T: 'static + TransferDescriptorHandler + Send,201{202fn on_event(&self) -> anyhow::Result<()> {203// `self.event` triggers ring buffer controller to run.204self.event.wait().context("cannot read from event")?;205let mut state = self.state.lock();206207match *state {208RingBufferState::Stopped => return Ok(()),209RingBufferState::Stopping => {210debug!("xhci: {}: stopping ring buffer controller", self.name);211*state = RingBufferState::Stopped;212self.stop_callback.lock().clear();213return Ok(());214}215RingBufferState::Running => {}216}217218let transfer_descriptor = self219.lock_ring_buffer()220.dequeue_transfer_descriptor()221.context("cannot dequeue transfer descriptor")?;222223let transfer_descriptor = match transfer_descriptor {224Some(t) => t,225None => {226*state = RingBufferState::Stopped;227self.stop_callback.lock().clear();228return Ok(());229}230};231232let event = self.event.try_clone().context("cannot clone event")?;233self.handler234.lock()235.handle_transfer_descriptor(transfer_descriptor, event)236}237}238239#[cfg(test)]240mod tests {241use std::mem::size_of;242use std::sync::mpsc::channel;243use std::sync::mpsc::Sender;244245use base::pagesize;246247use super::super::xhci_abi::LinkTrb;248use super::super::xhci_abi::NormalTrb;249use super::super::xhci_abi::Trb;250use super::super::xhci_abi::TrbType;251use super::*;252253struct TestHandler {254sender: Sender<i32>,255}256257impl TransferDescriptorHandler for TestHandler {258fn handle_transfer_descriptor(259&self,260descriptor: TransferDescriptor,261complete_event: Event,262) -> anyhow::Result<()> {263for atrb in &descriptor {264assert_eq!(atrb.trb.get_trb_type().unwrap(), TrbType::Normal);265self.sender.send(atrb.trb.get_parameter() as i32).unwrap();266}267complete_event.signal().unwrap();268Ok(())269}270}271272fn setup_mem() -> GuestMemory {273let trb_size = size_of::<Trb>() as u64;274let gm = GuestMemory::new(&[(GuestAddress(0), pagesize() as u64)]).unwrap();275276// Structure of ring buffer:277// 0x100 --> 0x200 --> 0x300278// trb 1 | trb 3 | trb 5279// trb 2 | trb 4 | trb 6280// l trb - l trb - l trb to 0x100281let mut trb = NormalTrb::new();282trb.set_trb_type(TrbType::Normal);283trb.set_data_buffer_pointer(1);284trb.set_chain(true);285gm.write_obj_at_addr(trb, GuestAddress(0x100)).unwrap();286287trb.set_data_buffer_pointer(2);288gm.write_obj_at_addr(trb, GuestAddress(0x100 + trb_size))289.unwrap();290291let mut ltrb = LinkTrb::new();292ltrb.set_trb_type(TrbType::Link);293ltrb.set_ring_segment_pointer(0x200);294gm.write_obj_at_addr(ltrb, GuestAddress(0x100 + 2 * trb_size))295.unwrap();296297trb.set_data_buffer_pointer(3);298gm.write_obj_at_addr(trb, GuestAddress(0x200)).unwrap();299300// Chain bit is false.301trb.set_data_buffer_pointer(4);302trb.set_chain(false);303gm.write_obj_at_addr(trb, GuestAddress(0x200 + 1 * trb_size))304.unwrap();305306ltrb.set_ring_segment_pointer(0x300);307gm.write_obj_at_addr(ltrb, GuestAddress(0x200 + 2 * trb_size))308.unwrap();309310trb.set_data_buffer_pointer(5);311trb.set_chain(true);312gm.write_obj_at_addr(trb, GuestAddress(0x300)).unwrap();313314// Chain bit is false.315trb.set_data_buffer_pointer(6);316trb.set_chain(false);317gm.write_obj_at_addr(trb, GuestAddress(0x300 + 1 * trb_size))318.unwrap();319320ltrb.set_ring_segment_pointer(0x100);321ltrb.set_toggle_cycle(true);322gm.write_obj_at_addr(ltrb, GuestAddress(0x300 + 2 * trb_size))323.unwrap();324gm325}326327#[test]328fn test_ring_buffer_controller() {329let (tx, rx) = channel();330let mem = setup_mem();331let (l, j) = EventLoop::start("test".to_string(), None).unwrap();332let l = Arc::new(l);333let controller = RingBufferController::new_with_handler(334"".to_string(),335mem,336l.clone(),337TestHandler { sender: tx },338)339.unwrap();340controller.set_dequeue_pointer(GuestAddress(0x100));341controller.set_consumer_cycle_state(false);342controller.start();343assert_eq!(rx.recv().unwrap(), 1);344assert_eq!(rx.recv().unwrap(), 2);345assert_eq!(rx.recv().unwrap(), 3);346assert_eq!(rx.recv().unwrap(), 4);347assert_eq!(rx.recv().unwrap(), 5);348assert_eq!(rx.recv().unwrap(), 6);349l.stop();350j.join().unwrap();351}352}353354355