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::interrupter::{Error as InterrupterError, Interrupter};
6 use super::scatter_gather_buffer::{Error as BufferError, ScatterGatherBuffer};
7 use super::usb_hub::{Error as HubError, UsbPort};
8 use super::xhci_abi::{
9 AddressedTrb, Error as TrbError, EventDataTrb, SetupStageTrb, TransferDescriptor, TrbCast,
10 TrbCompletionCode, TrbType,
11 };
12 use super::xhci_regs::MAX_INTERRUPTER;
13 use bit_field::Error as BitFieldError;
14 use std::cmp::min;
15 use std::fmt::{self, Display};
16 use std::mem;
17 use std::sync::{Arc, Weak};
18 use sync::Mutex;
19 use sys_util::{error, Error as SysError, EventFd, GuestMemory};
20 use usb_util::types::UsbRequestSetup;
21 use usb_util::usb_transfer::TransferStatus;
22
23 #[derive(Debug)]
24 pub enum Error {
25 TrbType(BitFieldError),
26 CastTrb(TrbError),
27 TransferLength(TrbError),
28 BadTrbType(TrbType),
29 WriteCompletionEvent(SysError),
30 CreateBuffer(BufferError),
31 DetachPort(HubError),
32 SendInterrupt(InterrupterError),
33 SubmitTransfer,
34 }
35
36 type Result<T> = std::result::Result<T, Error>;
37
38 impl Display for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result39 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
40 use self::Error::*;
41
42 match self {
43 TrbType(e) => write!(f, "cannot get trb type: {}", e),
44 CastTrb(e) => write!(f, "cannot cast trb: {}", e),
45 TransferLength(e) => write!(f, "cannot get transfer length: {}", e),
46 BadTrbType(t) => write!(f, "unexpected trb type: {:?}", t),
47 WriteCompletionEvent(e) => write!(f, "cannot write completion event: {}", e),
48 CreateBuffer(e) => write!(f, "cannot create transfer buffer: {}", e),
49 DetachPort(e) => write!(f, "cannot detach from port: {}", e),
50 SendInterrupt(e) => write!(f, "cannot send interrupter: {}", e),
51 SubmitTransfer => write!(f, "failed to submit transfer to backend"),
52 }
53 }
54 }
55
56 /// Type of usb endpoints.
57 #[derive(PartialEq, Clone, Copy, Debug)]
58 pub enum TransferDirection {
59 In,
60 Out,
61 Control,
62 }
63
64 /// Current state of xhci transfer.
65 pub enum XhciTransferState {
66 Created,
67 /// When transfer is submitted, it will contain a transfer callback, which should be invoked
68 /// when the transfer is cancelled.
69 Submitted {
70 cancel_callback: Box<dyn FnMut() + Send>,
71 },
72 Cancelling,
73 Cancelled,
74 Completed,
75 }
76
77 impl XhciTransferState {
78 /// Try to cancel this transfer, if it's possible.
try_cancel(&mut self)79 pub fn try_cancel(&mut self) {
80 match mem::replace(self, XhciTransferState::Created) {
81 XhciTransferState::Submitted {
82 mut cancel_callback,
83 } => {
84 *self = XhciTransferState::Cancelling;
85 cancel_callback();
86 }
87 XhciTransferState::Cancelling => {
88 error!("Another cancellation is already issued.");
89 }
90 _ => {
91 *self = XhciTransferState::Cancelled;
92 }
93 }
94 }
95 }
96
97 /// Type of a transfer received handled by transfer ring.
98 pub enum XhciTransferType {
99 // Normal means bulk transfer or interrupt transfer, depending on endpoint type.
100 // See spec 4.11.2.1.
101 Normal(ScatterGatherBuffer),
102 // See usb spec for setup stage, data stage and status stage,
103 // see xHCI spec 4.11.2.2 for corresponding trbs.
104 SetupStage(UsbRequestSetup),
105 DataStage(ScatterGatherBuffer),
106 StatusStage,
107 // See xHCI spec 4.11.2.3.
108 Isochronous(ScatterGatherBuffer),
109 // See xHCI spec 6.4.1.4.
110 Noop,
111 }
112
113 impl XhciTransferType {
114 /// Analyze transfer descriptor and return transfer type.
new(mem: GuestMemory, td: TransferDescriptor) -> Result<XhciTransferType>115 pub fn new(mem: GuestMemory, td: TransferDescriptor) -> Result<XhciTransferType> {
116 // We can figure out transfer type from the first trb.
117 // See transfer descriptor description in xhci spec for more details.
118 match td[0].trb.get_trb_type().map_err(Error::TrbType)? {
119 TrbType::Normal => {
120 let buffer = ScatterGatherBuffer::new(mem, td).map_err(Error::CreateBuffer)?;
121 Ok(XhciTransferType::Normal(buffer))
122 }
123 TrbType::SetupStage => {
124 let trb = td[0].trb.cast::<SetupStageTrb>().map_err(Error::CastTrb)?;
125 Ok(XhciTransferType::SetupStage(UsbRequestSetup::new(
126 trb.get_request_type(),
127 trb.get_request(),
128 trb.get_value(),
129 trb.get_index(),
130 trb.get_length(),
131 )))
132 }
133 TrbType::DataStage => {
134 let buffer = ScatterGatherBuffer::new(mem, td).map_err(Error::CreateBuffer)?;
135 Ok(XhciTransferType::DataStage(buffer))
136 }
137 TrbType::StatusStage => Ok(XhciTransferType::StatusStage),
138 TrbType::Isoch => {
139 let buffer = ScatterGatherBuffer::new(mem, td).map_err(Error::CreateBuffer)?;
140 Ok(XhciTransferType::Isochronous(buffer))
141 }
142 TrbType::Noop => Ok(XhciTransferType::Noop),
143 t => Err(Error::BadTrbType(t)),
144 }
145 }
146 }
147
148 /// Xhci Transfer manager holds reference to all ongoing transfers. Can cancel them all if
149 /// needed.
150 #[derive(Clone)]
151 pub struct XhciTransferManager {
152 transfers: Arc<Mutex<Vec<Weak<Mutex<XhciTransferState>>>>>,
153 }
154
155 impl XhciTransferManager {
156 /// Create a new manager.
new() -> XhciTransferManager157 pub fn new() -> XhciTransferManager {
158 XhciTransferManager {
159 transfers: Arc::new(Mutex::new(Vec::new())),
160 }
161 }
162
163 /// Build a new XhciTransfer. Endpoint id is the id in xHCI device slot.
create_transfer( &self, mem: GuestMemory, port: Arc<UsbPort>, interrupter: Arc<Mutex<Interrupter>>, slot_id: u8, endpoint_id: u8, transfer_trbs: TransferDescriptor, completion_event: EventFd, ) -> XhciTransfer164 pub fn create_transfer(
165 &self,
166 mem: GuestMemory,
167 port: Arc<UsbPort>,
168 interrupter: Arc<Mutex<Interrupter>>,
169 slot_id: u8,
170 endpoint_id: u8,
171 transfer_trbs: TransferDescriptor,
172 completion_event: EventFd,
173 ) -> XhciTransfer {
174 assert!(!transfer_trbs.is_empty());
175 let transfer_dir = {
176 if endpoint_id == 0 {
177 TransferDirection::Control
178 } else if (endpoint_id % 2) == 0 {
179 TransferDirection::Out
180 } else {
181 TransferDirection::In
182 }
183 };
184 let t = XhciTransfer {
185 manager: self.clone(),
186 state: Arc::new(Mutex::new(XhciTransferState::Created)),
187 mem,
188 port,
189 interrupter,
190 transfer_completion_event: completion_event,
191 slot_id,
192 endpoint_id,
193 transfer_dir,
194 transfer_trbs,
195 };
196 self.transfers.lock().push(Arc::downgrade(&t.state));
197 t
198 }
199
200 /// Cancel all current transfers.
cancel_all(&self)201 pub fn cancel_all(&self) {
202 self.transfers.lock().iter().for_each(|t| {
203 let state = match t.upgrade() {
204 Some(state) => state,
205 None => {
206 error!("transfer is already cancelled or finished");
207 return;
208 }
209 };
210 state.lock().try_cancel();
211 });
212 }
213
remove_transfer(&self, t: &Arc<Mutex<XhciTransferState>>)214 fn remove_transfer(&self, t: &Arc<Mutex<XhciTransferState>>) {
215 let mut transfers = self.transfers.lock();
216 match transfers.iter().position(|wt| match wt.upgrade() {
217 Some(wt) => Arc::ptr_eq(&wt, t),
218 None => false,
219 }) {
220 None => error!("attempted to remove unknow transfer"),
221 Some(i) => {
222 transfers.swap_remove(i);
223 }
224 }
225 }
226 }
227
228 /// Xhci transfer denotes a transfer initiated by guest os driver. It will be submitted to a
229 /// XhciBackendDevice.
230 pub struct XhciTransfer {
231 manager: XhciTransferManager,
232 state: Arc<Mutex<XhciTransferState>>,
233 mem: GuestMemory,
234 port: Arc<UsbPort>,
235 interrupter: Arc<Mutex<Interrupter>>,
236 slot_id: u8,
237 // id of endpoint in device slot.
238 endpoint_id: u8,
239 transfer_dir: TransferDirection,
240 transfer_trbs: TransferDescriptor,
241 transfer_completion_event: EventFd,
242 }
243
244 impl Drop for XhciTransfer {
drop(&mut self)245 fn drop(&mut self) {
246 self.manager.remove_transfer(&self.state);
247 }
248 }
249
250 impl fmt::Debug for XhciTransfer {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result251 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
252 write!(
253 f,
254 "xhci_transfer slot id: {}, endpoint id {}, transfer_dir {:?}, transfer_trbs {:?}",
255 self.slot_id, self.endpoint_id, self.transfer_dir, self.transfer_trbs
256 )
257 }
258 }
259
260 impl XhciTransfer {
261 /// Get state of this transfer.
state(&self) -> &Arc<Mutex<XhciTransferState>>262 pub fn state(&self) -> &Arc<Mutex<XhciTransferState>> {
263 &self.state
264 }
265
266 /// Get transfer type.
get_transfer_type(&self) -> Result<XhciTransferType>267 pub fn get_transfer_type(&self) -> Result<XhciTransferType> {
268 XhciTransferType::new(self.mem.clone(), self.transfer_trbs.clone())
269 }
270
271 /// Get endpoint number.
get_endpoint_number(&self) -> u8272 pub fn get_endpoint_number(&self) -> u8 {
273 // See spec 4.5.1 for dci.
274 self.endpoint_id / 2
275 }
276
277 /// get transfer direction.
get_transfer_dir(&self) -> TransferDirection278 pub fn get_transfer_dir(&self) -> TransferDirection {
279 self.transfer_dir
280 }
281
282 /// This functions should be invoked when transfer is completed (or failed).
on_transfer_complete( &self, status: &TransferStatus, bytes_transferred: u32, ) -> Result<()>283 pub fn on_transfer_complete(
284 &self,
285 status: &TransferStatus,
286 bytes_transferred: u32,
287 ) -> Result<()> {
288 match status {
289 TransferStatus::NoDevice => {
290 usb_debug!("device disconnected, detaching from port");
291 // If the device is gone, we don't need to send transfer completion event, cause we
292 // are going to destroy everything related to this device anyway.
293 self.port.detach().map_err(Error::DetachPort)?;
294 return Ok(());
295 }
296 TransferStatus::Cancelled => {
297 // TODO(jkwang) According to the spec, we should send a stopped event here. But
298 // kernel driver does not do anything meaningful when it sees a stopped event.
299 return self
300 .transfer_completion_event
301 .write(1)
302 .map_err(Error::WriteCompletionEvent);
303 }
304 TransferStatus::Completed => {
305 self.transfer_completion_event
306 .write(1)
307 .map_err(Error::WriteCompletionEvent)?;
308 }
309 _ => {
310 // Transfer failed, we are not handling this correctly yet. Guest kernel might see
311 // short packets for in transfer and might think control transfer is successful. It
312 // will eventually find out device is in a wrong state.
313 self.transfer_completion_event
314 .write(1)
315 .map_err(Error::WriteCompletionEvent)?;
316 }
317 }
318
319 let mut edtla: u32 = 0;
320 // As noted in xHCI spec 4.11.3.1
321 // Transfer Event TRB only occurs under the following conditions:
322 // 1. If the Interrupt On Completion flag is set.
323 // 2. When a short transfer occurs during the execution of a Transfer TRB and the
324 // Interrupt-on-Short Packet flag is set.
325 // 3. If an error occurs during the execution of a Transfer TRB.
326 // Errors are handled above, so just check for the two flags.
327 for atrb in &self.transfer_trbs {
328 edtla += atrb.trb.transfer_length().map_err(Error::TransferLength)?;
329 if atrb.trb.interrupt_on_completion()
330 || (atrb.trb.interrupt_on_short_packet() && edtla > bytes_transferred)
331 {
332 // For details about event data trb and EDTLA, see spec 4.11.5.2.
333 if atrb.trb.get_trb_type().map_err(Error::TrbType)? == TrbType::EventData {
334 let tlength = min(edtla, bytes_transferred);
335 self.interrupter
336 .lock()
337 .send_transfer_event_trb(
338 TrbCompletionCode::Success,
339 atrb.trb
340 .cast::<EventDataTrb>()
341 .map_err(Error::CastTrb)?
342 .get_event_data(),
343 tlength,
344 true,
345 self.slot_id,
346 self.endpoint_id,
347 )
348 .map_err(Error::SendInterrupt)?;
349 } else {
350 // For Short Transfer details, see xHCI spec 4.10.1.1.
351 if edtla > bytes_transferred {
352 usb_debug!("on transfer complete short packet");
353 let residual_transfer_length = edtla - bytes_transferred;
354 self.interrupter
355 .lock()
356 .send_transfer_event_trb(
357 TrbCompletionCode::ShortPacket,
358 atrb.gpa,
359 residual_transfer_length,
360 true,
361 self.slot_id,
362 self.endpoint_id,
363 )
364 .map_err(Error::SendInterrupt)?;
365 } else {
366 usb_debug!("on transfer complete success");
367 self.interrupter
368 .lock()
369 .send_transfer_event_trb(
370 TrbCompletionCode::Success,
371 atrb.gpa,
372 0, // transfer length
373 true,
374 self.slot_id,
375 self.endpoint_id,
376 )
377 .map_err(Error::SendInterrupt)?;
378 }
379 }
380 }
381 }
382 Ok(())
383 }
384
385 /// Send this transfer to backend if it's a valid transfer.
send_to_backend_if_valid(self) -> Result<()>386 pub fn send_to_backend_if_valid(self) -> Result<()> {
387 if self.validate_transfer()? {
388 // Backend should invoke on transfer complete when transfer is completed.
389 let port = self.port.clone();
390 let mut backend = port.get_backend_device();
391 match &mut *backend {
392 Some(backend) => backend
393 .submit_transfer(self)
394 .map_err(|_| Error::SubmitTransfer)?,
395 None => {
396 error!("backend is already disconnected");
397 self.transfer_completion_event
398 .write(1)
399 .map_err(Error::WriteCompletionEvent)?;
400 }
401 }
402 } else {
403 error!("invalid td on transfer ring");
404 self.transfer_completion_event
405 .write(1)
406 .map_err(Error::WriteCompletionEvent)?;
407 }
408 Ok(())
409 }
410
411 // Check each trb in the transfer descriptor for invalid or out of bounds
412 // parameters. Returns true iff the transfer descriptor is valid.
validate_transfer(&self) -> Result<bool>413 fn validate_transfer(&self) -> Result<bool> {
414 let mut valid = true;
415 for atrb in &self.transfer_trbs {
416 if !trb_is_valid(&atrb) {
417 self.interrupter
418 .lock()
419 .send_transfer_event_trb(
420 TrbCompletionCode::TrbError,
421 atrb.gpa,
422 0,
423 false,
424 self.slot_id,
425 self.endpoint_id,
426 )
427 .map_err(Error::SendInterrupt)?;
428 valid = false;
429 }
430 }
431 Ok(valid)
432 }
433 }
434
trb_is_valid(atrb: &AddressedTrb) -> bool435 fn trb_is_valid(atrb: &AddressedTrb) -> bool {
436 let can_be_in_transfer_ring = match atrb.trb.can_be_in_transfer_ring() {
437 Ok(v) => v,
438 Err(e) => {
439 error!("unknown error {:?}", e);
440 return false;
441 }
442 };
443 can_be_in_transfer_ring && (atrb.trb.interrupter_target() < MAX_INTERRUPTER)
444 }
445