/** @file\r
The XHCI controller driver.\r
\r
-Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
Xhc = XHC_FROM_THIS (This);\r
*MaxSpeed = EFI_USB_SPEED_SUPER;\r
*PortNumber = (UINT8) (Xhc->HcSParams1.Data.MaxPorts);\r
- *Is64BitCapable = (UINT8) (Xhc->HcCParams.Data.Ac64);\r
+ *Is64BitCapable = (UINT8) Xhc->Support64BitDma;\r
DEBUG ((EFI_D_INFO, "XhcGetCapability: %d ports, 64 bit %d\n", *PortNumber, *Is64BitCapable));\r
\r
gBS->RestoreTPL (OldTpl);\r
EFI_TPL OldTpl;\r
\r
Xhc = XHC_FROM_THIS (This);\r
- \r
+\r
if (Xhc->DevicePath != NULL) {\r
//\r
// Report Status Code to indicate reset happens\r
(EFI_IO_BUS_USB | EFI_IOB_PC_RESET),\r
Xhc->DevicePath\r
);\r
- } \r
+ }\r
\r
OldTpl = gBS->RaiseTPL (XHC_TPL);\r
\r
State = XhcReadOpReg (Xhc, Offset);\r
\r
//\r
- // According to XHCI 1.0 spec, bit 10~13 of the root port status register identifies the speed of the attached device.\r
+ // According to XHCI 1.1 spec November 2017,\r
+ // bit 10~13 of the root port status register identifies the speed of the attached device.\r
//\r
switch ((State & XHC_PORTSC_PS) >> 10) {\r
case 2:\r
break;\r
\r
case 4:\r
+ case 5:\r
PortStatus->PortStatus |= USB_PORT_STAT_SUPER_SPEED;\r
break;\r
\r
return Status;\r
}\r
\r
+/**\r
+ Submits a new transaction to a target USB device.\r
+\r
+ @param Xhc The XHCI Instance.\r
+ @param DeviceAddress The target device address.\r
+ @param EndPointAddress Endpoint number and its direction encoded in bit 7\r
+ @param DeviceSpeed Target device speed.\r
+ @param MaximumPacketLength Maximum packet size the default control transfer\r
+ endpoint is capable of sending or receiving.\r
+ @param Type The transaction type.\r
+ @param Request USB device request to send.\r
+ @param Data Data buffer to be transmitted or received from USB\r
+ device.\r
+ @param DataLength The size (in bytes) of the data buffer.\r
+ @param Timeout Indicates the maximum timeout, in millisecond.\r
+ @param TransferResult Return the result of this control transfer.\r
+\r
+ @retval EFI_SUCCESS Transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_TIMEOUT Transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.\r
+**/\r
+EFI_STATUS\r
+XhcTransfer (\r
+ IN USB_XHCI_INSTANCE *Xhc,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN UINT8 DeviceSpeed,\r
+ IN UINTN MaximumPacketLength,\r
+ IN UINTN Type,\r
+ IN EFI_USB_DEVICE_REQUEST *Request,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN *DataLength,\r
+ IN UINTN Timeout,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_STATUS RecoveryStatus;\r
+ URB *Urb;\r
+\r
+ ASSERT ((Type == XHC_CTRL_TRANSFER) || (Type == XHC_BULK_TRANSFER) || (Type == XHC_INT_TRANSFER_SYNC));\r
+ Urb = XhcCreateUrb (\r
+ Xhc,\r
+ DeviceAddress,\r
+ EndPointAddress,\r
+ DeviceSpeed,\r
+ MaximumPacketLength,\r
+ Type,\r
+ Request,\r
+ Data,\r
+ *DataLength,\r
+ NULL,\r
+ NULL\r
+ );\r
+\r
+ if (Urb == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "XhcTransfer[Type=%d]: failed to create URB!\n", Type));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout);\r
+\r
+ if (Status == EFI_TIMEOUT) {\r
+ //\r
+ // The transfer timed out. Abort the transfer by dequeueing of the TD.\r
+ //\r
+ RecoveryStatus = XhcDequeueTrbFromEndpoint(Xhc, Urb);\r
+ if (RecoveryStatus == EFI_ALREADY_STARTED) {\r
+ //\r
+ // The URB is finished just before stopping endpoint.\r
+ // Change returning status from EFI_TIMEOUT to EFI_SUCCESS.\r
+ //\r
+ ASSERT (Urb->Result == EFI_USB_NOERROR);\r
+ Status = EFI_SUCCESS;\r
+ DEBUG ((DEBUG_ERROR, "XhcTransfer[Type=%d]: pending URB is finished, Length = %d.\n", Type, Urb->Completed));\r
+ } else if (EFI_ERROR(RecoveryStatus)) {\r
+ DEBUG((DEBUG_ERROR, "XhcTransfer[Type=%d]: XhcDequeueTrbFromEndpoint failed!\n", Type));\r
+ }\r
+ }\r
+\r
+ *TransferResult = Urb->Result;\r
+ *DataLength = Urb->Completed;\r
+\r
+ if ((*TransferResult == EFI_USB_ERR_STALL) || (*TransferResult == EFI_USB_ERR_BABBLE)) {\r
+ ASSERT (Status == EFI_DEVICE_ERROR);\r
+ RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
+ if (EFI_ERROR (RecoveryStatus)) {\r
+ DEBUG ((DEBUG_ERROR, "XhcTransfer[Type=%d]: XhcRecoverHaltedEndpoint failed!\n", Type));\r
+ }\r
+ }\r
+\r
+ Xhc->PciIo->Flush (Xhc->PciIo);\r
+ XhcFreeUrb (Xhc, Urb);\r
+ return Status;\r
+}\r
\r
/**\r
Submits control transfer to a target USB device.\r
)\r
{\r
USB_XHCI_INSTANCE *Xhc;\r
- URB *Urb;\r
UINT8 Endpoint;\r
UINT8 Index;\r
UINT8 DescriptorType;\r
EFI_USB_HUB_DESCRIPTOR *HubDesc;\r
EFI_TPL OldTpl;\r
EFI_STATUS Status;\r
- EFI_STATUS RecoveryStatus;\r
UINTN MapSize;\r
EFI_USB_PORT_STATUS PortStatus;\r
UINT32 State;\r
// combination of Ep addr and its direction.\r
//\r
Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));\r
- Urb = XhcCreateUrb (\r
- Xhc,\r
- DeviceAddress,\r
- Endpoint,\r
- DeviceSpeed,\r
- MaximumPacketLength,\r
- XHC_CTRL_TRANSFER,\r
- Request,\r
- Data,\r
- *DataLength,\r
- NULL,\r
- NULL\r
- );\r
+ Status = XhcTransfer (\r
+ Xhc,\r
+ DeviceAddress,\r
+ Endpoint,\r
+ DeviceSpeed,\r
+ MaximumPacketLength,\r
+ XHC_CTRL_TRANSFER,\r
+ Request,\r
+ Data,\r
+ DataLength,\r
+ Timeout,\r
+ TransferResult\r
+ );\r
\r
- if (Urb == NULL) {\r
- DEBUG ((EFI_D_ERROR, "XhcControlTransfer: failed to create URB"));\r
- Status = EFI_OUT_OF_RESOURCES;\r
+ if (EFI_ERROR (Status)) {\r
goto ON_EXIT;\r
}\r
\r
- Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout);\r
-\r
- //\r
- // Get the status from URB. The result is updated in XhcCheckUrbResult\r
- // which is called by XhcExecTransfer\r
- //\r
- *TransferResult = Urb->Result;\r
- *DataLength = Urb->Completed;\r
-\r
- if (Status == EFI_TIMEOUT) {\r
- //\r
- // The transfer timed out. Abort the transfer by dequeueing of the TD.\r
- //\r
- RecoveryStatus = XhcDequeueTrbFromEndpoint(Xhc, Urb);\r
- if (EFI_ERROR(RecoveryStatus)) {\r
- DEBUG((EFI_D_ERROR, "XhcControlTransfer: XhcDequeueTrbFromEndpoint failed\n"));\r
- }\r
- goto FREE_URB;\r
- } else {\r
- if (*TransferResult == EFI_USB_NOERROR) {\r
- Status = EFI_SUCCESS;\r
- } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
- RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
- if (EFI_ERROR (RecoveryStatus)) {\r
- DEBUG ((EFI_D_ERROR, "XhcControlTransfer: XhcRecoverHaltedEndpoint failed\n"));\r
- }\r
- Status = EFI_DEVICE_ERROR;\r
- goto FREE_URB;\r
- } else {\r
- goto FREE_URB;\r
- }\r
- }\r
-\r
- Xhc->PciIo->Flush (Xhc->PciIo);\r
- \r
- if (Urb->DataMap != NULL) {\r
- Status = Xhc->PciIo->Unmap (Xhc->PciIo, Urb->DataMap);\r
- ASSERT_EFI_ERROR (Status);\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto FREE_URB;\r
- } \r
- }\r
-\r
//\r
// Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.\r
// Hook Get_Status request form UsbBus as we need trace device attach/detach event happened at hub.\r
// Hook Set_Config request from UsbBus as we need configure device endpoint.\r
//\r
if ((Request->Request == USB_REQ_GET_DESCRIPTOR) &&\r
- ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)) || \r
+ ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)) ||\r
((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_DEVICE))))) {\r
DescriptorType = (UINT8)(Request->Value >> 8);\r
if ((DescriptorType == USB_DESC_TYPE_DEVICE) && ((*DataLength == sizeof (EFI_USB_DEVICE_DESCRIPTOR)) || ((DeviceSpeed == EFI_USB_SPEED_FULL) && (*DataLength == 8)))) {\r
ClearPortRequest.Length = 0;\r
\r
XhcControlTransfer (\r
- This, \r
+ This,\r
DeviceAddress,\r
DeviceSpeed,\r
MaximumPacketLength,\r
*(UINT32 *)Data = *(UINT32*)&PortStatus;\r
}\r
\r
-FREE_URB:\r
- FreePool (Urb);\r
-\r
ON_EXIT:\r
-\r
if (EFI_ERROR (Status)) {\r
DEBUG ((EFI_D_ERROR, "XhcControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
}\r
)\r
{\r
USB_XHCI_INSTANCE *Xhc;\r
- URB *Urb;\r
UINT8 SlotId;\r
EFI_STATUS Status;\r
- EFI_STATUS RecoveryStatus;\r
EFI_TPL OldTpl;\r
\r
//\r
// Create a new URB, insert it into the asynchronous\r
// schedule list, then poll the execution status.\r
//\r
- Urb = XhcCreateUrb (\r
- Xhc,\r
- DeviceAddress,\r
- EndPointAddress,\r
- DeviceSpeed,\r
- MaximumPacketLength,\r
- XHC_BULK_TRANSFER,\r
- NULL,\r
- Data[0],\r
- *DataLength,\r
- NULL,\r
- NULL\r
- );\r
-\r
- if (Urb == NULL) {\r
- DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: failed to create URB\n"));\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto ON_EXIT;\r
- }\r
-\r
- Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout);\r
-\r
- *TransferResult = Urb->Result;\r
- *DataLength = Urb->Completed;\r
-\r
- if (Status == EFI_TIMEOUT) {\r
- //\r
- // The transfer timed out. Abort the transfer by dequeueing of the TD.\r
- //\r
- RecoveryStatus = XhcDequeueTrbFromEndpoint(Xhc, Urb);\r
- if (EFI_ERROR(RecoveryStatus)) {\r
- DEBUG((EFI_D_ERROR, "XhcBulkTransfer: XhcDequeueTrbFromEndpoint failed\n"));\r
- }\r
- } else {\r
- if (*TransferResult == EFI_USB_NOERROR) {\r
- Status = EFI_SUCCESS;\r
- } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
- RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
- if (EFI_ERROR (RecoveryStatus)) {\r
- DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: XhcRecoverHaltedEndpoint failed\n"));\r
- }\r
- Status = EFI_DEVICE_ERROR;\r
- }\r
- }\r
-\r
- Xhc->PciIo->Flush (Xhc->PciIo);\r
- XhcFreeUrb (Xhc, Urb);\r
+ Status = XhcTransfer (\r
+ Xhc,\r
+ DeviceAddress,\r
+ EndPointAddress,\r
+ DeviceSpeed,\r
+ MaximumPacketLength,\r
+ XHC_BULK_TRANSFER,\r
+ NULL,\r
+ Data[0],\r
+ DataLength,\r
+ Timeout,\r
+ TransferResult\r
+ );\r
\r
ON_EXIT:\r
-\r
if (EFI_ERROR (Status)) {\r
DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
}\r
EFI_STATUS Status;\r
UINT8 SlotId;\r
UINT8 Index;\r
- UINT8 *Data;\r
EFI_TPL OldTpl;\r
\r
//\r
goto ON_EXIT;\r
}\r
\r
- Data = AllocateZeroPool (DataLength);\r
-\r
- if (Data == NULL) {\r
- DEBUG ((EFI_D_ERROR, "XhcAsyncInterruptTransfer: failed to allocate buffer\n"));\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto ON_EXIT;\r
- }\r
-\r
- Urb = XhcCreateUrb (\r
+ Urb = XhciInsertAsyncIntTransfer (\r
Xhc,\r
DeviceAddress,\r
EndPointAddress,\r
DeviceSpeed,\r
MaximumPacketLength,\r
- XHC_INT_TRANSFER_ASYNC,\r
- NULL,\r
- Data,\r
DataLength,\r
CallBackFunction,\r
Context\r
);\r
-\r
if (Urb == NULL) {\r
- DEBUG ((EFI_D_ERROR, "XhcAsyncInterruptTransfer: failed to create URB\n"));\r
- FreePool (Data);\r
Status = EFI_OUT_OF_RESOURCES;\r
goto ON_EXIT;\r
}\r
\r
- InsertHeadList (&Xhc->AsyncIntTransfers, &Urb->UrbList);\r
//\r
// Ring the doorbell\r
//\r
)\r
{\r
USB_XHCI_INSTANCE *Xhc;\r
- URB *Urb;\r
UINT8 SlotId;\r
EFI_STATUS Status;\r
- EFI_STATUS RecoveryStatus;\r
EFI_TPL OldTpl;\r
\r
//\r
goto ON_EXIT;\r
}\r
\r
- Urb = XhcCreateUrb (\r
- Xhc,\r
- DeviceAddress,\r
- EndPointAddress,\r
- DeviceSpeed,\r
- MaximumPacketLength,\r
- XHC_INT_TRANSFER_SYNC,\r
- NULL,\r
- Data,\r
- *DataLength,\r
- NULL,\r
- NULL\r
- );\r
-\r
- if (Urb == NULL) {\r
- DEBUG ((EFI_D_ERROR, "XhcSyncInterruptTransfer: failed to create URB\n"));\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto ON_EXIT;\r
- }\r
-\r
- Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout);\r
-\r
- *TransferResult = Urb->Result;\r
- *DataLength = Urb->Completed;\r
-\r
- if (Status == EFI_TIMEOUT) {\r
- //\r
- // The transfer timed out. Abort the transfer by dequeueing of the TD.\r
- //\r
- RecoveryStatus = XhcDequeueTrbFromEndpoint(Xhc, Urb);\r
- if (EFI_ERROR(RecoveryStatus)) {\r
- DEBUG((EFI_D_ERROR, "XhcSyncInterruptTransfer: XhcDequeueTrbFromEndpoint failed\n"));\r
- }\r
- } else {\r
- if (*TransferResult == EFI_USB_NOERROR) {\r
- Status = EFI_SUCCESS;\r
- } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
- RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
- if (EFI_ERROR (RecoveryStatus)) {\r
- DEBUG ((EFI_D_ERROR, "XhcSyncInterruptTransfer: XhcRecoverHaltedEndpoint failed\n"));\r
- }\r
- Status = EFI_DEVICE_ERROR;\r
- }\r
- }\r
-\r
- Xhc->PciIo->Flush (Xhc->PciIo);\r
- XhcFreeUrb (Xhc, Urb);\r
+ Status = XhcTransfer (\r
+ Xhc,\r
+ DeviceAddress,\r
+ EndPointAddress,\r
+ DeviceSpeed,\r
+ MaximumPacketLength,\r
+ XHC_INT_TRANSFER_SYNC,\r
+ NULL,\r
+ Data,\r
+ DataLength,\r
+ Timeout,\r
+ TransferResult\r
+ );\r
\r
ON_EXIT:\r
if (EFI_ERROR (Status)) {\r
EFI_STATUS Status;\r
UINT32 PageSize;\r
UINT16 ExtCapReg;\r
+ UINT8 ReleaseNumber;\r
\r
Xhc = AllocateZeroPool (sizeof (USB_XHCI_INSTANCE));\r
\r
Xhc->OriginalPciAttributes = OriginalPciAttributes;\r
CopyMem (&Xhc->Usb2Hc, &gXhciUsb2HcTemplate, sizeof (EFI_USB2_HC_PROTOCOL));\r
\r
+ Status = PciIo->Pci.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ XHC_PCI_SBRN_OFFSET,\r
+ 1,\r
+ &ReleaseNumber\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ Xhc->Usb2Hc.MajorRevision = (ReleaseNumber & 0xF0) >> 4;\r
+ Xhc->Usb2Hc.MinorRevision = (ReleaseNumber & 0x0F);\r
+ }\r
+\r
InitializeListHead (&Xhc->AsyncIntTransfers);\r
\r
//\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
+ //\r
+ // Enable 64-bit DMA support in the PCI layer if this controller\r
+ // supports it.\r
+ //\r
+ if (Xhc->HcCParams.Data.Ac64 != 0) {\r
+ Status = PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationEnable,\r
+ EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,\r
+ NULL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Xhc->Support64BitDma = TRUE;\r
+ } else {\r
+ DEBUG ((EFI_D_WARN,\r
+ "%a: failed to enable 64-bit DMA on 64-bit capable controller @ %p (%r)\n",\r
+ __FUNCTION__, Controller, Status));\r
+ }\r
+ }\r
+\r
XhcSetBiosOwnership (Xhc);\r
\r
XhcResetHC (Xhc, XHC_RESET_TIMEOUT);\r
\r
\r
/**\r
- Stop this driver on ControllerHandle. Support stoping any child handles\r
+ Stop this driver on ControllerHandle. Support stopping any child handles\r
created by this driver.\r
\r
@param This Protocol instance pointer.\r