Path: blob/main/devices/src/usb/xhci/command_ring_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.34#![allow(clippy::result_large_err)]56use std::sync::Arc;78use anyhow::Context;9use base::error;10use base::warn;11use base::Error as SysError;12use base::Event;13use remain::sorted;14use sync::Mutex;15use thiserror::Error;16use vm_memory::GuestAddress;17use vm_memory::GuestMemory;1819use super::device_slot::DeviceSlot;20use super::device_slot::DeviceSlots;21use super::device_slot::Error as DeviceSlotError;22use super::interrupter::Error as InterrupterError;23use super::interrupter::Interrupter;24use super::ring_buffer_controller::Error as RingBufferControllerError;25use super::ring_buffer_controller::RingBufferController;26use super::ring_buffer_controller::TransferDescriptorHandler;27use super::xhci_abi::AddressDeviceCommandTrb;28use super::xhci_abi::AddressedTrb;29use super::xhci_abi::ConfigureEndpointCommandTrb;30use super::xhci_abi::DisableSlotCommandTrb;31use super::xhci_abi::Error as TrbError;32use super::xhci_abi::EvaluateContextCommandTrb;33use super::xhci_abi::ResetDeviceCommandTrb;34use super::xhci_abi::ResetEndpointCommandTrb;35use super::xhci_abi::SetTRDequeuePointerCommandTrb;36use super::xhci_abi::StopEndpointCommandTrb;37use super::xhci_abi::TransferDescriptor;38use super::xhci_abi::TrbCast;39use super::xhci_abi::TrbCompletionCode;40use super::xhci_abi::TrbType;41use super::xhci_regs::valid_slot_id;42use super::xhci_regs::MAX_SLOTS;43use crate::utils::EventLoop;4445#[sorted]46#[derive(Error, Debug)]47pub enum Error {48#[error("bad slot id: {0}")]49BadSlotId(u8),50#[error("failed to cast trb: {0}")]51CastTrb(TrbError),52#[error("failed to config endpoint: {0}")]53ConfigEndpoint(DeviceSlotError),54#[error("failed to disable slot: {0}")]55DisableSlot(DeviceSlotError),56#[error("failed to evaluate context: {0}")]57EvaluateContext(DeviceSlotError),58#[error("failed to reset slot: {0}")]59ResetSlot(DeviceSlotError),60#[error("failed to send interrupt: {0}")]61SendInterrupt(InterrupterError),62#[error("failed to set address: {0}")]63SetAddress(DeviceSlotError),64#[error("failed to set dequeue pointer: {0}")]65SetDequeuePointer(DeviceSlotError),66#[error("failed to stop endpoint: {0}")]67StopEndpoint(DeviceSlotError),68#[error("failed to write event: {0}")]69WriteEvent(SysError),70}7172type Result<T> = std::result::Result<T, Error>;7374pub type CommandRingController = RingBufferController<CommandRingTrbHandler>;75pub type CommandRingControllerError = RingBufferControllerError;7677impl CommandRingController {78pub fn new(79mem: GuestMemory,80event_loop: Arc<EventLoop>,81slots: DeviceSlots,82interrupter: Arc<Mutex<Interrupter>>,83) -> std::result::Result<Arc<CommandRingController>, RingBufferControllerError> {84RingBufferController::new_with_handler(85String::from("command ring"),86mem,87event_loop,88CommandRingTrbHandler::new(slots, interrupter),89)90}91}9293pub struct CommandRingTrbHandler {94slots: DeviceSlots,95interrupter: Arc<Mutex<Interrupter>>,96}9798impl CommandRingTrbHandler {99fn new(slots: DeviceSlots, interrupter: Arc<Mutex<Interrupter>>) -> Self {100CommandRingTrbHandler { slots, interrupter }101}102103fn slot(&self, slot_id: u8) -> Result<Arc<DeviceSlot>> {104self.slots.slot(slot_id).ok_or(Error::BadSlotId(slot_id))105}106107fn command_completion_callback(108interrupter: &Arc<Mutex<Interrupter>>,109completion_code: TrbCompletionCode,110slot_id: u8,111trb_addr: u64,112event: &Event,113) -> Result<()> {114interrupter115.lock()116.send_command_completion_trb(completion_code, slot_id, GuestAddress(trb_addr))117.map_err(Error::SendInterrupt)?;118event.signal().map_err(Error::WriteEvent)119}120121fn enable_slot(&self, atrb: &AddressedTrb, event: Event) -> Result<()> {122for slot_id in 1..=MAX_SLOTS {123if self.slot(slot_id)?.enable() {124return CommandRingTrbHandler::command_completion_callback(125&self.interrupter,126TrbCompletionCode::Success,127slot_id,128atrb.gpa,129&event,130);131}132}133134CommandRingTrbHandler::command_completion_callback(135&self.interrupter,136TrbCompletionCode::NoSlotsAvailableError,1370,138atrb.gpa,139&event,140)141}142143fn disable_slot(&self, atrb: &AddressedTrb, event: Event) -> Result<()> {144let trb = atrb145.trb146.cast::<DisableSlotCommandTrb>()147.map_err(Error::CastTrb)?;148let slot_id = trb.get_slot_id();149if valid_slot_id(slot_id) {150let gpa = atrb.gpa;151let interrupter = self.interrupter.clone();152self.slots153.disable_slot(slot_id, move |completion_code| {154CommandRingTrbHandler::command_completion_callback(155&interrupter,156completion_code,157slot_id,158gpa,159&event,160)161.map_err(|e| {162error!("failed to run command completion callback: {}", e);163})164})165.map_err(Error::DisableSlot)166} else {167CommandRingTrbHandler::command_completion_callback(168&self.interrupter,169TrbCompletionCode::TrbError,170slot_id,171atrb.gpa,172&event,173)174}175}176177fn address_device(&self, atrb: &AddressedTrb, event: Event) -> Result<()> {178let trb = atrb179.trb180.cast::<AddressDeviceCommandTrb>()181.map_err(Error::CastTrb)?;182let slot_id = trb.get_slot_id();183let completion_code = {184if valid_slot_id(slot_id) {185self.slot(slot_id)?186.set_address(trb)187.map_err(Error::SetAddress)?188} else {189TrbCompletionCode::TrbError190}191};192CommandRingTrbHandler::command_completion_callback(193&self.interrupter,194completion_code,195slot_id,196atrb.gpa,197&event,198)199}200201fn configure_endpoint(&self, atrb: &AddressedTrb, event: Event) -> Result<()> {202let trb = atrb203.trb204.cast::<ConfigureEndpointCommandTrb>()205.map_err(Error::CastTrb)?;206let slot_id = trb.get_slot_id();207let completion_code = {208if valid_slot_id(slot_id) {209self.slot(slot_id)?210.configure_endpoint(trb)211.map_err(Error::ConfigEndpoint)?212} else {213TrbCompletionCode::TrbError214}215};216CommandRingTrbHandler::command_completion_callback(217&self.interrupter,218completion_code,219slot_id,220atrb.gpa,221&event,222)223}224225fn evaluate_context(&self, atrb: &AddressedTrb, event: Event) -> Result<()> {226let trb = atrb227.trb228.cast::<EvaluateContextCommandTrb>()229.map_err(Error::CastTrb)?;230let slot_id = trb.get_slot_id();231let completion_code = {232if valid_slot_id(slot_id) {233self.slot(slot_id)?234.evaluate_context(trb)235.map_err(Error::EvaluateContext)?236} else {237TrbCompletionCode::TrbError238}239};240CommandRingTrbHandler::command_completion_callback(241&self.interrupter,242completion_code,243slot_id,244atrb.gpa,245&event,246)247}248249fn reset_device(&self, atrb: &AddressedTrb, event: Event) -> Result<()> {250let trb = atrb251.trb252.cast::<ResetDeviceCommandTrb>()253.map_err(Error::CastTrb)?;254let slot_id = trb.get_slot_id();255if valid_slot_id(slot_id) {256let gpa = atrb.gpa;257let interrupter = self.interrupter.clone();258self.slots259.reset_slot(slot_id, move |completion_code| {260CommandRingTrbHandler::command_completion_callback(261&interrupter,262completion_code,263slot_id,264gpa,265&event,266)267.map_err(|e| {268error!("command completion callback failed: {}", e);269})270})271.map_err(Error::ResetSlot)272} else {273CommandRingTrbHandler::command_completion_callback(274&self.interrupter,275TrbCompletionCode::TrbError,276slot_id,277atrb.gpa,278&event,279)280}281}282283fn stop_endpoint(&self, atrb: &AddressedTrb, event: Event) -> Result<()> {284let trb = atrb285.trb286.cast::<StopEndpointCommandTrb>()287.map_err(Error::CastTrb)?;288let slot_id = trb.get_slot_id();289let endpoint_id = trb.get_endpoint_id();290if valid_slot_id(slot_id) {291let gpa = atrb.gpa;292let interrupter = self.interrupter.clone();293self.slots294.stop_endpoint(slot_id, endpoint_id, move |completion_code| {295CommandRingTrbHandler::command_completion_callback(296&interrupter,297completion_code,298slot_id,299gpa,300&event,301)302.map_err(|e| {303error!("command completion callback failed: {}", e);304})305})306.map_err(Error::StopEndpoint)?;307Ok(())308} else {309error!("stop endpoint trb has invalid slot id {}", slot_id);310CommandRingTrbHandler::command_completion_callback(311&self.interrupter,312TrbCompletionCode::TrbError,313slot_id,314atrb.gpa,315&event,316)317}318}319320fn reset_endpoint(&self, atrb: &AddressedTrb, event: Event) -> Result<()> {321let trb = atrb322.trb323.cast::<ResetEndpointCommandTrb>()324.map_err(Error::CastTrb)?;325let slot_id = trb.get_slot_id();326let endpoint_id = trb.get_endpoint_id();327if valid_slot_id(slot_id) {328let gpa = atrb.gpa;329let interrupter = self.interrupter.clone();330self.slots331.reset_endpoint(slot_id, endpoint_id, move |completion_code| {332CommandRingTrbHandler::command_completion_callback(333&interrupter,334completion_code,335slot_id,336gpa,337&event,338)339.map_err(|e| {340error!("command completion callback failed: {}", e);341})342})343.map_err(Error::StopEndpoint)?;344Ok(())345} else {346error!("reset endpoint trb has invalid slot id {}", slot_id);347CommandRingTrbHandler::command_completion_callback(348&self.interrupter,349TrbCompletionCode::TrbError,350slot_id,351atrb.gpa,352&event,353)354}355}356357fn set_tr_dequeue_ptr(&self, atrb: &AddressedTrb, event: Event) -> Result<()> {358let trb = atrb359.trb360.cast::<SetTRDequeuePointerCommandTrb>()361.map_err(Error::CastTrb)?;362let slot_id = trb.get_slot_id();363let endpoint_id = trb.get_endpoint_id();364let stream_id = trb.get_stream_id();365// See Set TR Dequeue Pointer Trb in spec.366let dequeue_ptr = trb.get_dequeue_ptr().get_gpa().offset();367let completion_code = {368if valid_slot_id(slot_id) {369self.slot(slot_id)?370.set_tr_dequeue_ptr(endpoint_id, stream_id, dequeue_ptr)371.map_err(Error::SetDequeuePointer)?372} else {373error!("stop endpoint trb has invalid slot id {}", slot_id);374TrbCompletionCode::TrbError375}376};377CommandRingTrbHandler::command_completion_callback(378&self.interrupter,379completion_code,380slot_id,381atrb.gpa,382&event,383)384}385}386387impl TransferDescriptorHandler for CommandRingTrbHandler {388fn handle_transfer_descriptor(389&self,390descriptor: TransferDescriptor,391complete_event: Event,392) -> anyhow::Result<()> {393// Command descriptor always consist of a single TRB.394assert_eq!(descriptor.len(), 1);395let atrb = &descriptor[0];396let command_result = match atrb.trb.get_trb_type() {397Ok(TrbType::EnableSlotCommand) => self.enable_slot(atrb, complete_event),398Ok(TrbType::DisableSlotCommand) => self.disable_slot(atrb, complete_event),399Ok(TrbType::AddressDeviceCommand) => self.address_device(atrb, complete_event),400Ok(TrbType::ConfigureEndpointCommand) => self.configure_endpoint(atrb, complete_event),401Ok(TrbType::EvaluateContextCommand) => self.evaluate_context(atrb, complete_event),402Ok(TrbType::ResetDeviceCommand) => self.reset_device(atrb, complete_event),403Ok(TrbType::NoopCommand) => CommandRingTrbHandler::command_completion_callback(404&self.interrupter,405TrbCompletionCode::Success,4060,407atrb.gpa,408&complete_event,409),410Ok(TrbType::ResetEndpointCommand) => self.reset_endpoint(atrb, complete_event),411Ok(TrbType::StopEndpointCommand) => self.stop_endpoint(atrb, complete_event),412Ok(TrbType::SetTRDequeuePointerCommand) => {413self.set_tr_dequeue_ptr(atrb, complete_event)414}415_ => {416warn!(417// We are not handling type 14,15,16. See table 6.4.6.418"Unexpected command ring trb type: {}",419atrb.trb420);421match self.interrupter.lock().send_command_completion_trb(422TrbCompletionCode::TrbError,4230,424GuestAddress(atrb.gpa),425) {426Err(e) => Err(Error::SendInterrupt(e)),427Ok(_) => complete_event.signal().map_err(Error::WriteEvent),428}429}430};431command_result.context("command ring TRB failed")432}433}434435436