1use std::cmp::min;
6use std::collections::VecDeque;
7use std::fmt;
8use std::fmt::Display;
9use std::mem;
10use std::sync::Arc;
11use std::sync::Weak;
12
13use base::debug;
14use base::error;
15use base::info;
16use base::warn;
17use base::Error as SysError;
18use base::Event;
19use bit_field::Error as BitFieldError;
20use remain::sorted;
21use sync::Mutex;
22use thiserror::Error;
23use usb_util::TransferStatus;
24use usb_util::UsbRequestSetup;
25use vm_memory::GuestMemory;
26use vm_memory::GuestMemoryError;
27
28use super::device_slot::DeviceSlot;
29use super::interrupter::Error as InterrupterError;
30use super::interrupter::Interrupter;
31use super::ring_buffer_stop_cb::RingBufferStopCallback;
32use super::scatter_gather_buffer::Error as BufferError;
33use super::scatter_gather_buffer::ScatterGatherBuffer;
34use super::usb_hub::Error as HubError;
35use super::usb_hub::UsbPort;
36use super::xhci_abi::AddressedTrb;
37use super::xhci_abi::Error as TrbError;
38use super::xhci_abi::EventDataTrb;
39use super::xhci_abi::SetupStageTrb;
40use super::xhci_abi::TransferDescriptor;
41use super::xhci_abi::TrbCast;
42use super::xhci_abi::TrbCompletionCode;
43use super::xhci_abi::TrbType;
44use super::xhci_regs::MAX_INTERRUPTER;
45
46#[sorted]
47#[derive(Error, Debug)]
48pub enum Error {
49 #[error("unexpected trb type: {0:?}")]
50 BadTrbType(TrbType),
51 #[error("failed to cancel transfer")]
52 CancelTransfer,
53 #[error("cannot cast trb: {0}")]
54 CastTrb(TrbError),
55 #[error("cannot create transfer buffer: {0}")]
56 CreateBuffer(BufferError),
57 #[error("cannot detach from port: {0}")]
58 DetachPort(HubError),
59 #[error("failed to halt the endpoint: {0}")]
60 HaltEndpoint(u8),
61 #[error("failed to read guest memory: {0}")]
62 ReadGuestMemory(GuestMemoryError),
63 #[error("cannot send interrupt: {0}")]
64 SendInterrupt(InterrupterError),
65 #[error("failed to submit transfer to backend")]
66 SubmitTransfer,
67 #[error("cannot get transfer length: {0}")]
68 TransferLength(TrbError),
69 #[error("cannot get trb type: {0}")]
70 TrbType(BitFieldError),
71 #[error("cannot write completion event: {0}")]
72 WriteCompletionEvent(SysError),
73 #[error("failed to write guest memory: {0}")]
74 WriteGuestMemory(GuestMemoryError),
75}
76
77type Result<T> = std::result::Result<T, Error>;
78
79#[derive(PartialEq, Eq, Clone, Copy, Debug)]
81pub enum TransferDirection {
82 In,
83 Out,
84 Control,
85}
86
87type CancelCallback = Box<dyn FnOnce() -> Result<()> + Send>;
88
89pub enum XhciTransferState {
92 Created,
93 Submitted {
96 cancel_callback: CancelCallback,
97 },
98 Cancelling,
99 Cancelled,
100 Completed,
101}
102
103impl XhciTransferState {
104 pub fn try_cancel(&mut self, force: bool) -> bool {
106 let mut cancelled = true;
107 match mem::replace(self, XhciTransferState::Created) {
108 XhciTransferState::Submitted { cancel_callback } => {
109 match cancel_callback() {
116 Ok(()) => {
117 *self = XhciTransferState::Cancelling;
118 }
119 Err(_e) => {
120 if force {
121 *self = XhciTransferState::Cancelling;
122 } else {
123 let error_callback = Box::new(move || Err(Error::CancelTransfer));
124 *self = XhciTransferState::Submitted {
125 cancel_callback: error_callback,
126 };
127 cancelled = false;
128 }
129 }
130 }
131 }
132 XhciTransferState::Cancelling => {
133 error!("Another cancellation is already issued.");
134 *self = XhciTransferState::Cancelling;
135 }
136 _ => {
137 *self = XhciTransferState::Cancelled;
138 }
139 }
140 cancelled
141 }
142}
143
144pub enum XhciTransferType {
146 Normal,
149 SetupStage,
152 DataStage,
153 StatusStage,
154 Isochronous,
156 Noop,
158}
159
160impl Display for XhciTransferType {
161 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
162 use self::XhciTransferType::*;
163
164 match self {
165 Normal => write!(f, "Normal"),
166 SetupStage => write!(f, "SetupStage"),
167 DataStage => write!(f, "DataStage"),
168 StatusStage => write!(f, "StatusStage"),
169 Isochronous => write!(f, "Isochronous"),
170 Noop => write!(f, "Noop"),
171 }
172 }
173}
174
175#[derive(Clone)]
178pub struct XhciTransferManager {
179 transfers: Arc<Mutex<VecDeque<Weak<Mutex<XhciTransferState>>>>>,
180 device_slot: Weak<DeviceSlot>,
181 stop_callback: Arc<Mutex<Vec<RingBufferStopCallback>>>,
182}
183
184impl XhciTransferManager {
185 pub fn new(device_slot: Weak<DeviceSlot>) -> XhciTransferManager {
187 XhciTransferManager {
188 transfers: Arc::new(Mutex::new(VecDeque::new())),
189 device_slot,
190 stop_callback: Arc::new(Mutex::new(Vec::new())),
191 }
192 }
193
194 pub fn create_transfer(
196 &self,
197 mem: GuestMemory,
198 port: Arc<UsbPort>,
199 interrupter: Arc<Mutex<Interrupter>>,
200 slot_id: u8,
201 endpoint_id: u8,
202 transfer_descriptor: TransferDescriptor,
203 completion_event: Event,
204 stream_id: Option<u16>,
205 ) -> XhciTransfer {
206 let transfer_dir = {
207 if endpoint_id == 1 {
208 TransferDirection::Control
209 } else if (endpoint_id % 2) == 0 {
210 TransferDirection::Out
211 } else {
212 TransferDirection::In
213 }
214 };
215 let t = XhciTransfer {
216 manager: self.clone(),
217 state: Arc::new(Mutex::new(XhciTransferState::Created)),
218 mem,
219 port,
220 interrupter,
221 transfer_completion_event: completion_event,
222 slot_id,
223 endpoint_id,
224 transfer_dir,
225 transfer_descriptor,
226 device_slot: self.device_slot.clone(),
227 stream_id,
228 };
229 self.transfers.lock().push_back(Arc::downgrade(&t.state));
230 t
231 }
232
233 pub fn cancel_all(&self, callback: RingBufferStopCallback) {
235 let locked_transfers = self.transfers.lock();
236 if !locked_transfers.is_empty() {
237 self.stop_callback.lock().push(callback);
238 }
239
240 let mut force_cancel = false;
241 locked_transfers.iter().for_each(|t| {
242 let state = match t.upgrade() {
243 Some(state) => state,
244 None => {
245 error!("transfer is already cancelled or finished");
246 return;
247 }
248 };
249 force_cancel |= state.lock().try_cancel(force_cancel);
250 });
251 }
252
253 fn remove_transfer(&self, t: &Arc<Mutex<XhciTransferState>>) {
254 let mut transfers = self.transfers.lock();
255 match transfers.iter().position(|wt| match wt.upgrade() {
256 Some(wt) => Arc::ptr_eq(&wt, t),
257 None => false,
258 }) {
259 None => error!("attempted to remove unknown transfer"),
260 Some(i) => {
261 transfers.remove(i);
262 }
263 }
264 if transfers.is_empty() {
265 self.stop_callback.lock().clear();
266 }
267 }
268}
269
270impl Default for XhciTransferManager {
271 fn default() -> Self {
272 Self::new(Weak::new())
273 }
274}
275
276pub struct XhciTransfer {
279 manager: XhciTransferManager,
280 state: Arc<Mutex<XhciTransferState>>,
281 mem: GuestMemory,
282 port: Arc<UsbPort>,
283 interrupter: Arc<Mutex<Interrupter>>,
284 slot_id: u8,
285 endpoint_id: u8,
287 transfer_dir: TransferDirection,
288 transfer_descriptor: TransferDescriptor,
289 transfer_completion_event: Event,
290 device_slot: Weak<DeviceSlot>,
291 stream_id: Option<u16>,
292}
293
294impl Drop for XhciTransfer {
295 fn drop(&mut self) {
296 self.manager.remove_transfer(&self.state);
297 }
298}
299
300impl fmt::Debug for XhciTransfer {
301 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
302 write!(
303 f,
304 "xhci_transfer slot id: {}, endpoint id {}, transfer_dir {:?}, transfer_descriptor {:?}",
305 self.slot_id, self.endpoint_id, self.transfer_dir, self.transfer_descriptor
306 )
307 }
308}
309
310#[derive(Debug, PartialEq, Clone, Copy)]
311enum TransferAction {
312 HaltEndpoint,
313 SendEvent {
314 code: TrbCompletionCode,
315 gpa: u64,
316 residual_or_edtla: u32,
317 event_data: bool,
318 },
319}
320
321impl XhciTransfer {
322 pub fn state(&self) -> &Arc<Mutex<XhciTransferState>> {
324 &self.state
325 }
326
327 pub fn get_transfer_type(&self) -> Result<XhciTransferType> {
329 match self
332 .transfer_descriptor
333 .first_atrb()
334 .trb
335 .get_trb_type()
336 .map_err(Error::TrbType)?
337 {
338 TrbType::Normal => Ok(XhciTransferType::Normal),
339 TrbType::SetupStage => Ok(XhciTransferType::SetupStage),
340 TrbType::DataStage => Ok(XhciTransferType::DataStage),
341 TrbType::StatusStage => Ok(XhciTransferType::StatusStage),
342 TrbType::Isoch => Ok(XhciTransferType::Isochronous),
343 TrbType::Noop => Ok(XhciTransferType::Noop),
344 t => Err(Error::BadTrbType(t)),
345 }
346 }
347
348 pub fn create_buffer(&self) -> Result<ScatterGatherBuffer> {
350 ScatterGatherBuffer::new(self.mem.clone(), self.transfer_descriptor.clone())
351 .map_err(Error::CreateBuffer)
352 }
353
354 pub fn create_usb_request_setup(&self) -> Result<UsbRequestSetup> {
356 let first_atrb = self.transfer_descriptor.first_atrb();
357 let trb = first_atrb
358 .trb
359 .checked_cast::<SetupStageTrb>()
360 .map_err(Error::CastTrb)?;
361 Ok(UsbRequestSetup::new(
362 trb.get_request_type(),
363 trb.get_request(),
364 trb.get_value(),
365 trb.get_index(),
366 trb.get_length(),
367 ))
368 }
369
370 pub fn get_endpoint_number(&self) -> u8 {
372 self.endpoint_id / 2
374 }
375
376 pub fn get_transfer_dir(&self) -> TransferDirection {
378 self.transfer_dir
379 }
380
381 pub fn get_stream_id(&self) -> Option<u16> {
383 self.stream_id
384 }
385
386 fn process_td_results(
387 &self,
388 status: &TransferStatus,
389 bytes_transferred: u32,
390 ) -> Result<Vec<TransferAction>> {
391 let mut actions = Vec::new();
392 if *status == TransferStatus::Stalled {
393 warn!("xhci: endpoint is stalled. set state to Halted");
394 actions.push(TransferAction::HaltEndpoint);
395 }
396
397 let mut edtla: u32 = 0;
398 let mut remaining_transferred = bytes_transferred;
399 let mut retiring_on_short: bool = false;
400 let mut residual_on_short: u32 = 0;
401 let last_atrb_gpa = self.transfer_descriptor.last_atrb().gpa;
402
403 for atrb in &self.transfer_descriptor {
410 if atrb.trb.get_trb_type().map_err(Error::TrbType)? == TrbType::EventData {
412 let code = if retiring_on_short {
413 TrbCompletionCode::ShortPacket
414 } else {
415 TrbCompletionCode::Success
416 };
417 actions.push(TransferAction::SendEvent {
418 code,
419 gpa: atrb
420 .trb
421 .cast::<EventDataTrb>()
422 .map_err(Error::CastTrb)?
423 .get_event_data(),
424 residual_or_edtla: edtla,
425 event_data: true,
426 });
427 edtla = 0;
428 self.report_completion(atrb);
429 continue;
430 }
431
432 let length = atrb.trb.transfer_length().map_err(Error::TransferLength)?;
433 let transferred = min(length, remaining_transferred);
434 remaining_transferred -= transferred;
435
436 let residual = length - transferred;
437 edtla += transferred;
438
439 if *status == TransferStatus::Stalled && (residual > 0 || atrb.gpa == last_atrb_gpa) {
443 debug!("xhci: on transfer complete stalled");
444 actions.push(TransferAction::SendEvent {
445 code: TrbCompletionCode::StallError,
446 gpa: atrb.gpa,
447 residual_or_edtla: residual,
448 event_data: false,
449 });
450 break;
451 }
452
453 if retiring_on_short {
457 if atrb.trb.interrupt_on_completion() {
458 actions.push(TransferAction::SendEvent {
459 code: TrbCompletionCode::ShortPacket,
460 gpa: atrb.gpa,
461 residual_or_edtla: residual_on_short,
462 event_data: false,
463 });
464 }
465 } else if residual > 0 {
466 retiring_on_short = true;
467 residual_on_short = residual;
468 if atrb.trb.interrupt_on_completion() || atrb.trb.interrupt_on_short_packet() {
469 debug!("xhci: on transfer complete short packet");
470 actions.push(TransferAction::SendEvent {
471 code: TrbCompletionCode::ShortPacket,
472 gpa: atrb.gpa,
473 residual_or_edtla: residual,
474 event_data: false,
475 });
476 }
477 } else if atrb.trb.interrupt_on_completion() {
478 debug!("xhci: on transfer complete success");
479 actions.push(TransferAction::SendEvent {
480 code: TrbCompletionCode::Success,
481 gpa: atrb.gpa,
482 residual_or_edtla: 0,
483 event_data: false,
484 });
485 }
486
487 self.report_completion(atrb);
489 }
490 Ok(actions)
491 }
492
493 fn report_completion(&self, trb: &AddressedTrb) {
494 if let Some(device_slot) = self.device_slot.upgrade() {
495 device_slot.report_trb_completion(self.endpoint_id, self.stream_id, trb);
496 }
497 }
498
499 pub fn on_transfer_complete(
501 &self,
502 status: &TransferStatus,
503 bytes_transferred: u32,
504 ) -> Result<()> {
505 match status {
506 TransferStatus::NoDevice => {
507 info!("xhci: device disconnected, detaching from port");
508 return self
510 .transfer_completion_event
511 .signal()
512 .map_err(Error::WriteCompletionEvent);
513 }
514 TransferStatus::Cancelled => {
515 return self
516 .transfer_completion_event
517 .signal()
518 .map_err(Error::WriteCompletionEvent);
519 }
520 TransferStatus::Completed => {}
521 TransferStatus::Stalled => {
522 }
526 TransferStatus::Error => {
527 }
531 }
532
533 let mut halted = false;
534 let actions = self.process_td_results(status, bytes_transferred)?;
535 for action in actions {
536 match action {
537 TransferAction::SendEvent {
538 code,
539 gpa,
540 residual_or_edtla,
541 event_data,
542 } => {
543 self.interrupter
544 .lock()
545 .send_transfer_event_trb(
546 code,
547 gpa,
548 residual_or_edtla,
549 event_data,
550 self.slot_id,
551 self.endpoint_id,
552 )
553 .map_err(Error::SendInterrupt)?;
554 }
555 TransferAction::HaltEndpoint => {
556 if let Some(device_slot) = self.device_slot.upgrade() {
557 device_slot
558 .halt_endpoint(self.endpoint_id)
559 .map_err(|_| Error::HaltEndpoint(self.endpoint_id))?;
560 halted = true;
561 }
562 }
563 }
564 }
565
566 if !halted {
570 self.transfer_completion_event
571 .signal()
572 .map_err(Error::WriteCompletionEvent)
573 } else {
574 Ok(())
575 }
576 }
577
578 pub fn send_to_backend_if_valid(self) -> Result<()> {
580 if self.validate_transfer()? {
581 let port = self.port.clone();
583 let mut backend = port.backend_device();
584 match &mut *backend {
585 Some(backend) => backend
586 .lock()
587 .submit_xhci_transfer(self)
588 .map_err(|_| Error::SubmitTransfer)?,
589 None => {
590 error!("backend is already disconnected");
591 self.transfer_completion_event
592 .signal()
593 .map_err(Error::WriteCompletionEvent)?;
594 }
595 }
596 } else {
597 error!("invalid td on transfer ring");
598 self.transfer_completion_event
599 .signal()
600 .map_err(Error::WriteCompletionEvent)?;
601 }
602 Ok(())
603 }
604
605 fn validate_transfer(&self) -> Result<bool> {
608 let mut valid = true;
609 for atrb in &self.transfer_descriptor {
610 if !trb_is_valid(atrb) {
611 self.interrupter
612 .lock()
613 .send_transfer_event_trb(
614 TrbCompletionCode::TrbError,
615 atrb.gpa,
616 0,
617 false,
618 self.slot_id,
619 self.endpoint_id,
620 )
621 .map_err(Error::SendInterrupt)?;
622 valid = false;
623 }
624 }
625 Ok(valid)
626 }
627}
628
629fn trb_is_valid(atrb: &AddressedTrb) -> bool {
630 let can_be_in_transfer_ring = match atrb.trb.can_be_in_transfer_ring() {
631 Ok(v) => v,
632 Err(e) => {
633 error!("unknown error {:?}", e);
634 return false;
635 }
636 };
637 can_be_in_transfer_ring && (atrb.trb.interrupter_target() < MAX_INTERRUPTER)
638}
639
640#[cfg(test)]
641mod tests {
642 use base::pagesize;
643 use vm_memory::GuestAddress;
644
645 use super::*;
646 use crate::usb::xhci::xhci_abi::NormalTrb;
647 use crate::usb::xhci::xhci_abi::StatusStageTrb;
648 use crate::usb::xhci::xhci_abi::Trb;
649 use crate::usb::xhci::xhci_backend_device::BackendType;
650 use crate::usb::xhci::XhciRegs;
651
652 fn create_test_transfer(trbs: Vec<Trb>) -> XhciTransfer {
653 let mem = GuestMemory::new(&[(GuestAddress(0), pagesize() as u64)]).unwrap();
654 let mut gpa = 0x100;
655 let mut atrbs = Vec::new();
656 for trb in trbs {
657 mem.write_obj_at_addr(trb, GuestAddress(gpa)).unwrap();
658 atrbs.push(AddressedTrb { trb, gpa });
659 gpa += 16;
660 }
661
662 let td = TransferDescriptor::new(atrbs).unwrap();
663 let manager = XhciTransferManager::new(Weak::new());
664
665 let test_reg32 = register!(
666 name: "test",
667 ty: u32,
668 offset: 0x0,
669 reset_value: 0,
670 guest_writeable_mask: 0x0,
671 guest_write_1_to_clear_mask: 0,
672 );
673 let test_reg64 = register!(
674 name: "test",
675 ty: u64,
676 offset: 0x0,
677 reset_value: 0,
678 guest_writeable_mask: 0x0,
679 guest_write_1_to_clear_mask: 0,
680 );
681 let xhci_regs = XhciRegs {
682 usbcmd: test_reg32.clone(),
683 usbsts: test_reg32.clone(),
684 dnctrl: test_reg32.clone(),
685 crcr: test_reg64.clone(),
686 dcbaap: test_reg64.clone(),
687 config: test_reg64.clone(),
688 portsc: vec![test_reg32.clone(); 16],
689 doorbells: Vec::new(),
690 iman: test_reg32.clone(),
691 imod: test_reg32.clone(),
692 erstsz: test_reg32.clone(),
693 erstba: test_reg64.clone(),
694 erdp: test_reg64.clone(),
695 };
696
697 XhciTransfer {
698 manager,
699 state: Arc::new(Mutex::new(XhciTransferState::Created)),
700 mem,
701 port: Arc::new(UsbPort::new(
702 BackendType::Usb2,
703 1,
704 test_reg32.clone(),
705 test_reg32.clone(),
706 Arc::new(Mutex::new(Interrupter::new(
707 GuestMemory::new(&[]).unwrap(),
708 Event::new().unwrap(),
709 &xhci_regs,
710 ))),
711 )),
712 interrupter: Arc::new(Mutex::new(Interrupter::new(
713 GuestMemory::new(&[]).unwrap(),
714 Event::new().unwrap(),
715 &xhci_regs,
716 ))),
717 transfer_completion_event: Event::new().unwrap(),
718 slot_id: 1,
719 endpoint_id: 2,
720 transfer_dir: TransferDirection::Out,
721 transfer_descriptor: td,
722 device_slot: Weak::new(),
723 stream_id: None,
724 }
725 }
726
727 #[test]
728 fn test_bulk_success() {
729 let mut trb = Trb::new();
730 let normal_trb = trb.cast_mut::<NormalTrb>().unwrap();
731 normal_trb.set_trb_type(TrbType::Normal);
732 normal_trb.set_trb_transfer_length(100);
733 normal_trb.set_interrupt_on_completion(1);
734 let transfer = create_test_transfer(vec![trb]);
735
736 let actions = transfer
737 .process_td_results(&TransferStatus::Completed, 100)
738 .unwrap();
739 assert_eq!(
740 actions,
741 vec![TransferAction::SendEvent {
742 code: TrbCompletionCode::Success,
743 gpa: 0x100,
744 residual_or_edtla: 0,
745 event_data: false,
746 }]
747 );
748 }
749
750 #[test]
751 fn test_bulk_short_with_isp() {
752 let mut trb = Trb::new();
755 let normal_trb = trb.cast_mut::<NormalTrb>().unwrap();
756 normal_trb.set_trb_type(TrbType::Normal);
757 normal_trb.set_trb_transfer_length(100);
758 normal_trb.set_interrupt_on_short_packet(1);
759 let transfer = create_test_transfer(vec![trb]);
760
761 let actions = transfer
762 .process_td_results(&TransferStatus::Completed, 40)
763 .unwrap();
764 assert_eq!(
765 actions,
766 vec![TransferAction::SendEvent {
767 code: TrbCompletionCode::ShortPacket,
768 gpa: 0x100,
769 residual_or_edtla: 60,
770 event_data: false,
771 }]
772 );
773 }
774
775 #[test]
776 fn test_bulk_short_with_ioc() {
777 let mut trb = Trb::new();
780 let normal_trb = trb.cast_mut::<NormalTrb>().unwrap();
781 normal_trb.set_trb_type(TrbType::Normal);
782 normal_trb.set_trb_transfer_length(100);
783 normal_trb.set_interrupt_on_completion(1);
784 let transfer = create_test_transfer(vec![trb]);
785
786 let actions = transfer
787 .process_td_results(&TransferStatus::Completed, 40)
788 .unwrap();
789 assert_eq!(
790 actions,
791 vec![TransferAction::SendEvent {
792 code: TrbCompletionCode::ShortPacket,
793 gpa: 0x100,
794 residual_or_edtla: 60,
795 event_data: false,
796 }]
797 );
798 }
799
800 #[test]
801 fn test_bulk_without_evendata_retiring_after_short() {
802 let mut trb1 = Trb::new();
806 let normal_trb1 = trb1.cast_mut::<NormalTrb>().unwrap();
807 normal_trb1.set_trb_type(TrbType::Normal);
808 normal_trb1.set_trb_transfer_length(100);
809 normal_trb1.set_interrupt_on_short_packet(1);
810
811 let mut trb2 = Trb::new();
812 let normal_trb2 = trb2.cast_mut::<NormalTrb>().unwrap();
813 normal_trb2.set_trb_type(TrbType::Normal);
814 normal_trb2.set_trb_transfer_length(100);
815 normal_trb2.set_interrupt_on_completion(1);
816
817 let mut trb3 = Trb::new();
818 let normal_trb3 = trb3.cast_mut::<NormalTrb>().unwrap();
819 normal_trb3.set_trb_type(TrbType::Normal);
820 normal_trb3.set_trb_transfer_length(100);
821 normal_trb3.set_interrupt_on_completion(1);
822
823 let transfer = create_test_transfer(vec![trb1, trb2, trb3]);
824
825 let actions = transfer
826 .process_td_results(&TransferStatus::Completed, 40)
827 .unwrap();
828 assert_eq!(
829 actions,
830 vec![
831 TransferAction::SendEvent {
832 code: TrbCompletionCode::ShortPacket,
833 gpa: 0x100,
834 residual_or_edtla: 60,
835 event_data: false,
836 },
837 TransferAction::SendEvent {
838 code: TrbCompletionCode::ShortPacket,
839 gpa: 0x110,
840 residual_or_edtla: 60,
841 event_data: false,
842 },
843 TransferAction::SendEvent {
844 code: TrbCompletionCode::ShortPacket,
845 gpa: 0x120,
846 residual_or_edtla: 60,
847 event_data: false,
848 },
849 ]
850 );
851 }
852
853 #[test]
854 fn test_bulk_with_evendata_retiring_after_short() {
855 let mut trb1 = Trb::new();
860 let normal_trb1 = trb1.cast_mut::<NormalTrb>().unwrap();
861 normal_trb1.set_trb_type(TrbType::Normal);
862 normal_trb1.set_trb_transfer_length(100);
863 normal_trb1.set_interrupt_on_short_packet(1);
864
865 let mut trb2 = Trb::new();
866 let event_trb = trb2.cast_mut::<EventDataTrb>().unwrap();
867 event_trb.set_trb_type(TrbType::EventData);
868 event_trb.set_event_data(0x12345678abcdef0);
869 event_trb.set_interrupt_on_completion(1);
870
871 let mut trb3 = Trb::new();
872 let event_trb = trb3.cast_mut::<EventDataTrb>().unwrap();
873 event_trb.set_trb_type(TrbType::EventData);
874 event_trb.set_event_data(0x12345678abcdef1);
875 event_trb.set_interrupt_on_completion(1);
876
877 let transfer = create_test_transfer(vec![trb1, trb2, trb3]);
878
879 let actions = transfer
880 .process_td_results(&TransferStatus::Completed, 40)
881 .unwrap();
882 assert_eq!(
883 actions,
884 vec![
885 TransferAction::SendEvent {
886 code: TrbCompletionCode::ShortPacket,
887 gpa: 0x100,
888 residual_or_edtla: 60,
889 event_data: false,
890 },
891 TransferAction::SendEvent {
892 code: TrbCompletionCode::ShortPacket,
893 gpa: 0x12345678abcdef0,
894 residual_or_edtla: 40, event_data: true,
896 },
897 TransferAction::SendEvent {
898 code: TrbCompletionCode::ShortPacket,
899 gpa: 0x12345678abcdef1,
900 residual_or_edtla: 0, event_data: true,
902 },
903 ]
904 );
905 }
906
907 #[test]
908 fn test_bulk_stall_partial() {
909 let mut trb = Trb::new();
913 let normal_trb = trb.cast_mut::<NormalTrb>().unwrap();
914 normal_trb.set_trb_type(TrbType::Normal);
915 normal_trb.set_trb_transfer_length(100);
916 let transfer = create_test_transfer(vec![trb]);
917
918 let actions = transfer
920 .process_td_results(&TransferStatus::Stalled, 40)
921 .unwrap();
922 assert_eq!(
923 actions,
924 vec![
925 TransferAction::HaltEndpoint,
926 TransferAction::SendEvent {
927 code: TrbCompletionCode::StallError,
928 gpa: 0x100,
929 residual_or_edtla: 60,
930 event_data: false,
931 }
932 ]
933 );
934 }
935
936 #[test]
937 fn test_control_stall_no_data_stage() {
938 let mut trb = Trb::new();
939 let status_trb = trb.cast_mut::<StatusStageTrb>().unwrap();
940 status_trb.set_trb_type(TrbType::StatusStage);
941 status_trb.set_interrupt_on_completion(1);
942
943 let transfer = create_test_transfer(vec![trb]);
944
945 let actions = transfer
947 .process_td_results(&TransferStatus::Stalled, 0)
948 .unwrap();
949
950 assert_eq!(
951 actions,
952 vec![
953 TransferAction::HaltEndpoint,
954 TransferAction::SendEvent {
955 code: TrbCompletionCode::StallError,
956 gpa: 0x100,
957 residual_or_edtla: 0,
958 event_data: false,
959 }
960 ]
961 );
962 }
963
964 #[test]
965 fn test_bulk_stall_at_trb_start() {
966 let mut trb1 = Trb::new();
969 let normal_trb1 = trb1.cast_mut::<NormalTrb>().unwrap();
970 normal_trb1.set_trb_type(TrbType::Normal);
971 normal_trb1.set_trb_transfer_length(100);
972
973 let mut trb2 = Trb::new();
974 let normal_trb2 = trb2.cast_mut::<NormalTrb>().unwrap();
975 normal_trb2.set_trb_type(TrbType::Normal);
976 normal_trb2.set_trb_transfer_length(100);
977
978 let transfer = create_test_transfer(vec![trb1, trb2]);
979
980 let actions = transfer
982 .process_td_results(&TransferStatus::Stalled, 100)
983 .unwrap();
984
985 assert_eq!(
986 actions,
987 vec![
988 TransferAction::HaltEndpoint,
989 TransferAction::SendEvent {
990 code: TrbCompletionCode::StallError,
991 gpa: 0x110, residual_or_edtla: 100,
993 event_data: false,
994 }
995 ]
996 );
997 }
998
999 #[test]
1000 fn test_event_data_single() {
1001 let mut trb1 = Trb::new();
1004 let normal_trb = trb1.cast_mut::<NormalTrb>().unwrap();
1005 normal_trb.set_trb_type(TrbType::Normal);
1006 normal_trb.set_trb_transfer_length(100);
1007
1008 let mut trb2 = Trb::new();
1009 let event_trb = trb2.cast_mut::<EventDataTrb>().unwrap();
1010 event_trb.set_trb_type(TrbType::EventData);
1011 event_trb.set_event_data(0x12345678abcdef0);
1012 event_trb.set_interrupt_on_completion(1);
1013
1014 let transfer = create_test_transfer(vec![trb1, trb2]);
1015
1016 let actions = transfer
1018 .process_td_results(&TransferStatus::Completed, 100)
1019 .unwrap();
1020 assert_eq!(
1021 actions,
1022 vec![TransferAction::SendEvent {
1023 code: TrbCompletionCode::Success,
1024 gpa: 0x12345678abcdef0,
1025 residual_or_edtla: 100,
1026 event_data: true,
1027 }]
1028 );
1029
1030 let actions = transfer
1032 .process_td_results(&TransferStatus::Completed, 40)
1033 .unwrap();
1034 assert_eq!(
1035 actions,
1036 vec![TransferAction::SendEvent {
1037 code: TrbCompletionCode::ShortPacket,
1038 gpa: 0x12345678abcdef0,
1039 residual_or_edtla: 40,
1040 event_data: true,
1041 }]
1042 );
1043 }
1044
1045 #[test]
1046 fn test_event_data_multiple() {
1047 let mut trb1 = Trb::new();
1050 let normal_trb = trb1.cast_mut::<NormalTrb>().unwrap();
1051 normal_trb.set_trb_type(TrbType::Normal);
1052 normal_trb.set_trb_transfer_length(100);
1053 normal_trb.set_interrupt_on_short_packet(1);
1054
1055 let mut trb2 = Trb::new();
1056 let event_trb = trb2.cast_mut::<EventDataTrb>().unwrap();
1057 event_trb.set_trb_type(TrbType::EventData);
1058 event_trb.set_event_data(0x12345678abcdef0);
1059 event_trb.set_interrupt_on_completion(1);
1060
1061 let transfer = create_test_transfer(vec![trb1, trb2, trb1, trb2]);
1062
1063 let actions = transfer
1065 .process_td_results(&TransferStatus::Completed, 200)
1066 .unwrap();
1067 assert_eq!(
1068 actions,
1069 vec![
1070 TransferAction::SendEvent {
1071 code: TrbCompletionCode::Success,
1072 gpa: 0x12345678abcdef0,
1073 residual_or_edtla: 100, event_data: true,
1075 },
1076 TransferAction::SendEvent {
1077 code: TrbCompletionCode::Success,
1078 gpa: 0x12345678abcdef0,
1079 residual_or_edtla: 100, event_data: true,
1081 },
1082 ]
1083 );
1084
1085 let actions = transfer
1089 .process_td_results(&TransferStatus::Completed, 40)
1090 .unwrap();
1091 assert_eq!(
1092 actions,
1093 vec![
1094 TransferAction::SendEvent {
1095 code: TrbCompletionCode::ShortPacket,
1096 gpa: 0x100,
1097 residual_or_edtla: 60, event_data: false,
1099 },
1100 TransferAction::SendEvent {
1101 code: TrbCompletionCode::ShortPacket,
1102 gpa: 0x12345678abcdef0,
1103 residual_or_edtla: 40, event_data: true,
1105 },
1106 TransferAction::SendEvent {
1107 code: TrbCompletionCode::ShortPacket,
1108 gpa: 0x12345678abcdef0,
1109 residual_or_edtla: 0, event_data: true,
1111 },
1112 ]
1113 );
1114 }
1115}