devices/usb/xhci/
xhci_transfer.rs

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