PEIM to produce gPeiUsbHostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
which is used to enable recovery function from USB Drivers.\r
\r
-Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved. <BR>\r
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved. <BR>\r
\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions\r
\r
#include "UhcPeim.h"\r
\r
+/**\r
+ Stop the host controller.\r
+\r
+ @param Uhc The UHCI device.\r
+ @param Timeout Max time allowed.\r
+\r
+ @retval EFI_SUCCESS The host controller is stopped.\r
+ @retval EFI_TIMEOUT Failed to stop the host controller.\r
+\r
+**/\r
+EFI_STATUS\r
+UhciStopHc (\r
+ IN USB_UHC_DEV *Uhc,\r
+ IN UINTN Timeout\r
+ )\r
+{\r
+ UINT16 CommandContent;\r
+ UINT16 UsbSts;\r
+ UINTN Index;\r
+\r
+ CommandContent = USBReadPortW (Uhc, Uhc->UsbHostControllerBaseAddress + USBCMD);\r
+ CommandContent &= USBCMD_RS;\r
+ USBWritePortW (Uhc, Uhc->UsbHostControllerBaseAddress + USBCMD, CommandContent);\r
+\r
+ //\r
+ // ensure the HC is in halt status after send the stop command\r
+ // Timeout is in us unit.\r
+ //\r
+ for (Index = 0; Index < (Timeout / 50) + 1; Index++) {\r
+ UsbSts = USBReadPortW (Uhc, Uhc->UsbHostControllerBaseAddress + USBSTS);\r
+\r
+ if ((UsbSts & USBSTS_HCH) == USBSTS_HCH) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ MicroSecondDelay (50);\r
+ }\r
+\r
+ return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+ One notified function to stop the Host Controller at the end of PEI\r
+\r
+ @param[in] PeiServices Pointer to PEI Services Table.\r
+ @param[in] NotifyDescriptor Pointer to the descriptor for the Notification event that\r
+ caused this function to execute.\r
+ @param[in] Ppi Pointer to the PPI data associated with this function.\r
+\r
+ @retval EFI_SUCCESS The function completes successfully\r
+ @retval others\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UhcEndOfPei (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
+ IN VOID *Ppi\r
+ )\r
+{\r
+ USB_UHC_DEV *Uhc;\r
+\r
+ Uhc = PEI_RECOVERY_USB_UHC_DEV_FROM_THIS_NOTIFY (NotifyDescriptor);\r
+\r
+ //\r
+ // Stop the Host Controller\r
+ //\r
+ UhciStopHc (Uhc, 1000 * 1000);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
/**\r
Initializes Usb Host Controller.\r
\r
\r
UhcDev = (USB_UHC_DEV *) ((UINTN) TempPtr);\r
UhcDev->Signature = USB_UHC_DEV_SIGNATURE;\r
+ IoMmuInit (&UhcDev->IoMmu);\r
UhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;\r
\r
//\r
continue;\r
}\r
\r
+ UhcDev->EndOfPeiNotifyList.Flags = (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
+ UhcDev->EndOfPeiNotifyList.Guid = &gEfiEndOfPeiSignalPpiGuid;\r
+ UhcDev->EndOfPeiNotifyList.Notify = UhcEndOfPei;\r
+\r
+ PeiServicesNotifyPpi (&UhcDev->EndOfPeiNotifyList);\r
+\r
Index++;\r
}\r
\r
TD_STRUCT *PtrStatusTD;\r
EFI_STATUS Status;\r
UINT32 DataLen;\r
- UINT8 *PtrDataSource;\r
- UINT8 *Ptr;\r
UINT8 DataToggle;\r
+ UINT8 *RequestPhy;\r
+ VOID *RequestMap;\r
+ UINT8 *DataPhy;\r
+ VOID *DataMap;\r
\r
UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);\r
\r
\r
ClearStatusReg (UhcDev, StatusReg);\r
\r
+ //\r
+ // Map the Request and data for bus master access,\r
+ // then create a list of TD for this transfer\r
+ //\r
+ Status = UhciMapUserRequest (UhcDev, Request, &RequestPhy, &RequestMap);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = UhciMapUserData (UhcDev, TransferDirection, Data, DataLength, &PktID, &DataPhy, &DataMap);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ if (RequestMap != NULL) {\r
+ IoMmuUnmap (UhcDev->IoMmu, RequestMap);\r
+ }\r
+ return Status;\r
+ }\r
+\r
//\r
// generate Setup Stage TD\r
//\r
0,\r
DeviceSpeed,\r
(UINT8 *) Request,\r
+ RequestPhy,\r
(UINT8) sizeof (EFI_USB_DEVICE_REQUEST),\r
&PtrSetupTD\r
);\r
//\r
// Data Stage of Control Transfer\r
//\r
- switch (TransferDirection) {\r
-\r
- case EfiUsbDataIn:\r
- PktID = INPUT_PACKET_ID;\r
- PtrDataSource = Data;\r
- DataLen = (UINT32) *DataLength;\r
- Ptr = PtrDataSource;\r
- break;\r
-\r
- case EfiUsbDataOut:\r
- PktID = OUTPUT_PACKET_ID;\r
- PtrDataSource = Data;\r
- DataLen = (UINT32) *DataLength;\r
- Ptr = PtrDataSource;\r
- break;\r
-\r
- //\r
- // no data stage\r
- //\r
- case EfiUsbNoData:\r
- if (*DataLength != 0) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- PktID = OUTPUT_PACKET_ID;\r
- PtrDataSource = NULL;\r
- DataLen = 0;\r
- Ptr = NULL;\r
- break;\r
\r
- default:\r
- return EFI_INVALID_PARAMETER;\r
+ if (TransferDirection == EfiUsbNoData) {\r
+ DataLen = 0;\r
+ } else {\r
+ DataLen = (UINT32) *DataLength;\r
}\r
\r
DataToggle = 1;\r
UhcDev,\r
DeviceAddress,\r
0,\r
- Ptr,\r
+ Data,\r
+ DataPhy,\r
PacketSize,\r
PktID,\r
DataToggle,\r
PtrPreTD = PtrTD;\r
\r
DataToggle ^= 1;\r
- Ptr += PacketSize;\r
+ Data = (VOID *) ((UINT8 *) Data + PacketSize);\r
+ DataPhy += PacketSize;\r
DataLen -= PacketSize;\r
}\r
\r
// if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.\r
//\r
if (!IsStatusOK (UhcDev, StatusReg)) {\r
-\r
- ClearStatusReg (UhcDev, StatusReg);\r
*TransferResult |= EFI_USB_ERR_SYSTEM;\r
- return EFI_DEVICE_ERROR;\r
+ Status = EFI_DEVICE_ERROR;\r
}\r
\r
ClearStatusReg (UhcDev, StatusReg);\r
\r
+ if (DataMap != NULL) {\r
+ IoMmuUnmap (UhcDev->IoMmu, DataMap);\r
+ }\r
+ if (RequestMap != NULL) {\r
+ IoMmuUnmap (UhcDev->IoMmu, RequestMap);\r
+ }\r
+\r
return Status;\r
}\r
\r
TD_STRUCT *PtrPreTD;\r
\r
UINT8 PktID;\r
- UINT8 *PtrDataSource;\r
- UINT8 *Ptr;\r
\r
BOOLEAN IsFirstTD;\r
\r
\r
UINT16 CommandContent;\r
\r
+ UINT8 *DataPhy;\r
+ VOID *DataMap;\r
+\r
UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);\r
\r
//\r
PtrFirstTD = NULL;\r
PtrPreTD = NULL;\r
DataLen = 0;\r
- Ptr = NULL;\r
\r
ShortPacketEnable = FALSE;\r
\r
\r
ClearStatusReg (UhcDev, StatusReg);\r
\r
+ //\r
+ // Map the source data buffer for bus master access,\r
+ // then create a list of TDs\r
+ //\r
if ((EndPointAddress & 0x80) != 0) {\r
TransferDirection = EfiUsbDataIn;\r
} else {\r
TransferDirection = EfiUsbDataOut;\r
}\r
\r
- switch (TransferDirection) {\r
+ Status = UhciMapUserData (UhcDev, TransferDirection, Data, DataLength, &PktID, &DataPhy, &DataMap);\r
\r
- case EfiUsbDataIn:\r
- ShortPacketEnable = TRUE;\r
- PktID = INPUT_PACKET_ID;\r
- PtrDataSource = Data;\r
- DataLen = (UINT32) *DataLength;\r
- Ptr = PtrDataSource;\r
- break;\r
-\r
- case EfiUsbDataOut:\r
- PktID = OUTPUT_PACKET_ID;\r
- PtrDataSource = Data;\r
- DataLen = (UINT32) *DataLength;\r
- Ptr = PtrDataSource;\r
- break;\r
-\r
- default:\r
- break;\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
}\r
\r
+ DataLen = (UINT32) *DataLength;\r
+\r
PtrQH = UhcDev->BulkQH;\r
\r
IsFirstTD = TRUE;\r
UhcDev,\r
DeviceAddress,\r
EndPointAddress,\r
- Ptr,\r
+ Data,\r
+ DataPhy,\r
PacketSize,\r
PktID,\r
*DataToggle,\r
PtrPreTD = PtrTD;\r
\r
*DataToggle ^= 1;\r
- Ptr += PacketSize;\r
+ Data = (VOID *) ((UINT8 *) Data + PacketSize);\r
+ DataPhy += PacketSize;\r
DataLen -= PacketSize;\r
}\r
//\r
// if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.\r
//\r
if (!IsStatusOK (UhcDev, StatusReg)) {\r
-\r
- ClearStatusReg (UhcDev, StatusReg);\r
*TransferResult |= EFI_USB_ERR_SYSTEM;\r
- return EFI_DEVICE_ERROR;\r
+ Status = EFI_DEVICE_ERROR;\r
}\r
\r
ClearStatusReg (UhcDev, StatusReg);\r
\r
+ if (DataMap != NULL) {\r
+ IoMmuUnmap (UhcDev->IoMmu, DataMap);\r
+ }\r
+\r
return Status;\r
}\r
\r
@param DevAddr Device address.\r
@param Endpoint Endpoint number.\r
@param DeviceSpeed Device Speed.\r
- @param DevRequest Device reuquest.\r
+ @param DevRequest CPU memory address of request structure buffer to transfer.\r
+ @param RequestPhy PCI memory address of request structure buffer to transfer.\r
@param RequestLen Request length.\r
@param PtrTD TD_STRUCT generated.\r
\r
IN UINT8 Endpoint,\r
IN UINT8 DeviceSpeed,\r
IN UINT8 *DevRequest,\r
+ IN UINT8 *RequestPhy,\r
IN UINT8 RequestLen,\r
OUT TD_STRUCT **PtrTD\r
)\r
\r
TdStruct->PtrTDBuffer = (UINT8 *) DevRequest;\r
TdStruct->TDBufferLength = RequestLen;\r
- SetTDDataBuffer (TdStruct);\r
+ //\r
+ // Set the beginning address of the buffer that will be used\r
+ // during the transaction.\r
+ //\r
+ TdStruct->TDData.TDBufferPtr = (UINT32) (UINTN) RequestPhy;\r
\r
*PtrTD = TdStruct;\r
\r
@param UhcDev The UHCI device.\r
@param DevAddr Device address.\r
@param Endpoint Endpoint number.\r
- @param PtrData Data buffer.\r
+ @param PtrData CPU memory address of user data buffer to transfer.\r
+ @param DataPhy PCI memory address of user data buffer to transfer.\r
@param Len Data length.\r
@param PktID PacketID.\r
@param Toggle Data toggle value.\r
IN UINT8 DevAddr,\r
IN UINT8 Endpoint,\r
IN UINT8 *PtrData,\r
+ IN UINT8 *DataPhy,\r
IN UINT8 Len,\r
IN UINT8 PktID,\r
IN UINT8 Toggle,\r
\r
TdStruct->PtrTDBuffer = (UINT8 *) PtrData;\r
TdStruct->TDBufferLength = Len;\r
- SetTDDataBuffer (TdStruct);\r
+ //\r
+ // Set the beginning address of the buffer that will be used\r
+ // during the transaction.\r
+ //\r
+ TdStruct->TDData.TDBufferPtr = (UINT32) (UINTN) DataPhy;\r
\r
*PtrTD = TdStruct;\r
\r
\r
PtrTDStruct->PtrTDBuffer = NULL;\r
PtrTDStruct->TDBufferLength = 0;\r
- SetTDDataBuffer (PtrTDStruct);\r
+ //\r
+ // Set the beginning address of the buffer that will be used\r
+ // during the transaction.\r
+ //\r
+ PtrTDStruct->TDData.TDBufferPtr = 0;\r
\r
*PtrTD = PtrTDStruct;\r
\r
PtrTDStruct->TDData.TDTokenPID = PacketID;\r
}\r
\r
-/**\r
- Set the beginning address of the data buffer that will be used\r
- during the transaction.\r
-\r
- @param PtrTDStruct Place to store TD_STRUCT pointer.\r
-\r
-**/\r
-VOID\r
-SetTDDataBuffer (\r
- IN TD_STRUCT *PtrTDStruct\r
- )\r
-{\r
- //\r
- // Set the beginning address of the data buffer that will be used\r
- // during the transaction.\r
- //\r
- PtrTDStruct->TDData.TDBufferPtr = (UINT32) (UINTN) (PtrTDStruct->PtrTDBuffer);\r
-}\r
-\r
/**\r
Detect whether the TD is active.\r
\r
)\r
{\r
EFI_STATUS Status;\r
- EFI_PHYSICAL_ADDRESS TempPtr;\r
+ UINT8 *TempPtr;\r
UINTN MemPages;\r
UINT8 *Ptr;\r
+ VOID *Mapping;\r
+ EFI_PHYSICAL_ADDRESS MappedAddr;\r
\r
//\r
// Memory Block uses MemoryBlockSizeInPages pages,\r
// memory management header and bit array use 1 page\r
//\r
MemPages = MemoryBlockSizeInPages + 1;\r
- Status = PeiServicesAllocatePages (\r
- EfiBootServicesData,\r
+ Status = IoMmuAllocateBuffer (\r
+ UhcDev->IoMmu,\r
MemPages,\r
- &TempPtr\r
+ (VOID **) &TempPtr,\r
+ &MappedAddr,\r
+ &Mapping\r
);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
\r
- Ptr = (UINT8 *) ((UINTN) TempPtr);\r
+ Ptr = TempPtr;\r
\r
ZeroMem (Ptr, MemPages * EFI_PAGE_SIZE);\r
\r
//\r
// Memory block initial address\r
//\r
- Ptr = (UINT8 *) ((UINTN) TempPtr);\r
+ Ptr = TempPtr;\r
Ptr += EFI_PAGE_SIZE;\r
(*MemoryHeader)->MemoryBlockPtr = Ptr;\r
//\r
StartBitPos = (UINT8) (((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) % 8);\r
\r
//\r
- // reset associated bits in bit arry\r
+ // reset associated bits in bit array\r
//\r
for (Index = StartBytePos, Index2 = StartBitPos, Count = 0; Count < (RealAllocSize / 32); Count++) {\r
\r
}\r
}\r
}\r
+\r
+/**\r
+ Map address of request structure buffer.\r
+\r
+ @param Uhc The UHCI device.\r
+ @param Request The user request buffer.\r
+ @param MappedAddr Mapped address of request.\r
+ @param Map Identificaion of this mapping to return.\r
+\r
+ @return EFI_SUCCESS Success.\r
+ @return EFI_DEVICE_ERROR Fail to map the user request.\r
+\r
+**/\r
+EFI_STATUS\r
+UhciMapUserRequest (\r
+ IN USB_UHC_DEV *Uhc,\r
+ IN OUT VOID *Request,\r
+ OUT UINT8 **MappedAddr,\r
+ OUT VOID **Map\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Len;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+\r
+ Len = sizeof (EFI_USB_DEVICE_REQUEST);\r
+ Status = IoMmuMap (\r
+ Uhc->IoMmu,\r
+ EdkiiIoMmuOperationBusMasterRead,\r
+ Request,\r
+ &Len,\r
+ &PhyAddr,\r
+ Map\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ *MappedAddr = (UINT8 *) (UINTN) PhyAddr;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Map address of user data buffer.\r
+\r
+ @param Uhc The UHCI device.\r
+ @param Direction Direction of the data transfer.\r
+ @param Data The user data buffer.\r
+ @param Len Length of the user data.\r
+ @param PktId Packet identificaion.\r
+ @param MappedAddr Mapped address to return.\r
+ @param Map Identificaion of this mapping to return.\r
+\r
+ @return EFI_SUCCESS Success.\r
+ @return EFI_DEVICE_ERROR Fail to map the user data.\r
+\r
+**/\r
+EFI_STATUS\r
+UhciMapUserData (\r
+ IN USB_UHC_DEV *Uhc,\r
+ IN EFI_USB_DATA_DIRECTION Direction,\r
+ IN VOID *Data,\r
+ IN OUT UINTN *Len,\r
+ OUT UINT8 *PktId,\r
+ OUT UINT8 **MappedAddr,\r
+ OUT VOID **Map\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ switch (Direction) {\r
+ case EfiUsbDataIn:\r
+ //\r
+ // BusMasterWrite means cpu read\r
+ //\r
+ *PktId = INPUT_PACKET_ID;\r
+ Status = IoMmuMap (\r
+ Uhc->IoMmu,\r
+ EdkiiIoMmuOperationBusMasterWrite,\r
+ Data,\r
+ Len,\r
+ &PhyAddr,\r
+ Map\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto EXIT;\r
+ }\r
+\r
+ *MappedAddr = (UINT8 *) (UINTN) PhyAddr;\r
+ break;\r
+\r
+ case EfiUsbDataOut:\r
+ *PktId = OUTPUT_PACKET_ID;\r
+ Status = IoMmuMap (\r
+ Uhc->IoMmu,\r
+ EdkiiIoMmuOperationBusMasterRead,\r
+ Data,\r
+ Len,\r
+ &PhyAddr,\r
+ Map\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto EXIT;\r
+ }\r
+\r
+ *MappedAddr = (UINT8 *) (UINTN) PhyAddr;\r
+ break;\r
+\r
+ case EfiUsbNoData:\r
+ if ((Len != NULL) && (*Len != 0)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto EXIT;\r
+ }\r
+\r
+ *PktId = OUTPUT_PACKET_ID;\r
+ *MappedAddr = NULL;\r
+ *Map = NULL;\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+EXIT:\r
+ return Status;\r
+}\r
+\r