• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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