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