blob: 3a2779192dbbbb0d5022a8b61f58c6d91e3681ca [file] [log] [blame]
// Copyright 2019 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::fmt;
use std::fmt::Display;
use std::sync::Arc;
use std::sync::MutexGuard;
use anyhow::Context;
use base::debug;
use base::error;
use base::info;
use base::Error as SysError;
use base::Event;
use base::EventType;
use remain::sorted;
use sync::Mutex;
use thiserror::Error;
use vm_memory::GuestAddress;
use vm_memory::GuestMemory;
use super::ring_buffer::RingBuffer;
use super::ring_buffer_stop_cb::RingBufferStopCallback;
use super::xhci_abi::TransferDescriptor;
use crate::utils;
use crate::utils::EventHandler;
use crate::utils::EventLoop;
#[sorted]
#[derive(Error, Debug)]
pub enum Error {
#[error("failed to add event to event loop: {0}")]
AddEvent(utils::Error),
#[error("failed to create event: {0}")]
CreateEvent(SysError),
}
type Result<T> = std::result::Result<T, Error>;
#[derive(PartialEq, Copy, Clone, Eq)]
enum RingBufferState {
/// Running: RingBuffer is running, consuming transfer descriptor.
Running,
/// Stopping: Some thread requested RingBuffer stop. It will stop when current descriptor is
/// handled.
Stopping,
/// Stopped: RingBuffer already stopped.
Stopped,
}
/// TransferDescriptorHandler handles transfer descriptor. User should implement this trait and
/// build a ring buffer controller with the struct.
pub trait TransferDescriptorHandler {
/// Process descriptor asynchronously, write complete_event when done.
fn handle_transfer_descriptor(
&self,
descriptor: TransferDescriptor,
complete_event: Event,
) -> anyhow::Result<()>;
/// Stop is called when trying to stop ring buffer controller. Returns true when stop must be
/// performed asynchronously. This happens because the handler is handling some descriptor
/// asynchronously, the stop callback of ring buffer controller must be called after the
/// `async` part is handled or canceled. If the TransferDescriptorHandler decide it could stop
/// immediately, it could return false.
/// For example, if a handler submitted a transfer but the transfer has not yet finished. Then
/// guest kernel requests to stop the ring buffer controller. Transfer descriptor handler will
/// return true, thus RingBufferController would transfer to Stopping state. It will be stopped
/// when all pending transfer completed.
/// On the other hand, if hander does not have any pending transfers, it would return false.
fn stop(&self) -> bool {
true
}
}
/// RingBufferController owns a ring buffer. It lives on a event_loop. It will pop out transfer
/// descriptor and let TransferDescriptorHandler handle it.
pub struct RingBufferController<T: 'static + TransferDescriptorHandler> {
name: String,
state: Mutex<RingBufferState>,
stop_callback: Mutex<Vec<RingBufferStopCallback>>,
ring_buffer: Mutex<RingBuffer>,
handler: Mutex<T>,
event_loop: Arc<EventLoop>,
event: Event,
}
impl<T: 'static + TransferDescriptorHandler> Display for RingBufferController<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "RingBufferController `{}`", self.name)
}
}
impl<T: Send> RingBufferController<T>
where
T: 'static + TransferDescriptorHandler,
{
/// Create a ring buffer controller and add it to event loop.
pub fn new_with_handler(
name: String,
mem: GuestMemory,
event_loop: Arc<EventLoop>,
handler: T,
) -> Result<Arc<RingBufferController<T>>> {
let evt = Event::new().map_err(Error::CreateEvent)?;
let controller = Arc::new(RingBufferController {
name: name.clone(),
state: Mutex::new(RingBufferState::Stopped),
stop_callback: Mutex::new(Vec::new()),
ring_buffer: Mutex::new(RingBuffer::new(name, mem)),
handler: Mutex::new(handler),
event_loop: event_loop.clone(),
event: evt,
});
let event_handler: Arc<dyn EventHandler> = controller.clone();
event_loop
.add_event(
&controller.event,
EventType::Read,
Arc::downgrade(&event_handler),
)
.map_err(Error::AddEvent)?;
Ok(controller)
}
fn lock_ring_buffer(&self) -> MutexGuard<RingBuffer> {
self.ring_buffer.lock()
}
/// Get dequeue pointer of the internal ring buffer.
pub fn get_dequeue_pointer(&self) -> GuestAddress {
self.lock_ring_buffer().get_dequeue_pointer()
}
/// Set dequeue pointer of the internal ring buffer.
pub fn set_dequeue_pointer(&self, ptr: GuestAddress) {
xhci_trace!("{}: set_dequeue_pointer({:x})", self.name, ptr.0);
// Fast because this should only happen during xhci setup.
self.lock_ring_buffer().set_dequeue_pointer(ptr);
}
/// Get consumer cycle state.
pub fn get_consumer_cycle_state(&self) -> bool {
self.lock_ring_buffer().get_consumer_cycle_state()
}
/// Set consumer cycle state.
pub fn set_consumer_cycle_state(&self, state: bool) {
xhci_trace!("{}: set consumer cycle state: {}", self.name, state);
// Fast because this should only happen during xhci setup.
self.lock_ring_buffer().set_consumer_cycle_state(state);
}
/// Start the ring buffer.
pub fn start(&self) {
xhci_trace!("start {}", self.name);
let mut state = self.state.lock();
if *state != RingBufferState::Running {
*state = RingBufferState::Running;
if let Err(e) = self.event.signal() {
error!("cannot start event ring: {}", e);
}
}
}
/// Stop the ring buffer asynchronously.
pub fn stop(&self, callback: RingBufferStopCallback) {
xhci_trace!("stop {}", self.name);
let mut state = self.state.lock();
if *state == RingBufferState::Stopped {
info!("xhci: {} is already stopped", self.name);
return;
}
if self.handler.lock().stop() {
*state = RingBufferState::Stopping;
self.stop_callback.lock().push(callback);
} else {
*state = RingBufferState::Stopped;
}
}
}
impl<T> Drop for RingBufferController<T>
where
T: 'static + TransferDescriptorHandler,
{
fn drop(&mut self) {
// Remove self from the event loop.
if let Err(e) = self.event_loop.remove_event_for_descriptor(&self.event) {
error!(
"cannot remove ring buffer controller from event loop: {}",
e
);
}
}
}
impl<T> EventHandler for RingBufferController<T>
where
T: 'static + TransferDescriptorHandler + Send,
{
fn on_event(&self) -> anyhow::Result<()> {
// `self.event` triggers ring buffer controller to run.
self.event.wait().context("cannot read from event")?;
let mut state = self.state.lock();
match *state {
RingBufferState::Stopped => return Ok(()),
RingBufferState::Stopping => {
debug!("xhci: {}: stopping ring buffer controller", self.name);
*state = RingBufferState::Stopped;
self.stop_callback.lock().clear();
return Ok(());
}
RingBufferState::Running => {}
}
let transfer_descriptor = self
.lock_ring_buffer()
.dequeue_transfer_descriptor()
.context("cannot dequeue transfer descriptor")?;
let transfer_descriptor = match transfer_descriptor {
Some(t) => t,
None => {
*state = RingBufferState::Stopped;
self.stop_callback.lock().clear();
return Ok(());
}
};
let event = self.event.try_clone().context("cannot clone event")?;
self.handler
.lock()
.handle_transfer_descriptor(transfer_descriptor, event)
}
}
#[cfg(test)]
mod tests {
use std::mem::size_of;
use std::sync::mpsc::channel;
use std::sync::mpsc::Sender;
use base::pagesize;
use super::super::xhci_abi::LinkTrb;
use super::super::xhci_abi::NormalTrb;
use super::super::xhci_abi::Trb;
use super::super::xhci_abi::TrbType;
use super::*;
struct TestHandler {
sender: Sender<i32>,
}
impl TransferDescriptorHandler for TestHandler {
fn handle_transfer_descriptor(
&self,
descriptor: TransferDescriptor,
complete_event: Event,
) -> anyhow::Result<()> {
for atrb in descriptor {
assert_eq!(atrb.trb.get_trb_type().unwrap(), TrbType::Normal);
self.sender.send(atrb.trb.get_parameter() as i32).unwrap();
}
complete_event.signal().unwrap();
Ok(())
}
}
fn setup_mem() -> GuestMemory {
let trb_size = size_of::<Trb>() as u64;
let gm = GuestMemory::new(&[(GuestAddress(0), pagesize() as u64)]).unwrap();
// Structure of ring buffer:
// 0x100 --> 0x200 --> 0x300
// trb 1 | trb 3 | trb 5
// trb 2 | trb 4 | trb 6
// l trb - l trb - l trb to 0x100
let mut trb = NormalTrb::new();
trb.set_trb_type(TrbType::Normal);
trb.set_data_buffer(1);
trb.set_chain(true);
gm.write_obj_at_addr(trb, GuestAddress(0x100)).unwrap();
trb.set_data_buffer(2);
gm.write_obj_at_addr(trb, GuestAddress(0x100 + trb_size))
.unwrap();
let mut ltrb = LinkTrb::new();
ltrb.set_trb_type(TrbType::Link);
ltrb.set_ring_segment_pointer(0x200);
gm.write_obj_at_addr(ltrb, GuestAddress(0x100 + 2 * trb_size))
.unwrap();
trb.set_data_buffer(3);
gm.write_obj_at_addr(trb, GuestAddress(0x200)).unwrap();
// Chain bit is false.
trb.set_data_buffer(4);
trb.set_chain(false);
gm.write_obj_at_addr(trb, GuestAddress(0x200 + 1 * trb_size))
.unwrap();
ltrb.set_ring_segment_pointer(0x300);
gm.write_obj_at_addr(ltrb, GuestAddress(0x200 + 2 * trb_size))
.unwrap();
trb.set_data_buffer(5);
trb.set_chain(true);
gm.write_obj_at_addr(trb, GuestAddress(0x300)).unwrap();
// Chain bit is false.
trb.set_data_buffer(6);
trb.set_chain(false);
gm.write_obj_at_addr(trb, GuestAddress(0x300 + 1 * trb_size))
.unwrap();
ltrb.set_ring_segment_pointer(0x100);
gm.write_obj_at_addr(ltrb, GuestAddress(0x300 + 2 * trb_size))
.unwrap();
gm
}
#[test]
fn test_ring_buffer_controller() {
let (tx, rx) = channel();
let mem = setup_mem();
let (l, j) = EventLoop::start("test".to_string(), None).unwrap();
let l = Arc::new(l);
let controller = RingBufferController::new_with_handler(
"".to_string(),
mem,
l.clone(),
TestHandler { sender: tx },
)
.unwrap();
controller.set_dequeue_pointer(GuestAddress(0x100));
controller.set_consumer_cycle_state(false);
controller.start();
assert_eq!(rx.recv().unwrap(), 1);
assert_eq!(rx.recv().unwrap(), 2);
assert_eq!(rx.recv().unwrap(), 3);
assert_eq!(rx.recv().unwrap(), 4);
assert_eq!(rx.recv().unwrap(), 5);
assert_eq!(rx.recv().unwrap(), 6);
l.stop();
j.join().unwrap();
}
}