TianoCore EDK2 master
Loading...
Searching...
No Matches
Xhci.c
Go to the documentation of this file.
1
10#include "Xhci.h"
11
12//
13// Two arrays used to translate the XHCI port state (change)
14// to the UEFI protocol's port state (change).
15//
16USB_PORT_STATE_MAP mUsbPortStateMap[] = {
17 { XHC_PORTSC_CCS, USB_PORT_STAT_CONNECTION },
18 { XHC_PORTSC_PED, USB_PORT_STAT_ENABLE },
19 { XHC_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT },
20 { XHC_PORTSC_RESET, USB_PORT_STAT_RESET }
21};
22
23USB_PORT_STATE_MAP mUsbPortChangeMap[] = {
24 { XHC_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION },
25 { XHC_PORTSC_PEC, USB_PORT_STAT_C_ENABLE },
26 { XHC_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT },
27 { XHC_PORTSC_PRC, USB_PORT_STAT_C_RESET }
28};
29
30USB_CLEAR_PORT_MAP mUsbClearPortChangeMap[] = {
31 { XHC_PORTSC_CSC, EfiUsbPortConnectChange },
32 { XHC_PORTSC_PEC, EfiUsbPortEnableChange },
33 { XHC_PORTSC_OCC, EfiUsbPortOverCurrentChange },
34 { XHC_PORTSC_PRC, EfiUsbPortResetChange }
35};
36
37USB_PORT_STATE_MAP mUsbHubPortStateMap[] = {
38 { XHC_HUB_PORTSC_CCS, USB_PORT_STAT_CONNECTION },
39 { XHC_HUB_PORTSC_PED, USB_PORT_STAT_ENABLE },
40 { XHC_HUB_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT },
41 { XHC_HUB_PORTSC_RESET, USB_PORT_STAT_RESET }
42};
43
44USB_PORT_STATE_MAP mUsbHubPortChangeMap[] = {
45 { XHC_HUB_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION },
46 { XHC_HUB_PORTSC_PEC, USB_PORT_STAT_C_ENABLE },
47 { XHC_HUB_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT },
48 { XHC_HUB_PORTSC_PRC, USB_PORT_STAT_C_RESET }
49};
50
51USB_CLEAR_PORT_MAP mUsbHubClearPortChangeMap[] = {
52 { XHC_HUB_PORTSC_CSC, EfiUsbPortConnectChange },
53 { XHC_HUB_PORTSC_PEC, EfiUsbPortEnableChange },
54 { XHC_HUB_PORTSC_OCC, EfiUsbPortOverCurrentChange },
55 { XHC_HUB_PORTSC_PRC, EfiUsbPortResetChange },
56 { XHC_HUB_PORTSC_BHRC, Usb3PortBHPortResetChange }
57};
58
59EFI_DRIVER_BINDING_PROTOCOL gXhciDriverBinding = {
63 0x30,
64 NULL,
65 NULL
66};
67
68//
69// Template for Xhci's Usb2 Host Controller Protocol Instance.
70//
71EFI_USB2_HC_PROTOCOL gXhciUsb2HcTemplate = {
85 0x3,
86 0x0
87};
88
89static UINT64 mXhciPerformanceCounterStartValue;
90static UINT64 mXhciPerformanceCounterEndValue;
91static UINT64 mXhciPerformanceCounterFrequency;
92static BOOLEAN mXhciPerformanceCounterValuesCached = FALSE;
93
108EFIAPI
111 OUT UINT8 *MaxSpeed,
112 OUT UINT8 *PortNumber,
113 OUT UINT8 *Is64BitCapable
114 )
115{
117 EFI_TPL OldTpl;
118
119 if ((MaxSpeed == NULL) || (PortNumber == NULL) || (Is64BitCapable == NULL)) {
120 return EFI_INVALID_PARAMETER;
121 }
122
123 OldTpl = gBS->RaiseTPL (XHC_TPL);
124
125 Xhc = XHC_FROM_THIS (This);
126 *MaxSpeed = EFI_USB_SPEED_SUPER;
127 *PortNumber = (UINT8)(Xhc->HcSParams1.Data.MaxPorts);
128 *Is64BitCapable = (UINT8)Xhc->Support64BitDma;
129 DEBUG ((DEBUG_INFO, "XhcGetCapability: %d ports, 64 bit %d\n", *PortNumber, *Is64BitCapable));
130
131 gBS->RestoreTPL (OldTpl);
132
133 return EFI_SUCCESS;
134}
135
150EFIAPI
153 IN UINT16 Attributes
154 )
155{
157 EFI_STATUS Status;
158 EFI_TPL OldTpl;
159
160 Xhc = XHC_FROM_THIS (This);
161
162 if (Xhc->DevicePath != NULL) {
163 //
164 // Report Status Code to indicate reset happens
165 //
168 (EFI_IO_BUS_USB | EFI_IOB_PC_RESET),
169 Xhc->DevicePath
170 );
171 }
172
173 OldTpl = gBS->RaiseTPL (XHC_TPL);
174
175 switch (Attributes) {
176 case EFI_USB_HC_RESET_GLOBAL:
177 //
178 // Flow through, same behavior as Host Controller Reset
179 //
180 case EFI_USB_HC_RESET_HOST_CONTROLLER:
181 if ((Xhc->DebugCapSupOffset != 0xFFFFFFFF) && ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset) & 0xFF) == XHC_CAP_USB_DEBUG) &&
182 ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset + XHC_DC_DCCTRL) & BIT0) != 0))
183 {
184 Status = EFI_SUCCESS;
185 goto ON_EXIT;
186 }
187
188 //
189 // Host Controller must be Halt when Reset it
190 //
191 if (!XhcIsHalt (Xhc)) {
192 Status = XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
193
194 if (EFI_ERROR (Status)) {
195 Status = EFI_DEVICE_ERROR;
196 goto ON_EXIT;
197 }
198 }
199
200 Status = XhcResetHC (Xhc, XHC_RESET_TIMEOUT);
201 ASSERT (!(XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_CNR)));
202
203 if (EFI_ERROR (Status)) {
204 goto ON_EXIT;
205 }
206
207 //
208 // Clean up the asynchronous transfers, currently only
209 // interrupt supports asynchronous operation.
210 //
212 XhcFreeSched (Xhc);
213
214 XhcInitSched (Xhc);
215 break;
216
217 case EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG:
218 case EFI_USB_HC_RESET_HOST_WITH_DEBUG:
219 Status = EFI_UNSUPPORTED;
220 break;
221
222 default:
223 Status = EFI_INVALID_PARAMETER;
224 }
225
226ON_EXIT:
227 DEBUG ((DEBUG_INFO, "XhcReset: status %r\n", Status));
228 gBS->RestoreTPL (OldTpl);
229
230 return Status;
231}
232
247EFIAPI
250 OUT EFI_USB_HC_STATE *State
251 )
252{
254 EFI_TPL OldTpl;
255
256 if (State == NULL) {
257 return EFI_INVALID_PARAMETER;
258 }
259
260 OldTpl = gBS->RaiseTPL (XHC_TPL);
261
262 Xhc = XHC_FROM_THIS (This);
263
264 if (XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) {
265 *State = EfiUsbHcStateHalt;
266 } else {
268 }
269
270 DEBUG ((DEBUG_INFO, "XhcGetState: current state %d\n", *State));
271 gBS->RestoreTPL (OldTpl);
272
273 return EFI_SUCCESS;
274}
275
289EFIAPI
292 IN EFI_USB_HC_STATE State
293 )
294{
296 EFI_STATUS Status;
297 EFI_USB_HC_STATE CurState;
298 EFI_TPL OldTpl;
299
300 Status = XhcGetState (This, &CurState);
301
302 if (EFI_ERROR (Status)) {
303 return EFI_DEVICE_ERROR;
304 }
305
306 if (CurState == State) {
307 return EFI_SUCCESS;
308 }
309
310 OldTpl = gBS->RaiseTPL (XHC_TPL);
311
312 Xhc = XHC_FROM_THIS (This);
313
314 switch (State) {
316 Status = XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
317 break;
318
320 if (XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE)) {
321 Status = EFI_DEVICE_ERROR;
322 break;
323 }
324
325 //
326 // Software must not write a one to this field unless the host controller
327 // is in the Halted state. Doing so will yield undefined results.
328 // refers to Spec[XHCI1.0-2.3.1]
329 //
330 if (!XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) {
331 Status = EFI_DEVICE_ERROR;
332 break;
333 }
334
335 Status = XhcRunHC (Xhc, XHC_GENERIC_TIMEOUT);
336 break;
337
339 Status = EFI_UNSUPPORTED;
340 break;
341
342 default:
343 Status = EFI_INVALID_PARAMETER;
344 }
345
346 DEBUG ((DEBUG_INFO, "XhcSetState: status %r\n", Status));
347 gBS->RestoreTPL (OldTpl);
348
349 return Status;
350}
351
367EFIAPI
370 IN UINT8 PortNumber,
371 OUT EFI_USB_PORT_STATUS *PortStatus
372 )
373{
375 UINT32 Offset;
376 UINT32 State;
377 UINT32 TotalPort;
378 UINTN Index;
379 UINTN MapSize;
380 UINT8 PortSpeed;
381 EFI_STATUS Status;
382 USB_DEV_ROUTE ParentRouteChart;
383 EFI_TPL OldTpl;
384
385 if (PortStatus == NULL) {
386 return EFI_INVALID_PARAMETER;
387 }
388
389 OldTpl = gBS->RaiseTPL (XHC_TPL);
390
391 Xhc = XHC_FROM_THIS (This);
392 Status = EFI_SUCCESS;
393
394 TotalPort = Xhc->HcSParams1.Data.MaxPorts;
395
396 if (PortNumber >= TotalPort) {
397 Status = EFI_INVALID_PARAMETER;
398 goto ON_EXIT;
399 }
400
401 Offset = (UINT32)(XHC_PORTSC_OFFSET + (0x10 * PortNumber));
402 PortStatus->PortStatus = 0;
403 PortStatus->PortChangeStatus = 0;
404
405 State = XhcReadOpReg (Xhc, Offset);
406
407 PortSpeed = (State & XHC_PORTSC_PS) >> 10;
408
409 //
410 // According to XHCI 1.1 spec November 2017,
411 // Section 7.2 xHCI Support Protocol Capability
412 //
413 if (PortSpeed > 0) {
414 PortStatus->PortStatus = XhcCheckUsbPortSpeedUsedPsic (Xhc, PortSpeed, PortNumber);
415 // If no match found in ext cap reg, fall back to PORTSC
416 if (PortStatus->PortStatus == 0) {
417 //
418 // According to XHCI 1.1 spec November 2017,
419 // bit 10~13 of the root port status register identifies the speed of the attached device.
420 //
421 switch (PortSpeed) {
422 case 2:
423 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
424 break;
425
426 case 3:
427 PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;
428 break;
429
430 case 4:
431 case 5:
432 PortStatus->PortStatus |= USB_PORT_STAT_SUPER_SPEED;
433 break;
434
435 default:
436 break;
437 }
438 }
439 }
440
441 //
442 // Convert the XHCI port/port change state to UEFI status
443 //
444 MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);
445
446 for (Index = 0; Index < MapSize; Index++) {
447 if (XHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {
448 PortStatus->PortStatus = (UINT16)(PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);
449 }
450 }
451
452 //
453 // Bit5~8 reflects its current link state.
454 //
455 if ((State & XHC_PORTSC_PLS) >> 5 == 3) {
456 PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
457 }
458
459 MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
460
461 for (Index = 0; Index < MapSize; Index++) {
462 if (XHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {
463 PortStatus->PortChangeStatus = (UINT16)(PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);
464 }
465 }
466
467 MapSize = sizeof (mUsbClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
468
469 for (Index = 0; Index < MapSize; Index++) {
470 if (XHC_BIT_IS_SET (State, mUsbClearPortChangeMap[Index].HwState)) {
471 XhcClearRootHubPortFeature (This, PortNumber, (EFI_USB_PORT_FEATURE)mUsbClearPortChangeMap[Index].Selector);
472 }
473 }
474
475 //
476 // Poll the root port status register to enable/disable corresponding device slot if there is a device attached/detached.
477 // For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub.
478 //
479 ParentRouteChart.Dword = 0;
480 Status = XhcPollPortStatusChange (Xhc, ParentRouteChart, PortNumber, PortStatus);
481
482 //
483 // Force resetting the port by clearing the USB_PORT_STAT_C_RESET bit in PortChangeStatus
484 // when XhcPollPortStatusChange fails
485 //
486 if (EFI_ERROR (Status)) {
487 PortStatus->PortChangeStatus &= ~(USB_PORT_STAT_C_RESET);
488 Status = EFI_SUCCESS;
489 }
490
491ON_EXIT:
492 gBS->RestoreTPL (OldTpl);
493 return Status;
494}
495
509EFIAPI
512 IN UINT8 PortNumber,
513 IN EFI_USB_PORT_FEATURE PortFeature
514 )
515{
517 UINT32 Offset;
518 UINT32 State;
519 UINT32 TotalPort;
520 EFI_STATUS Status;
521 EFI_TPL OldTpl;
522
523 OldTpl = gBS->RaiseTPL (XHC_TPL);
524
525 Xhc = XHC_FROM_THIS (This);
526 Status = EFI_SUCCESS;
527
528 TotalPort = (Xhc->HcSParams1.Data.MaxPorts);
529
530 if (PortNumber >= TotalPort) {
531 Status = EFI_INVALID_PARAMETER;
532 goto ON_EXIT;
533 }
534
535 Offset = (UINT32)(XHC_PORTSC_OFFSET + (0x10 * PortNumber));
536 State = XhcReadOpReg (Xhc, Offset);
537
538 //
539 // Mask off the port status change bits, these bits are
540 // write clean bit
541 //
542 State &= ~(BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);
543
544 switch (PortFeature) {
545 case EfiUsbPortEnable:
546 //
547 // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
548 // A port may be disabled by software writing a '1' to this flag.
549 //
550 Status = EFI_SUCCESS;
551 break;
552
553 case EfiUsbPortSuspend:
554 State |= XHC_PORTSC_LWS;
555 XhcWriteOpReg (Xhc, Offset, State);
556 State &= ~XHC_PORTSC_PLS;
557 State |= (3 << 5);
558 XhcWriteOpReg (Xhc, Offset, State);
559 break;
560
561 case EfiUsbPortReset:
562 DEBUG ((DEBUG_INFO, "XhcUsbPortReset!\n"));
563 //
564 // Make sure Host Controller not halt before reset it
565 //
566 if (XhcIsHalt (Xhc)) {
567 Status = XhcRunHC (Xhc, XHC_GENERIC_TIMEOUT);
568
569 if (EFI_ERROR (Status)) {
570 DEBUG ((DEBUG_INFO, "XhcSetRootHubPortFeature :failed to start HC - %r\n", Status));
571 break;
572 }
573 }
574
575 //
576 // 4.3.1 Resetting a Root Hub Port
577 // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.
578 //
579 State |= XHC_PORTSC_RESET;
580 XhcWriteOpReg (Xhc, Offset, State);
581 XhcWaitOpRegBit (Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);
582 break;
583
584 case EfiUsbPortPower:
585 //
586 // Not supported, ignore the operation
587 //
588 Status = EFI_SUCCESS;
589 break;
590
591 case EfiUsbPortOwner:
592 //
593 // XHCI root hub port don't has the owner bit, ignore the operation
594 //
595 Status = EFI_SUCCESS;
596 break;
597
598 default:
599 Status = EFI_INVALID_PARAMETER;
600 }
601
602ON_EXIT:
603 DEBUG ((DEBUG_INFO, "XhcSetRootHubPortFeature: status %r\n", Status));
604 gBS->RestoreTPL (OldTpl);
605
606 return Status;
607}
608
625EFIAPI
628 IN UINT8 PortNumber,
629 IN EFI_USB_PORT_FEATURE PortFeature
630 )
631{
633 UINT32 Offset;
634 UINT32 State;
635 UINT32 TotalPort;
636 EFI_STATUS Status;
637 EFI_TPL OldTpl;
638
639 OldTpl = gBS->RaiseTPL (XHC_TPL);
640
641 Xhc = XHC_FROM_THIS (This);
642 Status = EFI_SUCCESS;
643
644 TotalPort = (Xhc->HcSParams1.Data.MaxPorts);
645
646 if (PortNumber >= TotalPort) {
647 Status = EFI_INVALID_PARAMETER;
648 goto ON_EXIT;
649 }
650
651 Offset = XHC_PORTSC_OFFSET + (0x10 * PortNumber);
652
653 //
654 // Mask off the port status change bits, these bits are
655 // write clean bit
656 //
657 State = XhcReadOpReg (Xhc, Offset);
658 State &= ~(BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);
659
660 switch (PortFeature) {
661 case EfiUsbPortEnable:
662 //
663 // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
664 // A port may be disabled by software writing a '1' to this flag.
665 //
666 State |= XHC_PORTSC_PED;
667 State &= ~XHC_PORTSC_RESET;
668 XhcWriteOpReg (Xhc, Offset, State);
669 break;
670
671 case EfiUsbPortSuspend:
672 State |= XHC_PORTSC_LWS;
673 XhcWriteOpReg (Xhc, Offset, State);
674 State &= ~XHC_PORTSC_PLS;
675 XhcWriteOpReg (Xhc, Offset, State);
676 break;
677
678 case EfiUsbPortReset:
679 //
680 // PORTSC_RESET BIT(4) bit is RW1S attribute, which means Write-1-to-set status:
681 // Register bits indicate status when read, a clear bit may be set by
682 // writing a '1'. Writing a '0' to RW1S bits has no effect.
683 //
684 break;
685
686 case EfiUsbPortOwner:
687 //
688 // XHCI root hub port don't has the owner bit, ignore the operation
689 //
690 break;
691
692 case EfiUsbPortConnectChange:
693 //
694 // Clear connect status change
695 //
696 State |= XHC_PORTSC_CSC;
697 XhcWriteOpReg (Xhc, Offset, State);
698 break;
699
700 case EfiUsbPortEnableChange:
701 //
702 // Clear enable status change
703 //
704 State |= XHC_PORTSC_PEC;
705 XhcWriteOpReg (Xhc, Offset, State);
706 break;
707
708 case EfiUsbPortOverCurrentChange:
709 //
710 // Clear PortOverCurrent change
711 //
712 State |= XHC_PORTSC_OCC;
713 XhcWriteOpReg (Xhc, Offset, State);
714 break;
715
716 case EfiUsbPortResetChange:
717 //
718 // Clear Port Reset change
719 //
720 State |= XHC_PORTSC_PRC;
721 XhcWriteOpReg (Xhc, Offset, State);
722 break;
723
724 case EfiUsbPortPower:
725 case EfiUsbPortSuspendChange:
726 //
727 // Not supported or not related operation
728 //
729 break;
730
731 default:
732 Status = EFI_INVALID_PARAMETER;
733 break;
734 }
735
736ON_EXIT:
737 DEBUG ((DEBUG_INFO, "XhcClearRootHubPortFeature: status %r\n", Status));
738 gBS->RestoreTPL (OldTpl);
739
740 return Status;
741}
742
769 IN UINT8 DeviceAddress,
770 IN UINT8 EndPointAddress,
771 IN UINT8 DeviceSpeed,
772 IN UINTN MaximumPacketLength,
773 IN UINTN Type,
774 IN EFI_USB_DEVICE_REQUEST *Request,
775 IN OUT VOID *Data,
776 IN OUT UINTN *DataLength,
777 IN UINTN Timeout,
778 OUT UINT32 *TransferResult
779 )
780{
781 EFI_STATUS Status;
782 EFI_STATUS RecoveryStatus;
783 URB *Urb;
784
785 ASSERT ((Type == XHC_CTRL_TRANSFER) || (Type == XHC_BULK_TRANSFER) || (Type == XHC_INT_TRANSFER_SYNC));
786 Urb = XhcCreateUrb (
787 Xhc,
788 DeviceAddress,
789 EndPointAddress,
790 DeviceSpeed,
791 MaximumPacketLength,
792 Type,
793 Request,
794 Data,
795 *DataLength,
796 NULL,
797 NULL
798 );
799
800 if (Urb == NULL) {
801 DEBUG ((DEBUG_ERROR, "XhcTransfer[Type=%d]: failed to create URB!\n", Type));
802 return EFI_OUT_OF_RESOURCES;
803 }
804
805 Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout);
806
807 if (Status == EFI_TIMEOUT) {
808 //
809 // The transfer timed out. Abort the transfer by dequeueing of the TD.
810 //
811 RecoveryStatus = XhcDequeueTrbFromEndpoint (Xhc, Urb);
812 if (RecoveryStatus == EFI_ALREADY_STARTED) {
813 //
814 // The URB is finished just before stopping endpoint.
815 // Change returning status from EFI_TIMEOUT to EFI_SUCCESS.
816 //
817 ASSERT (Urb->Result == EFI_USB_NOERROR);
818 Status = EFI_SUCCESS;
819 DEBUG ((DEBUG_ERROR, "XhcTransfer[Type=%d]: pending URB is finished, Length = %d.\n", Type, Urb->Completed));
820 } else if (EFI_ERROR (RecoveryStatus)) {
821 DEBUG ((DEBUG_ERROR, "XhcTransfer[Type=%d]: XhcDequeueTrbFromEndpoint failed!\n", Type));
822 }
823 }
824
825 *TransferResult = Urb->Result;
826 *DataLength = Urb->Completed;
827
828 //
829 // Based on XHCI spec 4.8.3, software should do the reset endpoint while USB Transaction occur.
830 //
831 if ((*TransferResult == EFI_USB_ERR_STALL) || (*TransferResult == EFI_USB_ERR_BABBLE) || (*TransferResult == EDKII_USB_ERR_TRANSACTION)) {
832 ASSERT (Status == EFI_DEVICE_ERROR);
833 RecoveryStatus = XhcRecoverHaltedEndpoint (Xhc, Urb);
834 if (EFI_ERROR (RecoveryStatus)) {
835 DEBUG ((DEBUG_ERROR, "XhcTransfer[Type=%d]: XhcRecoverHaltedEndpoint failed!\n", Type));
836 }
837 }
838
839 Xhc->PciIo->Flush (Xhc->PciIo);
840 XhcFreeUrb (Xhc, Urb);
841 return Status;
842}
843
869EFIAPI
872 IN UINT8 DeviceAddress,
873 IN UINT8 DeviceSpeed,
874 IN UINTN MaximumPacketLength,
875 IN EFI_USB_DEVICE_REQUEST *Request,
876 IN EFI_USB_DATA_DIRECTION TransferDirection,
877 IN OUT VOID *Data,
878 IN OUT UINTN *DataLength,
879 IN UINTN Timeout,
881 OUT UINT32 *TransferResult
882 )
883{
885 UINT8 Endpoint;
886 UINT8 Index;
887 UINT8 DescriptorType;
888 UINT8 SlotId;
889 UINT8 TTT;
890 UINT8 MTT;
891 UINT32 MaxPacket0;
892 EFI_USB_HUB_DESCRIPTOR *HubDesc;
893 EFI_TPL OldTpl;
894 EFI_STATUS Status;
895 UINTN MapSize;
896 EFI_USB_PORT_STATUS PortStatus;
897 UINT32 State;
898 EFI_USB_DEVICE_REQUEST ClearPortRequest;
899 UINTN Len;
900
901 //
902 // Validate parameters
903 //
904 if ((Request == NULL) || (TransferResult == NULL)) {
905 return EFI_INVALID_PARAMETER;
906 }
907
908 if ((TransferDirection != EfiUsbDataIn) &&
909 (TransferDirection != EfiUsbDataOut) &&
910 (TransferDirection != EfiUsbNoData))
911 {
912 return EFI_INVALID_PARAMETER;
913 }
914
915 if ((TransferDirection == EfiUsbNoData) &&
916 ((Data != NULL) || (*DataLength != 0)))
917 {
918 return EFI_INVALID_PARAMETER;
919 }
920
921 if ((TransferDirection != EfiUsbNoData) &&
922 ((Data == NULL) || (*DataLength == 0)))
923 {
924 return EFI_INVALID_PARAMETER;
925 }
926
927 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&
928 (MaximumPacketLength != 32) && (MaximumPacketLength != 64) &&
929 (MaximumPacketLength != 512)
930 )
931 {
932 return EFI_INVALID_PARAMETER;
933 }
934
935 if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {
936 return EFI_INVALID_PARAMETER;
937 }
938
939 if ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength != 512)) {
940 return EFI_INVALID_PARAMETER;
941 }
942
943 OldTpl = gBS->RaiseTPL (XHC_TPL);
944
945 Xhc = XHC_FROM_THIS (This);
946
947 Status = EFI_DEVICE_ERROR;
948 *TransferResult = EFI_USB_ERR_SYSTEM;
949 Len = 0;
950
951 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
952 DEBUG ((DEBUG_ERROR, "XhcControlTransfer: HC halted at entrance\n"));
953 goto ON_EXIT;
954 }
955
956 //
957 // Check if the device is still enabled before every transaction.
958 //
959 SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);
960 if (SlotId == 0) {
961 goto ON_EXIT;
962 }
963
964 //
965 // Hook the Set_Address request from UsbBus.
966 // According to XHCI 1.0 spec, the Set_Address request is replaced by XHCI's Address_Device cmd.
967 //
968 if ((Request->Request == USB_REQ_SET_ADDRESS) &&
969 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)))
970 {
971 //
972 // Reset the BusDevAddr field of all disabled entries in UsbDevContext array firstly.
973 // This way is used to clean the history to avoid using wrong device address by XhcAsyncInterruptTransfer().
974 //
975 for (Index = 0; Index < 255; Index++) {
976 if (!Xhc->UsbDevContext[Index + 1].Enabled &&
977 (Xhc->UsbDevContext[Index + 1].SlotId == 0) &&
978 (Xhc->UsbDevContext[Index + 1].BusDevAddr == (UINT8)Request->Value))
979 {
980 Xhc->UsbDevContext[Index + 1].BusDevAddr = 0;
981 }
982 }
983
984 if (Xhc->UsbDevContext[SlotId].XhciDevAddr == 0) {
985 Status = EFI_DEVICE_ERROR;
986 goto ON_EXIT;
987 }
988
989 //
990 // The actual device address has been assigned by XHCI during initializing the device slot.
991 // So we just need establish the mapping relationship between the device address requested from UsbBus
992 // and the actual device address assigned by XHCI. The the following invocations through EFI_USB2_HC_PROTOCOL interface
993 // can find out the actual device address by it.
994 //
995 Xhc->UsbDevContext[SlotId].BusDevAddr = (UINT8)Request->Value;
996 Status = EFI_SUCCESS;
997 goto ON_EXIT;
998 }
999
1000 //
1001 // Create a new URB, insert it into the asynchronous
1002 // schedule list, then poll the execution status.
1003 // Note that we encode the direction in address although default control
1004 // endpoint is bidirectional. XhcCreateUrb expects this
1005 // combination of Ep addr and its direction.
1006 //
1007 Endpoint = (UINT8)(0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));
1008 Status = XhcTransfer (
1009 Xhc,
1010 DeviceAddress,
1011 Endpoint,
1012 DeviceSpeed,
1013 MaximumPacketLength,
1014 XHC_CTRL_TRANSFER,
1015 Request,
1016 Data,
1017 DataLength,
1018 Timeout,
1019 TransferResult
1020 );
1021
1022 if (EFI_ERROR (Status)) {
1023 goto ON_EXIT;
1024 }
1025
1026 //
1027 // Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.
1028 // Hook Get_Status request form UsbBus as we need trace device attach/detach event happened at hub.
1029 // Hook Set_Config request from UsbBus as we need configure device endpoint.
1030 //
1031 if ((Request->Request == USB_REQ_GET_DESCRIPTOR) &&
1032 ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)) ||
1033 ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_DEVICE)))))
1034 {
1035 DescriptorType = (UINT8)(Request->Value >> 8);
1036 if ((DescriptorType == USB_DESC_TYPE_DEVICE) && ((*DataLength == sizeof (EFI_USB_DEVICE_DESCRIPTOR)) || ((DeviceSpeed == EFI_USB_SPEED_FULL) && (*DataLength == 8)))) {
1037 ASSERT (Data != NULL);
1038 //
1039 // Store a copy of device scriptor as hub device need this info to configure endpoint.
1040 //
1041 CopyMem (&Xhc->UsbDevContext[SlotId].DevDesc, Data, *DataLength);
1042 if (Xhc->UsbDevContext[SlotId].DevDesc.BcdUSB >= 0x0300) {
1043 //
1044 // If it's a usb3.0 device, then its max packet size is a 2^n.
1045 //
1046 MaxPacket0 = 1 << Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;
1047 } else {
1048 MaxPacket0 = Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;
1049 }
1050
1051 Xhc->UsbDevContext[SlotId].ConfDesc = AllocateZeroPool (Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations * sizeof (EFI_USB_CONFIG_DESCRIPTOR *));
1052 if (Xhc->HcCParams.Data.Csz == 0) {
1053 Status = XhcEvaluateContext (Xhc, SlotId, MaxPacket0);
1054 } else {
1055 Status = XhcEvaluateContext64 (Xhc, SlotId, MaxPacket0);
1056 }
1057 } else if (DescriptorType == USB_DESC_TYPE_CONFIG) {
1058 ASSERT (Data != NULL);
1059 if (*DataLength == ((UINT16 *)Data)[1]) {
1060 //
1061 // Get configuration value from request, Store the configuration descriptor for Configure_Endpoint cmd.
1062 //
1063 Index = (UINT8)Request->Value;
1064 ASSERT (Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations);
1065 Xhc->UsbDevContext[SlotId].ConfDesc[Index] = AllocateZeroPool (*DataLength);
1066 CopyMem (Xhc->UsbDevContext[SlotId].ConfDesc[Index], Data, *DataLength);
1067 //
1068 // Default to use AlternateSetting 0 for all interfaces.
1069 //
1070 Xhc->UsbDevContext[SlotId].ActiveAlternateSetting = AllocateZeroPool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->NumInterfaces * sizeof (UINT8));
1071 }
1072 } else if (((DescriptorType == USB_DESC_TYPE_HUB) ||
1073 (DescriptorType == USB_DESC_TYPE_HUB_SUPER_SPEED)) && (*DataLength > 2))
1074 {
1075 ASSERT (Data != NULL);
1076 HubDesc = (EFI_USB_HUB_DESCRIPTOR *)Data;
1077 ASSERT (HubDesc->NumPorts <= 15);
1078 //
1079 // The bit 5,6 of HubCharacter field of Hub Descriptor is TTT.
1080 //
1081 TTT = (UINT8)((HubDesc->HubCharacter & (BIT5 | BIT6)) >> 5);
1082 if (Xhc->UsbDevContext[SlotId].DevDesc.DeviceProtocol == 2) {
1083 //
1084 // Don't support multi-TT feature for super speed hub now.
1085 //
1086 MTT = 0;
1087 DEBUG ((DEBUG_ERROR, "XHCI: Don't support multi-TT feature for Hub now. (force to disable MTT)\n"));
1088 } else {
1089 MTT = 0;
1090 }
1091
1092 if (Xhc->HcCParams.Data.Csz == 0) {
1093 Status = XhcConfigHubContext (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);
1094 } else {
1095 Status = XhcConfigHubContext64 (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);
1096 }
1097 }
1098 } else if ((Request->Request == USB_REQ_SET_CONFIG) &&
1099 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)))
1100 {
1101 //
1102 // Hook Set_Config request from UsbBus as we need configure device endpoint.
1103 //
1104 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
1105 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->ConfigurationValue == (UINT8)Request->Value) {
1106 if (Xhc->HcCParams.Data.Csz == 0) {
1107 Status = XhcSetConfigCmd (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
1108 } else {
1109 Status = XhcSetConfigCmd64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
1110 }
1111
1112 break;
1113 }
1114 }
1115 } else if ((Request->Request == USB_REQ_SET_INTERFACE) &&
1116 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_INTERFACE)))
1117 {
1118 //
1119 // Hook Set_Interface request from UsbBus as we need configure interface setting.
1120 // Request->Value indicates AlterlateSetting to set
1121 // Request->Index indicates Interface to set
1122 //
1123 if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8)Request->Index] != (UINT8)Request->Value) {
1124 if (Xhc->HcCParams.Data.Csz == 0) {
1125 Status = XhcSetInterface (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Xhc->UsbDevContext[SlotId].ActiveConfiguration - 1], Request);
1126 } else {
1127 Status = XhcSetInterface64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Xhc->UsbDevContext[SlotId].ActiveConfiguration - 1], Request);
1128 }
1129 }
1130 } else if ((Request->Request == USB_REQ_GET_STATUS) &&
1131 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER)))
1132 {
1133 ASSERT (Data != NULL);
1134 //
1135 // Hook Get_Status request from UsbBus to keep track of the port status change.
1136 //
1137 State = *(UINT32 *)Data;
1138 PortStatus.PortStatus = 0;
1139 PortStatus.PortChangeStatus = 0;
1140
1141 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
1142 //
1143 // For super speed hub, its bit10~12 presents the attached device speed.
1144 //
1145 if ((State & XHC_PORTSC_PS) >> 10 == 0) {
1146 PortStatus.PortStatus |= USB_PORT_STAT_SUPER_SPEED;
1147 }
1148 } else {
1149 //
1150 // For high or full/low speed hub, its bit9~10 presents the attached device speed.
1151 //
1152 if (XHC_BIT_IS_SET (State, BIT9)) {
1153 PortStatus.PortStatus |= USB_PORT_STAT_LOW_SPEED;
1154 } else if (XHC_BIT_IS_SET (State, BIT10)) {
1155 PortStatus.PortStatus |= USB_PORT_STAT_HIGH_SPEED;
1156 }
1157 }
1158
1159 //
1160 // Convert the XHCI port/port change state to UEFI status
1161 //
1162 MapSize = sizeof (mUsbHubPortStateMap) / sizeof (USB_PORT_STATE_MAP);
1163 for (Index = 0; Index < MapSize; Index++) {
1164 if (XHC_BIT_IS_SET (State, mUsbHubPortStateMap[Index].HwState)) {
1165 PortStatus.PortStatus = (UINT16)(PortStatus.PortStatus | mUsbHubPortStateMap[Index].UefiState);
1166 }
1167 }
1168
1169 MapSize = sizeof (mUsbHubPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
1170 for (Index = 0; Index < MapSize; Index++) {
1171 if (XHC_BIT_IS_SET (State, mUsbHubPortChangeMap[Index].HwState)) {
1172 PortStatus.PortChangeStatus = (UINT16)(PortStatus.PortChangeStatus | mUsbHubPortChangeMap[Index].UefiState);
1173 }
1174 }
1175
1176 MapSize = sizeof (mUsbHubClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
1177
1178 for (Index = 0; Index < MapSize; Index++) {
1179 if (XHC_BIT_IS_SET (State, mUsbHubClearPortChangeMap[Index].HwState)) {
1180 ZeroMem (&ClearPortRequest, sizeof (EFI_USB_DEVICE_REQUEST));
1181 ClearPortRequest.RequestType = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER);
1182 ClearPortRequest.Request = (UINT8)USB_REQ_CLEAR_FEATURE;
1183 ClearPortRequest.Value = mUsbHubClearPortChangeMap[Index].Selector;
1184 ClearPortRequest.Index = Request->Index;
1185 ClearPortRequest.Length = 0;
1186
1188 This,
1189 DeviceAddress,
1190 DeviceSpeed,
1191 MaximumPacketLength,
1192 &ClearPortRequest,
1193 EfiUsbNoData,
1194 NULL,
1195 &Len,
1196 Timeout,
1197 Translator,
1198 TransferResult
1199 );
1200 }
1201 }
1202
1203 XhcPollPortStatusChange (Xhc, Xhc->UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus);
1204
1205 *(UINT32 *)Data = *(UINT32 *)&PortStatus;
1206 }
1207
1208ON_EXIT:
1209 if (EFI_ERROR (Status)) {
1210 DEBUG ((DEBUG_ERROR, "XhcControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
1211 }
1212
1213 gBS->RestoreTPL (OldTpl);
1214
1215 return Status;
1216}
1217
1249EFIAPI
1252 IN UINT8 DeviceAddress,
1253 IN UINT8 EndPointAddress,
1254 IN UINT8 DeviceSpeed,
1255 IN UINTN MaximumPacketLength,
1256 IN UINT8 DataBuffersNumber,
1257 IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
1258 IN OUT UINTN *DataLength,
1259 IN OUT UINT8 *DataToggle,
1260 IN UINTN Timeout,
1262 OUT UINT32 *TransferResult
1263 )
1264{
1265 USB_XHCI_INSTANCE *Xhc;
1266 UINT8 SlotId;
1267 EFI_STATUS Status;
1268 EFI_TPL OldTpl;
1269 UINTN DebugErrorLevel;
1270
1271 //
1272 // Validate the parameters
1273 //
1274 if ((DataLength == NULL) || (*DataLength == 0) ||
1275 (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL))
1276 {
1277 return EFI_INVALID_PARAMETER;
1278 }
1279
1280 if ((*DataToggle != 0) && (*DataToggle != 1)) {
1281 return EFI_INVALID_PARAMETER;
1282 }
1283
1284 if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
1285 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
1286 ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512)) ||
1287 ((EFI_USB_SPEED_SUPER == DeviceSpeed) && (MaximumPacketLength > 1024)))
1288 {
1289 return EFI_INVALID_PARAMETER;
1290 }
1291
1292 OldTpl = gBS->RaiseTPL (XHC_TPL);
1293
1294 Xhc = XHC_FROM_THIS (This);
1295
1296 *TransferResult = EFI_USB_ERR_SYSTEM;
1297 Status = EFI_DEVICE_ERROR;
1298
1299 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
1300 DEBUG ((DEBUG_ERROR, "XhcBulkTransfer: HC is halted\n"));
1301 goto ON_EXIT;
1302 }
1303
1304 //
1305 // Check if the device is still enabled before every transaction.
1306 //
1307 SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);
1308 if (SlotId == 0) {
1309 goto ON_EXIT;
1310 }
1311
1312 //
1313 // Create a new URB, insert it into the asynchronous
1314 // schedule list, then poll the execution status.
1315 //
1316 Status = XhcTransfer (
1317 Xhc,
1318 DeviceAddress,
1319 EndPointAddress,
1320 DeviceSpeed,
1321 MaximumPacketLength,
1322 XHC_BULK_TRANSFER,
1323 NULL,
1324 Data[0],
1325 DataLength,
1326 Timeout,
1327 TransferResult
1328 );
1329
1330ON_EXIT:
1331 if (EFI_ERROR (Status)) {
1332 if (Status == EFI_TIMEOUT) {
1333 DebugErrorLevel = DEBUG_VERBOSE;
1334 } else {
1335 DebugErrorLevel = DEBUG_ERROR;
1336 }
1337
1338 DEBUG ((DebugErrorLevel, "XhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
1339 }
1340
1341 gBS->RestoreTPL (OldTpl);
1342
1343 return Status;
1344}
1345
1376EFIAPI
1379 IN UINT8 DeviceAddress,
1380 IN UINT8 EndPointAddress,
1381 IN UINT8 DeviceSpeed,
1382 IN UINTN MaximumPacketLength,
1383 IN BOOLEAN IsNewTransfer,
1384 IN OUT UINT8 *DataToggle,
1385 IN UINTN PollingInterval,
1386 IN UINTN DataLength,
1388 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,
1389 IN VOID *Context OPTIONAL
1390 )
1391{
1392 USB_XHCI_INSTANCE *Xhc;
1393 URB *Urb;
1394 EFI_STATUS Status;
1395 UINT8 SlotId;
1396 UINT8 Index;
1397 EFI_TPL OldTpl;
1398
1399 //
1400 // Validate parameters
1401 //
1402 if (!XHCI_IS_DATAIN (EndPointAddress)) {
1403 return EFI_INVALID_PARAMETER;
1404 }
1405
1406 if (IsNewTransfer) {
1407 if (DataLength == 0) {
1408 return EFI_INVALID_PARAMETER;
1409 }
1410
1411 if ((*DataToggle != 1) && (*DataToggle != 0)) {
1412 return EFI_INVALID_PARAMETER;
1413 }
1414
1415 if ((PollingInterval > 255) || (PollingInterval < 1)) {
1416 return EFI_INVALID_PARAMETER;
1417 }
1418 }
1419
1420 OldTpl = gBS->RaiseTPL (XHC_TPL);
1421
1422 Xhc = XHC_FROM_THIS (This);
1423
1424 //
1425 // Delete Async interrupt transfer request.
1426 //
1427 if (!IsNewTransfer) {
1428 //
1429 // The delete request may happen after device is detached.
1430 //
1431 for (Index = 0; Index < 255; Index++) {
1432 if (Xhc->UsbDevContext[Index + 1].BusDevAddr == DeviceAddress) {
1433 break;
1434 }
1435 }
1436
1437 if (Index == 255) {
1438 Status = EFI_INVALID_PARAMETER;
1439 goto ON_EXIT;
1440 }
1441
1442 Status = XhciDelAsyncIntTransfer (Xhc, DeviceAddress, EndPointAddress);
1443 DEBUG ((DEBUG_INFO, "XhcAsyncInterruptTransfer: remove old transfer for addr %d, Status = %r\n", DeviceAddress, Status));
1444 goto ON_EXIT;
1445 }
1446
1447 Status = EFI_SUCCESS;
1448
1449 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
1450 DEBUG ((DEBUG_ERROR, "XhcAsyncInterruptTransfer: HC is halt\n"));
1451 Status = EFI_DEVICE_ERROR;
1452 goto ON_EXIT;
1453 }
1454
1455 //
1456 // Check if the device is still enabled before every transaction.
1457 //
1458 SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);
1459 if (SlotId == 0) {
1460 goto ON_EXIT;
1461 }
1462
1464 Xhc,
1465 DeviceAddress,
1466 EndPointAddress,
1467 DeviceSpeed,
1468 MaximumPacketLength,
1469 DataLength,
1470 CallBackFunction,
1471 Context
1472 );
1473 if (Urb == NULL) {
1474 Status = EFI_OUT_OF_RESOURCES;
1475 goto ON_EXIT;
1476 }
1477
1478 //
1479 // Ring the doorbell
1480 //
1481 Status = RingIntTransferDoorBell (Xhc, Urb);
1482
1483ON_EXIT:
1484 Xhc->PciIo->Flush (Xhc->PciIo);
1485 gBS->RestoreTPL (OldTpl);
1486
1487 return Status;
1488}
1489
1518EFIAPI
1521 IN UINT8 DeviceAddress,
1522 IN UINT8 EndPointAddress,
1523 IN UINT8 DeviceSpeed,
1524 IN UINTN MaximumPacketLength,
1525 IN OUT VOID *Data,
1526 IN OUT UINTN *DataLength,
1527 IN OUT UINT8 *DataToggle,
1528 IN UINTN Timeout,
1530 OUT UINT32 *TransferResult
1531 )
1532{
1533 USB_XHCI_INSTANCE *Xhc;
1534 UINT8 SlotId;
1535 EFI_STATUS Status;
1536 EFI_TPL OldTpl;
1537
1538 //
1539 // Validates parameters
1540 //
1541 if ((DataLength == NULL) || (*DataLength == 0) ||
1542 (Data == NULL) || (TransferResult == NULL))
1543 {
1544 return EFI_INVALID_PARAMETER;
1545 }
1546
1547 if ((*DataToggle != 1) && (*DataToggle != 0)) {
1548 return EFI_INVALID_PARAMETER;
1549 }
1550
1551 if (((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) ||
1552 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
1553 ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 3072)))
1554 {
1555 return EFI_INVALID_PARAMETER;
1556 }
1557
1558 OldTpl = gBS->RaiseTPL (XHC_TPL);
1559
1560 Xhc = XHC_FROM_THIS (This);
1561
1562 *TransferResult = EFI_USB_ERR_SYSTEM;
1563 Status = EFI_DEVICE_ERROR;
1564
1565 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
1566 DEBUG ((DEBUG_ERROR, "EhcSyncInterruptTransfer: HC is halt\n"));
1567 goto ON_EXIT;
1568 }
1569
1570 //
1571 // Check if the device is still enabled before every transaction.
1572 //
1573 SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);
1574 if (SlotId == 0) {
1575 goto ON_EXIT;
1576 }
1577
1578 Status = XhcTransfer (
1579 Xhc,
1580 DeviceAddress,
1581 EndPointAddress,
1582 DeviceSpeed,
1583 MaximumPacketLength,
1584 XHC_INT_TRANSFER_SYNC,
1585 NULL,
1586 Data,
1587 DataLength,
1588 Timeout,
1589 TransferResult
1590 );
1591
1592ON_EXIT:
1593 if (EFI_ERROR (Status)) {
1594 DEBUG ((DEBUG_ERROR, "XhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
1595 }
1596
1597 gBS->RestoreTPL (OldTpl);
1598
1599 return Status;
1600}
1601
1624EFIAPI
1627 IN UINT8 DeviceAddress,
1628 IN UINT8 EndPointAddress,
1629 IN UINT8 DeviceSpeed,
1630 IN UINTN MaximumPacketLength,
1631 IN UINT8 DataBuffersNumber,
1632 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1633 IN UINTN DataLength,
1635 OUT UINT32 *TransferResult
1636 )
1637{
1638 return EFI_UNSUPPORTED;
1639}
1640
1665EFIAPI
1668 IN UINT8 DeviceAddress,
1669 IN UINT8 EndPointAddress,
1670 IN UINT8 DeviceSpeed,
1671 IN UINTN MaximumPacketLength,
1672 IN UINT8 DataBuffersNumber,
1673 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1674 IN UINTN DataLength,
1676 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
1677 IN VOID *Context
1678 )
1679{
1680 return EFI_UNSUPPORTED;
1681}
1682
1694EFIAPI
1696 IN EFI_HANDLE ImageHandle,
1697 IN EFI_SYSTEM_TABLE *SystemTable
1698 )
1699{
1701 ImageHandle,
1702 SystemTable,
1703 &gXhciDriverBinding,
1704 ImageHandle,
1705 &gXhciComponentName,
1706 &gXhciComponentName2
1707 );
1708}
1709
1724EFIAPI
1727 IN EFI_HANDLE Controller,
1728 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1729 )
1730{
1731 EFI_STATUS Status;
1732 EFI_PCI_IO_PROTOCOL *PciIo;
1733 USB_CLASSC UsbClassCReg;
1734
1735 //
1736 // Test whether there is PCI IO Protocol attached on the controller handle.
1737 //
1738 Status = gBS->OpenProtocol (
1739 Controller,
1740 &gEfiPciIoProtocolGuid,
1741 (VOID **)&PciIo,
1742 This->DriverBindingHandle,
1743 Controller,
1744 EFI_OPEN_PROTOCOL_BY_DRIVER
1745 );
1746
1747 if (EFI_ERROR (Status)) {
1748 return EFI_UNSUPPORTED;
1749 }
1750
1751 Status = PciIo->Pci.Read (
1752 PciIo,
1753 EfiPciIoWidthUint8,
1754 PCI_CLASSCODE_OFFSET,
1755 sizeof (USB_CLASSC) / sizeof (UINT8),
1756 &UsbClassCReg
1757 );
1758
1759 if (EFI_ERROR (Status)) {
1760 Status = EFI_UNSUPPORTED;
1761 goto ON_EXIT;
1762 }
1763
1764 //
1765 // Test whether the controller belongs to Xhci type
1766 //
1767 if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||
1768 (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||
1769 (UsbClassCReg.ProgInterface != PCI_IF_XHCI))
1770 {
1771 Status = EFI_UNSUPPORTED;
1772 }
1773
1774ON_EXIT:
1775 gBS->CloseProtocol (
1776 Controller,
1777 &gEfiPciIoProtocolGuid,
1778 This->DriverBindingHandle,
1779 Controller
1780 );
1781
1782 return Status;
1783}
1784
1798 IN EFI_PCI_IO_PROTOCOL *PciIo,
1799 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1800 IN UINT64 OriginalPciAttributes
1801 )
1802{
1803 USB_XHCI_INSTANCE *Xhc;
1804 EFI_STATUS Status;
1805 UINT32 PageSize;
1806 UINT16 ExtCapReg;
1807 UINT8 ReleaseNumber;
1808
1809 Xhc = AllocateZeroPool (sizeof (USB_XHCI_INSTANCE));
1810
1811 if (Xhc == NULL) {
1812 return NULL;
1813 }
1814
1815 //
1816 // Initialize private data structure
1817 //
1818 Xhc->Signature = XHCI_INSTANCE_SIG;
1819 Xhc->PciIo = PciIo;
1820 Xhc->DevicePath = DevicePath;
1821 Xhc->OriginalPciAttributes = OriginalPciAttributes;
1822 CopyMem (&Xhc->Usb2Hc, &gXhciUsb2HcTemplate, sizeof (EFI_USB2_HC_PROTOCOL));
1823
1824 Status = PciIo->Pci.Read (
1825 PciIo,
1826 EfiPciIoWidthUint8,
1827 XHC_PCI_SBRN_OFFSET,
1828 1,
1829 &ReleaseNumber
1830 );
1831
1832 if (!EFI_ERROR (Status)) {
1833 Xhc->Usb2Hc.MajorRevision = (ReleaseNumber & 0xF0) >> 4;
1834 Xhc->Usb2Hc.MinorRevision = (ReleaseNumber & 0x0F);
1835 }
1836
1837 InitializeListHead (&Xhc->AsyncIntTransfers);
1838
1839 //
1840 // Be caution that the Offset passed to XhcReadCapReg() should be Dword align
1841 //
1842 Xhc->CapLength = XhcReadCapReg8 (Xhc, XHC_CAPLENGTH_OFFSET);
1843 Xhc->HcSParams1.Dword = XhcReadCapReg (Xhc, XHC_HCSPARAMS1_OFFSET);
1844 Xhc->HcSParams2.Dword = XhcReadCapReg (Xhc, XHC_HCSPARAMS2_OFFSET);
1845 Xhc->HcCParams.Dword = XhcReadCapReg (Xhc, XHC_HCCPARAMS_OFFSET);
1846 Xhc->DBOff = XhcReadCapReg (Xhc, XHC_DBOFF_OFFSET);
1847 Xhc->RTSOff = XhcReadCapReg (Xhc, XHC_RTSOFF_OFFSET);
1848
1849 //
1850 // This PageSize field defines the page size supported by the xHC implementation.
1851 // This xHC supports a page size of 2^(n+12) if bit n is Set. For example,
1852 // if bit 0 is Set, the xHC supports 4k byte page sizes.
1853 //
1854 PageSize = XhcReadOpReg (Xhc, XHC_PAGESIZE_OFFSET);
1855 if ((PageSize & (~XHC_PAGESIZE_MASK)) != 0) {
1856 DEBUG ((DEBUG_ERROR, "XhcCreateUsb3Hc: Reserved bits are not 0 for PageSize\n"));
1857 goto ON_ERROR;
1858 }
1859
1860 PageSize &= XHC_PAGESIZE_MASK;
1861 Xhc->PageSize = 1 << (HighBitSet32 (PageSize) + 12);
1862
1863 ExtCapReg = (UINT16)(Xhc->HcCParams.Data.ExtCapReg);
1864 Xhc->ExtCapRegBase = ExtCapReg << 2;
1865 Xhc->UsbLegSupOffset = XhcGetCapabilityAddr (Xhc, XHC_CAP_USB_LEGACY);
1866 Xhc->DebugCapSupOffset = XhcGetCapabilityAddr (Xhc, XHC_CAP_USB_DEBUG);
1867 Xhc->Usb2SupOffset = XhcGetSupportedProtocolCapabilityAddr (Xhc, XHC_SUPPORTED_PROTOCOL_DW0_MAJOR_REVISION_USB2);
1868 Xhc->Usb3SupOffset = XhcGetSupportedProtocolCapabilityAddr (Xhc, XHC_SUPPORTED_PROTOCOL_DW0_MAJOR_REVISION_USB3);
1869
1870 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: Capability length 0x%x\n", Xhc->CapLength));
1871 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: HcSParams1 0x%x\n", Xhc->HcSParams1));
1872 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: HcSParams2 0x%x\n", Xhc->HcSParams2));
1873 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: HcCParams 0x%x\n", Xhc->HcCParams));
1874 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: DBOff 0x%x\n", Xhc->DBOff));
1875 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: RTSOff 0x%x\n", Xhc->RTSOff));
1876 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: UsbLegSupOffset 0x%x\n", Xhc->UsbLegSupOffset));
1877 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: DebugCapSupOffset 0x%x\n", Xhc->DebugCapSupOffset));
1878 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: Usb2SupOffset 0x%x\n", Xhc->Usb2SupOffset));
1879 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: Usb3SupOffset 0x%x\n", Xhc->Usb3SupOffset));
1880
1881 //
1882 // Create AsyncRequest Polling Timer
1883 //
1884 Status = gBS->CreateEvent (
1885 EVT_TIMER | EVT_NOTIFY_SIGNAL,
1886 TPL_NOTIFY,
1888 Xhc,
1889 &Xhc->PollTimer
1890 );
1891
1892 if (EFI_ERROR (Status)) {
1893 goto ON_ERROR;
1894 }
1895
1896 return Xhc;
1897
1898ON_ERROR:
1899 FreePool (Xhc);
1900 return NULL;
1901}
1902
1910VOID
1911EFIAPI
1913 EFI_EVENT Event,
1914 VOID *Context
1915 )
1916
1917{
1918 USB_XHCI_INSTANCE *Xhc;
1919 EFI_PCI_IO_PROTOCOL *PciIo;
1920
1921 Xhc = (USB_XHCI_INSTANCE *)Context;
1922 PciIo = Xhc->PciIo;
1923
1924 //
1925 // Stop AsyncRequest Polling timer then stop the XHCI driver
1926 // and uninstall the XHCI protocl.
1927 //
1928 gBS->SetTimer (Xhc->PollTimer, TimerCancel, 0);
1929 XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
1930
1931 if (Xhc->PollTimer != NULL) {
1932 gBS->CloseEvent (Xhc->PollTimer);
1933 }
1934
1936
1937 //
1938 // Restore original PCI attributes
1939 //
1940 PciIo->Attributes (
1941 PciIo,
1943 Xhc->OriginalPciAttributes,
1944 NULL
1945 );
1946}
1947
1962EFIAPI
1965 IN EFI_HANDLE Controller,
1966 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1967 )
1968{
1969 EFI_STATUS Status;
1970 EFI_PCI_IO_PROTOCOL *PciIo;
1971 UINT64 Supports;
1972 UINT64 OriginalPciAttributes;
1973 BOOLEAN PciAttributesSaved;
1974 USB_XHCI_INSTANCE *Xhc;
1975 EFI_DEVICE_PATH_PROTOCOL *HcDevicePath;
1976
1977 //
1978 // Open the PciIo Protocol, then enable the USB host controller
1979 //
1980 Status = gBS->OpenProtocol (
1981 Controller,
1982 &gEfiPciIoProtocolGuid,
1983 (VOID **)&PciIo,
1984 This->DriverBindingHandle,
1985 Controller,
1986 EFI_OPEN_PROTOCOL_BY_DRIVER
1987 );
1988
1989 if (EFI_ERROR (Status)) {
1990 return Status;
1991 }
1992
1993 //
1994 // Open Device Path Protocol for on USB host controller
1995 //
1996 HcDevicePath = NULL;
1997 Status = gBS->OpenProtocol (
1998 Controller,
1999 &gEfiDevicePathProtocolGuid,
2000 (VOID **)&HcDevicePath,
2001 This->DriverBindingHandle,
2002 Controller,
2003 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2004 );
2005
2006 PciAttributesSaved = FALSE;
2007 //
2008 // Save original PCI attributes
2009 //
2010 Status = PciIo->Attributes (
2011 PciIo,
2013 0,
2014 &OriginalPciAttributes
2015 );
2016
2017 if (EFI_ERROR (Status)) {
2018 goto CLOSE_PCIIO;
2019 }
2020
2021 PciAttributesSaved = TRUE;
2022
2023 Status = PciIo->Attributes (
2024 PciIo,
2026 0,
2027 &Supports
2028 );
2029 if (!EFI_ERROR (Status)) {
2030 Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
2031 Status = PciIo->Attributes (
2032 PciIo,
2034 Supports,
2035 NULL
2036 );
2037 }
2038
2039 if (EFI_ERROR (Status)) {
2040 DEBUG ((DEBUG_ERROR, "XhcDriverBindingStart: failed to enable controller\n"));
2041 goto CLOSE_PCIIO;
2042 }
2043
2044 //
2045 // Create then install USB2_HC_PROTOCOL
2046 //
2047 Xhc = XhcCreateUsbHc (PciIo, HcDevicePath, OriginalPciAttributes);
2048
2049 if (Xhc == NULL) {
2050 DEBUG ((DEBUG_ERROR, "XhcDriverBindingStart: failed to create USB2_HC\n"));
2051 return EFI_OUT_OF_RESOURCES;
2052 }
2053
2054 //
2055 // Enable 64-bit DMA support in the PCI layer if this controller
2056 // supports it.
2057 //
2058 if (Xhc->HcCParams.Data.Ac64 != 0) {
2059 Status = PciIo->Attributes (
2060 PciIo,
2063 NULL
2064 );
2065 if (!EFI_ERROR (Status)) {
2066 Xhc->Support64BitDma = TRUE;
2067 } else {
2068 DEBUG ((
2069 DEBUG_WARN,
2070 "%a: failed to enable 64-bit DMA on 64-bit capable controller @ %p (%r)\n",
2071 __func__,
2072 Controller,
2073 Status
2074 ));
2075 }
2076 }
2077
2078 XhcSetBiosOwnership (Xhc);
2079
2080 Status = XhcResetHC (Xhc, XHC_RESET_TIMEOUT);
2081 if (EFI_ERROR (Status)) {
2082 DEBUG ((DEBUG_ERROR, "%a: failed to reset HC\n", __func__));
2083 goto FREE_POOL;
2084 }
2085
2086 ASSERT (XhcIsHalt (Xhc));
2087
2088 //
2089 // After Chip Hardware Reset wait until the Controller Not Ready (CNR) flag
2090 // in the USBSTS is '0' before writing any xHC Operational or Runtime registers.
2091 //
2092 ASSERT (!(XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_CNR)));
2093
2094 //
2095 // Initialize the schedule
2096 //
2097 XhcInitSched (Xhc);
2098
2099 //
2100 // Start the Host Controller
2101 //
2102 XhcRunHC (Xhc, XHC_GENERIC_TIMEOUT);
2103
2104 //
2105 // Start the asynchronous interrupt monitor
2106 //
2107 Status = gBS->SetTimer (Xhc->PollTimer, TimerPeriodic, XHC_ASYNC_TIMER_INTERVAL);
2108 if (EFI_ERROR (Status)) {
2109 DEBUG ((DEBUG_ERROR, "XhcDriverBindingStart: failed to start async interrupt monitor\n"));
2110 XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
2111 goto FREE_POOL;
2112 }
2113
2114 //
2115 // Create event to stop the HC when exit boot service.
2116 //
2117 Status = gBS->CreateEventEx (
2118 EVT_NOTIFY_SIGNAL,
2119 TPL_NOTIFY,
2121 Xhc,
2122 &gEfiEventExitBootServicesGuid,
2123 &Xhc->ExitBootServiceEvent
2124 );
2125 if (EFI_ERROR (Status)) {
2126 goto FREE_POOL;
2127 }
2128
2129 //
2130 // Install the component name protocol, don't fail the start
2131 // because of something for display.
2132 //
2134 "eng",
2135 gXhciComponentName.SupportedLanguages,
2136 &Xhc->ControllerNameTable,
2137 L"eXtensible Host Controller (USB 3.0)",
2138 TRUE
2139 );
2141 "en",
2142 gXhciComponentName2.SupportedLanguages,
2143 &Xhc->ControllerNameTable,
2144 L"eXtensible Host Controller (USB 3.0)",
2145 FALSE
2146 );
2147
2148 Status = gBS->InstallProtocolInterface (
2149 &Controller,
2150 &gEfiUsb2HcProtocolGuid,
2152 &Xhc->Usb2Hc
2153 );
2154 if (EFI_ERROR (Status)) {
2155 DEBUG ((DEBUG_ERROR, "XhcDriverBindingStart: failed to install USB2_HC Protocol\n"));
2156 goto FREE_POOL;
2157 }
2158
2159 DEBUG ((DEBUG_INFO, "XhcDriverBindingStart: XHCI started for controller @ %x\n", Controller));
2160 return EFI_SUCCESS;
2161
2162FREE_POOL:
2163 gBS->CloseEvent (Xhc->PollTimer);
2164 XhcFreeSched (Xhc);
2165 FreePool (Xhc);
2166
2167CLOSE_PCIIO:
2168 if (PciAttributesSaved) {
2169 //
2170 // Restore original PCI attributes
2171 //
2172 PciIo->Attributes (
2173 PciIo,
2175 OriginalPciAttributes,
2176 NULL
2177 );
2178 }
2179
2180 gBS->CloseProtocol (
2181 Controller,
2182 &gEfiPciIoProtocolGuid,
2183 This->DriverBindingHandle,
2184 Controller
2185 );
2186
2187 return Status;
2188}
2189
2204EFIAPI
2207 IN EFI_HANDLE Controller,
2208 IN UINTN NumberOfChildren,
2209 IN EFI_HANDLE *ChildHandleBuffer
2210 )
2211{
2212 EFI_STATUS Status;
2213 EFI_USB2_HC_PROTOCOL *Usb2Hc;
2214 EFI_PCI_IO_PROTOCOL *PciIo;
2215 USB_XHCI_INSTANCE *Xhc;
2216 UINT8 Index;
2217
2218 //
2219 // Test whether the Controller handler passed in is a valid
2220 // Usb controller handle that should be supported, if not,
2221 // return the error status directly
2222 //
2223 Status = gBS->OpenProtocol (
2224 Controller,
2225 &gEfiUsb2HcProtocolGuid,
2226 (VOID **)&Usb2Hc,
2227 This->DriverBindingHandle,
2228 Controller,
2229 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2230 );
2231
2232 if (EFI_ERROR (Status)) {
2233 return Status;
2234 }
2235
2236 Status = gBS->UninstallProtocolInterface (
2237 Controller,
2238 &gEfiUsb2HcProtocolGuid,
2239 Usb2Hc
2240 );
2241
2242 if (EFI_ERROR (Status)) {
2243 return Status;
2244 }
2245
2246 Xhc = XHC_FROM_THIS (Usb2Hc);
2247 PciIo = Xhc->PciIo;
2248
2249 //
2250 // Stop AsyncRequest Polling timer then stop the XHCI driver
2251 // and uninstall the XHCI protocl.
2252 //
2253 gBS->SetTimer (Xhc->PollTimer, TimerCancel, 0);
2254
2255 //
2256 // Disable the device slots occupied by these devices on its downstream ports.
2257 // Entry 0 is reserved.
2258 //
2259 for (Index = 0; Index < 255; Index++) {
2260 if (!Xhc->UsbDevContext[Index + 1].Enabled ||
2261 (Xhc->UsbDevContext[Index + 1].SlotId == 0))
2262 {
2263 continue;
2264 }
2265
2266 if (Xhc->HcCParams.Data.Csz == 0) {
2267 XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
2268 } else {
2269 XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
2270 }
2271 }
2272
2273 if (Xhc->PollTimer != NULL) {
2274 gBS->CloseEvent (Xhc->PollTimer);
2275 }
2276
2277 if (Xhc->ExitBootServiceEvent != NULL) {
2278 gBS->CloseEvent (Xhc->ExitBootServiceEvent);
2279 }
2280
2281 XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
2284 XhcFreeSched (Xhc);
2285
2286 if (Xhc->ControllerNameTable) {
2287 FreeUnicodeStringTable (Xhc->ControllerNameTable);
2288 }
2289
2290 //
2291 // Restore original PCI attributes
2292 //
2293 PciIo->Attributes (
2294 PciIo,
2296 Xhc->OriginalPciAttributes,
2297 NULL
2298 );
2299
2300 gBS->CloseProtocol (
2301 Controller,
2302 &gEfiPciIoProtocolGuid,
2303 This->DriverBindingHandle,
2304 Controller
2305 );
2306
2307 FreePool (Xhc);
2308
2309 return EFI_SUCCESS;
2310}
2311
2318UINT64
2320 IN UINT64 Time
2321 )
2322{
2323 UINT64 Ticks;
2324 UINT64 Remainder;
2325 UINT64 Divisor;
2326 UINTN Shift;
2327
2328 // Cache the return values to avoid repeated calls to GetPerformanceCounterProperties ()
2329 if (!mXhciPerformanceCounterValuesCached) {
2330 mXhciPerformanceCounterFrequency = GetPerformanceCounterProperties (
2331 &mXhciPerformanceCounterStartValue,
2332 &mXhciPerformanceCounterEndValue
2333 );
2334
2335 mXhciPerformanceCounterValuesCached = TRUE;
2336 }
2337
2338 // Prevent returning a tick value of 0, unless Time is already 0
2339 if (0 == mXhciPerformanceCounterFrequency) {
2340 return Time;
2341 }
2342
2343 // Nanoseconds per second
2344 Divisor = 1000000000;
2345
2346 //
2347 // Frequency
2348 // Ticks = ------------- x Time
2349 // 1,000,000,000
2350 //
2351 Ticks = MultU64x64 (
2353 mXhciPerformanceCounterFrequency,
2354 Divisor,
2355 &Remainder
2356 ),
2357 Time
2358 );
2359
2360 //
2361 // Ensure (Remainder * Time) will not overflow 64-bit.
2362 //
2363 // HighBitSet64 (Remainder) + 1 + HighBitSet64 (Time) + 1 <= 64
2364 //
2365 Shift = MAX (0, HighBitSet64 (Remainder) + HighBitSet64 (Time) - 62);
2366 Remainder = RShiftU64 (Remainder, (UINTN)Shift);
2367 Divisor = RShiftU64 (Divisor, (UINTN)Shift);
2368 Ticks += DivU64x64Remainder (MultU64x64 (Remainder, Time), Divisor, NULL);
2369
2370 return Ticks;
2371}
2372
2382UINT64
2384 IN OUT UINT64 *PreviousTick
2385 )
2386{
2387 UINT64 CurrentTick;
2388 UINT64 Delta;
2389
2390 CurrentTick = GetPerformanceCounter ();
2391
2392 //
2393 // Determine if the counter is counting up or down
2394 //
2395 if (mXhciPerformanceCounterStartValue < mXhciPerformanceCounterEndValue) {
2396 //
2397 // Counter counts upwards, check for an overflow condition
2398 //
2399 if (*PreviousTick > CurrentTick) {
2400 Delta = (mXhciPerformanceCounterEndValue - *PreviousTick) + CurrentTick;
2401 } else {
2402 Delta = CurrentTick - *PreviousTick;
2403 }
2404 } else {
2405 //
2406 // Counter counts downwards, check for an underflow condition
2407 //
2408 if (*PreviousTick < CurrentTick) {
2409 Delta = (mXhciPerformanceCounterStartValue - CurrentTick) + *PreviousTick;
2410 } else {
2411 Delta = *PreviousTick - CurrentTick;
2412 }
2413 }
2414
2415 //
2416 // Set PreviousTick to CurrentTick
2417 //
2418 *PreviousTick = CurrentTick;
2419
2420 return Delta;
2421}
UINT64 UINTN
UINT64 EFIAPI GetPerformanceCounterProperties(OUT UINT64 *StartValue OPTIONAL, OUT UINT64 *EndValue OPTIONAL)
UINT64 EFIAPI GetPerformanceCounter(VOID)
UINT64 EFIAPI MultU64x64(IN UINT64 Multiplicand, IN UINT64 Multiplier)
Definition: MultU64x64.c:27
UINT64 EFIAPI RShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: RShiftU64.c:28
UINT64 EFIAPI DivU64x64Remainder(IN UINT64 Dividend, IN UINT64 Divisor, OUT UINT64 *Remainder OPTIONAL)
LIST_ENTRY *EFIAPI InitializeListHead(IN OUT LIST_ENTRY *ListHead)
Definition: LinkedList.c:182
INTN EFIAPI HighBitSet64(IN UINT64 Operand)
Definition: HighBitSet64.c:27
INTN EFIAPI HighBitSet32(IN UINT32 Operand)
Definition: HighBitSet32.c:27
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define MAX(a, b)
Definition: Base.h:992
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define REPORT_STATUS_CODE_WITH_DEVICE_PATH(Type, Value, DevicePathParameter)
#define EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
Clear for PCI controllers that can not genrate a DAC.
Definition: PciIo.h:64
@ EfiPciIoAttributeOperationGet
Definition: PciIo.h:103
@ EfiPciIoAttributeOperationEnable
Definition: PciIo.h:111
@ EfiPciIoAttributeOperationSet
Definition: PciIo.h:107
@ EfiPciIoAttributeOperationSupported
Definition: PciIo.h:119
EFI_USB_PORT_FEATURE
#define USB_PORT_STAT_C_CONNECTION
#define EFI_USB_SPEED_SUPER
4.8 Gb/s, USB 3.0 XHCI HC.
EFI_USB_HC_STATE
@ EfiUsbHcStateHalt
@ EfiUsbHcStateOperational
@ EfiUsbHcStateSuspend
#define USB_PORT_STAT_CONNECTION
EFI_USB_DATA_DIRECTION
Definition: UsbIo.h:44
EFI_STATUS(EFIAPI * EFI_ASYNC_USB_TRANSFER_CALLBACK)(IN VOID *Data, IN UINTN DataLength, IN VOID *Context, IN UINT32 Status)
Definition: UsbIo.h:80
#define EFI_PROGRESS_CODE
Definition: PiStatusCode.h:43
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
UINTN EFI_TPL
Definition: UefiBaseType.h:41
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
EFI_STATUS EFIAPI AddUnicodeString2(IN CONST CHAR8 *Language, IN CONST CHAR8 *SupportedLanguages, IN OUT EFI_UNICODE_STRING_TABLE **UnicodeStringTable, IN CONST CHAR16 *UnicodeString, IN BOOLEAN Iso639Language)
Definition: UefiLib.c:1087
EFI_STATUS EFIAPI EfiLibInstallDriverBindingComponentName2(IN CONST EFI_HANDLE ImageHandle, IN CONST EFI_SYSTEM_TABLE *SystemTable, IN EFI_DRIVER_BINDING_PROTOCOL *DriverBinding, IN EFI_HANDLE DriverBindingHandle, IN CONST EFI_COMPONENT_NAME_PROTOCOL *ComponentName OPTIONAL, IN CONST EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2 OPTIONAL)
EFI_STATUS EFIAPI FreeUnicodeStringTable(IN EFI_UNICODE_STRING_TABLE *UnicodeStringTable)
Definition: UefiLib.c:1257
@ EFI_NATIVE_INTERFACE
Definition: UefiSpec.h:1193
@ TimerCancel
Definition: UefiSpec.h:531
@ TimerPeriodic
Definition: UefiSpec.h:535
EFI_STATUS EFIAPI XhcDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath)
Definition: Xhci.c:1725
EFI_STATUS EFIAPI XhcSetRootHubPortFeature(IN EFI_USB2_HC_PROTOCOL *This, IN UINT8 PortNumber, IN EFI_USB_PORT_FEATURE PortFeature)
Definition: Xhci.c:510
EFI_STATUS EFIAPI XhcReset(IN EFI_USB2_HC_PROTOCOL *This, IN UINT16 Attributes)
Definition: Xhci.c:151
EFI_STATUS EFIAPI XhcAsyncIsochronousTransfer(IN EFI_USB2_HC_PROTOCOL *This, IN UINT8 DeviceAddress, IN UINT8 EndPointAddress, IN UINT8 DeviceSpeed, IN UINTN MaximumPacketLength, IN UINT8 DataBuffersNumber, IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM], IN UINTN DataLength, IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack, IN VOID *Context)
Definition: Xhci.c:1666
EFI_STATUS EFIAPI XhcControlTransfer(IN EFI_USB2_HC_PROTOCOL *This, IN UINT8 DeviceAddress, IN UINT8 DeviceSpeed, IN UINTN MaximumPacketLength, IN EFI_USB_DEVICE_REQUEST *Request, IN EFI_USB_DATA_DIRECTION TransferDirection, IN OUT VOID *Data, IN OUT UINTN *DataLength, IN UINTN Timeout, IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, OUT UINT32 *TransferResult)
Definition: Xhci.c:870
EFI_STATUS EFIAPI XhcGetRootHubPortStatus(IN EFI_USB2_HC_PROTOCOL *This, IN UINT8 PortNumber, OUT EFI_USB_PORT_STATUS *PortStatus)
Definition: Xhci.c:368
EFI_STATUS EFIAPI XhcDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath)
Definition: Xhci.c:1963
UINT64 XhcGetElapsedTicks(IN OUT UINT64 *PreviousTick)
Definition: Xhci.c:2383
EFI_STATUS EFIAPI XhcSetState(IN EFI_USB2_HC_PROTOCOL *This, IN EFI_USB_HC_STATE State)
Definition: Xhci.c:290
EFI_STATUS EFIAPI XhcClearRootHubPortFeature(IN EFI_USB2_HC_PROTOCOL *This, IN UINT8 PortNumber, IN EFI_USB_PORT_FEATURE PortFeature)
Definition: Xhci.c:626
EFI_STATUS EFIAPI XhcGetCapability(IN EFI_USB2_HC_PROTOCOL *This, OUT UINT8 *MaxSpeed, OUT UINT8 *PortNumber, OUT UINT8 *Is64BitCapable)
Definition: Xhci.c:109
EFI_STATUS EFIAPI XhcIsochronousTransfer(IN EFI_USB2_HC_PROTOCOL *This, IN UINT8 DeviceAddress, IN UINT8 EndPointAddress, IN UINT8 DeviceSpeed, IN UINTN MaximumPacketLength, IN UINT8 DataBuffersNumber, IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM], IN UINTN DataLength, IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, OUT UINT32 *TransferResult)
Definition: Xhci.c:1625
EFI_STATUS EFIAPI XhcAsyncInterruptTransfer(IN EFI_USB2_HC_PROTOCOL *This, IN UINT8 DeviceAddress, IN UINT8 EndPointAddress, IN UINT8 DeviceSpeed, IN UINTN MaximumPacketLength, IN BOOLEAN IsNewTransfer, IN OUT UINT8 *DataToggle, IN UINTN PollingInterval, IN UINTN DataLength, IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction, IN VOID *Context OPTIONAL)
Definition: Xhci.c:1377
EFI_STATUS EFIAPI XhcGetState(IN EFI_USB2_HC_PROTOCOL *This, OUT EFI_USB_HC_STATE *State)
Definition: Xhci.c:248
USB_XHCI_INSTANCE * XhcCreateUsbHc(IN EFI_PCI_IO_PROTOCOL *PciIo, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN UINT64 OriginalPciAttributes)
Definition: Xhci.c:1797
VOID EFIAPI XhcExitBootService(EFI_EVENT Event, VOID *Context)
Definition: Xhci.c:1912
EFI_STATUS EFIAPI XhcDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer)
Definition: Xhci.c:2205
EFI_STATUS EFIAPI XhcSyncInterruptTransfer(IN EFI_USB2_HC_PROTOCOL *This, IN UINT8 DeviceAddress, IN UINT8 EndPointAddress, IN UINT8 DeviceSpeed, IN UINTN MaximumPacketLength, IN OUT VOID *Data, IN OUT UINTN *DataLength, IN OUT UINT8 *DataToggle, IN UINTN Timeout, IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, OUT UINT32 *TransferResult)
Definition: Xhci.c:1519
EFI_STATUS XhcTransfer(IN USB_XHCI_INSTANCE *Xhc, IN UINT8 DeviceAddress, IN UINT8 EndPointAddress, IN UINT8 DeviceSpeed, IN UINTN MaximumPacketLength, IN UINTN Type, IN EFI_USB_DEVICE_REQUEST *Request, IN OUT VOID *Data, IN OUT UINTN *DataLength, IN UINTN Timeout, OUT UINT32 *TransferResult)
Definition: Xhci.c:767
UINT64 XhcConvertTimeToTicks(IN UINT64 Time)
Definition: Xhci.c:2319
EFI_STATUS EFIAPI XhcBulkTransfer(IN EFI_USB2_HC_PROTOCOL *This, IN UINT8 DeviceAddress, IN UINT8 EndPointAddress, IN UINT8 DeviceSpeed, IN UINTN MaximumPacketLength, IN UINT8 DataBuffersNumber, IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM], IN OUT UINTN *DataLength, IN OUT UINT8 *DataToggle, IN UINTN Timeout, IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, OUT UINT32 *TransferResult)
Definition: Xhci.c:1250
EFI_STATUS EFIAPI XhcDriverEntryPoint(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
Definition: Xhci.c:1695
EFI_STATUS EFIAPI XhcSetConfigCmd64(IN USB_XHCI_INSTANCE *Xhc, IN UINT8 SlotId, IN UINT8 DeviceSpeed, IN USB_CONFIG_DESCRIPTOR *ConfigDesc)
Definition: XhciSched.c:3323
URB * XhciInsertAsyncIntTransfer(IN USB_XHCI_INSTANCE *Xhc, IN UINT8 BusAddr, IN UINT8 EpAddr, IN UINT8 DevSpeed, IN UINTN MaxPacket, IN UINTN DataLen, IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback, IN VOID *Context)
Definition: XhciSched.c:1474
EFI_STATUS EFIAPI XhcDisableSlotCmd(IN USB_XHCI_INSTANCE *Xhc, IN UINT8 SlotId)
Definition: XhciSched.c:2596
VOID XhciDelAllAsyncIntTransfers(IN USB_XHCI_INSTANCE *Xhc)
Definition: XhciSched.c:1430
VOID XhcFreeUrb(IN USB_XHCI_INSTANCE *Xhc, IN URB *Urb)
Definition: XhciSched.c:192
EFI_STATUS XhciDelAsyncIntTransfer(IN USB_XHCI_INSTANCE *Xhc, IN UINT8 BusAddr, IN UINT8 EpNum)
Definition: XhciSched.c:1381
EFI_STATUS XhcConfigHubContext64(IN USB_XHCI_INSTANCE *Xhc, IN UINT8 SlotId, IN UINT8 PortNum, IN UINT8 TTT, IN UINT8 MTT)
Definition: XhciSched.c:4204
VOID XhcFreeSched(IN USB_XHCI_INSTANCE *Xhc)
Definition: XhciSched.c:967
EFI_STATUS EFIAPI XhcSetInterface64(IN USB_XHCI_INSTANCE *Xhc, IN UINT8 SlotId, IN UINT8 DeviceSpeed, IN USB_CONFIG_DESCRIPTOR *ConfigDesc, IN EFI_USB_DEVICE_REQUEST *Request)
Definition: XhciSched.c:3802
EFI_STATUS EFIAPI XhcRecoverHaltedEndpoint(IN USB_XHCI_INSTANCE *Xhc, IN URB *Urb)
Definition: XhciSched.c:661
VOID EFIAPI XhcMonitorAsyncRequests(IN EFI_EVENT Event, IN VOID *Context)
Definition: XhciSched.c:1614
EFI_STATUS EFIAPI XhcDequeueTrbFromEndpoint(IN USB_XHCI_INSTANCE *Xhc, IN URB *Urb)
Definition: XhciSched.c:724
EFI_STATUS EFIAPI XhcEvaluateContext64(IN USB_XHCI_INSTANCE *Xhc, IN UINT8 SlotId, IN UINT32 MaxPacketSize)
Definition: XhciSched.c:4070
URB * XhcCreateUrb(IN USB_XHCI_INSTANCE *Xhc, IN UINT8 BusAddr, IN UINT8 EpAddr, IN UINT8 DevSpeed, IN UINTN MaxPacket, IN UINTN Type, IN EFI_USB_DEVICE_REQUEST *Request, IN VOID *Data, IN UINTN DataLen, IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback, IN VOID *Context)
Definition: XhciSched.c:134
VOID XhcInitSched(IN USB_XHCI_INSTANCE *Xhc)
Definition: XhciSched.c:475
EFI_STATUS RingIntTransferDoorBell(IN USB_XHCI_INSTANCE *Xhc, IN URB *Urb)
Definition: XhciSched.c:2099
EFI_STATUS XhcConfigHubContext(IN USB_XHCI_INSTANCE *Xhc, IN UINT8 SlotId, IN UINT8 PortNum, IN UINT8 TTT, IN UINT8 MTT)
Definition: XhciSched.c:4134
EFI_STATUS EFIAPI XhcEvaluateContext(IN USB_XHCI_INSTANCE *Xhc, IN UINT8 SlotId, IN UINT32 MaxPacketSize)
Definition: XhciSched.c:4007
EFI_STATUS XhcExecTransfer(IN USB_XHCI_INSTANCE *Xhc, IN BOOLEAN CmdTransfer, IN URB *Urb, IN UINTN Timeout)
Definition: XhciSched.c:1294
EFI_STATUS EFIAPI XhcSetConfigCmd(IN USB_XHCI_INSTANCE *Xhc, IN UINT8 SlotId, IN UINT8 DeviceSpeed, IN USB_CONFIG_DESCRIPTOR *ConfigDesc)
Definition: XhciSched.c:3230
EFI_STATUS EFIAPI XhcDisableSlotCmd64(IN USB_XHCI_INSTANCE *Xhc, IN UINT8 SlotId)
Definition: XhciSched.c:2709
UINT8 EFIAPI XhcBusDevAddrToSlotId(IN USB_XHCI_INSTANCE *Xhc, IN UINT8 BusDevAddr)
Definition: XhciSched.c:1853
EFI_STATUS EFIAPI XhcPollPortStatusChange(IN USB_XHCI_INSTANCE *Xhc, IN USB_DEV_ROUTE ParentRouteChart, IN UINT8 Port, IN EFI_USB_PORT_STATUS *PortState)
Definition: XhciSched.c:1727
EFI_STATUS EFIAPI XhcSetInterface(IN USB_XHCI_INSTANCE *Xhc, IN UINT8 SlotId, IN UINT8 DeviceSpeed, IN USB_CONFIG_DESCRIPTOR *ConfigDesc, IN EFI_USB_DEVICE_REQUEST *Request)
Definition: XhciSched.c:3595
EFI_STATUS XhcResetHC(IN USB_XHCI_INSTANCE *Xhc, IN UINT32 Timeout)
Definition: XhciReg.c:839
BOOLEAN XhcIsSysError(IN USB_XHCI_INSTANCE *Xhc)
Definition: XhciReg.c:788
EFI_STATUS XhcRunHC(IN USB_XHCI_INSTANCE *Xhc, IN UINT32 Timeout)
Definition: XhciReg.c:918
UINT32 XhcGetCapabilityAddr(IN USB_XHCI_INSTANCE *Xhc, IN UINT8 CapId)
Definition: XhciReg.c:530
VOID XhcClearBiosOwnership(IN USB_XHCI_INSTANCE *Xhc)
Definition: XhciReg.c:503
EFI_STATUS XhcHaltHC(IN USB_XHCI_INSTANCE *Xhc, IN UINT32 Timeout)
Definition: XhciReg.c:895
UINT16 XhcCheckUsbPortSpeedUsedPsic(IN USB_XHCI_INSTANCE *Xhc, IN UINT8 PortSpeed, IN UINT8 PortNumber)
Definition: XhciReg.c:690
UINT32 XhcReadExtCapReg(IN USB_XHCI_INSTANCE *Xhc, IN UINT32 Offset)
Definition: XhciReg.c:271
VOID XhcWriteOpReg(IN USB_XHCI_INSTANCE *Xhc, IN UINT32 Offset, IN UINT32 Data)
Definition: XhciReg.c:134
VOID XhcSetBiosOwnership(IN USB_XHCI_INSTANCE *Xhc)
Definition: XhciReg.c:479
UINT32 XhcGetSupportedProtocolCapabilityAddr(IN USB_XHCI_INSTANCE *Xhc, IN UINT8 MajorVersion)
Definition: XhciReg.c:570
UINT32 XhcReadCapReg(IN USB_XHCI_INSTANCE *Xhc, IN UINT32 Offset)
Definition: XhciReg.c:62
UINT32 XhcReadOpReg(IN USB_XHCI_INSTANCE *Xhc, IN UINT32 Offset)
Definition: XhciReg.c:98
BOOLEAN XhcIsHalt(IN USB_XHCI_INSTANCE *Xhc)
Definition: XhciReg.c:771
UINT8 XhcReadCapReg8(IN USB_XHCI_INSTANCE *Xhc, IN UINT32 Offset)
Definition: XhciReg.c:24
EFI_STATUS XhcWaitOpRegBit(IN USB_XHCI_INSTANCE *Xhc, IN UINT32 Offset, IN UINT32 Bit, IN BOOLEAN WaitToSet, IN UINT32 Timeout)
Definition: XhciReg.c:434
Definition: EhciUrb.h:200
UINT8 CapLength
Capability Register Length.
Definition: Xhci.h:222
XHC_HCSPARAMS2 HcSParams2
Structural Parameters 2.
Definition: Xhci.h:224
UINT32 DBOff
Doorbell Offset.
Definition: Xhci.h:226
XHC_HCCPARAMS HcCParams
Capability Parameters.
Definition: Xhci.h:225
UINT32 RTSOff
Runtime Register Space Offset.
Definition: Xhci.h:227
XHC_HCSPARAMS1 HcSParams1
Structural Parameters 1.
Definition: Xhci.h:223
EFI_PCI_IO_PROTOCOL_CONFIG Read
Definition: PciIo.h:232
UINT16 PortChangeStatus
Contains current port status change bitmap.
UINT16 PortStatus
Contains current port status bitmap.