X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=MdeModulePkg%2FBus%2FPci%2FUhciDxe%2FUhciSched.c;h=90f010c9985ba0d9b8559f889be9e94d60529135;hb=01331951708f980fca1fb3a791ab544adcd3a5d0;hp=e1b602e7e2fc34f0035b5b00eb0d5ed841ec2656;hpb=c52fa98ca98ceaab75e8ddf9ebcfbcbd323bab13;p=mirror_edk2.git diff --git a/MdeModulePkg/Bus/Pci/UhciDxe/UhciSched.c b/MdeModulePkg/Bus/Pci/UhciDxe/UhciSched.c index e1b602e7e2..90f010c998 100644 --- a/MdeModulePkg/Bus/Pci/UhciDxe/UhciSched.c +++ b/MdeModulePkg/Bus/Pci/UhciDxe/UhciSched.c @@ -1,7 +1,9 @@ /** @file -Copyright (c) 2007, Intel Corporation -All rights reserved. This program and the accompanying materials + The EHCI register operation routines. + +Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php @@ -9,30 +11,19 @@ http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -Module Name: - - UhciSched.c - -Abstract: - - The EHCI register operation routines. - -Revision History - - **/ #include "Uhci.h" /** - Create Frame List Structure + Create Frame List Structure. - @param Uhc UHCI device + @param Uhc UHCI device. - @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources - @retval EFI_UNSUPPORTED Map memory fail - @retval EFI_SUCCESS Success + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources. + @retval EFI_UNSUPPORTED Map memory fail. + @retval EFI_SUCCESS Success. **/ EFI_STATUS @@ -47,6 +38,7 @@ UhciInitFrameList ( UINTN Pages; UINTN Bytes; UINTN Index; + EFI_PHYSICAL_ADDRESS PhyAddr; // // The Frame List is a common buffer that will be @@ -84,8 +76,14 @@ UhciInitFrameList ( goto ON_ERROR; } - Uhc->FrameBase = (UINT32 *) (UINTN) MappedAddr; - Uhc->FrameMapping = Mapping; + Uhc->FrameBase = (UINT32 *) (UINTN) Buffer; + Uhc->FrameMapping = Mapping; + + // + // Tell the Host Controller where the Frame List lies, + // by set the Frame List Base Address Register. + // + UhciSetFrameListBaseAddr (Uhc->PciIo, (VOID *) (UINTN) MappedAddr); // // Allocate the QH used by sync interrupt/control/bulk transfer. @@ -110,10 +108,12 @@ UhciInitFrameList ( // Each frame entry is linked to this sequence of QH. These QH // will remain on the schedul, never got removed // - Uhc->SyncIntQh->QhHw.HorizonLink = QH_HLINK (Uhc->CtrlQh, FALSE); + PhyAddr = UsbHcGetPciAddressForHostMem (Uhc->MemPool, Uhc->CtrlQh, sizeof (UHCI_QH_HW)); + Uhc->SyncIntQh->QhHw.HorizonLink = QH_HLINK (PhyAddr, FALSE); Uhc->SyncIntQh->NextQh = Uhc->CtrlQh; - Uhc->CtrlQh->QhHw.HorizonLink = QH_HLINK (Uhc->BulkQh, FALSE); + PhyAddr = UsbHcGetPciAddressForHostMem (Uhc->MemPool, Uhc->BulkQh, sizeof (UHCI_QH_HW)); + Uhc->CtrlQh->QhHw.HorizonLink = QH_HLINK (PhyAddr, FALSE); Uhc->CtrlQh->NextQh = Uhc->BulkQh; // @@ -121,23 +121,22 @@ UhciInitFrameList ( // in supporting the full speed bandwidth reclamation in the previous // mentioned form. Most new platforms don't suffer it. // -#ifdef UHCI_NO_BW_RECLAMATION - Uhc->BulkQh->QhHw.HorizonLink = QH_HLINK (NULL, TRUE); -#else - Uhc->BulkQh->QhHw.HorizonLink = QH_HLINK (Uhc->BulkQh, FALSE); -#endif + Uhc->BulkQh->QhHw.HorizonLink = QH_HLINK (PhyAddr, FALSE); Uhc->BulkQh->NextQh = NULL; + Uhc->FrameBaseHostAddr = AllocateZeroPool (4096); + if (Uhc->FrameBaseHostAddr == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + + PhyAddr = UsbHcGetPciAddressForHostMem (Uhc->MemPool, Uhc->SyncIntQh, sizeof (UHCI_QH_HW)); for (Index = 0; Index < UHCI_FRAME_NUM; Index++) { - Uhc->FrameBase[Index] = QH_HLINK (Uhc->SyncIntQh, FALSE); + Uhc->FrameBase[Index] = QH_HLINK (PhyAddr, FALSE); + Uhc->FrameBaseHostAddr[Index] = (UINT32)(UINTN)Uhc->SyncIntQh; } - // - // Tell the Host Controller where the Frame List lies, - // by set the Frame List Base Address Register. - // - UhciSetFrameListBaseAddr (Uhc->PciIo, (VOID *) (Uhc->FrameBase)); return EFI_SUCCESS; ON_ERROR: @@ -159,11 +158,9 @@ ON_ERROR: /** - Destory FrameList buffer - - @param Uhc The UHCI device + Destory FrameList buffer. - @return VOID + @param Uhc The UHCI device. **/ VOID @@ -184,6 +181,10 @@ UhciDestoryFrameList ( (VOID *) Uhc->FrameBase ); + if (Uhc->FrameBaseHostAddr != NULL) { + FreePool (Uhc->FrameBaseHostAddr); + } + if (Uhc->SyncIntQh != NULL) { UsbHcFreeMem (Uhc->MemPool, Uhc->SyncIntQh, sizeof (UHCI_QH_SW)); } @@ -196,20 +197,21 @@ UhciDestoryFrameList ( UsbHcFreeMem (Uhc->MemPool, Uhc->BulkQh, sizeof (UHCI_QH_SW)); } - Uhc->FrameBase = NULL; - Uhc->SyncIntQh = NULL; - Uhc->CtrlQh = NULL; - Uhc->BulkQh = NULL; + Uhc->FrameBase = NULL; + Uhc->FrameBaseHostAddr = NULL; + Uhc->SyncIntQh = NULL; + Uhc->CtrlQh = NULL; + Uhc->BulkQh = NULL; } /** Convert the poll rate to the maxium 2^n that is smaller - than Interval + than Interval. - @param Interval The poll rate to convert + @param Interval The poll rate to convert. - @return The converted poll rate + @return The converted poll rate. **/ UINTN @@ -239,31 +241,33 @@ UhciConvertPollRate ( Link a queue head (for asynchronous interrupt transfer) to the frame list. - @param FrameBase The base of the frame list - @param Qh The queue head to link into - - @return None + @param Uhc The UHCI device. + @param Qh The queue head to link into. **/ VOID UhciLinkQhToFrameList ( - UINT32 *FrameBase, + USB_HC_DEV *Uhc, UHCI_QH_SW *Qh ) { UINTN Index; UHCI_QH_SW *Prev; UHCI_QH_SW *Next; + EFI_PHYSICAL_ADDRESS PhyAddr; + EFI_PHYSICAL_ADDRESS QhPciAddr; - ASSERT ((FrameBase != NULL) && (Qh != NULL)); + ASSERT ((Uhc->FrameBase != NULL) && (Qh != NULL)); + + QhPciAddr = UsbHcGetPciAddressForHostMem (Uhc->MemPool, Qh, sizeof (UHCI_QH_HW)); for (Index = 0; Index < UHCI_FRAME_NUM; Index += Qh->Interval) { // // First QH can't be NULL because we always keep static queue // heads on the frame list // - ASSERT (!LINK_TERMINATED (FrameBase[Index])); - Next = UHCI_ADDR (FrameBase[Index]); + ASSERT (!LINK_TERMINATED (Uhc->FrameBase[Index])); + Next = (UHCI_QH_SW*)(UINTN)Uhc->FrameBaseHostAddr[Index]; Prev = NULL; // @@ -283,10 +287,9 @@ UhciLinkQhToFrameList ( while (Next->Interval > Qh->Interval) { Prev = Next; Next = Next->NextQh; + ASSERT (Next != NULL); } - ASSERT (Next != NULL); - // // The entry may have been linked into the frame by early insertation. // For example: if insert a Qh with Qh.Interval == 4, and there is a Qh @@ -315,7 +318,8 @@ UhciLinkQhToFrameList ( Prev->NextQh = Qh; Qh->QhHw.HorizonLink = Prev->QhHw.HorizonLink; - Prev->QhHw.HorizonLink = QH_HLINK (Qh, FALSE); + + Prev->QhHw.HorizonLink = QH_HLINK (QhPciAddr, FALSE); break; } @@ -326,14 +330,16 @@ UhciLinkQhToFrameList ( // if (Qh->NextQh == NULL) { Qh->NextQh = Next; - Qh->QhHw.HorizonLink = QH_HLINK (Next, FALSE); + PhyAddr = UsbHcGetPciAddressForHostMem (Uhc->MemPool, Next, sizeof (UHCI_QH_HW)); + Qh->QhHw.HorizonLink = QH_HLINK (PhyAddr, FALSE); } if (Prev == NULL) { - FrameBase[Index] = QH_HLINK (Qh, FALSE); + Uhc->FrameBase[Index] = QH_HLINK (QhPciAddr, FALSE); + Uhc->FrameBaseHostAddr[Index] = (UINT32)(UINTN)Qh; } else { Prev->NextQh = Qh; - Prev->QhHw.HorizonLink = QH_HLINK (Qh, FALSE); + Prev->QhHw.HorizonLink = QH_HLINK (QhPciAddr, FALSE); } } } @@ -344,31 +350,29 @@ UhciLinkQhToFrameList ( the precedence node, and pointer there next to QhSw's next. - @param FrameBase The base address of the frame list - @param Qh The queue head to unlink - - @return None + @param Uhc The UHCI device. + @param Qh The queue head to unlink. **/ VOID UhciUnlinkQhFromFrameList ( - UINT32 *FrameBase, - UHCI_QH_SW *Qh + USB_HC_DEV *Uhc, + UHCI_QH_SW *Qh ) { UINTN Index; UHCI_QH_SW *Prev; UHCI_QH_SW *This; - ASSERT ((FrameBase != NULL) && (Qh != NULL)); + ASSERT ((Uhc->FrameBase != NULL) && (Qh != NULL)); for (Index = 0; Index < UHCI_FRAME_NUM; Index += Qh->Interval) { // // Frame link can't be NULL because we always keep static // queue heads on the frame list // - ASSERT (!LINK_TERMINATED (FrameBase[Index])); - This = UHCI_ADDR (FrameBase[Index]); + ASSERT (!LINK_TERMINATED (Uhc->FrameBase[Index])); + This = (UHCI_QH_SW*)(UINTN)Uhc->FrameBaseHostAddr[Index]; Prev = NULL; // @@ -392,7 +396,8 @@ UhciUnlinkQhFromFrameList ( // // Qh is the first entry in the frame // - FrameBase[Index] = Qh->QhHw.HorizonLink; + Uhc->FrameBase[Index] = Qh->QhHw.HorizonLink; + Uhc->FrameBaseHostAddr[Index] = (UINT32)(UINTN)Qh->NextQh; } else { Prev->NextQh = Qh->NextQh; Prev->QhHw.HorizonLink = Qh->QhHw.HorizonLink; @@ -402,17 +407,16 @@ UhciUnlinkQhFromFrameList ( /** - Check TDs Results + Check TDs Results. - @param Uhc This UHCI device - @param Td UHCI_TD_SW to check - @param IsLow Is Low Speed Device - @param QhResult Return the result of this TD list + @param Uhc This UHCI device. + @param Td UHCI_TD_SW to check. + @param IsLow Is Low Speed Device. + @param QhResult Return the result of this TD list. @return Whether the TD's result is finialized. **/ -STATIC BOOLEAN UhciCheckTdStatus ( IN USB_HC_DEV *Uhc, @@ -456,23 +460,23 @@ UhciCheckTdStatus ( // upper layer won't distinguish these condtions. So, only // set these bits when TD is actually halted. // - if (State & USBTD_STALLED) { - if (State & USBTD_BABBLE) { + if ((State & USBTD_STALLED) != 0) { + if ((State & USBTD_BABBLE) != 0) { QhResult->Result |= EFI_USB_ERR_BABBLE; } else if (TdHw->ErrorCount != 0) { QhResult->Result |= EFI_USB_ERR_STALL; } - if (State & USBTD_CRC) { + if ((State & USBTD_CRC) != 0) { QhResult->Result |= EFI_USB_ERR_CRC; } - if (State & USBTD_BUFFERR) { + if ((State & USBTD_BUFFERR) != 0) { QhResult->Result |= EFI_USB_ERR_BUFFER; } - if (Td->TdHw.Status & USBTD_BITSTUFF) { + if ((Td->TdHw.Status & USBTD_BITSTUFF) != 0) { QhResult->Result |= EFI_USB_ERR_BITSTUFF; } @@ -483,7 +487,7 @@ UhciCheckTdStatus ( Finished = TRUE; goto ON_EXIT; - } else if (State & USBTD_ACTIVE) { + } else if ((State & USBTD_ACTIVE) != 0) { // // The TD is still active, no need to check further. // @@ -515,7 +519,7 @@ UhciCheckTdStatus ( // terminate the transfer // if (!IsLow && (TdHw->ShortPacket == 1) && (Len < Td->DataLen)) { - UHCI_DEBUG (("UhciCheckTdStatus: short packet read occured\n")); + DEBUG ((EFI_D_VERBOSE, "UhciCheckTdStatus: short packet read occured\n")); Finished = TRUE; goto ON_EXIT; @@ -544,18 +548,18 @@ ON_EXIT: } - /** - Check the result of the transfer + Check the result of the transfer. - @param Uhc The UHCI device - @param Td The first TDs of the transfer - @param TimeOut TimeOut value in milliseconds - @param IsLow Is Low Speed Device - @param QhResult The variable to return result + @param Uhc The UHCI device. + @param Qh The queue head of the transfer. + @param Td The first TDs of the transfer. + @param TimeOut TimeOut value in milliseconds. + @param IsLow Is Low Speed Device. + @param QhResult The variable to return result. - @retval EFI_SUCCESS The transfer finished with success - @retval EFI_DEVICE_ERROR Transfer failed + @retval EFI_SUCCESS The transfer finished with success. + @retval EFI_DEVICE_ERROR Transfer failed. **/ EFI_STATUS @@ -572,12 +576,23 @@ UhciExecuteTransfer ( UINTN Delay; BOOLEAN Finished; EFI_STATUS Status; + BOOLEAN InfiniteLoop; - Finished = FALSE; - Status = EFI_SUCCESS; - Delay = (TimeOut * STALL_1_MS / UHC_SYN_POLL) + 1; + Finished = FALSE; + Status = EFI_SUCCESS; + Delay = TimeOut * UHC_1_MILLISECOND; + InfiniteLoop = FALSE; + + // + // According to UEFI spec section 16.2.4, If Timeout is 0, then the caller + // must wait for the function to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR + // is returned. + // + if (TimeOut == 0) { + InfiniteLoop = TRUE; + } - for (Index = 0; Index < Delay; Index++) { + for (Index = 0; InfiniteLoop || (Index < Delay); Index++) { Finished = UhciCheckTdStatus (Uhc, Td, IsLow, QhResult); // @@ -587,20 +602,20 @@ UhciExecuteTransfer ( break; } - gBS->Stall (UHC_SYN_POLL); + gBS->Stall (UHC_1_MICROSECOND); } if (!Finished) { - UHCI_ERROR (("UhciExecuteTransfer: execution not finished for %dms\n", TimeOut)); - UHCI_DUMP_QH ((Qh)); - UHCI_DUMP_TDS ((Td)); + DEBUG ((EFI_D_ERROR, "UhciExecuteTransfer: execution not finished for %dms\n", (UINT32)TimeOut)); + UhciDumpQh (Qh); + UhciDumpTds (Td); Status = EFI_TIMEOUT; } else if (QhResult->Result != EFI_USB_NOERROR) { - UHCI_ERROR (("UhciExecuteTransfer: execution failed with result %x\n", QhResult->Result)); - UHCI_DUMP_QH ((Qh)); - UHCI_DUMP_TDS ((Td)); + DEBUG ((EFI_D_ERROR, "UhciExecuteTransfer: execution failed with result %x\n", QhResult->Result)); + UhciDumpQh (Qh); + UhciDumpTds (Td); Status = EFI_DEVICE_ERROR; } @@ -610,18 +625,17 @@ UhciExecuteTransfer ( /** - Update Async Request, QH and TDs - - @param AsyncReq The UHCI asynchronous transfer to update - @param Result Transfer reslut - @param ErrTdPos Error TD Position + Update Async Request, QH and TDs. - @return VOID + @param Uhc The UHCI device. + @param AsyncReq The UHCI asynchronous transfer to update. + @param Result Transfer reslut. + @param NextToggle The toggle of next data. **/ -STATIC VOID UhciUpdateAsyncReq ( + IN USB_HC_DEV *Uhc, IN UHCI_ASYNC_REQUEST *AsyncReq, IN UINT32 Result, IN UINT32 NextToggle @@ -650,30 +664,29 @@ UhciUpdateAsyncReq ( Td->TdHw.Status |= USBTD_ACTIVE; } - UhciLinkTdToQh (Qh, FirstTd); + UhciLinkTdToQh (Uhc, Qh, FirstTd); return ; } } /** - Create Async Request node, and Link to List - - @param Uhc The UHCI device - @param Qh The queue head of the transfer - @param FirstTd First TD of the transfer - @param DevAddr Device Address - @param EndPoint EndPoint Address - @param DataLen Data length - @param Interval Polling Interval when inserted to frame list - @param Mapping Mapping value - @param Data Data buffer, unmapped - @param Callback Callback after interrupt transfeer - @param Context Callback Context passed as function parameter - @param IsLow Is Low Speed - - @retval EFI_SUCCESS An asynchronous transfer is created - @retval EFI_INVALID_PARAMETER Paremeter is error + Create Async Request node, and Link to List. + + @param Uhc The UHCI device. + @param Qh The queue head of the transfer. + @param FirstTd First TD of the transfer. + @param DevAddr Device Address. + @param EndPoint EndPoint Address. + @param DataLen Data length. + @param Interval Polling Interval when inserted to frame list. + @param Data Data buffer, unmapped. + @param Callback Callback after interrupt transfeer. + @param Context Callback Context passed as function parameter. + @param IsLow Is Low Speed. + + @retval EFI_SUCCESS An asynchronous transfer is created. + @retval EFI_INVALID_PARAMETER Paremeter is error. @retval EFI_OUT_OF_RESOURCES Failed because of resource shortage. **/ @@ -686,7 +699,6 @@ UhciCreateAsyncReq ( IN UINT8 EndPoint, IN UINTN DataLen, IN UINTN Interval, - IN VOID *Mapping, IN UINT8 *Data, IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback, IN VOID *Context, @@ -708,8 +720,7 @@ UhciCreateAsyncReq ( AsyncReq->DevAddr = DevAddr; AsyncReq->EndPoint = EndPoint; AsyncReq->DataLen = DataLen; - AsyncReq->Interval = Interval; - AsyncReq->Mapping = Mapping; + AsyncReq->Interval = UhciConvertPollRate(Interval); AsyncReq->Data = Data; AsyncReq->Callback = Callback; AsyncReq->Context = Context; @@ -729,17 +740,13 @@ UhciCreateAsyncReq ( } - /** - Free an asynchronous request's resource such as memory - - @param Uhc The UHCI device - @param AsyncReq The asynchronous request to free + Free an asynchronous request's resource such as memory. - @return None + @param Uhc The UHCI device. + @param AsyncReq The asynchronous request to free. **/ -STATIC VOID UhciFreeAsyncReq ( IN USB_HC_DEV *Uhc, @@ -751,12 +758,8 @@ UhciFreeAsyncReq ( UhciDestoryTds (Uhc, AsyncReq->FirstTd); UsbHcFreeMem (Uhc->MemPool, AsyncReq->QhSw, sizeof (UHCI_QH_SW)); - if (AsyncReq->Mapping != NULL) { - Uhc->PciIo->Unmap (Uhc->PciIo, AsyncReq->Mapping); - } - if (AsyncReq->Data != NULL) { - gBS->FreePool (AsyncReq->Data); + UsbHcFreeMem (Uhc->MemPool, AsyncReq->Data, AsyncReq->DataLen); } gBS->FreePool (AsyncReq); @@ -770,15 +773,12 @@ UhciFreeAsyncReq ( UHC's recycle list to wait for a while before release the memory. Until then, hardware won't hold point to the request. - @param Uhc The UHCI device - @param AsyncReq The asynchronous request to free + @param Uhc The UHCI device. + @param AsyncReq The asynchronous request to free. @param FreeNow If TRUE, free the resource immediately, otherwise add the request to recycle wait list. - @return None - **/ -STATIC VOID UhciUnlinkAsyncReq ( IN USB_HC_DEV *Uhc, @@ -789,7 +789,7 @@ UhciUnlinkAsyncReq ( ASSERT ((Uhc != NULL) && (AsyncReq != NULL)); RemoveEntryList (&(AsyncReq->Link)); - UhciUnlinkQhFromFrameList (Uhc->FrameBase, AsyncReq->QhSw); + UhciUnlinkQhFromFrameList (Uhc, AsyncReq->QhSw); if (FreeNow) { UhciFreeAsyncReq (Uhc, AsyncReq); @@ -806,16 +806,16 @@ UhciUnlinkAsyncReq ( /** - Delete Async Interrupt QH and TDs + Delete Async Interrupt QH and TDs. - @param Uhc The UHCI device - @param DevAddr Device Address - @param EndPoint EndPoint Address - @param Toggle The next data toggle to use + @param Uhc The UHCI device. + @param DevAddr Device Address. + @param EndPoint EndPoint Address. + @param Toggle The next data toggle to use. - @retval EFI_SUCCESS The request is deleted - @retval EFI_INVALID_PARAMETER Paremeter is error - @retval EFI_NOT_FOUND The asynchronous isn't found + @retval EFI_SUCCESS The request is deleted. + @retval EFI_INVALID_PARAMETER Paremeter is error. + @retval EFI_NOT_FOUND The asynchronous isn't found. **/ EFI_STATUS @@ -890,12 +890,9 @@ UhciRemoveAsyncReq ( existing for at least 50ms, far enough for the hardware to clear its cache. - @param Uhc The UHCI device - - @return None + @param Uhc The UHCI device. **/ -STATIC VOID UhciRecycleAsyncReq ( IN USB_HC_DEV *Uhc @@ -921,9 +918,7 @@ UhciRecycleAsyncReq ( /** Release all the asynchronous transfers on the lsit. - @param Uhc The UHCI device - - @return VOID + @param Uhc The UHCI device. **/ VOID @@ -956,15 +951,14 @@ UhciFreeAllAsyncReq ( /** - Interrupt transfer periodic check handler - - @param Event The event of the time - @param Context Context of the event, pointer to USB_HC_DEV + Interrupt transfer periodic check handler. - @return VOID + @param Event The event of the time. + @param Context Context of the event, pointer to USB_HC_DEV. **/ VOID +EFIAPI UhciMonitorAsyncReqList ( IN EFI_EVENT Event, IN VOID *Context @@ -1021,7 +1015,7 @@ UhciMonitorAsyncReqList ( CopyMem (Data, AsyncReq->FirstTd->Data, QhResult.Complete); } - UhciUpdateAsyncReq (AsyncReq, QhResult.Result, QhResult.NextToggle); + UhciUpdateAsyncReq (Uhc, AsyncReq, QhResult.Result, QhResult.NextToggle); // // Now, either transfer is SUCCESS or met errors since