\r
XHCI transfer scheduling routines.\r
\r
-Copyright (c) 2011 - 2014, 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
if ((Xhc == NULL) || (Urb == NULL)) {\r
return;\r
}\r
- \r
+\r
if (Urb->DataMap != NULL) {\r
Xhc->PciIo->Unmap (Xhc->PciIo, Urb->DataMap);\r
}\r
} else {\r
EPType = (UINT8) ((DEVICE_CONTEXT_64 *)OutputContext)->EP[Dci-1].EPType;\r
}\r
- \r
- if (Urb->Data != NULL) {\r
+\r
+ //\r
+ // No need to remap.\r
+ //\r
+ if ((Urb->Data != NULL) && (Urb->DataMap == NULL)) {\r
if (((UINT8) (Urb->Ep.Direction)) == EfiUsbDataIn) {\r
MapOp = EfiPciIoOperationBusMasterWrite;\r
} else {\r
MapOp = EfiPciIoOperationBusMasterRead;\r
}\r
- \r
+\r
Len = Urb->DataLen;\r
Status = Xhc->PciIo->Map (Xhc->PciIo, MapOp, Urb->Data, &Len, &PhyAddr, &Map);\r
- \r
+\r
if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {\r
DEBUG ((EFI_D_ERROR, "XhcCreateTransferTrb: Fail to map Urb->Data.\n"));\r
return EFI_OUT_OF_RESOURCES;\r
}\r
- \r
+\r
Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);\r
Urb->DataMap = Map;\r
}\r
TrbStart->TrbCtrSetup.wValue = Urb->Request->Value;\r
TrbStart->TrbCtrSetup.wIndex = Urb->Request->Index;\r
TrbStart->TrbCtrSetup.wLength = Urb->Request->Length;\r
- TrbStart->TrbCtrSetup.Lenth = 8;\r
+ TrbStart->TrbCtrSetup.Length = 8;\r
TrbStart->TrbCtrSetup.IntTarget = 0;\r
TrbStart->TrbCtrSetup.IOC = 1;\r
TrbStart->TrbCtrSetup.IDT = 1;\r
TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
TrbStart->TrbCtrData.TRBPtrLo = XHC_LOW_32BIT(Urb->DataPhy);\r
TrbStart->TrbCtrData.TRBPtrHi = XHC_HIGH_32BIT(Urb->DataPhy);\r
- TrbStart->TrbCtrData.Lenth = (UINT32) Urb->DataLen;\r
+ TrbStart->TrbCtrData.Length = (UINT32) Urb->DataLen;\r
TrbStart->TrbCtrData.TDSize = 0;\r
TrbStart->TrbCtrData.IntTarget = 0;\r
TrbStart->TrbCtrData.ISP = 1;\r
TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->DataPhy + TotalLen);\r
TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->DataPhy + TotalLen);\r
- TrbStart->TrbNormal.Lenth = (UINT32) Len;\r
+ TrbStart->TrbNormal.Length = (UINT32) Len;\r
TrbStart->TrbNormal.TDSize = 0;\r
TrbStart->TrbNormal.IntTarget = 0;\r
TrbStart->TrbNormal.ISP = 1;\r
TrbStart = (TRB *)(UINTN)EPRing->RingEnqueue;\r
TrbStart->TrbNormal.TRBPtrLo = XHC_LOW_32BIT((UINT8 *) Urb->DataPhy + TotalLen);\r
TrbStart->TrbNormal.TRBPtrHi = XHC_HIGH_32BIT((UINT8 *) Urb->DataPhy + TotalLen);\r
- TrbStart->TrbNormal.Lenth = (UINT32) Len;\r
+ TrbStart->TrbNormal.Length = (UINT32) Len;\r
TrbStart->TrbNormal.TDSize = 0;\r
TrbStart->TrbNormal.IntTarget = 0;\r
TrbStart->TrbNormal.ISP = 1;\r
VOID *Dcbaa;\r
EFI_PHYSICAL_ADDRESS DcbaaPhy;\r
UINT64 CmdRing;\r
- EFI_PHYSICAL_ADDRESS CmdRingPhy; \r
+ EFI_PHYSICAL_ADDRESS CmdRingPhy;\r
UINTN Entries;\r
UINT32 MaxScratchpadBufs;\r
UINT64 *ScratchBuf;\r
ScratchEntryMap = AllocateZeroPool (sizeof (UINTN) * MaxScratchpadBufs);\r
ASSERT (ScratchEntryMap != NULL);\r
Xhc->ScratchEntryMap = ScratchEntryMap;\r
- \r
+\r
//\r
// Allocate the buffer to record the host address for each entry\r
//\r
Xhc->PciIo,\r
EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)),\r
Xhc->PageSize,\r
- (VOID **) &ScratchBuf, \r
+ (VOID **) &ScratchBuf,\r
&ScratchPhy,\r
&Xhc->ScratchMap\r
);\r
XhcWriteOpReg (Xhc, XHC_CRCR_OFFSET, XHC_LOW_32BIT(CmdRingPhy));\r
XhcWriteOpReg (Xhc, XHC_CRCR_OFFSET + 4, XHC_HIGH_32BIT (CmdRingPhy));\r
\r
- DEBUG ((EFI_D_INFO, "XhcInitSched:XHC_CRCR=0x%x\n", Xhc->CmdRing.RingSeg0));\r
-\r
//\r
// Disable the 'interrupter enable' bit in USB_CMD\r
// and clear IE & IP bit in all Interrupter X Management Registers.\r
// Allocate EventRing for Cmd, Ctrl, Bulk, Interrupt, AsynInterrupt transfer\r
//\r
CreateEventRing (Xhc, &Xhc->EventRing);\r
- DEBUG ((EFI_D_INFO, "XhcInitSched:XHC_EVENTRING=0x%x\n", Xhc->EventRing.EventRingSeg0));\r
+ DEBUG ((DEBUG_INFO, "XhcInitSched: Created CMD ring [%p~%p) EVENT ring [%p~%p)\n",\r
+ Xhc->CmdRing.RingSeg0, (UINTN)Xhc->CmdRing.RingSeg0 + sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER,\r
+ Xhc->EventRing.EventRingSeg0, (UINTN)Xhc->EventRing.EventRingSeg0 + sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER\r
+ ));\r
}\r
\r
/**\r
)\r
{\r
EFI_STATUS Status;\r
- EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
- CMD_TRB_RESET_ENDPOINT CmdTrbResetED;\r
- CMD_SET_TR_DEQ_POINTER CmdSetTRDeq;\r
UINT8 Dci;\r
UINT8 SlotId;\r
- EFI_PHYSICAL_ADDRESS PhyAddr;\r
\r
Status = EFI_SUCCESS;\r
SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
}\r
Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
ASSERT (Dci < 32);\r
- \r
+\r
DEBUG ((EFI_D_INFO, "Recovery Halted Slot = %x,Dci = %x\n", SlotId, Dci));\r
\r
//\r
// 1) Send Reset endpoint command to transit from halt to stop state\r
//\r
- ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));\r
- CmdTrbResetED.CycleBit = 1;\r
- CmdTrbResetED.Type = TRB_TYPE_RESET_ENDPOINT;\r
- CmdTrbResetED.EDID = Dci;\r
- CmdTrbResetED.SlotId = SlotId;\r
- Status = XhcCmdTransfer (\r
- Xhc,\r
- (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,\r
- XHC_GENERIC_TIMEOUT,\r
- (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
- );\r
+ Status = XhcResetEndpoint(Xhc, SlotId, Dci);\r
if (EFI_ERROR(Status)) {\r
DEBUG ((EFI_D_ERROR, "XhcRecoverHaltedEndpoint: Reset Endpoint Failed, Status = %r\n", Status));\r
goto Done;\r
//\r
// 2)Set dequeue pointer\r
//\r
- ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));\r
- PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));\r
- CmdSetTRDeq.PtrLo = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;\r
- CmdSetTRDeq.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
- CmdSetTRDeq.CycleBit = 1;\r
- CmdSetTRDeq.Type = TRB_TYPE_SET_TR_DEQUE;\r
- CmdSetTRDeq.Endpoint = Dci;\r
- CmdSetTRDeq.SlotId = SlotId;\r
- Status = XhcCmdTransfer (\r
- Xhc,\r
- (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,\r
- XHC_GENERIC_TIMEOUT,\r
- (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
- );\r
+ Status = XhcSetTrDequeuePointer(Xhc, SlotId, Dci, Urb);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcRecoverHaltedEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status));\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // 3)Ring the doorbell to transit from stop to active\r
+ //\r
+ XhcRingDoorBell (Xhc, SlotId, Dci);\r
+\r
+Done:\r
+ return Status;\r
+}\r
+\r
+/**\r
+ System software shall use a Stop Endpoint Command (section 4.6.9) and the Set TR Dequeue Pointer\r
+ Command (section 4.6.10) to remove the timed-out TDs from the xHC transfer ring. The next write to\r
+ the Doorbell of the Endpoint will transition the Endpoint Context from the Stopped to the Running\r
+ state.\r
+\r
+ @param Xhc The XHCI Instance.\r
+ @param Urb The urb which doesn't get completed in a specified timeout range.\r
+\r
+ @retval EFI_SUCCESS The dequeuing of the TDs is successful.\r
+ @retval EFI_ALREADY_STARTED The Urb is finished so no deque is needed.\r
+ @retval Others Failed to stop the endpoint and dequeue the TDs.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcDequeueTrbFromEndpoint (\r
+ IN USB_XHCI_INSTANCE *Xhc,\r
+ IN URB *Urb\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 Dci;\r
+ UINT8 SlotId;\r
+\r
+ Status = EFI_SUCCESS;\r
+ SlotId = XhcBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
+ if (SlotId == 0) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ Dci = XhcEndpointToDci (Urb->Ep.EpAddr, (UINT8)(Urb->Ep.Direction));\r
+ ASSERT (Dci < 32);\r
+\r
+ DEBUG ((EFI_D_INFO, "Stop Slot = %x,Dci = %x\n", SlotId, Dci));\r
+\r
+ //\r
+ // 1) Send Stop endpoint command to stop xHC from executing of the TDs on the endpoint\r
+ //\r
+ Status = XhcStopEndpoint(Xhc, SlotId, Dci, Urb);\r
if (EFI_ERROR(Status)) {\r
- DEBUG ((EFI_D_ERROR, "XhcRecoverHaltedEndpoint: Set Dequeue Pointer Failed, Status = %r\n", Status));\r
+ DEBUG ((EFI_D_ERROR, "XhcDequeueTrbFromEndpoint: Stop Endpoint Failed, Status = %r\n", Status));\r
goto Done;\r
}\r
\r
+ //\r
+ // 2)Set dequeue pointer\r
+ //\r
+ if (Urb->Finished && Urb->Result == EFI_USB_NOERROR) {\r
+ //\r
+ // Return Already Started to indicate the pending URB is finished.\r
+ // This fixes BULK data loss when transfer is detected as timeout\r
+ // but finished just before stopping endpoint.\r
+ //\r
+ Status = EFI_ALREADY_STARTED;\r
+ DEBUG ((DEBUG_INFO, "XhcDequeueTrbFromEndpoint: Pending URB is finished: Length Actual/Expect = %d/%d!\n", Urb->Completed, Urb->DataLen));\r
+ } else {\r
+ Status = XhcSetTrDequeuePointer(Xhc, SlotId, Dci, Urb);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "XhcDequeueTrbFromEndpoint: Set Transfer Ring Dequeue Pointer Failed, Status = %r\n", Status));\r
+ goto Done;\r
+ }\r
+ }\r
+\r
//\r
// 3)Ring the doorbell to transit from stop to active\r
//\r
EventRing->TrbNumber = EVENT_RING_TRB_NUMBER;\r
EventRing->EventRingDequeue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;\r
EventRing->EventRingEnqueue = (TRB_TEMPLATE *) EventRing->EventRingSeg0;\r
- \r
+\r
DequeuePhy = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Buf, Size);\r
- \r
+\r
//\r
// Software maintains an Event Ring Consumer Cycle State (CCS) bit, initializing it to '1'\r
// and toggling it every time the Event Ring Dequeue Pointer wraps back to the beginning of the Event Ring.\r
{\r
UINT32 Index;\r
UINT64 *ScratchEntry;\r
- \r
+\r
if (Xhc->ScratchBuf != NULL) {\r
ScratchEntry = Xhc->ScratchEntry;\r
for (Index = 0; Index < Xhc->MaxScratchpadBufs; Index++) {\r
UsbHcFreeMem (Xhc->MemPool, Xhc->CmdRing.RingSeg0, sizeof (TRB_TEMPLATE) * CMD_RING_TRB_NUMBER);\r
Xhc->CmdRing.RingSeg0 = NULL;\r
}\r
- \r
+\r
XhcFreeEventRing (Xhc,&Xhc->EventRing);\r
\r
if (Xhc->DCBAA != NULL) {\r
UsbHcFreeMem (Xhc->MemPool, Xhc->DCBAA, (Xhc->MaxSlotsEn + 1) * sizeof(UINT64));\r
Xhc->DCBAA = NULL;\r
}\r
- \r
+\r
//\r
// Free memory pool at last\r
//\r
}\r
\r
/**\r
- Check if the Trb is a transaction of the URBs in XHCI's asynchronous transfer list.\r
+ Check if the Trb is a transaction of the URB.\r
\r
@param Xhc The XHCI Instance.\r
- @param Trb The TRB to be checked.\r
- @param Urb The pointer to the matched Urb.\r
+ @param Trb The TRB to be checked\r
+ @param Urb The URB to be checked.\r
\r
- @retval TRUE The Trb is matched with a transaction of the URBs in the async list.\r
- @retval FALSE The Trb is not matched with any URBs in the async list.\r
+ @retval TRUE It is a transaction of the URB.\r
+ @retval FALSE It is not any transaction of the URB.\r
\r
**/\r
BOOLEAN\r
-IsAsyncIntTrb (\r
+IsTransferRingTrb (\r
IN USB_XHCI_INSTANCE *Xhc,\r
IN TRB_TEMPLATE *Trb,\r
- OUT URB **Urb\r
+ IN URB *Urb\r
)\r
{\r
- LIST_ENTRY *Entry;\r
- LIST_ENTRY *Next;\r
- TRB_TEMPLATE *CheckedTrb;\r
- URB *CheckedUrb;\r
- UINTN Index;\r
+ LINK_TRB *LinkTrb;\r
+ TRB_TEMPLATE *CheckedTrb;\r
+ UINTN Index;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
\r
- EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
- CheckedUrb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
- CheckedTrb = CheckedUrb->TrbStart;\r
- for (Index = 0; Index < CheckedUrb->TrbNum; Index++) {\r
- if (Trb == CheckedTrb) {\r
- *Urb = CheckedUrb;\r
- return TRUE;\r
- }\r
- CheckedTrb++;\r
- if ((UINTN)CheckedTrb >= ((UINTN) CheckedUrb->Ring->RingSeg0 + sizeof (TRB_TEMPLATE) * CheckedUrb->Ring->TrbNumber)) {\r
- CheckedTrb = (TRB_TEMPLATE*) CheckedUrb->Ring->RingSeg0;\r
- }\r
+ CheckedTrb = Urb->TrbStart;\r
+ for (Index = 0; Index < Urb->TrbNum; Index++) {\r
+ if (Trb == CheckedTrb) {\r
+ return TRUE;\r
+ }\r
+ CheckedTrb++;\r
+ //\r
+ // If the checked TRB is the link TRB at the end of the transfer ring,\r
+ // recircle it to the head of the ring.\r
+ //\r
+ if (CheckedTrb->Type == TRB_TYPE_LINK) {\r
+ LinkTrb = (LINK_TRB *) CheckedTrb;\r
+ PhyAddr = (EFI_PHYSICAL_ADDRESS)(LinkTrb->PtrLo | LShiftU64 ((UINT64) LinkTrb->PtrHi, 32));\r
+ CheckedTrb = (TRB_TEMPLATE *)(UINTN) UsbHcGetHostAddrForPciAddr (Xhc->MemPool, (VOID *)(UINTN) PhyAddr, sizeof (TRB_TEMPLATE));\r
+ ASSERT (CheckedTrb == Urb->Ring->RingSeg0);\r
}\r
}\r
\r
}\r
\r
/**\r
- Check if the Trb is a transaction of the URB.\r
+ Check if the Trb is a transaction of the URBs in XHCI's asynchronous transfer list.\r
\r
- @param Trb The TRB to be checked\r
- @param Urb The transfer ring to be checked.\r
+ @param Xhc The XHCI Instance.\r
+ @param Trb The TRB to be checked.\r
+ @param Urb The pointer to the matched Urb.\r
\r
- @retval TRUE It is a transaction of the URB.\r
- @retval FALSE It is not any transaction of the URB.\r
+ @retval TRUE The Trb is matched with a transaction of the URBs in the async list.\r
+ @retval FALSE The Trb is not matched with any URBs in the async list.\r
\r
**/\r
BOOLEAN\r
-IsTransferRingTrb (\r
+IsAsyncIntTrb (\r
+ IN USB_XHCI_INSTANCE *Xhc,\r
IN TRB_TEMPLATE *Trb,\r
- IN URB *Urb\r
+ OUT URB **Urb\r
)\r
{\r
- TRB_TEMPLATE *CheckedTrb;\r
- UINTN Index;\r
-\r
- CheckedTrb = Urb->Ring->RingSeg0;\r
-\r
- ASSERT (Urb->Ring->TrbNumber == CMD_RING_TRB_NUMBER || Urb->Ring->TrbNumber == TR_RING_TRB_NUMBER);\r
+ LIST_ENTRY *Entry;\r
+ LIST_ENTRY *Next;\r
+ URB *CheckedUrb;\r
\r
- for (Index = 0; Index < Urb->Ring->TrbNumber; Index++) {\r
- if (Trb == CheckedTrb) {\r
+ EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
+ CheckedUrb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
+ if (IsTransferRingTrb (Xhc, Trb, CheckedUrb)) {\r
+ *Urb = CheckedUrb;\r
return TRUE;\r
}\r
- CheckedTrb++;\r
}\r
\r
return FALSE;\r
}\r
\r
+\r
/**\r
Check the URB's execution result and update the URB's\r
result accordingly.\r
@return Whether the result of URB transfer is finialized.\r
\r
**/\r
-EFI_STATUS\r
+BOOLEAN\r
XhcCheckUrbResult (\r
IN USB_XHCI_INSTANCE *Xhc,\r
IN URB *Urb\r
\r
if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
Urb->Result |= EFI_USB_ERR_SYSTEM;\r
- Status = EFI_DEVICE_ERROR;\r
goto EXIT;\r
}\r
\r
if ((EvtTrb->Type != TRB_TYPE_COMMAND_COMPLT_EVENT) && (EvtTrb->Type != TRB_TYPE_TRANS_EVENT)) {\r
continue;\r
}\r
- \r
+\r
//\r
// Need convert pci device address to host address\r
//\r
TRBPtr = (TRB_TEMPLATE *)(UINTN) UsbHcGetHostAddrForPciAddr (Xhc->MemPool, (VOID *)(UINTN) PhyAddr, sizeof (TRB_TEMPLATE));\r
\r
//\r
- // Update the status of Urb according to the finished event regardless of whether\r
- // the urb is current checked one or in the XHCI's async transfer list.\r
+ // Update the status of URB including the pending URB, the URB that is currently checked,\r
+ // and URBs in the XHCI's async interrupt transfer list.\r
// This way is used to avoid that those completed async transfer events don't get\r
// handled in time and are flushed by newer coming events.\r
//\r
- if (IsTransferRingTrb (TRBPtr, Urb)) {\r
+ if (Xhc->PendingUrb != NULL && IsTransferRingTrb (Xhc, TRBPtr, Xhc->PendingUrb)) {\r
+ CheckedUrb = Xhc->PendingUrb;\r
+ } else if (IsTransferRingTrb (Xhc, TRBPtr, Urb)) {\r
CheckedUrb = Urb;\r
- } else if (IsAsyncIntTrb (Xhc, TRBPtr, &AsyncUrb)) { \r
+ } else if (IsAsyncIntTrb (Xhc, TRBPtr, &AsyncUrb)) {\r
CheckedUrb = AsyncUrb;\r
} else {\r
continue;\r
}\r
- \r
+\r
switch (EvtTrb->Completecode) {\r
case TRB_COMPLETION_STALL_ERROR:\r
CheckedUrb->Result |= EFI_USB_ERR_STALL;\r
DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n",EvtTrb->Completecode));\r
goto EXIT;\r
\r
+ case TRB_COMPLETION_STOPPED:\r
+ case TRB_COMPLETION_STOPPED_LENGTH_INVALID:\r
+ CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;\r
+ CheckedUrb->Finished = TRUE;\r
+ //\r
+ // The pending URB is timeout and force stopped when stopping endpoint.\r
+ // Continue the loop to receive the Command Complete Event for stopping endpoint.\r
+ //\r
+ continue;\r
+\r
case TRB_COMPLETION_SHORT_PACKET:\r
case TRB_COMPLETION_SUCCESS:\r
if (EvtTrb->Completecode == TRB_COMPLETION_SHORT_PACKET) {\r
- DEBUG ((EFI_D_ERROR, "XhcCheckUrbResult: short packet happens!\n"));\r
+ DEBUG ((EFI_D_VERBOSE, "XhcCheckUrbResult: short packet happens!\n"));\r
}\r
\r
TRBType = (UINT8) (TRBPtr->Type);\r
if ((TRBType == TRB_TYPE_DATA_STAGE) ||\r
(TRBType == TRB_TYPE_NORMAL) ||\r
(TRBType == TRB_TYPE_ISOCH)) {\r
- CheckedUrb->Completed += (CheckedUrb->DataLen - EvtTrb->Lenth);\r
+ CheckedUrb->Completed += (((TRANSFER_TRB_NORMAL*)TRBPtr)->Length - EvtTrb->Length);\r
}\r
\r
break;\r
XhcWriteRuntimeReg (Xhc, XHC_ERDP_OFFSET + 4, XHC_HIGH_32BIT (PhyAddr));\r
}\r
\r
- return Status;\r
+ return Urb->Finished;\r
}\r
\r
\r
{\r
EFI_STATUS Status;\r
UINTN Index;\r
- UINTN Loop;\r
+ UINT64 Loop;\r
UINT8 SlotId;\r
UINT8 Dci;\r
+ BOOLEAN Finished;\r
\r
if (CmdTransfer) {\r
SlotId = 0;\r
XhcRingDoorBell (Xhc, SlotId, Dci);\r
\r
for (Index = 0; Index < Loop; Index++) {\r
- Status = XhcCheckUrbResult (Xhc, Urb);\r
- if (Urb->Finished) {\r
+ Finished = XhcCheckUrbResult (Xhc, Urb);\r
+ if (Finished) {\r
break;\r
}\r
gBS->Stall (XHC_1_MICROSECOND);\r
\r
if (Index == Loop) {\r
Urb->Result = EFI_USB_ERR_TIMEOUT;\r
+ Status = EFI_TIMEOUT;\r
+ } else if (Urb->Result != EFI_USB_NOERROR) {\r
+ Status = EFI_DEVICE_ERROR;\r
}\r
\r
return Status;\r
LIST_ENTRY *Next;\r
URB *Urb;\r
EFI_USB_DATA_DIRECTION Direction;\r
+ EFI_STATUS Status;\r
\r
Direction = ((EpNum & 0x80) != 0) ? EfiUsbDataIn : EfiUsbDataOut;\r
EpNum &= 0x0F;\r
if ((Urb->Ep.BusAddr == BusAddr) &&\r
(Urb->Ep.EpAddr == EpNum) &&\r
(Urb->Ep.Direction == Direction)) {\r
+ //\r
+ // Device doesn't finish the IntTransfer until real data comes\r
+ // So the TRB should be removed as well.\r
+ //\r
+ Status = XhcDequeueTrbFromEndpoint (Xhc, Urb);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XhciDelAsyncIntTransfer: XhcDequeueTrbFromEndpoint failed\n"));\r
+ }\r
+\r
RemoveEntryList (&Urb->UrbList);\r
FreePool (Urb->Data);\r
XhcFreeUrb (Xhc, Urb);\r
LIST_ENTRY *Entry;\r
LIST_ENTRY *Next;\r
URB *Urb;\r
+ EFI_STATUS Status;\r
\r
EFI_LIST_FOR_EACH_SAFE (Entry, Next, &Xhc->AsyncIntTransfers) {\r
Urb = EFI_LIST_CONTAINER (Entry, URB, UrbList);\r
+\r
+ //\r
+ // Device doesn't finish the IntTransfer until real data comes\r
+ // So the TRB should be removed as well.\r
+ //\r
+ Status = XhcDequeueTrbFromEndpoint (Xhc, Urb);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XhciDelAllAsyncIntTransfers: XhcDequeueTrbFromEndpoint failed\n"));\r
+ }\r
+\r
RemoveEntryList (&Urb->UrbList);\r
FreePool (Urb->Data);\r
XhcFreeUrb (Xhc, Urb);\r
}\r
}\r
\r
+/**\r
+ Insert a single asynchronous interrupt transfer for\r
+ the device and endpoint.\r
+\r
+ @param Xhc The XHCI Instance\r
+ @param BusAddr The logical device address assigned by UsbBus driver\r
+ @param EpAddr Endpoint addrress\r
+ @param DevSpeed The device speed\r
+ @param MaxPacket The max packet length of the endpoint\r
+ @param DataLen The length of data buffer\r
+ @param Callback The function to call when data is transferred\r
+ @param Context The context to the callback\r
+\r
+ @return Created URB or NULL\r
+\r
+**/\r
+URB *\r
+XhciInsertAsyncIntTransfer (\r
+ IN USB_XHCI_INSTANCE *Xhc,\r
+ IN UINT8 BusAddr,\r
+ IN UINT8 EpAddr,\r
+ IN UINT8 DevSpeed,\r
+ IN UINTN MaxPacket,\r
+ IN UINTN DataLen,\r
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ VOID *Data;\r
+ URB *Urb;\r
+\r
+ Data = AllocateZeroPool (DataLen);\r
+ if (Data == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "%a: failed to allocate buffer\n", __FUNCTION__));\r
+ return NULL;\r
+ }\r
+\r
+ Urb = XhcCreateUrb (\r
+ Xhc,\r
+ BusAddr,\r
+ EpAddr,\r
+ DevSpeed,\r
+ MaxPacket,\r
+ XHC_INT_TRANSFER_ASYNC,\r
+ NULL,\r
+ Data,\r
+ DataLen,\r
+ Callback,\r
+ Context\r
+ );\r
+ if (Urb == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "%a: failed to create URB\n", __FUNCTION__));\r
+ FreePool (Data);\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // New asynchronous transfer must inserted to the head.\r
+ // Check the comments in XhcMoniteAsyncRequests\r
+ //\r
+ InsertHeadList (&Xhc->AsyncIntTransfers, &Urb->UrbList);\r
+\r
+ return Urb;\r
+}\r
+\r
/**\r
Update the queue head for next round of asynchronous transfer\r
\r
//\r
ProcBuf = NULL;\r
if (Urb->Result == EFI_USB_NOERROR) {\r
- ASSERT (Urb->Completed <= Urb->DataLen);\r
-\r
- ProcBuf = AllocateZeroPool (Urb->Completed);\r
+ //\r
+ // Make sure the data received from HW is no more than expected.\r
+ //\r
+ if (Urb->Completed <= Urb->DataLen) {\r
+ ProcBuf = AllocateZeroPool (Urb->Completed);\r
+ }\r
\r
if (ProcBuf == NULL) {\r
XhcUpdateAsyncRequest (Xhc, Urb);\r
Status = XhcInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed);\r
}\r
}\r
- } \r
+ }\r
\r
return Status;\r
}\r
// 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
// Context data structure described above.\r
//\r
+ // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request\r
+ // to device.\r
+ //\r
+ gBS->Stall (XHC_RESET_RECOVERY_DELAY);\r
ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT));\r
CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
// 8) Issue an Address Device Command for the Device Slot, where the command points to the Input\r
// Context data structure described above.\r
//\r
+ // Delay 10ms to meet TRSTRCY delay requirement in usb 2.0 spec chapter 7.1.7.5 before sending SetAddress() request\r
+ // to device.\r
+ //\r
+ gBS->Stall (XHC_RESET_RECOVERY_DELAY);\r
ZeroMem (&CmdTrbAddr, sizeof (CmdTrbAddr));\r
PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Xhc->UsbDevContext[SlotId].InputContext, sizeof (INPUT_CONTEXT_64));\r
CmdTrbAddr.PtrLo = XHC_LOW_32BIT (PhyAddr);\r
EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
}\r
\r
+ if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {\r
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
+ continue;\r
+ }\r
+\r
EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);\r
Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
\r
EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
+ DEBUG ((DEBUG_INFO, "Endpoint[%x]: Created BULK ring [%p~%p)\n",\r
+ EpDesc->EndpointAddress,\r
+ EndpointTransferRing->RingSeg0,\r
+ (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)\r
+ ));\r
}\r
\r
break;\r
InputContext->EP[Dci-1].CErr = 0;\r
InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
}\r
- break;\r
+ //\r
+ // Get the bInterval from descriptor and init the the interval field of endpoint context.\r
+ // Refer to XHCI 1.1 spec section 6.2.3.6.\r
+ //\r
+ if (DeviceSpeed == EFI_USB_SPEED_FULL) {\r
+ Interval = EpDesc->Interval;\r
+ ASSERT (Interval >= 1 && Interval <= 16);\r
+ InputContext->EP[Dci-1].Interval = Interval + 2;\r
+ } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
+ Interval = EpDesc->Interval;\r
+ ASSERT (Interval >= 1 && Interval <= 16);\r
+ InputContext->EP[Dci-1].Interval = Interval - 1;\r
+ }\r
+\r
+ //\r
+ // Do not support isochronous transfer now.\r
+ //\r
+ DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unsupport ISO EP found, Transfer ring is not allocated.\n"));\r
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
+ continue;\r
case USB_ENDPOINT_INTERRUPT:\r
if (Direction == EfiUsbDataIn) {\r
InputContext->EP[Dci-1].CErr = 3;\r
EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
+ DEBUG ((DEBUG_INFO, "Endpoint[%x]: Created INT ring [%p~%p)\n",\r
+ EpDesc->EndpointAddress,\r
+ EndpointTransferRing->RingSeg0,\r
+ (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)\r
+ ));\r
}\r
break;\r
\r
case USB_ENDPOINT_CONTROL:\r
+ //\r
+ // Do not support control transfer now.\r
+ //\r
+ DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unsupport Control EP found, Transfer ring is not allocated.\n"));\r
default:\r
- ASSERT (0);\r
- break;\r
+ DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext: Unknown EP found, Transfer ring is not allocated.\n"));\r
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
+ continue;\r
}\r
\r
PhyAddr = UsbHcGetPciAddrForHostAddr (\r
((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,\r
sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
);\r
- PhyAddr &= ~(0x0F);\r
- PhyAddr |= ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;\r
+ PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);\r
+ PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;\r
InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);\r
InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
\r
EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
}\r
\r
+ if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {\r
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
+ continue;\r
+ }\r
+\r
EpAddr = (UINT8)(EpDesc->EndpointAddress & 0x0F);\r
Direction = (UINT8)((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
\r
EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
+ DEBUG ((DEBUG_INFO, "Endpoint64[%x]: Created BULK ring [%p~%p)\n",\r
+ EpDesc->EndpointAddress,\r
+ EndpointTransferRing->RingSeg0,\r
+ (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)\r
+ ));\r
}\r
\r
break;\r
InputContext->EP[Dci-1].CErr = 0;\r
InputContext->EP[Dci-1].EPType = ED_ISOCH_OUT;\r
}\r
- break;\r
+ //\r
+ // Get the bInterval from descriptor and init the the interval field of endpoint context.\r
+ // Refer to XHCI 1.1 spec section 6.2.3.6.\r
+ //\r
+ if (DeviceSpeed == EFI_USB_SPEED_FULL) {\r
+ Interval = EpDesc->Interval;\r
+ ASSERT (Interval >= 1 && Interval <= 16);\r
+ InputContext->EP[Dci-1].Interval = Interval + 2;\r
+ } else if ((DeviceSpeed == EFI_USB_SPEED_HIGH) || (DeviceSpeed == EFI_USB_SPEED_SUPER)) {\r
+ Interval = EpDesc->Interval;\r
+ ASSERT (Interval >= 1 && Interval <= 16);\r
+ InputContext->EP[Dci-1].Interval = Interval - 1;\r
+ }\r
+\r
+ //\r
+ // Do not support isochronous transfer now.\r
+ //\r
+ DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unsupport ISO EP found, Transfer ring is not allocated.\n"));\r
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
+ continue;\r
case USB_ENDPOINT_INTERRUPT:\r
if (Direction == EfiUsbDataIn) {\r
InputContext->EP[Dci-1].CErr = 3;\r
EndpointTransferRing = AllocateZeroPool(sizeof (TRANSFER_RING));\r
Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1] = (VOID *) EndpointTransferRing;\r
CreateTransferRing(Xhc, TR_RING_TRB_NUMBER, (TRANSFER_RING *)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1]);\r
+ DEBUG ((DEBUG_INFO, "Endpoint64[%x]: Created INT ring [%p~%p)\n",\r
+ EpDesc->EndpointAddress,\r
+ EndpointTransferRing->RingSeg0,\r
+ (UINTN) EndpointTransferRing->RingSeg0 + TR_RING_TRB_NUMBER * sizeof (TRB_TEMPLATE)\r
+ ));\r
}\r
break;\r
\r
case USB_ENDPOINT_CONTROL:\r
+ //\r
+ // Do not support control transfer now.\r
+ //\r
+ DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unsupport Control EP found, Transfer ring is not allocated.\n"));\r
default:\r
- ASSERT (0);\r
- break;\r
+ DEBUG ((EFI_D_INFO, "XhcInitializeEndpointContext64: Unknown EP found, Transfer ring is not allocated.\n"));\r
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
+ continue;\r
}\r
\r
PhyAddr = UsbHcGetPciAddrForHostAddr (\r
((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingSeg0,\r
sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER\r
);\r
- PhyAddr &= ~(0x0F);\r
- PhyAddr |= ((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;\r
+ PhyAddr &= ~((EFI_PHYSICAL_ADDRESS)0x0F);\r
+ PhyAddr |= (EFI_PHYSICAL_ADDRESS)((TRANSFER_RING *)(UINTN)Xhc->UsbDevContext[SlotId].EndpointTransferRing[Dci-1])->RingPCS;\r
InputContext->EP[Dci-1].PtrLo = XHC_LOW_32BIT (PhyAddr);\r
InputContext->EP[Dci-1].PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
\r
IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
}\r
\r
+ if (IfDesc->Length < sizeof (USB_INTERFACE_DESCRIPTOR)) {\r
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
+ continue;\r
+ }\r
+\r
Dci = XhcInitializeEndpointContext (Xhc, SlotId, DeviceSpeed, InputContext, IfDesc);\r
if (Dci > MaxDci) {\r
MaxDci = Dci;\r
IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
}\r
\r
+ if (IfDesc->Length < sizeof (USB_INTERFACE_DESCRIPTOR)) {\r
+ IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
+ continue;\r
+ }\r
+\r
Dci = XhcInitializeEndpointContext64 (Xhc, SlotId, DeviceSpeed, InputContext, IfDesc);\r
if (Dci > MaxDci) {\r
MaxDci = Dci;\r
}\r
- \r
+\r
IfDesc = (USB_INTERFACE_DESCRIPTOR *)((UINTN)IfDesc + IfDesc->Length);\r
}\r
\r
@param Xhc The XHCI Instance.\r
@param SlotId The slot id to be configured.\r
@param Dci The device context index of endpoint.\r
+ @param PendingUrb The pending URB to check completion status when stopping the end point.\r
\r
@retval EFI_SUCCESS Stop endpoint successfully.\r
@retval Others Failed to stop endpoint.\r
XhcStopEndpoint (\r
IN USB_XHCI_INSTANCE *Xhc,\r
IN UINT8 SlotId,\r
- IN UINT8 Dci\r
+ IN UINT8 Dci,\r
+ IN URB *PendingUrb OPTIONAL\r
)\r
{\r
EFI_STATUS Status;\r
\r
DEBUG ((EFI_D_INFO, "XhcStopEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));\r
\r
+ //\r
+ // When XhcCheckUrbResult waits for the Stop_Endpoint completion, it also checks\r
+ // the PendingUrb completion status, because it's possible that the PendingUrb is\r
+ // finished just before stopping the end point, but after the looping check.\r
+ //\r
+ // The PendingUrb could be passed to XhcCmdTransfer to XhcExecTransfer to XhcCheckUrbResult\r
+ // through function parameter, but That will cause every consumer of XhcCmdTransfer,\r
+ // XhcExecTransfer and XhcCheckUrbResult pass a NULL PendingUrb.\r
+ // But actually only XhcCheckUrbResult is aware of the PendingUrb.\r
+ // So we choose to save the PendingUrb into the USB_XHCI_INSTANCE and use it in XhcCheckUrbResult.\r
+ //\r
+ ASSERT (Xhc->PendingUrb == NULL);\r
+ Xhc->PendingUrb = PendingUrb;\r
+ //\r
+ // Reset the URB result from Timeout to NoError.\r
+ // The USB result will be:\r
+ // changed to Timeout when Stop/StopInvalidLength Transfer Event is received, or\r
+ // remain NoError when Success/ShortPacket Transfer Event is received.\r
+ //\r
+ if (PendingUrb != NULL) {\r
+ PendingUrb->Result = EFI_USB_NOERROR;\r
+ }\r
+\r
//\r
// Send stop endpoint command to transit Endpoint from running to stop state\r
//\r
DEBUG ((EFI_D_ERROR, "XhcStopEndpoint: Stop Endpoint Failed, Status = %r\n", Status));\r
}\r
\r
+ Xhc->PendingUrb = NULL;\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Reset endpoint through XHCI's Reset_Endpoint cmd.\r
+\r
+ @param Xhc The XHCI Instance.\r
+ @param SlotId The slot id to be configured.\r
+ @param Dci The device context index of endpoint.\r
+\r
+ @retval EFI_SUCCESS Reset endpoint successfully.\r
+ @retval Others Failed to reset endpoint.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcResetEndpoint (\r
+ IN USB_XHCI_INSTANCE *Xhc,\r
+ IN UINT8 SlotId,\r
+ IN UINT8 Dci\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
+ CMD_TRB_RESET_ENDPOINT CmdTrbResetED;\r
+\r
+ DEBUG ((EFI_D_INFO, "XhcResetEndpoint: Slot = 0x%x, Dci = 0x%x\n", SlotId, Dci));\r
+\r
+ //\r
+ // Send stop endpoint command to transit Endpoint from running to stop state\r
+ //\r
+ ZeroMem (&CmdTrbResetED, sizeof (CmdTrbResetED));\r
+ CmdTrbResetED.CycleBit = 1;\r
+ CmdTrbResetED.Type = TRB_TYPE_RESET_ENDPOINT;\r
+ CmdTrbResetED.EDID = Dci;\r
+ CmdTrbResetED.SlotId = SlotId;\r
+ Status = XhcCmdTransfer (\r
+ Xhc,\r
+ (TRB_TEMPLATE *) (UINTN) &CmdTrbResetED,\r
+ XHC_GENERIC_TIMEOUT,\r
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcResetEndpoint: Reset Endpoint Failed, Status = %r\n", Status));\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Set transfer ring dequeue pointer through XHCI's Set_Tr_Dequeue_Pointer cmd.\r
+\r
+ @param Xhc The XHCI Instance.\r
+ @param SlotId The slot id to be configured.\r
+ @param Dci The device context index of endpoint.\r
+ @param Urb The dequeue pointer of the transfer ring specified\r
+ by the urb to be updated.\r
+\r
+ @retval EFI_SUCCESS Set transfer ring dequeue pointer succeeds.\r
+ @retval Others Failed to set transfer ring dequeue pointer.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcSetTrDequeuePointer (\r
+ IN USB_XHCI_INSTANCE *Xhc,\r
+ IN UINT8 SlotId,\r
+ IN UINT8 Dci,\r
+ IN URB *Urb\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EVT_TRB_COMMAND_COMPLETION *EvtTrb;\r
+ CMD_SET_TR_DEQ_POINTER CmdSetTRDeq;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+\r
+ DEBUG ((EFI_D_INFO, "XhcSetTrDequeuePointer: Slot = 0x%x, Dci = 0x%x, Urb = 0x%x\n", SlotId, Dci, Urb));\r
+\r
+ //\r
+ // Send stop endpoint command to transit Endpoint from running to stop state\r
+ //\r
+ ZeroMem (&CmdSetTRDeq, sizeof (CmdSetTRDeq));\r
+ PhyAddr = UsbHcGetPciAddrForHostAddr (Xhc->MemPool, Urb->Ring->RingEnqueue, sizeof (CMD_SET_TR_DEQ_POINTER));\r
+ CmdSetTRDeq.PtrLo = XHC_LOW_32BIT (PhyAddr) | Urb->Ring->RingPCS;\r
+ CmdSetTRDeq.PtrHi = XHC_HIGH_32BIT (PhyAddr);\r
+ CmdSetTRDeq.CycleBit = 1;\r
+ CmdSetTRDeq.Type = TRB_TYPE_SET_TR_DEQUE;\r
+ CmdSetTRDeq.Endpoint = Dci;\r
+ CmdSetTRDeq.SlotId = SlotId;\r
+ Status = XhcCmdTransfer (\r
+ Xhc,\r
+ (TRB_TEMPLATE *) (UINTN) &CmdSetTRDeq,\r
+ XHC_GENERIC_TIMEOUT,\r
+ (TRB_TEMPLATE **) (UINTN) &EvtTrb\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_ERROR, "XhcSetTrDequeuePointer: Set TR Dequeue Pointer Failed, Status = %r\n", Status));\r
+ }\r
+\r
return Status;\r
}\r
\r
\r
IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
while ((UINTN) IfDesc < ((UINTN) ConfigDesc + ConfigDesc->TotalLength)) {\r
- if (IfDesc->DescriptorType == USB_DESC_TYPE_INTERFACE) {\r
+ if ((IfDesc->DescriptorType == USB_DESC_TYPE_INTERFACE) && (IfDesc->Length >= sizeof (USB_INTERFACE_DESCRIPTOR))) {\r
if (IfDesc->InterfaceNumber == (UINT8) Request->Index) {\r
if (IfDesc->AlternateSetting == Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[IfDesc->InterfaceNumber]) {\r
//\r
EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
}\r
\r
+ if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {\r
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
+ continue;\r
+ }\r
+\r
EpAddr = (UINT8) (EpDesc->EndpointAddress & 0x0F);\r
Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
\r
// XHCI 4.3.6 - Setting Alternate Interfaces\r
// 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.\r
//\r
- Status = XhcStopEndpoint (Xhc, SlotId, Dci);\r
+ Status = XhcStopEndpoint (Xhc, SlotId, Dci, NULL);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
\r
IfDesc = (USB_INTERFACE_DESCRIPTOR *)(ConfigDesc + 1);\r
while ((UINTN) IfDesc < ((UINTN) ConfigDesc + ConfigDesc->TotalLength)) {\r
- if (IfDesc->DescriptorType == USB_DESC_TYPE_INTERFACE) {\r
+ if ((IfDesc->DescriptorType == USB_DESC_TYPE_INTERFACE) && (IfDesc->Length >= sizeof (USB_INTERFACE_DESCRIPTOR))) {\r
if (IfDesc->InterfaceNumber == (UINT8) Request->Index) {\r
if (IfDesc->AlternateSetting == Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[IfDesc->InterfaceNumber]) {\r
//\r
EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
}\r
\r
+ if (EpDesc->Length < sizeof (USB_ENDPOINT_DESCRIPTOR)) {\r
+ EpDesc = (USB_ENDPOINT_DESCRIPTOR *)((UINTN)EpDesc + EpDesc->Length);\r
+ continue;\r
+ }\r
+\r
EpAddr = (UINT8) (EpDesc->EndpointAddress & 0x0F);\r
Direction = (UINT8) ((EpDesc->EndpointAddress & 0x80) ? EfiUsbDataIn : EfiUsbDataOut);\r
\r
// XHCI 4.3.6 - Setting Alternate Interfaces\r
// 1) Stop any Running Transfer Rings affected by the Alternate Interface setting.\r
//\r
- Status = XhcStopEndpoint (Xhc, SlotId, Dci);\r
+ Status = XhcStopEndpoint (Xhc, SlotId, Dci, NULL);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r