1 // Copyright 2019 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use super::device_slot::{DeviceSlot, DeviceSlots, Error as DeviceSlotError}; 6 use super::interrupter::{Error as InterrupterError, Interrupter}; 7 use super::ring_buffer_controller::{ 8 Error as RingBufferControllerError, RingBufferController, TransferDescriptorHandler, 9 }; 10 use super::xhci_abi::{ 11 AddressDeviceCommandTrb, AddressedTrb, ConfigureEndpointCommandTrb, DisableSlotCommandTrb, 12 Error as TrbError, EvaluateContextCommandTrb, ResetDeviceCommandTrb, 13 SetTRDequeuePointerCommandTrb, StopEndpointCommandTrb, TransferDescriptor, TrbCast, 14 TrbCompletionCode, TrbType, 15 }; 16 use super::xhci_regs::{valid_slot_id, MAX_SLOTS}; 17 use crate::utils::EventLoop; 18 use std::fmt::{self, Display}; 19 use std::sync::Arc; 20 use sync::Mutex; 21 use sys_util::{error, warn, Error as SysError, EventFd, GuestAddress, GuestMemory}; 22 23 #[derive(Debug)] 24 pub enum Error { 25 WriteEventFd(SysError), 26 SendInterrupt(InterrupterError), 27 CastTrb(TrbError), 28 BadSlotId(u8), 29 StopEndpoint(DeviceSlotError), 30 ConfigEndpoint(DeviceSlotError), 31 SetAddress(DeviceSlotError), 32 SetDequeuePointer(DeviceSlotError), 33 EvaluateContext(DeviceSlotError), 34 DisableSlot(DeviceSlotError), 35 ResetSlot(DeviceSlotError), 36 } 37 38 type Result<T> = std::result::Result<T, Error>; 39 40 impl Display for Error { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result41 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 42 use self::Error::*; 43 44 match self { 45 WriteEventFd(e) => write!(f, "failed to write event fd: {}", e), 46 SendInterrupt(e) => write!(f, "failed to send interrupt: {}", e), 47 CastTrb(e) => write!(f, "failed to cast trb: {}", e), 48 BadSlotId(id) => write!(f, "bad slot id: {}", id), 49 StopEndpoint(e) => write!(f, "failed to stop endpoint: {}", e), 50 ConfigEndpoint(e) => write!(f, "failed to config endpoint: {}", e), 51 SetAddress(e) => write!(f, "failed to set address: {}", e), 52 SetDequeuePointer(e) => write!(f, "failed to set dequeue pointer: {}", e), 53 EvaluateContext(e) => write!(f, "failed to evaluate context: {}", e), 54 DisableSlot(e) => write!(f, "failed to disable slot: {}", e), 55 ResetSlot(e) => write!(f, "failed to reset slot: {}", e), 56 } 57 } 58 } 59 60 pub type CommandRingController = RingBufferController<CommandRingTrbHandler>; 61 pub type CommandRingControllerError = RingBufferControllerError; 62 63 impl CommandRingController { new( mem: GuestMemory, event_loop: Arc<EventLoop>, slots: DeviceSlots, interrupter: Arc<Mutex<Interrupter>>, ) -> std::result::Result<Arc<CommandRingController>, RingBufferControllerError>64 pub fn new( 65 mem: GuestMemory, 66 event_loop: Arc<EventLoop>, 67 slots: DeviceSlots, 68 interrupter: Arc<Mutex<Interrupter>>, 69 ) -> std::result::Result<Arc<CommandRingController>, RingBufferControllerError> { 70 RingBufferController::new_with_handler( 71 String::from("command ring"), 72 mem, 73 event_loop, 74 CommandRingTrbHandler::new(slots, interrupter), 75 ) 76 } 77 } 78 79 pub struct CommandRingTrbHandler { 80 slots: DeviceSlots, 81 interrupter: Arc<Mutex<Interrupter>>, 82 } 83 84 impl CommandRingTrbHandler { new(slots: DeviceSlots, interrupter: Arc<Mutex<Interrupter>>) -> Self85 fn new(slots: DeviceSlots, interrupter: Arc<Mutex<Interrupter>>) -> Self { 86 CommandRingTrbHandler { slots, interrupter } 87 } 88 slot(&self, slot_id: u8) -> Result<Arc<DeviceSlot>>89 fn slot(&self, slot_id: u8) -> Result<Arc<DeviceSlot>> { 90 self.slots.slot(slot_id).ok_or(Error::BadSlotId(slot_id)) 91 } 92 command_completion_callback( interrupter: &Arc<Mutex<Interrupter>>, completion_code: TrbCompletionCode, slot_id: u8, trb_addr: u64, event_fd: &EventFd, ) -> Result<()>93 fn command_completion_callback( 94 interrupter: &Arc<Mutex<Interrupter>>, 95 completion_code: TrbCompletionCode, 96 slot_id: u8, 97 trb_addr: u64, 98 event_fd: &EventFd, 99 ) -> Result<()> { 100 interrupter 101 .lock() 102 .send_command_completion_trb(completion_code, slot_id, GuestAddress(trb_addr)) 103 .map_err(Error::SendInterrupt)?; 104 event_fd.write(1).map_err(Error::WriteEventFd) 105 } 106 enable_slot(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()>107 fn enable_slot(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()> { 108 for slot_id in 1..=MAX_SLOTS { 109 if self.slot(slot_id)?.enable() { 110 return CommandRingTrbHandler::command_completion_callback( 111 &self.interrupter, 112 TrbCompletionCode::Success, 113 slot_id, 114 atrb.gpa, 115 &event_fd, 116 ); 117 } 118 } 119 120 CommandRingTrbHandler::command_completion_callback( 121 &self.interrupter, 122 TrbCompletionCode::NoSlotsAvailableError, 123 0, 124 atrb.gpa, 125 &event_fd, 126 ) 127 } 128 disable_slot(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()>129 fn disable_slot(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()> { 130 let trb = atrb 131 .trb 132 .cast::<DisableSlotCommandTrb>() 133 .map_err(Error::CastTrb)?; 134 let slot_id = trb.get_slot_id(); 135 if valid_slot_id(slot_id) { 136 let gpa = atrb.gpa; 137 let interrupter = self.interrupter.clone(); 138 self.slots 139 .disable_slot(slot_id, move |completion_code| { 140 CommandRingTrbHandler::command_completion_callback( 141 &interrupter, 142 completion_code, 143 slot_id, 144 gpa, 145 &event_fd, 146 ) 147 .map_err(|e| { 148 error!("failed to run command completion callback: {}", e); 149 }) 150 }) 151 .map_err(Error::DisableSlot) 152 } else { 153 CommandRingTrbHandler::command_completion_callback( 154 &self.interrupter, 155 TrbCompletionCode::TrbError, 156 slot_id, 157 atrb.gpa, 158 &event_fd, 159 ) 160 } 161 } 162 address_device(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()>163 fn address_device(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()> { 164 let trb = atrb 165 .trb 166 .cast::<AddressDeviceCommandTrb>() 167 .map_err(Error::CastTrb)?; 168 let slot_id = trb.get_slot_id(); 169 let completion_code = { 170 if valid_slot_id(slot_id) { 171 self.slot(slot_id)? 172 .set_address(trb) 173 .map_err(Error::SetAddress)? 174 } else { 175 TrbCompletionCode::TrbError 176 } 177 }; 178 CommandRingTrbHandler::command_completion_callback( 179 &self.interrupter, 180 completion_code, 181 slot_id, 182 atrb.gpa, 183 &event_fd, 184 ) 185 } 186 configure_endpoint(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()>187 fn configure_endpoint(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()> { 188 let trb = atrb 189 .trb 190 .cast::<ConfigureEndpointCommandTrb>() 191 .map_err(Error::CastTrb)?; 192 let slot_id = trb.get_slot_id(); 193 let completion_code = { 194 if valid_slot_id(slot_id) { 195 self.slot(slot_id)? 196 .configure_endpoint(trb) 197 .map_err(Error::ConfigEndpoint)? 198 } else { 199 TrbCompletionCode::TrbError 200 } 201 }; 202 CommandRingTrbHandler::command_completion_callback( 203 &self.interrupter, 204 completion_code, 205 slot_id, 206 atrb.gpa, 207 &event_fd, 208 ) 209 } 210 evaluate_context(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()>211 fn evaluate_context(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()> { 212 let trb = atrb 213 .trb 214 .cast::<EvaluateContextCommandTrb>() 215 .map_err(Error::CastTrb)?; 216 let slot_id = trb.get_slot_id(); 217 let completion_code = { 218 if valid_slot_id(slot_id) { 219 self.slot(slot_id)? 220 .evaluate_context(trb) 221 .map_err(Error::EvaluateContext)? 222 } else { 223 TrbCompletionCode::TrbError 224 } 225 }; 226 CommandRingTrbHandler::command_completion_callback( 227 &self.interrupter, 228 completion_code, 229 slot_id, 230 atrb.gpa, 231 &event_fd, 232 ) 233 } 234 reset_device(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()>235 fn reset_device(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()> { 236 let trb = atrb 237 .trb 238 .cast::<ResetDeviceCommandTrb>() 239 .map_err(Error::CastTrb)?; 240 let slot_id = trb.get_slot_id(); 241 if valid_slot_id(slot_id) { 242 let gpa = atrb.gpa; 243 let interrupter = self.interrupter.clone(); 244 self.slots 245 .reset_slot(slot_id, move |completion_code| { 246 CommandRingTrbHandler::command_completion_callback( 247 &interrupter, 248 completion_code, 249 slot_id, 250 gpa, 251 &event_fd, 252 ) 253 .map_err(|e| { 254 error!("command completion callback failed: {}", e); 255 }) 256 }) 257 .map_err(Error::ResetSlot) 258 } else { 259 CommandRingTrbHandler::command_completion_callback( 260 &self.interrupter, 261 TrbCompletionCode::TrbError, 262 slot_id, 263 atrb.gpa, 264 &event_fd, 265 ) 266 } 267 } 268 stop_endpoint(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()>269 fn stop_endpoint(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()> { 270 let trb = atrb 271 .trb 272 .cast::<StopEndpointCommandTrb>() 273 .map_err(Error::CastTrb)?; 274 let slot_id = trb.get_slot_id(); 275 let endpoint_id = trb.get_endpoint_id(); 276 if valid_slot_id(slot_id) { 277 let gpa = atrb.gpa; 278 let interrupter = self.interrupter.clone(); 279 self.slots 280 .stop_endpoint(slot_id, endpoint_id, move |completion_code| { 281 CommandRingTrbHandler::command_completion_callback( 282 &interrupter, 283 completion_code, 284 slot_id, 285 gpa, 286 &event_fd, 287 ) 288 .map_err(|e| { 289 error!("command completion callback failed: {}", e); 290 }) 291 }) 292 .map_err(Error::StopEndpoint)?; 293 Ok(()) 294 } else { 295 error!("stop endpoint trb has invalid slot id {}", slot_id); 296 CommandRingTrbHandler::command_completion_callback( 297 &self.interrupter, 298 TrbCompletionCode::TrbError, 299 slot_id, 300 atrb.gpa, 301 &event_fd, 302 ) 303 } 304 } 305 set_tr_dequeue_ptr(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()>306 fn set_tr_dequeue_ptr(&self, atrb: &AddressedTrb, event_fd: EventFd) -> Result<()> { 307 let trb = atrb 308 .trb 309 .cast::<SetTRDequeuePointerCommandTrb>() 310 .map_err(Error::CastTrb)?; 311 let slot_id = trb.get_slot_id(); 312 let endpoint_id = trb.get_endpoint_id(); 313 // See Set TR Dequeue Pointer Trb in spec. 314 let dequeue_ptr = trb.get_dequeue_ptr().get_gpa().offset(); 315 let completion_code = { 316 if valid_slot_id(slot_id) { 317 self.slot(slot_id)? 318 .set_tr_dequeue_ptr(endpoint_id, dequeue_ptr) 319 .map_err(Error::SetDequeuePointer)? 320 } else { 321 error!("stop endpoint trb has invalid slot id {}", slot_id); 322 TrbCompletionCode::TrbError 323 } 324 }; 325 CommandRingTrbHandler::command_completion_callback( 326 &self.interrupter, 327 completion_code, 328 slot_id, 329 atrb.gpa, 330 &event_fd, 331 ) 332 } 333 } 334 335 impl TransferDescriptorHandler for CommandRingTrbHandler { handle_transfer_descriptor( &self, descriptor: TransferDescriptor, complete_event: EventFd, ) -> std::result::Result<(), ()>336 fn handle_transfer_descriptor( 337 &self, 338 descriptor: TransferDescriptor, 339 complete_event: EventFd, 340 ) -> std::result::Result<(), ()> { 341 // Command descriptor always consist of a single TRB. 342 assert_eq!(descriptor.len(), 1); 343 let atrb = &descriptor[0]; 344 let command_result = match atrb.trb.get_trb_type() { 345 Ok(TrbType::EnableSlotCommand) => self.enable_slot(atrb, complete_event), 346 Ok(TrbType::DisableSlotCommand) => self.disable_slot(atrb, complete_event), 347 Ok(TrbType::AddressDeviceCommand) => self.address_device(atrb, complete_event), 348 Ok(TrbType::ConfigureEndpointCommand) => self.configure_endpoint(atrb, complete_event), 349 Ok(TrbType::EvaluateContextCommand) => self.evaluate_context(atrb, complete_event), 350 Ok(TrbType::ResetDeviceCommand) => self.reset_device(atrb, complete_event), 351 Ok(TrbType::NoopCommand) => CommandRingTrbHandler::command_completion_callback( 352 &self.interrupter, 353 TrbCompletionCode::Success, 354 0, 355 atrb.gpa, 356 &complete_event, 357 ), 358 Ok(TrbType::ResetEndpointCommand) => { 359 error!( 360 "Receiving reset endpoint command. \ 361 It should only happen when cmd ring stall" 362 ); 363 CommandRingTrbHandler::command_completion_callback( 364 &self.interrupter, 365 TrbCompletionCode::TrbError, 366 0, 367 atrb.gpa, 368 &complete_event, 369 ) 370 } 371 Ok(TrbType::StopEndpointCommand) => self.stop_endpoint(atrb, complete_event), 372 Ok(TrbType::SetTRDequeuePointerCommand) => { 373 self.set_tr_dequeue_ptr(atrb, complete_event) 374 } 375 _ => { 376 warn!( 377 // We are not handling type 14,15,16. See table 6.4.6. 378 "Unexpected command ring trb type: {}", 379 atrb.trb 380 ); 381 match self.interrupter.lock().send_command_completion_trb( 382 TrbCompletionCode::TrbError, 383 0, 384 GuestAddress(atrb.gpa), 385 ) { 386 Err(e) => Err(Error::SendInterrupt(e)), 387 Ok(_) => complete_event.write(1).map_err(Error::WriteEventFd), 388 } 389 } 390 }; 391 command_result.map_err(|e| { 392 error!("command failed: {}", e); 393 }) 394 } 395 } 396