1use 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#[derive(PartialEq, Eq, Clone, Copy, Debug)]
77pub enum TransferDirection {
78 In,
79 Out,
80 Control,
81}
82
83pub enum XhciTransferState {
85 Created,
86 Submitted {
89 cancel_callback: Box<dyn FnOnce() + Send>,
90 },
91 Cancelling,
92 Cancelled,
93 Completed,
94}
95
96impl XhciTransferState {
97 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
114pub enum XhciTransferType {
116 Normal,
119 SetupStage,
122 DataStage,
123 StatusStage,
124 Isochronous,
126 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#[derive(Clone)]
148pub struct XhciTransferManager {
149 transfers: Arc<Mutex<Vec<Weak<Mutex<XhciTransferState>>>>>,
150 device_slot: Weak<DeviceSlot>,
151}
152
153impl XhciTransferManager {
154 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 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 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
235pub 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 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
269#[derive(Debug, PartialEq, Clone, Copy)]
270enum TransferAction {
271 HaltEndpoint,
272 SendEvent {
273 code: TrbCompletionCode,
274 gpa: u64,
275 residual_or_edtla: u32,
276 event_data: bool,
277 },
278}
279
280impl XhciTransfer {
281 pub fn state(&self) -> &Arc<Mutex<XhciTransferState>> {
283 &self.state
284 }
285
286 pub fn get_transfer_type(&self) -> Result<XhciTransferType> {
288 match self
291 .transfer_descriptor
292 .first_atrb()
293 .trb
294 .get_trb_type()
295 .map_err(Error::TrbType)?
296 {
297 TrbType::Normal => Ok(XhciTransferType::Normal),
298 TrbType::SetupStage => Ok(XhciTransferType::SetupStage),
299 TrbType::DataStage => Ok(XhciTransferType::DataStage),
300 TrbType::StatusStage => Ok(XhciTransferType::StatusStage),
301 TrbType::Isoch => Ok(XhciTransferType::Isochronous),
302 TrbType::Noop => Ok(XhciTransferType::Noop),
303 t => Err(Error::BadTrbType(t)),
304 }
305 }
306
307 pub fn create_buffer(&self) -> Result<ScatterGatherBuffer> {
309 ScatterGatherBuffer::new(self.mem.clone(), self.transfer_descriptor.clone())
310 .map_err(Error::CreateBuffer)
311 }
312
313 pub fn create_usb_request_setup(&self) -> Result<UsbRequestSetup> {
315 let first_atrb = self.transfer_descriptor.first_atrb();
316 let trb = first_atrb
317 .trb
318 .checked_cast::<SetupStageTrb>()
319 .map_err(Error::CastTrb)?;
320 Ok(UsbRequestSetup::new(
321 trb.get_request_type(),
322 trb.get_request(),
323 trb.get_value(),
324 trb.get_index(),
325 trb.get_length(),
326 ))
327 }
328
329 pub fn get_endpoint_number(&self) -> u8 {
331 self.endpoint_id / 2
333 }
334
335 pub fn get_transfer_dir(&self) -> TransferDirection {
337 self.transfer_dir
338 }
339
340 pub fn get_stream_id(&self) -> Option<u16> {
342 self.stream_id
343 }
344
345 fn process_td_results(
346 &self,
347 status: &TransferStatus,
348 bytes_transferred: u32,
349 ) -> Result<Vec<TransferAction>> {
350 let mut actions = Vec::new();
351 if *status == TransferStatus::Stalled {
352 warn!("xhci: endpoint is stalled. set state to Halted");
353 actions.push(TransferAction::HaltEndpoint);
354 }
355
356 let mut edtla: u32 = 0;
357 let mut remaining_transferred = bytes_transferred;
358 let mut retiring_on_short: bool = false;
359 let mut residual_on_short: u32 = 0;
360 let last_atrb_gpa = self.transfer_descriptor.last_atrb().gpa;
361
362 for atrb in &self.transfer_descriptor {
369 if atrb.trb.get_trb_type().map_err(Error::TrbType)? == TrbType::EventData {
371 let code = if retiring_on_short {
372 TrbCompletionCode::ShortPacket
373 } else {
374 TrbCompletionCode::Success
375 };
376 actions.push(TransferAction::SendEvent {
377 code,
378 gpa: atrb
379 .trb
380 .cast::<EventDataTrb>()
381 .map_err(Error::CastTrb)?
382 .get_event_data(),
383 residual_or_edtla: edtla,
384 event_data: true,
385 });
386 edtla = 0;
387 continue;
388 }
389
390 let length = atrb.trb.transfer_length().map_err(Error::TransferLength)?;
391 let transferred = min(length, remaining_transferred);
392 remaining_transferred -= transferred;
393
394 let residual = length - transferred;
395 edtla += transferred;
396
397 if *status == TransferStatus::Stalled && (residual > 0 || atrb.gpa == last_atrb_gpa) {
401 debug!("xhci: on transfer complete stalled");
402 actions.push(TransferAction::SendEvent {
403 code: TrbCompletionCode::StallError,
404 gpa: atrb.gpa,
405 residual_or_edtla: residual,
406 event_data: false,
407 });
408 break;
409 }
410
411 if retiring_on_short {
415 if atrb.trb.interrupt_on_completion() {
416 actions.push(TransferAction::SendEvent {
417 code: TrbCompletionCode::ShortPacket,
418 gpa: atrb.gpa,
419 residual_or_edtla: residual_on_short,
420 event_data: false,
421 });
422 }
423 } else if residual > 0 {
424 retiring_on_short = true;
425 residual_on_short = residual;
426 if atrb.trb.interrupt_on_completion() || atrb.trb.interrupt_on_short_packet() {
427 debug!("xhci: on transfer complete short packet");
428 actions.push(TransferAction::SendEvent {
429 code: TrbCompletionCode::ShortPacket,
430 gpa: atrb.gpa,
431 residual_or_edtla: residual,
432 event_data: false,
433 });
434 }
435 } else if atrb.trb.interrupt_on_completion() {
436 debug!("xhci: on transfer complete success");
437 actions.push(TransferAction::SendEvent {
438 code: TrbCompletionCode::Success,
439 gpa: atrb.gpa,
440 residual_or_edtla: 0,
441 event_data: false,
442 });
443 }
444 }
445 Ok(actions)
446 }
447
448 pub fn on_transfer_complete(
450 &self,
451 status: &TransferStatus,
452 bytes_transferred: u32,
453 ) -> Result<()> {
454 match status {
455 TransferStatus::NoDevice => {
456 info!("xhci: device disconnected, detaching from port");
457 return match self.port.detach() {
460 Ok(()) => Ok(()),
461 Err(HubError::AlreadyDetached(_e)) => Ok(()),
464 Err(e) => Err(Error::DetachPort(e)),
465 };
466 }
467 TransferStatus::Cancelled => {
468 return self
471 .transfer_completion_event
472 .signal()
473 .map_err(Error::WriteCompletionEvent);
474 }
475 TransferStatus::Completed | TransferStatus::Stalled => {
476 self.transfer_completion_event
477 .signal()
478 .map_err(Error::WriteCompletionEvent)?;
479 }
480 _ => {
481 self.transfer_completion_event
485 .signal()
486 .map_err(Error::WriteCompletionEvent)?;
487 }
488 }
489
490 let actions = self.process_td_results(status, bytes_transferred)?;
491 for action in actions {
492 match action {
493 TransferAction::SendEvent {
494 code,
495 gpa,
496 residual_or_edtla,
497 event_data,
498 } => {
499 self.interrupter
500 .lock()
501 .send_transfer_event_trb(
502 code,
503 gpa,
504 residual_or_edtla,
505 event_data,
506 self.slot_id,
507 self.endpoint_id,
508 )
509 .map_err(Error::SendInterrupt)?;
510 }
511 TransferAction::HaltEndpoint => {
512 if let Some(device_slot) = self.device_slot.upgrade() {
513 device_slot
514 .halt_endpoint(self.endpoint_id)
515 .map_err(|_| Error::HaltEndpoint(self.endpoint_id))?;
516 }
517 }
518 }
519 }
520 Ok(())
521 }
522
523 pub fn send_to_backend_if_valid(self) -> Result<()> {
525 if self.validate_transfer()? {
526 let port = self.port.clone();
528 let mut backend = port.backend_device();
529 match &mut *backend {
530 Some(backend) => backend
531 .lock()
532 .submit_xhci_transfer(self)
533 .map_err(|_| Error::SubmitTransfer)?,
534 None => {
535 error!("backend is already disconnected");
536 self.transfer_completion_event
537 .signal()
538 .map_err(Error::WriteCompletionEvent)?;
539 }
540 }
541 } else {
542 error!("invalid td on transfer ring");
543 self.transfer_completion_event
544 .signal()
545 .map_err(Error::WriteCompletionEvent)?;
546 }
547 Ok(())
548 }
549
550 fn validate_transfer(&self) -> Result<bool> {
553 let mut valid = true;
554 for atrb in &self.transfer_descriptor {
555 if !trb_is_valid(atrb) {
556 self.interrupter
557 .lock()
558 .send_transfer_event_trb(
559 TrbCompletionCode::TrbError,
560 atrb.gpa,
561 0,
562 false,
563 self.slot_id,
564 self.endpoint_id,
565 )
566 .map_err(Error::SendInterrupt)?;
567 valid = false;
568 }
569 }
570 Ok(valid)
571 }
572}
573
574fn trb_is_valid(atrb: &AddressedTrb) -> bool {
575 let can_be_in_transfer_ring = match atrb.trb.can_be_in_transfer_ring() {
576 Ok(v) => v,
577 Err(e) => {
578 error!("unknown error {:?}", e);
579 return false;
580 }
581 };
582 can_be_in_transfer_ring && (atrb.trb.interrupter_target() < MAX_INTERRUPTER)
583}
584
585#[cfg(test)]
586mod tests {
587 use base::pagesize;
588 use vm_memory::GuestAddress;
589
590 use super::*;
591 use crate::usb::xhci::xhci_abi::NormalTrb;
592 use crate::usb::xhci::xhci_abi::StatusStageTrb;
593 use crate::usb::xhci::xhci_abi::Trb;
594 use crate::usb::xhci::xhci_backend_device::BackendType;
595 use crate::usb::xhci::XhciRegs;
596
597 fn create_test_transfer(trbs: Vec<Trb>) -> XhciTransfer {
598 let mem = GuestMemory::new(&[(GuestAddress(0), pagesize() as u64)]).unwrap();
599 let mut gpa = 0x100;
600 let mut atrbs = Vec::new();
601 for trb in trbs {
602 mem.write_obj_at_addr(trb, GuestAddress(gpa)).unwrap();
603 atrbs.push(AddressedTrb { trb, gpa });
604 gpa += 16;
605 }
606
607 let td = TransferDescriptor::new(atrbs).unwrap();
608 let manager = XhciTransferManager::new(Weak::new());
609
610 let test_reg32 = register!(
611 name: "test",
612 ty: u32,
613 offset: 0x0,
614 reset_value: 0,
615 guest_writeable_mask: 0x0,
616 guest_write_1_to_clear_mask: 0,
617 );
618 let test_reg64 = register!(
619 name: "test",
620 ty: u64,
621 offset: 0x0,
622 reset_value: 0,
623 guest_writeable_mask: 0x0,
624 guest_write_1_to_clear_mask: 0,
625 );
626 let xhci_regs = XhciRegs {
627 usbcmd: test_reg32.clone(),
628 usbsts: test_reg32.clone(),
629 dnctrl: test_reg32.clone(),
630 crcr: test_reg64.clone(),
631 dcbaap: test_reg64.clone(),
632 config: test_reg64.clone(),
633 portsc: vec![test_reg32.clone(); 16],
634 doorbells: Vec::new(),
635 iman: test_reg32.clone(),
636 imod: test_reg32.clone(),
637 erstsz: test_reg32.clone(),
638 erstba: test_reg64.clone(),
639 erdp: test_reg64.clone(),
640 };
641
642 XhciTransfer {
643 manager,
644 state: Arc::new(Mutex::new(XhciTransferState::Created)),
645 mem,
646 port: Arc::new(UsbPort::new(
647 BackendType::Usb2,
648 1,
649 test_reg32.clone(),
650 test_reg32.clone(),
651 Arc::new(Mutex::new(Interrupter::new(
652 GuestMemory::new(&[]).unwrap(),
653 Event::new().unwrap(),
654 &xhci_regs,
655 ))),
656 )),
657 interrupter: Arc::new(Mutex::new(Interrupter::new(
658 GuestMemory::new(&[]).unwrap(),
659 Event::new().unwrap(),
660 &xhci_regs,
661 ))),
662 transfer_completion_event: Event::new().unwrap(),
663 slot_id: 1,
664 endpoint_id: 2,
665 transfer_dir: TransferDirection::Out,
666 transfer_descriptor: td,
667 device_slot: Weak::new(),
668 stream_id: None,
669 }
670 }
671
672 #[test]
673 fn test_bulk_success() {
674 let mut trb = Trb::new();
675 let normal_trb = trb.cast_mut::<NormalTrb>().unwrap();
676 normal_trb.set_trb_type(TrbType::Normal);
677 normal_trb.set_trb_transfer_length(100);
678 normal_trb.set_interrupt_on_completion(1);
679 let transfer = create_test_transfer(vec![trb]);
680
681 let actions = transfer
682 .process_td_results(&TransferStatus::Completed, 100)
683 .unwrap();
684 assert_eq!(
685 actions,
686 vec![TransferAction::SendEvent {
687 code: TrbCompletionCode::Success,
688 gpa: 0x100,
689 residual_or_edtla: 0,
690 event_data: false,
691 }]
692 );
693 }
694
695 #[test]
696 fn test_bulk_short_with_isp() {
697 let mut trb = Trb::new();
700 let normal_trb = trb.cast_mut::<NormalTrb>().unwrap();
701 normal_trb.set_trb_type(TrbType::Normal);
702 normal_trb.set_trb_transfer_length(100);
703 normal_trb.set_interrupt_on_short_packet(1);
704 let transfer = create_test_transfer(vec![trb]);
705
706 let actions = transfer
707 .process_td_results(&TransferStatus::Completed, 40)
708 .unwrap();
709 assert_eq!(
710 actions,
711 vec![TransferAction::SendEvent {
712 code: TrbCompletionCode::ShortPacket,
713 gpa: 0x100,
714 residual_or_edtla: 60,
715 event_data: false,
716 }]
717 );
718 }
719
720 #[test]
721 fn test_bulk_short_with_ioc() {
722 let mut trb = Trb::new();
725 let normal_trb = trb.cast_mut::<NormalTrb>().unwrap();
726 normal_trb.set_trb_type(TrbType::Normal);
727 normal_trb.set_trb_transfer_length(100);
728 normal_trb.set_interrupt_on_completion(1);
729 let transfer = create_test_transfer(vec![trb]);
730
731 let actions = transfer
732 .process_td_results(&TransferStatus::Completed, 40)
733 .unwrap();
734 assert_eq!(
735 actions,
736 vec![TransferAction::SendEvent {
737 code: TrbCompletionCode::ShortPacket,
738 gpa: 0x100,
739 residual_or_edtla: 60,
740 event_data: false,
741 }]
742 );
743 }
744
745 #[test]
746 fn test_bulk_without_evendata_retiring_after_short() {
747 let mut trb1 = Trb::new();
751 let normal_trb1 = trb1.cast_mut::<NormalTrb>().unwrap();
752 normal_trb1.set_trb_type(TrbType::Normal);
753 normal_trb1.set_trb_transfer_length(100);
754 normal_trb1.set_interrupt_on_short_packet(1);
755
756 let mut trb2 = Trb::new();
757 let normal_trb2 = trb2.cast_mut::<NormalTrb>().unwrap();
758 normal_trb2.set_trb_type(TrbType::Normal);
759 normal_trb2.set_trb_transfer_length(100);
760 normal_trb2.set_interrupt_on_completion(1);
761
762 let mut trb3 = Trb::new();
763 let normal_trb3 = trb3.cast_mut::<NormalTrb>().unwrap();
764 normal_trb3.set_trb_type(TrbType::Normal);
765 normal_trb3.set_trb_transfer_length(100);
766 normal_trb3.set_interrupt_on_completion(1);
767
768 let transfer = create_test_transfer(vec![trb1, trb2, trb3]);
769
770 let actions = transfer
771 .process_td_results(&TransferStatus::Completed, 40)
772 .unwrap();
773 assert_eq!(
774 actions,
775 vec![
776 TransferAction::SendEvent {
777 code: TrbCompletionCode::ShortPacket,
778 gpa: 0x100,
779 residual_or_edtla: 60,
780 event_data: false,
781 },
782 TransferAction::SendEvent {
783 code: TrbCompletionCode::ShortPacket,
784 gpa: 0x110,
785 residual_or_edtla: 60,
786 event_data: false,
787 },
788 TransferAction::SendEvent {
789 code: TrbCompletionCode::ShortPacket,
790 gpa: 0x120,
791 residual_or_edtla: 60,
792 event_data: false,
793 },
794 ]
795 );
796 }
797
798 #[test]
799 fn test_bulk_with_evendata_retiring_after_short() {
800 let mut trb1 = Trb::new();
805 let normal_trb1 = trb1.cast_mut::<NormalTrb>().unwrap();
806 normal_trb1.set_trb_type(TrbType::Normal);
807 normal_trb1.set_trb_transfer_length(100);
808 normal_trb1.set_interrupt_on_short_packet(1);
809
810 let mut trb2 = Trb::new();
811 let event_trb = trb2.cast_mut::<EventDataTrb>().unwrap();
812 event_trb.set_trb_type(TrbType::EventData);
813 event_trb.set_event_data(0x12345678abcdef0);
814 event_trb.set_interrupt_on_completion(1);
815
816 let mut trb3 = Trb::new();
817 let event_trb = trb3.cast_mut::<EventDataTrb>().unwrap();
818 event_trb.set_trb_type(TrbType::EventData);
819 event_trb.set_event_data(0x12345678abcdef1);
820 event_trb.set_interrupt_on_completion(1);
821
822 let transfer = create_test_transfer(vec![trb1, trb2, trb3]);
823
824 let actions = transfer
825 .process_td_results(&TransferStatus::Completed, 40)
826 .unwrap();
827 assert_eq!(
828 actions,
829 vec![
830 TransferAction::SendEvent {
831 code: TrbCompletionCode::ShortPacket,
832 gpa: 0x100,
833 residual_or_edtla: 60,
834 event_data: false,
835 },
836 TransferAction::SendEvent {
837 code: TrbCompletionCode::ShortPacket,
838 gpa: 0x12345678abcdef0,
839 residual_or_edtla: 40, event_data: true,
841 },
842 TransferAction::SendEvent {
843 code: TrbCompletionCode::ShortPacket,
844 gpa: 0x12345678abcdef1,
845 residual_or_edtla: 0, event_data: true,
847 },
848 ]
849 );
850 }
851
852 #[test]
853 fn test_bulk_stall_partial() {
854 let mut trb = Trb::new();
858 let normal_trb = trb.cast_mut::<NormalTrb>().unwrap();
859 normal_trb.set_trb_type(TrbType::Normal);
860 normal_trb.set_trb_transfer_length(100);
861 let transfer = create_test_transfer(vec![trb]);
862
863 let actions = transfer
865 .process_td_results(&TransferStatus::Stalled, 40)
866 .unwrap();
867 assert_eq!(
868 actions,
869 vec![
870 TransferAction::HaltEndpoint,
871 TransferAction::SendEvent {
872 code: TrbCompletionCode::StallError,
873 gpa: 0x100,
874 residual_or_edtla: 60,
875 event_data: false,
876 }
877 ]
878 );
879 }
880
881 #[test]
882 fn test_control_stall_no_data_stage() {
883 let mut trb = Trb::new();
884 let status_trb = trb.cast_mut::<StatusStageTrb>().unwrap();
885 status_trb.set_trb_type(TrbType::StatusStage);
886 status_trb.set_interrupt_on_completion(1);
887
888 let transfer = create_test_transfer(vec![trb]);
889
890 let actions = transfer
892 .process_td_results(&TransferStatus::Stalled, 0)
893 .unwrap();
894
895 assert_eq!(
896 actions,
897 vec![
898 TransferAction::HaltEndpoint,
899 TransferAction::SendEvent {
900 code: TrbCompletionCode::StallError,
901 gpa: 0x100,
902 residual_or_edtla: 0,
903 event_data: false,
904 }
905 ]
906 );
907 }
908
909 #[test]
910 fn test_bulk_stall_at_trb_start() {
911 let mut trb1 = Trb::new();
914 let normal_trb1 = trb1.cast_mut::<NormalTrb>().unwrap();
915 normal_trb1.set_trb_type(TrbType::Normal);
916 normal_trb1.set_trb_transfer_length(100);
917
918 let mut trb2 = Trb::new();
919 let normal_trb2 = trb2.cast_mut::<NormalTrb>().unwrap();
920 normal_trb2.set_trb_type(TrbType::Normal);
921 normal_trb2.set_trb_transfer_length(100);
922
923 let transfer = create_test_transfer(vec![trb1, trb2]);
924
925 let actions = transfer
927 .process_td_results(&TransferStatus::Stalled, 100)
928 .unwrap();
929
930 assert_eq!(
931 actions,
932 vec![
933 TransferAction::HaltEndpoint,
934 TransferAction::SendEvent {
935 code: TrbCompletionCode::StallError,
936 gpa: 0x110, residual_or_edtla: 100,
938 event_data: false,
939 }
940 ]
941 );
942 }
943
944 #[test]
945 fn test_event_data_single() {
946 let mut trb1 = Trb::new();
949 let normal_trb = trb1.cast_mut::<NormalTrb>().unwrap();
950 normal_trb.set_trb_type(TrbType::Normal);
951 normal_trb.set_trb_transfer_length(100);
952
953 let mut trb2 = Trb::new();
954 let event_trb = trb2.cast_mut::<EventDataTrb>().unwrap();
955 event_trb.set_trb_type(TrbType::EventData);
956 event_trb.set_event_data(0x12345678abcdef0);
957 event_trb.set_interrupt_on_completion(1);
958
959 let transfer = create_test_transfer(vec![trb1, trb2]);
960
961 let actions = transfer
963 .process_td_results(&TransferStatus::Completed, 100)
964 .unwrap();
965 assert_eq!(
966 actions,
967 vec![TransferAction::SendEvent {
968 code: TrbCompletionCode::Success,
969 gpa: 0x12345678abcdef0,
970 residual_or_edtla: 100,
971 event_data: true,
972 }]
973 );
974
975 let actions = transfer
977 .process_td_results(&TransferStatus::Completed, 40)
978 .unwrap();
979 assert_eq!(
980 actions,
981 vec![TransferAction::SendEvent {
982 code: TrbCompletionCode::ShortPacket,
983 gpa: 0x12345678abcdef0,
984 residual_or_edtla: 40,
985 event_data: true,
986 }]
987 );
988 }
989
990 #[test]
991 fn test_event_data_multiple() {
992 let mut trb1 = Trb::new();
995 let normal_trb = trb1.cast_mut::<NormalTrb>().unwrap();
996 normal_trb.set_trb_type(TrbType::Normal);
997 normal_trb.set_trb_transfer_length(100);
998 normal_trb.set_interrupt_on_short_packet(1);
999
1000 let mut trb2 = Trb::new();
1001 let event_trb = trb2.cast_mut::<EventDataTrb>().unwrap();
1002 event_trb.set_trb_type(TrbType::EventData);
1003 event_trb.set_event_data(0x12345678abcdef0);
1004 event_trb.set_interrupt_on_completion(1);
1005
1006 let transfer = create_test_transfer(vec![trb1, trb2, trb1, trb2]);
1007
1008 let actions = transfer
1010 .process_td_results(&TransferStatus::Completed, 200)
1011 .unwrap();
1012 assert_eq!(
1013 actions,
1014 vec![
1015 TransferAction::SendEvent {
1016 code: TrbCompletionCode::Success,
1017 gpa: 0x12345678abcdef0,
1018 residual_or_edtla: 100, event_data: true,
1020 },
1021 TransferAction::SendEvent {
1022 code: TrbCompletionCode::Success,
1023 gpa: 0x12345678abcdef0,
1024 residual_or_edtla: 100, event_data: true,
1026 },
1027 ]
1028 );
1029
1030 let actions = transfer
1034 .process_td_results(&TransferStatus::Completed, 40)
1035 .unwrap();
1036 assert_eq!(
1037 actions,
1038 vec![
1039 TransferAction::SendEvent {
1040 code: TrbCompletionCode::ShortPacket,
1041 gpa: 0x100,
1042 residual_or_edtla: 60, event_data: false,
1044 },
1045 TransferAction::SendEvent {
1046 code: TrbCompletionCode::ShortPacket,
1047 gpa: 0x12345678abcdef0,
1048 residual_or_edtla: 40, event_data: true,
1050 },
1051 TransferAction::SendEvent {
1052 code: TrbCompletionCode::ShortPacket,
1053 gpa: 0x12345678abcdef0,
1054 residual_or_edtla: 0, event_data: true,
1056 },
1057 ]
1058 );
1059 }
1060}